Files
Cinderwild/tests/test_worldlets.gd

90 lines
3.7 KiB
GDScript

extends SceneTree
## W0 (docs/WORLDLETS_DESIGN.md): the terrain is built from a worldlet's
## blocks (data/worldlets/<id>.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