diff --git a/AGRARIAN_DEVELOPMENT_ROADMAP.md b/AGRARIAN_DEVELOPMENT_ROADMAP.md index 168653b..05b5a46 100644 --- a/AGRARIAN_DEVELOPMENT_ROADMAP.md +++ b/AGRARIAN_DEVELOPMENT_ROADMAP.md @@ -533,7 +533,9 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe `BP_StoneResourceNode`, placed in the Ground Zero resource pass, and covered by focused stone-resource verification. - [x] Add fiber resource. -- [ ] Add edible plant resource. +- [x] Add edible plant resource. Added `BP_EdiblePlantResourceNode` as a + gatherable food-yield node, placed deterministic Ground Zero forage nodes, and + extended resource verification to cover edible plant harvest sources. - [ ] Add water gathering interaction. - [x] Add resource depletion. - [ ] Add respawn rules for MVP. diff --git a/Content/Agrarian/Blueprints/Resources/BP_EdiblePlantResourceNode.uasset b/Content/Agrarian/Blueprints/Resources/BP_EdiblePlantResourceNode.uasset new file mode 100644 index 0000000..fd42a9d --- /dev/null +++ b/Content/Agrarian/Blueprints/Resources/BP_EdiblePlantResourceNode.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5cacd9ec819a6ddbf4446aa24250bb5f2ddb738fa118cff7f9d9fcf302818fdf +size 24716 diff --git a/Content/Agrarian/Maps/L_GroundZeroTerrain_Test.umap b/Content/Agrarian/Maps/L_GroundZeroTerrain_Test.umap index 55cccdb..617a7b0 100644 --- a/Content/Agrarian/Maps/L_GroundZeroTerrain_Test.umap +++ b/Content/Agrarian/Maps/L_GroundZeroTerrain_Test.umap @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:580adc112b44b622efd99ca0f91668a19a678cfcc719b589688f2507daf00c79 -size 7485609 +oid sha256:f207ef59e6a315690ba89c0aec9be6ab6e08c5902e971e9f2e144a2d0fd05cf6 +size 7491637 diff --git a/Content/Agrarian/Materials/M_AGR_GZ_EdiblePlant_Resource.uasset b/Content/Agrarian/Materials/M_AGR_GZ_EdiblePlant_Resource.uasset new file mode 100644 index 0000000..1d5fc93 --- /dev/null +++ b/Content/Agrarian/Materials/M_AGR_GZ_EdiblePlant_Resource.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28006641db81f6ef4d8f507c38b76da85e914051c67054127f5d093df2d73e8c +size 5489 diff --git a/Docs/TechnicalDesignDocument.md b/Docs/TechnicalDesignDocument.md index 3203e74..3afc752 100644 --- a/Docs/TechnicalDesignDocument.md +++ b/Docs/TechnicalDesignDocument.md @@ -418,14 +418,17 @@ Data Assets should describe content. Server code should enforce gameplay rules. ### Gatherable Resources The 0.1.F resource baseline uses `AAgrarianResourceNode` for simple gatherable -world resources. Wood, fiber, and stone each have item definitions, resource -Blueprints, deterministic Ground Zero placements, replicated remaining harvest -counts, and bare-hand gathering through the shared interaction path. +world resources. Wood, fiber, stone, and edible plants each have item +definitions or yield definitions, resource Blueprints, deterministic Ground Zero +placements, replicated remaining harvest counts, and bare-hand gathering through +the shared interaction path. Stone specifically is represented by `DA_Item_Stone` and `BP_StoneResourceNode`. Ground Zero includes stone nodes in slope, exposed terrain, and valley-edge positions so primitive tools, campfires, and early construction recipes have an in-world source instead of relying on debug grants. +Edible plants are represented by `BP_EdiblePlantResourceNode`, which yields the +MVP `food` item from scrub, grassland, and drainage-candidate forage patches. ### Wildlife Navigation diff --git a/Docs/Terrain/GroundZeroResourcePass.md b/Docs/Terrain/GroundZeroResourcePass.md index 37510f5..984dd82 100644 --- a/Docs/Terrain/GroundZeroResourcePass.md +++ b/Docs/Terrain/GroundZeroResourcePass.md @@ -8,6 +8,8 @@ height, slope, and drainage-candidate analysis. - Wood: scrub/woodland and hillside patches. - Fiber: grassland, scrub, and drainage-candidate areas. +- Edible plants: coastal scrub, grassland, and drainage-candidate forage + patches that yield the MVP `food` item. - Stone: slope, exposed terrain, and valley-edge areas. Freshwater remains separate because the water-source roadmap item follows this @@ -16,6 +18,8 @@ pass and should be implemented as its own gameplay actor/system. ## Implementation - Added `BP_StoneResourceNode` through `Scripts/setup_playable_blueprints.py`. +- Added `BP_EdiblePlantResourceNode` through + `Scripts/setup_playable_blueprints.py`. - Updated `Scripts/setup_ground_zero_demo_map.py` to place deterministic Ground Zero resource nodes. - Added `Scripts/verify_ground_zero_resources.py` to validate node presence, @@ -27,6 +31,7 @@ The map now contains: - Wood nodes: `4` - Fiber nodes: `5` +- Edible plant nodes: `3` - Stone nodes: `4` These counts include the original demo wood and fiber nodes so the first player diff --git a/Scripts/setup_ground_zero_demo_map.py b/Scripts/setup_ground_zero_demo_map.py index 7632e46..a3381e0 100644 --- a/Scripts/setup_ground_zero_demo_map.py +++ b/Scripts/setup_ground_zero_demo_map.py @@ -73,6 +73,11 @@ ENVIRONMENT_MATERIALS = { "color": unreal.LinearColor(0.55, 0.49, 0.28, 1.0), "roughness": 0.93, }, + "edible_plant_resource": { + "path": f"{MATERIAL_FOLDER}/M_AGR_GZ_EdiblePlant_Resource", + "color": unreal.LinearColor(0.22, 0.46, 0.18, 1.0), + "roughness": 0.9, + }, "stone_resource": { "path": f"{MATERIAL_FOLDER}/M_AGR_GZ_Stone_Sandstone", "color": unreal.LinearColor(0.43, 0.40, 0.35, 1.0), @@ -87,6 +92,7 @@ ENVIRONMENT_MATERIALS = { RESOURCE_MATERIAL_BY_LABEL_PREFIX = { "AGR_GZ_Wood": "wood_resource", "AGR_GZ_Fiber": "fiber_resource", + "AGR_GZ_EdiblePlant": "edible_plant_resource", "AGR_GZ_Stone": "stone_resource", "AGR_DemoWoodResource": "wood_resource", "AGR_DemoFiberResource": "fiber_resource", @@ -245,6 +251,27 @@ BIOME_RESOURCE_ACTORS = [ "z_offset": 65.0, "rotation": unreal.Rotator(0.0, 114.0, 0.0), }, + { + "label": "AGR_GZ_EdiblePlant_CoastalScrub_01", + "class_path": "/Game/Agrarian/Blueprints/Resources/BP_EdiblePlantResourceNode", + "location_xy": unreal.Vector(-31400.0, -7600.0, 0.0), + "z_offset": 58.0, + "rotation": unreal.Rotator(0.0, 21.0, 0.0), + }, + { + "label": "AGR_GZ_EdiblePlant_Grassland_02", + "class_path": "/Game/Agrarian/Blueprints/Resources/BP_EdiblePlantResourceNode", + "location_xy": unreal.Vector(6200.0, -26800.0, 0.0), + "z_offset": 58.0, + "rotation": unreal.Rotator(0.0, -48.0, 0.0), + }, + { + "label": "AGR_GZ_EdiblePlant_DrainageCandidate_03", + "class_path": "/Game/Agrarian/Blueprints/Resources/BP_EdiblePlantResourceNode", + "location_xy": unreal.Vector(-9400.0, 12800.0, 0.0), + "z_offset": 58.0, + "rotation": unreal.Rotator(0.0, 96.0, 0.0), + }, { "label": "AGR_GZ_Stone_Slope_01", "class_path": "/Game/Agrarian/Blueprints/Resources/BP_StoneResourceNode", diff --git a/Scripts/setup_playable_blueprints.py b/Scripts/setup_playable_blueprints.py index d8d42a7..aa6ef02 100644 --- a/Scripts/setup_playable_blueprints.py +++ b/Scripts/setup_playable_blueprints.py @@ -10,6 +10,7 @@ WORLD_FOLDER = f"{BLUEPRINT_ROOT}/World" WOOD_ITEM_PATH = "/Game/Agrarian/DataAssets/Items/DA_Item_Wood" FIBER_ITEM_PATH = "/Game/Agrarian/DataAssets/Items/DA_Item_Fiber" STONE_ITEM_PATH = "/Game/Agrarian/DataAssets/Items/DA_Item_Stone" +FOOD_ITEM_PATH = "/Game/Agrarian/DataAssets/Items/DA_Item_Food" PLACEHOLDER_MESH_FOLDER = "/Game/Agrarian/Environment/PlaceholderMeshes" PLACEHOLDER_MESH_SOURCES = { @@ -60,6 +61,18 @@ BLUEPRINTS = [ "mesh": MESH_CUBE_PATH, "scale": unreal.Vector(0.9, 0.75, 0.45), }, + { + "asset": "BP_EdiblePlantResourceNode", + "folder": RESOURCE_FOLDER, + "parent": unreal.AgrarianResourceNode, + "defaults": { + "yield_item_definition": FOOD_ITEM_PATH, + "remaining_harvests": 8, + "quantity_per_harvest": 1, + }, + "mesh": MESH_CYLINDER_PATH, + "scale": unreal.Vector(0.65, 0.65, 0.85), + }, { "asset": "BP_Campfire", "folder": STRUCTURE_FOLDER, diff --git a/Scripts/verify_edible_plant_resource.py b/Scripts/verify_edible_plant_resource.py new file mode 100644 index 0000000..7944403 --- /dev/null +++ b/Scripts/verify_edible_plant_resource.py @@ -0,0 +1,80 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +FILES = { + "setup_item_definitions.py": ROOT / "Scripts" / "setup_item_definitions.py", + "setup_playable_blueprints.py": ROOT / "Scripts" / "setup_playable_blueprints.py", + "setup_ground_zero_demo_map.py": ROOT / "Scripts" / "setup_ground_zero_demo_map.py", + "verify_playable_blueprints.py": ROOT / "Scripts" / "verify_playable_blueprints.py", + "verify_ground_zero_resources.py": ROOT / "Scripts" / "verify_ground_zero_resources.py", + "GroundZeroResourcePass.md": ROOT / "Docs" / "Terrain" / "GroundZeroResourcePass.md", + "TechnicalDesignDocument.md": ROOT / "Docs" / "TechnicalDesignDocument.md", + "AGRARIAN_DEVELOPMENT_ROADMAP.md": ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md", +} + +EXPECTED = { + "setup_item_definitions.py": [ + '"asset": "DA_Item_Food"', + '"item_id": "food"', + '"item_type": unreal.AgrarianItemType.FOOD', + ], + "setup_playable_blueprints.py": [ + 'FOOD_ITEM_PATH = "/Game/Agrarian/DataAssets/Items/DA_Item_Food"', + '"asset": "BP_EdiblePlantResourceNode"', + '"yield_item_definition": FOOD_ITEM_PATH', + '"remaining_harvests": 8', + '"quantity_per_harvest": 1', + ], + "setup_ground_zero_demo_map.py": [ + '"edible_plant_resource"', + '"/Game/Agrarian/Blueprints/Resources/BP_EdiblePlantResourceNode"', + '"AGR_GZ_EdiblePlant_CoastalScrub_01"', + '"AGR_GZ_EdiblePlant_Grassland_02"', + '"AGR_GZ_EdiblePlant_DrainageCandidate_03"', + ], + "verify_playable_blueprints.py": [ + '"/Game/Agrarian/Blueprints/Resources/BP_EdiblePlantResourceNode"', + '"yield_item_id": "food"', + ], + "verify_ground_zero_resources.py": [ + '"food": [', + '"AGR_GZ_EdiblePlant_CoastalScrub_01"', + "edible plant", + ], + "GroundZeroResourcePass.md": [ + "Edible plants:", + "`food` item", + "Added `BP_EdiblePlantResourceNode`", + "Edible plant nodes: `3`", + ], + "TechnicalDesignDocument.md": [ + "edible plants", + "`BP_EdiblePlantResourceNode`", + "MVP `food` item", + "forage patches", + ], + "AGRARIAN_DEVELOPMENT_ROADMAP.md": [ + "[x] Add edible plant resource.", + "`BP_EdiblePlantResourceNode`", + "Ground Zero forage nodes", + ], +} + + +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("Edible plant resource verification failed: " + "; ".join(missing)) + + print("Agrarian edible plant resource verification complete.") + + +if __name__ == "__main__": + main() diff --git a/Scripts/verify_ground_zero_resources.py b/Scripts/verify_ground_zero_resources.py index fd654ce..ae34815 100644 --- a/Scripts/verify_ground_zero_resources.py +++ b/Scripts/verify_ground_zero_resources.py @@ -17,6 +17,11 @@ EXPECTED_RESOURCE_LABELS = { "AGR_GZ_Fiber_Scrub_03", "AGR_GZ_Fiber_DrainageCandidate_04", ], + "food": [ + "AGR_GZ_EdiblePlant_CoastalScrub_01", + "AGR_GZ_EdiblePlant_Grassland_02", + "AGR_GZ_EdiblePlant_DrainageCandidate_03", + ], "stone": [ "AGR_GZ_Stone_Slope_01", "AGR_GZ_Stone_Slope_02", @@ -67,6 +72,7 @@ def main(): "Ground Zero resource verification complete: " f"{len(EXPECTED_RESOURCE_LABELS['wood'])} wood, " f"{len(EXPECTED_RESOURCE_LABELS['fiber'])} fiber, " + f"{len(EXPECTED_RESOURCE_LABELS['food'])} edible plant, " f"{len(EXPECTED_RESOURCE_LABELS['stone'])} stone nodes." ) diff --git a/Scripts/verify_playable_blueprints.py b/Scripts/verify_playable_blueprints.py index 1705645..5850823 100644 --- a/Scripts/verify_playable_blueprints.py +++ b/Scripts/verify_playable_blueprints.py @@ -23,6 +23,13 @@ EXPECTED = { }, "yield_item_id": "stone", }, + "/Game/Agrarian/Blueprints/Resources/BP_EdiblePlantResourceNode": { + "properties": { + "remaining_harvests": 8, + "quantity_per_harvest": 1, + }, + "yield_item_id": "food", + }, "/Game/Agrarian/Blueprints/Structures/BP_Campfire": { "properties": { "fuel_seconds": 180.0,