c4beeae38f
Top-down twin-stick bullet-hell, Godot 4.7, server-authoritative dedicated server with client-side prediction. Clients send input only; the server resolves every hit for both players and enemies (no PvP). - SimWorld: whole simulation as plain RefCounted objects (no nodes, no physics server), ~0.24ms/tick at peak load -- runs headless for free and drives 78 tests in under a second - BulletPool: struct-of-arrays bullet storage, replicated as spawn/despawn events rather than per-tick state - Emitter framework (Ring/AimedSpread/WallGap/ArcSweep) shared by trash enemies and bosses -- a new boss is data in src/content/content.gd, no simulation changes - The Warden of the Fold: stationary 4-phase boss built entirely on that format - Lobby hub with a portal into on-demand dungeon instances; one process hosts the hub plus every concurrent dungeon - Emergency escape: 3s server-owned channel, cancelled by damage - tools/check.sh, test.sh (GUT), smoke.sh (real server + bot clients over ENet), bench.gd; git hooks wired to the same scripts - docs/ARCHITECTURE.md, NETCODE.md, WORKFLOW.md, ROADMAP.md
49 lines
1.4 KiB
GDScript
49 lines
1.4 KiB
GDScript
extends Node
|
|
## Parse every GDScript in the project so the engine prints any parse or type
|
|
## error, then quit.
|
|
##
|
|
## Run as a scene (not with --script) because autoload identifiers such as `Net`
|
|
## are only registered when the engine boots a real main loop; a --script run
|
|
## reports false "Identifier not found" errors for every file that uses one.
|
|
##
|
|
## godot --headless --path . res://tools/check.tscn
|
|
##
|
|
## `tools/check.sh` wraps this and owns the exit code: a script that fails to
|
|
## parse can still come back from ResourceLoader as a non-null object, so the
|
|
## engine's own stderr is the reliable signal.
|
|
|
|
const SKIP_DIRS := ["res://addons", "res://.godot"]
|
|
|
|
|
|
func _ready() -> void:
|
|
var scripts := _collect("res://")
|
|
scripts.sort()
|
|
for path in scripts:
|
|
ResourceLoader.load(path, "Script")
|
|
print("CHECK_COMPLETE scripts=%d" % scripts.size())
|
|
get_tree().quit(0)
|
|
|
|
|
|
func _collect(dir_path: String) -> Array[String]:
|
|
var out: Array[String] = []
|
|
for skip in SKIP_DIRS:
|
|
if dir_path.begins_with(skip):
|
|
return out
|
|
var dir := DirAccess.open(dir_path)
|
|
if dir == null:
|
|
return out
|
|
dir.list_dir_begin()
|
|
var entry := dir.get_next()
|
|
while entry != "":
|
|
if entry.begins_with("."):
|
|
entry = dir.get_next()
|
|
continue
|
|
var full := dir_path.path_join(entry)
|
|
if dir.current_is_dir():
|
|
out.append_array(_collect(full))
|
|
elif entry.ends_with(".gd"):
|
|
out.append(full)
|
|
entry = dir.get_next()
|
|
dir.list_dir_end()
|
|
return out
|