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
+64
View File
@@ -0,0 +1,64 @@
class_name SimConfig
extends RefCounted
## Tuning constants shared verbatim by the server simulation and the client
## replica. Nothing here may differ between the two builds -- if a value needs
## to differ, it belongs in [GameConfig], not here.
# --- Time -------------------------------------------------------------------
const TICK_RATE := 60
const TICK_DELTA := 1.0 / 60.0
## Server sends a snapshot every N ticks (60 / 3 = 20 Hz).
const SNAPSHOT_INTERVAL := 3
## How far behind the newest snapshot the client renders remote actors.
const INTERPOLATION_DELAY_TICKS := 6
# --- Arena ------------------------------------------------------------------
const ARENA_HALF := Vector2(620.0, 340.0)
## Bullets are culled once they leave the arena by this margin.
const BULLET_CULL_MARGIN := 64.0
# --- Player -----------------------------------------------------------------
const PLAYER_SPEED := 240.0
const PLAYER_RADIUS := 9.0
const PLAYER_MAX_HP := 100
const PLAYER_FIRE_COOLDOWN := 7 # ticks
const PLAYER_BULLET_SPEED := 620.0
const PLAYER_BULLET_RADIUS := 4.0
const PLAYER_BULLET_LIFETIME := 90 # ticks
const PLAYER_BULLET_DAMAGE := 6
const PLAYER_IFRAMES := 36 # ticks of invulnerability after a hit
const PLAYER_RESPAWN_DELAY := 180 # ticks
# --- Anti-cheat guards ------------------------------------------------------
## Inputs older than this (relative to the newest accepted) are discarded.
const INPUT_MAX_AGE := 30
## Inputs claiming to be further ahead than this of the server tick are clamped.
const INPUT_MAX_LEAD := 12
## Hard ceiling on inputs consumed from one peer in a single tick.
const INPUT_MAX_PER_TICK := 4
# --- Emergency escape -------------------------------------------------------
const ESCAPE_CHANNEL_TICKS := 180 # 3 seconds
## Taking damage while channelling cancels the escape.
const ESCAPE_BREAK_ON_DAMAGE := true
# --- Bullets ----------------------------------------------------------------
const MAX_BULLETS := 4096
const TEAM_PLAYER := 0
const TEAM_ENEMY := 1
# --- Bullet visual kinds (index into the renderer's atlas) ------------------
const KIND_PLAYER_SHOT := 0
const KIND_ORB := 1
const KIND_NEEDLE := 2
const KIND_HEAVY := 3
# --- Instances --------------------------------------------------------------
const LOBBY_INSTANCE_ID := 1
const DUNGEON_PARTY_MAX := 4
## How long a forming dungeon waits for more players before it locks.
const DUNGEON_FORMING_TICKS := 300
# --- Portal -----------------------------------------------------------------
const PORTAL_POS := Vector2(0.0, -220.0)
const PORTAL_RADIUS := 60.0