Maps are editor-built scenes: [Tool] Playground/Crag, headless rebuild for agents

scenes/maps/playground.tscn and crag.tscn are generated by the map scripts' Rebuild (inspector
button, or godot-mono --headless --path . tools/rebuild_maps.tscn) and loaded as saved by the game,
so hand edits stick. The crag route is saved as Marker3D nodes and crag_spike checks the saved
scene. Layout verified identical to the code-built one (tools/map_dump.tscn).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
FoxyzandClaude Opus 5.5 committed 2026-10-02 20:10:10 +03:00
1 parent 3e300c7f04
commit df7a2c5a89
17 files changed
+6863 -65

No files matched your search

+62
View File
@@ -0,0 +1,62 @@
using Godot;
using System.Collections.Generic;
using System.Linq;
// Dumps the map layout (type, transform, shape/mesh size, groups) sorted, for before/after comparison.
// godot-mono --headless --path . tools/map_dump.tscn -- out=<file>
public partial class MapDump : Node3D
{
private int _frame;
public override void _Ready()
{
foreach (string path in RebuildMaps.Maps)
AddChild(GD.Load<PackedScene>(path).Instantiate());
}
public override void _Process(double delta)
{
if (++_frame < 3)
return;
string outPath = "/tmp/claude-1000/maps/dump.txt";
foreach (string a in OS.GetCmdlineUserArgs())
if (a.StartsWith("out="))
outPath = a[4..];
var lines = new List<string>();
foreach (Node map in GetChildren())
Walk(map, map.GetType().Name, lines);
lines.Sort(System.StringComparer.Ordinal);
System.IO.File.WriteAllLines(outPath, lines);
GD.Print($"MAPDUMP: {lines.Count} nodes → {outPath}");
GetTree().Quit();
}
private static string R(Vector3 v) => $"({v.X:F3},{v.Y:F3},{v.Z:F3})";
private void Walk(Node n, string map, List<string> lines)
{
foreach (Node ch in n.GetChildren())
{
string info = ch.GetClass();
if (ch is Node3D n3)
{
Transform3D t = n3.GlobalTransform;
info += $" o{R(t.Origin)} x{R(t.Basis.X)} y{R(t.Basis.Y)}";
}
if (ch is CollisionShape3D cs && cs.Shape is BoxShape3D bs) info += $" box{R(bs.Size)}";
if (ch is CollisionShape3D cc && cc.Shape is CylinderShape3D cy) info += $" cyl{cy.Radius:F3}/{cy.Height:F3}";
if (ch is CollisionShape3D cp && cp.Shape is SphereShape3D sp) info += $" sph{sp.Radius:F3}";
if (ch is MeshInstance3D mi && mi.GetSurfaceOverrideMaterial(0) is StandardMaterial3D m) info += $" col{m.AlbedoColor.ToHtml()} sh{(int)mi.CastShadow}";
if (ch is Label3D l) info += $" text[{l.Text}] px{l.PixelSize:F4}";
if (ch is CollisionObject3D co) info += $" L{co.CollisionLayer}/{co.CollisionMask}";
if (ch is RigidBody3D rb) info += $" m{rb.Mass:F2} f{rb.PhysicsMaterialOverride?.Friction:F2}";
var groups = ch.GetGroups().Select(g => g.ToString()).Where(g => !g.StartsWith("_")).OrderBy(g => g);
info += " g[" + string.Join(",", groups) + "]";
if (ch is Joint3D j) info += $" joint {j.GetNodeOrNull(j.NodeA)?.GetClass()}@{R((j.GetNodeOrNull(j.NodeA) as Node3D)?.GlobalPosition ?? Vector3.Zero)}-{j.GetNodeOrNull(j.NodeB)?.GetClass()}@{R((j.GetNodeOrNull(j.NodeB) as Node3D)?.GlobalPosition ?? Vector3.Zero)}";
if (ch.GetType().Name == "TeleportMarker" || ch.SceneFilePath != "") info += $" scene[{ch.SceneFilePath}] label[{ch.Get("MarkerLabel")}]";
lines.Add($"{map}: {info}");
if (ch.SceneFilePath == "")
Walk(ch, map, lines);
}
}
}