mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
b43ad207c1
multiplayer-next.md was a 1662-line mix of standing architecture spec and task-completion tracking, most of which was dense per-task DONE evidence for finished Phases 0-6. Split it: - MULTIPLAYER_SPEC.md (new): the locked architecture decisions, wire format, server-side input handling, prediction/reconciliation, latency/frame-rate budget, and match lifecycle state machine - standing design reference, not task-tracked. - multiplayer-next.md (trimmed 1662 -> ~370 lines): only outstanding work remains - §0 status, §7 Phase 7/8 task tables condensed to "what's left" per task, §8-11 reference material (refactoring notes, gotchas, testing, flagged items). Phases 0-6 collapsed to a pointer at git history instead of ~500 lines of DONE evidence. Also: - Repointed every `multiplayer-next.md §N` code comment (N 1-6) across Game/scripts, Game/tools and Game/tests to MULTIPLAYER_SPEC.md, since those sections moved. Task-number references (`task N.N`, §7-11) correctly still point at multiplayer-next.md. - Updated CLAUDE.md's doc index and docs/TECH_STACK.md's spec-section citations to match. - TODO.md: added a "what's left to actually finish multiplayer (human-actionable)" checklist pulled from multiplayer-next.md §0 and docs/MATCHMAKING.md - things that need a person (hardware, a design decision, a Steam App ID, hands on a controller), not more agent code.
48 lines
1.9 KiB
GDScript
48 lines
1.9 KiB
GDScript
extends RefCounted
|
|
|
|
# Plain data holder for one body's snapshot state (§2.4 of MULTIPLAYER_SPEC.md).
|
|
# Deliberately not Ship/Ball themselves, and deliberately not a scene-tree
|
|
# node — NetCodec's pack/unpack must stay callable from pure-function tests
|
|
# with no live scene. Phase 2's snapshot writer fills one of these per body
|
|
# per tick from the real RigidBody3D state; Phase 2's interpolator does the
|
|
# reverse.
|
|
#
|
|
# avel_range must match what the sender quantised with (SHIP_AVEL_RANGE vs
|
|
# BALL_AVEL_RANGE in net_codec.gd) — it is not carried on the wire, because
|
|
# slot order already tells both peers which body is which (§1.3: "entities
|
|
# are addressed by integer slot, never by path").
|
|
|
|
var position := Vector3.ZERO
|
|
var rotation := Quaternion.IDENTITY
|
|
var linear_velocity := Vector3.ZERO
|
|
var angular_velocity := Vector3.ZERO
|
|
var frozen := false
|
|
var turbo := false
|
|
var thrust_z := 0.0 # -1..1; re-quantised to a 3-bit bin on the wire
|
|
var stalled := false
|
|
var avel_range := 4.0 # NetCodec.SHIP_AVEL_RANGE; set to BALL_AVEL_RANGE for the ball
|
|
|
|
# Self-referential preload, not get_script().new() — this file deliberately
|
|
# has no class_name (same cache-timing reason as test_case.gd and other
|
|
# path-`extends`d files in this project), and get_script().new() throws
|
|
# "Nonexistent function 'new' in base 'GDScript'" from within the script's
|
|
# own body in this Godot version.
|
|
const _NetBodyState = preload("res://scripts/net_body_state.gd")
|
|
|
|
|
|
# Same contract as ShipAction.copy() (see its own comment): a distinct
|
|
# instance with equal fields, for callers that hold onto a state past the
|
|
# tick/comparison it was returned in.
|
|
func copy() -> RefCounted:
|
|
var c := _NetBodyState.new()
|
|
c.position = position
|
|
c.rotation = rotation
|
|
c.linear_velocity = linear_velocity
|
|
c.angular_velocity = angular_velocity
|
|
c.frozen = frozen
|
|
c.turbo = turbo
|
|
c.thrust_z = thrust_z
|
|
c.stalled = stalled
|
|
c.avel_range = avel_range
|
|
return c
|