script

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 14, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package script is the deterministic COB bytecode virtual machine. A unit's compiled BOS script drives its piece animation (walking gaits, rotating turrets, opening build yards), weapon aim threads and death sequences; without it a unit is an inert model. The VM runs identically on the native authority and the wasm client because every operation is integer math through engine/fixed and the only entropy source is a seeded engine/rng stream, so two engines fed the same script and the same tick sequence evolve bit-identically.

The layering mirrors the rest of the engine: a Program is the immutable, shared compiled form of one unit type's script (parsed once from a COB), while the mutable per-unit state — threads, static variables, piece animators — lives on a Unit owned by a Runtime. sim drives the Runtime through the sim.Runtime interface and reads piece transforms through sim.Binding; neither requires sim to import this package, keeping the dependency arrow pointing in.

Index

Constants

View Source
const (
	UVWeaponAimAborted = 21
	UVWeaponReady      = 22
	UVWeaponLaunchNow  = 23
	UVFinishedDying    = 26
	UVCurrentSpeed     = 29
)

TA: Kingdoms unit-value ports (21+, inert under the TA engine). The weapon trio backs TA:K's aim handshake: a v6 script signals aim state by WRITING the weapon index into WEAPON_READY / WEAPON_AIM_ABORTED via SET_VALUE instead of returning a value from the aim thread the way TA scripts do. CURRENT_SPEED feeds the MoveWatcher loops TA:K units poll to trigger their walk gaits (the world pushes it through SetUnitValuePort each tick).

Variables

This section is empty.

Functions

This section is empty.

Types

type Host

type Host interface {
	GetUnitValue(port int) int32
	SetUnitValue(port, value int)
	EmitSfx(sfxType, piece int)
	PlaySound(sound, volume int)
	Explode(piece, sfxType int)
}

Host is the optional callback surface the world exposes to running scripts: unit-value ports the scripts poll/set and the effect opcodes (EMIT_SFX, PLAY_SOUND, EXPLODE). A nil Host makes the VM self-contained — GET reads return TA's engine defaults and effect opcodes are no-ops — which is what the VM's unit tests rely on. The world supplies a real Host once combat and effects are wired through.

type Instruction

type Instruction struct {
	Op     uint32
	P1, P2 int32
	Offset uint32
}

Instruction is one decoded COB instruction in VM-ready form: the 32-bit opcode plus its (up to two) inline operands and its byte offset within the script's code, which JUMP/JUMP_IF_FALSE targets resolve against.

type Program

type Program struct {
	// contains filtered or unexported fields
}

Program is the immutable compiled form of one unit type's COB. It is shared read-only across every unit instance of that type; all mutable execution state lives on Unit.

func FromCOB

func FromCOB(c *scripting.COB) (*Program, error)

FromCOB compiles a parsed COB into a Program by disassembling every script.

func NewProgram

func NewProgram(pieceNames []string, numStatic int, scripts []ScriptSource) *Program

NewProgram assembles a Program from raw script sources. The piece-name list sizes the per-unit animator and visibility tables; numStatic sizes the static variable array.

func (*Program) HasScript

func (p *Program) HasScript(name string) bool

HasScript reports whether the program defines the named entry point.

func (*Program) PieceNames

func (p *Program) PieceNames() []string

PieceNames returns the program's piece-name list (rest-pose order).

func (*Program) ScriptIndex

func (p *Program) ScriptIndex(name string) (int, bool)

ScriptIndex resolves a script name (case-insensitively) to its index.

func (*Program) ScriptNames

func (p *Program) ScriptNames() []string

ScriptNames returns the program's script entry-point names in index order. The studio's unit editor lists them so the Actions panel can offer a button per script (Create, Activate, AimPrimary, …).

func (*Program) SoundName

func (p *Program) SoundName(i int) string

SoundName resolves a PLAY_SOUND index to its .wav stem, "" when the program carries no sound table or the index is out of range.

type Runtime

type Runtime struct {
	// contains filtered or unexported fields
}

Runtime hosts every unit's script VM for one world and advances them in lockstep on a fixed tick. It owns the deterministic RNG that OP_RAND draws from, so the whole simulation reproduces from a seed. It satisfies sim.Runtime: the world calls Tick once per simulated tick with its running millisecond clock.

func NewRuntime

func NewRuntime(seed uint32) *Runtime

NewRuntime builds a runtime whose script RNG is seeded deterministically. Every client seeded identically draws the same script randomness in the same order, which is what keeps script-driven outcomes in lockstep.

func (*Runtime) KillAllThreads

func (r *Runtime) KillAllThreads()

KillAllThreads marks every live thread on every hosted unit dead. It backs the studio's "Terminate All Scripts" developer command; the next tickStep prunes the dead threads. Debug-only — a sandbox tool, never driven from gameplay — so it carries no determinism contract.

func (*Runtime) NewUnit

func (r *Runtime) NewUnit(p *Program, host Host) *Unit

NewUnit instantiates a unit of the given program with an optional Host and registers it for ticking. The returned *Unit satisfies sim.Binding.

func (*Runtime) Reset

func (r *Runtime) Reset()

