Files
claude c4beeae38f 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
2026-09-03 16:03:57 +02:00

111 lines
2.6 KiB
GDScript

# -------------
# {
# object(script or instance) or StringName(native class name):{
# method_name1: [StubParams, StubParams],
# method_name2: [StubParams, StubParams]
# },
# object(script or instance) or StringName(native class name):{
# method_name1: [StubParams, StubParams],
# method_name2: [StubParams, StubParams]
# }
# }
var stubs = {}
func _normalize_stub_target(target):
var to_return = null
if(GutUtils.is_native_class(target)):
to_return = GutUtils.strutils.type2str(target)
elif(typeof(target) == TYPE_OBJECT):
to_return = target
elif(typeof(target) == TYPE_STRING):
if(FileAccess.file_exists(target)):
to_return = load(target)
else:
to_return = null
return to_return
func _get_entries_matching_target(target):
var match_on = [target]
var trav = target
var done = false
var current = trav
while(trav != null and !done):
if(GutUtils.is_singleton_double(trav)):
trav = trav.__gutdbl.get_singleton()
match_on.push_front(trav)
elif(GutUtils.is_instance(trav)):
trav = trav.get_script()
match_on.push_front(trav)
else:
trav = trav.get_base_script()
if(trav != null):
match_on.push_front(trav)
else:
var type_name = current.get_instance_base_type()
match_on.push_front(type_name)
trav = null
done = true
if(trav == null):
done = true
else:
current = trav
return match_on
func clear():
stubs.clear()
func add_stub(stub_params):
var key = _normalize_stub_target(stub_params.stub_target)
if(!stubs.has(key)):
stubs[key] = {}
if(!stubs[key].has(stub_params.stub_method)):
stubs[key][stub_params.stub_method] = []
stubs[key][stub_params.stub_method].append(stub_params)
func get_all_stubs(thing, method):
var obj = _normalize_stub_target(thing)
var match_on = _get_entries_matching_target(obj)
var matches = []
for entry in match_on:
if(stubs.has(entry) and stubs[entry].has(method)):
matches.append_array(stubs[entry][method])
return matches
func get_default_stub(thing, method):
var obj = _normalize_stub_target(thing)
var match_on = _get_entries_matching_target(obj)
var to_return = null
for entry in match_on:
if(stubs.has(entry) and stubs[entry].has(method)):
var method_stubs = stubs[entry][method]
for stub in method_stubs:
if(stub.is_script_default):
to_return = stub
return to_return
func to_s():
var text = ''
for thing in stubs:
text += str("-- ", thing, " --\n")
for method in stubs[thing]:
text += str("\t", method, "\n")
for i in range(stubs[thing][method].size()):
text += "\t\t" + stubs[thing][method][i].to_s() + "\n"
if(text == ''):
text = 'No Stubs';
return text