using Godot; using System.Collections.Generic; // Shared plumbing for the editor-built maps (Playground, Crag). Each map is the ROOT of its own scene // (scenes/maps/*.tscn) with a [Tool] script whose Rebuild() regenerates every child from code and // gives it to the scene (Owner = the map root) so it is saved into the .tscn like hand-made nodes. // The game never regenerates: it loads what was saved, so edits made in the editor stick (until the // next Rebuild, which replaces ALL children). Rebuild from the inspector button with the map scene // open, or headless for agents: godot-mono --headless --path . tools/rebuild_maps.tscn public static class MapScene { public const string PropGroup = "prop"; // The inspector button only works with the map scene itself open (nodes owned by an instanced // sub-scene's root aren't saved into the outer scene). public static bool CanRebuildInEditor(Node map) { if (map.GetTree()?.EditedSceneRoot == map) return true; GD.PushWarning($"{map.Name}: open its own scene (scenes/maps/) to rebuild it — it's instanced here."); return false; } public static void Clear(Node map) { foreach (Node child in map.GetChildren()) { map.RemoveChild(child); child.Free(); } } // Every generated node belongs to the map scene; children of instanced sub-scenes (e.g. a // teleport marker) keep their own owner. public static void Adopt(Node map) { foreach (Node child in map.GetChildren()) Adopt(map, child); } private static void Adopt(Node root, Node node) { if (node.Owner == null) node.Owner = root; if (node.SceneFilePath != "") return; foreach (Node child in node.GetChildren()) Adopt(root, child); } public static void MarkUnsaved() { #if TOOLS if (Engine.IsEditorHint()) EditorInterface.Singleton.MarkSceneAsUnsaved(); #endif } // Runtime: the dynamic props (group "prop") and where they start, for Reset(). public static void CollectProps(Node map, List<(RigidBody3D Body, Transform3D Start)> props) { props.Clear(); foreach (Node child in map.GetChildren()) if (child is RigidBody3D body && body.IsInGroup(PropGroup)) props.Add((body, body.GlobalTransform)); } public static void Reset(List<(RigidBody3D Body, Transform3D Start)> props) { foreach (var (body, start) in props) { if (!GodotObject.IsInstanceValid(body)) continue; body.GlobalTransform = start; body.LinearVelocity = Vector3.Zero; body.AngularVelocity = Vector3.Zero; body.ResetPhysicsInterpolation(); } } }