Add inventory persistence restore hook

This commit is contained in:
2026-05-17 13:56:28 -07:00
parent 09eed7c4c4
commit ac9fee463c
7 changed files with 95 additions and 3 deletions
+4 -1
View File
@@ -519,7 +519,10 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe
from the full developer HUD and shows occupied slots, total carried weight,
and visible item stacks from the replicated inventory component.
- [x] Add replication for inventory changes.
- [ ] Add persistence for inventory.
- [x] Add persistence for inventory. Player save data stores
`FAgrarianSavedPlayer::Inventory`, capture writes the inventory component's
stack array, restore now goes through `RestoreSavedItems`, and inventory UI
listeners are notified after load.
- [x] Add debug item spawn command.
## 0.1.F Gathering And Resources
+3 -1
View File
@@ -100,7 +100,9 @@ player's inventory without a translation layer.
Save/load responsibilities:
- Save the player inventory from `UAgrarianInventoryComponent::Items`.
- Restore the stack array onto the component during load.
- Restore the stack array through
`UAgrarianInventoryComponent::RestoreSavedItems` during load so HUD/UI
listeners receive `OnInventoryChanged`.
- Recompute derived values such as total weight after load from stack data.
- Avoid saving UI-only selection state as part of the inventory model.
+6
View File
@@ -144,6 +144,12 @@ array, shows occupied slots, total carried weight, and a short visible stack
list, and leaves mutation actions on the existing server-authoritative commands
and RPCs until a full UMG inventory screen is introduced.
Inventory persistence saves `UAgrarianInventoryComponent::Items` into
`FAgrarianSavedPlayer::Inventory` and restores through
`UAgrarianInventoryComponent::RestoreSavedItems`. Restore broadcasts
`OnInventoryChanged`, which keeps the MVP HUD panel and future UI listeners in
sync after load while preserving total weight as a derived value.
## Time And Environment
The MVP gameplay calendar target is:
+67
View File
@@ -0,0 +1,67 @@
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
FILES = {
"AgrarianSaveGame.h": ROOT / "Source" / "AgrarianGame" / "AgrarianSaveGame.h",
"AgrarianInventoryComponent.h": ROOT / "Source" / "AgrarianGame" / "AgrarianInventoryComponent.h",
"AgrarianInventoryComponent.cpp": ROOT / "Source" / "AgrarianGame" / "AgrarianInventoryComponent.cpp",
"AgrarianPersistenceSubsystem.cpp": ROOT / "Source" / "AgrarianGame" / "AgrarianPersistenceSubsystem.cpp",
"InventoryDataModel.md": ROOT / "Docs" / "InventoryDataModel.md",
"TechnicalDesignDocument.md": ROOT / "Docs" / "TechnicalDesignDocument.md",
"AGRARIAN_DEVELOPMENT_ROADMAP.md": ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md",
}
EXPECTED = {
"AgrarianSaveGame.h": [
"TArray<FAgrarianItemStack> Inventory",
],
"AgrarianInventoryComponent.h": [
"RestoreSavedItems",
"const TArray<FAgrarianItemStack>& SavedItems",
],
"AgrarianInventoryComponent.cpp": [
"UAgrarianInventoryComponent::RestoreSavedItems",
"Items = SavedItems",
"BroadcastInventoryChanged()",
],
"AgrarianPersistenceSubsystem.cpp": [
"SavedPlayer.Inventory = InventoryComponent->Items",
"InventoryComponent->RestoreSavedItems(SavedPlayer->Inventory)",
],
"InventoryDataModel.md": [
"`UAgrarianInventoryComponent::RestoreSavedItems`",
"`OnInventoryChanged`",
"Recompute derived values such as total weight",
],
"TechnicalDesignDocument.md": [
"Inventory persistence saves",
"`FAgrarianSavedPlayer::Inventory`",
"`UAgrarianInventoryComponent::RestoreSavedItems`",
"`OnInventoryChanged`",
],
"AGRARIAN_DEVELOPMENT_ROADMAP.md": [
"[x] Add persistence for inventory.",
"`FAgrarianSavedPlayer::Inventory`",
"`RestoreSavedItems`",
"listeners are notified after load",
],
}
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("Inventory persistence verification failed: " + "; ".join(missing))
print("Agrarian inventory persistence verification complete.")
if __name__ == "__main__":
main()
@@ -136,6 +136,17 @@ bool UAgrarianInventoryComponent::SplitStackByIndex(int32 StackIndex, int32 Spli
return true;
}
void UAgrarianInventoryComponent::RestoreSavedItems(const TArray<FAgrarianItemStack>& SavedItems)
{
if (!GetOwner() || !GetOwner()->HasAuthority())
{
return;
}
Items = SavedItems;
BroadcastInventoryChanged();
}
void UAgrarianInventoryComponent::ServerAddItem_Implementation(const FAgrarianItemStack& Stack)
{
AddItem(Stack);
@@ -49,6 +49,9 @@ public:
UFUNCTION(BlueprintCallable, Category = "Agrarian|Inventory")
bool SplitStackByIndex(int32 StackIndex, int32 SplitQuantity);
UFUNCTION(BlueprintCallable, Category = "Agrarian|Inventory")
void RestoreSavedItems(const TArray<FAgrarianItemStack>& SavedItems);
UFUNCTION(Server, Reliable, BlueprintCallable, Category = "Agrarian|Inventory")
void ServerAddItem(const FAgrarianItemStack& Stack);
@@ -231,7 +231,7 @@ int32 UAgrarianPersistenceSubsystem::RestorePlayers(const UAgrarianSaveGame* Sav
if (UAgrarianInventoryComponent* InventoryComponent = Character->GetInventoryComponent())
{
InventoryComponent->Items = SavedPlayer->Inventory;
InventoryComponent->RestoreSavedItems(SavedPlayer->Inventory);
}
RestoredCount++;