Initial commit: Transcience MVP
ci / verify (push) Successful in 1m57s

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
This commit is contained in:
Adyrem
2026-09-03 16:03:57 +02:00
commit 651c4ad94a
385 changed files with 28725 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
extends GutTest
## Movement is the one function the client is allowed to run ahead of the
## server, so client prediction is only correct while these hold.
func test_diagonal_is_not_faster_than_cardinal() -> void:
var straight := Movement.step_player(Vector2.ZERO, Vector2(1, 0), SimConfig.PLAYER_SPEED, SimConfig.ARENA_HALF)
var diagonal := Movement.step_player(Vector2.ZERO, Vector2(1, 1), SimConfig.PLAYER_SPEED, SimConfig.ARENA_HALF)
assert_almost_eq(diagonal.length(), straight.length(), 0.001,
"a diagonal must cover the same distance as a cardinal move")
func test_oversized_input_vector_is_clamped() -> void:
# The wire format cannot express this, but a patched client could try.
var cheated := Movement.step_player(Vector2.ZERO, Vector2(1000, 0), SimConfig.PLAYER_SPEED, SimConfig.ARENA_HALF)
var honest := Movement.step_player(Vector2.ZERO, Vector2(1, 0), SimConfig.PLAYER_SPEED, SimConfig.ARENA_HALF)
assert_eq(cheated, honest, "an over-long move vector must buy no extra speed")
func test_speed_matches_config() -> void:
var moved := Movement.step_player(Vector2.ZERO, Vector2.RIGHT, SimConfig.PLAYER_SPEED, SimConfig.ARENA_HALF)
assert_almost_eq(moved.x, SimConfig.PLAYER_SPEED * SimConfig.TICK_DELTA, 0.001)
func test_player_is_clamped_to_the_arena() -> void:
var far := Vector2(SimConfig.ARENA_HALF.x - 1.0, 0.0)
var out := Movement.step_player(far, Vector2.RIGHT, 10000.0, SimConfig.ARENA_HALF)
assert_almost_eq(out.x, SimConfig.ARENA_HALF.x, 0.001)
func test_circles_overlap_at_the_boundary() -> void:
assert_true(Movement.circles_overlap(Vector2.ZERO, 5.0, Vector2(9.9, 0.0), 5.0))
assert_false(Movement.circles_overlap(Vector2.ZERO, 5.0, Vector2(10.1, 0.0), 5.0))
func test_outside_arena_respects_the_cull_margin() -> void:
var edge := SimConfig.ARENA_HALF.x + SimConfig.BULLET_CULL_MARGIN
assert_false(Movement.outside_arena(Vector2(edge - 1.0, 0.0)))
assert_true(Movement.outside_arena(Vector2(edge + 1.0, 0.0)))