extends SceneTree ## W0 (docs/WORLDLETS_DESIGN.md): the terrain is built from a worldlet's ## blocks (data/worldlets/.json), and the Valley made that way is the same ## island, height for height, as the hand-coded one it replaced (the hashes ## below were taken from the old code). Also: the world answers the WorldInfo ## questions, a new save remembers its worldlet, an old save without one is ## the Valley, and a bad worldlet falls back to the Valley. ## Run: godot --headless --path . --script res://tests/test_worldlets.gd ## SHA-256 of the height grid, from the terrain before W0 (commit f4df2bc). const GRID_HASHES := { 1337: "c87679a4ed30bff0c4be1caacda735454ad23f690ada28e7179667a9a7d62aa7", 777: "2edef348df09bf1f84ed3f5b0921f28fe54b3c827a698fac0a7d50fcdb95a24e", 42: "801430858909739fc8cf46694eee35c0cffa86ff1a9ad1ed379f1dfdea4b133c", 9001: "7d509d2508395a0e27e93a3384ac1e63323d588ef3cd1262f1e3f0c1c3e3254b", } var _fails := 0 var _finished := false func check(cond: bool, what: String) -> void: print((" ok " if cond else " FAIL ") + what) if not cond: _fails += 1 func _initialize() -> void: _run.call_deferred() func _run() -> void: var S: Node = root.get_node("Saves") S.root_dir = "user://test_worlds" for w in S.list_worlds(): S.delete_world(w.id) await _body(S) check(_finished, "test ran to the end (no script errors)") for w in S.list_worlds(): S.delete_world(w.id) DirAccess.remove_absolute(S.root_dir) print("RESULT: %s (%d failures)" % ["PASS" if _fails == 0 else "FAIL", _fails]) quit(1 if _fails > 0 else 0) func _grid_hash(t: Node) -> String: var h := HashingContext.new() h.start(HashingContext.HASH_SHA256) h.update(t._heights.to_byte_array()) return h.finish().hex_encode() func _body(S: Node) -> void: var T: Script = load("res://scripts/world/terrain.gd") print("the Valley, from data") var list: Array = T.worldlets() check(list.any(func(w): return w.id == "valley"), "the Valley is a worldlet (%s)" % [list.map(func(w): return w.id)]) var def: Dictionary = T.load_worldlet("valley") check(def.get("terrain", []).size() == 5, "built from 5 blocks: hills, rim, sea cliff, lake, ocean edge") for s in GRID_HASHES: var t: Node3D = T.new() t.noise_seed = s root.add_child(t) await process_frame check(_grid_hash(t) == GRID_HASHES[s], "seed %d: the same island, height for height" % s) t.queue_free() await process_frame var bad: Node3D = T.new() check(not bad.use_worldlet("nowhere").is_empty() and bad.worldlet_id == "valley", "an unknown worldlet is refused (the Valley stays)") bad.free() print("in a world") var id: String = S.create_world("W0", 1337, {}) check(String(S.read_meta(id).get("worldlet", "")) == "valley", "a new world remembers its worldlet") var meta: Dictionary = S.read_meta(id) meta.erase("worldlet") S._write_json(S._dir(id).path_join("meta.json"), meta) S.current_id = id var world: Node3D = load("res://scenes/world.tscn").instantiate() root.add_child(world) for _i in range(5): await physics_frame check(world.worldlet_id() == "valley", "an old world with no worldlet is the Valley") var water: Array = world.water_bodies() check(water.size() == 2 and water.any(func(w): return w.type == "lake") and water.any(func(w): return w.type == "sea"), "its water: a lake and the sea") var lake: Dictionary = water.filter(func(w): return w.type == "lake")[0] var lp: Vector2 = lake.center check(world.water_at(lp.x, lp.y).get("type", "") == "lake", "(and the lake is where it says)") check(absf(float(world.climate().snowline) - 40.0) < 0.01, "its snowline: 40 m") check(world.crossings().any(func(c): return c.to == "cove" and c.by == "tunnel"), "its way on: a tunnel to the Cove (planned)") world.queue_free() await process_frame _finished = true