You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
6.2 KiB
Go

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"`
}
// AdventureLogLinePayload is sent when a new line is appended to the hero's adventure log.
type AdventureLogLinePayload struct {
Message string `json:"message"`
}
// TownExitPayload is sent when the hero leaves a town.
type TownExitPayload struct{}
// MerchantLootPayload is sent after a successful wandering merchant trade (WS or REST when online).
type MerchantLootPayload struct {
GoldSpent int64 `json:"goldSpent"`
ItemType string `json:"itemType"` // "potion", equipment slot key, etc.
ItemName string `json:"itemName,omitempty"`
Rarity string `json:"rarity,omitempty"`
GoldAmount int64 `json:"goldAmount,omitempty"` // auto-sell gold
}
// NPCEncounterPayload is sent when the hero meets a wandering NPC on the road (e.g. merchant).
type NPCEncounterPayload struct {
NPCID int64 `json:"npcId"`
NPCName string `json:"npcName"`
Role string `json:"role"`
Dialogue string `json:"dialogue,omitempty"`
Cost int64 `json:"cost"`
}
// NPCEncounterEndPayload is sent when the wandering merchant prompt ends (e.g. timeout).
type NPCEncounterEndPayload struct {
Reason string `json:"reason"` // "timeout"
}
// 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"`
}