import unreal MAP_PATH = "/Game/Agrarian/Maps/L_GroundZeroTerrain_Test" CHARACTER_CLASS_PATH = "/Game/Agrarian/Blueprints/Characters/BP_AgrarianPlayerCharacter" RABBIT_LABELS = ["AGR_DemoRabbitWildlife_01", "AGR_RabbitWildlife_01"] def get_actor_label(actor): try: return actor.get_actor_label() except Exception: return actor.get_name() def load_blueprint_class(path): generated_class = unreal.EditorAssetLibrary.load_blueprint_class(path) if not generated_class: raise RuntimeError(f"Could not load Blueprint class: {path}") return generated_class def find_actor_by_label(label): for actor in unreal.EditorLevelLibrary.get_all_level_actors(): if get_actor_label(actor) == label: return actor return None def find_actor_by_any_label(labels): for label in labels: actor = find_actor_by_label(label) if actor: return actor return None def enum_name(value): return str(value).split(".")[-1].lower() def get_bool_property(actor, *property_names): for property_name in property_names: try: return bool(actor.get_editor_property(property_name)) except Exception: continue raise RuntimeError(f"Could not read any bool property from {property_names}") def main(): if not unreal.EditorLevelLibrary.load_level(MAP_PATH): raise RuntimeError(f"Could not load map: {MAP_PATH}") character_class = load_blueprint_class(CHARACTER_CLASS_PATH) rabbit = find_actor_by_any_label(RABBIT_LABELS) if not rabbit: raise RuntimeError(f"Could not find placed rabbit wildlife by labels: {RABBIT_LABELS}") character = unreal.AgrarianEditorAutomationLibrary.spawn_actor_in_editor_world( character_class, unreal.Vector(500.0, 320.0, 180.0), unreal.Rotator(0.0, 0.0, 0.0), "AGR_AutomationWildlifeCharacter", ) if not character: raise RuntimeError("Could not spawn automation character") inventory = character.get_component_by_class(unreal.AgrarianInventoryComponent) if not inventory: raise RuntimeError("Automation character is missing AgrarianInventoryComponent") starting_health = float(rabbit.get_editor_property("health")) max_health = float(rabbit.get_editor_property("max_health")) if starting_health <= 0.0 or max_health <= 0.0: raise RuntimeError(f"Rabbit starts invalid health={starting_health}, max_health={max_health}") rabbit.apply_wildlife_damage(1.0, character) damaged_health = float(rabbit.get_editor_property("health")) damaged_state = enum_name(rabbit.get_editor_property("wildlife_state")) if not damaged_health < starting_health: raise RuntimeError(f"Rabbit non-lethal damage did not reduce health: {starting_health} -> {damaged_health}") if "fleeing" not in damaged_state: raise RuntimeError(f"Rabbit expected fleeing after non-lethal damage, got {damaged_state}") rabbit.apply_wildlife_damage(max_health + 10.0, character) dead_health = float(rabbit.get_editor_property("health")) dead_state = enum_name(rabbit.get_editor_property("wildlife_state")) if dead_health != 0.0: raise RuntimeError(f"Rabbit lethal damage expected health 0, got {dead_health}") if "dead" not in dead_state: raise RuntimeError(f"Rabbit expected dead after lethal damage, got {dead_state}") if not rabbit.can_interact(character): raise RuntimeError("Rabbit should be harvestable after death") meat_before = inventory.get_item_count("meat") hide_before = inventory.get_item_count("hide") rabbit.interact(character) meat_after = inventory.get_item_count("meat") hide_after = inventory.get_item_count("hide") if meat_after <= meat_before: raise RuntimeError(f"Rabbit harvest did not add meat: {meat_before} -> {meat_after}") if hide_after <= hide_before: raise RuntimeError(f"Rabbit harvest did not add hide: {hide_before} -> {hide_after}") if not get_bool_property(rabbit, "b_harvested", "harvested"): raise RuntimeError("Rabbit harvest did not set bHarvested") if rabbit.can_interact(character): raise RuntimeError("Rabbit should not be harvestable twice") unreal.EditorLevelLibrary.destroy_actor(character) unreal.log( "PASS: wildlife damage/death/harvest verified " f"health {starting_health}->{damaged_health}->0, " f"meat {meat_before}->{meat_after}, hide {hide_before}->{hide_after}" ) main()