Fix 354 gdlint warnings across 65 files: 194 class-definitions-order (reorder declarations), 138 max-line-length (split long lines), 22 code issues (unused args, no-else-return, naming). Update .gdlintrc to exclude addons/ and raise max-public-methods for test files. No logic changes — declaration order, whitespace, and naming only. Ticket: #783 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
174 lines
5.6 KiB
GDScript
174 lines
5.6 KiB
GDScript
## Generate MessagePack fixtures from GDScript encoder for Rust decoder testing.
|
|
## Run with: make fixtures-client
|
|
## (or: godot --headless --path client -s res://tests/gen_client_fixtures.gd)
|
|
##
|
|
## Reverse direction of server/tests/gen_fixtures.rs: GDScript encodes -> Rust decodes.
|
|
## Together with the Rust-generated fixtures, this closes the cross-encoder
|
|
## compatibility loop (D-030 Layer 1, #475).
|
|
##
|
|
## Loads Messagepack encoder directly (not via class_name) because -s scripts
|
|
## run before the project's class_name registry is fully populated.
|
|
extends SceneTree
|
|
|
|
var _msgpack: GDScript
|
|
var _count := 0
|
|
var _errors := 0
|
|
var _output_dir: String
|
|
|
|
|
|
func _init():
|
|
_run.call_deferred()
|
|
|
|
|
|
func _run():
|
|
_msgpack = load("res://addons/messagepack/messagepack.gd")
|
|
|
|
# Resolve repo root from Godot project root (client/).
|
|
# Assumes client/ is one level below repo root — validated below.
|
|
var project_root := ProjectSettings.globalize_path("res://")
|
|
var repo_root := project_root.rstrip("/").get_base_dir()
|
|
_output_dir = repo_root.path_join("server/tests/fixtures/gdscript")
|
|
|
|
if not DirAccess.dir_exists_absolute(repo_root.path_join("server")):
|
|
push_error("Repo root detection failed: %s/server/ does not exist" % repo_root)
|
|
quit(1)
|
|
return
|
|
|
|
DirAccess.make_dir_recursive_absolute(_output_dir)
|
|
|
|
_generate_inputs()
|
|
_generate_boundary_inputs()
|
|
_generate_batch()
|
|
|
|
if _errors > 0:
|
|
push_error("FAILED: %d encode errors encountered" % _errors)
|
|
quit(1)
|
|
return
|
|
if _count == 0:
|
|
push_error("FAILED: no fixtures generated")
|
|
quit(1)
|
|
return
|
|
print("Generated %d GDScript fixtures at %s" % [_count, _output_dir])
|
|
quit()
|
|
|
|
|
|
func _write_fixture(name: String, bytes: PackedByteArray) -> void:
|
|
if bytes.is_empty():
|
|
push_error("Encode produced empty bytes for fixture: %s" % name)
|
|
_errors += 1
|
|
return
|
|
var path := _output_dir.path_join(name + ".msgpack")
|
|
var file := FileAccess.open(path, FileAccess.WRITE)
|
|
if file == null:
|
|
push_error("Failed to write fixture: %s (error: %d)" % [path, FileAccess.get_open_error()])
|
|
_errors += 1
|
|
return
|
|
file.store_buffer(bytes)
|
|
file.flush()
|
|
file.close()
|
|
print(" Wrote %s (%d bytes)" % [name, bytes.size()])
|
|
_count += 1
|
|
|
|
|
|
## Encode a single PlayerInput to MessagePack bytes.
|
|
## Mirrors Protocol.encode_player_input() from protocol.gd.
|
|
func _encode_input(tick: int, action_name: String, action_data: Variant = null) -> PackedByteArray:
|
|
var action: Variant
|
|
if action_data != null:
|
|
action = {action_name: action_data}
|
|
elif action_name == "Interact":
|
|
action = {"Interact": {"target_entity_id": null, "verb": null}}
|
|
else:
|
|
action = action_name
|
|
|
|
var result = _msgpack.encode({"tick": tick, "action": action})
|
|
if result.status != null:
|
|
push_error("Encode failed: %s" % result.status)
|
|
return PackedByteArray()
|
|
return result.value
|
|
|
|
|
|
## Encode an array of PlayerInputs to MessagePack bytes.
|
|
## Mirrors Protocol.encode_player_inputs() from protocol.gd.
|
|
func _encode_inputs(inputs: Array) -> PackedByteArray:
|
|
var wire_inputs: Array = []
|
|
for input in inputs:
|
|
var action_name: String = input["action_name"]
|
|
var action_data: Variant = input.get("action_data")
|
|
var action: Variant
|
|
if action_data != null:
|
|
action = {action_name: action_data}
|
|
elif action_name == "Interact":
|
|
action = {"Interact": {"target_entity_id": null, "verb": null}}
|
|
else:
|
|
action = action_name
|
|
wire_inputs.append({"tick": input["tick"], "action": action})
|
|
|
|
var result = _msgpack.encode(wire_inputs)
|
|
if result.status != null:
|
|
push_error("Batch encode failed: %s" % result.status)
|
|
return PackedByteArray()
|
|
return result.value
|
|
|
|
|
|
func _generate_inputs() -> void:
|
|
# Unit variants: all 8 movement directions (tick=100)
|
|
for dir_name in [
|
|
"MoveNorth", "MoveSouth", "MoveEast", "MoveWest",
|
|
"MoveNortheast", "MoveSoutheast", "MoveSouthwest", "MoveNorthwest",
|
|
]:
|
|
_write_fixture("input_%s" % dir_name.to_snake_case(),
|
|
_encode_input(100, dir_name))
|
|
|
|
# Data variant: UsePerceptionMode (tick=200)
|
|
_write_fixture("input_perception_mode",
|
|
_encode_input(200, "UsePerceptionMode", "thermal"))
|
|
|
|
# Struct variant: Interact with null fields (tick=100)
|
|
_write_fixture("input_interact",
|
|
_encode_input(100, "Interact"))
|
|
|
|
# Other unit variants
|
|
_write_fixture("input_pause",
|
|
_encode_input(100, "Pause"))
|
|
_write_fixture("input_unpause",
|
|
_encode_input(100, "Unpause"))
|
|
_write_fixture("input_toggle_stance_up",
|
|
_encode_input(100, "ToggleStanceUp"))
|
|
_write_fixture("input_toggle_stance_down",
|
|
_encode_input(100, "ToggleStanceDown"))
|
|
_write_fixture("input_walk_away",
|
|
_encode_input(100, "WalkAway"))
|
|
|
|
|
|
func _generate_boundary_inputs() -> void:
|
|
# Tick values at MessagePack encoding format boundaries.
|
|
# GDScript encodes 256-32767 as int_16 (0xd1); Rust encodes as uint_16 (0xcd).
|
|
# GDScript encodes 65536-2147483647 as int_32 (0xd2); Rust as uint_32 (0xce).
|
|
# Both are valid MessagePack. Rust's rmp_serde must accept both.
|
|
var boundary_ticks: Array = [
|
|
[0, "boundary_tick_0"],
|
|
[127, "boundary_tick_127"],
|
|
[128, "boundary_tick_128"],
|
|
[255, "boundary_tick_255"],
|
|
[256, "boundary_tick_256"], # int_16 asymmetry start
|
|
[32767, "boundary_tick_32767"], # int_16 asymmetry end
|
|
[32768, "boundary_tick_32768"],
|
|
[65535, "boundary_tick_65535"],
|
|
[65536, "boundary_tick_65536"], # int_32 asymmetry start
|
|
[2147483647, "boundary_tick_2147483647"], # int_32 asymmetry end
|
|
]
|
|
|
|
for pair in boundary_ticks:
|
|
_write_fixture(pair[1],
|
|
_encode_input(pair[0], "Pause"))
|
|
|
|
|
|
func _generate_batch() -> void:
|
|
# Vec<PlayerInput> with two actions (mirrors Rust input_batch_two fixture)
|
|
_write_fixture("input_batch_two",
|
|
_encode_inputs([
|
|
{"tick": 0, "action_name": "MoveNorth"},
|
|
{"tick": 0, "action_name": "Interact"},
|
|
]))
|