87 lines
4.7 KiB
Python
87 lines
4.7 KiB
Python
"""An isolated generated map, simple meshes and a ready-to-use character."""
|
|
import unreal
|
|
|
|
from .paths import GENERATED, slug
|
|
|
|
|
|
class Scene:
|
|
"""Owns one map. Building again replaces only that generated map's actors."""
|
|
|
|
def __init__(self, name="MyShot"):
|
|
from . import render
|
|
if render.is_rendering() or unreal.get_editor_subsystem(unreal.MoviePipelineQueueSubsystem).is_rendering():
|
|
raise RuntimeError("Poczekaj na zakonczenie renderu przed przebudowa sceny.")
|
|
# Discard Sequencer's live bindings before replacing their actors.
|
|
current_sequence = unreal.LevelSequenceEditorBlueprintLibrary.get_current_level_sequence()
|
|
if current_sequence and current_sequence.get_path_name().startswith(GENERATED + "/"):
|
|
unreal.LevelSequenceEditorBlueprintLibrary.close_level_sequence()
|
|
self.name = slug(name)
|
|
self.map_path = f"{GENERATED}/{name}/Map"
|
|
self.subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
|
|
editor = unreal.get_editor_subsystem(unreal.LevelEditorSubsystem)
|
|
current = editor.get_current_level()
|
|
current_path = current.get_outer().get_path_name().split(".")[0] if current else ""
|
|
if current_path == self.map_path:
|
|
# This map is wholly generated by this exercise, never a user's other map.
|
|
for actor in self.subsystem.get_all_level_actors():
|
|
if "Workshop" in [str(tag) for tag in actor.tags]:
|
|
self.subsystem.destroy_actor(actor)
|
|
else:
|
|
if unreal.EditorLoadingAndSavingUtils.get_dirty_map_packages():
|
|
raise RuntimeError("Zapisz zmiany aktualnej mapy przed utworzeniem sceny warsztatowej.")
|
|
if unreal.EditorAssetLibrary.does_asset_exist(self.map_path):
|
|
if not editor.load_level(self.map_path):
|
|
raise RuntimeError("Nie mozna otworzyc " + self.map_path)
|
|
for actor in self.subsystem.get_all_level_actors():
|
|
if "Workshop" in [str(tag) for tag in actor.tags]:
|
|
self.subsystem.destroy_actor(actor)
|
|
elif not editor.new_level(self.map_path):
|
|
raise RuntimeError("Nie mozna utworzyc " + self.map_path)
|
|
|
|
def spawn(self, actor_class, name, location=(0, 0, 0), rotation=(0, 0, 0)):
|
|
actor = self.subsystem.spawn_actor_from_class(actor_class, unreal.Vector(*location),
|
|
unreal.Rotator(*rotation))
|
|
if actor is None:
|
|
raise RuntimeError("Nie mozna utworzyc aktora " + name)
|
|
actor.set_actor_label(name)
|
|
actor.tags = ["Workshop"]
|
|
actor.set_folder_path("Workshop")
|
|
return actor
|
|
|
|
def mesh(self, asset, name="Model", location=(0, 0, 0), scale=(1, 1, 1), material=None):
|
|
mesh = unreal.load_asset(asset) if isinstance(asset, str) else asset
|
|
if not isinstance(mesh, unreal.StaticMesh):
|
|
raise TypeError(f"Oczekiwano StaticMesh: {asset}")
|
|
actor = self.spawn(unreal.StaticMeshActor, name, location)
|
|
actor.static_mesh_component.set_mobility(unreal.ComponentMobility.MOVABLE)
|
|
actor.static_mesh_component.set_static_mesh(mesh)
|
|
actor.set_actor_scale3d(unreal.Vector(*scale))
|
|
if material is not None:
|
|
actor.static_mesh_component.set_material(0, material)
|
|
return actor
|
|
|
|
def primitive(self, shape="Cube", **kwargs):
|
|
if shape not in {"Cube", "Sphere", "Cylinder", "Cone", "Plane"}:
|
|
raise ValueError("Ksztalt: Cube, Sphere, Cylinder, Cone lub Plane.")
|
|
return self.mesh(f"/Engine/BasicShapes/{shape}.{shape}", **kwargs)
|
|
|
|
def character(self, material=None, head_scale=1.0):
|
|
root = self.spawn(unreal.StaticMeshActor, "Character")
|
|
root.static_mesh_component.set_mobility(unreal.ComponentMobility.MOVABLE)
|
|
for shape, name, position, scale in [
|
|
("Cube", "Body", (0, 0, 90), (0.55, 0.8, 0.9)),
|
|
("Sphere", "Head", (0, 0, 175), (0.7 * head_scale,) * 3),
|
|
("Cube", "LeftLeg", (0, -23, 25), (0.35, 0.3, 0.5)),
|
|
("Cube", "RightLeg", (0, 23, 25), (0.35, 0.3, 0.5)),
|
|
("Sphere", "Nose", (34, 0, 177), (0.24, 0.2, 0.2)),
|
|
]:
|
|
actor = self.primitive(shape, name=name, location=position, scale=scale, material=material)
|
|
actor.attach_to_actor(root, "", unreal.AttachmentRule.KEEP_WORLD,
|
|
unreal.AttachmentRule.KEEP_WORLD, unreal.AttachmentRule.KEEP_WORLD, False)
|
|
return root
|
|
|
|
def save(self):
|
|
editor = unreal.get_editor_subsystem(unreal.LevelEditorSubsystem)
|
|
if not editor.save_current_level():
|
|
raise RuntimeError("Nie mozna zapisac mapy " + self.map_path)
|