Reset drops every hosted unit and rewinds the tick clock. The world calls this when it rebuilds its unit set (a resync from an authoritative snapshot) so stale script state can't leak across the restore.

func (*Runtime) RestoreRng

func (r *Runtime) RestoreRng(state uint32)

RestoreRng sets the script RNG's internal state, the inverse of SnapshotRng.

func (*Runtime) SnapshotRng

func (r *Runtime) SnapshotRng() uint32

SnapshotRng returns the script RNG's internal state so a resync can hand the joiner the exact draw position the authority reached. OP_RAND consumes this stream, so matching it keeps script-driven randomness (and thus animation) in lockstep across the join.

func (*Runtime) Tick

func (r *Runtime) Tick(ms int64)

Tick advances script time to the world's millisecond clock in fixed steps. The world increments its clock by exactly one tick before each call, so in steady state this runs a single step; the loop only matters if the clock ever jumps forward, and a fresh runtime aligns to the first observed time rather than fast-forwarding through history.

type ScriptSource

type ScriptSource struct {
	Name  string
	Insts []Instruction
}

ScriptSource is one named entry point's instruction stream, the input to NewProgram. FromCOB produces these from a parsed COB; a future in-tree assembler could target the same shape.

type Unit

type Unit struct {
	// contains filtered or unexported fields
}

Unit is one unit's live script state: its threads, static variables and per-piece animators. It satisfies sim.Binding.

func (*Unit) AddBreakpoint

func (u *Unit) AddBreakpoint(scriptIdx int, offset uint32)

AddBreakpoint sets a breakpoint at a byte offset of one script; RemoveBreakpoint clears it; ClearBreakpoints drops every breakpoint on the unit. Threads park on a set offset before executing its instruction.

func (*Unit) AimStatus

func (u *Unit) AimStatus(id int32) (done bool, ret int32)

AimStatus reports whether the thread with the given id has finished and, if so, the value it returned. A still-running thread reports (false, 0). A thread that died this tick reports its captured return value from the death ledger. An id that is neither live nor in the ledger — already pruned, or never a real thread (id 0) — reports (true, 1): a vanished aim thread is treated as a completed, successful aim so the weapon SM degrades to firing rather than stalling forever.

func (*Unit) ClearBreakpointHits

func (u *Unit) ClearBreakpointHits()

ClearBreakpointHits releases every thread parked on a breakpoint (the debugger's "Continue"): it clears the hit flag and arms bpResume so the thread runs past the breakpoint it is stopped on rather than re-parking immediately.

func (*Unit) ClearBreakpoints

func (u *Unit) ClearBreakpoints()

func (*Unit) CobState

func (u *Unit) CobState() frame.CobUnitState

CobState returns the unit's inspectable script state — a copy of its static variables plus a per-live-thread summary — for the studio's Runtime / Script Variables panels. Debug-only: it never feeds the world hash, so reporting it cannot perturb determinism.

func (*Unit) Coverage

func (u *Unit) Coverage() map[int][]uint32

Coverage returns a stable snapshot of every executed byte offset, keyed by script index, for the debugger's coverage-dimming view.

func (*Unit) DrainEffects

func (u *Unit) DrainEffects() []frame.Event

DrainEffects returns the effect events buffered since the last drain and clears the buffer. The world calls it each tick to harvest script-emitted SFX / sounds for the render snapshot.

func (*Unit) ExportCob

func (u *Unit) ExportCob() frame.CobSnapshot

ExportCob captures the unit's full live VM state — statics, active animators, hidden pieces, running threads and the thread-id counter — so a late joiner can resume the exact piece poses (turret aim, rotation, mid-animation) the authority holds rather than re-deriving them by replaying Create/StartMoving. Idle animators and visible pieces are the rest state a freshly built unit already carries, so only the deviations are serialized.

func (*Unit) FinishedDying

func (u *Unit) FinishedDying() bool

FinishedDying reports whether the unit's Dying script has signalled completion by setting FINISHED_DYING — TA:K's cue that the fall animation has landed and the corpse swap can happen.

func (*Unit) HasScript

func (u *Unit) HasScript(name string) bool

HasScript reports whether the unit's program defines the named entry point.

func (*Unit) ImportCob

func (u *Unit) ImportCob(snap frame.CobSnapshot)

ImportCob overwrites the unit's live VM state with a previously exported snapshot, the inverse of ExportCob. The unit must already be built from the same program (so animator arrays are sized and scriptIndex values resolve); the caller rebuilds the unit via NewUnit, then applies this instead of running Create. Animators and visibility start from the freshly built rest state and are overwritten only where the snapshot deviates.

func (*Unit) KillAllThreads

func (u *Unit) KillAllThreads()

KillAllThreads marks every live thread on this unit dead (the per-unit "Stop all threads" developer command). Animators keep their last pose; only the threads stop.

func (*Unit) KillThread

func (u *Unit) KillThread(id int32)

KillThread marks the single thread with the given id dead (the per-thread kill button in the Runtime panel). Unknown ids are ignored.

func (*Unit) KillThreadsByName

func (u *Unit) KillThreadsByName(name string)

KillThreadsByName marks dead every live thread running the named script. The offline unit editor uses it to retract a transient pose handler (the RestoreAfterDelay / RestorePosition threads a one-shot aim leaves behind) before re-driving the unit. Unknown names are ignored.

func (*Unit) KilledStatus

func (u *Unit) KilledStatus(id int32) (done bool, corpsetype int32)

KilledStatus reports whether the tracked Killed thread has finished and, when it has, the corpsetype its second local held — TA's out-param convention (1 = intact corpse, 2 = damaged, 3 = nothing). A vanished or never-real id reports (true, 1) so a unit whose death script was pruned still leaves the default corpse.

func (*Unit) Pieces

func (u *Unit) Pieces() []frame.PieceState

Pieces returns the current per-piece transform for the render snapshot. A piece with no active animator on an axis contributes its rest value (zero offset / rotation), and visibility reflects SHOW/HIDE.

func (*Unit) RemoveBreakpoint

func (u *Unit) RemoveBreakpoint(scriptIdx int, offset uint32)

func (*Unit) ResetState

func (u *Unit) ResetState()

ResetState returns the unit to a clean slate: every thread dies, static vars zero, animators snap back to rest, and all pieces become visible — the per-unit "Reset" developer command. It does not re-run Create; the caller decides whether to restart any entry point.

func (*Unit) Restart

func (u *Unit) Restart(name string, args ...int)

Restart spawns a thread on the named script, first marking any live thread already running that same script dead. It gives the world the COB START opcode's supersede semantics, so a continuously re-driven tracking thread (a weapon's aim loop, re-issued as its target moves) replaces its prior instance instead of accumulating a fresh thread every tick.

