Add item pickup actor
This commit is contained in:
@@ -490,7 +490,10 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe
|
|||||||
- [x] Create item definition data asset.
|
- [x] Create item definition data asset.
|
||||||
- [x] Create item stack structure.
|
- [x] Create item stack structure.
|
||||||
- [x] Create inventory component.
|
- [x] Create inventory component.
|
||||||
- [ ] Add item pickup.
|
- [x] Add item pickup. Added native `AAgrarianItemPickup` interactable world
|
||||||
|
actor with definition-backed or inline stack data, server-authoritative
|
||||||
|
inventory add, prompt text, and destroy-on-success behavior so failed pickups
|
||||||
|
remain available.
|
||||||
- [ ] Add item drop.
|
- [ ] Add item drop.
|
||||||
- [ ] Add stack splitting.
|
- [ ] Add stack splitting.
|
||||||
- [ ] Add item use.
|
- [ ] Add item use.
|
||||||
|
|||||||
@@ -91,6 +91,14 @@ and save-game `FAgrarianItemStack` records, and a server-authoritative
|
|||||||
splitting, item use, equipment, carry capacity, persistence, and UI work should
|
splitting, item use, equipment, carry capacity, persistence, and UI work should
|
||||||
extend that contract rather than inventing parallel inventory state.
|
extend that contract rather than inventing parallel inventory state.
|
||||||
|
|
||||||
|
World pickups use `AAgrarianItemPickup`, an interactable replicated actor with a
|
||||||
|
static mesh and either a definition-backed or inline `FAgrarianItemStack`.
|
||||||
|
Player interaction already routes to the server through the Agrarian character,
|
||||||
|
so pickups validate authority, produce a valid stack, add it to the player's
|
||||||
|
inventory, and only then remove the pickup by destroying the world pickup actor.
|
||||||
|
If the inventory is full or the stack is invalid, the pickup remains in the
|
||||||
|
world for another attempt.
|
||||||
|
|
||||||
## Time And Environment
|
## Time And Environment
|
||||||
|
|
||||||
The MVP gameplay calendar target is:
|
The MVP gameplay calendar target is:
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
FILES = {
|
||||||
|
"AgrarianItemPickup.h": ROOT / "Source" / "AgrarianGame" / "AgrarianItemPickup.h",
|
||||||
|
"AgrarianItemPickup.cpp": ROOT / "Source" / "AgrarianGame" / "AgrarianItemPickup.cpp",
|
||||||
|
"InventoryDataModel.md": ROOT / "Docs" / "InventoryDataModel.md",
|
||||||
|
"TechnicalDesignDocument.md": ROOT / "Docs" / "TechnicalDesignDocument.md",
|
||||||
|
"AGRARIAN_DEVELOPMENT_ROADMAP.md": ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md",
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECTED = {
|
||||||
|
"AgrarianItemPickup.h": [
|
||||||
|
"class AGRARIANGAME_API AAgrarianItemPickup : public AActor, public IAgrarianInteractable",
|
||||||
|
"TObjectPtr<UStaticMeshComponent> Mesh;",
|
||||||
|
"FAgrarianItemStack PickupStack;",
|
||||||
|
"TObjectPtr<UAgrarianItemDefinitionAsset> ItemDefinition;",
|
||||||
|
"int32 Quantity = 1;",
|
||||||
|
"virtual FText GetInteractionText_Implementation",
|
||||||
|
"virtual bool CanInteract_Implementation",
|
||||||
|
"virtual void Interact_Implementation",
|
||||||
|
"FAgrarianItemStack MakePickupStack() const;",
|
||||||
|
],
|
||||||
|
"AgrarianItemPickup.cpp": [
|
||||||
|
"bReplicates = true;",
|
||||||
|
"Mesh->SetCollisionProfileName(TEXT(\"BlockAll\"));",
|
||||||
|
"ItemDefinition->MakeStack(Quantity)",
|
||||||
|
"MakePickupStack().IsValidStack()",
|
||||||
|
"if (!HasAuthority() || !Interactor)",
|
||||||
|
"Interactor->GetInventoryComponent()",
|
||||||
|
"Inventory->AddItem(Stack)",
|
||||||
|
"Destroy();",
|
||||||
|
],
|
||||||
|
"InventoryDataModel.md": [
|
||||||
|
"Pickup:",
|
||||||
|
"world item validates range, authority, stack data, and available",
|
||||||
|
],
|
||||||
|
"TechnicalDesignDocument.md": [
|
||||||
|
"`AAgrarianItemPickup`",
|
||||||
|
"definition-backed or inline `FAgrarianItemStack`",
|
||||||
|
"destroying the world pickup actor",
|
||||||
|
],
|
||||||
|
"AGRARIAN_DEVELOPMENT_ROADMAP.md": [
|
||||||
|
"[x] Add item pickup.",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
missing = []
|
||||||
|
for label, path in FILES.items():
|
||||||
|
text = path.read_text(encoding="utf-8")
|
||||||
|
for snippet in EXPECTED[label]:
|
||||||
|
if snippet not in text:
|
||||||
|
missing.append(f"{label}: {snippet}")
|
||||||
|
|
||||||
|
if missing:
|
||||||
|
raise RuntimeError("Item pickup verification failed: " + "; ".join(missing))
|
||||||
|
|
||||||
|
print("Agrarian item pickup verification complete.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
// Copyright Pacificao. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "AgrarianItemPickup.h"
|
||||||
|
#include "AgrarianGameCharacter.h"
|
||||||
|
#include "AgrarianInventoryComponent.h"
|
||||||
|
#include "AgrarianItemDefinitionAsset.h"
|
||||||
|
#include "Components/StaticMeshComponent.h"
|
||||||
|
|
||||||
|
AAgrarianItemPickup::AAgrarianItemPickup()
|
||||||
|
{
|
||||||
|
bReplicates = true;
|
||||||
|
|
||||||
|
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
|
||||||
|
RootComponent = Mesh;
|
||||||
|
Mesh->SetCollisionProfileName(TEXT("BlockAll"));
|
||||||
|
|
||||||
|
PickupStack.ItemId = TEXT("wood");
|
||||||
|
PickupStack.DisplayName = FText::FromString(TEXT("Wood"));
|
||||||
|
PickupStack.Quantity = 1;
|
||||||
|
PickupStack.UnitWeight = 1.0f;
|
||||||
|
InteractionVerb = FText::FromString(TEXT("Pick up"));
|
||||||
|
}
|
||||||
|
|
||||||
|
FText AAgrarianItemPickup::GetInteractionText_Implementation(const AAgrarianGameCharacter* Interactor) const
|
||||||
|
{
|
||||||
|
const FAgrarianItemStack Stack = MakePickupStack();
|
||||||
|
const FText DisplayName = Stack.DisplayName.IsEmpty() ? FText::FromName(Stack.ItemId) : Stack.DisplayName;
|
||||||
|
const FString Verb = InteractionVerb.IsEmpty() ? FString(TEXT("Pick up")) : InteractionVerb.ToString();
|
||||||
|
|
||||||
|
if (Stack.Quantity > 1)
|
||||||
|
{
|
||||||
|
return FText::FromString(FString::Printf(TEXT("%s %s x%d"), *Verb, *DisplayName.ToString(), Stack.Quantity));
|
||||||
|
}
|
||||||
|
|
||||||
|
return FText::FromString(FString::Printf(TEXT("%s %s"), *Verb, *DisplayName.ToString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AAgrarianItemPickup::CanInteract_Implementation(const AAgrarianGameCharacter* Interactor) const
|
||||||
|
{
|
||||||
|
return Interactor != nullptr && MakePickupStack().IsValidStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AAgrarianItemPickup::Interact_Implementation(AAgrarianGameCharacter* Interactor)
|
||||||
|
{
|
||||||
|
if (!HasAuthority() || !Interactor)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UAgrarianInventoryComponent* Inventory = Interactor->GetInventoryComponent();
|
||||||
|
if (!Inventory)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FAgrarianItemStack Stack = MakePickupStack();
|
||||||
|
if (Inventory->AddItem(Stack))
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FAgrarianItemStack AAgrarianItemPickup::MakePickupStack() const
|
||||||
|
{
|
||||||
|
if (ItemDefinition)
|
||||||
|
{
|
||||||
|
return ItemDefinition->MakeStack(Quantity);
|
||||||
|
}
|
||||||
|
|
||||||
|
FAgrarianItemStack Stack = PickupStack;
|
||||||
|
if (Quantity > 0)
|
||||||
|
{
|
||||||
|
Stack.Quantity = Quantity;
|
||||||
|
}
|
||||||
|
return Stack;
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// Copyright Pacificao. All Rights Reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "GameFramework/Actor.h"
|
||||||
|
#include "AgrarianInteractable.h"
|
||||||
|
#include "AgrarianTypes.h"
|
||||||
|
#include "AgrarianItemPickup.generated.h"
|
||||||
|
|
||||||
|
class AAgrarianGameCharacter;
|
||||||
|
class UAgrarianItemDefinitionAsset;
|
||||||
|
class UStaticMeshComponent;
|
||||||
|
|
||||||
|
UCLASS(Blueprintable)
|
||||||
|
class AGRARIANGAME_API AAgrarianItemPickup : public AActor, public IAgrarianInteractable
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
AAgrarianItemPickup();
|
||||||
|
|
||||||
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Pickup")
|
||||||
|
TObjectPtr<UStaticMeshComponent> Mesh;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Pickup")
|
||||||
|
FAgrarianItemStack PickupStack;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Pickup")
|
||||||
|
TObjectPtr<UAgrarianItemDefinitionAsset> ItemDefinition;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Pickup", meta = (ClampMin = "1"))
|
||||||
|
int32 Quantity = 1;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Pickup")
|
||||||
|
FText InteractionVerb;
|
||||||
|
|
||||||
|
virtual FText GetInteractionText_Implementation(const AAgrarianGameCharacter* Interactor) const override;
|
||||||
|
virtual bool CanInteract_Implementation(const AAgrarianGameCharacter* Interactor) const override;
|
||||||
|
virtual void Interact_Implementation(AAgrarianGameCharacter* Interactor) override;
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Agrarian|Pickup")
|
||||||
|
FAgrarianItemStack MakePickupStack() const;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user