Gododin Gododin Documentation

Linked repository source

examples/bunny_mark/declarations/bunny.odin

This read-only view comes from the file in the Gododin repository. It retains its design, example or evidence context.

Download the original file · Return to the guide

package declarations

import "core:math"
import raw "gododin:bindings/raw"
import godot "gododin:bindings/typed/godot"
import gd "gododin:bindings/typed/call"
import bunny "../subsystem"

// Bunny is deliberately the per-instance counterexample: one authored Sprite2D
// and one native step call per bunny, with a typed position read and write.
// The scene supplies the same texture and seeded scale as the other arms.
// The driver owns fixed steps for every mode; there is no hidden _process
// callback outside its timing bracket. Real game hot loops belong in BunnyField.
@(gododin_class="Sprite2D")
Bunny :: struct {
	vx, vy, bounds_x, bounds_y, speed_scale, gravity: f32,
	live: bool,
}

// Bunny_Configure validates finite positive f32 bounds. Returns -1 for an
// invalid call or -2 for bounds outside (0,1000000].
@(gododin)
bunny_configure :: proc(self: ^Bunny, call: gd.Main_Call, bounds_x, bounds_y: f64) -> i64 {
	if gd.validate_main_call(call) != .None do return -1
	if !bunny.valid_profile({bunny.CANONICAL_DT, f32(bounds_x), f32(bounds_y), 1, 900}) do return -2
	self.bounds_x, self.bounds_y = f32(bounds_x), f32(bounds_y)
	return 0
}

// Bunny_Launch sets the actual Sprite2D position and velocity. Returns -1 for
// authority, -2 for an unavailable Node2D, -3 for non-finite or abs>1000000 inputs, -4
// for a failed position write. Setup is outside the measured frame bracket.
@(gododin)
bunny_launch :: proc(self: ^Bunny, call: gd.Main_Call, x, y, vx, vy: f64) -> i64 {
	if gd.validate_main_call(call) != .None do return -1
	for v in ([4]f32{f32(x),f32(y),f32(vx),f32(vy)}) {if math.is_nan(v)||math.is_inf(v)||math.abs(v)>1000000 do return -3}
	object, ok := gd.self(call)
	if !ok do return -2
	node, cast_ok := godot.cast_Node2D(gd.godot_main_call(call), &object)
	if !cast_ok do return -2
	if err := godot.node2d_set_position(gd.godot_main_call(call), node, transmute(raw.Vector2)[2]f32{f32(x),f32(y)}); err != .None do return -4
	self.vx, self.vy, self.live = f32(vx), f32(vy), true
	return 0
}

// Bunny_Set_Motion accepts the same nonnegative bounded profile as the field.
// Returns -1 for authority, -2 for an unsupported/non-finite profile.
@(gododin)
bunny_set_motion :: proc(self: ^Bunny, call: gd.Main_Call, speed_scale, gravity: f64) -> i64 {
	if gd.validate_main_call(call) != .None do return -1
	if !bunny.valid_profile({bunny.CANONICAL_DT,1280,720,f32(speed_scale),f32(gravity)}) do return -2
	self.speed_scale, self.gravity = f32(speed_scale), f32(gravity)
	return 0
}

// Bunny_Step_Fixed reads and writes the live engine position around the same
// f32 integration used by the staged population. Returns -1 invalid authority,
// -2 unconfigured/unavailable object, -3 failed read, -4 failed write.
@(gododin)
bunny_step_fixed :: proc(self: ^Bunny, call: gd.Main_Call) -> i64 {
	if gd.validate_main_call(call) != .None do return -1
	if !self.live do return -2
	object, ok := gd.self(call)
	if !ok do return -2
	node, cast_ok := godot.cast_Node2D(gd.godot_main_call(call), &object)
	if !cast_ok do return -2
	stored, read_error := godot.node2d_get_position(gd.godot_main_call(call), node)
	if read_error != .None do return -3
	p := transmute([2]f32)stored
	x,y,vx,vy := bunny.integrate(p[0],p[1],self.vx,self.vy,{bunny.CANONICAL_DT,self.bounds_x,self.bounds_y,self.speed_scale,self.gravity})
	if err := godot.node2d_set_position(gd.godot_main_call(call), node, transmute(raw.Vector2)[2]f32{x,y}); err != .None do return -4
	self.vx, self.vy = vx, vy
	return 0
}

// Bunny_Verify checks actual engine position and live velocity against the
// independent canonical replay. The scene checks texture/scale/drawable count.
// Runs outside timing. Returns -1 invalid input, -2 unavailable object, -3
// read failure or -4 a bitwise state mismatch.
@(gododin)
bunny_verify :: proc(self: ^Bunny, call: gd.Main_Call, index, frames, seed: i64) -> i64 {
	if gd.validate_main_call(call) != .None || index<0 || frames<0 || frames>100000 do return -1
	object, ok := gd.self(call)
	if !ok do return -2
	node, cast_ok := godot.cast_Node2D(gd.godot_main_call(call), &object)
	if !cast_ok do return -2
	stored, err := godot.node2d_get_position(gd.godot_main_call(call), node)
	if err != .None do return -3
	p := transmute([2]f32)stored
	expected := bunny.reference_state(index,frames,u32(seed & 0xffffffff))
	actual := [4]f32{p[0],p[1],self.vx,self.vy}
	want := [4]f32{expected.x0,expected.y0,expected.vx0,expected.vy0}
	for v,i in actual {if transmute(u32)v != transmute(u32)want[i] do return -4}
	return 0
}