package model import "encoding/json" // WSEnvelope is the wire format for all WebSocket messages (both directions). type WSEnvelope struct { Type string `json:"type"` Payload json.RawMessage `json:"payload"` } // NewWSEnvelope creates an envelope by marshaling the payload to JSON. // If marshaling fails, payload is set to "{}". func NewWSEnvelope(msgType string, payload any) WSEnvelope { raw, err := json.Marshal(payload) if err != nil { raw = []byte("{}") } return WSEnvelope{Type: msgType, Payload: raw} } // ClientMessage is a parsed inbound message from a WebSocket client, // tagged with the hero ID of the sending connection. type ClientMessage struct { HeroID int64 Type string Payload json.RawMessage } // --- Server -> Client payload types --- // HeroMovePayload is sent at 2 Hz while the hero is walking. type HeroMovePayload struct { X float64 `json:"x"` Y float64 `json:"y"` TargetX float64 `json:"targetX"` TargetY float64 `json:"targetY"` Speed float64 `json:"speed"` Heading float64 `json:"heading"` // radians } // PositionSyncPayload is sent every 10s as drift correction. type PositionSyncPayload struct { X float64 `json:"x"` Y float64 `json:"y"` WaypointIndex int `json:"waypointIndex"` WaypointFraction float64 `json:"waypointFraction"` State string `json:"state"` } // RouteAssignedPayload is sent when the hero starts walking a new road segment. type RouteAssignedPayload struct { RoadID int64 `json:"roadId"` Waypoints []PointXY `json:"waypoints"` DestinationTownID int64 `json:"destinationTownId"` Speed float64 `json:"speed"` } // PointXY is a 2D coordinate used in route payloads. type PointXY struct { X float64 `json:"x"` Y float64 `json:"y"` } // CombatStartPayload is sent when combat begins. type CombatStartPayload struct { Enemy CombatEnemyInfo `json:"enemy"` } // CombatEnemyInfo is the enemy snapshot sent to the client on combat_start. type CombatEnemyInfo struct { Name string `json:"name"` Type string `json:"type"` HP int `json:"hp"` MaxHP int `json:"maxHp"` Attack int `json:"attack"` Defense int `json:"defense"` Speed float64 `json:"speed"` IsElite bool `json:"isElite"` } // AttackPayload is sent on each swing during combat. type AttackPayload struct { Source string `json:"source"` // "hero" or "enemy" Damage int `json:"damage"` IsCrit bool `json:"isCrit,omitempty"` HeroHP int `json:"heroHp"` EnemyHP int `json:"enemyHp"` DebuffApplied string `json:"debuffApplied,omitempty"` } // CombatEndPayload is sent when the hero wins a fight. type CombatEndPayload struct { XPGained int64 `json:"xpGained"` GoldGained int64 `json:"goldGained"` Loot []LootItem `json:"loot,omitempty"` LeveledUp bool `json:"leveledUp"` NewLevel int `json:"newLevel,omitempty"` } // LootItem describes a single piece of loot in the combat_end payload. type LootItem struct { ItemType string `json:"itemType"` Name string `json:"name"` Rarity string `json:"rarity"` } // HeroDiedPayload is sent when the hero's HP reaches 0. type HeroDiedPayload struct { KilledBy string `json:"killedBy"` } // HeroRevivedPayload is sent after a revive. type HeroRevivedPayload struct { HP int `json:"hp"` } // TownNPCInfo describes an NPC in a town (town_enter payload). type TownNPCInfo struct { ID int64 `json:"id"` Name string `json:"name"` Type string `json:"type"` } // TownEnterPayload is sent when a hero arrives at a town. type TownEnterPayload struct { TownID int64 `json:"townId"` TownName string `json:"townName"` Biome string `json:"biome"` NPCs []TownNPCInfo `json:"npcs"` RestDurationMs int64 `json:"restDurationMs"` } // TownNPCVisitPayload is sent when the hero approaches an NPC (quest/shop/healer) during a town stay. type TownNPCVisitPayload struct { NPCID int64 `json:"npcId"` Name string `json:"name"` Type string `json:"type"` TownID int64 `json:"townId"` } // TownExitPayload is sent when the hero leaves a town. type TownExitPayload struct{} // LevelUpPayload is sent on level-up. type LevelUpPayload struct { NewLevel int `json:"newLevel"` } // BuffAppliedPayload is sent when a buff is activated. type BuffAppliedPayload struct { BuffType string `json:"buffType"` Duration float64 `json:"duration"` // seconds Magnitude float64 `json:"magnitude"` } // ErrorPayload is sent when a client command fails validation. type ErrorPayload struct { Code string `json:"code"` Message string `json:"message"` } // --- Client -> Server payload types --- // ActivateBuffPayload is the payload for the activate_buff command. type ActivateBuffPayload struct { BuffType string `json:"buffType"` } // AcceptQuestPayload is the payload for the accept_quest command. type AcceptQuestPayload struct { QuestID int64 `json:"questId"` } // ClaimQuestPayload is the payload for the claim_quest command. type ClaimQuestPayload struct { QuestID int64 `json:"questId"` } // NPCInteractPayload is the payload for the npc_interact command. type NPCInteractPayload struct { NPCID int64 `json:"npcId"` }