fix(*): apply the locomotion mask during in-game/eval inference, not just training

AIShipController (eval + real gameplay) ran the raw policy output unmasked
regardless of allow_vertical/allow_pitch_roll, while ShipAIController
(training) correctly discarded those axes for grounded curriculum stages.
A grounded-trained model's untrained vertical/pitch-roll output reached the
ship as noise during eval, understating it against models that were never
handicapped this way.
This commit is contained in:
Josh Creek
2026-07-21 22:23:09 +01:00
parent dd2b3c570b
commit 8c15c466ef
5 changed files with 78 additions and 8 deletions
+13 -3
View File
@@ -17,6 +17,16 @@ extends ShipController
# Uniform noise magnitude added to each action axis (0 = play at full skill).
@export_range(0.0, 1.0) var action_noise: float = 0.0
# Must mirror whatever the model was actually trained with (see
# ShipAIController's identical exports on the training side, curriculum
# stages 1-2 in TRAINING.md). A model trained grounded (mask on) never got a
# reward gradient on these axes, so its raw output there is untrained noise —
# leaving this true for such a model doesn't make it fly well, it just lets
# that noise reach the ship instead of being discarded like it was in
# training. Set false to match a grounded-trained model's actual behaviour.
@export var allow_vertical := true
@export var allow_pitch_roll := true
var _policy: PolicyNetwork
var _action := ShipAction.new()
var _ticks_until_decision := 0
@@ -53,13 +63,13 @@ func _decide() -> void:
# gymnasium orders by SORTED key name — rotation xyz, thrust xyz, turbo
# (> 0 means on) — NOT ShipAction's thrust-first declaration order.
_action.rotation = Vector3(
_axis(out[0]),
_axis(out[0]) if allow_pitch_roll else 0.0,
_axis(out[1]),
_axis(out[2])
_axis(out[2]) if allow_pitch_roll else 0.0
)
_action.thrust = Vector3(
_axis(out[3]),
_axis(out[4]),
_axis(out[4]) if allow_vertical else 0.0,
_axis(out[5])
)
_action.turbo = out[6] > 0.0