import unreal EXPECTED = { "/Game/Agrarian/Blueprints/Resources/BP_WoodResourceNode": { "properties": { "remaining_harvests": 16, "quantity_per_harvest": 2, }, "yield_item_id": "wood", }, "/Game/Agrarian/Blueprints/Resources/BP_FiberResourceNode": { "properties": { "remaining_harvests": 10, "quantity_per_harvest": 3, }, "yield_item_id": "fiber", }, "/Game/Agrarian/Blueprints/Resources/BP_StoneResourceNode": { "properties": { "remaining_harvests": 12, "quantity_per_harvest": 2, }, "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, "warmth_radius": 650.0, "warmth_per_second": 0.03, }, }, "/Game/Agrarian/Blueprints/World/BP_FreshWaterSource": { "properties": { "water_restore_amount": 45.0, }, }, "/Game/Agrarian/Blueprints/Structures/BP_PrimitiveShelter": { "properties": { "weather_protection": 0.7, }, }, "/Game/Agrarian/Blueprints/Wildlife/BP_RabbitWildlife": { "properties": { "wildlife_id": "rabbit", "max_health": 12.0, "health": 12.0, "wander_radius": 900.0, "wander_speed": 160.0, "flee_speed": 520.0, "aggro_radius": 0.0, "flee_radius": 750.0, "decision_interval_seconds": 1.5, }, "harvest_yield_ids": ["meat", "hide"], }, } def nearly_equal(left, right): if isinstance(left, float) or isinstance(right, float): return abs(float(left) - float(right)) < 0.001 return left == right def main(): failures = [] for path, expected in EXPECTED.items(): blueprint = unreal.EditorAssetLibrary.load_asset(path) if not blueprint: failures.append(f"{path} missing") continue generated_class = unreal.EditorAssetLibrary.load_blueprint_class(path) if not generated_class: failures.append(f"{path} parent class mismatch") continue 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) 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}") expected_yield_item_id = expected.get("yield_item_id") if expected_yield_item_id: item_asset = cdo.get_editor_property("yield_item_definition") definition = item_asset.get_editor_property("definition") if item_asset else None item_id = str(definition.get_editor_property("item_id")) if definition else "" if item_id != expected_yield_item_id: failures.append(f"{path} yield_item_definition expected {expected_yield_item_id}, got {item_id}") expected_harvest_ids = expected.get("harvest_yield_ids") if expected_harvest_ids: harvest_yields = cdo.get_editor_property("harvest_yields") actual_ids = [str(stack.get_editor_property("item_id")) for stack in harvest_yields] if actual_ids != expected_harvest_ids: failures.append(f"{path} harvest_yields expected {expected_harvest_ids}, got {actual_ids}") if failures: raise RuntimeError("Playable Blueprint verification failed: " + "; ".join(failures)) unreal.log("Agrarian playable Blueprint verification complete.") main()