ci: gate .NET workflow on server paths; add GDScript lint/format CI

- Run .NET build/test only when the solution, server/, or the workflow changes.
- Add gdlint and gdformat --check for client/ on relevant path changes.
- Align client GDScript with gdtoolkit (formatting, enum order, line length).
pull/10/head
VinPropane 2026-03-30 21:16:16 -04:00
parent a8cbcb5ff7
commit 15b0ee0921
6 changed files with 64 additions and 16 deletions

View File

@ -4,8 +4,16 @@ name: .NET
on:
push:
branches: [main]
paths:
- "NeonSprawl.sln"
- "server/**"
- ".github/workflows/dotnet.yml"
pull_request:
branches: [main]
paths:
- "NeonSprawl.sln"
- "server/**"
- ".github/workflows/dotnet.yml"
jobs:
build:

33
.github/workflows/gdscript.yml vendored 100644
View File

@ -0,0 +1,33 @@
# Lint and format-check GDScript (Godot 4). Uses gdtoolkit: https://github.com/Scony/godot-gdscript-toolkit
name: GDScript
on:
push:
branches: [main]
paths:
- "client/**/*.gd"
- ".github/workflows/gdscript.yml"
pull_request:
branches: [main]
paths:
- "client/**/*.gd"
- ".github/workflows/gdscript.yml"
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Install gdtoolkit
run: pip install "gdtoolkit==4.5.0"
- name: gdlint
run: gdlint client/
- name: gdformat (check only)
run: gdformat --check client/

View File

@ -5,7 +5,8 @@ extends Node3D
signal target_chosen(world: Vector3)
## Fallback when `Viewport.get_camera_3d()` is null (e.g. some editor setups). Set from `main.gd` in `_ready`.
## Fallback when `Viewport.get_camera_3d()` is null (e.g. some editor setups). Set from `main.gd`
## in `_ready`.
var fallback_camera: Camera3D

View File

@ -1,6 +1,7 @@
extends Node3D
## NS-16: composes ground pick + server authority; see `ground_pick.gd` / `position_authority_client.gd`.
## NS-16: composes ground pick + server authority; see `ground_pick.gd` /
## `position_authority_client.gd`.
@onready var _camera: Camera3D = $World/Camera3D
@onready var _player: CharacterBody3D = $Player
@ -11,7 +12,9 @@ extends Node3D
func _ready() -> void:
_ground_pick.set("fallback_camera", _camera)
_ground_pick.connect("target_chosen", Callable(self, "_on_target_chosen"))
_authority.connect("authoritative_position_received", Callable(self, "_on_authoritative_position"))
_authority.connect(
"authoritative_position_received", Callable(self, "_on_authoritative_position")
)
_authority.call("sync_from_server")

View File

@ -13,13 +13,13 @@ func _ready() -> void:
_goal = global_position
func set_move_goal(world_pos: Vector3) -> void:
_goal = world_pos
_goal.y = global_position.y
## NS-16: snap to authoritative server position; clears velocity so `move_and_slide` does not fight the sync.
## NS-16: snap to authoritative server position; clears velocity so `move_and_slide` does not fight
## the sync.
func snap_to_server(world_pos: Vector3) -> void:
global_position = world_pos
velocity = Vector3.ZERO

View File

@ -1,18 +1,19 @@
extends Node
## NS-16: POST MoveCommand then GET PositionState; emits authoritative world position for the avatar.
## NS-16: POST MoveCommand then GET PositionState; emits authoritative world position for the
## avatar.
## (No `class_name` so headless/CI can load the project before `.godot` import exists.)
signal authoritative_position_received(world: Vector3)
enum Phase { BOOT_GET, POST_MOVE, VERIFY_GET }
@export var base_url: String = "http://127.0.0.1:5253"
@export var dev_player_id: String = "dev-local-1"
var _http: HTTPRequest
var _busy: bool = false
enum _Phase { BOOT_GET, POST_MOVE, VERIFY_GET }
var _phase: _Phase = _Phase.BOOT_GET
var _phase: Phase = Phase.BOOT_GET
func _ready() -> void:
@ -25,7 +26,7 @@ func sync_from_server() -> void:
if _busy:
return
_busy = true
_phase = _Phase.BOOT_GET
_phase = Phase.BOOT_GET
_request_get()
@ -33,7 +34,7 @@ func submit_move_target(world: Vector3) -> void:
if _busy:
return
_busy = true
_phase = _Phase.POST_MOVE
_phase = Phase.POST_MOVE
var url := "%s/game/players/%s/move" % [_base_root(), _player_path_segment()]
var payload := {
"schemaVersion": 1,
@ -64,7 +65,9 @@ func _request_get() -> void:
_busy = false
func _on_request_completed(_result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
func _on_request_completed(
_result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray
) -> void:
if _result != HTTPRequest.RESULT_SUCCESS:
_busy = false
return
@ -72,17 +75,17 @@ func _on_request_completed(_result: int, response_code: int, _headers: PackedStr
var text := body.get_string_from_utf8()
match _phase:
_Phase.BOOT_GET:
Phase.BOOT_GET:
_busy = false
if response_code == 200:
_emit_position_from_response(text)
_Phase.POST_MOVE:
Phase.POST_MOVE:
if response_code != 200:
_busy = false
return
_phase = _Phase.VERIFY_GET
_phase = Phase.VERIFY_GET
_request_get()
_Phase.VERIFY_GET:
Phase.VERIFY_GET:
_busy = false
if response_code == 200:
_emit_position_from_response(text)