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) fmt.Printf("Registered %d packet handlers\n", 16) } // 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)) } // 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}, } }