SpaceZone.BroadcastRadarUpdates() queues RadarContactUpdateEvent (contacts, currentMode, currentRange, radarPowerUsage, activeScanCooldown) every radar interval, but MessagePackSerializer.EventToDict has no case for RadarContactUpdateEvent — the event goes over the wire as just {type: "RadarContactUpdate", serverTick} (the type name comes from the GetEventTypeName fallback; the field switch silently drops everything else).
Impact:
The Angular client (game-server.service.ts:1083, normalizeRadarContactUpdateEvent) receives empty events — the radar HUD has presumably never shown a contact via the MessagePack path.
The Godot client (spikersoft-games-godot PR #2) hit the same wall; it now synthesizes radar locally from tracked ships and will automatically prefer server contacts once this is fixed.
Fix: add a RadarContactUpdateEvent e case to EventToDict serializing contacts (list of dicts: entityId, contactType, x/y/z → note Angular expects lastKnownX/Y/Z naming — pick one and align the clients), timeSinceUpdate, isGhost, isStealthed, signalStrength, distance, name, healthPercent, shieldPercent, isHostile, isFriendly, plus currentMode, currentRange, radarPowerUsage, activeScanCooldown.
`SpaceZone.BroadcastRadarUpdates()` queues `RadarContactUpdateEvent` (contacts, currentMode, currentRange, radarPowerUsage, activeScanCooldown) every radar interval, but `MessagePackSerializer.EventToDict` has **no case for `RadarContactUpdateEvent`** — the event goes over the wire as just `{type: "RadarContactUpdate", serverTick}` (the type name comes from the `GetEventTypeName` fallback; the field switch silently drops everything else).
Impact:
- The Angular client (`game-server.service.ts:1083`, `normalizeRadarContactUpdateEvent`) receives empty events — the radar HUD has presumably never shown a contact via the MessagePack path.
- The Godot client (spikersoft-games-godot PR #2) hit the same wall; it now synthesizes radar locally from tracked ships and will automatically prefer server contacts once this is fixed.
Fix: add a `RadarContactUpdateEvent e` case to `EventToDict` serializing `contacts` (list of dicts: `entityId`, `contactType`, `x/y/z` → note Angular expects `lastKnownX/Y/Z` naming — pick one and align the clients), `timeSinceUpdate`, `isGhost`, `isStealthed`, `signalStrength`, `distance`, `name`, `healthPercent`, `shieldPercent`, `isHostile`, `isFriendly`, plus `currentMode`, `currentRange`, `radarPowerUsage`, `activeScanCooldown`.
Refs: `SpikerSoft.GameServer/Network/MessagePackSerializer.cs` (EventToDict switch), `SpikerSoft.GameServer/Zones/SpaceZone.cs` ~L881 (`BroadcastRadarUpdates`), `SpikerSoft.Common/Models/GameServer/RadarEvents.cs`.
Scope update (found while reviewing spikersoft-games-godot PR #3): the same missing-EventToDict-case gap also affects two more Space events, both queued owner-only by SpaceZone:
RadarModeChangedEvent (entityId, newMode, newRange, powerUsage) — queued on every successful SetRadarMode (SpaceZone.cs:1307/:1338) and after ActiveScan (:1477).
StealthStateChangedEvent (entityId, isStealthActive, isFullyEngaged, activationDelayRemaining, reactivationCooldown, powerUsage, heatGeneration) — queued on stealth activate (:1411) and deactivate (:866).
Both currently arrive as {type, serverTick} only. The Godot client (PR #3) treats its radar/stealth UI state as optimistic and applies these events defensively when fields are present, so it will pick the fields up automatically once the EventToDict cases land — please add cases for these two alongside RadarContactUpdateEvent.
Scope update (found while reviewing spikersoft-games-godot PR #3): the same missing-`EventToDict`-case gap also affects two more Space events, both queued owner-only by `SpaceZone`:
- **`RadarModeChangedEvent`** (`entityId`, `newMode`, `newRange`, `powerUsage`) — queued on every successful `SetRadarMode` (SpaceZone.cs:1307/:1338) and after `ActiveScan` (:1477).
- **`StealthStateChangedEvent`** (`entityId`, `isStealthActive`, `isFullyEngaged`, `activationDelayRemaining`, `reactivationCooldown`, `powerUsage`, `heatGeneration`) — queued on stealth activate (:1411) and deactivate (:866).
Both currently arrive as `{type, serverTick}` only. The Godot client (PR #3) treats its radar/stealth UI state as optimistic and applies these events defensively when fields are present, so it will pick the fields up automatically once the `EventToDict` cases land — please add cases for these two alongside `RadarContactUpdateEvent`.
Fix is ready in spikersoft-backend PR #517 (CI fully green: unit tests, both arch builds, game-server pipeline). Adds EventToDict cases for RadarContactUpdateEvent, RadarModeChangedEvent, StealthStateChangedEvent, ContactLostEvent and ContactGhostEvent. Contact positions serialize as lastKnownX/Y/Z with type/contactType and detectedThroughStealth aliases — matching what the Angular normalizer and the Godot client already parse, so no client changes needed. Closing once the PR merges (merge is awaiting a human click — the agent's merge action was permission-blocked).
Fix is ready in spikersoft-backend PR #517 (CI fully green: unit tests, both arch builds, game-server pipeline). Adds `EventToDict` cases for `RadarContactUpdateEvent`, `RadarModeChangedEvent`, `StealthStateChangedEvent`, `ContactLostEvent` and `ContactGhostEvent`. Contact positions serialize as `lastKnownX/Y/Z` with `type`/`contactType` and `detectedThroughStealth` aliases — matching what the Angular normalizer and the Godot client already parse, so no client changes needed. Closing once the PR merges (merge is awaiting a human click — the agent's merge action was permission-blocked).
Resolved in spikersoft-backend PR #517 (merged to master). EventToDict now serializes RadarContactUpdate, RadarModeChanged, StealthStateChanged, ContactLost and ContactGhost with full fields (contact positions as lastKnownX/Y/Z, matching both the Angular and Godot clients as-is). The master deploy pipeline ships it to the gameserver. Closing.
Resolved in spikersoft-backend PR #517 (merged to master). `EventToDict` now serializes `RadarContactUpdate`, `RadarModeChanged`, `StealthStateChanged`, `ContactLost` and `ContactGhost` with full fields (contact positions as `lastKnownX/Y/Z`, matching both the Angular and Godot clients as-is). The master deploy pipeline ships it to the gameserver. Closing.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
SpaceZone.BroadcastRadarUpdates()queuesRadarContactUpdateEvent(contacts, currentMode, currentRange, radarPowerUsage, activeScanCooldown) every radar interval, butMessagePackSerializer.EventToDicthas no case forRadarContactUpdateEvent— the event goes over the wire as just{type: "RadarContactUpdate", serverTick}(the type name comes from theGetEventTypeNamefallback; the field switch silently drops everything else).Impact:
game-server.service.ts:1083,normalizeRadarContactUpdateEvent) receives empty events — the radar HUD has presumably never shown a contact via the MessagePack path.Fix: add a
RadarContactUpdateEvent ecase toEventToDictserializingcontacts(list of dicts:entityId,contactType,x/y/z→ note Angular expectslastKnownX/Y/Znaming — pick one and align the clients),timeSinceUpdate,isGhost,isStealthed,signalStrength,distance,name,healthPercent,shieldPercent,isHostile,isFriendly, pluscurrentMode,currentRange,radarPowerUsage,activeScanCooldown.Refs:
SpikerSoft.GameServer/Network/MessagePackSerializer.cs(EventToDict switch),SpikerSoft.GameServer/Zones/SpaceZone.cs~L881 (BroadcastRadarUpdates),SpikerSoft.Common/Models/GameServer/RadarEvents.cs.Scope update (found while reviewing spikersoft-games-godot PR #3): the same missing-
EventToDict-case gap also affects two more Space events, both queued owner-only bySpaceZone:RadarModeChangedEvent(entityId,newMode,newRange,powerUsage) — queued on every successfulSetRadarMode(SpaceZone.cs:1307/:1338) and afterActiveScan(:1477).StealthStateChangedEvent(entityId,isStealthActive,isFullyEngaged,activationDelayRemaining,reactivationCooldown,powerUsage,heatGeneration) — queued on stealth activate (:1411) and deactivate (:866).Both currently arrive as
{type, serverTick}only. The Godot client (PR #3) treats its radar/stealth UI state as optimistic and applies these events defensively when fields are present, so it will pick the fields up automatically once theEventToDictcases land — please add cases for these two alongsideRadarContactUpdateEvent.Fix is ready in spikersoft-backend PR #517 (CI fully green: unit tests, both arch builds, game-server pipeline). Adds
EventToDictcases forRadarContactUpdateEvent,RadarModeChangedEvent,StealthStateChangedEvent,ContactLostEventandContactGhostEvent. Contact positions serialize aslastKnownX/Y/Zwithtype/contactTypeanddetectedThroughStealthaliases — matching what the Angular normalizer and the Godot client already parse, so no client changes needed. Closing once the PR merges (merge is awaiting a human click — the agent's merge action was permission-blocked).Resolved in spikersoft-backend PR #517 (merged to master).
EventToDictnow serializesRadarContactUpdate,RadarModeChanged,StealthStateChanged,ContactLostandContactGhostwith full fields (contact positions aslastKnownX/Y/Z, matching both the Angular and Godot clients as-is). The master deploy pipeline ships it to the gameserver. Closing.