func (*Unit) RunQuery

func (u *Unit) RunQuery(name string, args ...int) (int32, bool)

RunQuery executes a Query* script synchronously within the current tick and returns the value its first local ended up holding — the convention TA uses to report a firing piece. It fails (ok=false) if the script does not exist or would yield (sleep/wait/animate/spawn), keeping the synchronous contract honest.

func (*Unit) ScriptNames

func (u *Unit) ScriptNames() []string

ScriptNames returns the unit type's script entry-point names in index order, the list the offline editor's Actions panel turns into a run-script button per entry (Create, Activate, AimPrimary, …).

func (*Unit) SetStatic

func (u *Unit) SetStatic(idx int, v int32)

SetStatic writes one of the unit's static variables (the debugger's editable Globals tray). Out-of-range indices are ignored.

func (*Unit) SetThreadLocal

func (u *Unit) SetThreadLocal(id int32, idx int, v int32)

SetThreadLocal writes one of a thread's local variables (the debugger's editable Locals tray). Out-of-range indices are ignored.

func (*Unit) SetThreadPC

func (u *Unit) SetThreadPC(id int32, pc int)

SetThreadPC moves a thread's program counter to an instruction index and clears its sleep / wait / breakpoint-parked state so execution resumes from the new spot. The index is clamped to the current script's instruction range.

func (*Unit) SetUnitValuePort

func (u *Unit) SetUnitValuePort(port int, v int32)

SetUnitValuePort writes a COB unit-value port that scripts read via GET_UNIT_VALUE (TA's GetUnitValue). The offline unit editor uses it to drive HEALTH / build-percent / activation / standing-orders from its inspector sliders. With no Host attached this store is the port source; a hosted unit routes through the Host instead. Debug/authoring-only — never feeds the hash.

func (*Unit) Start

func (u *Unit) Start(name string, args ...int)

Start spawns a thread on the named script with the given integer arguments as its initial locals. Unknown names are ignored, matching the world's fire-and-forget calls into optional handlers (Create, StartMoving, ...).

func (*Unit) StartAim

func (u *Unit) StartAim(name string, args ...int) int32

StartAim spawns the named aim script with the COB START supersede semantics (cancelling any live instance) and returns the new thread's id so the caller can poll its completion via AimStatus. It returns 0 if the script is unknown, which AimStatus reads as "already done" so a unit without the script never blocks its fire cadence.

func (*Unit) StepThread

func (u *Unit) StepThread(id int32)

StepThread advances one thread by exactly one instruction (the debugger's "Step" button). It clears any sleep / wait so the instruction runs now and resumes past a breakpoint the thread is parked on. A missing or dead thread is a no-op. Debug-only — never driven from gameplay.

func (*Unit) TakeWeaponAimAborted

func (u *Unit) TakeWeaponAimAborted(slot int) bool

TakeWeaponAimAborted reports whether the script has signalled WEAPON_AIM_ABORTED for the given weapon index since the last call, clearing the flag.

func (*Unit) TakeWeaponReady

func (u *Unit) TakeWeaponReady(slot int) bool

TakeWeaponReady reports whether the script has signalled WEAPON_READY for the given weapon index since the last call, clearing the flag. This is the TA:K equivalent of an aim thread returning TRUE.

func (*Unit) UnitValuePort

func (u *Unit) UnitValuePort(port int) int32

UnitValuePort reports the current value of a COB unit-value port (the read the inspector's Ports panel surfaces). Returns the effective value GET_UNIT_VALUE would yield: an explicit port write, else TA's resting default.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL