Add item data assets and building placement foundation
This commit is contained in:
@@ -18,6 +18,12 @@
|
|||||||
- [x] Character now owns survival, inventory, and crafting components.
|
- [x] Character now owns survival, inventory, and crafting components.
|
||||||
- [x] Character has server-authoritative interaction path.
|
- [x] Character has server-authoritative interaction path.
|
||||||
- [x] Git ignore and Git LFS attribute prep files added.
|
- [x] Git ignore and Git LFS attribute prep files added.
|
||||||
|
- [x] Item definition data asset class added.
|
||||||
|
- [x] Recipe data asset class added.
|
||||||
|
- [x] Crafting component can load recipes from data assets.
|
||||||
|
- [x] Resource nodes can use item definition assets for harvest yields.
|
||||||
|
- [x] Building placement component added.
|
||||||
|
- [x] Character now owns a building placement component.
|
||||||
|
|
||||||
## Next Unreal Editor Tasks
|
## Next Unreal Editor Tasks
|
||||||
|
|
||||||
@@ -36,9 +42,9 @@
|
|||||||
|
|
||||||
## Next C++ Foundation Tasks
|
## Next C++ Foundation Tasks
|
||||||
|
|
||||||
- [ ] Add building placement component.
|
- [x] Add building placement component.
|
||||||
- [ ] Add simple crafting recipe defaults or data asset pipeline.
|
- [x] Add simple crafting recipe defaults or data asset pipeline.
|
||||||
- [ ] Add item definition data asset class.
|
- [x] Add item definition data asset class.
|
||||||
- [ ] Add save/load capture for placed actors.
|
- [ ] Add save/load capture for placed actors.
|
||||||
- [ ] Add admin/dev console commands.
|
- [ ] Add admin/dev console commands.
|
||||||
- [ ] Add wildlife base actor.
|
- [ ] Add wildlife base actor.
|
||||||
|
|||||||
@@ -0,0 +1,204 @@
|
|||||||
|
// Copyright Pacificao. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "AgrarianBuildingPlacementComponent.h"
|
||||||
|
#include "AgrarianInventoryComponent.h"
|
||||||
|
#include "GameFramework/Pawn.h"
|
||||||
|
#include "GameFramework/Controller.h"
|
||||||
|
#include "Engine/World.h"
|
||||||
|
|
||||||
|
UAgrarianBuildingPlacementComponent::UAgrarianBuildingPlacementComponent()
|
||||||
|
{
|
||||||
|
PrimaryComponentTick.bCanEverTick = false;
|
||||||
|
SetIsReplicatedByDefault(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UAgrarianBuildingPlacementComponent::SetActiveBuildable(TSubclassOf<AActor> BuildClass, const TArray<FAgrarianItemStack>& Cost)
|
||||||
|
{
|
||||||
|
ActiveBuildClass = BuildClass;
|
||||||
|
PlacementCost = Cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UAgrarianBuildingPlacementComponent::GetPlacementPreview(FTransform& OutTransform, FText& FailureReason) const
|
||||||
|
{
|
||||||
|
const APawn* OwnerPawn = Cast<APawn>(GetOwner());
|
||||||
|
if (!OwnerPawn)
|
||||||
|
{
|
||||||
|
FailureReason = FText::FromString(TEXT("Only pawns can place buildables."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FVector ViewLocation;
|
||||||
|
FRotator ViewRotation;
|
||||||
|
if (OwnerPawn->GetController())
|
||||||
|
{
|
||||||
|
OwnerPawn->GetController()->GetPlayerViewPoint(ViewLocation, ViewRotation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ViewLocation = OwnerPawn->GetActorLocation();
|
||||||
|
ViewRotation = OwnerPawn->GetActorRotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
const FVector TraceEnd = ViewLocation + ViewRotation.Vector() * PlacementDistance;
|
||||||
|
FHitResult Hit;
|
||||||
|
FCollisionQueryParams Params(SCENE_QUERY_STAT(AgrarianBuildPlacementTrace), false, OwnerPawn);
|
||||||
|
|
||||||
|
FVector PlacementLocation = TraceEnd;
|
||||||
|
if (GetWorld() && GetWorld()->LineTraceSingleByChannel(Hit, ViewLocation, TraceEnd, ECC_Visibility, Params))
|
||||||
|
{
|
||||||
|
PlacementLocation = Hit.ImpactPoint + Hit.ImpactNormal * SurfaceOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlacementLocation = SnapLocation(PlacementLocation);
|
||||||
|
const FRotator PlacementRotation(0.0f, OwnerPawn->GetActorRotation().Yaw, 0.0f);
|
||||||
|
OutTransform = FTransform(PlacementRotation, PlacementLocation);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UAgrarianBuildingPlacementComponent::CanPlaceAtTransform(TSubclassOf<AActor> BuildClass, const FTransform& PlacementTransform, FText& FailureReason) const
|
||||||
|
{
|
||||||
|
if (!BuildClass)
|
||||||
|
{
|
||||||
|
FailureReason = FText::FromString(TEXT("No buildable is selected."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AActor* OwnerActor = GetOwner();
|
||||||
|
if (!OwnerActor)
|
||||||
|
{
|
||||||
|
FailureReason = FText::FromString(TEXT("No owner is available."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FVector::DistSquared(OwnerActor->GetActorLocation(), PlacementTransform.GetLocation()) > FMath::Square(PlacementDistance + 150.0f))
|
||||||
|
{
|
||||||
|
FailureReason = FText::FromString(TEXT("Placement is too far away."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetWorld())
|
||||||
|
{
|
||||||
|
FailureReason = FText::FromString(TEXT("No world is available."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FCollisionQueryParams Params(SCENE_QUERY_STAT(AgrarianBuildPlacementProbe), false, OwnerActor);
|
||||||
|
const bool bBlocked = GetWorld()->OverlapBlockingTestByChannel(
|
||||||
|
PlacementTransform.GetLocation() + FVector(0.0f, 0.0f, PlacementProbeRadius),
|
||||||
|
PlacementTransform.GetRotation(),
|
||||||
|
ECC_WorldDynamic,
|
||||||
|
FCollisionShape::MakeSphere(PlacementProbeRadius),
|
||||||
|
Params);
|
||||||
|
|
||||||
|
if (bBlocked)
|
||||||
|
{
|
||||||
|
FailureReason = FText::FromString(TEXT("Placement area is blocked."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UAgrarianBuildingPlacementComponent::PlaceActiveBuildable()
|
||||||
|
{
|
||||||
|
FTransform PlacementTransform;
|
||||||
|
FText FailureReason;
|
||||||
|
if (!GetPlacementPreview(PlacementTransform, FailureReason))
|
||||||
|
{
|
||||||
|
FailPlacement(FailureReason);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetOwner())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetOwner()->HasAuthority())
|
||||||
|
{
|
||||||
|
ServerPlaceBuildable(ActiveBuildClass, PlacementTransform);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerPlaceBuildable_Implementation(ActiveBuildClass, PlacementTransform);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UAgrarianBuildingPlacementComponent::ServerPlaceBuildable_Implementation(TSubclassOf<AActor> BuildClass, FTransform PlacementTransform)
|
||||||
|
{
|
||||||
|
FText FailureReason;
|
||||||
|
if (!CanPlaceAtTransform(BuildClass, PlacementTransform, FailureReason) || !HasPlacementCost(FailureReason))
|
||||||
|
{
|
||||||
|
FailPlacement(FailureReason);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FActorSpawnParameters SpawnParams;
|
||||||
|
SpawnParams.Owner = GetOwner();
|
||||||
|
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding;
|
||||||
|
|
||||||
|
AActor* PlacedActor = GetWorld()->SpawnActor<AActor>(BuildClass, PlacementTransform, SpawnParams);
|
||||||
|
if (!PlacedActor)
|
||||||
|
{
|
||||||
|
FailPlacement(FText::FromString(TEXT("Buildable could not be placed.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsumePlacementCost();
|
||||||
|
OnBuildPlaced.Broadcast(PlacedActor);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UAgrarianBuildingPlacementComponent::HasPlacementCost(FText& FailureReason) const
|
||||||
|
{
|
||||||
|
const UAgrarianInventoryComponent* Inventory = GetOwner() ? GetOwner()->FindComponentByClass<UAgrarianInventoryComponent>() : nullptr;
|
||||||
|
if (!Inventory)
|
||||||
|
{
|
||||||
|
FailureReason = FText::FromString(TEXT("No inventory is available."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const FAgrarianItemStack& Cost : PlacementCost)
|
||||||
|
{
|
||||||
|
if (!Inventory->HasItem(Cost.ItemId, Cost.Quantity))
|
||||||
|
{
|
||||||
|
FailureReason = FText::Format(
|
||||||
|
FText::FromString(TEXT("Missing build material: {0}")),
|
||||||
|
Cost.DisplayName.IsEmpty() ? FText::FromName(Cost.ItemId) : Cost.DisplayName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UAgrarianBuildingPlacementComponent::ConsumePlacementCost()
|
||||||
|
{
|
||||||
|
UAgrarianInventoryComponent* Inventory = GetOwner() ? GetOwner()->FindComponentByClass<UAgrarianInventoryComponent>() : nullptr;
|
||||||
|
if (!Inventory)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const FAgrarianItemStack& Cost : PlacementCost)
|
||||||
|
{
|
||||||
|
Inventory->RemoveItem(Cost.ItemId, Cost.Quantity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UAgrarianBuildingPlacementComponent::FailPlacement(const FText& Reason)
|
||||||
|
{
|
||||||
|
OnBuildPlacementFailed.Broadcast(Reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
FVector UAgrarianBuildingPlacementComponent::SnapLocation(const FVector& Location) const
|
||||||
|
{
|
||||||
|
if (!bSnapToGrid || GridSize <= 0.0f)
|
||||||
|
{
|
||||||
|
return Location;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FVector(
|
||||||
|
FMath::GridSnap(Location.X, GridSize),
|
||||||
|
FMath::GridSnap(Location.Y, GridSize),
|
||||||
|
Location.Z);
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
// Copyright Pacificao. All Rights Reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Components/ActorComponent.h"
|
||||||
|
#include "AgrarianTypes.h"
|
||||||
|
#include "AgrarianBuildingPlacementComponent.generated.h"
|
||||||
|
|
||||||
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAgrarianBuildPlacedSignature, AActor*, PlacedActor);
|
||||||
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAgrarianBuildPlacementFailedSignature, FText, Reason);
|
||||||
|
|
||||||
|
UCLASS(ClassGroup = (Agrarian), BlueprintType, Blueprintable, meta = (BlueprintSpawnableComponent))
|
||||||
|
class UAgrarianBuildingPlacementComponent : public UActorComponent
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UAgrarianBuildingPlacementComponent();
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintAssignable, Category = "Agrarian|Building")
|
||||||
|
FAgrarianBuildPlacedSignature OnBuildPlaced;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintAssignable, Category = "Agrarian|Building")
|
||||||
|
FAgrarianBuildPlacementFailedSignature OnBuildPlacementFailed;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building")
|
||||||
|
TSubclassOf<AActor> ActiveBuildClass;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building")
|
||||||
|
TArray<FAgrarianItemStack> PlacementCost;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building", meta = (ClampMin = "100"))
|
||||||
|
float PlacementDistance = 600.0f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building", meta = (ClampMin = "0"))
|
||||||
|
float PlacementProbeRadius = 75.0f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building", meta = (ClampMin = "0"))
|
||||||
|
float SurfaceOffset = 2.0f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building")
|
||||||
|
bool bSnapToGrid = true;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building", meta = (EditCondition = "bSnapToGrid", ClampMin = "1"))
|
||||||
|
float GridSize = 50.0f;
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Agrarian|Building")
|
||||||
|
void SetActiveBuildable(TSubclassOf<AActor> BuildClass, const TArray<FAgrarianItemStack>& Cost);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Agrarian|Building")
|
||||||
|
bool GetPlacementPreview(FTransform& OutTransform, FText& FailureReason) const;
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Agrarian|Building")
|
||||||
|
bool CanPlaceAtTransform(TSubclassOf<AActor> BuildClass, const FTransform& PlacementTransform, FText& FailureReason) const;
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Agrarian|Building")
|
||||||
|
bool PlaceActiveBuildable();
|
||||||
|
|
||||||
|
UFUNCTION(Server, Reliable, BlueprintCallable, Category = "Agrarian|Building")
|
||||||
|
void ServerPlaceBuildable(TSubclassOf<AActor> BuildClass, FTransform PlacementTransform);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool HasPlacementCost(FText& FailureReason) const;
|
||||||
|
void ConsumePlacementCost();
|
||||||
|
void FailPlacement(const FText& Reason);
|
||||||
|
FVector SnapLocation(const FVector& Location) const;
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "AgrarianCraftingComponent.h"
|
#include "AgrarianCraftingComponent.h"
|
||||||
#include "AgrarianInventoryComponent.h"
|
#include "AgrarianInventoryComponent.h"
|
||||||
|
#include "AgrarianRecipeDataAsset.h"
|
||||||
|
|
||||||
UAgrarianCraftingComponent::UAgrarianCraftingComponent()
|
UAgrarianCraftingComponent::UAgrarianCraftingComponent()
|
||||||
{
|
{
|
||||||
@@ -111,6 +112,15 @@ bool UAgrarianCraftingComponent::AddKnownRecipe(const FAgrarianRecipe& Recipe)
|
|||||||
|
|
||||||
bool UAgrarianCraftingComponent::FindRecipe(FName RecipeId, FAgrarianRecipe& OutRecipe) const
|
bool UAgrarianCraftingComponent::FindRecipe(FName RecipeId, FAgrarianRecipe& OutRecipe) const
|
||||||
{
|
{
|
||||||
|
for (const UAgrarianRecipeDataAsset* RecipeAsset : KnownRecipeAssets)
|
||||||
|
{
|
||||||
|
if (RecipeAsset && RecipeAsset->Recipe.RecipeId == RecipeId)
|
||||||
|
{
|
||||||
|
OutRecipe = RecipeAsset->Recipe;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const FAgrarianRecipe& Recipe : KnownRecipes)
|
for (const FAgrarianRecipe& Recipe : KnownRecipes)
|
||||||
{
|
{
|
||||||
if (Recipe.RecipeId == RecipeId)
|
if (Recipe.RecipeId == RecipeId)
|
||||||
@@ -128,7 +138,7 @@ UAgrarianInventoryComponent* UAgrarianCraftingComponent::GetInventory() const
|
|||||||
return GetOwner() ? GetOwner()->FindComponentByClass<UAgrarianInventoryComponent>() : nullptr;
|
return GetOwner() ? GetOwner()->FindComponentByClass<UAgrarianInventoryComponent>() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UAgrarianCraftingComponent::FailCraft(FName RecipeId, const FText& Reason) const
|
void UAgrarianCraftingComponent::FailCraft(FName RecipeId, const FText& Reason)
|
||||||
{
|
{
|
||||||
OnCraftFailed.Broadcast(RecipeId, Reason);
|
OnCraftFailed.Broadcast(RecipeId, Reason);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "AgrarianCraftingComponent.generated.h"
|
#include "AgrarianCraftingComponent.generated.h"
|
||||||
|
|
||||||
class UAgrarianInventoryComponent;
|
class UAgrarianInventoryComponent;
|
||||||
|
class UAgrarianRecipeDataAsset;
|
||||||
|
|
||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FAgrarianCraftCompletedSignature, FName, RecipeId, const FAgrarianItemStack&, Result);
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FAgrarianCraftCompletedSignature, FName, RecipeId, const FAgrarianItemStack&, Result);
|
||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FAgrarianCraftFailedSignature, FName, RecipeId, FText, Reason);
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FAgrarianCraftFailedSignature, FName, RecipeId, FText, Reason);
|
||||||
@@ -29,6 +30,9 @@ public:
|
|||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Crafting")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Crafting")
|
||||||
TArray<FAgrarianRecipe> KnownRecipes;
|
TArray<FAgrarianRecipe> KnownRecipes;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Crafting")
|
||||||
|
TArray<TObjectPtr<UAgrarianRecipeDataAsset>> KnownRecipeAssets;
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable, Category = "Agrarian|Crafting")
|
UFUNCTION(BlueprintCallable, Category = "Agrarian|Crafting")
|
||||||
bool CanCraft(FName RecipeId, FText& FailureReason) const;
|
bool CanCraft(FName RecipeId, FText& FailureReason) const;
|
||||||
|
|
||||||
@@ -46,5 +50,5 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
UAgrarianInventoryComponent* GetInventory() const;
|
UAgrarianInventoryComponent* GetInventory() const;
|
||||||
void FailCraft(FName RecipeId, const FText& Reason) const;
|
void FailCraft(FName RecipeId, const FText& Reason);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||||
|
|
||||||
#include "AgrarianGameCharacter.h"
|
#include "AgrarianGameCharacter.h"
|
||||||
|
#include "AgrarianBuildingPlacementComponent.h"
|
||||||
#include "AgrarianCraftingComponent.h"
|
#include "AgrarianCraftingComponent.h"
|
||||||
#include "AgrarianInteractable.h"
|
#include "AgrarianInteractable.h"
|
||||||
#include "AgrarianInventoryComponent.h"
|
#include "AgrarianInventoryComponent.h"
|
||||||
@@ -53,6 +54,7 @@ AAgrarianGameCharacter::AAgrarianGameCharacter()
|
|||||||
SurvivalComponent = CreateDefaultSubobject<UAgrarianSurvivalComponent>(TEXT("SurvivalComponent"));
|
SurvivalComponent = CreateDefaultSubobject<UAgrarianSurvivalComponent>(TEXT("SurvivalComponent"));
|
||||||
InventoryComponent = CreateDefaultSubobject<UAgrarianInventoryComponent>(TEXT("InventoryComponent"));
|
InventoryComponent = CreateDefaultSubobject<UAgrarianInventoryComponent>(TEXT("InventoryComponent"));
|
||||||
CraftingComponent = CreateDefaultSubobject<UAgrarianCraftingComponent>(TEXT("CraftingComponent"));
|
CraftingComponent = CreateDefaultSubobject<UAgrarianCraftingComponent>(TEXT("CraftingComponent"));
|
||||||
|
BuildingPlacementComponent = CreateDefaultSubobject<UAgrarianBuildingPlacementComponent>(TEXT("BuildingPlacementComponent"));
|
||||||
|
|
||||||
// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character)
|
// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character)
|
||||||
// are set in the derived blueprint asset named ThirdPersonCharacter (to avoid direct content references in C++)
|
// are set in the derived blueprint asset named ThirdPersonCharacter (to avoid direct content references in C++)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
class USpringArmComponent;
|
class USpringArmComponent;
|
||||||
class UCameraComponent;
|
class UCameraComponent;
|
||||||
class UInputAction;
|
class UInputAction;
|
||||||
|
class UAgrarianBuildingPlacementComponent;
|
||||||
class UAgrarianCraftingComponent;
|
class UAgrarianCraftingComponent;
|
||||||
class UAgrarianInventoryComponent;
|
class UAgrarianInventoryComponent;
|
||||||
class UAgrarianSurvivalComponent;
|
class UAgrarianSurvivalComponent;
|
||||||
@@ -46,6 +47,10 @@ class AAgrarianGameCharacter : public ACharacter
|
|||||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components", meta = (AllowPrivateAccess = "true"))
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components", meta = (AllowPrivateAccess = "true"))
|
||||||
UAgrarianCraftingComponent* CraftingComponent;
|
UAgrarianCraftingComponent* CraftingComponent;
|
||||||
|
|
||||||
|
/** Server-authoritative primitive building placement component. */
|
||||||
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components", meta = (AllowPrivateAccess = "true"))
|
||||||
|
UAgrarianBuildingPlacementComponent* BuildingPlacementComponent;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/** Jump Input Action */
|
/** Jump Input Action */
|
||||||
@@ -135,5 +140,8 @@ public:
|
|||||||
|
|
||||||
/** Returns CraftingComponent subobject **/
|
/** Returns CraftingComponent subobject **/
|
||||||
FORCEINLINE UAgrarianCraftingComponent* GetCraftingComponent() const { return CraftingComponent; }
|
FORCEINLINE UAgrarianCraftingComponent* GetCraftingComponent() const { return CraftingComponent; }
|
||||||
|
|
||||||
|
/** Returns BuildingPlacementComponent subobject **/
|
||||||
|
FORCEINLINE UAgrarianBuildingPlacementComponent* GetBuildingPlacementComponent() const { return BuildingPlacementComponent; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// Copyright Pacificao. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "AgrarianItemDefinitionAsset.h"
|
||||||
|
|
||||||
|
FAgrarianItemStack UAgrarianItemDefinitionAsset::MakeStack(int32 Quantity) const
|
||||||
|
{
|
||||||
|
FAgrarianItemStack Stack;
|
||||||
|
Stack.ItemId = Definition.ItemId;
|
||||||
|
Stack.DisplayName = Definition.DisplayName;
|
||||||
|
Stack.Quantity = FMath::Clamp(Quantity, 0, Definition.MaxStackSize);
|
||||||
|
Stack.UnitWeight = Definition.UnitWeight;
|
||||||
|
return Stack;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright Pacificao. All Rights Reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Engine/PrimaryDataAsset.h"
|
||||||
|
#include "AgrarianTypes.h"
|
||||||
|
#include "AgrarianItemDefinitionAsset.generated.h"
|
||||||
|
|
||||||
|
UCLASS(BlueprintType)
|
||||||
|
class UAgrarianItemDefinitionAsset : public UPrimaryDataAsset
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Agrarian|Items")
|
||||||
|
FAgrarianItemDefinition Definition;
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Agrarian|Items")
|
||||||
|
FAgrarianItemStack MakeStack(int32 Quantity) const;
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright Pacificao. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "AgrarianRecipeDataAsset.h"
|
||||||
|
|
||||||
|
FName UAgrarianRecipeDataAsset::GetRecipeId() const
|
||||||
|
{
|
||||||
|
return Recipe.RecipeId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright Pacificao. All Rights Reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Engine/PrimaryDataAsset.h"
|
||||||
|
#include "AgrarianTypes.h"
|
||||||
|
#include "AgrarianRecipeDataAsset.generated.h"
|
||||||
|
|
||||||
|
UCLASS(BlueprintType)
|
||||||
|
class UAgrarianRecipeDataAsset : public UPrimaryDataAsset
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Agrarian|Crafting")
|
||||||
|
FAgrarianRecipe Recipe;
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Agrarian|Crafting")
|
||||||
|
FName GetRecipeId() const;
|
||||||
|
};
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "AgrarianResourceNode.h"
|
#include "AgrarianResourceNode.h"
|
||||||
#include "AgrarianGameCharacter.h"
|
#include "AgrarianGameCharacter.h"
|
||||||
#include "AgrarianInventoryComponent.h"
|
#include "AgrarianInventoryComponent.h"
|
||||||
|
#include "AgrarianItemDefinitionAsset.h"
|
||||||
#include "Components/StaticMeshComponent.h"
|
#include "Components/StaticMeshComponent.h"
|
||||||
#include "Net/UnrealNetwork.h"
|
#include "Net/UnrealNetwork.h"
|
||||||
|
|
||||||
@@ -45,9 +46,7 @@ void AAgrarianResourceNode::Interact_Implementation(AAgrarianGameCharacter* Inte
|
|||||||
|
|
||||||
if (UAgrarianInventoryComponent* Inventory = Interactor->GetInventoryComponent())
|
if (UAgrarianInventoryComponent* Inventory = Interactor->GetInventoryComponent())
|
||||||
{
|
{
|
||||||
FAgrarianItemStack Granted = YieldItem;
|
const FAgrarianItemStack Granted = MakeYieldStack();
|
||||||
Granted.Quantity = QuantityPerHarvest;
|
|
||||||
|
|
||||||
if (Inventory->AddItem(Granted))
|
if (Inventory->AddItem(Granted))
|
||||||
{
|
{
|
||||||
RemainingHarvests--;
|
RemainingHarvests--;
|
||||||
@@ -61,6 +60,18 @@ void AAgrarianResourceNode::OnRep_RemainingHarvests()
|
|||||||
UpdateDepletedState();
|
UpdateDepletedState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FAgrarianItemStack AAgrarianResourceNode::MakeYieldStack() const
|
||||||
|
{
|
||||||
|
if (YieldItemDefinition)
|
||||||
|
{
|
||||||
|
return YieldItemDefinition->MakeStack(QuantityPerHarvest);
|
||||||
|
}
|
||||||
|
|
||||||
|
FAgrarianItemStack Granted = YieldItem;
|
||||||
|
Granted.Quantity = QuantityPerHarvest;
|
||||||
|
return Granted;
|
||||||
|
}
|
||||||
|
|
||||||
void AAgrarianResourceNode::UpdateDepletedState()
|
void AAgrarianResourceNode::UpdateDepletedState()
|
||||||
{
|
{
|
||||||
if (Mesh)
|
if (Mesh)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "AgrarianResourceNode.generated.h"
|
#include "AgrarianResourceNode.generated.h"
|
||||||
|
|
||||||
class UStaticMeshComponent;
|
class UStaticMeshComponent;
|
||||||
|
class UAgrarianItemDefinitionAsset;
|
||||||
|
|
||||||
UCLASS(Blueprintable)
|
UCLASS(Blueprintable)
|
||||||
class AAgrarianResourceNode : public AActor, public IAgrarianInteractable
|
class AAgrarianResourceNode : public AActor, public IAgrarianInteractable
|
||||||
@@ -26,6 +27,9 @@ public:
|
|||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Resource")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Resource")
|
||||||
FAgrarianItemStack YieldItem;
|
FAgrarianItemStack YieldItem;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Resource")
|
||||||
|
TObjectPtr<UAgrarianItemDefinitionAsset> YieldItemDefinition;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, ReplicatedUsing = OnRep_RemainingHarvests, Category = "Agrarian|Resource", meta = (ClampMin = "0"))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, ReplicatedUsing = OnRep_RemainingHarvests, Category = "Agrarian|Resource", meta = (ClampMin = "0"))
|
||||||
int32 RemainingHarvests = 5;
|
int32 RemainingHarvests = 5;
|
||||||
|
|
||||||
@@ -40,5 +44,6 @@ protected:
|
|||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
void OnRep_RemainingHarvests();
|
void OnRep_RemainingHarvests();
|
||||||
|
|
||||||
|
FAgrarianItemStack MakeYieldStack() const;
|
||||||
void UpdateDepletedState();
|
void UpdateDepletedState();
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user