705 lines
24 KiB
Go
705 lines
24 KiB
Go
package world
|
|
|
|
import (
|
|
"eq2emu/internal/packets"
|
|
"fmt"
|
|
)
|
|
|
|
// RegisterPacketHandlers registers all world server packet handlers
|
|
func (w *World) RegisterPacketHandlers() {
|
|
fmt.Println("Registering world server packet handlers...")
|
|
|
|
// Basic connection and loading handlers
|
|
packets.RegisterGlobalHandler(packets.OP_DoneLoadingZoneResourcesMsg, w.HandleDoneLoadingZoneResources)
|
|
packets.RegisterGlobalHandler(packets.OP_DoneSendingInitialEntitiesMsg, w.HandleDoneSendingInitialEntities)
|
|
packets.RegisterGlobalHandler(packets.OP_DoneLoadingEntityResourcesMsg, w.HandleDoneLoadingEntityResources)
|
|
packets.RegisterGlobalHandler(packets.OP_DoneLoadingUIResourcesMsg, w.HandleDoneLoadingUIResources)
|
|
|
|
// Zone readiness
|
|
packets.RegisterGlobalHandler(packets.OP_ReadyToZoneMsg, w.HandleReadyToZone)
|
|
|
|
// Command handling
|
|
packets.RegisterGlobalHandler(packets.OP_ClientCmdMsg, w.HandleClientCommand)
|
|
packets.RegisterGlobalHandler(packets.OP_DispatchClientCmdMsg, w.HandleDispatchClientCommand)
|
|
|
|
// Position updates
|
|
packets.RegisterGlobalHandler(packets.OP_UpdatePositionMsg, w.HandlePositionUpdate)
|
|
|
|
// Chat system
|
|
packets.RegisterGlobalHandler(packets.OP_ChatTellChannelMsg, w.HandleChatTellChannel)
|
|
packets.RegisterGlobalHandler(packets.OP_ChatTellUserMsg, w.HandleChatTellUser)
|
|
|
|
// Zone transitions
|
|
packets.RegisterGlobalHandler(packets.OP_ChangeZoneMsg, w.HandleChangeZone)
|
|
packets.RegisterGlobalHandler(packets.OP_ClientTeleportRequestMsg, w.HandleClientTeleportRequest)
|
|
|
|
// Achievement system
|
|
packets.RegisterGlobalHandler(packets.OP_AchievementUpdateMsg, w.HandleAchievementUpdate)
|
|
packets.RegisterGlobalHandler(packets.OP_CharacterAchievements, w.HandleCharacterAchievements)
|
|
|
|
// Title system
|
|
packets.RegisterGlobalHandler(packets.OP_TitleUpdateMsg, w.HandleTitleUpdate)
|
|
packets.RegisterGlobalHandler(packets.OP_CharacterTitles, w.HandleCharacterTitles)
|
|
packets.RegisterGlobalHandler(packets.OP_SetActiveTitleMsg, w.HandleSetActiveTitle)
|
|
|
|
// NPC system
|
|
packets.RegisterGlobalHandler(packets.OP_NPCAttackMsg, w.HandleNPCAttack)
|
|
packets.RegisterGlobalHandler(packets.OP_NPCTargetMsg, w.HandleNPCTarget)
|
|
packets.RegisterGlobalHandler(packets.OP_NPCInfoMsg, w.HandleNPCInfo)
|
|
packets.RegisterGlobalHandler(packets.OP_NPCSpellCastMsg, w.HandleNPCSpellCast)
|
|
packets.RegisterGlobalHandler(packets.OP_NPCMovementMsg, w.HandleNPCMovement)
|
|
|
|
fmt.Printf("Registered %d packet handlers\n", 21)
|
|
}
|
|
|
|
// HandleDoneLoadingZoneResources handles when client finishes loading zone resources
|
|
func (w *World) HandleDoneLoadingZoneResources(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s finished loading zone resources\n", ctx.Client.GetCharacterName())
|
|
|
|
// Update client state
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
// TODO: Send initial zone data, spawns, etc.
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleDoneSendingInitialEntities handles when client finishes receiving initial entities
|
|
func (w *World) HandleDoneSendingInitialEntities(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s finished receiving initial entities\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
// TODO: Mark client as fully loaded
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleDoneLoadingEntityResources handles when client finishes loading entity resources
|
|
func (w *World) HandleDoneLoadingEntityResources(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s finished loading entity resources\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleDoneLoadingUIResources handles when client finishes loading UI resources
|
|
func (w *World) HandleDoneLoadingUIResources(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s finished loading UI resources\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
// TODO: Send initial UI packets (character sheet, spellbook, etc.)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleReadyToZone handles when client is ready to enter the zone
|
|
func (w *World) HandleReadyToZone(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s is ready to enter zone\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// TODO: Complete zone entry process
|
|
// - Send world time
|
|
// - Send MOTD
|
|
// - Send initial game state
|
|
// - Add player to zone
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleClientCommand handles client command messages
|
|
func (w *World) HandleClientCommand(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
// TODO: Parse command from packet data
|
|
// For now, just log the attempt
|
|
fmt.Printf("Client %s sent command (raw packet)\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// TODO: Extract command text and dispatch to command manager
|
|
// This will require parsing the packet structure
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleDispatchClientCommand handles dispatched client commands
|
|
func (w *World) HandleDispatchClientCommand(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s sent dispatched command\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
// TODO: Handle dispatched commands
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandlePositionUpdate handles player position updates
|
|
func (w *World) HandlePositionUpdate(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
// Position updates are frequent, so only log occasionally
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// TODO: Parse position data from packet
|
|
// TODO: Update player position in zone
|
|
// TODO: Send position update to other players in range
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleChatTellChannel handles channel chat messages
|
|
func (w *World) HandleChatTellChannel(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s sent channel chat message\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// TODO: Parse chat message from packet
|
|
// TODO: Validate channel permissions
|
|
// TODO: Broadcast message to appropriate recipients
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleChatTellUser handles direct tell messages
|
|
func (w *World) HandleChatTellUser(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s sent tell message\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// TODO: Parse tell message and target from packet
|
|
// TODO: Find target player
|
|
// TODO: Send message to target
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleChangeZone handles zone change requests
|
|
func (w *World) HandleChangeZone(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s requested zone change\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// TODO: Parse zone change request from packet
|
|
// TODO: Validate zone change is allowed
|
|
// TODO: Begin zone transfer process
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleClientTeleportRequest handles client teleport requests
|
|
func (w *World) HandleClientTeleportRequest(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s requested teleport\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// TODO: Parse teleport request from packet
|
|
// TODO: Validate teleport permissions
|
|
// TODO: Execute teleport
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleAchievementUpdate handles achievement update requests from client
|
|
func (w *World) HandleAchievementUpdate(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s requested achievement update\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// Send current achievement data to client
|
|
w.SendAchievementData(client)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleCharacterAchievements handles character achievements request from client
|
|
func (w *World) HandleCharacterAchievements(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s requested character achievements\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// Send complete achievement list to client
|
|
w.SendCharacterAchievements(client)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// SendAchievementData sends achievement data to a client
|
|
func (w *World) SendAchievementData(client *Client) {
|
|
if w.achievementMgr == nil {
|
|
return
|
|
}
|
|
|
|
characterID := client.CharacterID
|
|
|
|
// Get player's completed achievements
|
|
completedAchievements := w.achievementMgr.GetPlayerCompletedAchievements(characterID)
|
|
inProgressAchievements := w.achievementMgr.GetPlayerInProgressAchievements(characterID)
|
|
|
|
fmt.Printf("Sending achievement data to %s: %d completed, %d in progress\n",
|
|
client.CharacterName, len(completedAchievements), len(inProgressAchievements))
|
|
|
|
// Create achievement update packet
|
|
// This would normally build a proper packet structure
|
|
totalPoints := w.calculateAchievementPoints(characterID)
|
|
|
|
// Send packet to client (placeholder - would use actual packet building)
|
|
client.SendSimpleMessage(fmt.Sprintf("Achievement Update: %d completed, %d in progress, %d points",
|
|
len(completedAchievements), len(inProgressAchievements), totalPoints))
|
|
}
|
|
|
|
// SendCharacterAchievements sends complete character achievements to client
|
|
func (w *World) SendCharacterAchievements(client *Client) {
|
|
if w.achievementMgr == nil {
|
|
return
|
|
}
|
|
|
|
characterID := client.CharacterID
|
|
|
|
// Get all achievements with player progress
|
|
allAchievements := w.achievementMgr.masterList.GetAllAchievements()
|
|
characterData := make(map[string]interface{})
|
|
|
|
for achievementID, achievement := range allAchievements {
|
|
progress := w.achievementMgr.GetPlayerProgress(characterID, achievementID)
|
|
completed := w.achievementMgr.IsPlayerCompleted(characterID, achievementID)
|
|
percentage := w.achievementMgr.GetCompletionPercentage(characterID, achievementID)
|
|
|
|
characterData[fmt.Sprintf("achievement_%d", achievementID)] = map[string]interface{}{
|
|
"id": achievementID,
|
|
"title": achievement.Title,
|
|
"description": achievement.UncompletedText,
|
|
"completed": completed,
|
|
"progress": progress,
|
|
"required": achievement.QtyRequired,
|
|
"percentage": percentage,
|
|
"points": achievement.PointValue,
|
|
"category": achievement.Category,
|
|
"expansion": achievement.Expansion,
|
|
}
|
|
}
|
|
|
|
fmt.Printf("Sending complete achievement list to %s: %d achievements\n",
|
|
client.CharacterName, len(allAchievements))
|
|
|
|
// Send packet to client (placeholder - would use actual packet building)
|
|
client.SendSimpleMessage(fmt.Sprintf("Character Achievements: %d total achievements", len(allAchievements)))
|
|
}
|
|
|
|
// calculateAchievementPoints calculates total achievement points for a character
|
|
func (w *World) calculateAchievementPoints(characterID int32) uint32 {
|
|
if w.achievementMgr == nil {
|
|
return 0
|
|
}
|
|
|
|
completedAchievements := w.achievementMgr.GetPlayerCompletedAchievements(characterID)
|
|
totalPoints := uint32(0)
|
|
|
|
for _, achievementID := range completedAchievements {
|
|
achievement := w.achievementMgr.GetAchievement(achievementID)
|
|
if achievement != nil {
|
|
totalPoints += achievement.PointValue
|
|
}
|
|
}
|
|
|
|
return totalPoints
|
|
}
|
|
|
|
// HandleTitleUpdate handles title update requests from client
|
|
func (w *World) HandleTitleUpdate(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s requested title update\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// Send current title data to client
|
|
w.SendTitleData(client)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleCharacterTitles handles character titles request from client
|
|
func (w *World) HandleCharacterTitles(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s requested character titles\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// Send complete title list to client
|
|
w.SendCharacterTitles(client)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleSetActiveTitle handles setting active title requests from client
|
|
func (w *World) HandleSetActiveTitle(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s requested to set active title\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// TODO: Parse title ID and position from packet data
|
|
// TODO: Validate player has the title
|
|
// TODO: Set active title
|
|
// TODO: Send confirmation to client
|
|
|
|
// For now, just log the request
|
|
fmt.Printf("Set active title request for %s processed\n", client.CharacterName)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// SendTitleData sends title data to a client
|
|
func (w *World) SendTitleData(client *Client) {
|
|
if w.titleMgr == nil {
|
|
return
|
|
}
|
|
|
|
characterID := client.CharacterID
|
|
|
|
// Get player's titles
|
|
playerTitles := w.titleMgr.GetPlayerTitles(characterID)
|
|
titleCount := playerTitles.GetTitleCount()
|
|
|
|
fmt.Printf("Sending title data to %s: %d titles\n",
|
|
client.CharacterName, titleCount)
|
|
|
|
// Create title update packet (placeholder)
|
|
client.SendSimpleMessage(fmt.Sprintf("Title Update: %d titles available", titleCount))
|
|
}
|
|
|
|
// SendCharacterTitles sends complete character titles to client
|
|
func (w *World) SendCharacterTitles(client *Client) {
|
|
if w.titleMgr == nil {
|
|
return
|
|
}
|
|
|
|
characterID := client.CharacterID
|
|
|
|
// Get player's titles and master list
|
|
playerTitles := w.titleMgr.GetPlayerTitles(characterID)
|
|
masterList := w.titleMgr.titleManager.GetMasterList()
|
|
|
|
titleCount := playerTitles.GetTitleCount()
|
|
totalTitles := masterList.GetTitleCount()
|
|
|
|
fmt.Printf("Sending complete title list to %s: %d owned out of %d total\n",
|
|
client.CharacterName, titleCount, totalTitles)
|
|
|
|
// Get player's formatted name with titles
|
|
formattedName := w.titleMgr.GetPlayerFormattedName(characterID, client.CharacterName)
|
|
|
|
// Send packet to client (placeholder - would use actual packet building)
|
|
client.SendSimpleMessage(fmt.Sprintf("Character Titles: %d owned, %d total. Display name: %s",
|
|
titleCount, totalTitles, formattedName))
|
|
}
|
|
|
|
// NPC Packet Handlers
|
|
|
|
// HandleNPCAttack handles NPC attack packets from clients
|
|
func (w *World) HandleNPCAttack(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s sent NPC attack packet\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// TODO: Parse NPC ID and attack type from packet data
|
|
// TODO: Validate player can attack NPC
|
|
// TODO: Process attack through combat system
|
|
// TODO: Send attack result to client and nearby players
|
|
|
|
// For now, just trigger a test NPC kill event for achievement testing
|
|
if w.npcMgr != nil {
|
|
testNPCID := int32(1001)
|
|
w.npcMgr.OnNPCKilled(testNPCID, ctx.Client.GetCharacterID())
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleNPCTarget handles NPC targeting packets from clients
|
|
func (w *World) HandleNPCTarget(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s sent NPC target packet\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// TODO: Parse NPC ID from packet data
|
|
// TODO: Validate NPC exists and is targetable
|
|
// TODO: Set player's target
|
|
// TODO: Send targeting confirmation to client
|
|
|
|
// For testing, send NPC info for any targeting
|
|
w.SendNPCInfo(client, 1001) // Test NPC
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleNPCInfo handles NPC info requests from clients
|
|
func (w *World) HandleNPCInfo(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s requested NPC info\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// TODO: Parse NPC ID from packet data
|
|
// TODO: Send NPC information to client
|
|
|
|
// For testing, send test NPC info
|
|
w.SendNPCInfo(client, 1001)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleNPCSpellCast handles NPC spell cast notifications
|
|
func (w *World) HandleNPCSpellCast(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
fmt.Printf("Client %s received NPC spell cast notification\n", ctx.Client.GetCharacterName())
|
|
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// TODO: Parse spell cast data from packet
|
|
// TODO: Process spell effects
|
|
// TODO: Update client state based on spell effects
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HandleNPCMovement handles NPC movement updates
|
|
func (w *World) HandleNPCMovement(ctx *packets.PacketContext, packet *packets.PacketData) error {
|
|
// NPC movement updates can be frequent, so only log occasionally
|
|
client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID())
|
|
if client != nil {
|
|
client.UpdateActivity()
|
|
|
|
// TODO: Parse NPC movement data from packet
|
|
// TODO: Update NPC position in world
|
|
// TODO: Send movement update to other clients in range
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// SendNPCInfo sends NPC information to a client
|
|
func (w *World) SendNPCInfo(client *Client, npcID int32) {
|
|
if w.npcMgr == nil {
|
|
return
|
|
}
|
|
|
|
// Get NPC information
|
|
npcInfo := w.npcMgr.GetNPCInfo(npcID)
|
|
if npcInfo == nil {
|
|
return
|
|
}
|
|
|
|
fmt.Printf("Sending NPC info to %s: NPC %d (%s) Level %d\n",
|
|
client.CharacterName, npcInfo.ID, npcInfo.Name, npcInfo.Level)
|
|
|
|
// Get NPC statistics for additional info
|
|
stats := w.npcMgr.GetStatistics()
|
|
|
|
// Create NPC info packet (placeholder)
|
|
client.SendSimpleMessage(fmt.Sprintf("NPC Info: %s (ID: %d, Level: %d) - %v total NPCs active",
|
|
npcInfo.Name, npcInfo.ID, npcInfo.Level, stats["total_npcs"]))
|
|
}
|
|
|
|
// SendNPCUpdate sends NPC update to clients in range
|
|
func (w *World) SendNPCUpdate(npcID int32, updateType string, data map[string]interface{}) {
|
|
// TODO: Implement NPC update broadcasting
|
|
// This would send updates to all clients in range of the NPC
|
|
|
|
fmt.Printf("NPC Update: NPC %d - %s: %v\n", npcID, updateType, data)
|
|
|
|
// Get all clients and send update (placeholder)
|
|
clients := w.clients.GetAll()
|
|
for _, client := range clients {
|
|
if client.CurrentZone != nil {
|
|
// TODO: Check if client is in range of NPC
|
|
client.SendSimpleMessage(fmt.Sprintf("NPC Update: %s for NPC %d", updateType, npcID))
|
|
}
|
|
}
|
|
}
|
|
|
|
// SendNPCCombatUpdate sends combat-related NPC updates to clients
|
|
func (w *World) SendNPCCombatUpdate(npcID int32, targetID int32, combatType string, damage int32) {
|
|
// TODO: Implement NPC combat update broadcasting
|
|
|
|
fmt.Printf("NPC Combat Update: NPC %d -> Target %d, %s for %d damage\n",
|
|
npcID, targetID, combatType, damage)
|
|
|
|
// Send to relevant clients (placeholder)
|
|
clients := w.clients.GetAll()
|
|
for _, client := range clients {
|
|
if client.CurrentZone != nil && (client.CharacterID == targetID ||
|
|
client.CharacterID == npcID) { // TODO: Proper range check
|
|
client.SendSimpleMessage(fmt.Sprintf("Combat: NPC %d %s target %d for %d damage",
|
|
npcID, combatType, targetID, damage))
|
|
}
|
|
}
|
|
}
|
|
|
|
// WorldDatabaseAdapter adapts the World's database for packet handlers
|
|
type WorldDatabaseAdapter struct {
|
|
world *World
|
|
}
|
|
|
|
// GetCharacter implements packets.DatabaseInterface
|
|
func (wda *WorldDatabaseAdapter) GetCharacter(characterID int32) (map[string]interface{}, error) {
|
|
// TODO: Implement character loading from database
|
|
return nil, fmt.Errorf("character loading not yet implemented")
|
|
}
|
|
|
|
// SaveCharacter implements packets.DatabaseInterface
|
|
func (wda *WorldDatabaseAdapter) SaveCharacter(characterID int32, data map[string]interface{}) error {
|
|
// TODO: Implement character saving to database
|
|
return fmt.Errorf("character saving not yet implemented")
|
|
}
|
|
|
|
// WorldClientAdapter adapts World's Client to packets.ClientInterface
|
|
type WorldClientAdapter struct {
|
|
client *Client
|
|
world *World
|
|
}
|
|
|
|
// GetCharacterID implements packets.ClientInterface
|
|
func (wca *WorldClientAdapter) GetCharacterID() int32 {
|
|
return wca.client.CharacterID
|
|
}
|
|
|
|
// GetAccountID implements packets.ClientInterface
|
|
func (wca *WorldClientAdapter) GetAccountID() int32 {
|
|
return wca.client.AccountID
|
|
}
|
|
|
|
// GetCharacterName implements packets.ClientInterface
|
|
func (wca *WorldClientAdapter) GetCharacterName() string {
|
|
return wca.client.CharacterName
|
|
}
|
|
|
|
// GetClientVersion implements packets.ClientInterface
|
|
func (wca *WorldClientAdapter) GetClientVersion() int32 {
|
|
return wca.client.GetClientVersion()
|
|
}
|
|
|
|
// GetAdminLevel implements packets.ClientInterface
|
|
func (wca *WorldClientAdapter) GetAdminLevel() int {
|
|
return wca.client.AdminLevel
|
|
}
|
|
|
|
// IsInZone implements packets.ClientInterface
|
|
func (wca *WorldClientAdapter) IsInZone() bool {
|
|
return wca.client.CurrentZone != nil
|
|
}
|
|
|
|
// SendPacket implements packets.ClientInterface
|
|
func (wca *WorldClientAdapter) SendPacket(opcode packets.InternalOpcode, data []byte) error {
|
|
// TODO: Implement packet sending via UDP connection
|
|
fmt.Printf("Sending packet %s to client %s\n",
|
|
packets.GetInternalOpcodeName(opcode),
|
|
wca.client.CharacterName)
|
|
return nil
|
|
}
|
|
|
|
// Disconnect implements packets.ClientInterface
|
|
func (wca *WorldClientAdapter) Disconnect() error {
|
|
wca.client.DisconnectWithReason("Disconnected by packet handler")
|
|
return nil
|
|
}
|
|
|
|
// WorldServerAdapter adapts World to packets.WorldInterface
|
|
type WorldServerAdapter struct {
|
|
world *World
|
|
}
|
|
|
|
// GetClientByID implements packets.WorldInterface
|
|
func (wsa *WorldServerAdapter) GetClientByID(characterID int32) packets.ClientInterface {
|
|
client := wsa.world.clients.GetByCharacterID(characterID)
|
|
if client != nil {
|
|
return &WorldClientAdapter{client: client, world: wsa.world}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetAllClients implements packets.WorldInterface
|
|
func (wsa *WorldServerAdapter) GetAllClients() []packets.ClientInterface {
|
|
clients := wsa.world.clients.GetAll()
|
|
result := make([]packets.ClientInterface, len(clients))
|
|
|
|
for i, client := range clients {
|
|
result[i] = &WorldClientAdapter{client: client, world: wsa.world}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// BroadcastPacket implements packets.WorldInterface
|
|
func (wsa *WorldServerAdapter) BroadcastPacket(opcode packets.InternalOpcode, data []byte) {
|
|
// TODO: Implement packet broadcasting
|
|
fmt.Printf("Broadcasting packet %s to all clients\n", packets.GetInternalOpcodeName(opcode))
|
|
}
|
|
|
|
// BroadcastToZone implements packets.WorldInterface
|
|
func (wsa *WorldServerAdapter) BroadcastToZone(zoneID int32, opcode packets.InternalOpcode, data []byte) {
|
|
// TODO: Implement zone-specific broadcasting
|
|
fmt.Printf("Broadcasting packet %s to zone %d\n", packets.GetInternalOpcodeName(opcode), zoneID)
|
|
}
|
|
|
|
// CreatePacketContext creates a packet context for a client
|
|
func (w *World) CreatePacketContext(client *Client) *packets.PacketContext {
|
|
return &packets.PacketContext{
|
|
Client: &WorldClientAdapter{client: client, world: w},
|
|
World: &WorldServerAdapter{world: w},
|
|
Database: &WorldDatabaseAdapter{world: w},
|
|
}
|
|
} |