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) // Item system packets.RegisterGlobalHandler(packets.OP_ItemMoveMsg, w.HandleItemMove) packets.RegisterGlobalHandler(packets.OP_ItemEquipMsg, w.HandleItemEquip) packets.RegisterGlobalHandler(packets.OP_ItemUnequipMsg, w.HandleItemUnequip) packets.RegisterGlobalHandler(packets.OP_ItemPickupMsg, w.HandleItemPickup) packets.RegisterGlobalHandler(packets.OP_ItemDropMsg, w.HandleItemDrop) packets.RegisterGlobalHandler(packets.OP_ItemExamineMsg, w.HandleItemExamine) packets.RegisterGlobalHandler(packets.OP_ItemUpdateMsg, w.HandleItemUpdate) fmt.Printf("Registered %d packet handlers\n", 28) } // 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]any) 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]any{ "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]any) { // 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]any, 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]any) 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}, } } // Item Packet Handlers // HandleItemMove handles item movement within player inventory func (w *World) HandleItemMove(ctx *packets.PacketContext, packet *packets.PacketData) error { fmt.Printf("Client %s sent item move packet\n", ctx.Client.GetCharacterName()) client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID()) if client != nil { client.UpdateActivity() // TODO: Parse move data from packet (fromBagID, fromSlot, toBagID, toSlot) // For now, use placeholder values for testing fromBagID := int32(0) fromSlot := int16(0) toBagID := int32(0) toSlot := int16(1) if w.itemMgr != nil { err := w.itemMgr.MoveItem(uint32(ctx.Client.GetCharacterID()), fromBagID, fromSlot, toBagID, toSlot) if err != nil { client.SendSimpleMessage(fmt.Sprintf("Item move failed: %v", err)) } else { client.SendSimpleMessage("Item moved successfully") } } } return nil } // HandleItemEquip handles item equipping func (w *World) HandleItemEquip(ctx *packets.PacketContext, packet *packets.PacketData) error { fmt.Printf("Client %s sent item equip packet\n", ctx.Client.GetCharacterName()) client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID()) if client != nil { client.UpdateActivity() // TODO: Parse equip data from packet (uniqueID, slot) // For now, use placeholder values for testing uniqueID := int32(1001) slot := int8(0) // Primary hand if w.itemMgr != nil { err := w.itemMgr.EquipItem(uint32(ctx.Client.GetCharacterID()), uniqueID, slot) if err != nil { client.SendSimpleMessage(fmt.Sprintf("Item equip failed: %v", err)) } else { client.SendSimpleMessage(fmt.Sprintf("Item equipped to slot %d", slot)) } } } return nil } // HandleItemUnequip handles item unequipping func (w *World) HandleItemUnequip(ctx *packets.PacketContext, packet *packets.PacketData) error { fmt.Printf("Client %s sent item unequip packet\n", ctx.Client.GetCharacterName()) client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID()) if client != nil { client.UpdateActivity() // TODO: Parse unequip data from packet (slot) // For now, use placeholder values for testing slot := int8(0) // Primary hand if w.itemMgr != nil { err := w.itemMgr.UnequipItem(uint32(ctx.Client.GetCharacterID()), slot) if err != nil { client.SendSimpleMessage(fmt.Sprintf("Item unequip failed: %v", err)) } else { client.SendSimpleMessage(fmt.Sprintf("Item unequipped from slot %d", slot)) } } } return nil } // HandleItemPickup handles picking up world drops func (w *World) HandleItemPickup(ctx *packets.PacketContext, packet *packets.PacketData) error { fmt.Printf("Client %s sent item pickup packet\n", ctx.Client.GetCharacterName()) client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID()) if client != nil { client.UpdateActivity() // TODO: Parse pickup data from packet (itemUniqueID) // For now, use placeholder values for testing itemUniqueID := int32(5001) zoneID := int32(1) // Current zone if w.itemMgr != nil { err := w.itemMgr.PickupWorldDrop(uint32(ctx.Client.GetCharacterID()), itemUniqueID, zoneID) if err != nil { client.SendSimpleMessage(fmt.Sprintf("Item pickup failed: %v", err)) } else { client.SendSimpleMessage("Item picked up") // TODO: Remove item from world display for other players } } } return nil } // HandleItemDrop handles dropping items to the world func (w *World) HandleItemDrop(ctx *packets.PacketContext, packet *packets.PacketData) error { fmt.Printf("Client %s sent item drop packet\n", ctx.Client.GetCharacterName()) client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID()) if client != nil { client.UpdateActivity() // TODO: Parse drop data from packet (uniqueID, quantity, x, y, z) // For now, use placeholder values for testing itemID := int32(1001) quantity := int16(1) x, y, z := float32(100), float32(100), float32(50) zoneID := int32(1) if w.itemMgr != nil { // First remove from player inventory (would need to look up by uniqueID) // TODO: Get uniqueID from packet and remove from player // Create world drop err := w.itemMgr.CreateWorldDrop(itemID, quantity, x, y, z, zoneID) if err != nil { client.SendSimpleMessage(fmt.Sprintf("Item drop failed: %v", err)) } else { client.SendSimpleMessage("Item dropped") // TODO: Show item to other players in range } } } return nil } // HandleItemExamine handles item examination requests func (w *World) HandleItemExamine(ctx *packets.PacketContext, packet *packets.PacketData) error { fmt.Printf("Client %s sent item examine packet\n", ctx.Client.GetCharacterName()) client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID()) if client != nil { client.UpdateActivity() // TODO: Parse examine data from packet (uniqueID or itemID) // For now, use placeholder values for testing itemID := int32(1001) if w.itemMgr != nil { itemTemplate := w.itemMgr.GetItemTemplate(itemID) if itemTemplate == nil { client.SendSimpleMessage("Item not found") } else { // Send item details to client w.SendItemDetails(client, itemTemplate) } } } return nil } // HandleItemUpdate handles item update notifications func (w *World) HandleItemUpdate(ctx *packets.PacketContext, packet *packets.PacketData) error { fmt.Printf("Client %s sent item update packet\n", ctx.Client.GetCharacterName()) client := w.clients.GetByCharacterID(ctx.Client.GetCharacterID()) if client != nil { client.UpdateActivity() // TODO: Parse update data from packet // This might be triggered when client needs updated item information if w.itemMgr != nil { // Send updated inventory to client w.SendPlayerInventory(client) } } return nil } // SendItemDetails sends detailed item information to a client func (w *World) SendItemDetails(client *Client, item any) { if w.itemMgr == nil { return } // TODO: Implement actual item detail packet building // This would include stats, description, level requirements, etc. fmt.Printf("Sending item details to %s\n", client.CharacterName) // Placeholder - send basic item info as chat message client.SendSimpleMessage("Item Details: [Item information would be displayed here]") } // SendPlayerInventory sends complete inventory to a client func (w *World) SendPlayerInventory(client *Client) { if w.itemMgr == nil { return } playerID := uint32(client.CharacterID) // Get player inventory and equipment inventory, err := w.itemMgr.GetPlayerInventory(playerID) if err != nil { fmt.Printf("Failed to get inventory for player %d: %v\n", playerID, err) return } equipment, err := w.itemMgr.GetPlayerEquipment(playerID, 0) // Base equipment if err != nil { fmt.Printf("Failed to get equipment for player %d: %v\n", playerID, err) return } // TODO: Build and send inventory packet fmt.Printf("Sending inventory to %s: %d inventory items, %d equipped items\n", client.CharacterName, inventory.GetNumberOfItems(), equipment.GetNumberOfItems()) // Placeholder - send summary as chat message client.SendSimpleMessage(fmt.Sprintf("Inventory Update: %d items in inventory, %d equipped", inventory.GetNumberOfItems(), equipment.GetNumberOfItems())) } // SendItemUpdate sends item update to client func (w *World) SendItemUpdate(client *Client, updateType string, itemData map[string]any) { if w.itemMgr == nil { return } // TODO: Build and send item update packet fmt.Printf("Sending item update to %s: %s - %v\n", client.CharacterName, updateType, itemData) // Placeholder - send update as chat message client.SendSimpleMessage(fmt.Sprintf("Item Update: %s", updateType)) } // BroadcastItemUpdate broadcasts item updates to nearby players func (w *World) BroadcastItemUpdate(sourcePlayerID uint32, updateType string, itemData map[string]any) { // TODO: Implement item update broadcasting (for things like equipment changes visible to others) fmt.Printf("Broadcasting item update from player %d: %s - %v\n", sourcePlayerID, updateType, itemData) // Send to players in range (placeholder) clients := w.clients.GetAll() for _, client := range clients { if client.CurrentZone != nil && client.CharacterID != int32(sourcePlayerID) { // TODO: Check if client is in range client.SendSimpleMessage(fmt.Sprintf("Player item update: %s", updateType)) } } }