From 63f48bcadfcff307c87f9ab36cba3859bed15387 Mon Sep 17 00:00:00 2001 From: nathan Date: Tue, 19 May 2026 10:42:06 -0700 Subject: [PATCH] Add readable MVP survival object proxies --- AGRARIAN_DEVELOPMENT_ROADMAP.md | 2 +- .../MvpReadableSurvivalObjectProxies.md | 31 +++++ ...fy_mvp_readable_survival_object_proxies.py | 120 ++++++++++++++++++ Source/AgrarianGame/AgrarianCampfire.cpp | 75 +++++++++++ Source/AgrarianGame/AgrarianCampfire.h | 15 +++ Source/AgrarianGame/AgrarianItemPickup.cpp | 65 ++++++++++ Source/AgrarianGame/AgrarianItemPickup.h | 9 ++ Source/AgrarianGame/AgrarianResourceNode.cpp | 49 +++++++ Source/AgrarianGame/AgrarianResourceNode.h | 6 + Source/AgrarianGame/AgrarianShelterActor.cpp | 82 ++++++++++++ Source/AgrarianGame/AgrarianShelterActor.h | 18 +++ Source/AgrarianGame/AgrarianWaterSource.cpp | 63 +++++++++ Source/AgrarianGame/AgrarianWaterSource.h | 9 ++ Source/AgrarianGame/AgrarianWildlifeBase.cpp | 64 ++++++++++ Source/AgrarianGame/AgrarianWildlifeBase.h | 16 +++ 15 files changed, 623 insertions(+), 1 deletion(-) create mode 100644 Docs/CharactersAndObjects/MvpReadableSurvivalObjectProxies.md create mode 100644 Scripts/verify_mvp_readable_survival_object_proxies.py diff --git a/AGRARIAN_DEVELOPMENT_ROADMAP.md b/AGRARIAN_DEVELOPMENT_ROADMAP.md index 6bb72b8..51ff368 100644 --- a/AGRARIAN_DEVELOPMENT_ROADMAP.md +++ b/AGRARIAN_DEVELOPMENT_ROADMAP.md @@ -821,7 +821,7 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe - [x] Make startup credits, character selection, server/join, loading, pause, save, and quit feel like separate intentional segments, with no impression that gameplay has started underneath the UI. Switched startup/menu control to UI-only input, added explicit segment labels for character selection, server join, loading, pause, and saving, and made Save & Quit transition through a dedicated saving screen before issuing save/quit. - [x] Add a visually verified packaged-client startup test using Sunshine/Moonlight or another real GPU desktop capture path, because QEMU guest-agent screenshots cannot validate the interactive rendered desktop. Added a packaged-client GPU startup visual test runbook, a Windows helper that checks the packaged demo and Sunshine service before capture, and verifier coverage requiring Moonlight/Sunshine evidence instead of QEMU guest-agent screenshots. - [x] Add first realistic playable character proxies for the selected young adult male and female archetypes, replacing the default mannequin/dummy presentation for investor builds. Added selected male/female MVP proxy application to the player controller, workwear material generation, cook coverage for Agrarian character assets, documentation, and verification so the menu-selected archetype changes the possessed pawn instead of leaving one default dummy presentation. -- [ ] Replace box/sphere/cylinder survival objects with readable MVP meshes for campfires, primitive shelter pieces, resource pickups, water sources, wildlife, and gathered items. +- [x] Replace box/sphere/cylinder survival objects with readable MVP meshes for campfires, primitive shelter pieces, resource pickups, water sources, wildlife, and gathered items. Added composed native proxy visuals for campfires, primitive shelters, pickups, resource nodes, water sources, and wildlife using cooked Agrarian placeholder mesh assets plus Ground Zero materials, with child visuals set to no collision so gameplay behavior remains unchanged while investor builds read as intentional objects instead of primitive debug shapes. - [ ] Replace the placeholder Ground Zero environment presentation with investor-facing biome dressing: believable terrain material, grass, brush, shrubs, bushes, trees, rocks, water visuals, and local coastal-scrub color variation. - [ ] Add a real water-source visual pass with surface material, edge treatment, scale, and placement that reads as collectable freshwater instead of a placeholder plane. - [ ] Add density and sightline tuning so grasses, shrubs, trees, and resource clusters are visible enough to sell the world without hiding gameplay-critical objects. diff --git a/Docs/CharactersAndObjects/MvpReadableSurvivalObjectProxies.md b/Docs/CharactersAndObjects/MvpReadableSurvivalObjectProxies.md new file mode 100644 index 0000000..ed646d6 --- /dev/null +++ b/Docs/CharactersAndObjects/MvpReadableSurvivalObjectProxies.md @@ -0,0 +1,31 @@ +# MVP Readable Survival Object Proxies + +The 0.1.O investor visual pass replaces primitive single-shape survival object +presentation with composed, readable MVP proxy silhouettes. These are not final +art assets, but they are intentional enough for investor builds to communicate +what the player is looking at before final production meshes arrive. + +Covered native actors: + +- `AAgrarianCampfire`: stone/ash base, stacked log proxies, ember proxy, existing + smoke and light behavior. +- `AAgrarianShelterActor`: floor, rear wall, sloped roof panels, and frame posts. +- `AAgrarianItemPickup`: bundled pickup body, strap, and marker so loose gathered + items no longer read as a single debug cube. +- `AAgrarianResourceNode`: harvestable cluster and marker layered onto the + existing interactable node. +- `AAgrarianWaterSource`: stone bank, water surface, and collect marker. +- `AAgrarianWildlifeBase`: small animal body, head, ears, and tail proxy suitable + for the MVP rabbit/wildlife prototype. + +Implementation notes: + +- The existing root meshes remain responsible for actor transform, interaction, + collision, save/load, replication, and blueprint compatibility. +- Added child mesh proxies use no collision and no overlap generation so they do + not change gameplay behavior. +- The pass uses already-cooked Agrarian placeholder mesh assets and Ground Zero + material assets so packaged investor builds do not depend on uncooked editor + content. +- Final realistic art should replace these proxies without changing survival, + inventory, shelter, water, or wildlife gameplay contracts. diff --git a/Scripts/verify_mvp_readable_survival_object_proxies.py b/Scripts/verify_mvp_readable_survival_object_proxies.py new file mode 100644 index 0000000..86181fe --- /dev/null +++ b/Scripts/verify_mvp_readable_survival_object_proxies.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +"""Verify 0.1.O readable survival-object proxy coverage.""" + +from __future__ import annotations + +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +REQUIRED_SNIPPETS = { + "Source/AgrarianGame/AgrarianCampfire.h": [ + "StoneRingProxy", + "LogProxyA", + "LogProxyB", + "LogProxyC", + "EmberProxy", + ], + "Source/AgrarianGame/AgrarianCampfire.cpp": [ + "SM_AGR_Placeholder_Cylinder", + "M_AGR_GZ_Wood_Resource", + "M_AGR_GZ_Stone_Sandstone", + "ConfigureCampfireProxyComponent", + "LogProxyA->SetRelativeRotation", + ], + "Source/AgrarianGame/AgrarianShelterActor.h": [ + "FloorProxy", + "BackWallProxy", + "LeftRoofProxy", + "RightRoofProxy", + "FrameProxyA", + "FrameProxyB", + ], + "Source/AgrarianGame/AgrarianShelterActor.cpp": [ + "SM_AGR_Placeholder_ChamferCube", + "M_AGR_GZ_Fiber_Resource", + "LeftRoofProxy->SetRelativeRotation", + "ConfigureShelterProxyComponent", + ], + "Source/AgrarianGame/AgrarianWaterSource.h": [ + "WaterSurfaceProxy", + "StoneBankProxy", + "CollectMarkerProxy", + ], + "Source/AgrarianGame/AgrarianWaterSource.cpp": [ + "SM_AGR_Placeholder_Plane", + "M_AGR_GZ_FreshWater", + "WaterSurfaceProxy->SetCollisionEnabled(ECollisionEnabled::NoCollision)", + "StoneBankProxy->SetCollisionEnabled(ECollisionEnabled::NoCollision)", + ], + "Source/AgrarianGame/AgrarianItemPickup.h": [ + "BundleProxy", + "StrapProxy", + "ItemMarkerProxy", + ], + "Source/AgrarianGame/AgrarianItemPickup.cpp": [ + "BundleProxy->SetRelativeRotation", + "StrapProxy->SetCollisionEnabled(ECollisionEnabled::NoCollision)", + "ItemMarkerProxy->SetCollisionEnabled(ECollisionEnabled::NoCollision)", + ], + "Source/AgrarianGame/AgrarianResourceNode.h": [ + "ResourceClusterProxy", + "HarvestableMarkerProxy", + ], + "Source/AgrarianGame/AgrarianResourceNode.cpp": [ + "ResourceClusterProxy->SetRelativeRotation", + "HarvestableMarkerProxy->SetCollisionEnabled(ECollisionEnabled::NoCollision)", + "Mesh->SetVisibility(RemainingHarvests > 0, true)", + ], + "Source/AgrarianGame/AgrarianWildlifeBase.h": [ + "WildlifeBodyProxy", + "WildlifeHeadProxy", + "WildlifeEarProxyA", + "WildlifeEarProxyB", + "WildlifeTailProxy", + ], + "Source/AgrarianGame/AgrarianWildlifeBase.cpp": [ + "WildlifeBodyProxy->SetupAttachment(RootComponent)", + "WildlifeHeadProxy->SetupAttachment(WildlifeBodyProxy)", + "WildlifeTailProxy->SetRelativeRotation", + "ConfigureWildlifeProxyComponent", + ], + "Docs/CharactersAndObjects/MvpReadableSurvivalObjectProxies.md": [ + "MVP Readable Survival Object Proxies", + "no collision", + "Final realistic art should replace these proxies", + ], + "AGRARIAN_DEVELOPMENT_ROADMAP.md": [ + "- [x] Replace box/sphere/cylinder survival objects with readable MVP meshes", + "Added composed native proxy visuals for campfires, primitive shelters, pickups, resource nodes, water sources, and wildlife", + ], +} + + +def main() -> int: + missing: list[str] = [] + for relative_path, snippets in REQUIRED_SNIPPETS.items(): + path = ROOT / relative_path + if not path.exists(): + missing.append(f"{relative_path}: file missing") + continue + + text = path.read_text(encoding="utf-8") + for snippet in snippets: + if snippet not in text: + missing.append(f"{relative_path}: missing {snippet!r}") + + if missing: + print("Readable survival-object proxy verification failed:") + for item in missing: + print(f"- {item}") + return 1 + + print("Readable survival-object proxy verification passed.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/Source/AgrarianGame/AgrarianCampfire.cpp b/Source/AgrarianGame/AgrarianCampfire.cpp index 359652a..b2a394f 100644 --- a/Source/AgrarianGame/AgrarianCampfire.cpp +++ b/Source/AgrarianGame/AgrarianCampfire.cpp @@ -9,8 +9,33 @@ #include "Particles/ParticleSystemComponent.h" #include "Components/PointLightComponent.h" #include "Components/StaticMeshComponent.h" +#include "Engine/StaticMesh.h" #include "Kismet/GameplayStatics.h" +#include "Materials/MaterialInterface.h" #include "Net/UnrealNetwork.h" +#include "UObject/ConstructorHelpers.h" + +namespace +{ + void ConfigureCampfireProxyComponent(UStaticMeshComponent* Component, UStaticMesh* MeshAsset, UMaterialInterface* MaterialAsset) + { + if (!Component) + { + return; + } + + Component->SetCollisionEnabled(ECollisionEnabled::NoCollision); + Component->SetGenerateOverlapEvents(false); + if (MeshAsset) + { + Component->SetStaticMesh(MeshAsset); + } + if (MaterialAsset) + { + Component->SetMaterial(0, MaterialAsset); + } + } +} AAgrarianCampfire::AAgrarianCampfire() { @@ -20,6 +45,56 @@ AAgrarianCampfire::AAgrarianCampfire() Mesh = CreateDefaultSubobject(TEXT("Mesh")); RootComponent = Mesh; + Mesh->SetCollisionProfileName(TEXT("BlockAll")); + + static ConstructorHelpers::FObjectFinder CylinderMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cylinder.SM_AGR_Placeholder_Cylinder")); + static ConstructorHelpers::FObjectFinder ChamferCubeMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_ChamferCube.SM_AGR_Placeholder_ChamferCube")); + static ConstructorHelpers::FObjectFinder CubeMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cube.SM_AGR_Placeholder_Cube")); + static ConstructorHelpers::FObjectFinder StoneMaterial(TEXT("/Game/Agrarian/Materials/M_AGR_GZ_Stone_Sandstone.M_AGR_GZ_Stone_Sandstone")); + static ConstructorHelpers::FObjectFinder WoodMaterial(TEXT("/Game/Agrarian/Materials/M_AGR_GZ_Wood_Resource.M_AGR_GZ_Wood_Resource")); + static ConstructorHelpers::FObjectFinder FiberMaterial(TEXT("/Game/Agrarian/Materials/M_AGR_GZ_Fiber_Resource.M_AGR_GZ_Fiber_Resource")); + + if (CylinderMesh.Succeeded()) + { + Mesh->SetStaticMesh(CylinderMesh.Object); + Mesh->SetRelativeScale3D(FVector(0.72f, 0.72f, 0.08f)); + } + if (StoneMaterial.Succeeded()) + { + Mesh->SetMaterial(0, StoneMaterial.Object); + } + + StoneRingProxy = CreateDefaultSubobject(TEXT("StoneRingProxy")); + StoneRingProxy->SetupAttachment(RootComponent); + ConfigureCampfireProxyComponent(StoneRingProxy, CylinderMesh.Succeeded() ? CylinderMesh.Object : nullptr, StoneMaterial.Succeeded() ? StoneMaterial.Object : nullptr); + StoneRingProxy->SetRelativeScale3D(FVector(1.05f, 1.05f, 0.12f)); + + LogProxyA = CreateDefaultSubobject(TEXT("LogProxyA")); + LogProxyA->SetupAttachment(RootComponent); + ConfigureCampfireProxyComponent(LogProxyA, CylinderMesh.Succeeded() ? CylinderMesh.Object : nullptr, WoodMaterial.Succeeded() ? WoodMaterial.Object : nullptr); + LogProxyA->SetRelativeLocation(FVector(0.0f, -12.0f, 18.0f)); + LogProxyA->SetRelativeRotation(FRotator(0.0f, 90.0f, 90.0f)); + LogProxyA->SetRelativeScale3D(FVector(0.16f, 0.16f, 0.72f)); + + LogProxyB = CreateDefaultSubobject(TEXT("LogProxyB")); + LogProxyB->SetupAttachment(RootComponent); + ConfigureCampfireProxyComponent(LogProxyB, CylinderMesh.Succeeded() ? CylinderMesh.Object : nullptr, WoodMaterial.Succeeded() ? WoodMaterial.Object : nullptr); + LogProxyB->SetRelativeLocation(FVector(-12.0f, 10.0f, 20.0f)); + LogProxyB->SetRelativeRotation(FRotator(0.0f, 28.0f, 90.0f)); + LogProxyB->SetRelativeScale3D(FVector(0.16f, 0.16f, 0.68f)); + + LogProxyC = CreateDefaultSubobject(TEXT("LogProxyC")); + LogProxyC->SetupAttachment(RootComponent); + ConfigureCampfireProxyComponent(LogProxyC, CylinderMesh.Succeeded() ? CylinderMesh.Object : nullptr, WoodMaterial.Succeeded() ? WoodMaterial.Object : nullptr); + LogProxyC->SetRelativeLocation(FVector(12.0f, 10.0f, 22.0f)); + LogProxyC->SetRelativeRotation(FRotator(0.0f, -28.0f, 90.0f)); + LogProxyC->SetRelativeScale3D(FVector(0.16f, 0.16f, 0.68f)); + + EmberProxy = CreateDefaultSubobject(TEXT("EmberProxy")); + EmberProxy->SetupAttachment(RootComponent); + ConfigureCampfireProxyComponent(EmberProxy, ChamferCubeMesh.Succeeded() ? ChamferCubeMesh.Object : (CubeMesh.Succeeded() ? CubeMesh.Object : nullptr), FiberMaterial.Succeeded() ? FiberMaterial.Object : nullptr); + EmberProxy->SetRelativeLocation(FVector(0.0f, 0.0f, 13.0f)); + EmberProxy->SetRelativeScale3D(FVector(0.38f, 0.38f, 0.09f)); FireLight = CreateDefaultSubobject(TEXT("FireLight")); FireLight->SetupAttachment(RootComponent); diff --git a/Source/AgrarianGame/AgrarianCampfire.h b/Source/AgrarianGame/AgrarianCampfire.h index f44bd5d..a620a84 100644 --- a/Source/AgrarianGame/AgrarianCampfire.h +++ b/Source/AgrarianGame/AgrarianCampfire.h @@ -28,6 +28,21 @@ public: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Fire") TObjectPtr Mesh; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Fire|Visuals") + TObjectPtr StoneRingProxy; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Fire|Visuals") + TObjectPtr LogProxyA; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Fire|Visuals") + TObjectPtr LogProxyB; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Fire|Visuals") + TObjectPtr LogProxyC; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Fire|Visuals") + TObjectPtr EmberProxy; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Fire") TObjectPtr FireLight; diff --git a/Source/AgrarianGame/AgrarianItemPickup.cpp b/Source/AgrarianGame/AgrarianItemPickup.cpp index 72b60f2..2aac3d3 100644 --- a/Source/AgrarianGame/AgrarianItemPickup.cpp +++ b/Source/AgrarianGame/AgrarianItemPickup.cpp @@ -5,6 +5,9 @@ #include "AgrarianInventoryComponent.h" #include "AgrarianItemDefinitionAsset.h" #include "Components/StaticMeshComponent.h" +#include "Engine/StaticMesh.h" +#include "Materials/MaterialInterface.h" +#include "UObject/ConstructorHelpers.h" AAgrarianItemPickup::AAgrarianItemPickup() { @@ -15,6 +18,68 @@ AAgrarianItemPickup::AAgrarianItemPickup() RootComponent = Mesh; Mesh->SetCollisionProfileName(TEXT("BlockAll")); + static ConstructorHelpers::FObjectFinder ChamferCubeMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_ChamferCube.SM_AGR_Placeholder_ChamferCube")); + static ConstructorHelpers::FObjectFinder CubeMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cube.SM_AGR_Placeholder_Cube")); + static ConstructorHelpers::FObjectFinder CylinderMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cylinder.SM_AGR_Placeholder_Cylinder")); + static ConstructorHelpers::FObjectFinder WoodMaterial(TEXT("/Game/Agrarian/Materials/M_AGR_GZ_Wood_Resource.M_AGR_GZ_Wood_Resource")); + static ConstructorHelpers::FObjectFinder FiberMaterial(TEXT("/Game/Agrarian/Materials/M_AGR_GZ_Fiber_Resource.M_AGR_GZ_Fiber_Resource")); + + if (ChamferCubeMesh.Succeeded()) + { + Mesh->SetStaticMesh(ChamferCubeMesh.Object); + Mesh->SetRelativeScale3D(FVector(0.42f, 0.32f, 0.2f)); + } + if (WoodMaterial.Succeeded()) + { + Mesh->SetMaterial(0, WoodMaterial.Object); + } + + BundleProxy = CreateDefaultSubobject(TEXT("BundleProxy")); + BundleProxy->SetupAttachment(RootComponent); + BundleProxy->SetCollisionEnabled(ECollisionEnabled::NoCollision); + BundleProxy->SetGenerateOverlapEvents(false); + if (CylinderMesh.Succeeded()) + { + BundleProxy->SetStaticMesh(CylinderMesh.Object); + } + if (WoodMaterial.Succeeded()) + { + BundleProxy->SetMaterial(0, WoodMaterial.Object); + } + BundleProxy->SetRelativeLocation(FVector(0.0f, 0.0f, 16.0f)); + BundleProxy->SetRelativeRotation(FRotator(0.0f, 90.0f, 90.0f)); + BundleProxy->SetRelativeScale3D(FVector(0.12f, 0.12f, 0.58f)); + + StrapProxy = CreateDefaultSubobject(TEXT("StrapProxy")); + StrapProxy->SetupAttachment(RootComponent); + StrapProxy->SetCollisionEnabled(ECollisionEnabled::NoCollision); + StrapProxy->SetGenerateOverlapEvents(false); + if (CubeMesh.Succeeded()) + { + StrapProxy->SetStaticMesh(CubeMesh.Object); + } + if (FiberMaterial.Succeeded()) + { + StrapProxy->SetMaterial(0, FiberMaterial.Object); + } + StrapProxy->SetRelativeLocation(FVector(0.0f, 0.0f, 18.0f)); + StrapProxy->SetRelativeScale3D(FVector(0.08f, 0.54f, 0.08f)); + + ItemMarkerProxy = CreateDefaultSubobject(TEXT("ItemMarkerProxy")); + ItemMarkerProxy->SetupAttachment(RootComponent); + ItemMarkerProxy->SetCollisionEnabled(ECollisionEnabled::NoCollision); + ItemMarkerProxy->SetGenerateOverlapEvents(false); + if (CubeMesh.Succeeded()) + { + ItemMarkerProxy->SetStaticMesh(CubeMesh.Object); + } + if (FiberMaterial.Succeeded()) + { + ItemMarkerProxy->SetMaterial(0, FiberMaterial.Object); + } + ItemMarkerProxy->SetRelativeLocation(FVector(0.0f, -18.0f, 26.0f)); + ItemMarkerProxy->SetRelativeScale3D(FVector(0.16f, 0.04f, 0.16f)); + PickupStack.ItemId = TEXT("wood"); PickupStack.DisplayName = FText::FromString(TEXT("Wood")); PickupStack.Quantity = 1; diff --git a/Source/AgrarianGame/AgrarianItemPickup.h b/Source/AgrarianGame/AgrarianItemPickup.h index 23cdfd4..b4a584e 100644 --- a/Source/AgrarianGame/AgrarianItemPickup.h +++ b/Source/AgrarianGame/AgrarianItemPickup.h @@ -23,6 +23,15 @@ public: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Pickup") TObjectPtr Mesh; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Pickup|Visuals") + TObjectPtr BundleProxy; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Pickup|Visuals") + TObjectPtr StrapProxy; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Pickup|Visuals") + TObjectPtr ItemMarkerProxy; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Pickup") FAgrarianItemStack PickupStack; diff --git a/Source/AgrarianGame/AgrarianResourceNode.cpp b/Source/AgrarianGame/AgrarianResourceNode.cpp index b75c1a6..584f139 100644 --- a/Source/AgrarianGame/AgrarianResourceNode.cpp +++ b/Source/AgrarianGame/AgrarianResourceNode.cpp @@ -6,8 +6,11 @@ #include "AgrarianItemDefinitionAsset.h" #include "AgrarianSaveGame.h" #include "Components/StaticMeshComponent.h" +#include "Engine/StaticMesh.h" +#include "Materials/MaterialInterface.h" #include "TimerManager.h" #include "Net/UnrealNetwork.h" +#include "UObject/ConstructorHelpers.h" AAgrarianResourceNode::AAgrarianResourceNode() { @@ -18,6 +21,52 @@ AAgrarianResourceNode::AAgrarianResourceNode() RootComponent = Mesh; Mesh->SetCollisionProfileName(TEXT("BlockAll")); + static ConstructorHelpers::FObjectFinder ChamferCubeMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_ChamferCube.SM_AGR_Placeholder_ChamferCube")); + static ConstructorHelpers::FObjectFinder CylinderMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cylinder.SM_AGR_Placeholder_Cylinder")); + static ConstructorHelpers::FObjectFinder WoodMaterial(TEXT("/Game/Agrarian/Materials/M_AGR_GZ_Wood_Resource.M_AGR_GZ_Wood_Resource")); + static ConstructorHelpers::FObjectFinder FiberMaterial(TEXT("/Game/Agrarian/Materials/M_AGR_GZ_Fiber_Resource.M_AGR_GZ_Fiber_Resource")); + + if (ChamferCubeMesh.Succeeded()) + { + Mesh->SetStaticMesh(ChamferCubeMesh.Object); + Mesh->SetRelativeScale3D(FVector(0.8f, 0.58f, 0.44f)); + } + if (WoodMaterial.Succeeded()) + { + Mesh->SetMaterial(0, WoodMaterial.Object); + } + + ResourceClusterProxy = CreateDefaultSubobject(TEXT("ResourceClusterProxy")); + ResourceClusterProxy->SetupAttachment(RootComponent); + ResourceClusterProxy->SetCollisionEnabled(ECollisionEnabled::NoCollision); + ResourceClusterProxy->SetGenerateOverlapEvents(false); + if (CylinderMesh.Succeeded()) + { + ResourceClusterProxy->SetStaticMesh(CylinderMesh.Object); + } + if (WoodMaterial.Succeeded()) + { + ResourceClusterProxy->SetMaterial(0, WoodMaterial.Object); + } + ResourceClusterProxy->SetRelativeLocation(FVector(0.0f, -18.0f, 28.0f)); + ResourceClusterProxy->SetRelativeRotation(FRotator(0.0f, 90.0f, 90.0f)); + ResourceClusterProxy->SetRelativeScale3D(FVector(0.12f, 0.12f, 0.7f)); + + HarvestableMarkerProxy = CreateDefaultSubobject(TEXT("HarvestableMarkerProxy")); + HarvestableMarkerProxy->SetupAttachment(RootComponent); + HarvestableMarkerProxy->SetCollisionEnabled(ECollisionEnabled::NoCollision); + HarvestableMarkerProxy->SetGenerateOverlapEvents(false); + if (ChamferCubeMesh.Succeeded()) + { + HarvestableMarkerProxy->SetStaticMesh(ChamferCubeMesh.Object); + } + if (FiberMaterial.Succeeded()) + { + HarvestableMarkerProxy->SetMaterial(0, FiberMaterial.Object); + } + HarvestableMarkerProxy->SetRelativeLocation(FVector(0.0f, 22.0f, 36.0f)); + HarvestableMarkerProxy->SetRelativeScale3D(FVector(0.28f, 0.18f, 0.22f)); + YieldItem.ItemId = TEXT("wood"); YieldItem.DisplayName = FText::FromString(TEXT("Wood")); YieldItem.Quantity = 1; diff --git a/Source/AgrarianGame/AgrarianResourceNode.h b/Source/AgrarianGame/AgrarianResourceNode.h index 7c9bea2..bf20a84 100644 --- a/Source/AgrarianGame/AgrarianResourceNode.h +++ b/Source/AgrarianGame/AgrarianResourceNode.h @@ -27,6 +27,12 @@ public: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Resource") TObjectPtr Mesh; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Resource|Visuals") + TObjectPtr ResourceClusterProxy; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Resource|Visuals") + TObjectPtr HarvestableMarkerProxy; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Resource") FAgrarianItemStack YieldItem; diff --git a/Source/AgrarianGame/AgrarianShelterActor.cpp b/Source/AgrarianGame/AgrarianShelterActor.cpp index 44d3135..f807aed 100644 --- a/Source/AgrarianGame/AgrarianShelterActor.cpp +++ b/Source/AgrarianGame/AgrarianShelterActor.cpp @@ -4,7 +4,32 @@ #include "AgrarianPersistentActorComponent.h" #include "Components/BoxComponent.h" #include "Components/StaticMeshComponent.h" +#include "Engine/StaticMesh.h" +#include "Materials/MaterialInterface.h" #include "Net/UnrealNetwork.h" +#include "UObject/ConstructorHelpers.h" + +namespace +{ + void ConfigureShelterProxyComponent(UStaticMeshComponent* Component, UStaticMesh* MeshAsset, UMaterialInterface* MaterialAsset) + { + if (!Component) + { + return; + } + + Component->SetCollisionEnabled(ECollisionEnabled::NoCollision); + Component->SetGenerateOverlapEvents(false); + if (MeshAsset) + { + Component->SetStaticMesh(MeshAsset); + } + if (MaterialAsset) + { + Component->SetMaterial(0, MaterialAsset); + } + } +} AAgrarianShelterActor::AAgrarianShelterActor() { @@ -13,6 +38,63 @@ AAgrarianShelterActor::AAgrarianShelterActor() Mesh = CreateDefaultSubobject(TEXT("Mesh")); RootComponent = Mesh; + Mesh->SetCollisionProfileName(TEXT("BlockAll")); + + static ConstructorHelpers::FObjectFinder CubeMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cube.SM_AGR_Placeholder_Cube")); + static ConstructorHelpers::FObjectFinder ChamferCubeMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_ChamferCube.SM_AGR_Placeholder_ChamferCube")); + static ConstructorHelpers::FObjectFinder CylinderMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cylinder.SM_AGR_Placeholder_Cylinder")); + static ConstructorHelpers::FObjectFinder WoodMaterial(TEXT("/Game/Agrarian/Materials/M_AGR_GZ_Wood_Resource.M_AGR_GZ_Wood_Resource")); + static ConstructorHelpers::FObjectFinder FiberMaterial(TEXT("/Game/Agrarian/Materials/M_AGR_GZ_Fiber_Resource.M_AGR_GZ_Fiber_Resource")); + + if (CubeMesh.Succeeded()) + { + Mesh->SetStaticMesh(CubeMesh.Object); + Mesh->SetRelativeScale3D(FVector(3.2f, 2.6f, 0.08f)); + } + if (WoodMaterial.Succeeded()) + { + Mesh->SetMaterial(0, WoodMaterial.Object); + } + + FloorProxy = CreateDefaultSubobject(TEXT("FloorProxy")); + FloorProxy->SetupAttachment(RootComponent); + ConfigureShelterProxyComponent(FloorProxy, CubeMesh.Succeeded() ? CubeMesh.Object : nullptr, WoodMaterial.Succeeded() ? WoodMaterial.Object : nullptr); + FloorProxy->SetRelativeLocation(FVector(0.0f, 0.0f, 10.0f)); + FloorProxy->SetRelativeScale3D(FVector(3.0f, 2.4f, 0.08f)); + + BackWallProxy = CreateDefaultSubobject(TEXT("BackWallProxy")); + BackWallProxy->SetupAttachment(RootComponent); + ConfigureShelterProxyComponent(BackWallProxy, CubeMesh.Succeeded() ? CubeMesh.Object : nullptr, FiberMaterial.Succeeded() ? FiberMaterial.Object : nullptr); + BackWallProxy->SetRelativeLocation(FVector(-140.0f, 0.0f, 105.0f)); + BackWallProxy->SetRelativeScale3D(FVector(0.14f, 2.2f, 1.5f)); + + LeftRoofProxy = CreateDefaultSubobject(TEXT("LeftRoofProxy")); + LeftRoofProxy->SetupAttachment(RootComponent); + ConfigureShelterProxyComponent(LeftRoofProxy, ChamferCubeMesh.Succeeded() ? ChamferCubeMesh.Object : (CubeMesh.Succeeded() ? CubeMesh.Object : nullptr), FiberMaterial.Succeeded() ? FiberMaterial.Object : nullptr); + LeftRoofProxy->SetRelativeLocation(FVector(8.0f, -82.0f, 168.0f)); + LeftRoofProxy->SetRelativeRotation(FRotator(0.0f, 0.0f, -24.0f)); + LeftRoofProxy->SetRelativeScale3D(FVector(3.1f, 0.16f, 1.45f)); + + RightRoofProxy = CreateDefaultSubobject(TEXT("RightRoofProxy")); + RightRoofProxy->SetupAttachment(RootComponent); + ConfigureShelterProxyComponent(RightRoofProxy, ChamferCubeMesh.Succeeded() ? ChamferCubeMesh.Object : (CubeMesh.Succeeded() ? CubeMesh.Object : nullptr), FiberMaterial.Succeeded() ? FiberMaterial.Object : nullptr); + RightRoofProxy->SetRelativeLocation(FVector(8.0f, 82.0f, 168.0f)); + RightRoofProxy->SetRelativeRotation(FRotator(0.0f, 0.0f, 24.0f)); + RightRoofProxy->SetRelativeScale3D(FVector(3.1f, 0.16f, 1.45f)); + + FrameProxyA = CreateDefaultSubobject(TEXT("FrameProxyA")); + FrameProxyA->SetupAttachment(RootComponent); + ConfigureShelterProxyComponent(FrameProxyA, CylinderMesh.Succeeded() ? CylinderMesh.Object : nullptr, WoodMaterial.Succeeded() ? WoodMaterial.Object : nullptr); + FrameProxyA->SetRelativeLocation(FVector(95.0f, -94.0f, 96.0f)); + FrameProxyA->SetRelativeRotation(FRotator(0.0f, 0.0f, -12.0f)); + FrameProxyA->SetRelativeScale3D(FVector(0.12f, 0.12f, 1.92f)); + + FrameProxyB = CreateDefaultSubobject(TEXT("FrameProxyB")); + FrameProxyB->SetupAttachment(RootComponent); + ConfigureShelterProxyComponent(FrameProxyB, CylinderMesh.Succeeded() ? CylinderMesh.Object : nullptr, WoodMaterial.Succeeded() ? WoodMaterial.Object : nullptr); + FrameProxyB->SetRelativeLocation(FVector(95.0f, 94.0f, 96.0f)); + FrameProxyB->SetRelativeRotation(FRotator(0.0f, 0.0f, 12.0f)); + FrameProxyB->SetRelativeScale3D(FVector(0.12f, 0.12f, 1.92f)); ProtectionVolume = CreateDefaultSubobject(TEXT("ProtectionVolume")); ProtectionVolume->SetupAttachment(RootComponent); diff --git a/Source/AgrarianGame/AgrarianShelterActor.h b/Source/AgrarianGame/AgrarianShelterActor.h index b8a4fad..9fb6314 100644 --- a/Source/AgrarianGame/AgrarianShelterActor.h +++ b/Source/AgrarianGame/AgrarianShelterActor.h @@ -28,6 +28,24 @@ public: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Shelter") TObjectPtr Mesh; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Shelter|Visuals") + TObjectPtr FloorProxy; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Shelter|Visuals") + TObjectPtr BackWallProxy; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Shelter|Visuals") + TObjectPtr LeftRoofProxy; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Shelter|Visuals") + TObjectPtr RightRoofProxy; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Shelter|Visuals") + TObjectPtr FrameProxyA; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Shelter|Visuals") + TObjectPtr FrameProxyB; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Shelter") TObjectPtr ProtectionVolume; diff --git a/Source/AgrarianGame/AgrarianWaterSource.cpp b/Source/AgrarianGame/AgrarianWaterSource.cpp index 398c4aa..afa931a 100644 --- a/Source/AgrarianGame/AgrarianWaterSource.cpp +++ b/Source/AgrarianGame/AgrarianWaterSource.cpp @@ -5,6 +5,9 @@ #include "AgrarianGameCharacter.h" #include "AgrarianSurvivalComponent.h" #include "Components/StaticMeshComponent.h" +#include "Engine/StaticMesh.h" +#include "Materials/MaterialInterface.h" +#include "UObject/ConstructorHelpers.h" AAgrarianWaterSource::AAgrarianWaterSource() { @@ -15,6 +18,66 @@ AAgrarianWaterSource::AAgrarianWaterSource() RootComponent = Mesh; Mesh->SetCollisionProfileName(TEXT("BlockAll")); + static ConstructorHelpers::FObjectFinder PlaneMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Plane.SM_AGR_Placeholder_Plane")); + static ConstructorHelpers::FObjectFinder CylinderMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cylinder.SM_AGR_Placeholder_Cylinder")); + static ConstructorHelpers::FObjectFinder CubeMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cube.SM_AGR_Placeholder_Cube")); + static ConstructorHelpers::FObjectFinder WaterMaterial(TEXT("/Game/Agrarian/Materials/M_AGR_GZ_FreshWater.M_AGR_GZ_FreshWater")); + static ConstructorHelpers::FObjectFinder StoneMaterial(TEXT("/Game/Agrarian/Materials/M_AGR_GZ_Stone_Sandstone.M_AGR_GZ_Stone_Sandstone")); + + if (CylinderMesh.Succeeded()) + { + Mesh->SetStaticMesh(CylinderMesh.Object); + Mesh->SetRelativeScale3D(FVector(2.4f, 1.7f, 0.08f)); + } + if (StoneMaterial.Succeeded()) + { + Mesh->SetMaterial(0, StoneMaterial.Object); + } + + WaterSurfaceProxy = CreateDefaultSubobject(TEXT("WaterSurfaceProxy")); + WaterSurfaceProxy->SetupAttachment(RootComponent); + WaterSurfaceProxy->SetCollisionEnabled(ECollisionEnabled::NoCollision); + WaterSurfaceProxy->SetGenerateOverlapEvents(false); + if (PlaneMesh.Succeeded()) + { + WaterSurfaceProxy->SetStaticMesh(PlaneMesh.Object); + } + if (WaterMaterial.Succeeded()) + { + WaterSurfaceProxy->SetMaterial(0, WaterMaterial.Object); + } + WaterSurfaceProxy->SetRelativeLocation(FVector(0.0f, 0.0f, 8.0f)); + WaterSurfaceProxy->SetRelativeScale3D(FVector(2.15f, 1.45f, 1.0f)); + + StoneBankProxy = CreateDefaultSubobject(TEXT("StoneBankProxy")); + StoneBankProxy->SetupAttachment(RootComponent); + StoneBankProxy->SetCollisionEnabled(ECollisionEnabled::NoCollision); + StoneBankProxy->SetGenerateOverlapEvents(false); + if (CylinderMesh.Succeeded()) + { + StoneBankProxy->SetStaticMesh(CylinderMesh.Object); + } + if (StoneMaterial.Succeeded()) + { + StoneBankProxy->SetMaterial(0, StoneMaterial.Object); + } + StoneBankProxy->SetRelativeScale3D(FVector(2.55f, 1.85f, 0.05f)); + + CollectMarkerProxy = CreateDefaultSubobject(TEXT("CollectMarkerProxy")); + CollectMarkerProxy->SetupAttachment(RootComponent); + CollectMarkerProxy->SetCollisionEnabled(ECollisionEnabled::NoCollision); + CollectMarkerProxy->SetGenerateOverlapEvents(false); + if (CubeMesh.Succeeded()) + { + CollectMarkerProxy->SetStaticMesh(CubeMesh.Object); + } + if (WaterMaterial.Succeeded()) + { + CollectMarkerProxy->SetMaterial(0, WaterMaterial.Object); + } + CollectMarkerProxy->SetRelativeLocation(FVector(0.0f, -84.0f, 24.0f)); + CollectMarkerProxy->SetRelativeScale3D(FVector(0.22f, 0.08f, 0.32f)); + DisplayName = FText::FromString(TEXT("Fresh Water")); } diff --git a/Source/AgrarianGame/AgrarianWaterSource.h b/Source/AgrarianGame/AgrarianWaterSource.h index eae3b5a..0f50367 100644 --- a/Source/AgrarianGame/AgrarianWaterSource.h +++ b/Source/AgrarianGame/AgrarianWaterSource.h @@ -20,6 +20,15 @@ public: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Water") TObjectPtr Mesh; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Water|Visuals") + TObjectPtr WaterSurfaceProxy; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Water|Visuals") + TObjectPtr StoneBankProxy; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Water|Visuals") + TObjectPtr CollectMarkerProxy; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Water", meta = (ClampMin = "0")) float WaterRestoreAmount = 45.0f; diff --git a/Source/AgrarianGame/AgrarianWildlifeBase.cpp b/Source/AgrarianGame/AgrarianWildlifeBase.cpp index 275171f..68045ad 100644 --- a/Source/AgrarianGame/AgrarianWildlifeBase.cpp +++ b/Source/AgrarianGame/AgrarianWildlifeBase.cpp @@ -4,11 +4,37 @@ #include "AgrarianGameCharacter.h" #include "AgrarianInventoryComponent.h" #include "AIController.h" +#include "Components/StaticMeshComponent.h" +#include "Engine/StaticMesh.h" #include "GameFramework/CharacterMovementComponent.h" #include "Kismet/GameplayStatics.h" +#include "Materials/MaterialInterface.h" #include "Navigation/PathFollowingComponent.h" #include "NavigationSystem.h" #include "Net/UnrealNetwork.h" +#include "UObject/ConstructorHelpers.h" + +namespace +{ + void ConfigureWildlifeProxyComponent(UStaticMeshComponent* Component, UStaticMesh* MeshAsset, UMaterialInterface* MaterialAsset) + { + if (!Component) + { + return; + } + + Component->SetCollisionEnabled(ECollisionEnabled::NoCollision); + Component->SetGenerateOverlapEvents(false); + if (MeshAsset) + { + Component->SetStaticMesh(MeshAsset); + } + if (MaterialAsset) + { + Component->SetMaterial(0, MaterialAsset); + } + } +} AAgrarianWildlifeBase::AAgrarianWildlifeBase() { @@ -22,6 +48,44 @@ AAgrarianWildlifeBase::AAgrarianWildlifeBase() GetCharacterMovement()->bOrientRotationToMovement = true; bUseControllerRotationYaw = false; + static ConstructorHelpers::FObjectFinder ChamferCubeMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_ChamferCube.SM_AGR_Placeholder_ChamferCube")); + static ConstructorHelpers::FObjectFinder CubeMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cube.SM_AGR_Placeholder_Cube")); + static ConstructorHelpers::FObjectFinder CylinderMesh(TEXT("/Game/Agrarian/Environment/PlaceholderMeshes/SM_AGR_Placeholder_Cylinder.SM_AGR_Placeholder_Cylinder")); + static ConstructorHelpers::FObjectFinder FurMaterial(TEXT("/Game/Agrarian/Materials/M_AGR_GZ_Fiber_Resource.M_AGR_GZ_Fiber_Resource")); + + WildlifeBodyProxy = CreateDefaultSubobject(TEXT("WildlifeBodyProxy")); + WildlifeBodyProxy->SetupAttachment(RootComponent); + ConfigureWildlifeProxyComponent(WildlifeBodyProxy, ChamferCubeMesh.Succeeded() ? ChamferCubeMesh.Object : nullptr, FurMaterial.Succeeded() ? FurMaterial.Object : nullptr); + WildlifeBodyProxy->SetRelativeLocation(FVector(10.0f, 0.0f, -42.0f)); + WildlifeBodyProxy->SetRelativeScale3D(FVector(0.62f, 0.32f, 0.24f)); + + WildlifeHeadProxy = CreateDefaultSubobject(TEXT("WildlifeHeadProxy")); + WildlifeHeadProxy->SetupAttachment(WildlifeBodyProxy); + ConfigureWildlifeProxyComponent(WildlifeHeadProxy, ChamferCubeMesh.Succeeded() ? ChamferCubeMesh.Object : nullptr, FurMaterial.Succeeded() ? FurMaterial.Object : nullptr); + WildlifeHeadProxy->SetRelativeLocation(FVector(42.0f, 0.0f, 20.0f)); + WildlifeHeadProxy->SetRelativeScale3D(FVector(0.46f, 0.34f, 0.36f)); + + WildlifeEarProxyA = CreateDefaultSubobject(TEXT("WildlifeEarProxyA")); + WildlifeEarProxyA->SetupAttachment(WildlifeHeadProxy); + ConfigureWildlifeProxyComponent(WildlifeEarProxyA, CubeMesh.Succeeded() ? CubeMesh.Object : nullptr, FurMaterial.Succeeded() ? FurMaterial.Object : nullptr); + WildlifeEarProxyA->SetRelativeLocation(FVector(4.0f, -12.0f, 28.0f)); + WildlifeEarProxyA->SetRelativeRotation(FRotator(0.0f, 0.0f, -10.0f)); + WildlifeEarProxyA->SetRelativeScale3D(FVector(0.08f, 0.08f, 0.38f)); + + WildlifeEarProxyB = CreateDefaultSubobject(TEXT("WildlifeEarProxyB")); + WildlifeEarProxyB->SetupAttachment(WildlifeHeadProxy); + ConfigureWildlifeProxyComponent(WildlifeEarProxyB, CubeMesh.Succeeded() ? CubeMesh.Object : nullptr, FurMaterial.Succeeded() ? FurMaterial.Object : nullptr); + WildlifeEarProxyB->SetRelativeLocation(FVector(4.0f, 12.0f, 28.0f)); + WildlifeEarProxyB->SetRelativeRotation(FRotator(0.0f, 0.0f, 10.0f)); + WildlifeEarProxyB->SetRelativeScale3D(FVector(0.08f, 0.08f, 0.38f)); + + WildlifeTailProxy = CreateDefaultSubobject(TEXT("WildlifeTailProxy")); + WildlifeTailProxy->SetupAttachment(WildlifeBodyProxy); + ConfigureWildlifeProxyComponent(WildlifeTailProxy, CylinderMesh.Succeeded() ? CylinderMesh.Object : nullptr, FurMaterial.Succeeded() ? FurMaterial.Object : nullptr); + WildlifeTailProxy->SetRelativeLocation(FVector(-42.0f, 0.0f, 10.0f)); + WildlifeTailProxy->SetRelativeRotation(FRotator(0.0f, 90.0f, 90.0f)); + WildlifeTailProxy->SetRelativeScale3D(FVector(0.12f, 0.12f, 0.24f)); + DisplayName = FText::FromString(TEXT("Wildlife")); } diff --git a/Source/AgrarianGame/AgrarianWildlifeBase.h b/Source/AgrarianGame/AgrarianWildlifeBase.h index 188c8bf..2d38c7e 100644 --- a/Source/AgrarianGame/AgrarianWildlifeBase.h +++ b/Source/AgrarianGame/AgrarianWildlifeBase.h @@ -9,6 +9,7 @@ #include "AgrarianWildlifeBase.generated.h" class AAgrarianGameCharacter; +class UStaticMeshComponent; DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAgrarianWildlifeStateChangedSignature, EAgrarianWildlifeState, NewState); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FAgrarianWildlifeHealthChangedSignature, float, Health, float, MaxHealth); @@ -30,6 +31,21 @@ public: UPROPERTY(BlueprintAssignable, Category = "Agrarian|Wildlife") FAgrarianWildlifeHealthChangedSignature OnWildlifeHealthChanged; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Wildlife|Visuals") + TObjectPtr WildlifeBodyProxy; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Wildlife|Visuals") + TObjectPtr WildlifeHeadProxy; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Wildlife|Visuals") + TObjectPtr WildlifeEarProxyA; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Wildlife|Visuals") + TObjectPtr WildlifeEarProxyB; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Wildlife|Visuals") + TObjectPtr WildlifeTailProxy; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife") FName WildlifeId = TEXT("wildlife");