Add crafting debug exec tools

This commit is contained in:
2026-05-17 18:08:48 -07:00
parent 3509641df8
commit 70eb22d716
5 changed files with 137 additions and 1 deletions
+4 -1
View File
@@ -572,7 +572,10 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe
recipes, shows current ingredient counts, highlights craftable rows, and
preloads the Agrarian player Blueprint with primitive recipe assets.
- [x] Add multiplayer authority checks.
- [~] Add crafting debug tools.
- [x] Add crafting debug tools. Added `AgrarianCraftStatus` and
`AgrarianCraft <RecipeId>` exec commands for listing known recipes,
inspecting craftability, and triggering server-authoritative craft requests
during smoke tests and demo rehearsal.
## 0.1.H Fire System
+6
View File
@@ -153,6 +153,12 @@ reads those recipes plus the replicated inventory to show craftable status and
ingredient counts. Interactive UMG recipe browsing, hotkeys, and queued
crafting controls are deferred until the primitive loop settles.
Crafting debug tools live on the player controller. `AgrarianCraftStatus`
prints known recipes and current craftability, while `AgrarianCraft <RecipeId>`
requests a server-authoritative craft through `UAgrarianCraftingComponent`.
These commands are intended for smoke testing and investor-demo rehearsal until
proper UI input exists.
Inventory persistence saves `UAgrarianInventoryComponent::Items` into
`FAgrarianSavedPlayer::Inventory` and restores through
`UAgrarianInventoryComponent::RestoreSavedItems`. Restore broadcasts
+47
View File
@@ -0,0 +1,47 @@
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
EXPECTED = {
ROOT / "Source" / "AgrarianGame" / "AgrarianGamePlayerController.h": [
"void AgrarianCraft(FName RecipeId);",
"void AgrarianCraftStatus();",
"void ServerAgrarianCraft(FName RecipeId);",
],
ROOT / "Source" / "AgrarianGame" / "AgrarianGamePlayerController.cpp": [
"#include \"AgrarianCraftingComponent.h\"",
"void AAgrarianGamePlayerController::AgrarianCraft(FName RecipeId)",
"void AAgrarianGamePlayerController::AgrarianCraftStatus()",
"CraftingComponent->GetKnownRecipes(Recipes)",
"CraftingComponent->CanCraft(Recipe.RecipeId, FailureReason)",
"void AAgrarianGamePlayerController::ServerAgrarianCraft_Implementation(FName RecipeId)",
"CraftingComponent->Craft(RecipeId)",
],
ROOT / "Docs" / "TechnicalDesignDocument.md": [
"`AgrarianCraft <RecipeId>`",
"`AgrarianCraftStatus`",
],
ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md": [
"- [x] Add crafting debug tools.",
"AgrarianCraftStatus",
],
}
def main():
missing = []
for path, snippets in EXPECTED.items():
text = path.read_text(encoding="utf-8")
for snippet in snippets:
if snippet not in text:
missing.append(f"{path.relative_to(ROOT)} missing {snippet!r}")
if missing:
raise RuntimeError("Crafting debug tools verification failed: " + "; ".join(missing))
print("PASS: crafting debug exec tools are wired and documented.")
if __name__ == "__main__":
main()
@@ -2,6 +2,7 @@
#include "AgrarianGamePlayerController.h"
#include "AgrarianCraftingComponent.h"
#include "AgrarianGameCharacter.h"
#include "AgrarianInventoryComponent.h"
#include "AgrarianItemPickup.h"
@@ -194,6 +195,49 @@ void AAgrarianGamePlayerController::AgrarianUseItem(FName ItemId, int32 Quantity
ServerAgrarianUseItem(ItemId, Quantity);
}
void AAgrarianGamePlayerController::AgrarianCraft(FName RecipeId)
{
if (RecipeId == NAME_None)
{
ClientMessage(TEXT("Usage: AgrarianCraft <RecipeId>"));
return;
}
ServerAgrarianCraft(RecipeId);
}
void AAgrarianGamePlayerController::AgrarianCraftStatus()
{
const AAgrarianGameCharacter* AgrarianCharacter = GetPawn<AAgrarianGameCharacter>();
const UAgrarianCraftingComponent* CraftingComponent = AgrarianCharacter ? AgrarianCharacter->GetCraftingComponent() : nullptr;
if (!CraftingComponent)
{
ClientMessage(TEXT("No Agrarian crafting component found."));
return;
}
TArray<FAgrarianRecipe> Recipes;
CraftingComponent->GetKnownRecipes(Recipes);
if (Recipes.IsEmpty())
{
ClientMessage(TEXT("No known Agrarian recipes."));
return;
}
ClientMessage(FString::Printf(TEXT("Known Agrarian recipes: %d"), Recipes.Num()));
for (const FAgrarianRecipe& Recipe : Recipes)
{
FText FailureReason;
const bool bCanCraft = CraftingComponent->CanCraft(Recipe.RecipeId, FailureReason);
const FString RecipeName = Recipe.DisplayName.IsEmpty() ? Recipe.RecipeId.ToString() : Recipe.DisplayName.ToString();
ClientMessage(FString::Printf(
TEXT("- %s (%s): %s"),
*RecipeName,
*Recipe.RecipeId.ToString(),
bCanCraft ? TEXT("ready") : *FailureReason.ToString()));
}
}
void AAgrarianGamePlayerController::AgrarianTravel(float X, float Y, float Z)
{
ServerAgrarianTravel(FVector(X, Y, Z));
@@ -372,6 +416,33 @@ void AAgrarianGamePlayerController::ServerAgrarianUseItem_Implementation(FName I
ClientMessage(FString::Printf(TEXT("Used %d x %s: %s."), UsedStack.Quantity, *ItemId.ToString(), *EffectSummary));
}
void AAgrarianGamePlayerController::ServerAgrarianCraft_Implementation(FName RecipeId)
{
AAgrarianGameCharacter* AgrarianCharacter = GetPawn<AAgrarianGameCharacter>();
UAgrarianCraftingComponent* CraftingComponent = AgrarianCharacter ? AgrarianCharacter->GetCraftingComponent() : nullptr;
if (!CraftingComponent)
{
ClientMessage(TEXT("No Agrarian crafting component found."));
return;
}
FText FailureReason;
if (!CraftingComponent->CanCraft(RecipeId, FailureReason))
{
ClientMessage(FString::Printf(TEXT("Cannot craft %s: %s"), *RecipeId.ToString(), *FailureReason.ToString()));
return;
}
if (CraftingComponent->Craft(RecipeId))
{
ClientMessage(FString::Printf(TEXT("Crafted %s."), *RecipeId.ToString()));
}
else
{
ClientMessage(FString::Printf(TEXT("Failed to craft %s."), *RecipeId.ToString()));
}
}
void AAgrarianGamePlayerController::ServerAgrarianTravel_Implementation(FVector Destination)
{
APawn* ControlledPawn = GetPawn();
@@ -75,6 +75,12 @@ public:
UFUNCTION(Exec)
void AgrarianUseItem(FName ItemId, int32 Quantity);
UFUNCTION(Exec)
void AgrarianCraft(FName RecipeId);
UFUNCTION(Exec)
void AgrarianCraftStatus();
UFUNCTION(Exec)
void AgrarianTravel(float X, float Y, float Z);
@@ -103,6 +109,9 @@ protected:
UFUNCTION(Server, Reliable)
void ServerAgrarianUseItem(FName ItemId, int32 Quantity);
UFUNCTION(Server, Reliable)
void ServerAgrarianCraft(FName RecipeId);
UFUNCTION(Server, Reliable)
void ServerAgrarianTravel(FVector Destination);
};