forked from MagicBane/Server
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1225 lines
45 KiB
1225 lines
45 KiB
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . |
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· |
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ |
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ |
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ |
|
// 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<String, JobContainer> 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 |
|
} |
|
|
|
}
|
|
|