Add MVP inventory HUD panel
This commit is contained in:
@@ -515,7 +515,9 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe
|
|||||||
thresholds, strength-scaled movement penalties, and a debug HUD carried
|
thresholds, strength-scaled movement penalties, and a debug HUD carried
|
||||||
weight readout. Later volume, backpack, awkward-object, and hard overload
|
weight readout. Later volume, backpack, awkward-object, and hard overload
|
||||||
rules should extend this hook.
|
rules should extend this hook.
|
||||||
- [ ] Add inventory UI.
|
- [x] Add inventory UI. Added a compact MVP HUD inventory panel that is separate
|
||||||
|
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.
|
- [x] Add replication for inventory changes.
|
||||||
- [ ] Add persistence for inventory.
|
- [ ] Add persistence for inventory.
|
||||||
- [x] Add debug item spawn command.
|
- [x] Add debug item spawn command.
|
||||||
|
|||||||
@@ -119,6 +119,8 @@ The 0.1.E inventory work should implement these operations on top of the model:
|
|||||||
- Carry capacity: continue using total weight first, with later volume or pack
|
- Carry capacity: continue using total weight first, with later volume or pack
|
||||||
systems layered on top.
|
systems layered on top.
|
||||||
- UI: read the replicated stack list and send requests back through server RPCs.
|
- UI: read the replicated stack list and send requests back through server RPCs.
|
||||||
|
The MVP HUD now includes a compact inventory panel that shows occupied slots,
|
||||||
|
total carried weight, and the first visible item stacks.
|
||||||
|
|
||||||
## Carry Capacity Placeholder
|
## Carry Capacity Placeholder
|
||||||
|
|
||||||
|
|||||||
@@ -138,6 +138,12 @@ HUD. Future backpacks, containers, awkward-object rules, and hard overload
|
|||||||
limits should extend this total-weight path rather than creating a second carry
|
limits should extend this total-weight path rather than creating a second carry
|
||||||
model.
|
model.
|
||||||
|
|
||||||
|
The MVP inventory UI is a compact `AAgrarianDebugHUD` inventory panel, enabled
|
||||||
|
separately from the full developer HUD. It reads the replicated inventory stack
|
||||||
|
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.
|
||||||
|
|
||||||
## Time And Environment
|
## Time And Environment
|
||||||
|
|
||||||
The MVP gameplay calendar target is:
|
The MVP gameplay calendar target is:
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
FILES = {
|
||||||
|
"AgrarianDebugHUD.h": ROOT / "Source" / "AgrarianGame" / "AgrarianDebugHUD.h",
|
||||||
|
"AgrarianDebugHUD.cpp": ROOT / "Source" / "AgrarianGame" / "AgrarianDebugHUD.cpp",
|
||||||
|
"InventoryDataModel.md": ROOT / "Docs" / "InventoryDataModel.md",
|
||||||
|
"TechnicalDesignDocument.md": ROOT / "Docs" / "TechnicalDesignDocument.md",
|
||||||
|
"AGRARIAN_DEVELOPMENT_ROADMAP.md": ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md",
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECTED = {
|
||||||
|
"AgrarianDebugHUD.h": [
|
||||||
|
"bShowInventoryHUD",
|
||||||
|
"InventoryTextScale",
|
||||||
|
"MaxInventoryPanelRows",
|
||||||
|
"DrawInventoryPanel",
|
||||||
|
],
|
||||||
|
"AgrarianDebugHUD.cpp": [
|
||||||
|
"DrawInventoryPanel(AgrarianCharacter)",
|
||||||
|
"AAgrarianDebugHUD::DrawInventoryPanel",
|
||||||
|
"InventoryComponent->Items.Num()",
|
||||||
|
"InventoryComponent->MaxSlots",
|
||||||
|
"InventoryComponent->GetTotalWeight()",
|
||||||
|
"MaxInventoryPanelRows",
|
||||||
|
"Stack.UnitWeight * Stack.Quantity",
|
||||||
|
],
|
||||||
|
"InventoryDataModel.md": [
|
||||||
|
"compact inventory panel",
|
||||||
|
"occupied slots",
|
||||||
|
"total carried weight",
|
||||||
|
"visible item stacks",
|
||||||
|
],
|
||||||
|
"TechnicalDesignDocument.md": [
|
||||||
|
"The MVP inventory UI is a compact `AAgrarianDebugHUD` inventory panel",
|
||||||
|
"enabled",
|
||||||
|
"separately from the full developer HUD",
|
||||||
|
"shows occupied slots",
|
||||||
|
"total carried weight",
|
||||||
|
"server-authoritative commands",
|
||||||
|
],
|
||||||
|
"AGRARIAN_DEVELOPMENT_ROADMAP.md": [
|
||||||
|
"[x] Add inventory UI.",
|
||||||
|
"compact MVP HUD inventory panel",
|
||||||
|
"replicated inventory component",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 UI verification failed: " + "; ".join(missing))
|
||||||
|
|
||||||
|
print("Agrarian inventory UI verification complete.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -24,6 +24,7 @@ void AAgrarianDebugHUD::DrawHUD()
|
|||||||
|
|
||||||
DrawInteractionPrompt(AgrarianCharacter);
|
DrawInteractionPrompt(AgrarianCharacter);
|
||||||
DrawCriticalStats(AgrarianCharacter->GetSurvivalComponent());
|
DrawCriticalStats(AgrarianCharacter->GetSurvivalComponent());
|
||||||
|
DrawInventoryPanel(AgrarianCharacter);
|
||||||
|
|
||||||
if (bShowDebugHUD)
|
if (bShowDebugHUD)
|
||||||
{
|
{
|
||||||
@@ -109,6 +110,73 @@ void AAgrarianDebugHUD::DrawCriticalStats(const UAgrarianSurvivalComponent* Surv
|
|||||||
DrawScaledLine(FString::Printf(TEXT("Sickness %3.0f"), Survival.SicknessSeverity), X, Y, CriticalStatsTextScale, StatusColor(Survival.SicknessSeverity, true));
|
DrawScaledLine(FString::Printf(TEXT("Sickness %3.0f"), Survival.SicknessSeverity), X, Y, CriticalStatsTextScale, StatusColor(Survival.SicknessSeverity, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AAgrarianDebugHUD::DrawInventoryPanel(const AAgrarianGameCharacter* AgrarianCharacter)
|
||||||
|
{
|
||||||
|
if (!bShowInventoryHUD || !AgrarianCharacter || !Canvas)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UAgrarianInventoryComponent* InventoryComponent = AgrarianCharacter->GetInventoryComponent();
|
||||||
|
if (!InventoryComponent)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float Scale = FMath::Max(0.25f, InventoryTextScale);
|
||||||
|
const float PanelWidth = 360.0f * Scale;
|
||||||
|
const float X = FMath::Max(32.0f, Canvas->ClipX - PanelWidth - 32.0f);
|
||||||
|
float Y = 32.0f;
|
||||||
|
|
||||||
|
const int32 VisibleRows = InventoryComponent->Items.IsEmpty()
|
||||||
|
? 1
|
||||||
|
: FMath::Min(InventoryComponent->Items.Num(), FMath::Max(1, MaxInventoryPanelRows));
|
||||||
|
const float LineHeight = 18.0f * Scale;
|
||||||
|
const float PanelHeight = (56.0f * Scale) + (VisibleRows * LineHeight);
|
||||||
|
|
||||||
|
DrawRect(FLinearColor(0.02f, 0.025f, 0.02f, 0.72f), X - (12.0f * Scale), Y - (10.0f * Scale), PanelWidth, PanelHeight);
|
||||||
|
DrawText(
|
||||||
|
FString::Printf(
|
||||||
|
TEXT("INVENTORY %d/%d slots %.1f wt"),
|
||||||
|
InventoryComponent->Items.Num(),
|
||||||
|
InventoryComponent->MaxSlots,
|
||||||
|
InventoryComponent->GetTotalWeight()),
|
||||||
|
FColor(160, 220, 140),
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
nullptr,
|
||||||
|
Scale,
|
||||||
|
false);
|
||||||
|
Y += 24.0f * Scale;
|
||||||
|
|
||||||
|
if (InventoryComponent->Items.IsEmpty())
|
||||||
|
{
|
||||||
|
DrawText(TEXT("Empty"), FColor::Silver, X, Y, nullptr, Scale, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32 Index = 0; Index < VisibleRows; ++Index)
|
||||||
|
{
|
||||||
|
const FAgrarianItemStack& Stack = InventoryComponent->Items[Index];
|
||||||
|
const FText DisplayName = Stack.DisplayName.IsEmpty() ? FText::FromName(Stack.ItemId) : Stack.DisplayName;
|
||||||
|
FString ItemName = DisplayName.ToString();
|
||||||
|
if (ItemName.Len() > 24)
|
||||||
|
{
|
||||||
|
ItemName = ItemName.Left(21) + TEXT("...");
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawText(
|
||||||
|
FString::Printf(TEXT("%02d %-24s x%-3d %5.1f"), Index + 1, *ItemName, Stack.Quantity, Stack.UnitWeight * Stack.Quantity),
|
||||||
|
FColor(225, 235, 220),
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
nullptr,
|
||||||
|
Scale,
|
||||||
|
false);
|
||||||
|
Y += LineHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AAgrarianDebugHUD::DrawPlayerStatus(const AAgrarianGameCharacter* AgrarianCharacter, float X, float& Y)
|
void AAgrarianDebugHUD::DrawPlayerStatus(const AAgrarianGameCharacter* AgrarianCharacter, float X, float& Y)
|
||||||
{
|
{
|
||||||
if (!AgrarianCharacter)
|
if (!AgrarianCharacter)
|
||||||
|
|||||||
@@ -23,12 +23,21 @@ public:
|
|||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD")
|
||||||
bool bShowCriticalStatsHUD = true;
|
bool bShowCriticalStatsHUD = true;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD")
|
||||||
|
bool bShowInventoryHUD = true;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD", meta = (ClampMin = "0.25"))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD", meta = (ClampMin = "0.25"))
|
||||||
float TextScale = 1.0f;
|
float TextScale = 1.0f;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD", meta = (ClampMin = "0.25"))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD", meta = (ClampMin = "0.25"))
|
||||||
float CriticalStatsTextScale = 1.0f;
|
float CriticalStatsTextScale = 1.0f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD", meta = (ClampMin = "0.25"))
|
||||||
|
float InventoryTextScale = 0.9f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD", meta = (ClampMin = "1", ClampMax = "12"))
|
||||||
|
int32 MaxInventoryPanelRows = 6;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD")
|
||||||
bool bShowInteractionPrompt = true;
|
bool bShowInteractionPrompt = true;
|
||||||
|
|
||||||
@@ -38,6 +47,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
void DrawInteractionPrompt(const class AAgrarianGameCharacter* AgrarianCharacter);
|
void DrawInteractionPrompt(const class AAgrarianGameCharacter* AgrarianCharacter);
|
||||||
void DrawCriticalStats(const UAgrarianSurvivalComponent* SurvivalComponent);
|
void DrawCriticalStats(const UAgrarianSurvivalComponent* SurvivalComponent);
|
||||||
|
void DrawInventoryPanel(const class AAgrarianGameCharacter* AgrarianCharacter);
|
||||||
void DrawPlayerStatus(const class AAgrarianGameCharacter* AgrarianCharacter, float X, float& Y);
|
void DrawPlayerStatus(const class AAgrarianGameCharacter* AgrarianCharacter, float X, float& Y);
|
||||||
void DrawSurvival(const UAgrarianSurvivalComponent* SurvivalComponent, float X, float& Y);
|
void DrawSurvival(const UAgrarianSurvivalComponent* SurvivalComponent, float X, float& Y);
|
||||||
void DrawInventory(const UAgrarianInventoryComponent* InventoryComponent, float X, float& Y);
|
void DrawInventory(const UAgrarianInventoryComponent* InventoryComponent, float X, float& Y);
|
||||||
|
|||||||
Reference in New Issue
Block a user