135 lines
4 KiB
GDScript
135 lines
4 KiB
GDScript
extends SceneTree
|
|
|
|
# Usage:
|
|
# godot --headless --path demo --script scripts/bake_dungeon.gd -- SEED DEPTH OUT_DIR
|
|
#
|
|
# Shells out to bin/genesis --emit=json and bakes the result into two sibling
|
|
# assets under OUT_DIR:
|
|
# - mesh_library.tres (tile catalog, same content MLB.build()
|
|
# produces at runtime — shareable across bakes)
|
|
# - dungeon_seed<S>_depth<D>.tscn (PackedScene with a GridMap referencing
|
|
# the MeshLibrary, populated per the
|
|
# generated dungeon)
|
|
#
|
|
# Override the genesis binary path with the GENESIS_BIN env var; default is
|
|
# "../bin/genesis" relative to the Godot project.
|
|
|
|
const MESH_LIB_NAME := "mesh_library.tres"
|
|
const MLB = preload("res://scripts/mesh_library_builder.gd")
|
|
|
|
func _init() -> void:
|
|
var args := OS.get_cmdline_user_args()
|
|
if args.size() != 3:
|
|
push_error("usage: -- SEED DEPTH OUT_DIR")
|
|
quit(1)
|
|
return
|
|
|
|
var seed := int(args[0])
|
|
var depth := int(args[1])
|
|
var out_dir := args[2]
|
|
|
|
var bin_path := OS.get_environment("GENESIS_BIN")
|
|
if bin_path == "":
|
|
bin_path = ProjectSettings.globalize_path("res://") + "../bin/genesis"
|
|
bin_path = bin_path.simplify_path()
|
|
|
|
if not DirAccess.dir_exists_absolute(out_dir):
|
|
var err := DirAccess.make_dir_recursive_absolute(out_dir)
|
|
if err != OK:
|
|
push_error("cannot create %s (err %d)" % [out_dir, err])
|
|
quit(1)
|
|
return
|
|
|
|
var stdout: Array = []
|
|
var exit_code := OS.execute(bin_path, [
|
|
"--seed", str(seed), "--depth", str(depth), "--emit=json",
|
|
], stdout, true)
|
|
if exit_code != 0:
|
|
push_error("genesis exited %d (bin=%s)" % [exit_code, bin_path])
|
|
quit(1)
|
|
return
|
|
|
|
var grid: Dictionary = JSON.parse_string(stdout[0])
|
|
if grid.is_empty():
|
|
push_error("genesis produced invalid JSON")
|
|
quit(1)
|
|
return
|
|
|
|
# Step 1 — MeshLibrary.tres.
|
|
var lib_path := "%s/%s" % [out_dir, MESH_LIB_NAME]
|
|
var save_err := MLB.save_resource(lib_path, true)
|
|
if save_err != OK:
|
|
push_error("failed to save %s (err %d)" % [lib_path, save_err])
|
|
quit(1)
|
|
return
|
|
|
|
# Step 2 — PackedScene with populated GridMap.
|
|
var lib: MeshLibrary = load(lib_path)
|
|
var root := Node3D.new()
|
|
root.name = "Dungeon_seed%d_depth%d" % [seed, depth]
|
|
var gm := GridMap.new()
|
|
gm.name = "GridMap"
|
|
gm.mesh_library = lib
|
|
gm.cell_size = Vector3(1, 1, 1)
|
|
root.add_child(gm)
|
|
gm.owner = root
|
|
|
|
var cells_set := _populate(gm, grid)
|
|
|
|
var packed := PackedScene.new()
|
|
var pack_err := packed.pack(root)
|
|
if pack_err != OK:
|
|
push_error("failed to pack scene (err %d)" % pack_err)
|
|
quit(1)
|
|
return
|
|
|
|
var scn_path := "%s/dungeon_seed%d_depth%d.tscn" % [out_dir, seed, depth]
|
|
var scn_err := ResourceSaver.save(packed, scn_path)
|
|
if scn_err != OK:
|
|
push_error("failed to save %s (err %d)" % [scn_path, scn_err])
|
|
quit(1)
|
|
return
|
|
|
|
print("wrote %s + %s — %d cells" % [scn_path, lib_path, cells_set])
|
|
quit(0)
|
|
|
|
# Decode the base64 layers and stamp tile IDs into the GridMap. Mirrors
|
|
# arcade_scene.gd _populate_grid_map so the CLI produces the same geometry
|
|
# as the in-engine path for the same seed/depth. Chasms stay as empty cells.
|
|
func _populate(gm: GridMap, grid: Dictionary) -> int:
|
|
var w := int(grid["width"])
|
|
var h := int(grid["height"])
|
|
var terrain := Marshalls.base64_to_raw(grid["terrain"])
|
|
var liquid := Marshalls.base64_to_raw(grid["liquid"])
|
|
|
|
var count := 0
|
|
for y in range(h):
|
|
for x in range(w):
|
|
var idx := y * w + x
|
|
var t := terrain[idx]
|
|
var liq := liquid[idx]
|
|
if t == 5 and liq == 3: # T_LIQUID + L_CHASM
|
|
continue
|
|
var tile := _tile_for(t, liq)
|
|
if tile < 0:
|
|
continue
|
|
gm.set_cell_item(Vector3i(x, 0, y), tile)
|
|
count += 1
|
|
return count
|
|
|
|
func _tile_for(terrain: int, liquid: int) -> int:
|
|
match terrain:
|
|
1: return MLB.TILE_FLOOR
|
|
4: return MLB.TILE_CORRIDOR
|
|
3: return MLB.TILE_DOOR
|
|
2: return MLB.TILE_WALL
|
|
6: return MLB.TILE_BRIDGE
|
|
7: return MLB.TILE_STAIRS_UP
|
|
8: return MLB.TILE_STAIRS_DOWN
|
|
5:
|
|
match liquid:
|
|
1: return MLB.TILE_WATER
|
|
2: return MLB.TILE_LAVA
|
|
4: return MLB.TILE_BRIMSTONE
|
|
_: return MLB.TILE_WATER
|
|
_: return -1
|