Add campfire cooking placeholder
This commit is contained in:
@@ -587,7 +587,9 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe
|
||||
update path used by natural fuel depletion.
|
||||
- [x] Add warmth radius.
|
||||
- [x] Add light source.
|
||||
- [ ] Add cooking placeholder if needed.
|
||||
- [x] Add cooking placeholder if needed. Added replicated campfire cooking
|
||||
placeholder state, a native cookability check, and progress ratio helpers so
|
||||
later recipe UI and food systems have a stable hook.
|
||||
- [ ] Add smoke/visual effect placeholder.
|
||||
- [x] Add replication.
|
||||
- [ ] Add persistence.
|
||||
|
||||
@@ -292,6 +292,11 @@ Campfires expose native extinguish logic through `AAgrarianCampfire::Extinguish`
|
||||
Extinguishing clears remaining fuel, turns off replicated lit state, and reuses
|
||||
the same visual update path as natural fuel depletion.
|
||||
|
||||
Campfires also expose a minimal replicated cooking placeholder. While lit and
|
||||
enabled, `AAgrarianCampfire` advances `CookingProgressSeconds` toward
|
||||
`CookingSecondsRequired` on the server and exposes `CanCook` plus a normalized
|
||||
progress ratio for future recipe UI, food transformation, and interaction hooks.
|
||||
|
||||
The first real-weather adapter is `UAgrarianWeatherProviderSubsystem`. It uses
|
||||
Open-Meteo forecast requests keyed by tile center latitude/longitude, parses the
|
||||
current temperature, daily low/high, precipitation, wind, humidity, cloud cover,
|
||||
|
||||
@@ -207,6 +207,22 @@ def make_stack(data):
|
||||
return stack
|
||||
|
||||
|
||||
def set_default_property(cdo, property_name, value):
|
||||
property_names = [property_name]
|
||||
if isinstance(value, bool):
|
||||
property_names.append(f"b_{property_name}")
|
||||
property_names.append("b" + "".join(part.capitalize() for part in property_name.split("_")))
|
||||
|
||||
for reflected_name in property_names:
|
||||
try:
|
||||
cdo.set_editor_property(reflected_name, value)
|
||||
return
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
raise RuntimeError(f"Could not set default property {property_name}")
|
||||
|
||||
|
||||
def apply_defaults(blueprint, config):
|
||||
blueprint_path = f"{config['folder']}/{config['asset']}"
|
||||
unreal.BlueprintEditorLibrary.compile_blueprint(blueprint)
|
||||
@@ -222,7 +238,7 @@ def apply_defaults(blueprint, config):
|
||||
elif property_name == "harvest_yields":
|
||||
value = [make_stack(stack_data) for stack_data in value]
|
||||
|
||||
cdo.set_editor_property(property_name, value)
|
||||
set_default_property(cdo, property_name, value)
|
||||
|
||||
mesh_path = config.get("mesh")
|
||||
if mesh_path:
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
REQUIRED = {
|
||||
ROOT / "Source" / "AgrarianGame" / "AgrarianCampfire.h": [
|
||||
"bool bCookingPlaceholderEnabled = true;",
|
||||
"float CookingSecondsRequired = 30.0f;",
|
||||
"float CookingProgressSeconds = 0.0f;",
|
||||
"bool CanCook() const;",
|
||||
"float GetCookingProgressRatio() const;",
|
||||
],
|
||||
ROOT / "Source" / "AgrarianGame" / "AgrarianCampfire.cpp": [
|
||||
"DOREPLIFETIME(AAgrarianCampfire, bCookingPlaceholderEnabled);",
|
||||
"DOREPLIFETIME(AAgrarianCampfire, CookingSecondsRequired);",
|
||||
"DOREPLIFETIME(AAgrarianCampfire, CookingProgressSeconds);",
|
||||
"CookingProgressSeconds = FMath::Min(CookingSecondsRequired, CookingProgressSeconds + DeltaSeconds);",
|
||||
"bool AAgrarianCampfire::CanCook() const",
|
||||
"float AAgrarianCampfire::GetCookingProgressRatio() const",
|
||||
],
|
||||
ROOT / "Scripts" / "setup_playable_blueprints.py": [
|
||||
"def set_default_property(cdo, property_name, value):",
|
||||
"property_names.append(f\"b_{property_name}\")",
|
||||
"property_names.append(\"b\" + \"\".join(part.capitalize() for part in property_name.split(\"_\")))",
|
||||
],
|
||||
ROOT / "Scripts" / "verify_playable_blueprints.py": [
|
||||
"def get_property(cdo, property_name, expected_value):",
|
||||
"property_names.append(f\"b_{property_name}\")",
|
||||
"property_names.append(\"b\" + \"\".join(part.capitalize() for part in property_name.split(\"_\")))",
|
||||
],
|
||||
ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md": [
|
||||
"- [x] Add cooking placeholder if needed.",
|
||||
],
|
||||
ROOT / "Docs" / "TechnicalDesignDocument.md": [
|
||||
"minimal replicated cooking placeholder",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
missing = []
|
||||
for path, snippets in REQUIRED.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 SystemExit("Campfire cooking placeholder verification failed:\n" + "\n".join(missing))
|
||||
|
||||
print("PASS: campfire cooking placeholder is implemented and documented.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -94,6 +94,21 @@ def nearly_equal(left, right):
|
||||
return left == right
|
||||
|
||||
|
||||
def get_property(cdo, property_name, expected_value):
|
||||
property_names = [property_name]
|
||||
if isinstance(expected_value, bool):
|
||||
property_names.append(f"b_{property_name}")
|
||||
property_names.append("b" + "".join(part.capitalize() for part in property_name.split("_")))
|
||||
|
||||
for reflected_name in property_names:
|
||||
try:
|
||||
return cdo.get_editor_property(reflected_name)
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
raise RuntimeError(f"Could not read property {property_name}")
|
||||
|
||||
|
||||
def main():
|
||||
failures = []
|
||||
|
||||
@@ -110,7 +125,7 @@ def main():
|
||||
|
||||
cdo = unreal.get_default_object(generated_class)
|
||||
for property_name, expected_value in expected.get("properties", {}).items():
|
||||
actual_value = cdo.get_editor_property(property_name)
|
||||
actual_value = get_property(cdo, property_name, expected_value)
|
||||
if str(actual_value) != expected_value and not nearly_equal(actual_value, expected_value):
|
||||
failures.append(f"{path} {property_name} expected {expected_value}, got {actual_value}")
|
||||
|
||||
|
||||
@@ -36,6 +36,11 @@ void AAgrarianCampfire::Tick(float DeltaSeconds)
|
||||
SetLit(false);
|
||||
}
|
||||
|
||||
if (CanCook())
|
||||
{
|
||||
CookingProgressSeconds = FMath::Min(CookingSecondsRequired, CookingProgressSeconds + DeltaSeconds);
|
||||
}
|
||||
|
||||
WarmNearbyCharacters(DeltaSeconds);
|
||||
}
|
||||
}
|
||||
@@ -45,6 +50,9 @@ void AAgrarianCampfire::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& Ou
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
DOREPLIFETIME(AAgrarianCampfire, bLit);
|
||||
DOREPLIFETIME(AAgrarianCampfire, FuelSeconds);
|
||||
DOREPLIFETIME(AAgrarianCampfire, bCookingPlaceholderEnabled);
|
||||
DOREPLIFETIME(AAgrarianCampfire, CookingSecondsRequired);
|
||||
DOREPLIFETIME(AAgrarianCampfire, CookingProgressSeconds);
|
||||
}
|
||||
|
||||
FText AAgrarianCampfire::GetInteractionText_Implementation(const AAgrarianGameCharacter* Interactor) const
|
||||
@@ -96,6 +104,21 @@ void AAgrarianCampfire::Extinguish()
|
||||
}
|
||||
}
|
||||
|
||||
bool AAgrarianCampfire::CanCook() const
|
||||
{
|
||||
return bLit && bCookingPlaceholderEnabled && CookingSecondsRequired > 0.0f;
|
||||
}
|
||||
|
||||
float AAgrarianCampfire::GetCookingProgressRatio() const
|
||||
{
|
||||
if (CookingSecondsRequired <= 0.0f)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return FMath::Clamp(CookingProgressSeconds / CookingSecondsRequired, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
void AAgrarianCampfire::OnRep_FireState()
|
||||
{
|
||||
UpdateVisualState();
|
||||
|
||||
@@ -39,6 +39,15 @@ public:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Fire", meta = (ClampMin = "0"))
|
||||
float WarmthPerSecond = 0.02f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "Agrarian|Fire|Cooking")
|
||||
bool bCookingPlaceholderEnabled = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "Agrarian|Fire|Cooking", meta = (ClampMin = "0"))
|
||||
float CookingSecondsRequired = 30.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "Agrarian|Fire|Cooking", meta = (ClampMin = "0"))
|
||||
float CookingProgressSeconds = 0.0f;
|
||||
|
||||
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;
|
||||
@@ -49,6 +58,12 @@ public:
|
||||
UFUNCTION(BlueprintCallable, Category = "Agrarian|Fire")
|
||||
void Extinguish();
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Agrarian|Fire|Cooking")
|
||||
bool CanCook() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Agrarian|Fire|Cooking")
|
||||
float GetCookingProgressRatio() const;
|
||||
|
||||
protected:
|
||||
UFUNCTION()
|
||||
void OnRep_FireState();
|
||||
|
||||
Reference in New Issue
Block a user