// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.net.client; import engine.Enum.DispatchChannel; import engine.Enum.GameObjectType; import engine.InterestManagement.WorldGrid; import engine.exception.MsgSendException; import engine.gameManager.*; import engine.job.JobContainer; import engine.job.JobScheduler; import engine.jobs.RefreshGroupJob; import engine.jobs.StuckJob; import engine.math.Vector3fImmutable; import engine.net.Dispatch; import engine.net.DispatchMessage; import engine.net.NetMsgHandler; import engine.net.client.handlers.AbstractClientMsgHandler; import engine.net.client.msg.*; import engine.net.client.msg.chat.AbstractChatMsg; import engine.net.client.msg.commands.ClientAdminCommandMsg; import engine.objects.*; import engine.server.MBServerStatics; import engine.server.world.WorldServer; import engine.session.Session; import engine.util.StringUtils; import org.pmw.tinylog.Logger; import java.sql.SQLException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; import static engine.math.FastMath.sqr; /** * @author: * @summary: This class is the mainline router for application protocol * messages received by the client. */ public class ClientMessagePump implements NetMsgHandler { // Instance variable declaration private final WorldServer server; public ClientMessagePump(WorldServer server) { super(); this.server = server; } /* * Incoming client protocol message are processed here */ private static void WhoRequest(WhoRequestMsg msg, ClientConnection origin) { // Handle /who request PlayerCharacter pc = origin.getPlayerCharacter(); if (pc == null) return; if (pc.getTimeStamp("WHO") > System.currentTimeMillis()) { ErrorPopupMsg.sendErrorMsg(pc, "Who too fast! Please wait 3 seconds."); return; } WhoResponseMsg.HandleResponse(msg.getSet(), msg.getFilterType(), msg.getFilter(), origin); pc.getTimestamps().put("WHO", System.currentTimeMillis() + 3000); } // *** Refactor need to figure this out. // Commented out for some reson or another. private static void runWalkSitStand(UpdateStateMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; pc.update(); if (msg.getSpeed() == 2) pc.setWalkMode(false); else pc.setWalkMode(true); DispatchMessage.dispatchMsgToInterestArea(pc, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); } private static void toggleLfgRecruiting(ToggleLfgRecruitingMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; int num = msg.toggleLfgRecruiting(); if (num == 1) pc.toggleLFGroup(); else if (num == 2) pc.toggleLFGuild(); else if (num == 3) pc.toggleRecruiting(); UpdateStateMsg rwss = new UpdateStateMsg(); rwss.setPlayer(pc); DispatchMessage.dispatchMsgToInterestArea(pc, rwss, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); } private static void toggleSitStand(ToggleSitStandMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; pc.update(); pc.setSit(msg.toggleSitStand()); // cancel effects that break on sit if (pc.isSit()) { pc.setCombat(false); pc.cancelOnSit(); } UpdateStateMsg rwss = new UpdateStateMsg(); if (pc.isSit()) { pc.setCombat(false); rwss.setAware(1); } rwss.setPlayer(pc); DispatchMessage.dispatchMsgToInterestArea(pc, rwss, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); } private static void targetObject(TargetObjectMsg msg, ClientConnection origin) { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; // TODO improve this later. hacky way to make sure player ingame is // active. if (!pc.isActive()) pc.setActive(true); pc.setLastTarget(GameObjectType.values()[msg.getTargetType()], msg.getTargetID()); } private static void social(SocialMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; DispatchMessage.dispatchMsgToInterestArea(pc, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, true); } //call this if the transfer fails server side to kick the item back to inventory from vault public static void forceTransferFromInventoryToVault(ItemFromVaultMsg msg, ClientConnection origin, String reason) { PlayerCharacter player = origin.getPlayerCharacter(); Dispatch dispatch; if (player == null) return; ItemToVaultMsg back = new ItemToVaultMsg(msg); dispatch = Dispatch.borrow(player, back); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); ChatManager.chatInfoError(player, "Can't transfer to inventory: " + reason); } //call this if the transfer fails server side to kick the item back to vault from inventory public static void forceTransferFromVaultToInventory(ItemToVaultMsg msg, ClientConnection origin, String reason) { PlayerCharacter player = origin.getPlayerCharacter(); Dispatch dispatch; if (player == null) return; ItemFromVaultMsg back = new ItemFromVaultMsg(msg); dispatch = Dispatch.borrow(player, back); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); ChatManager.chatInfoError(player, "Can't transfer to vault: " + reason); } private static void DeleteItem(DeleteItemMsg msg, ClientConnection origin) { CharacterItemManager itemManager = origin.getPlayerCharacter().charItemManager; int uuid = msg.getUUID(); PlayerCharacter sourcePlayer = origin.getPlayerCharacter(); if (sourcePlayer == null) return; if (!sourcePlayer.isAlive()) return; Item i = Item.getFromCache(msg.getUUID()); if (i == null) return; if (!itemManager.doesCharOwnThisItem(i.getObjectUUID())) return; if (!itemManager.inventoryContains(i)) return; if (i.isCanDestroy()) if (itemManager.delete(i) == true) { Dispatch dispatch = Dispatch.borrow(sourcePlayer, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } } private static void ackBankWindowOpened(AckBankWindowOpenedMsg msg, ClientConnection origin) { // According to the Wiki, the client should not send this message. // Log the instance to investigate, and modify Wiki accordingly. Logger.error(msg.toString()); } private static void modifyStat(ModifyStatMsg msg, ClientConnection origin) { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; int type = msg.getType(); switch (type) { case MBServerStatics.STAT_STR_ID: pc.addStr(msg.getAmount()); break; case MBServerStatics.STAT_DEX_ID: pc.addDex(msg.getAmount()); break; case MBServerStatics.STAT_CON_ID: pc.addCon(msg.getAmount()); break; case MBServerStatics.STAT_INT_ID: pc.addInt(msg.getAmount()); break; case MBServerStatics.STAT_SPI_ID: pc.addSpi(msg.getAmount()); break; } } // called when player clicks respawn button private static void respawn(RespawnMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter sourcePlayer = SessionManager.getPlayerCharacter(origin); if (sourcePlayer == null) return; if (msg.getObjectType() != sourcePlayer.getObjectType().ordinal() || msg.getObjectID() != sourcePlayer.getObjectUUID()) { Logger.error("Player " + sourcePlayer.getObjectUUID() + " respawning character of id " + msg.getObjectType() + ' ' + msg.getObjectID()); return; } if (sourcePlayer.isAlive()) { Logger.error("Player " + sourcePlayer.getObjectUUID() + " respawning while alive"); return; } // ResetAfterDeath player sourcePlayer.respawnLock.writeLock().lock(); try { sourcePlayer.respawn(true, false, true); } catch (Exception e) { Logger.error(e); } finally { sourcePlayer.respawnLock.writeLock().unlock(); } // Echo ResetAfterDeath message back msg.setPlayerHealth(sourcePlayer.getHealth()); // TODO calculate any experience loss before this point msg.setPlayerExp(sourcePlayer.getExp() + sourcePlayer.getOverFlowEXP()); Dispatch dispatch = Dispatch.borrow(sourcePlayer, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY); MoveToPointMsg moveMsg = new MoveToPointMsg(); moveMsg.setPlayer(sourcePlayer); moveMsg.setStartCoord(sourcePlayer.getLoc()); moveMsg.setEndCoord(sourcePlayer.getLoc()); moveMsg.setInBuilding(-1); moveMsg.setInBuildingFloor(-1); dispatch = Dispatch.borrow(sourcePlayer, moveMsg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY); MovementManager.sendRWSSMsg(sourcePlayer); // refresh the whole group with what just happened JobScheduler.getInstance().scheduleJob(new RefreshGroupJob(sourcePlayer), MBServerStatics.LOAD_OBJECT_DELAY); } private static void lootWindowRequest(LootWindowRequestMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; if (!pc.isAlive()) return; if (msg.getSourceType() != pc.getObjectType().ordinal() || msg.getSourceID() != pc.getObjectUUID()) { Logger.error("Player " + pc.getObjectUUID() + " looting from character of id " + msg.getSourceType() + ' ' + msg.getSourceID()); return; } if (pc.getAltitude() > 0) return; if (!pc.isAlive()) { return; } LootWindowResponseMsg lwrm = null; GameObjectType targetType = GameObjectType.values()[msg.getTargetType()]; AbstractCharacter characterTarget = null; Corpse corpseTarget = null; switch (targetType) { case PlayerCharacter: characterTarget = PlayerCharacter.getFromCache(msg.getTargetID()); if (characterTarget == null) return; if (characterTarget.isAlive()) return; if (pc.getLoc().distanceSquared2D(characterTarget.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)) { ErrorPopupMsg.sendErrorMsg(pc, "You are too far away to loot this corpse."); Logger.info(pc.getFirstName() + " tried looting at " + pc.getLoc().distance2D(characterTarget.getLoc()) + " distance."); return; } lwrm = new LootWindowResponseMsg(characterTarget.getObjectType().ordinal(), characterTarget.getObjectUUID(), characterTarget.getInventory(true)); break; case NPC: characterTarget = NPC.getFromCache(msg.getTargetID()); if (characterTarget == null) return; break; case Mob: characterTarget = Mob.getFromCache(msg.getTargetID()); if ((characterTarget == null) || characterTarget.isAlive()) { return; } if (pc.getLoc().distanceSquared2D(characterTarget.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)) { ErrorPopupMsg.sendErrorMsg(pc, "You are too far away to loot this corpse."); Logger.info(pc.getFirstName() + " tried looting at " + pc.getLoc().distance2D(characterTarget.getLoc()) + " distance."); if (!((Mob) characterTarget).isLootSync()) { ((Mob) characterTarget).setLootSync(true); WorldGrid.updateObject(characterTarget, pc); } return; } lwrm = new LootWindowResponseMsg(characterTarget.getObjectType().ordinal(), characterTarget.getObjectUUID(), characterTarget.getInventory()); break; case Corpse: corpseTarget = Corpse.getCorpse(msg.getTargetID()); if ((corpseTarget == null)) { return; } if (pc.getLoc().distanceSquared(corpseTarget.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)) { ErrorPopupMsg.sendErrorMsg(pc, "You are too far away to loot this corpse."); Logger.info(pc.getFirstName() + " tried looting at " + pc.getLoc().distance2D(characterTarget.getLoc()) + " distance."); return; } lwrm = new LootWindowResponseMsg(corpseTarget.getObjectType().ordinal(), msg.getTargetID(), corpseTarget.getInventory()); break; } if (lwrm == null) return; DispatchMessage.dispatchMsgToInterestArea(pc, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); Dispatch dispatch = Dispatch.borrow(pc, lwrm); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY); } private static void loot(LootMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter player = SessionManager.getPlayerCharacter(origin); if (player == null) return; if (!player.isAlive()) return; Item item = msg.getItem(); if (item == null) return; if (item.lootLock.tryLock()) { try { Item itemRet = null; // get current owner int targetType = msg.getTargetType(); int targetID = msg.getTargetID(); if (targetType == GameObjectType.PlayerCharacter.ordinal() || targetType == GameObjectType.Mob.ordinal() || targetType == GameObjectType.Corpse.ordinal()) { } else { //needed for getting contracts for some reason targetType = msg.getSourceID2(); targetID = msg.getUnknown01(); } //can't loot while flying if (player.getAltitude() > 0) return; AbstractCharacter tar = null; Corpse corpse = null; if (targetType == GameObjectType.PlayerCharacter.ordinal() || targetType == GameObjectType.Mob.ordinal()) { if (targetType == GameObjectType.PlayerCharacter.ordinal()) { tar = PlayerCharacter.getFromCache(targetID); if (tar == null) return; if (player.getObjectUUID() != tar.getObjectUUID() && ((PlayerCharacter) tar).isInSafeZone()) return; } else if (targetType == GameObjectType.NPC.ordinal()) tar = NPC.getFromCache(targetID); else if (targetType == GameObjectType.Mob.ordinal()) tar = Mob.getFromCache(targetID); if (tar == null) return; if (tar.equals(player)) { ErrorPopupMsg.sendErrorMsg(player, "Cannot loot this item."); return; } if (player.getLoc().distanceSquared2D(tar.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)) { ErrorPopupMsg.sendErrorMsg(player, "You are too far away to loot this corpse."); Logger.info(player.getFirstName() + " tried looting at " + player.getLoc().distance2D(tar.getLoc()) + " distance."); return; } //can't loot from someone who is alive. if (AbstractWorldObject.IsAbstractCharacter(tar)) { if (tar.isAlive()) return; // Logger.error("WorldServer.loot", "Looting from live player"); } if (!GroupManager.goldSplit(player, item, origin, tar)) { if (tar.charItemManager != null) { itemRet = tar.charItemManager.lootItemFromMe(item, player, origin); //Take equipment off mob if (tar.getObjectType() == GameObjectType.Mob && itemRet != null) { Mob mobTarget = (Mob) tar; if (item != null && item.getObjectType() == GameObjectType.MobLoot) { for (Item equip : mobTarget.charItemManager.equipped.values()) { TransferItemFromEquipToInventoryMsg back = new TransferItemFromEquipToInventoryMsg(mobTarget, equip.equipSlot); DispatchMessage.dispatchMsgToInterestArea(mobTarget, back, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); LootMsg lootMsg = new LootMsg(0, 0, tar.getObjectType().ordinal(), tar.getObjectUUID(), equip); Dispatch dispatch = Dispatch.borrow(player, lootMsg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); break; } } } } } } else if (targetType == GameObjectType.Corpse.ordinal()) { corpse = Corpse.getCorpse(targetID); if (corpse == null) return; if (player.getLoc().distanceSquared2D(corpse.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)) { ErrorPopupMsg.sendErrorMsg(player, "You are too far away to loot this corpse."); Logger.info(player.getFirstName() + " tried looting at " + player.getLoc().distance2D(corpse.getLoc()) + " distance."); return; } //can't loot other players in safe zone. if (corpse.getBelongsToType() == GameObjectType.PlayerCharacter.ordinal()) { if (player.getObjectUUID() == corpse.getBelongsToID()) itemRet = corpse.lootItem(item, player); else if (!GroupManager.goldSplit(player, item, origin, corpse)) { itemRet = corpse.lootItem(item, player); } if (itemRet == null) return; if (item.template.item_type.equals(engine.Enum.ItemType.GOLD)) { // this is done to prevent the temporary goldItem item // (from the mob) from appearing in player's inventory. // It also updates the goldItem quantity display UpdateGoldMsg updateTargetGold = null; if (corpse != null) updateTargetGold = new UpdateGoldMsg(corpse); updateTargetGold.configure(); DispatchMessage.dispatchMsgToInterestArea(corpse, updateTargetGold, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); UpdateGoldMsg ugm = new UpdateGoldMsg(player); ugm.configure(); Dispatch dispatch = Dispatch.borrow(player, ugm); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); // respond back loot message. Try sending to everyone. } else { DispatchMessage.dispatchMsgToInterestArea(corpse, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, true); //player.getCharItemManager().updateInventory(); } //TODO send group loot message if player is grouped and visible Group group = GroupManager.getGroup(player); if (group != null && group.getSplitGold() && (item.template.item_type.equals(engine.Enum.ItemType.GOLD) == false)) { String name = item.getName(); String text = player.getFirstName() + " has looted " + name + '.'; ChatManager.chatGroupInfoCanSee(player, text); } return; } } else return; if (itemRet == null) { return; } if (item.template.item_type.equals(engine.Enum.ItemType.GOLD)) { // this is done to prevent the temporary goldItem item // (from the mob) from appearing in player's inventory. // It also updates the goldItem quantity display UpdateGoldMsg updateTargetGold = null; if (tar != null) updateTargetGold = new UpdateGoldMsg(tar); else if (corpse != null) updateTargetGold = new UpdateGoldMsg(corpse); updateTargetGold.configure(); DispatchMessage.dispatchMsgToInterestArea(tar, updateTargetGold, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); UpdateGoldMsg ugm = new UpdateGoldMsg(player); ugm.configure(); Dispatch dispatch = Dispatch.borrow(player, ugm); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); // respond back loot message. Try sending to everyone. } else { msg.setSourceType1(0); msg.setSourceType2(0); msg.setSourceID1(0); msg.setSourceID2(0); Dispatch dispatch = Dispatch.borrow(player, msg); //DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY); DispatchMessage.dispatchMsgToInterestArea(tar, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, true); LootMsg newItemMsg = new LootMsg(GameObjectType.PlayerCharacter.ordinal(), player.getObjectUUID(), 0, 0, itemRet); dispatch = Dispatch.borrow(player, newItemMsg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY); //player.getCharItemManager().updateInventory(); } //TODO send group loot message if player is grouped and visible Group group = GroupManager.getGroup(player); if (group != null && group.getSplitGold() && (item.template.item_type.equals(engine.Enum.ItemType.GOLD) == false)) { String name = item.getName(); String text = player.getFirstName() + " has looted " + name + '.'; ChatManager.chatGroupInfoCanSee(player, text); } } catch (Exception e) { Logger.info(e.getMessage()); } finally { item.lootLock.unlock(); } } } // called when player types /show private static void show(ShowMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; int targetType = msg.getTargetType(); AbstractCharacter tar = null; if (targetType == GameObjectType.PlayerCharacter.ordinal()) tar = PlayerCharacter.getFromCache(msg.getTargetID()); else if (targetType == GameObjectType.NPC.ordinal()) tar = NPC.getFromCache(msg.getTargetID()); else if (targetType == GameObjectType.Mob.ordinal()) tar = Mob.getFromCache(msg.getTargetID()); if (tar == null || !tar.isAlive() || !tar.isActive()) return; msg.setUnknown01(pc.getLoc()); msg.setUnknown02(pc.getLoc()); msg.setRange01(pc.getRange()); msg.setUnknown03(tar.getLoc()); msg.setUnknown04(tar.getLoc()); msg.setRange01(tar.getRange()); Dispatch dispatch = Dispatch.borrow(pc, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } private static void ViewResourcesMessage(ViewResourcesMessage msg, ClientConnection origin) throws SQLException { PlayerCharacter player = SessionManager.getPlayerCharacter(origin); if (player == null) return; Guild guild = player.getGuild(); City city = guild.getOwnedCity(); if (city == null) return; Building warehouse = BuildingManager.getBuilding(city.getWarehouseBuildingID()); if (warehouse == null) return; ViewResourcesMessage vrm = new ViewResourcesMessage(player); vrm.setWarehouseBuilding(warehouse); vrm.setGuild(player.getGuild()); vrm.configure(); Dispatch dispatch = Dispatch.borrow(player, vrm); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } private static void randomRoll(RandomMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter source = origin.getPlayerCharacter(); if (source == null || !source.isAlive()) return; //2 second cooldown on random rolls long lastRandom = source.getTimeStamp("RandomRoll"); if (System.currentTimeMillis() - lastRandom < 2000) return; source.setTimeStamp("RandomRoll", System.currentTimeMillis()); //handle random roll int max = msg.getMax(); if (max > 0) msg.setRoll(ThreadLocalRandom.current().nextInt(max) + 1); else if (max < 0) { max = 1 - max; msg.setRoll((ThreadLocalRandom.current().nextInt(max) - max) + 1); } msg.setSourceType(source.getObjectType().ordinal()); msg.setSourceID(source.getObjectUUID()); //send to all in range DispatchMessage.dispatchMsgToInterestArea(source, msg, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, true); } //returns true if looted item is goldItem and is split. Otherwise returns false private static void stuck(ClientConnection origin) { PlayerCharacter sourcePlayer = origin.getPlayerCharacter(); if (sourcePlayer == null) return; if (sourcePlayer.getTimers().containsKey("Stuck")) return; StuckJob sj = new StuckJob(sourcePlayer); JobContainer jc = JobScheduler.getInstance().scheduleJob(sj, 10000); // Convert ConcurrentHashMap timers = sourcePlayer.getTimers(); if (timers != null) { if (timers.containsKey("Stuck")) { timers.get("Stuck").cancelJob(); timers.remove("Stuck"); } timers.put("Stuck", jc); } } private static void GuildTreeStatusMsg(GuildTreeStatusMsg msg, ClientConnection origin) throws SQLException { PlayerCharacter player = SessionManager.getPlayerCharacter(origin); Dispatch dispatch; if (player == null) return; if (origin.guildtreespam > System.currentTimeMillis()) { return; } origin.guildtreespam = System.currentTimeMillis() + 5000; Building b = BuildingManager.getBuildingFromCache(msg.getTargetID()); if (b == null) return; GuildTreeStatusMsg gtsm = new GuildTreeStatusMsg(b, player); gtsm.configure(); dispatch = Dispatch.borrow(player, gtsm); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } private static void openSellToNPCWindow(SellToNPCWindowMsg msg, ClientConnection origin) { PlayerCharacter sourcePlayer = SessionManager.getPlayerCharacter(origin); Dispatch dispatch; if (sourcePlayer == null) return; NPC npc = NPC.getFromCache(msg.getNPCID()); if (npc == null) return; // test within talking range if (sourcePlayer.getLoc().distanceSquared2D(npc.getLoc()) > MBServerStatics.NPC_TALK_RANGE * MBServerStatics.NPC_TALK_RANGE) { ErrorPopupMsg.sendErrorPopup(sourcePlayer, 14); return; } Contract con = npc.getContract(); if (con == null) return; float bargain = sourcePlayer.getBargain(); float profit = npc.getBuyPercent(sourcePlayer) + bargain; if (profit > 1) profit = 1; msg.setupOutput(); msg.setUnknown05(profit); msg.setUnknown06(500000); //TODO set goldItem on npc later msg.setItemType(con.getBuyItemType()); msg.setSkillTokens(con.getBuySkillToken()); msg.setUnknownArray(con.getBuyUnknownToken()); dispatch = Dispatch.borrow(sourcePlayer, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } private static void openBuyFromNPCWindow(BuyFromNPCWindowMsg msg, ClientConnection origin) { PlayerCharacter sourcePlayer = SessionManager.getPlayerCharacter(origin); Dispatch dispatch; if (sourcePlayer == null) return; NPC npc = NPC.getFromCache(msg.getNpcID()); if (npc == null) return; // test within talking range if (sourcePlayer.getLoc().distanceSquared2D(npc.getLoc()) > MBServerStatics.NPC_TALK_RANGE * MBServerStatics.NPC_TALK_RANGE) { ErrorPopupMsg.sendErrorPopup(sourcePlayer, 14); return; } dispatch = Dispatch.borrow(sourcePlayer, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } protected static void petAttack(PetAttackMsg msg, ClientConnection conn) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(conn); if (pc == null) return; Mob pet = pc.getPet(); if (pet == null) return; if (!pet.isAlive()) return; if ((pc.inSafeZone()) && (msg.getTargetType() == GameObjectType.PlayerCharacter.ordinal())) return; //CombatManager.setAttackTarget(msg, conn); if (msg.getTargetType() == GameObjectType.Building.ordinal()) { conn.getPlayerCharacter().getPet().setCombatTarget(PlayerCharacter.getPlayerCharacter(msg.getTargetID())); } switch (msg.getTargetType()) { case 53: //player character conn.getPlayerCharacter().getPet().setCombatTarget(PlayerCharacter.getPlayerCharacter(msg.getTargetID())); break; case 37://mob conn.getPlayerCharacter().getPet().setCombatTarget(Mob.getMob(msg.getTargetID())); break; case 8://mob conn.getPlayerCharacter().getPet().setCombatTarget(BuildingManager.getBuilding(msg.getTargetID())); break; } if (pet.getCombatTarget() == null) return; } protected static void petCmd(PetCmdMsg msg, ClientConnection conn) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(conn); if (pc == null) return; Mob pet = pc.getPet(); if (pet == null) return; if (!pet.isAlive()) return; //if (pet.state == STATE.Disabled) // return; int type = msg.getType(); if (type == 1) { //stop attack pet.setCombatTarget(null); pc.setCombat(false); } else if (type == 2) { //dismiss pet.dismiss(); pc.dismissPet(); if (pet.isAlive()) WorldGrid.updateObject(pet); } else if (type == 3) //toggle assist pet.toggleAssist(); else if (type == 5) { //rest boolean sit = (!(pet.isSit())); pet.setSit(sit); // cancel effects that break on sit if (pet.isSit()) pet.cancelOnSit(); UpdateStateMsg rwss = new UpdateStateMsg(); rwss.setPlayer(pet); DispatchMessage.sendToAllInRange(pet, rwss); } } //Handle RepairObject Window and RepairObject Requests protected static void HandlePromptRecall(PromptRecallMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter player = SessionManager.getPlayerCharacter(origin); boolean recallAccepted; if (player == null) return; boolean confirmed = msg.getConfirmed(); if (confirmed == true) { long timeElapsed = System.currentTimeMillis() - player.getTimeStamp("PromptRecall"); //send fail message recallAccepted = timeElapsed < 15000; } else recallAccepted = false; if (recallAccepted == true) { //handle recall long type = player.getTimeStamp("LastRecallType"); if (type == 1) { //recall to bind player.teleport(player.getBindLoc()); player.setSafeMode(); } else { //recall to rg float dist = 9999999999f; Building rg = null; Vector3fImmutable rgLoc; for (Runegate runegate : Runegate._runegates.values()) { rgLoc = runegate.gateBuilding.getLoc(); float distanceSquaredToRunegate = player.getLoc().distanceSquared2D(rgLoc); if (distanceSquaredToRunegate < sqr(dist)) rg = runegate.gateBuilding; } //nearest runegate found. teleport characterTarget if (rg != null) { player.teleport(rg.getLoc()); player.setSafeMode(); } } } } @Override public boolean handleClientMsg(ClientNetMsg msg) { if (msg == null) { Logger.error("handleClientMsg", "Recieved null msg. Returning."); return false; } ClientConnection origin; Protocol protocolMsg = Protocol.NONE; Session s; try { // Try registered opcodes first as we take a hatchet to this GodObject AbstractClientMsgHandler msgHandler = msg.getProtocolMsg().handler; if (msgHandler != null) return msgHandler.handleNetMsg(msg); // Any remaining opcodes fall through and are routed // through this ungodly switch of doom. origin = (ClientConnection) msg.getOrigin(); s = SessionManager.getSession(origin); protocolMsg = msg.getProtocolMsg(); switch (protocolMsg) { case SETSELECTEDOBECT: ClientMessagePump.targetObject((TargetObjectMsg) msg, origin); break; /* * Chat */ // Simplify by fall through. Route in ChatManager case CHATSAY: case CHATSHOUT: case CHATTELL: case CHATGUILD: case CHATGROUP: case CHATPVP: case CHATIC: case CHATCITY: case CHATINFO: case SYSTEMBROADCASTCHANNEL: case CHATCSR: case SYSTEMCHANNEL: case GLOBALCHANNELMESSAGE: case LEADERCHANNELMESSAGE: ChatManager.handleChatMsg(s, (AbstractChatMsg) msg); break; case UPDATESTATE: UpdateStateMsg rwss = (UpdateStateMsg) msg; runWalkSitStand(rwss, origin); break; case ACTIVATECHARTER: UseCharterMsg ucm = (UseCharterMsg) msg; ucm.setUnknown02(1); ucm.configure(); Dispatch dispatch = Dispatch.borrow(origin.getPlayerCharacter(), ucm); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); break; case CHECKUNIQUEGUILD: break; case CANCELGUILDCREATION: break; case LEAVEREQUEST: origin.disconnect(); break; case POWER: PowersManager.usePower((PerformActionMsg) msg, origin, false); break; case READYTOENTER: break; case OPENVAULT: break; case WHOREQUEST: WhoRequest((WhoRequestMsg) msg, origin); break; case CLIENTADMINCOMMAND: ChatManager.HandleClientAdminCmd((ClientAdminCommandMsg) msg, origin); break; case SOCIALCHANNEL: social((SocialMsg) msg, origin); break; case COMBATMODE: CombatManager.toggleCombat(((ToggleCombatMsg) msg).toggleCombat(), origin); break; case ARCCOMBATMODEATTACKING: CombatManager.toggleCombat(((SetCombatModeMsg) msg).getToggle(), origin); break; case MODIFYGUILDSTATE: ToggleLfgRecruitingMsg tlrm = (ToggleLfgRecruitingMsg) msg; toggleLfgRecruiting(tlrm, origin); break; case TOGGLESITSTAND: ToggleSitStandMsg tssm = (ToggleSitStandMsg) msg; toggleSitStand(tssm, origin); break; case GUILDTREESTATUS: GuildTreeStatusMsg((GuildTreeStatusMsg) msg, origin); break; case IGNORE: ((IgnoreMsg) msg).handleRequest(origin); break; case DELETEOBJECT: DeleteItem((DeleteItemMsg) msg, origin); break; case VIEWRESOURCES: ViewResourcesMessage((ViewResourcesMessage) msg, origin); break; case RAISEATTR: modifyStat((ModifyStatMsg) msg, origin); break; case COSTTOOPENBANK: ackBankWindowOpened((AckBankWindowOpenedMsg) msg, origin); break; case RESETAFTERDEATH: respawn((RespawnMsg) msg, origin); break; case REQUESTCONTENTS: lootWindowRequest((LootWindowRequestMsg) msg, origin); break; case MOVEOBJECTTOCONTAINER: loot((LootMsg) msg, origin); break; case SHOWCOMBATINFO: show((ShowMsg) msg, origin); break; case REQUESTTOTRADE: TradeManager.tradeRequest((TradeRequestMsg) msg, origin); break; case REQUESTTRADEOK: TradeManager.acceptTradeRequest((AcceptTradeRequestMsg) msg, origin); break; case REQUESTTRADECANCEL: TradeManager.rejectTradeRequest((RejectTradeRequestMsg) msg, origin); break; case TRADEADDOBJECT: TradeManager.addItemToTradeWindow((AddItemToTradeWindowMsg) msg, origin); break; case TRADEADDGOLD: TradeManager.addGoldToTradeWindow((AddGoldToTradeWindowMsg) msg, origin); break; case TRADECONFIRM: TradeManager.commitToTrade((CommitToTradeMsg) msg, origin); break; case TRADEUNCONFIRM: TradeManager.uncommitToTrade((UncommitToTradeMsg) msg, origin); break; case TRADECLOSE: TradeManager.closeTradeWindow((CloseTradeWindowMsg) msg, origin); break; case ARCREQUESTTRADEBUSY: TradeManager.invalidTradeRequest((InvalidTradeRequestMsg) msg); break; case VENDORDIALOG: VendorDialogMsg.replyDialog((VendorDialogMsg) msg, origin); break; case SHOPLIST: openBuyFromNPCWindow((BuyFromNPCWindowMsg) msg, origin); break; case SHOPINFO: openSellToNPCWindow((SellToNPCWindowMsg) msg, origin); break; case TRAINERLIST: WorldServer.trainerInfo((TrainerInfoMsg) msg, origin); break; case ARCUNTRAINLIST: WorldServer.refinerScreen((RefinerScreenMsg) msg, origin); break; case TRAINSKILL: TrainMsg.train((TrainMsg) msg, origin); break; case ARCUNTRAINABILITY: RefineMsg.refine((RefineMsg) msg, origin); break; case POWERTARGNAME: PowersManager.summon((SendSummonsRequestMsg) msg, origin); break; case ARCSUMMON: PowersManager.recvSummon((RecvSummonsRequestMsg) msg, origin); break; case ARCTRACKINGLIST: PowersManager.trackWindow((TrackWindowMsg) msg, origin); break; case STUCK: stuck(origin); break; case RANDOM: ClientMessagePump.randomRoll((RandomMsg) msg, origin); break; case ARCPETATTACK: petAttack((PetAttackMsg) msg, origin); break; case ARCPETCMD: petCmd((PetCmdMsg) msg, origin); break; case MANAGENPC: ManageNPCCmd((ManageNPCMsg) msg, origin); break; case ARCPROMPTRECALL: HandlePromptRecall((PromptRecallMsg) msg, origin); break; case CHANNELMUTE: break; case KEEPALIVESERVERCLIENT: break; case UNKNOWN: break; case CONFIRMPROMOTE: break; default: String ocHex = StringUtils.toHexString(protocolMsg.opcode); Logger.error("Cannot handle Opcode: " + ocHex + " " + protocolMsg.name()); return false; } } catch (MsgSendException | SQLException e) { Logger.error("handler for " + protocolMsg + " failed: " + e); return false; } return true; } //TODO what is this used for? private void ManageNPCCmd(ManageNPCMsg msg, ClientConnection origin) { } //call this if the transfer fails server side to kick the item back to inventory from equip private void forceTransferFromInventoryToEquip(TransferItemFromEquipToInventoryMsg msg, ClientConnection origin, String reason) { //TODO add this later //PATCHED CODEZZ } }