Initial commit: Transcience MVP

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:
2026-09-03 16:03:57 +02:00
commit c4beeae38f
385 changed files with 28725 additions and 0 deletions
+124
View File
@@ -0,0 +1,124 @@
var PanelControls = load("res://addons/gut/gui/panel_controls.gd")
# All titles so we can free them when we want.
var _all_titles = []
var base_container = null
# All the various PanelControls indexed by thier keys.
var controls = {}
func _init(cont):
base_container = cont
func add_title(text):
var row = PanelControls.BaseGutPanelControl.new(text, text)
base_container.add_child(row)
row.connect('draw', _on_title_cell_draw.bind(row))
_all_titles.append(row)
return row
func add_ctrl(key, ctrl):
controls[key] = ctrl
base_container.add_child(ctrl)
func add_number(key, value, disp_text, v_min, v_max, hint=''):
var ctrl = PanelControls.GpcNumber.new(disp_text, value, v_min, v_max, hint)
add_ctrl(key, ctrl)
return ctrl
func add_float(key, value, disp_text, step, v_min, v_max, hint=''):
var ctrl = PanelControls.GpcFloat.new(disp_text, value, step, v_min, v_max, hint)
add_ctrl(key, ctrl)
return ctrl
func add_select(key, value, values, disp_text, hint=''):
var ctrl = PanelControls.GpcSelect.new(disp_text, value, values, hint)
add_ctrl(key, ctrl)
return ctrl
func add_value(key, value, disp_text, hint=''):
var ctrl = PanelControls.GpcString.new(disp_text, value, hint)
add_ctrl(key, ctrl)
return ctrl
func add_multiline_text(key, value, disp_text, hint=''):
var ctrl = PanelControls.GpcMultiLineString.new(disp_text, value, hint)
add_ctrl(key, ctrl)
return ctrl
func add_boolean(key, value, disp_text, hint=''):
var ctrl = PanelControls.GpcBoolean.new(disp_text, value, hint)
add_ctrl(key, ctrl)
return ctrl
func add_directory(key, value, disp_text, hint=''):
var ctrl = PanelControls.GpcDirectory.new(disp_text, value, hint)
add_ctrl(key, ctrl)
ctrl.dialog.title = disp_text
return ctrl
func add_file(key, value, disp_text, hint=''):
var ctrl = PanelControls.GpcDirectory.new(disp_text, value, hint)
add_ctrl(key, ctrl)
ctrl.dialog.file_mode = ctrl.dialog.FILE_MODE_OPEN_FILE
ctrl.dialog.title = disp_text
return ctrl
func add_save_file_anywhere(key, value, disp_text, hint=''):
var ctrl = PanelControls.GpcDirectory.new(disp_text, value, hint)
add_ctrl(key, ctrl)
ctrl.dialog.file_mode = ctrl.dialog.FILE_MODE_SAVE_FILE
ctrl.dialog.access = ctrl.dialog.ACCESS_FILESYSTEM
ctrl.dialog.title = disp_text
return ctrl
func add_color(key, value, disp_text, hint=''):
var ctrl = PanelControls.GpcColor.new(disp_text, value, hint)
add_ctrl(key, ctrl)
return ctrl
var _blurbs = 0
func add_blurb(text):
var ctrl = RichTextLabel.new()
ctrl.fit_content = true
ctrl.bbcode_enabled = true
ctrl.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
ctrl.text = text
add_ctrl(str("blurb_", _blurbs), ctrl)
return ctrl
# ------------------
# Events
# ------------------
func _on_title_cell_draw(which):
which.draw_rect(Rect2(Vector2(0, 0), which.size), Color(0, 0, 0, .15))
# ------------------
# Public
# ------------------
func clear():
for key in controls:
controls[key].free()
controls.clear()
for entry in _all_titles:
entry.free()
_all_titles.clear()