Browse Source

Merge remote-tracking branch 'refs/remotes/origin/feature-workorder2.8' into magicbox-1.5.2.1

combat-2
MagicBot 8 months ago
parent
commit
111ba02289
  1. 17
      src/engine/InterestManagement/RealmMap.java
  2. 8
      src/engine/InterestManagement/Terrain.java
  3. 4
      src/engine/db/handlers/dbContractHandler.java
  4. 96
      src/engine/db/handlers/dbEffectsResourceCostHandler.java
  5. 11
      src/engine/db/handlers/dbItemHandler.java
  6. 116
      src/engine/db/handlers/dbNPCHandler.java
  7. 82
      src/engine/db/handlers/dbWarehouseHandler.java
  8. 37
      src/engine/devcmd/cmds/CreateItemCmd.java
  9. 310
      src/engine/gameManager/CombatManager.java
  10. 18
      src/engine/gameManager/ConfigManager.java
  11. 408
      src/engine/gameManager/ForgeManager.java
  12. 25
      src/engine/gameManager/ItemManager.java
  13. 29
      src/engine/gameManager/LootManager.java
  14. 14
      src/engine/gameManager/NPCManager.java
  15. 1
      src/engine/gameManager/PowersManager.java
  16. 21
      src/engine/gameManager/SimulationManager.java
  17. 255
      src/engine/loot/WorkOrder.java
  18. 20
      src/engine/mbEnums.java
  19. 125
      src/engine/mobileAI/MobAI.java
  20. 2
      src/engine/mobileAI/Threads/MobAIThread.java
  21. 8
      src/engine/mobileAI/Threads/Respawner.java
  22. 1
      src/engine/net/AbstractConnection.java
  23. 1
      src/engine/net/AbstractNetMsg.java
  24. 1
      src/engine/net/CheckNetMsgFactoryJob.java
  25. 135
      src/engine/net/ItemProductionManager.java
  26. 86
      src/engine/net/ItemQueue.java
  27. 94
      src/engine/net/MessageDispatcher.java
  28. 1
      src/engine/net/NetMsgFactory.java
  29. 2
      src/engine/net/NetMsgStat.java
  30. 26
      src/engine/net/Protocol.java
  31. 1
      src/engine/net/client/ClientConnection.java
  32. 2
      src/engine/net/client/handlers/AbstractChatMsgHandler.java
  33. 7
      src/engine/net/client/handlers/DestroyBuildingHandler.java
  34. 450
      src/engine/net/client/handlers/ItemProductionMsgHandler.java
  35. 55
      src/engine/net/client/handlers/ObjectActionMsgHandler.java
  36. 2
      src/engine/net/client/handlers/PlaceAssetMsgHandler.java
  37. 12
      src/engine/net/client/handlers/ViewResourcesMsgHandler.java
  38. 2
      src/engine/net/client/msg/AbandonAssetMsg.java
  39. 2
      src/engine/net/client/msg/AcceptFriendMsg.java
  40. 2
      src/engine/net/client/msg/AcceptTradeRequestMsg.java
  41. 6
      src/engine/net/client/msg/ActivateNPCMessage.java
  42. 2
      src/engine/net/client/msg/AddFriendMessage.java
  43. 2
      src/engine/net/client/msg/AddGoldToTradeWindowMsg.java
  44. 2
      src/engine/net/client/msg/AddItemToTradeWindowMsg.java
  45. 2
      src/engine/net/client/msg/AllianceChangeMsg.java
  46. 2
      src/engine/net/client/msg/AllyEnemyListMsg.java
  47. 2
      src/engine/net/client/msg/ApplyBuildingEffectMsg.java
  48. 2
      src/engine/net/client/msg/ApplyEffectMsg.java
  49. 1
      src/engine/net/client/msg/ApplyRuneMsg.java
  50. 2
      src/engine/net/client/msg/ArcLoginNotifyMsg.java
  51. 2
      src/engine/net/client/msg/ArcMineChangeProductionMsg.java
  52. 2
      src/engine/net/client/msg/ArcMineWindowAvailableTimeMsg.java
  53. 2
      src/engine/net/client/msg/ArcMineWindowChangeMsg.java
  54. 2
      src/engine/net/client/msg/ArcOwnedMinesListMsg.java
  55. 2
      src/engine/net/client/msg/ArcSiegeSpireMsg.java
  56. 2
      src/engine/net/client/msg/ArcViewAssetTransactionsMsg.java
  57. 2
      src/engine/net/client/msg/AssetSupportMsg.java
  58. 2
      src/engine/net/client/msg/AttackCmdMsg.java
  59. 2
      src/engine/net/client/msg/ChangeAltitudeMsg.java
  60. 2
      src/engine/net/client/msg/ChangeGuildLeaderMsg.java
  61. 2
      src/engine/net/client/msg/ChatFilterMsg.java
  62. 2
      src/engine/net/client/msg/CityAssetMsg.java
  63. 6
      src/engine/net/client/msg/CityChoiceMsg.java
  64. 6
      src/engine/net/client/msg/CityDataMsg.java
  65. 2
      src/engine/net/client/msg/CityZoneMsg.java
  66. 2
      src/engine/net/client/msg/ClaimAssetMsg.java
  67. 2
      src/engine/net/client/msg/ClaimGuildTreeMsg.java
  68. 6
      src/engine/net/client/msg/ClientNetMsg.java
  69. 2
      src/engine/net/client/msg/CloseTradeWindowMsg.java
  70. 2
      src/engine/net/client/msg/CommitToTradeMsg.java
  71. 2
      src/engine/net/client/msg/ConfirmPromoteMsg.java
  72. 2
      src/engine/net/client/msg/CostOpenBankMsg.java
  73. 2
      src/engine/net/client/msg/DeclineFriendMsg.java
  74. 2
      src/engine/net/client/msg/DeleteItemMsg.java
  75. 2
      src/engine/net/client/msg/DestroyBuildingMsg.java
  76. 2
      src/engine/net/client/msg/DoorTryOpenMsg.java
  77. 2
      src/engine/net/client/msg/DropGoldMsg.java
  78. 2
      src/engine/net/client/msg/EnterWorldReceivedMsg.java
  79. 1
      src/engine/net/client/msg/ErrorPopupMsg.java
  80. 2
      src/engine/net/client/msg/FriendRequestMsg.java
  81. 4
      src/engine/net/client/msg/FurnitureMsg.java
  82. 2
      src/engine/net/client/msg/GoldFromVaultMsg.java
  83. 4
      src/engine/net/client/msg/GoldToVaultMsg.java
  84. 2
      src/engine/net/client/msg/GrantExperienceMsg.java
  85. 2
      src/engine/net/client/msg/GuildTreeStatusMsg.java
  86. 2
      src/engine/net/client/msg/HirelingServiceMsg.java
  87. 2
      src/engine/net/client/msg/HotzoneChangeMsg.java
  88. 2
      src/engine/net/client/msg/IgnoreListMsg.java
  89. 2
      src/engine/net/client/msg/IgnoreMsg.java
  90. 2
      src/engine/net/client/msg/InvalidTradeRequestMsg.java
  91. 2
      src/engine/net/client/msg/ItemEffectMsg.java
  92. 2
      src/engine/net/client/msg/ItemFromVaultMsg.java
  93. 2
      src/engine/net/client/msg/ItemHealthUpdateMsg.java
  94. 282
      src/engine/net/client/msg/ItemProductionMsg.java
  95. 2
      src/engine/net/client/msg/ItemToVaultMsg.java
  96. 2
      src/engine/net/client/msg/KeepAliveServerClientMsg.java
  97. 2
      src/engine/net/client/msg/LeaderboardMessage.java
  98. 2
      src/engine/net/client/msg/LeaveWorldMsg.java
  99. 6
      src/engine/net/client/msg/LoadCharacterMsg.java
  100. 6
      src/engine/net/client/msg/LoadStructureMsg.java
  101. Some files were not shown because too many files have changed in this diff Show More

17
src/engine/InterestManagement/RealmMap.java

@ -8,10 +8,6 @@
package engine.InterestManagement; package engine.InterestManagement;
/* This class is the main interface for Magicbane's
* Interest management facilities.
*/
import engine.math.Vector3fImmutable; import engine.math.Vector3fImmutable;
import engine.mbEnums; import engine.mbEnums;
import engine.net.Dispatch; import engine.net.Dispatch;
@ -31,10 +27,17 @@ import static engine.objects.Realm.getRealm;
public enum RealmMap { public enum RealmMap {
REALM_MAP; // MB Dev Notes:
// This class loads and caches realm maps used by each
// map set for its realm overlay. The RealmMap loaded is
// controlled by config entry MB_WORLD_REALMMAP
//
// Unlike a Heightmap this is a just color lookup; identical to
// the old image maps used in 90s web technology.
//
// Realm Map images are stored on disk in /mb.data/realmmaps/
// Spatial hashmap. Used for determining which Realm REALM_MAP;
// a player is currently located within.
private static final HashMap<Color, Integer> _rgbToIDMap = new HashMap<>(); private static final HashMap<Color, Integer> _rgbToIDMap = new HashMap<>();
public static int[][] _realmImageMap; public static int[][] _realmImageMap;

8
src/engine/InterestManagement/Terrain.java

@ -18,6 +18,14 @@ import java.util.HashMap;
import static java.lang.Math.PI; import static java.lang.Math.PI;
// MB Dev Notes:
// The Terrain class handles lookups into the Heightmap data.
// It supports all current maps along with the differences in
// their parenting configuration.
//
// Heightmap images are stored on disk in /mb.data/heightmaps/
public class Terrain { public class Terrain {
public static final HashMap<Integer, short[][]> _heightmap_pixel_cache = new HashMap<>(); public static final HashMap<Integer, short[][]> _heightmap_pixel_cache = new HashMap<>();
public short[][] terrain_pixel_data; public short[][] terrain_pixel_data;

4
src/engine/db/handlers/dbContractHandler.java

@ -10,10 +10,10 @@
package engine.db.handlers; package engine.db.handlers;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.gameManager.ItemManager;
import engine.mbEnums; import engine.mbEnums;
import engine.objects.Contract; import engine.objects.Contract;
import engine.objects.Item; import engine.objects.Item;
import engine.objects.MobLoot;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.Connection; import java.sql.Connection;
@ -66,7 +66,7 @@ public class dbContractHandler extends dbHandlerBase {
int templateID = rs.getInt("templateID"); int templateID = rs.getInt("templateID");
Item item = new Item(templateID); Item item = new Item(templateID);
item.objectUUID = MobLoot.lastNegativeID.decrementAndGet(); item.objectUUID = ItemManager.lastNegativeID.decrementAndGet();
contract.getSellInventory().add(item); contract.getSellInventory().add(item);
} }

96
src/engine/db/handlers/dbEffectsResourceCostHandler.java

@ -10,8 +10,10 @@
package engine.db.handlers; package engine.db.handlers;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.gameManager.PowersManager;
import engine.mbEnums; import engine.mbEnums;
import engine.objects.EffectsResourceCosts; import engine.objects.EffectsResourceCosts;
import org.json.JSONObject;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.Connection; import java.sql.Connection;
@ -19,6 +21,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
public class dbEffectsResourceCostHandler extends dbHandlerBase { public class dbEffectsResourceCostHandler extends dbHandlerBase {
@ -27,6 +30,99 @@ public class dbEffectsResourceCostHandler extends dbHandlerBase {
this.localObjectType = mbEnums.GameObjectType.valueOf(this.localClass.getSimpleName()); this.localObjectType = mbEnums.GameObjectType.valueOf(this.localClass.getSimpleName());
} }
public void GENERATE_COST_DATA() {
ArrayList<String> effectList = GET_EFFECTS_WITH_COST();
for (String effectID : effectList) {
JSONObject costMap = GET_EFFECT_COSTMAP(effectID);
WRITE_COSTMAP(effectID, costMap);
}
}
public JSONObject GET_EFFECT_COSTMAP(String effectID) {
HashMap<mbEnums.ResourceType, Integer> costMap = new HashMap<>();
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_power_effectcost` WHERE `IDString` = ?")) {
preparedStatement.setString(1, effectID);
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
mbEnums.ResourceType resourceType = mbEnums.ResourceType.resourceLookup.get(rs.getInt("resource"));
int value = rs.getInt("amount");
costMap.put(resourceType, value);
}
} catch (SQLException e) {
Logger.error(e);
}
return new JSONObject(costMap);
}
public ArrayList<String> GET_EFFECTS_WITH_COST() {
ArrayList<String> effectList = new ArrayList<>();
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT DISTINCT `IDString` FROM `static_power_effectcost`")) {
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
effectList.add(rs.getString("IdString"));
}
} catch (SQLException e) {
Logger.error(e);
}
return effectList;
}
public boolean WRITE_COSTMAP(String effectID, JSONObject costmap) {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO `static_effect_costmaps` (`effectID`, `costMap`) VALUES (?, ?) " +
"ON DUPLICATE KEY UPDATE `costmap` = VALUES(`costmap`)")) {
preparedStatement.setString(1, effectID);
preparedStatement.setString(2, costmap.toString());
return (preparedStatement.executeUpdate() > 0);
} catch (SQLException e) {
Logger.error(e);
}
return false;
}
public void LOAD_ALL_COSTMAPS() {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_effect_costmaps`")) {
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
String effectID = rs.getString("effectID");
String costString = rs.getString("costmap");
JSONObject costJSON = new JSONObject(costString);
HashMap<mbEnums.ResourceType, Integer> costmap = new HashMap<>();
for (String key : costJSON.keySet()) {
int value = costJSON.getInt(key);
costmap.put(mbEnums.ResourceType.valueOf(key), value);
}
PowersManager._effect_costMaps.put(effectID, costmap);
}
} catch (SQLException e) {
Logger.error(e);
}
}
public ArrayList<EffectsResourceCosts> GET_ALL_EFFECT_RESOURCES(String idString) { public ArrayList<EffectsResourceCosts> GET_ALL_EFFECT_RESOURCES(String idString) {
ArrayList<EffectsResourceCosts> effectsResourceCosts = new ArrayList<>(); ArrayList<EffectsResourceCosts> effectsResourceCosts = new ArrayList<>();

11
src/engine/db/handlers/dbItemHandler.java

@ -17,8 +17,7 @@ import engine.objects.AbstractCharacter;
import engine.objects.CharacterItemManager; import engine.objects.CharacterItemManager;
import engine.objects.Item; import engine.objects.Item;
import engine.objects.ItemTemplate; import engine.objects.ItemTemplate;
import org.json.simple.JSONObject; import org.json.JSONObject;
import org.json.simple.parser.JSONParser;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.Connection; import java.sql.Connection;
@ -26,6 +25,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -179,7 +179,7 @@ public class dbItemHandler extends dbHandlerBase {
public void LOAD_ITEM_TEMPLATES() { public void LOAD_ITEM_TEMPLATES() {
JSONParser jsonParser = new JSONParser(); HashMap<ItemType, Integer> templateTCountMap = new HashMap<>();
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_item_templates`;"); PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_item_templates`;");
@ -187,12 +187,15 @@ public class dbItemHandler extends dbHandlerBase {
while (rs.next()) { while (rs.next()) {
int templateID = rs.getInt("id"); int templateID = rs.getInt("id");
JSONObject jsonObject = (JSONObject) jsonParser.parse(rs.getString("template")); JSONObject jsonObject = new JSONObject(rs.getString("template"));
ItemTemplate itemTemplate = new ItemTemplate(jsonObject); ItemTemplate itemTemplate = new ItemTemplate(jsonObject);
itemTemplate.template_id = templateID; itemTemplate.template_id = templateID;
ItemTemplate.templates.put(templateID, itemTemplate); ItemTemplate.templates.put(templateID, itemTemplate);
templateTCountMap.merge(itemTemplate.item_type, 1, Integer::sum);
} }
Logger.info(templateTCountMap.toString());
} catch (Exception e) { } catch (Exception e) {
Logger.error(e); Logger.error(e);
} }

116
src/engine/db/handlers/dbNPCHandler.java

@ -9,13 +9,12 @@
package engine.db.handlers; package engine.db.handlers;
import engine.mbEnums;
import engine.mbEnums.ProfitType;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.math.Vector3fImmutable; import engine.math.Vector3fImmutable;
import engine.mbEnums;
import engine.mbEnums.ProfitType;
import engine.objects.NPC; import engine.objects.NPC;
import engine.objects.NPCProfits; import engine.objects.NPCProfits;
import engine.objects.ProducedItem;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@ -346,117 +345,6 @@ public class dbNPCHandler extends dbHandlerBase {
+ NPC._pirateNames.size() + " mobBases"); + NPC._pirateNames.size() + " mobBases");
} }
public boolean ADD_TO_PRODUCTION_LIST(final long ID, final long npcUID, final long templateID, DateTime dateTime, String prefix, String suffix, String name, boolean isRandom, int playerID) {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO `dyn_npc_production` (`ID`,`npcUID`, `templateID`,`dateToUpgrade`, `isRandom`, `prefix`, `suffix`, `name`,`playerID`) VALUES (?,?,?,?,?,?,?,?,?)")) {
preparedStatement.setLong(1, ID);
preparedStatement.setLong(2, npcUID);
preparedStatement.setLong(3, templateID);
preparedStatement.setTimestamp(4, new java.sql.Timestamp(dateTime.getMillis()));
preparedStatement.setBoolean(5, isRandom);
preparedStatement.setString(6, prefix);
preparedStatement.setString(7, suffix);
preparedStatement.setString(8, name);
preparedStatement.setInt(9, playerID);
return (preparedStatement.executeUpdate() > 0);
} catch (SQLException e) {
Logger.error(e);
return false;
}
}
public boolean REMOVE_FROM_PRODUCTION_LIST(final long ID, final long npcUID) {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("DELETE FROM `dyn_npc_production` WHERE `ID`=? AND `npcUID`=?;")) {
preparedStatement.setLong(1, ID);
preparedStatement.setLong(2, npcUID);
return (preparedStatement.executeUpdate() > 0);
} catch (SQLException e) {
Logger.error(e);
return false;
}
}
public boolean UPDATE_ITEM_TO_INVENTORY(final long ID, final long npcUID) {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE `dyn_npc_production` SET `inForge`=? WHERE `ID`=? AND `npcUID`=?;")) {
preparedStatement.setByte(1, (byte) 0);
preparedStatement.setLong(2, ID);
preparedStatement.setLong(3, npcUID);
return (preparedStatement.executeUpdate() > 0);
} catch (SQLException e) {
Logger.error(e);
return false;
}
}
public boolean UPDATE_ITEM_PRICE(final long ID, final long npcUID, int value) {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE `dyn_npc_production` SET `value`=? WHERE `ID`=? AND `npcUID`=?;")) {
preparedStatement.setInt(1, value);
preparedStatement.setLong(2, ID);
preparedStatement.setLong(3, npcUID);
return (preparedStatement.executeUpdate() > 0);
} catch (SQLException e) {
Logger.error(e);
return false;
}
}
public boolean UPDATE_ITEM_ID(final long ID, final long npcUID, final long value) {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE `dyn_npc_production` SET `ID`=? WHERE `ID`=? AND `npcUID`=? LIMIT 1;")) {
preparedStatement.setLong(1, value);
preparedStatement.setLong(2, ID);
preparedStatement.setLong(3, npcUID);
return (preparedStatement.executeUpdate() > 0);
} catch (SQLException e) {
Logger.error(e);
return false;
}
}
public void LOAD_ALL_ITEMS_TO_PRODUCE(NPC npc) {
if (npc == null)
return;
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `dyn_npc_production` WHERE `npcUID` = ?")) {
preparedStatement.setInt(1, npc.getObjectUUID());
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
ProducedItem producedItem = new ProducedItem(rs);
npc.forgedItems.add(producedItem);
}
} catch (SQLException e) {
Logger.error(e);
}
}
public boolean UPDATE_PROFITS(NPC npc, ProfitType profitType, float value) { public boolean UPDATE_PROFITS(NPC npc, ProfitType profitType, float value) {
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();

82
src/engine/db/handlers/dbWarehouseHandler.java

@ -9,19 +9,20 @@
package engine.db.handlers; package engine.db.handlers;
import engine.gameManager.DbManager;
import engine.gameManager.ForgeManager;
import engine.loot.WorkOrder;
import engine.mbEnums; import engine.mbEnums;
import engine.mbEnums.GameObjectType; import engine.mbEnums.GameObjectType;
import engine.mbEnums.TransactionType; import engine.mbEnums.TransactionType;
import engine.gameManager.DbManager;
import engine.objects.Building; import engine.objects.Building;
import engine.objects.City; import engine.objects.City;
import engine.objects.Transaction; import engine.objects.Transaction;
import engine.objects.Warehouse; import engine.objects.Warehouse;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.json.simple.JSONArray; import org.json.JSONArray;
import org.json.simple.JSONObject; import org.json.JSONObject;
import org.json.simple.parser.JSONParser;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.Connection; import java.sql.Connection;
@ -106,7 +107,7 @@ public class dbWarehouseHandler extends dbHandlerBase {
JSONArray locks = new JSONArray(); JSONArray locks = new JSONArray();
for (mbEnums.ResourceType resource : warehouse.locked) for (mbEnums.ResourceType resource : warehouse.locked)
locks.add(resource.name()); locks.put(resource.name());
warehouseJSON.put("locked", locks); warehouseJSON.put("locked", locks);
@ -127,15 +128,13 @@ public class dbWarehouseHandler extends dbHandlerBase {
public void LOAD_WAREHOUSES() { public void LOAD_WAREHOUSES() {
JSONParser jsonParser = new JSONParser();
try (Connection connection = DbManager.getConnection(); try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `dyn_warehouse`;"); PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `dyn_warehouse`;");
ResultSet rs = preparedStatement.executeQuery()) { ResultSet rs = preparedStatement.executeQuery()) {
while (rs.next()) { while (rs.next()) {
int cityUID = rs.getInt("cityUUID"); int cityUID = rs.getInt("cityUUID");
JSONObject jsonObject = (JSONObject) jsonParser.parse(rs.getString("warehouse")); JSONObject jsonObject = new JSONObject(rs.getString("warehouse"));
City city = City.getCity(cityUID); City city = City.getCity(cityUID);
city.warehouse = new Warehouse(jsonObject); city.warehouse = new Warehouse(jsonObject);
city.warehouse.city = city; city.warehouse.city = city;
@ -154,4 +153,71 @@ public class dbWarehouseHandler extends dbHandlerBase {
Logger.error(e); Logger.error(e);
} }
} }
public boolean WRITE_WORKORDER(WorkOrder workOrder) {
JSONObject warehouseJSON = WorkOrder.toJson(workOrder);
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO `dyn_workorders` (`workorderID`, `workorder`) VALUES (?, ?) " +
"ON DUPLICATE KEY UPDATE `workorder` = VALUES(`workorder`)")) {
preparedStatement.setInt(1, workOrder.workOrderID);
preparedStatement.setString(2, warehouseJSON.toString());
return (preparedStatement.executeUpdate() > 0);
} catch (SQLException e) {
Logger.error(e);
}
return false;
}
public void DELETE_WORKORDER(WorkOrder workOrder) {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("DELETE FROM `dyn_workorders` WHERE `workorderID` = ?;")) {
preparedStatement.setInt(1, workOrder.workOrderID);
preparedStatement.executeUpdate();
} catch (SQLException e) {
Logger.error(e);
}
}
public void LOAD_WORKORDERS() {
ArrayList<WorkOrder> submitList = new ArrayList<>();
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `dyn_workorders`;");
ResultSet rs = preparedStatement.executeQuery()) {
while (rs.next()) {
JSONObject jsonObject = new JSONObject(rs.getString("workorder"));
WorkOrder workOrder = new WorkOrder(jsonObject);
submitList.add(workOrder);
}
} catch (Exception e) {
Logger.error(e);
}
// Remove the old workOrder records
for (WorkOrder workOrder : submitList)
DbManager.WarehouseQueries.DELETE_WORKORDER(workOrder);
// Submit the new workOrders to the ForgeManager
for (WorkOrder workOrder : submitList) {
workOrder.workOrderID = ForgeManager.workOrderCounter.incrementAndGet();
ForgeManager.vendorWorkOrderLookup.get(workOrder.vendor).add(workOrder);
// If workorder is not yet complete process it
if (workOrder.runCompleted == false)
ForgeManager.forge.add(workOrder);
}
}
} }

37
src/engine/devcmd/cmds/CreateItemCmd.java

@ -10,9 +10,14 @@
package engine.devcmd.cmds; package engine.devcmd.cmds;
import engine.devcmd.AbstractDevCmd; import engine.devcmd.AbstractDevCmd;
import engine.gameManager.ChatManager;
import engine.gameManager.DbManager;
import engine.mbEnums;
import engine.objects.AbstractGameObject; import engine.objects.AbstractGameObject;
import engine.objects.ItemFactory; import engine.objects.Item;
import engine.objects.ItemTemplate;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import org.pmw.tinylog.Logger;
/** /**
* @author Eighty * @author Eighty
@ -24,22 +29,46 @@ public class CreateItemCmd extends AbstractDevCmd {
} }
@Override @Override
protected void _doCmd(PlayerCharacter pc, String[] words, protected void _doCmd(PlayerCharacter playerCharacter, String[] words,
AbstractGameObject target) { AbstractGameObject target) {
if (words.length < 2) { if (words.length < 2) {
this.sendUsage(pc); this.sendUsage(playerCharacter);
return; return;
} }
int templateID = Integer.parseInt(words[0]); int templateID = Integer.parseInt(words[0]);
ItemTemplate template = ItemTemplate.templates.get(templateID);
if (template == null) {
ChatManager.chatSystemInfo(playerCharacter, "No such template found.");
return;
}
int size = 1; int size = 1;
if (words.length == 2) if (words.length == 2)
size = Integer.parseInt(words[1]); size = Integer.parseInt(words[1]);
ItemFactory.fillInventory(pc, templateID, size); for (int i = 0; i < size; i++) {
if (!playerCharacter.charItemManager.hasRoomInventory(template.item_wt)) {
ChatManager.chatSystemInfo(playerCharacter, "You are encumbered!.");
break;
}
Item item = new Item(templateID);
item.ownerID = playerCharacter.getObjectUUID();
item.ownerType = mbEnums.OwnerType.PlayerCharacter;
item.containerType = mbEnums.ItemContainerType.INVENTORY;
try {
item = DbManager.ItemQueries.PERSIST(item);
playerCharacter.charItemManager.addItemToInventory(item);
} catch (Exception e) {
Logger.error(e);
}
}
playerCharacter.charItemManager.updateInventory();
} }
@Override @Override

310
src/engine/gameManager/CombatManager.java

@ -23,6 +23,8 @@ import engine.powers.effectmodifiers.AbstractEffectModifier;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@ -38,9 +40,13 @@ public enum CombatManager {
if (attacker == null || target == null || !attacker.isAlive() || !target.isAlive()) if (attacker == null || target == null || !attacker.isAlive() || !target.isAlive())
return; return;
if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob))
if (((Mob) attacker).nextAttackTime > System.currentTimeMillis())
return;
switch (target.getObjectType()) { switch (target.getObjectType()) {
case Building: case Building:
if (((Building) target).isVulnerable() == false) if (!((Building) target).isVulnerable())
return; return;
break; break;
case PlayerCharacter: case PlayerCharacter:
@ -59,33 +65,54 @@ public enum CombatManager {
if (mainWeapon == null && offWeapon == null) { if (mainWeapon == null && offWeapon == null) {
//no weapons equipped, punch with both fists //no weapons equipped, punch with both fists
processAttack(attacker, target, mbEnums.EquipSlotType.RHELD); processAttack(attacker, target, mbEnums.EquipSlotType.RHELD);
if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter))
processAttack(attacker, target, mbEnums.EquipSlotType.LHELD); processAttack(attacker, target, mbEnums.EquipSlotType.LHELD);
} else if (mainWeapon == null && offWeapon != null && offWeapon.template.item_skill_required.containsKey("Block")) { return;
}
if (mainWeapon != null && offWeapon == null) {
//swing right hand only
processAttack(attacker, target, mbEnums.EquipSlotType.RHELD);
return;
}
if (mainWeapon == null && offWeapon != null && !offWeapon.template.item_skill_required.containsKey("Block")) {
//swing left hand only
processAttack(attacker, target, mbEnums.EquipSlotType.LHELD);
return;
}
if (mainWeapon == null && offWeapon != null && offWeapon.template.item_skill_required.containsKey("Block")) {
//no weapon equipped with a shield, punch with one hand //no weapon equipped with a shield, punch with one hand
processAttack(attacker, target, mbEnums.EquipSlotType.RHELD); processAttack(attacker, target, mbEnums.EquipSlotType.RHELD);
} else if (mainWeapon != null && offWeapon != null && offWeapon.template.item_skill_required.containsKey("Block")) { return;
}
if (mainWeapon != null && offWeapon != null && offWeapon.template.item_skill_required.containsKey("Block")) {
//one weapon equipped with a shield, swing with one hand //one weapon equipped with a shield, swing with one hand
processAttack(attacker, target, mbEnums.EquipSlotType.RHELD); processAttack(attacker, target, mbEnums.EquipSlotType.RHELD);
} else if (mainWeapon != null && offWeapon != null && offWeapon.template.item_skill_required.containsKey("Block") == false) { return;
}
if (mainWeapon != null && offWeapon != null && !offWeapon.template.item_skill_required.containsKey("Block")) {
//two weapons equipped, swing both hands //two weapons equipped, swing both hands
processAttack(attacker, target, mbEnums.EquipSlotType.RHELD); processAttack(attacker, target, mbEnums.EquipSlotType.RHELD);
if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter))
processAttack(attacker, target, mbEnums.EquipSlotType.LHELD); processAttack(attacker, target, mbEnums.EquipSlotType.LHELD);
} else if (mainWeapon == null && offWeapon != null && offWeapon.template.item_skill_required.containsKey("Block") == false) {
//swing left hand only
processAttack(attacker, target, mbEnums.EquipSlotType.LHELD);
} else if (mainWeapon != null && offWeapon == null) {
//swing left hand only
processAttack(attacker, target, mbEnums.EquipSlotType.RHELD);
} }
} }
public static void processAttack(AbstractCharacter attacker, AbstractWorldObject target, mbEnums.EquipSlotType slot) { public static void processAttack(AbstractCharacter attacker, AbstractWorldObject target, mbEnums.EquipSlotType slot) {
// heck if character can even attack yet if(attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) {
if (!attacker.isCombat())
return;
if (attacker.getTimestamps().containsKey("Attack" + slot.name())) if (attacker.getTimestamps().get("Attack" + slot.name()) != null && attacker.getTimestamps().get("Attack" + slot.name()) < System.currentTimeMillis()) {
if (System.currentTimeMillis() < attacker.getTimestamps().get("Attack" + slot.name())) setAutoAttackJob(attacker, slot, 1000);
return; return;
}
}
// check if character is in range to attack target // check if character is in range to attack target
@ -109,11 +136,78 @@ public enum CombatManager {
float distanceSquared = attacker.loc.distanceSquared(target.loc); float distanceSquared = attacker.loc.distanceSquared(target.loc);
if (distanceSquared > attackRange * attackRange) boolean inRange = false;
return; if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) {
attackRange += ((PlayerCharacter) attacker).getCharacterHeight() * 0.5f;
} else {
attackRange += attacker.calcHitBox();
}
switch (target.getObjectType()) {
case PlayerCharacter:
attackRange += ((PlayerCharacter) target).getCharacterHeight() * 0.5f;
if (distanceSquared < attackRange * attackRange)
inRange = true;
break;
case Mob:
attackRange += ((AbstractCharacter) target).calcHitBox();
if (distanceSquared < attackRange * attackRange)
inRange = true;
break;
case Building:
float locX = target.loc.x - target.getBounds().getHalfExtents().x;
float locZ = target.loc.z - target.getBounds().getHalfExtents().y;
float sizeX = (target.getBounds().getHalfExtents().x + attackRange) * 2;
float sizeZ = (target.getBounds().getHalfExtents().y + attackRange) * 2;
Rectangle2D.Float rect = new Rectangle2D.Float(locX, locZ, sizeX, sizeZ);
if (rect.contains(new Point2D.Float(attacker.loc.x, attacker.loc.z)))
inRange = true;
break;
}
// take stamina away from attacker //get delay for the auto attack job
long delay = 5000;
if (weapon != null) {
int wepSpeed = (int) (weapon.template.item_weapon_wepspeed);
if (weapon.getBonusPercent(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None) != 0f) //add weapon speed bonus
wepSpeed *= (1 + weapon.getBonus(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None));
if (attacker.getBonuses() != null && attacker.getBonuses().getFloatPercentAll(mbEnums.ModType.AttackDelay, mbEnums.SourceType.None) != 0f) //add effects speed bonus
wepSpeed *= (1 + attacker.getBonuses().getFloatPercentAll(mbEnums.ModType.AttackDelay, mbEnums.SourceType.None));
if (wepSpeed < 10)
wepSpeed = 10; //Old was 10, but it can be reached lower with legit buffs,effects.
delay = wepSpeed * 100L;
}
if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob))
((Mob) attacker).nextAttackTime = System.currentTimeMillis() + delay;
if (inRange) {
//handle retaliate
if (AbstractCharacter.IsAbstractCharacter(target)) {
if (((AbstractCharacter) target).combatTarget == null || !((AbstractCharacter) target).combatTarget.isAlive()) {
((AbstractCharacter) target).combatTarget = attacker;
if (target.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter) && ((AbstractCharacter) target).isCombat())
combatCycle((AbstractCharacter) target, attacker);
}
}
//check if Out of Stamina
if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) {
if (attacker.getStamina() < (weapon.template.item_wt / 3f)) {
//set auto attack job
setAutoAttackJob(attacker, slot, delay);
return;
}
}
// take stamina away from attacker
if (weapon != null) { if (weapon != null) {
float stam = weapon.template.item_wt / 3f; float stam = weapon.template.item_wt / 3f;
stam = (stam < 1) ? 1 : stam; stam = (stam < 1) ? 1 : stam;
@ -149,7 +243,7 @@ public enum CombatManager {
int hitChance; int hitChance;
if (def == 0) if (def == 0)
def = 1; def = 1;
float dif = atr / def; float dif = atr * 1f / def;
if (dif <= 0.8f) if (dif <= 0.8f)
hitChance = 4; hitChance = 4;
@ -172,6 +266,8 @@ public enum CombatManager {
else else
DispatchMessage.sendToAllInRange(attacker, msg); DispatchMessage.sendToAllInRange(attacker, msg);
//set auto attack job
setAutoAttackJob(attacker, slot, delay);
return; return;
} }
@ -199,7 +295,7 @@ public enum CombatManager {
passiveType = mbEnums.PassiveType.Parry; passiveType = mbEnums.PassiveType.Parry;
if (passiveType.equals(mbEnums.PassiveType.None) == false) { if (!passiveType.equals(mbEnums.PassiveType.None)) {
TargetedActionMsg msg = new TargetedActionMsg(attacker, passiveAnim, target, passiveType.value); TargetedActionMsg msg = new TargetedActionMsg(attacker, passiveAnim, target, passiveType.value);
if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter) if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter)
@ -207,15 +303,19 @@ public enum CombatManager {
else else
DispatchMessage.sendToAllInRange(attacker, msg); DispatchMessage.sendToAllInRange(attacker, msg);
//set auto attack job
setAutoAttackJob(attacker, slot, delay);
return; return;
} }
} }
//calculate the base damage //calculate the base damage
int damage = ThreadLocalRandom.current().nextInt(min, max + 1); int damage = ThreadLocalRandom.current().nextInt(min, max + 1);
if (damage == 0) if (damage == 0) {
//set auto attack job
setAutoAttackJob(attacker, slot, delay);
return; return;
}
//get the damage type //get the damage type
mbEnums.DamageType damageType; mbEnums.DamageType damageType;
@ -233,7 +333,7 @@ public enum CombatManager {
Resists resists; Resists resists;
if (AbstractCharacter.IsAbstractCharacter(target) == false) if (!AbstractCharacter.IsAbstractCharacter(target))
resists = ((Building) target).getResists(); //this is a building resists = ((Building) target).getResists(); //this is a building
else else
resists = ((AbstractCharacter) target).getResists(); //this is a character resists = ((AbstractCharacter) target).getResists(); //this is a character
@ -280,9 +380,11 @@ public enum CombatManager {
//check for damage type immunities //check for damage type immunities
if (resists.immuneTo(damageType)) if (resists.immuneTo(damageType)) {
//set auto attack job
setAutoAttackJob(attacker, slot, delay);
return; return;
}
//calculate resisted damage including fortitude //calculate resisted damage including fortitude
damage = (int) resists.getResistedDamage(attacker, (AbstractCharacter) target, damageType, damage, 0); damage = (int) resists.getResistedDamage(attacker, (AbstractCharacter) target, damageType, damage, 0);
@ -300,11 +402,18 @@ public enum CombatManager {
int attackAnim = getSwingAnimation(null, null, slot.equals(mbEnums.EquipSlotType.RHELD)); int attackAnim = getSwingAnimation(null, null, slot.equals(mbEnums.EquipSlotType.RHELD));
if (attacker.charItemManager.getEquipped().get(slot) != null) { if (attacker.charItemManager.getEquipped().get(slot) != null) {
if(attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) {
DeferredPowerJob weaponPower = ((PlayerCharacter) attacker).getWeaponPower();
attackAnim = getSwingAnimation(attacker.charItemManager.getEquipped().get(slot).template, weaponPower, slot.equals(mbEnums.EquipSlotType.RHELD));
}else {
attackAnim = getSwingAnimation(attacker.charItemManager.getEquipped().get(slot).template, null, slot.equals(mbEnums.EquipSlotType.RHELD)); attackAnim = getSwingAnimation(attacker.charItemManager.getEquipped().get(slot).template, null, slot.equals(mbEnums.EquipSlotType.RHELD));
} }
}
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) damage, attackAnim); TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) damage, attackAnim);
DispatchMessage.sendToAllInRange(target, cmm); DispatchMessage.sendToAllInRange(target, cmm);
} }
}
DeferredPowerJob dpj = null; DeferredPowerJob dpj = null;
if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) { if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) {
@ -318,39 +427,9 @@ public enum CombatManager {
((PlayerCharacter) attacker).setWeaponPower(dpj); ((PlayerCharacter) attacker).setWeaponPower(dpj);
} }
} }
//calculate next allowed attack and update the timestamp
long delay = 20 * 100;
if (weapon != null) {
int wepSpeed = (int) (weapon.template.item_weapon_wepspeed);
if (weapon.getBonusPercent(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None) != 0f) //add weapon speed bonus
wepSpeed *= (1 + weapon.getBonus(mbEnums.ModType.WeaponSpeed, mbEnums.SourceType.None));
if (attacker.getBonuses() != null && attacker.getBonuses().getFloatPercentAll(mbEnums.ModType.AttackDelay, mbEnums.SourceType.None) != 0f) //add effects speed bonus
wepSpeed *= (1 + attacker.getBonuses().getFloatPercentAll(mbEnums.ModType.AttackDelay, mbEnums.SourceType.None));
if (wepSpeed < 10)
wepSpeed = 10; //Old was 10, but it can be reached lower with legit buffs,effects.
delay = wepSpeed * 100;
}
attacker.getTimestamps().put("Attack" + slot.name(), System.currentTimeMillis() + delay);
//handle auto attack job creation
ConcurrentHashMap<String, JobContainer> timers = attacker.getTimers(); //set auto attack job
setAutoAttackJob(attacker, slot, delay);
if (timers != null) {
AttackJob aj = new AttackJob(attacker, slot.ordinal(), true);
JobContainer job;
job = JobScheduler.getInstance().scheduleJob(aj, (System.currentTimeMillis() + delay)); // offset 1 millisecond so no overlap issue
timers.put("Attack" + slot, job);
} else
Logger.error("Unable to find Timers for Character " + attacker.getObjectUUID());
} }
@ -411,116 +490,51 @@ public enum CombatManager {
public static int getSwingAnimation(ItemTemplate wb, DeferredPowerJob dpj, boolean mainHand) { public static int getSwingAnimation(ItemTemplate wb, DeferredPowerJob dpj, boolean mainHand) {
int token = 0; int token;
if (dpj != null) {
if (dpj != null)
token = (dpj.getPower() != null) ? dpj.getPower().getToken() : 0; token = (dpj.getPower() != null) ? dpj.getPower().getToken() : 0;
if (token == 563721004) //kick animation if (token == 563721004) //kick animation
return 79; return 79;
if (wb == null) if (wb != null) {
return 75;
ItemTemplate template = wb;
if (mainHand) { if (mainHand) {
if (template.weapon_attack_anim_right.size() > 0) { int random = ThreadLocalRandom.current().nextInt(wb.weapon_attack_anim_right.size());
int anim = wb.weapon_attack_anim_right.get(random)[0];
int animation; return anim;
}else {
int random = ThreadLocalRandom.current().nextInt(template.weapon_attack_anim_right.size()); int random = ThreadLocalRandom.current().nextInt(wb.weapon_attack_anim_left.size());
return wb.weapon_attack_anim_left.get(random)[0];
try {
animation = template.weapon_attack_anim_right.get(random)[0];
return animation;
} catch (Exception e) {
Logger.error(e.getMessage());
return template.weapon_attack_anim_right.get(0)[0];
} }
} else if (template.weapon_attack_anim_left.size() > 0) {
int animation;
int random = ThreadLocalRandom.current().nextInt(template.weapon_attack_anim_left.size());
try {
animation = template.weapon_attack_anim_left.get(random)[0];
return animation;
} catch (Exception e) {
Logger.error(e.getMessage());
return template.weapon_attack_anim_right.get(0)[0];
} }
} }
} else {
if (template.weapon_attack_anim_left.size() > 0) {
int animation; if (wb == null)
int random = ThreadLocalRandom.current().nextInt(template.weapon_attack_anim_left.size()); return 75;
try {
animation = template.weapon_attack_anim_left.get(random)[0];
return animation;
} catch (Exception e) {
Logger.error(e.getMessage());
return template.weapon_attack_anim_right.get(0)[0];
}
} else if (template.weapon_attack_anim_left.size() > 0) {
int animation;
int random = ThreadLocalRandom.current().nextInt(template.weapon_attack_anim_left.size());
try { if (mainHand)
animation = template.weapon_attack_anim_left.get(random)[0]; return wb.weapon_attack_anim_right.get(0)[0];
return animation; else
} catch (Exception e) { return wb.weapon_attack_anim_left.get(0)[0];
Logger.error(e.getMessage());
return template.weapon_attack_anim_right.get(0)[0];
} }
} public static void setAutoAttackJob(AbstractCharacter attacker, mbEnums.EquipSlotType slot, long delay) {
} //calculate next allowed attack and update the timestamp
attacker.getTimestamps().put("Attack" + slot.name(), System.currentTimeMillis() + delay);
String required = template.item_skill_used; //handle auto attack job creation
String mastery = wb.item_skill_mastery_used; ConcurrentHashMap<String, JobContainer> timers = attacker.getTimers();
if (required.equals("Unarmed Combat")) if (timers != null) {
return 75; AttackJob aj = new AttackJob(attacker, slot.ordinal(), true);
else if (required.equals("Sword")) { JobContainer job;
job = JobScheduler.getInstance().scheduleJob(aj, (System.currentTimeMillis() + delay)); // offset 1 millisecond so no overlap issue
timers.put("Attack" + slot, job);
} else
Logger.error("Unable to find Timers for Character " + attacker.getObjectUUID());
if (ItemManager.isTwoHanded(template))
return 105;
else
return 98;
} else if (required.equals("Staff") || required.equals("Pole Arm")) {
return 85;
} else if (required.equals("Spear")) {
return 92;
} else if (required.equals("Hammer") || required.equals("Axe")) {
if (ItemManager.isTwoHanded(template)) {
return 105;
} else if (mastery.equals("Throwing")) {
return 115;
} else {
return 100;
}
} else if (required.equals("Dagger")) {
if (mastery.equals("Throwing")) {
return 117;
} else {
return 81;
}
} else if (required.equals("Crossbow")) {
return 110;
} else if (required.equals("Bow")) {
return 109;
} else if (ItemManager.isTwoHanded(template)) {
return 105;
} else {
return 100;
}
} }
} }

18
src/engine/gameManager/ConfigManager.java

@ -8,10 +8,6 @@
package engine.gameManager; package engine.gameManager;
/* This enumeration implements Magicbane's configuration data which
is loaded from environment variables.
*/
import engine.mbEnums; import engine.mbEnums;
import engine.server.login.LoginServer; import engine.server.login.LoginServer;
import engine.server.world.WorldServer; import engine.server.world.WorldServer;
@ -27,6 +23,14 @@ import java.util.regex.Pattern;
public enum ConfigManager { public enum ConfigManager {
// MB Dev notes:
// Magicbane configuration is loaded from environment variables
//
// On boot the game first looks in /mb.conf for the file magicbane.conf.
//
// If not found, a default config is loaded from /mb.data to enable bootstrap.
// This version should never be modified.
MB_BIND_ADDR, MB_BIND_ADDR,
MB_EXTERNAL_ADDR, MB_EXTERNAL_ADDR,
@ -105,11 +109,11 @@ public enum ConfigManager {
// and determine the server type at runtime. // and determine the server type at runtime.
public static final String DEFAULT_DATA_DIR = "mb.data/"; public static final String DEFAULT_DATA_DIR = "mb.data/";
public static Map<String, String> configMap = new HashMap(System.getenv()); public static final Map<String, String> configMap = new HashMap(System.getenv());
public static mbEnums.ServerType serverType = mbEnums.ServerType.NONE; public static mbEnums.ServerType serverType = mbEnums.ServerType.NONE;
public static WorldServer worldServer; public static WorldServer worldServer;
public static LoginServer loginServer; public static LoginServer loginServer;
public static Map<ConfigManager, Pattern> regex = new HashMap<>(); public static final Map<ConfigManager, Pattern> regex = new HashMap<>();
public static String currentRepoBranch = ""; public static String currentRepoBranch = "";
@ -124,7 +128,7 @@ public enum ConfigManager {
Logger.info(configSetting.name() + ":" + configSetting.getValue()); Logger.info(configSetting.name() + ":" + configSetting.getValue());
else { else {
Logger.error("Missing Config: " + configSetting.name()); Logger.error("Missing Config: " + configSetting.name());
Logger.error("This codebase requires >= MagicBox v1.5.1"); Logger.error("This codebase requires >= MagicBox v1.5.2");
Logger.error("docker pull magicbane/magicbox:latest"); Logger.error("docker pull magicbane/magicbox:latest");
return false; return false;
} }

408
src/engine/gameManager/ForgeManager.java

@ -0,0 +1,408 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.gameManager;
import engine.loot.ModTableEntry;
import engine.loot.ModTypeTableEntry;
import engine.loot.WorkOrder;
import engine.mbEnums;
import engine.net.DispatchMessage;
import engine.net.client.msg.ItemProductionMsg;
import engine.objects.City;
import engine.objects.Item;
import engine.objects.ItemTemplate;
import engine.objects.NPC;
import engine.powers.EffectsBase;
import org.pmw.tinylog.Logger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public enum ForgeManager implements Runnable {
// MB Dev notes:
// Class implements forge rolling mechanics for Magicbane.
//
// .submit(workOrder) may be called from any thread: (ItemProductionMsgHandler).
// Concurrency is managed by the same lock used by the warehouse (city.cityTransactionLock).
// WorkOrders are persisted then reconstituted at bootstrap using table dyn.workorders.
//
// Replaces garbage code that looked as if written by a mental patient with face boils.
FORGE_MANAGER;
public static final BlockingQueue<WorkOrder> forge = new DelayQueue<>();
public static final AtomicInteger workOrderCounter = new AtomicInteger(0);
public static final ConcurrentHashMap<NPC, ConcurrentHashMap.KeySetView<WorkOrder, Boolean>> vendorWorkOrderLookup = new ConcurrentHashMap<>();
public static final ConcurrentHashMap<Item, WorkOrder> itemWorkOrderLookup = new ConcurrentHashMap<>();
@Override
public void run() {
WorkOrder workOrder;
while (true) {
// .forge is a delayQueue (blocking priority queue using an epoc sort)
// workOrders are popped and processed when their completion time has passed.
try {
workOrder = forge.take();
// This workOrder has completed production.
if (workOrder.total_produced >= workOrder.total_to_produce) {
// Set items as completed in the window.
// First CONFIRM_PRODUCE adds virtual item to the interface.
// Second CONFIRM_PRODUCE sets virtual item to complete.
for (Item workOrderItem : workOrder.cooking) {
workOrderItem.flags.add(mbEnums.ItemFlags.Identified);
ItemProductionMsg outMsg = new ItemProductionMsg(workOrder.vendor.building, workOrder.vendor, workOrderItem, mbEnums.ProductionActionType.CONFIRM_PRODUCE, true);
DispatchMessage.dispatchMsgToInterestArea(workOrder.vendor, outMsg, mbEnums.DispatchChannel.SECONDARY, 700, false, false);
}
workOrder.runCompleted = true;
// Update workOrder on disk
DbManager.WarehouseQueries.WRITE_WORKORDER(workOrder);
}
if (workOrder.runCompleted)
continue;
// Move current cooking batch to vendor inventory
completeWorkOrderBatch(workOrder);
// Create new set of in-memory only virtual items
forgeWorkOrderBatch(workOrder);
// enQueue this workOrder again; back into the oven
// until all items for this workOrder are completed.
forge.add(workOrder);
// Debugging: Logger.info(workOrder.toString());
} catch (Exception e) {
Logger.error(e);
}
}
}
public static void start() {
Thread forgeManager;
forgeManager = new Thread(FORGE_MANAGER);
forgeManager.setName("Forge Manager");
forgeManager.start();
}
public static int submit(WorkOrder workOrder) {
// Must have a city to roll anything
City city = workOrder.vendor.building.getCity();
if (city == null)
return 58; //58: The formula is beyond the means of this facility
// Concurrency is rightly managed by same lock as warehouse
city.transactionLock.writeLock().lock();
// Make sure vendor can roll the formulae, warehouse can
// afford this wordOrder and other related checks.
int validation_result = WorkOrder.validate(workOrder);
// The return code is used by the caller (ItemProductionMsgHandler)
// for display of a popup error message to the player.
if (validation_result != 0)
return validation_result;
try {
// Configure this production run.
workOrder.workOrderID = workOrderCounter.incrementAndGet();
workOrder.rollingDuration = ForgeManager.calcRollingDuration(workOrder);
workOrder.completionTime = System.currentTimeMillis() + workOrder.rollingDuration;
workOrder.slots_used = calcAvailableSlots(workOrder);
workOrder.total_produced = 0;
// Single item configuration
if (!workOrder.multiple_slot_request && workOrder.total_to_produce == 0)
workOrder.total_to_produce = 1;
// Set total cost for production run
workOrder.total_to_produce *= workOrder.slots_used;
workOrder.production_cost = calcProductionCost(workOrder);
workOrder.production_cost_total.putAll(workOrder.production_cost);
workOrder.production_cost_total.forEach((key, value) -> workOrder.production_cost_total.put(key, value * workOrder.total_to_produce));
// Withdraw gold and resource costs. Availability has previously been validated.
if (!WorkOrder.withdrawWorkOrderCost(workOrder))
return 58; //58: The formula is beyond the means of this facility
// Create new batch of virtual items
forgeWorkOrderBatch(workOrder);
// Enqueue workOrder in the .forge and then
// add the workOrder to it's vendor
vendorWorkOrderLookup.get(workOrder.vendor).add(workOrder);
forge.add(workOrder);
// PERSIST workOrder (dyn_workorders)
DbManager.WarehouseQueries.WRITE_WORKORDER(workOrder);
} catch (Exception e) {
Logger.error(e);
} finally {
city.transactionLock.writeLock().unlock();
}
Logger.info(workOrder.toString());
return validation_result;
}
public static long calcRollingDuration(WorkOrder workOrder) {
float rollingDuration;
rollingDuration = workOrder.vendor.getBuilding().getRank() * -5L + 40;
rollingDuration = TimeUnit.MINUTES.toMillis((long) rollingDuration);
rollingDuration *= Float.parseFloat(ConfigManager.MB_PRODUCTION_RATE.getValue());
ItemTemplate template = ItemTemplate.templates.get(workOrder.templateID);
// Bane circles
if (template.item_bane_rank > 0)
rollingDuration = (long) template.item_bane_rank * 60 * 60 * 3 * 1000 * Float.parseFloat(ConfigManager.MB_PRODUCTION_RATE.getValue());
return (long) rollingDuration;
}
public static int calcAvailableSlots(WorkOrder workOrder) {
// Slots available in a forge are based on the npc rank
int availableSlots = workOrder.vendor.getRank();
// Subtract the slots currently assigned to other workOrders for this vendor
for (WorkOrder npcWorkOrder : ForgeManager.vendorWorkOrderLookup.get(workOrder.vendor))
availableSlots = availableSlots - npcWorkOrder.cooking.size();
// Single item rolls are always a single slot
if (availableSlots > 0 && !workOrder.multiple_slot_request)
availableSlots = 1;
return availableSlots;
}
public static HashMap<mbEnums.ResourceType, Integer> calcProductionCost(WorkOrder workOrder) {
// Calculate production cost for a single run of the workOrder
HashMap<mbEnums.ResourceType, Integer> production_cost = new HashMap<>();
ItemTemplate template = ItemTemplate.templates.get(workOrder.templateID);
// Add gold and resource costs from template
production_cost.put(mbEnums.ResourceType.GOLD, template.item_value);
production_cost.putAll(template.item_resource_cost);
// Calculate cost of prefix and suffix
if (workOrder.prefixToken != 0) {
EffectsBase prefix = PowersManager.getEffectByToken(workOrder.prefixToken);
production_cost.putAll(PowersManager._effect_costMaps.get(prefix.getIDString()));
}
if (workOrder.suffixToken != 0) {
EffectsBase suffix = PowersManager.getEffectByToken(workOrder.suffixToken);
production_cost.putAll(PowersManager._effect_costMaps.get(suffix.getIDString()));
}
return production_cost;
}
public static Item forgeItem(WorkOrder workOrder) {
// Create new virtual item from specified template
ItemTemplate template = ItemTemplate.templates.get(workOrder.templateID);
Item forgedItem = new Item(workOrder.templateID);
// forgedItem gets a negative id; a virtual item which is not persisted
forgedItem.objectUUID = ItemManager.lastNegativeID.getAndDecrement();
forgedItem.containerType = mbEnums.ItemContainerType.FORGE;
forgedItem.ownerID = workOrder.vendor.getObjectUUID();
// item.upgradeDate is serialized (ItemProductionMsg)
// for vendor forge window completion time.
forgedItem.setDateToUpgrade(workOrder.completionTime);
// Assign a prefix and suffix to this item if random rolled
if (workOrder.prefixToken == 0)
forgedItem.prefixToken = calcRandomMod(workOrder.vendor, mbEnums.ItemModType.PREFIX, template.modTable);
else
forgedItem.prefixToken = workOrder.prefixToken;
if (workOrder.suffixToken == 0)
forgedItem.suffixToken = calcRandomMod(workOrder.vendor, mbEnums.ItemModType.SUFFIX, template.modTable);
else
forgedItem.suffixToken = workOrder.suffixToken;
// Random rolled items are unidentified until completed
if (workOrder.prefixToken == 0 && workOrder.suffixToken == 0)
forgedItem.flags.remove(mbEnums.ItemFlags.Identified);
else
forgedItem.flags.add(mbEnums.ItemFlags.Identified);
// Add virtual item to in-memory caches
workOrder.cooking.add(forgedItem);
DbManager.addToCache(forgedItem);
itemWorkOrderLookup.put(forgedItem, workOrder);
return forgedItem;
}
public static void completeWorkOrderBatch(WorkOrder workOrder) {
ArrayList<Item> toRemove = new ArrayList<>();
for (Item virutalItem : workOrder.cooking) {
// Identify completed items
virutalItem.flags.add(mbEnums.ItemFlags.Identified);
virutalItem.containerType = mbEnums.ItemContainerType.INVENTORY;
// Persist item
Item completedItem = DbManager.ItemQueries.PERSIST(virutalItem);
// Copy Prefix and Suffix tokens from virtual item.
completedItem.prefixToken = virutalItem.prefixToken;
completedItem.suffixToken = virutalItem.suffixToken;
// Add effects to these tokens. Writes to disk.
ItemManager.applyItemEffects(completedItem);
// Add to the vendor inventory
workOrder.vendor.charItemManager.addItemToInventory(completedItem);
ItemProductionMsg outMsg1 = new ItemProductionMsg(workOrder.vendor.building, workOrder.vendor, completedItem, mbEnums.ProductionActionType.DEPOSIT, true);
DispatchMessage.dispatchMsgToInterestArea(workOrder.vendor, outMsg1, mbEnums.DispatchChannel.SECONDARY, 700, false, false);
ItemProductionMsg outMsg2 = new ItemProductionMsg(workOrder.vendor.building, workOrder.vendor, completedItem, mbEnums.ProductionActionType.CONFIRM_DEPOSIT, true);
DispatchMessage.dispatchMsgToInterestArea(workOrder.vendor, outMsg2, mbEnums.DispatchChannel.SECONDARY, 700, false, false);
toRemove.add(virutalItem);
}
for (Item virtualItem : toRemove) {
// Remove virtual items from the forge window
ItemProductionMsg outMsg = new ItemProductionMsg(workOrder.vendor.building, workOrder.vendor, virtualItem, mbEnums.ProductionActionType.CONFIRM_SETPRICE, true);
DispatchMessage.dispatchMsgToInterestArea(workOrder.vendor, outMsg, mbEnums.DispatchChannel.SECONDARY, 700, false, false);
// Remove virtual item from all collections
workOrder.cooking.remove(virtualItem);
itemWorkOrderLookup.remove(virtualItem);
DbManager.removeFromCache(virtualItem);
}
}
public static void forgeWorkOrderBatch(WorkOrder workOrder) {
// Completion time for this batch is in the future
workOrder.completionTime = System.currentTimeMillis() + workOrder.rollingDuration;
for (int i = 0; i < workOrder.slots_used; ++i) {
Item forged_item = forgeItem(workOrder);
// Update NPC window
ItemProductionMsg outMsg = new ItemProductionMsg(workOrder.vendor.building, workOrder.vendor, forged_item, mbEnums.ProductionActionType.CONFIRM_PRODUCE, true);
DispatchMessage.dispatchMsgToInterestArea(workOrder.vendor, outMsg, mbEnums.DispatchChannel.SECONDARY, 700, false, false);
workOrder.total_produced = workOrder.total_produced + 1;
}
// Write updated workOrder to disk
DbManager.WarehouseQueries.WRITE_WORKORDER(workOrder);
}
public static int calcRandomMod(NPC vendor, mbEnums.ItemModType itemModType, int modTable) {
// Random prefix or suffix token based on item.template.modtable
int modifier = 0;
ModTypeTableEntry modTypeTableEntry = null;
ModTableEntry modTableEntry;
int rollForModifier;
switch (itemModType) {
case PREFIX:
int randomPrefix = vendor.getModTypeTable().get(vendor.getItemModTable().indexOf(modTable));
modTypeTableEntry = ModTypeTableEntry.rollTable(randomPrefix, ThreadLocalRandom.current().nextInt(1, 100 + 1));
break;
case SUFFIX:
int randomSuffix = vendor.getModSuffixTable().get(vendor.getItemModTable().indexOf(modTable));
modTypeTableEntry = ModTypeTableEntry.rollTable(randomSuffix, ThreadLocalRandom.current().nextInt(1, 100 + 1));
break;
}
if (modTypeTableEntry == null)
return 0;
rollForModifier = ThreadLocalRandom.current().nextInt(1, 100 + 1);
if (rollForModifier < 80) {
int randomModifier = LootManager.TableRoll(vendor.getLevel(), false);
modTableEntry = ModTableEntry.rollTable(modTypeTableEntry.modTableID, randomModifier);
EffectsBase effectsBase = PowersManager.getEffectByIDString(modTableEntry.action);
modifier = effectsBase.getToken();
}
return modifier;
}
}

25
src/engine/gameManager/ItemManager.java

@ -2,10 +2,12 @@ package engine.gameManager;
import engine.mbEnums; import engine.mbEnums;
import engine.objects.*; import engine.objects.*;
import engine.powers.EffectsBase;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
@ -17,6 +19,8 @@ import java.util.concurrent.ConcurrentHashMap;
public enum ItemManager { public enum ItemManager {
ITEMMANAGER; ITEMMANAGER;
public static final AtomicInteger lastNegativeID = new AtomicInteger(0);
public static Boolean ValidRace(Item item, mbEnums.MonsterType race) { public static Boolean ValidRace(Item item, mbEnums.MonsterType race) {
if (item.template.item_race_req.isEmpty() && item.template.item_race_res.isEmpty()) if (item.template.item_race_req.isEmpty() && item.template.item_race_res.isEmpty())
@ -27,7 +31,7 @@ public enum ItemManager {
return true; return true;
if (item.template.item_race_res.isEmpty() == false) if (item.template.item_race_res.isEmpty() == false)
if (item.template.item_class_res.contains(race) == false) if (item.template.item_race_res.contains(race) == false)
return true; return true;
return false; return false;
@ -185,7 +189,10 @@ public enum ItemManager {
if (!validForSkills(item, abstractCharacter.getSkills())) if (!validForSkills(item, abstractCharacter.getSkills()))
return false; return false;
if (canCharacterEquip(item, abstractCharacter) == false) if (!ValidRace(item, abstractCharacter.absRace))
return false;
if (!ValidClass(item, abstractCharacter.absBaseClass,abstractCharacter.absPromotionClass))
return false; return false;
//players can't wear 0 value items. //players can't wear 0 value items.
@ -220,4 +227,18 @@ public enum ItemManager {
return true; return true;
} }
public static void applyItemEffects(Item forgedItem) {
if (forgedItem.prefixToken != 0) {
EffectsBase prefix = PowersManager.getEffectByToken(forgedItem.prefixToken);
forgedItem.addPermanentEnchantment(prefix.getIDString(), 0);
}
if (forgedItem.suffixToken != 0) {
EffectsBase suffix = PowersManager.getEffectByToken(forgedItem.suffixToken);
forgedItem.addPermanentEnchantment(suffix.getIDString(), 0);
}
}
} }

29
src/engine/gameManager/LootManager.java

@ -80,17 +80,10 @@ public enum LootManager {
RunBootySet(_bootySetMap.get(mob.bootySet), mob, inHotzone); RunBootySet(_bootySetMap.get(mob.bootySet), mob, inHotzone);
//lastly, check mobs inventory for godly or disc runes to send a server announcement //lastly, check mobs inventory for godly or disc runes to send a server announcement
for (Item it : mob.getInventory()) { for (Item item : mob.getInventory()) {
ItemTemplate ib = it.template; if ((item.templateID > 2499 && item.templateID <= 3050) || item.template.item_base_name.toLowerCase().contains("of the gods")) {
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mob.getName() + " in " + mob.getParentZone().zoneName + " has found the " + item.template.item_base_name + ". Are you tough enough to take it?");
if (ib == null)
break;
ItemTemplate template = ItemTemplate.templates.get(it.templateID);
if ((it.templateID > 2499 && it.templateID <= 3050) || template.item_base_name.toLowerCase().contains("of the gods")) {
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mob.getName() + " in " + mob.getParentZone().zoneName + " has found the " + template.item_base_name + ". Are you tough enough to take it?");
chatMsg.setMessageType(10); chatMsg.setMessageType(10);
chatMsg.setChannel(mbEnums.ChatChannelType.SYSTEM.getChannelID()); chatMsg.setChannel(mbEnums.ChatChannelType.SYSTEM.getChannelID());
DispatchMessage.dispatchMsgToAll(chatMsg); DispatchMessage.dispatchMsgToAll(chatMsg);
@ -219,7 +212,7 @@ public enum LootManager {
int prefixTableRoll = 0; int prefixTableRoll = 0;
if (mob.getObjectType().ordinal() == 52) if (mob.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter))
prefixTableRoll = ThreadLocalRandom.current().nextInt(1, 320 + 1); prefixTableRoll = ThreadLocalRandom.current().nextInt(1, 320 + 1);
else else
prefixTableRoll = TableRoll(mob.level, inHotzone); prefixTableRoll = TableRoll(mob.level, inHotzone);
@ -229,7 +222,7 @@ public enum LootManager {
if (prefixMod == null) if (prefixMod == null)
return inItem; return inItem;
if (prefixMod.action.length() > 0) { if (prefixMod.action.isEmpty() == false) {
inItem.setPrefix(prefixMod.action); inItem.setPrefix(prefixMod.action);
inItem.addPermanentEnchantment(prefixMod.action, 0, prefixMod.level, true); inItem.addPermanentEnchantment(prefixMod.action, 0, prefixMod.level, true);
} }
@ -253,7 +246,7 @@ public enum LootManager {
int suffixTableRoll; int suffixTableRoll;
if (mob.getObjectType().ordinal() == 52) if (mob.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter))
suffixTableRoll = ThreadLocalRandom.current().nextInt(1, 320 + 1); suffixTableRoll = ThreadLocalRandom.current().nextInt(1, 320 + 1);
else else
suffixTableRoll = TableRoll(mob.level, inHotzone); suffixTableRoll = TableRoll(mob.level, inHotzone);
@ -263,7 +256,7 @@ public enum LootManager {
if (suffixMod == null) if (suffixMod == null)
return inItem; return inItem;
if (suffixMod.action.length() > 0) { if (suffixMod.action.isEmpty() == false) {
inItem.setSuffix(suffixMod.action); inItem.setSuffix(suffixMod.action);
inItem.addPermanentEnchantment(suffixMod.action, 0, suffixMod.level, false); inItem.addPermanentEnchantment(suffixMod.action, 0, suffixMod.level, false);
} }
@ -277,14 +270,10 @@ public enum LootManager {
mobLevel = 65; mobLevel = 65;
int max = (int) (4.882 * mobLevel + 127.0); int max = (int) (4.882 * mobLevel + 127.0);
if (max > 319)
max = 319;
int min = (int) (4.469 * mobLevel - 3.469); int min = (int) (4.469 * mobLevel - 3.469);
if (min < 70) min = Math.max(min, 70);
min = 70; max = Math.min(max, 319);
if (inHotzone) if (inHotzone)
min += mobLevel; min += mobLevel;

14
src/engine/gameManager/NPCManager.java

@ -9,6 +9,7 @@
package engine.gameManager; package engine.gameManager;
import engine.InterestManagement.WorldGrid; import engine.InterestManagement.WorldGrid;
import engine.loot.WorkOrder;
import engine.math.Quaternion; import engine.math.Quaternion;
import engine.math.Vector3f; import engine.math.Vector3f;
import engine.math.Vector3fImmutable; import engine.math.Vector3fImmutable;
@ -26,6 +27,7 @@ import org.pmw.tinylog.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import static engine.math.FastMath.acos; import static engine.math.FastMath.acos;
@ -516,4 +518,16 @@ public enum NPCManager {
return true; return true;
} }
public static ArrayList<Item> getAllCookingForVendor(NPC npc) {
ArrayList<Item> itemList = new ArrayList<>();
ConcurrentHashMap.KeySetView<WorkOrder, Boolean> vendorWorkOrders = ForgeManager.vendorWorkOrderLookup.get(npc);
for (WorkOrder workOrder : vendorWorkOrders)
itemList.addAll(workOrder.cooking);
return itemList;
}
} }

1
src/engine/gameManager/PowersManager.java

@ -57,6 +57,7 @@ public enum PowersManager {
public static HashMap<String, Integer> AnimationOverrides = new HashMap<>(); public static HashMap<String, Integer> AnimationOverrides = new HashMap<>();
public static HashMap<Integer, ArrayList<RunePowerEntry>> _allRunePowers; public static HashMap<Integer, ArrayList<RunePowerEntry>> _allRunePowers;
public static HashMap<Integer, ArrayList<RuneSkillAdjustEntry>> _allRuneSkillAdjusts; public static HashMap<Integer, ArrayList<RuneSkillAdjustEntry>> _allRuneSkillAdjusts;
public static HashMap<String, HashMap<ResourceType, Integer>> _effect_costMaps = new HashMap<>();
private static JobScheduler js; private static JobScheduler js;
public static void initPowersManager(boolean fullPowersLoad) { public static void initPowersManager(boolean fullPowersLoad) {

21
src/engine/gameManager/SimulationManager.java

@ -24,10 +24,16 @@ import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.Collection; import java.util.Collection;
/* // MB Dev Notes:
* This class contains all methods necessary to drive periodic //
* updates of the game simulation from the main _exec loop. // Class models timers that drive Magicbane simulation ticks used
*/ // for movement updates, triggers and more. Eventually we hope to
// refactor to more of a traditional simulation appropriate for a
// mmo with a transform class and other bells and whistles.
//
// Do as little as possible in here. For any tick you do not want
// deltaTime to approach 1.0f.
public enum SimulationManager { public enum SimulationManager {
SERVERHEARTBEAT; SERVERHEARTBEAT;
@ -35,15 +41,14 @@ public enum SimulationManager {
private static final long CITY_PULSE = 2000; private static final long CITY_PULSE = 2000;
private static final long RUNEGATE_PULSE = 3000; private static final long RUNEGATE_PULSE = 3000;
private static final long UPDATE_PULSE = 1000; private static final long UPDATE_PULSE = 1000;
private static final long FlIGHT_PULSE = 100; private static final long FLIGHT_PULSE = 100;
public static Duration executionTime = Duration.ofNanos(1); public static Duration executionTime = Duration.ofNanos(1);
public static Duration executionMax = Duration.ofNanos(1); public static Duration executionMax = Duration.ofNanos(1);
private static SimulationManager instance = null;
private long _cityPulseTime = System.currentTimeMillis() + CITY_PULSE; private long _cityPulseTime = System.currentTimeMillis() + CITY_PULSE;
private long _runegatePulseTime = System.currentTimeMillis() private long _runegatePulseTime = System.currentTimeMillis()
+ RUNEGATE_PULSE; + RUNEGATE_PULSE;
private long _updatePulseTime = System.currentTimeMillis() + UPDATE_PULSE; private long _updatePulseTime = System.currentTimeMillis() + UPDATE_PULSE;
private long _flightPulseTime = System.currentTimeMillis() + FlIGHT_PULSE; private long _flightPulseTime = System.currentTimeMillis() + FLIGHT_PULSE;
private SimulationManager() { private SimulationManager() {
@ -181,7 +186,7 @@ public enum SimulationManager {
player.updateFlight(); player.updateFlight();
} }
_flightPulseTime = System.currentTimeMillis() + FlIGHT_PULSE; _flightPulseTime = System.currentTimeMillis() + FLIGHT_PULSE;
} }
private void pulseCities() { private void pulseCities() {

255
src/engine/loot/WorkOrder.java

@ -0,0 +1,255 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.loot;
import engine.gameManager.DbManager;
import engine.gameManager.ForgeManager;
import engine.mbEnums;
import engine.objects.Item;
import engine.objects.ItemTemplate;
import engine.objects.NPC;
import engine.objects.Warehouse;
import org.json.JSONArray;
import org.json.JSONObject;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public class WorkOrder implements Delayed {
// MB Dev notes:
// Class defines a Forge rolling request made through a
// vendor; then passed to the ForgeManager singleton
// for completion.
//
// A workOrder once created will last until all items are
// either completed or junked. They are persisted in the
// table dyn_workorders.
public int workOrderID;
public NPC vendor;
public int slots_used;
public int total_to_produce;
public int total_produced;
public boolean multiple_slot_request;
public HashMap<mbEnums.ResourceType, Integer> production_cost = new HashMap<>();
public HashMap<mbEnums.ResourceType, Integer> production_cost_total = new HashMap<>();
public int templateID;
public String item_name_override;
public int prefixToken;
public int suffixToken;
public long rollingDuration;
public long completionTime;
public boolean runCompleted = false;
public boolean runCanceled = false;
// This collection is serialized to the vendor rolling window in ManageNPCMsg.
public ConcurrentHashMap.KeySetView<Item, Boolean> cooking = ConcurrentHashMap.newKeySet();
public WorkOrder() {
}
public WorkOrder(JSONObject jsonWorkOrder) {
// This constructor is used to load workOrders from disk
// during bootstrap. (dyn_workorders)
this.workOrderID = jsonWorkOrder.getInt("workOrderID");
this.vendor = NPC.getNPC(jsonWorkOrder.getInt("vendor"));
this.slots_used = jsonWorkOrder.getInt("slots_used");
this.total_to_produce = jsonWorkOrder.getInt("total_to_produce");
this.total_produced = jsonWorkOrder.getInt("total_produced");
this.multiple_slot_request = jsonWorkOrder.getBoolean("multiple_slot_request");
this.templateID = jsonWorkOrder.getInt("templateID");
this.item_name_override = jsonWorkOrder.getString("item_name_override");
this.prefixToken = jsonWorkOrder.getInt("prefixToken");
this.suffixToken = jsonWorkOrder.getInt("suffixToken");
this.slots_used = jsonWorkOrder.getInt("slots_used");
this.rollingDuration = jsonWorkOrder.getLong("rollingDuration");
this.completionTime = jsonWorkOrder.getLong("completionTime");
this.runCompleted = jsonWorkOrder.getBoolean("runCompleted");
JSONObject productionCostMap = jsonWorkOrder.getJSONObject("production_cost");
for (String key : productionCostMap.keySet()) {
mbEnums.ResourceType resourceType = mbEnums.ResourceType.valueOf(key);
int value = productionCostMap.getInt(key);
this.production_cost.put(resourceType, value);
}
JSONObject productionTotalCostMap = jsonWorkOrder.getJSONObject("production_cost_total");
for (String key : productionTotalCostMap.keySet()) {
mbEnums.ResourceType resourceType = mbEnums.ResourceType.valueOf(key);
int value = productionTotalCostMap.getInt(key);
this.production_cost_total.put(resourceType, value);
}
// Reconstruct cooking items
JSONArray tokenList = jsonWorkOrder.getJSONArray("cookingTokens");
for (Object o : tokenList) {
int prefix = ((JSONArray) o).getInt(0);
int suffix = ((JSONArray) o).getInt(1);
Item cookingItem = ForgeManager.forgeItem(this);
cookingItem.prefixToken = prefix;
cookingItem.suffixToken = suffix;
cookingItem.setDateToUpgrade(this.completionTime);
}
}
public static int validate(WorkOrder workOrder) {
// Validate that a workOrder can be completed by both
// the vendor and the forge.
int validation_result = 0;
ItemTemplate template = ItemTemplate.templates.get(workOrder.templateID);
if (workOrder.vendor.getBuilding() == null)
return 58; //58: The formula is beyond the means of this facility
if (!workOrder.vendor.charItemManager.hasRoomInventory(template.item_wt))
return 30; //30: That person cannot carry that item
if (!workOrder.vendor.getItemModTable().contains((template.modTable)))
return 59; //59: This hireling does not have this formula
if (!Warehouse.calcCostOverrun(workOrder).isEmpty())
return 10; //18: You can't really afford that
// Forge must be protected in order to access warehouse.
if (ForgeManager.calcProductionCost(workOrder).size() > 1)
if (!EnumSet.of(mbEnums.ProtectionState.PROTECTED, mbEnums.ProtectionState.CONTRACT).contains(workOrder.vendor.building.protectionState))
return 193; //193: Production denied: This building must be protected to gain access to warehouse
return validation_result;
}
public static boolean withdrawWorkOrderCost(WorkOrder workOrder) {
if (workOrder.vendor.building.getCity() == null)
return false;
int strongbox = workOrder.vendor.building.getStrongboxValue();
// Strongbox can cover total gold cost;
if (workOrder.production_cost_total.get(mbEnums.ResourceType.GOLD) <= strongbox) {
workOrder.vendor.building.setStrongboxValue(strongbox - workOrder.production_cost_total.get(mbEnums.ResourceType.GOLD));
workOrder.production_cost_total.put(mbEnums.ResourceType.GOLD, 0);
// Early exit for Strongbox covering gold only rolls
if (workOrder.production_cost_total.size() == 1)
return true;
} else {
int remainingAmount = workOrder.production_cost_total.get(mbEnums.ResourceType.GOLD) - strongbox;
workOrder.vendor.building.setStrongboxValue(0);
workOrder.production_cost_total.put(mbEnums.ResourceType.GOLD, workOrder.production_cost_total.get(mbEnums.ResourceType.GOLD) - remainingAmount);
}
// There is an overflow at this point and a warehouse is required
Warehouse warehouse = workOrder.vendor.building.getCity().warehouse;
if (warehouse == null)
return false;
// Deduct total production cost from warehouse
workOrder.production_cost_total.forEach((key, value) -> warehouse.resources.put(key, warehouse.resources.get(key) - value));
DbManager.WarehouseQueries.UPDATE_WAREHOUSE(warehouse);
return true;
}
@Override
public long getDelay(TimeUnit unit) {
long timeRemaining = completionTime - System.currentTimeMillis();
return unit.convert(timeRemaining, TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
return Long.compare(this.completionTime, ((WorkOrder) o).completionTime);
}
public static JSONObject toJson(WorkOrder workOrder) {
// Workorders are persisted in JSON format.
JSONObject jsonWorkOrder = new JSONObject();
jsonWorkOrder.put("workOrderID", workOrder.workOrderID);
jsonWorkOrder.put("vendor", workOrder.vendor.getObjectUUID());
jsonWorkOrder.put("slots_used", workOrder.slots_used);
jsonWorkOrder.put("total_to_produce", workOrder.total_to_produce);
jsonWorkOrder.put("total_produced", workOrder.total_produced);
jsonWorkOrder.put("multiple_slot_request", workOrder.multiple_slot_request);
jsonWorkOrder.put("production_cost", workOrder.production_cost);
jsonWorkOrder.put("production_cost_total", workOrder.production_cost_total);
jsonWorkOrder.put("templateID", workOrder.templateID);
jsonWorkOrder.put("item_name_override", workOrder.item_name_override);
jsonWorkOrder.put("prefixToken", workOrder.prefixToken);
jsonWorkOrder.put("suffixToken", workOrder.suffixToken);
jsonWorkOrder.put("rollingDuration", workOrder.rollingDuration);
jsonWorkOrder.put("completionTime", workOrder.completionTime);
jsonWorkOrder.put("runCompleted", workOrder.runCompleted);
ArrayList<Integer[]> cookingTokens = new ArrayList<>();
for (Item item : workOrder.cooking)
cookingTokens.add(new Integer[]{item.prefixToken, item.suffixToken});
jsonWorkOrder.put("cookingTokens", cookingTokens);
return jsonWorkOrder;
}
public String toString() {
LocalDateTime localDateTime = Instant.ofEpochMilli(this.completionTime)
.atZone(ZoneId.systemDefault()).toLocalDateTime();
Duration duration = Duration.ofMillis(this.rollingDuration);
String outSTring = "\r\nwordOrderID: " + this.workOrderID + "\r\n" +
"vendor: " + this.vendor.getObjectUUID() + "\r\n" +
"slots_used: " + this.slots_used + "\r\n" +
"total_to_produce: " + this.total_to_produce + "\r\n" +
"total_produced: " + this.total_produced + "\r\n" +
"templateID: " + this.templateID + "\r\n" +
"item_name_override: " + this.item_name_override + "\r\n" +
"prefixToken: " + this.prefixToken + "\r\n" +
"suffixToken: " + this.suffixToken + "\r\n" +
"rollingDuration: " + duration + "\r\n" +
"completionTime: " + localDateTime + "\r\n" +
"runCompleted: " + this.runCompleted + "\r\n" +
"runCanceled: " + this.runCanceled + "\r\n" +
"productionCost: " + this.production_cost.toString() + "\r\n" +
"totalProductionCost:: " + this.production_cost_total.toString();
return outSTring;
}
}

20
src/engine/mbEnums.java

@ -3024,5 +3024,25 @@ public class mbEnums {
} }
} }
public enum ProductionActionType {
NONE,
PRODUCE,
JUNK,
RECYCLE,
COMPLETE,
SETPRICE,
DEPOSIT,
TAKE,
CONFIRM_PRODUCE,
CONFIRM_SETPRICE,
CONFIRM_DEPOSIT,
CONFIRM_TAKE;
}
public enum ItemModType {
PREFIX,
SUFFIX;
}
} }

125
src/engine/mobileAI/MobAI.java

@ -38,7 +38,7 @@ import static engine.math.FastMath.sqr;
public class MobAI { public class MobAI {
private static void AttackTarget(Mob mob, AbstractWorldObject target) { private static void attackTarget(Mob mob, AbstractWorldObject target) {
try { try {
@ -58,7 +58,7 @@ public class MobAI {
if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter && canCast(mob)) { if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter && canCast(mob)) {
if (MobCast(mob)) { if (mobCast(mob)) {
mob.updateLocation(); mob.updateLocation();
return; return;
} }
@ -71,15 +71,15 @@ public class MobAI {
switch (target.getObjectType()) { switch (target.getObjectType()) {
case PlayerCharacter: case PlayerCharacter:
PlayerCharacter targetPlayer = (PlayerCharacter) target; PlayerCharacter targetPlayer = (PlayerCharacter) target;
AttackPlayer(mob, targetPlayer); attackPlayer(mob, targetPlayer);
break; break;
case Building: case Building:
Building targetBuilding = (Building) target; Building targetBuilding = (Building) target;
AttackBuilding(mob, targetBuilding); attackBuilding(mob, targetBuilding);
break; break;
case Mob: case Mob:
Mob targetMob = (Mob) target; Mob targetMob = (Mob) target;
AttackMob(mob, targetMob); attackMob(mob, targetMob);
break; break;
} }
@ -90,7 +90,7 @@ public class MobAI {
} }
} }
public static void AttackPlayer(Mob mob, PlayerCharacter target) { public static void attackPlayer(Mob mob, PlayerCharacter target) {
try { try {
@ -100,7 +100,7 @@ public class MobAI {
} }
if (mob.behaviourType.callsForHelp) if (mob.behaviourType.callsForHelp)
MobCallForHelp(mob); mobCallForHelp(mob);
if (!MovementUtilities.inRangeDropAggro(mob, target)) { if (!MovementUtilities.inRangeDropAggro(mob, target)) {
mob.setCombatTarget(null); mob.setCombatTarget(null);
@ -128,7 +128,7 @@ public class MobAI {
} }
public static void AttackBuilding(Mob mob, Building target) { public static void attackBuilding(Mob mob, Building target) {
try { try {
@ -162,7 +162,7 @@ public class MobAI {
} }
} }
public static void AttackMob(Mob mob, Mob target) { public static void attackMob(Mob mob, Mob target) {
try { try {
@ -179,7 +179,7 @@ public class MobAI {
} }
} }
private static void Patrol(Mob mob) { private static void patrol(Mob mob) {
try { try {
@ -230,7 +230,7 @@ public class MobAI {
for (Integer minionUUID : mob.minions) { for (Integer minionUUID : mob.minions) {
Mob minion = Mob.getMob(minionUUID); Mob minion = Mob.getMob(minionUUID);
if (minion.isAlive() && minion.combatTarget == null) if (minion.isAlive() && minion.combatTarget == null)
MobAI.Patrol(minion); MobAI.patrol(minion);
} }
MovementUtilities.aiMove(mob, mob.destination, true); MovementUtilities.aiMove(mob, mob.destination, true);
@ -284,7 +284,7 @@ public class MobAI {
return false; return false;
} }
public static boolean MobCast(Mob mob) { public static boolean mobCast(Mob mob) {
try { try {
// Method picks a random spell from a mobile's list of powers // Method picks a random spell from a mobile's list of powers
@ -296,7 +296,7 @@ public class MobAI {
AbstractCharacter target = (AbstractCharacter) mob.getCombatTarget(); AbstractCharacter target = (AbstractCharacter) mob.getCombatTarget();
if (mob.behaviourType.callsForHelp) if (mob.behaviourType.callsForHelp)
MobCallForHelp(mob); mobCallForHelp(mob);
// Generate a list of tokens from the mob powers for this mobile. // Generate a list of tokens from the mob powers for this mobile.
@ -410,7 +410,7 @@ public class MobAI {
return powerRank; return powerRank;
} }
public static void MobCallForHelp(Mob mob) { public static void mobCallForHelp(Mob mob) {
try { try {
@ -445,7 +445,7 @@ public class MobAI {
} }
} }
public static void DetermineAction(Mob mob) { public static void determineAction(Mob mob) {
try { try {
@ -465,7 +465,7 @@ public class MobAI {
//trebuchet spawn handler //trebuchet spawn handler
if (mob.despawned && mob.getMobBase().getLoadID() == 13171) { if (mob.despawned && mob.getMobBase().getLoadID() == 13171) {
CheckForRespawn(mob); checkForRespawn(mob);
return; return;
} }
@ -486,12 +486,12 @@ public class MobAI {
} }
} }
CheckForRespawn(mob); checkForRespawn(mob);
//check to send mob home for player guards to prevent exploit of dragging guards away and then teleporting //check to send mob home for player guards to prevent exploit of dragging guards away and then teleporting
if (!mob.agentType.equals(mbEnums.AIAgentType.PET)) if (!mob.agentType.equals(mbEnums.AIAgentType.PET))
CheckToSendMobHome(mob); checkToSendMobHome(mob);
return; return;
} }
@ -499,7 +499,7 @@ public class MobAI {
//no need to continue if mob is dead, check for respawn and move on //no need to continue if mob is dead, check for respawn and move on
if (!mob.isAlive()) { if (!mob.isAlive()) {
CheckForRespawn(mob); checkForRespawn(mob);
return; return;
} }
@ -520,7 +520,7 @@ public class MobAI {
if (mob.agentType.equals(mbEnums.AIAgentType.PET) == false) if (mob.agentType.equals(mbEnums.AIAgentType.PET) == false)
CheckToSendMobHome(mob); checkToSendMobHome(mob);
if (mob.getCombatTarget() != null) { if (mob.getCombatTarget() != null) {
@ -550,17 +550,17 @@ public class MobAI {
case GuardCaptain: case GuardCaptain:
case GuardMinion: case GuardMinion:
case GuardWallArcher: case GuardWallArcher:
GuardLogic(mob); guardLogic(mob);
break; break;
case Pet1: case Pet1:
case SiegeEngine: case SiegeEngine:
PetLogic(mob); petLogic(mob);
break; break;
case HamletGuard: case HamletGuard:
HamletGuardLogic(mob); hamletGuardLogic(mob);
break; break;
default: default:
DefaultLogic(mob); defaultLogic(mob);
break; break;
} }
} catch (Exception e) { } catch (Exception e) {
@ -568,7 +568,7 @@ public class MobAI {
} }
} }
private static void CheckForAggro(Mob aiAgent) { private static void checkForAggro(Mob aiAgent) {
try { try {
@ -642,7 +642,7 @@ public class MobAI {
} }
} }
private static void CheckMobMovement(Mob mob) { private static void checkMobMovement(Mob mob) {
try { try {
@ -685,9 +685,9 @@ public class MobAI {
// Minions only patrol on their own if captain is dead. // Minions only patrol on their own if captain is dead.
if (mob.agentType.equals(mbEnums.AIAgentType.GUARDMINION) == false) if (mob.agentType.equals(mbEnums.AIAgentType.GUARDMINION) == false)
Patrol(mob); patrol(mob);
else if (mob.guardCaptain.isAlive() == false) else if (mob.guardCaptain.isAlive() == false)
Patrol(mob); patrol(mob);
} else } else
mob.stopPatrolTime = System.currentTimeMillis(); mob.stopPatrolTime = System.currentTimeMillis();
} else { } else {
@ -700,7 +700,7 @@ public class MobAI {
} }
} }
private static void CheckForRespawn(Mob aiAgent) { private static void checkForRespawn(Mob aiAgent) {
try { try {
@ -747,7 +747,7 @@ public class MobAI {
} }
} }
public static void CheckForAttack(Mob mob) { public static void checkForAttack(Mob mob) {
try { try {
//checks if mob can attack based on attack timer and range //checks if mob can attack based on attack timer and range
@ -764,25 +764,14 @@ public class MobAI {
mob.setCombatTarget(null); mob.setCombatTarget(null);
return; return;
} }
if (System.currentTimeMillis() > mob.getNextAttackTime()) { attackTarget(mob, mob.getCombatTarget());
int delay = 3000;
if (mob.charItemManager.getEquipped().get(mbEnums.EquipSlotType.RHELD) != null) {
delay = (int) (mob.charItemManager.getEquipped().get(mbEnums.EquipSlotType.RHELD).template.item_weapon_wepspeed * 100);
}
if (mob.charItemManager.getEquipped().get(mbEnums.EquipSlotType.LHELD) != null && mob.charItemManager.getEquipped().get(mbEnums.EquipSlotType.LHELD).template.item_type.equals(mbEnums.ItemType.WEAPON)) {
delay += (int) (mob.charItemManager.getEquipped().get(mbEnums.EquipSlotType.LHELD).template.item_weapon_wepspeed * 100);
}
mob.nextAttackTime = System.currentTimeMillis() + delay;
AttackTarget(mob, mob.getCombatTarget());
}
} catch (Exception e) { } catch (Exception e) {
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForAttack" + " " + e.getMessage()); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForAttack" + " " + e.getMessage());
} }
} }
private static void CheckToSendMobHome(Mob mob) { private static void checkToSendMobHome(Mob mob) {
try { try {
@ -864,7 +853,7 @@ public class MobAI {
} }
} }
private static void SafeGuardAggro(Mob mob) { private static void safeGuardAggro(Mob mob) {
try { try {
HashSet<AbstractWorldObject> awoList = WorldGrid.getObjectsInRangePartial(mob, 100, MBServerStatics.MASK_MOB); HashSet<AbstractWorldObject> awoList = WorldGrid.getObjectsInRangePartial(mob, 100, MBServerStatics.MASK_MOB);
@ -896,19 +885,19 @@ public class MobAI {
} }
} }
public static void GuardLogic(Mob mob) { public static void guardLogic(Mob mob) {
try { try {
if (mob.getCombatTarget() == null) { if (mob.getCombatTarget() == null) {
CheckForPlayerGuardAggro(mob); checkForPlayerGuardAggro(mob);
} else { } else {
//do not need to look to change target if target is already null //do not need to look to change target if target is already null
AbstractWorldObject newTarget = ChangeTargetFromHateValue(mob); AbstractWorldObject newTarget = changeTargetFromHateValue(mob);
if (newTarget != null) { if (newTarget != null) {
if (newTarget.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) { if (newTarget.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) {
if (GuardCanAggro(mob, (PlayerCharacter) newTarget)) if (guardCanAggro(mob, (PlayerCharacter) newTarget))
mob.setCombatTarget(newTarget); mob.setCombatTarget(newTarget);
} else } else
mob.setCombatTarget(newTarget); mob.setCombatTarget(newTarget);
@ -916,17 +905,17 @@ public class MobAI {
} }
if (mob.behaviourType.canRoam) if (mob.behaviourType.canRoam)
CheckMobMovement(mob);//all guards that can move check to move checkMobMovement(mob);//all guards that can move check to move
if (mob.combatTarget != null) if (mob.combatTarget != null)
CheckForAttack(mob); //only check to attack if combat target is not null checkForAttack(mob); //only check to attack if combat target is not null
} catch (Exception e) { } catch (Exception e) {
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardLogic" + " " + e.getMessage()); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardLogic" + " " + e.getMessage());
} }
} }
private static void PetLogic(Mob mob) { private static void petLogic(Mob mob) {
try { try {
@ -935,9 +924,9 @@ public class MobAI {
mob.killCharacter("no owner"); mob.killCharacter("no owner");
if (MovementUtilities.canMove(mob) && mob.behaviourType.canRoam) if (MovementUtilities.canMove(mob) && mob.behaviourType.canRoam)
CheckMobMovement(mob); checkMobMovement(mob);
CheckForAttack(mob); checkForAttack(mob);
//recover health //recover health
@ -959,23 +948,23 @@ public class MobAI {
} }
} }
private static void HamletGuardLogic(Mob mob) { private static void hamletGuardLogic(Mob mob) {
try { try {
//safehold guard //safehold guard
if (mob.getCombatTarget() == null) if (mob.getCombatTarget() == null)
SafeGuardAggro(mob); safeGuardAggro(mob);
else if (mob.getCombatTarget().isAlive() == false) else if (mob.getCombatTarget().isAlive() == false)
SafeGuardAggro(mob); safeGuardAggro(mob);
CheckForAttack(mob); checkForAttack(mob);
} catch (Exception e) { } catch (Exception e) {
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: HamletGuardLogic" + " " + e.getMessage()); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: HamletGuardLogic" + " " + e.getMessage());
} }
} }
private static void DefaultLogic(Mob mob) { private static void defaultLogic(Mob mob) {
try { try {
@ -986,16 +975,16 @@ public class MobAI {
if (mob.behaviourType.isAgressive) { if (mob.behaviourType.isAgressive) {
AbstractWorldObject newTarget = ChangeTargetFromHateValue(mob); AbstractWorldObject newTarget = changeTargetFromHateValue(mob);
if (newTarget != null) if (newTarget != null)
mob.setCombatTarget(newTarget); mob.setCombatTarget(newTarget);
else { else {
if (mob.getCombatTarget() == null) { if (mob.getCombatTarget() == null) {
if (mob.behaviourType == mbEnums.MobBehaviourType.HamletGuard) if (mob.behaviourType == mbEnums.MobBehaviourType.HamletGuard)
SafeGuardAggro(mob); //safehold guard safeGuardAggro(mob); //safehold guard
else else
CheckForAggro(mob); //normal aggro checkForAggro(mob); //normal aggro
} }
} }
} }
@ -1003,19 +992,19 @@ public class MobAI {
//check if mob can move for patrol or moving to target //check if mob can move for patrol or moving to target
if (mob.behaviourType.canRoam) if (mob.behaviourType.canRoam)
CheckMobMovement(mob); checkMobMovement(mob);
//check if mob can attack if it isn't wimpy //check if mob can attack if it isn't wimpy
if (!mob.behaviourType.isWimpy && mob.getCombatTarget() != null) if (!mob.behaviourType.isWimpy && mob.getCombatTarget() != null)
CheckForAttack(mob); checkForAttack(mob);
} catch (Exception e) { } catch (Exception e) {
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: DefaultLogic" + " " + e.getMessage()); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: DefaultLogic" + " " + e.getMessage());
} }
} }
public static void CheckForPlayerGuardAggro(Mob mob) { public static void checkForPlayerGuardAggro(Mob mob) {
try { try {
@ -1061,7 +1050,7 @@ public class MobAI {
// No aggro for this player // No aggro for this player
if (GuardCanAggro(mob, loadedPlayer) == false) if (guardCanAggro(mob, loadedPlayer) == false)
continue; continue;
if (MovementUtilities.inRangeToAggro(mob, loadedPlayer) && mob.getCombatTarget() == null) { if (MovementUtilities.inRangeToAggro(mob, loadedPlayer) && mob.getCombatTarget() == null) {
@ -1079,7 +1068,7 @@ public class MobAI {
Mob aggroMob = (Mob) awoMob; Mob aggroMob = (Mob) awoMob;
if (GuardCanAggro(mob, aggroMob)) { if (guardCanAggro(mob, aggroMob)) {
mob.setCombatTarget(aggroMob); mob.setCombatTarget(aggroMob);
return; return;
} }
@ -1091,7 +1080,7 @@ public class MobAI {
} }
} }
public static Boolean GuardCanAggro(Mob mob, AbstractCharacter target) { public static Boolean guardCanAggro(Mob mob, AbstractCharacter target) {
try { try {
@ -1200,7 +1189,7 @@ public class MobAI {
} }
} }
public static AbstractWorldObject ChangeTargetFromHateValue(Mob mob) { public static AbstractWorldObject changeTargetFromHateValue(Mob mob) {
try { try {

2
src/engine/mobileAI/Threads/MobAIThread.java

@ -32,7 +32,7 @@ public class MobAIThread implements Runnable {
try { try {
if (mob != null) if (mob != null)
MobAI.DetermineAction(mob); MobAI.determineAction(mob);
} catch (Exception e) { } catch (Exception e) {
Logger.error("Mob: " + mob.getName() + " UUID: " + mob.getObjectUUID() + " ERROR: " + e); Logger.error("Mob: " + mob.getName() + " UUID: " + mob.getObjectUUID() + " ERROR: " + e);
e.printStackTrace(); e.printStackTrace();

8
src/engine/mobileAI/Threads/Respawner.java

@ -16,7 +16,15 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue; import java.util.concurrent.DelayQueue;
public enum Respawner implements Runnable { public enum Respawner implements Runnable {
// MB Dev Notes:
//
// Thread acts as a throttle for messages to the client. Mobiles are
// respawned over a short time so as not to flood the client when
// an entire camp respawns at once.
RESPAWNER; RESPAWNER;
public static BlockingQueue<Mob> respawnQueue = new DelayQueue(); public static BlockingQueue<Mob> respawnQueue = new DelayQueue();
@Override @Override

1
src/engine/net/AbstractConnection.java

@ -10,7 +10,6 @@
package engine.net; package engine.net;
import engine.job.JobManager; import engine.job.JobManager;
import engine.net.client.Protocol;
import engine.net.client.msg.ClientNetMsg; import engine.net.client.msg.ClientNetMsg;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;

1
src/engine/net/AbstractNetMsg.java

@ -10,7 +10,6 @@
package engine.net; package engine.net;
import engine.exception.SerializationException; import engine.exception.SerializationException;
import engine.net.client.Protocol;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import engine.util.StringUtils; import engine.util.StringUtils;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;

1
src/engine/net/CheckNetMsgFactoryJob.java

@ -9,7 +9,6 @@
package engine.net; package engine.net;
import engine.job.AbstractJob; import engine.job.AbstractJob;
import engine.net.client.Protocol;
import engine.net.client.msg.ClientNetMsg; import engine.net.client.msg.ClientNetMsg;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;

135
src/engine/net/ItemProductionManager.java

@ -1,135 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.net;
import engine.mbEnums.DispatchChannel;
import engine.objects.ProducedItem;
import org.pmw.tinylog.Logger;
import java.util.HashSet;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.atomic.LongAdder;
/**
* Thread blocks until MagicBane dispatch messages are
* enqueued then processes them in FIFO order. The collection
* is thread safe.
* <p>
* Any large messages not time sensitive such as load object
* sent to more than a single individual should be spawned
* individually on a DispatchMessageThread.
*/
public enum ItemProductionManager implements Runnable {
ITEMPRODUCTIONMANAGER;
// Instance variables
@SuppressWarnings("unchecked") // Cannot have arrays of generics in java.
private static final DelayQueue<ItemQueue> producedQueue = new DelayQueue<>();
public static volatile long[] messageCount = new long[DispatchChannel.values().length];
// Class variables
public static LongAdder[] dispatchCount = new LongAdder[DispatchChannel.values().length];
// Performance metrics
public static volatile long[] maxRecipients = new long[DispatchChannel.values().length];
public static LongAdder dispatchPoolSize = new LongAdder();
public static HashSet<ProducedItem> FailedItems = new HashSet<>();
public Thread itemProductionThread = null;
private ItemQueue itemQueue;
private long nextFailedItemAudit;
// Thread constructor
public static void send(ItemQueue item) {
// Don't queue up empty dispatches!
if (item == null)
return;
producedQueue.add(item);
}
public static String getNetstatString() {
String outString = null;
String newLine = System.getProperty("line.separator");
outString = "[LUA_NETSTA()]" + newLine;
outString += "poolSize: " + dispatchPoolSize.longValue() + '\n';
for (DispatchChannel dispatchChannel : DispatchChannel.values()) {
outString += "Channel: " + dispatchChannel.name() + '\n';
outString += "Dispatches: " + dispatchCount[dispatchChannel.getChannelID()].longValue() + '\n';
outString += "Messages: " + messageCount[dispatchChannel.getChannelID()] + '\n';
outString += "maxRecipients: " + maxRecipients[dispatchChannel.getChannelID()] + '\n';
}
return outString;
}
public void startMessagePump() {
itemProductionThread = new Thread(this);
itemProductionThread.setName("ItemProductionManager");
}
public void initialize() {
itemProductionThread.start();
}
@Override
public void run() {
while (true) {
try {
this.itemQueue = producedQueue.take();
if (this.itemQueue == null) {
return;
}
if (this.itemQueue != null) {
if (this.itemQueue.item == null) {
this.itemQueue.release();
return;
}
boolean created = this.itemQueue.item.finishProduction();
if (!created)
FailedItems.add(this.itemQueue.item);
this.itemQueue.release();
}
} catch (Exception e) {
Logger.error(e);
}
}
}
// For Debugging:
//Logger.error("MessageDispatcher", messageDispatch.msg.getOpcodeAsString() + " sent to " + messageDispatch.playerList.size() + " players");
}

86
src/engine/net/ItemQueue.java

@ -1,86 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.net;
import engine.objects.ProducedItem;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import static engine.net.MessageDispatcher.itemPoolSize;
/**
* Data class holds a message and a distribution list
*/
public class ItemQueue implements Delayed {
private static final ConcurrentLinkedQueue<ItemQueue> itemPool = new ConcurrentLinkedQueue<>();
public ProducedItem item;
public long delayTime;
public ItemQueue(ProducedItem item, long delayTime) {
this.item = item;
this.delayTime = System.currentTimeMillis() + delayTime;
}
public static ItemQueue borrow(ProducedItem item, long delayTime) {
ItemQueue itemQueue;
itemQueue = itemPool.poll();
if (itemQueue == null) {
itemQueue = new ItemQueue(item, delayTime);
} else {
itemQueue.item = item;
itemQueue.delayTime = System.currentTimeMillis() + delayTime;
itemPoolSize.decrement();
}
return itemQueue;
}
public void reset() {
this.item = null;
this.delayTime = 0;
}
public void release() {
this.reset();
itemPool.add(this);
itemPoolSize.increment();
}
@Override
public int compareTo(Delayed another) {
ItemQueue anotherTask = (ItemQueue) another;
if (this.delayTime < anotherTask.delayTime) {
return -1;
}
if (this.delayTime > anotherTask.delayTime) {
return 1;
}
return 0;
}
@Override
public long getDelay(TimeUnit unit) {
long difference = delayTime - System.currentTimeMillis();
return unit.convert(difference, TimeUnit.MILLISECONDS);
}
}

94
src/engine/net/MessageDispatcher.java

@ -17,36 +17,33 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.LongAdder; import java.util.concurrent.atomic.LongAdder;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** // MB Dev Notes:
* Thread blocks until MagicBane dispatch messages are // All outgoing Protocol messages to the player are managed through the MessageDispatcher.class.
* enqueued then processes them in FIFO order. The collection // All incoming Protocol messages from the player are managed by the Protocol.class.
* is thread safe. //
* <p> // A DispatchMessage is configured (Protocol messsage) and wrapped in a Dispatch (distribution list).
* Any large messages not time sensitive such as load object // A Dispatch can be submitted to the MessageDispatcher for delivery from any thread.
* sent to more than a single individual should be spawned //
* individually on a DispatchMessageThread. // Dispatches are interleaved between channels. This is to ensure
*/ // a combat or movement message is not delayed by spam clicking a
// larger message. Choose your channel wisely.
public class MessageDispatcher implements Runnable { public class MessageDispatcher implements Runnable {
// Instance variables // Class variables
@SuppressWarnings("unchecked") // Cannot have arrays of generics in java.
private static final ConcurrentLinkedQueue<Dispatch>[] _messageQueue = new ConcurrentLinkedQueue[DispatchChannel.values().length]; private static final ConcurrentLinkedQueue<Dispatch>[] _messageQueue = new ConcurrentLinkedQueue[DispatchChannel.values().length];
private static final LinkedBlockingQueue<Boolean> _blockingQueue = new LinkedBlockingQueue<>(); private static final LinkedBlockingQueue<Boolean> _blockingQueue = new LinkedBlockingQueue<>();
// Class variables
public static volatile long[] messageCount = new long[DispatchChannel.values().length]; public static volatile long[] messageCount = new long[DispatchChannel.values().length];
public static LongAdder[] dispatchCount = new LongAdder[DispatchChannel.values().length]; public static LongAdder[] dispatchCount = new LongAdder[DispatchChannel.values().length];
// Performance metrics // Performance metrics
public static volatile long[] maxRecipients = new long[DispatchChannel.values().length]; public static volatile long[] maxRecipients = new long[DispatchChannel.values().length];
public static LongAdder itemPoolSize = new LongAdder(); public static LongAdder itemPoolSize = new LongAdder();
private final Pattern filterPattern; // Unused, but just in case private final Pattern filterPattern; // Unused, but just in case
private Dispatch messageDispatch; private Dispatch messageDispatch;
// Thread constructor
public MessageDispatcher() { public MessageDispatcher() {
// Create new FIFO queues for this network thread // Create new FIFO queues for this network thread
@ -61,8 +58,41 @@ public class MessageDispatcher implements Runnable {
} }
@Override
public void run() {
boolean shouldBlock;
while (true) {
try {
shouldBlock = true;
for (DispatchChannel dispatchChannel : DispatchChannel.values()) {
this.messageDispatch = _messageQueue[dispatchChannel.getChannelID()].poll();
if (this.messageDispatch != null) {
DispatchMessage.serializeDispatch(this.messageDispatch);
shouldBlock = false;
}
}
if (shouldBlock == true)
shouldBlock = _blockingQueue.take();
} catch (Exception e) {
Logger.error(e);
}
}
}
public static void send(Dispatch messageDispatch, DispatchChannel dispatchChannel) { public static void send(Dispatch messageDispatch, DispatchChannel dispatchChannel) {
// Use Dispatch.borrow() for a new dispatch.
// The Dispatch will be released by the system
// once delivered.
// Don't queue up empty dispatches! // Don't queue up empty dispatches!
if (messageDispatch.player == null) if (messageDispatch.player == null)
@ -74,12 +104,11 @@ public class MessageDispatcher implements Runnable {
// Update performance metrics // Update performance metrics
messageCount[dispatchChannel.getChannelID()]++; messageCount[dispatchChannel.getChannelID()]++;
} }
public static String getNetstatString() { public static String getNetstatString() {
String outString = null; String outString;
String newLine = System.getProperty("line.separator"); String newLine = System.getProperty("line.separator");
outString = "[LUA_NETSTA()]" + newLine; outString = "[LUA_NETSTA()]" + newLine;
outString += "poolSize: " + itemPoolSize.longValue() + '\n'; outString += "poolSize: " + itemPoolSize.longValue() + '\n';
@ -94,37 +123,6 @@ public class MessageDispatcher implements Runnable {
return outString; return outString;
} }
@Override
public void run() {
boolean shouldBlock;
while (true) {
try {
shouldBlock = true;
for (DispatchChannel dispatchChannel : DispatchChannel.values()) {
this.messageDispatch = _messageQueue[dispatchChannel.getChannelID()].poll();
if (this.messageDispatch != null) {
DispatchMessage.serializeDispatch(this.messageDispatch);
shouldBlock = false;
}
}
if (shouldBlock == true)
shouldBlock = _blockingQueue.take();
} catch (Exception e) {
Logger.error(e);
}
}
}
// For Debugging: // For Debugging:
//Logger.error("MessageDispatcher", messageDispatch.msg.getOpcodeAsString() + " sent to " + messageDispatch.playerList.size() + " players"); //Logger.error("MessageDispatcher", messageDispatch.msg.getOpcodeAsString() + " sent to " + messageDispatch.playerList.size() + " players");
} }

1
src/engine/net/NetMsgFactory.java

@ -12,7 +12,6 @@ package engine.net;
import engine.exception.FactoryBuildException; import engine.exception.FactoryBuildException;
import engine.gameManager.ChatManager; import engine.gameManager.ChatManager;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.Protocol;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.joda.time.DateTime; import org.joda.time.DateTime;

2
src/engine/net/NetMsgStat.java

@ -9,8 +9,6 @@
package engine.net; package engine.net;
import engine.net.client.Protocol;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;

26
src/engine/net/client/Protocol.java → src/engine/net/Protocol.java

@ -1,11 +1,13 @@
package engine.net.client; // • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.net;
/* This class defines Magicbane's application network protocol.
--> Name / Opcode / Message / Handler
*/
import engine.net.AbstractConnection;
import engine.net.ByteBufferReader;
import engine.net.client.handlers.*; import engine.net.client.handlers.*;
import engine.net.client.msg.*; import engine.net.client.msg.*;
import engine.net.client.msg.chat.*; import engine.net.client.msg.chat.*;
@ -18,6 +20,13 @@ import org.pmw.tinylog.Logger;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.util.HashMap; import java.util.HashMap;
// MB Dev Notes:
// This class defines the application network protocol used by SB.
// --> Name / Opcode / Message / Handler
//
// All incoming Protocol messages from the player are managed by the Protocol.class.
// All outgoing Protocol messages to the player are managed through the MessageDispatcher.class.
public enum Protocol { public enum Protocol {
NONE(0x0, null, null), NONE(0x0, null, null),
@ -288,9 +297,7 @@ public enum Protocol {
public static boolean handleClientMsg(ClientNetMsg msg) { public static boolean handleClientMsg(ClientNetMsg msg) {
// Main message handler for Magicbane. All messages // Process incoming Protocol message from client.
// incoming from the client are executed here for
// both the login and world servers.
if (msg == null) if (msg == null)
return false; return false;
@ -342,7 +349,6 @@ public enum Protocol {
} }
} }
public static int FindNextValidOpcode(ByteBufferReader reader) { public static int FindNextValidOpcode(ByteBufferReader reader) {
int startPos = reader.position(); int startPos = reader.position();
int bytesLeft = reader.remaining(); int bytesLeft = reader.remaining();

1
src/engine/net/client/ClientConnection.java

@ -17,6 +17,7 @@ import engine.mbEnums;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.AbstractNetMsg; import engine.net.AbstractNetMsg;
import engine.net.Network; import engine.net.Network;
import engine.net.Protocol;
import engine.net.client.msg.ClientNetMsg; import engine.net.client.msg.ClientNetMsg;
import engine.net.client.msg.login.LoginErrorMsg; import engine.net.client.msg.login.LoginErrorMsg;
import engine.objects.Account; import engine.objects.Account;

2
src/engine/net/client/handlers/AbstractChatMsgHandler.java

@ -10,8 +10,8 @@ package engine.net.client.handlers;
import engine.exception.MsgSendException; import engine.exception.MsgSendException;
import engine.gameManager.ChatManager; import engine.gameManager.ChatManager;
import engine.net.Protocol;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.Protocol;
import engine.net.client.msg.ClientNetMsg; import engine.net.client.msg.ClientNetMsg;
import engine.net.client.msg.chat.*; import engine.net.client.msg.chat.*;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;

7
src/engine/net/client/handlers/DestroyBuildingHandler.java

@ -1,10 +1,10 @@
package engine.net.client.handlers; package engine.net.client.handlers;
import engine.mbEnums;
import engine.mbEnums.BuildingGroup;
import engine.InterestManagement.WorldGrid; import engine.InterestManagement.WorldGrid;
import engine.exception.MsgSendException; import engine.exception.MsgSendException;
import engine.gameManager.BuildingManager; import engine.gameManager.BuildingManager;
import engine.mbEnums;
import engine.mbEnums.BuildingGroup;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.msg.ClientNetMsg; import engine.net.client.msg.ClientNetMsg;
import engine.net.client.msg.DestroyBuildingMsg; import engine.net.client.msg.DestroyBuildingMsg;
@ -91,8 +91,9 @@ public class DestroyBuildingHandler extends AbstractClientMsgHandler {
building.disableSpire(true); building.disableSpire(true);
if (blueprint.getBuildingGroup() == BuildingGroup.WAREHOUSE) { if (blueprint.getBuildingGroup() == BuildingGroup.WAREHOUSE) {
if (city != null) if (city != null)
city.setWarehouseBuildingID(0); city.warehouse = null;
} }
BuildingManager.setRank(building, -1); BuildingManager.setRank(building, -1);

450
src/engine/net/client/handlers/ItemProductionMsgHandler.java

@ -9,12 +9,13 @@
package engine.net.client.handlers; package engine.net.client.handlers;
import engine.exception.MsgSendException; import engine.exception.MsgSendException;
import engine.gameManager.ChatManager; import engine.gameManager.ChatManager;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.gameManager.ForgeManager;
import engine.gameManager.ItemManager;
import engine.loot.WorkOrder;
import engine.mbEnums; import engine.mbEnums;
import engine.mbEnums.GameObjectType;
import engine.mbEnums.ItemType; import engine.mbEnums.ItemType;
import engine.net.Dispatch; import engine.net.Dispatch;
import engine.net.DispatchMessage; import engine.net.DispatchMessage;
@ -32,24 +33,158 @@ import java.util.HashMap;
* @Summary: Processes application protocol message which modifies * @Summary: Processes application protocol message which modifies
* hireling inventory through rolling, junking or depositing. * hireling inventory through rolling, junking or depositing.
*/ */
public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
private static final int ACTION_PRODUCE = 1; public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
private static final int ACTION_JUNK = 2;
private static final int ACTION_RECYCLE = 3;
private static final int ACTION_COMPLETE = 4;
private static final int ACTION_DEPOSIT = 6;
private static final int ACTION_SETPRICE = 5;
private static final int ACTION_TAKE = 7;
private static final int ACTION_CONFIRM_SETPRICE = 9; // Unsure. Sent by client
private static final int ACTION_CONFIRM_DEPOSIT = 10; // Unsure. Sent by client
private static final int ACTION_CONFIRM_TAKE = 11; // Unsure. Sent by client
public ItemProductionMsgHandler() { public ItemProductionMsgHandler() {
super(ItemProductionMsg.class); super(ItemProductionMsg.class);
} }
private static void setItemPrice(int itemType, int itemUUID, int itemPrice, NPC vendor, ClientConnection origin) { @Override
protected boolean _handleNetMsg(ClientNetMsg baseMsg, ClientConnection origin) throws MsgSendException {
// Member variable declaration
PlayerCharacter player;
NPC vendor;
ItemProductionMsg msg;
Dispatch dispatch;
// Member variable assignment
msg = (ItemProductionMsg) baseMsg;
player = origin.getPlayerCharacter();
if (player == null)
return true;
// Grab reference to vendor we are interacting with
vendor = (NPC) DbManager.getObject(mbEnums.GameObjectType.NPC, msg.npcUUID);
// Oops?
if (vendor == null)
return true;
// Process Request
switch (msg.actionType) {
case PRODUCE:
// Create new work order
WorkOrder workOrder = new WorkOrder();
workOrder.total_to_produce = msg.total_to_produce;
workOrder.vendor = vendor;
workOrder.templateID = msg.itemUUID;
workOrder.prefixToken = msg.pToken;
workOrder.suffixToken = msg.sToken;
workOrder.item_name_override = msg.name;
workOrder.multiple_slot_request = (msg.size != 0);
// Submit workOder to begin rolling items
int validation_result = ForgeManager.submit(workOrder);
// workOrder could not be completed
// Report back to the user the reason why
if (validation_result != 0) {
ErrorPopupMsg.sendErrorPopup(player, validation_result);
return true;
}
break;
case JUNK:
junkItem(msg.itemUUID, vendor, origin);
break;
case RECYCLE:
recycleItem(msg.items, vendor, origin);
msg.actionType = mbEnums.ProductionActionType.TAKE;
dispatch = Dispatch.borrow(player, msg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
break;
case COMPLETE:
completeItem(msg.itemUUID, vendor);
break;
case DEPOSIT:
depositItem(msg.itemUUID, vendor, origin);
break;
case SETPRICE:
setItemPrice(msg.itemUUID, msg.itemPrice, vendor, origin);
break;
case TAKE:
takeItem(msg.items, vendor, origin);
dispatch = Dispatch.borrow(player, msg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
break;
}
return true;
}
private static void completeItem(int itemUUID, NPC vendor) {
Item virtualItem = Item.getFromCache(itemUUID);
WorkOrder workOrder = ForgeManager.itemWorkOrderLookup.get(virtualItem);
City city = workOrder.vendor.building.getCity();
city.transactionLock.writeLock().lock();
try {
// Remove virtual item from the vendor rolling window
// (Add / Completed / Remove)
ItemProductionMsg outMsg = new ItemProductionMsg(workOrder.vendor.building, workOrder.vendor, virtualItem, mbEnums.ProductionActionType.CONFIRM_SETPRICE, true);
DispatchMessage.dispatchMsgToInterestArea(workOrder.vendor, outMsg, mbEnums.DispatchChannel.SECONDARY, 700, false, false);
// Remove virtualItem from collections
workOrder.cooking.remove(virtualItem);
ForgeManager.itemWorkOrderLookup.remove(virtualItem);
DbManager.removeFromCache(virtualItem);
workOrder.slots_used = workOrder.slots_used - 1;
// Update workOrder on disk
if (workOrder.cooking.isEmpty()) {
ForgeManager.vendorWorkOrderLookup.get(vendor).remove(workOrder);
DbManager.WarehouseQueries.DELETE_WORKORDER(workOrder);
} else
DbManager.WarehouseQueries.WRITE_WORKORDER(workOrder);
// Persist item and add to vendor inventory
virtualItem.containerType = mbEnums.ItemContainerType.INVENTORY;
Item completedItem = DbManager.ItemQueries.PERSIST(virtualItem);
// Apply Item effects for Prefix and Suffix tokens
completedItem.prefixToken = virtualItem.prefixToken;
completedItem.suffixToken = virtualItem.suffixToken;
ItemManager.applyItemEffects(completedItem);
vendor.charItemManager.addItemToInventory(completedItem);
// Add persisted items to the vendor inventory window
ItemProductionMsg outMsg1 = new ItemProductionMsg(vendor.building, vendor, completedItem, mbEnums.ProductionActionType.DEPOSIT, true);
DispatchMessage.dispatchMsgToInterestArea(vendor, outMsg1, mbEnums.DispatchChannel.SECONDARY, 700, false, false);
ItemProductionMsg outMsg2 = new ItemProductionMsg(vendor.building, vendor, completedItem, mbEnums.ProductionActionType.CONFIRM_DEPOSIT, true);
DispatchMessage.dispatchMsgToInterestArea(vendor, outMsg2, mbEnums.DispatchChannel.SECONDARY, 700, false, false);
} catch (Exception e) {
Logger.error(e);
} finally {
city.transactionLock.writeLock().unlock();
}
}
private static void setItemPrice(int itemUUID, int itemPrice, NPC vendor, ClientConnection origin) {
Item targetItem; Item targetItem;
ItemProductionMsg outMsg; ItemProductionMsg outMsg;
@ -60,48 +195,24 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
if (player == null) if (player == null)
return; return;
if (itemType == GameObjectType.Item.ordinal())
targetItem = Item.getFromCache(itemUUID); targetItem = Item.getFromCache(itemUUID);
else if (itemType == GameObjectType.MobLoot.ordinal())
targetItem = MobLoot.getFromCache(itemUUID);
else
targetItem = null;
if (targetItem == null) if (targetItem == null)
return; return;
if (targetItem.getObjectType() == GameObjectType.Item) {
if (!DbManager.ItemQueries.UPDATE_VALUE(targetItem, itemPrice)) { if (!DbManager.ItemQueries.UPDATE_VALUE(targetItem, itemPrice)) {
ChatManager.chatInfoError(origin.getPlayerCharacter(), "Failed to set price! Contact CCR For help."); ChatManager.chatInfoError(origin.getPlayerCharacter(), "Failed to set price! Contact CCR For help.");
return; return;
} }
targetItem.setValue(itemPrice);
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, ACTION_DEPOSIT, true);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, ACTION_SETPRICE, true);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
} else if (targetItem.getObjectType() == GameObjectType.MobLoot) {
MobLoot mobLoot = (MobLoot) targetItem;
if (!DbManager.NPCQueries.UPDATE_ITEM_PRICE(mobLoot.getObjectUUID(), vendor.getObjectUUID(), itemPrice)) {
ChatManager.chatInfoError(origin.getPlayerCharacter(), "Failed to set price! Contact CCR For help.");
return;
}
targetItem.setValue(itemPrice); targetItem.setValue(itemPrice);
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, ACTION_DEPOSIT, true); outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, mbEnums.ProductionActionType.DEPOSIT, true);
dispatch = Dispatch.borrow(player, outMsg); dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, ACTION_SETPRICE, true); outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, mbEnums.ProductionActionType.SETPRICE, true);
dispatch = Dispatch.borrow(player, outMsg); dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
}
// Set item's price
} }
@ -130,7 +241,6 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
return; return;
if (!vendor.charItemManager.hasRoomInventory(targetItem.template.item_wt)) { if (!vendor.charItemManager.hasRoomInventory(targetItem.template.item_wt)) {
ErrorPopupMsg.sendErrorPopup(player, 21); ErrorPopupMsg.sendErrorPopup(player, 21);
return; return;
} }
@ -157,12 +267,11 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
return; return;
} }
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, mbEnums.ProductionActionType.DEPOSIT, true);
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, ACTION_DEPOSIT, true);
dispatch = Dispatch.borrow(player, outMsg); dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, ACTION_CONFIRM_DEPOSIT, true); outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, mbEnums.ProductionActionType.CONFIRM_DEPOSIT, true);
dispatch = Dispatch.borrow(player, outMsg); dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
@ -172,59 +281,8 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
} finally { } finally {
origin.sellLock.unlock(); origin.sellLock.unlock();
} }
}
}
// Method adds an item from the players inventory to the vendor.
private static void completeItem(int itemUUID, NPC vendor, ClientConnection origin, ItemProductionMsg msg) {
Item targetItem;
ManageNPCMsg outMsg;
Dispatch dispatch;
PlayerCharacter player = origin.getPlayerCharacter();
if (player == null)
return;
if (origin.buyLock.tryLock()) {
try {
targetItem = Item.getFromCache(itemUUID);
if (targetItem == null)
return;
if (!vendor.charItemManager.forgeContains(targetItem, vendor))
return;
boolean worked = DbManager.ItemQueries.UPDATE_FORGE_TO_INVENTORY(targetItem);
if (!worked) {
Guild guild = vendor.getGuild();
if (guild == null)
return;
//ChatManager.chatGuildInfo(guild, "Failed to complete Item " + targetItem.getName());
return;
} }
targetItem.containerType = mbEnums.ItemContainerType.INVENTORY;
targetItem.setOwner(vendor);
vendor.charItemManager.addItemToInventory(targetItem);
vendor.removeItemFromForge(targetItem);
outMsg = new ManageNPCMsg(vendor);
outMsg.setMessageType(ACTION_PRODUCE);
dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
} finally {
origin.buyLock.unlock();
}
}
} }
// Method completes an item that has been previously rolled // Method completes an item that has been previously rolled
@ -235,7 +293,6 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
Item targetItem; Item targetItem;
ItemProductionMsg outMsg; ItemProductionMsg outMsg;
int totalValue = 0; int totalValue = 0;
int currentStrongbox;
Dispatch dispatch; Dispatch dispatch;
if (vendor.getBuilding() == null) if (vendor.getBuilding() == null)
@ -256,12 +313,7 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
for (int itemUUID : itemList.keySet()) { for (int itemUUID : itemList.keySet()) {
int itemValue = 0; int itemValue = 0;
int type = itemList.get(itemUUID);
if (type == GameObjectType.Item.ordinal())
targetItem = Item.getFromCache(itemUUID); targetItem = Item.getFromCache(itemUUID);
else
targetItem = MobLoot.getFromCache(itemUUID);
if (targetItem == null) if (targetItem == null)
continue; continue;
@ -271,7 +323,8 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
if (!vendor.charItemManager.doesCharOwnThisItem(targetItem.getObjectUUID())) if (!vendor.charItemManager.doesCharOwnThisItem(targetItem.getObjectUUID()))
continue; continue;
if (vendor.charItemManager.inventoryContains(targetItem) == false)
if (!vendor.charItemManager.inventoryContains(targetItem))
continue; continue;
itemValue = targetItem.template.item_value; itemValue = targetItem.template.item_value;
@ -288,18 +341,13 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
case REALMCHARTER: case REALMCHARTER:
case SCROLL: case SCROLL:
case POTION: case POTION:
itemValue = 0;
continue; continue;
} }
totalValue += itemValue; totalValue += itemValue;
long start = System.currentTimeMillis();
vendor.charItemManager.recycle(targetItem); vendor.charItemManager.recycle(targetItem);
long end = System.currentTimeMillis();
long timetook = end - start;
// ChatManager.chatSystemInfo(player, "Took " + timetook + " ms to finish");
outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, ACTION_TAKE, true); outMsg = new ItemProductionMsg(vendor.getBuilding(), vendor, targetItem, mbEnums.ProductionActionType.TAKE, true);
dispatch = Dispatch.borrow(origin.getPlayerCharacter(), outMsg); dispatch = Dispatch.borrow(origin.getPlayerCharacter(), outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
@ -307,58 +355,85 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
// Refund a portion of the gold // Refund a portion of the gold
if (!vendor.getBuilding().transferGold(totalValue, false)) vendor.getBuilding().transferGold(totalValue, false);
return;
} catch (Exception e) { } catch (Exception e) {
Logger.error(e); Logger.error(e);
} finally { } finally {
origin.sellLock.unlock(); origin.sellLock.unlock();
} }
} }
// Refresh vendor's inventory to client
} }
// Method handles recycling of an item // Method handles recycling of an item
private static void junkItem(int itemUUID, NPC vendor, ClientConnection origin) { private static void junkItem(int itemUUID, NPC vendor, ClientConnection origin) {
MobLoot targetItem; Item virtualItem;
ManageNPCMsg outMsg; ManageNPCMsg outMsg;
Dispatch dispatch; Dispatch dispatch;
if (origin.sellLock.tryLock()) {
try {
targetItem = MobLoot.getFromCache(itemUUID);
PlayerCharacter player = origin.getPlayerCharacter(); PlayerCharacter player = origin.getPlayerCharacter();
if (player == null) if (player == null)
return; return;
// Can't junk nothing! // Cannot junk items without a forge!
if (targetItem == null) if (vendor.getBuilding() == null)
return; return;
// junk nothing?
if (!vendor.charItemManager.forgeContains(targetItem, vendor)) virtualItem = Item.getFromCache(itemUUID);
if (virtualItem == null)
return; return;
// Cannot junk items without a forge! WorkOrder workOrder = ForgeManager.itemWorkOrderLookup.get(virtualItem);
if (vendor.getBuilding() == null) // If this virtual item was already processed then
// it will have been removed from the workOrder.
if (workOrder == null)
return; return;
// Delete the item and cancel any pending rolling timer jobs if (workOrder.cooking.contains(virtualItem) == false)
return;
;
targetItem.recycle(vendor); City city = workOrder.vendor.building.getCity();
vendor.removeItemFromForge(targetItem);
if (city == null)
return;
city.transactionLock.writeLock().lock();
try {
workOrder.cooking.remove(virtualItem);
DbManager.removeFromCache(virtualItem);
ForgeManager.itemWorkOrderLookup.remove(virtualItem);
// Update total_to_produce accounting for the slot being
// removed while workOrder is not completed.
if (workOrder.runCompleted == false) {
int itemsPerSlot = workOrder.total_to_produce / workOrder.slots_used;
workOrder.total_to_produce = workOrder.total_to_produce - itemsPerSlot;
}
// Slot is no longer allocated to this workOrder.
workOrder.slots_used = workOrder.slots_used - 1;
// Update workOrder on disk
if (workOrder.cooking.isEmpty()) {
ForgeManager.vendorWorkOrderLookup.get(vendor).remove(workOrder);
DbManager.WarehouseQueries.DELETE_WORKORDER(workOrder);
} else
DbManager.WarehouseQueries.WRITE_WORKORDER(workOrder);
// Refresh vendor's inventory to client // Refresh vendor's inventory to client
@ -366,146 +441,43 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
outMsg.setMessageType(1); outMsg.setMessageType(1);
dispatch = Dispatch.borrow(player, outMsg); dispatch = Dispatch.borrow(player, outMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
; } catch (Exception e) {
Logger.error(e);
} finally { } finally {
origin.sellLock.unlock(); city.transactionLock.writeLock().unlock();
}
} }
} }
// Method junks an item that has been rolled but not completed
private static void takeItem(HashMap<Integer, Integer> itemList, NPC vendor, ClientConnection origin) { private static void takeItem(HashMap<Integer, Integer> itemList, NPC vendor, ClientConnection origin) {
Item targetItem; Item targetItem;
PlayerCharacter player = origin.getPlayerCharacter(); PlayerCharacter player = origin.getPlayerCharacter();
if (player == null) if (player == null)
return; return;
for (int itemUUID : itemList.keySet()) { for (int itemUUID : itemList.keySet()) {
int type = itemList.get(itemUUID);
if (type == GameObjectType.Item.ordinal()) {
targetItem = Item.getFromCache(itemUUID); targetItem = Item.getFromCache(itemUUID);
} else {
targetItem = MobLoot.getFromCache(itemUUID);
}
if (targetItem == null) if (targetItem == null)
return; return;
if (targetItem.template.item_type.equals(ItemType.GOLD)) if (targetItem.template.item_type.equals(ItemType.GOLD))
return; return;
if (vendor.charItemManager.inventoryContains(targetItem) == false)
if (!vendor.charItemManager.inventoryContains(targetItem))
return; return;
if (player.charItemManager.hasRoomInventory(targetItem.template.item_wt) == false) if (!player.charItemManager.hasRoomInventory(targetItem.template.item_wt))
return; return;
player.charItemManager.buyFromNPC(targetItem, vendor); player.charItemManager.buyFromNPC(targetItem, vendor);
} }
player.charItemManager.updateInventory(); player.charItemManager.updateInventory();
// Update NPC inventory to client
} }
// Method removes item from an NPC's inventory and transferes it to a player
@Override
protected boolean _handleNetMsg(ClientNetMsg baseMsg, ClientConnection origin) throws MsgSendException {
// Member variable declaration
PlayerCharacter player;
NPC vendorNPC;
ItemProductionMsg msg;
Dispatch dispatch;
// Member variable assignment
msg = (ItemProductionMsg) baseMsg;
player = origin.getPlayerCharacter();
if (player == null)
return true;
// Grab reference to vendor we are interacting with
vendorNPC = (NPC) DbManager.getObject(mbEnums.GameObjectType.NPC, msg.getNpcUUID());
// Oops?
if (vendorNPC == null)
return true;
// Process Request
switch (msg.getActionType()) {
case ACTION_PRODUCE:
boolean isRandom = false;
if (msg.getUnknown03() != 0 && msg.getpToken() == 0 && msg.getsToken() == 0)
isRandom = true;
//Create Multiple Item Function.. Fill all empty slots
if (msg.isMultiple()) {
int emptySlots = vendorNPC.getRank() - vendorNPC.getRolling().size();
if (emptySlots > 0) {
for (int i = 0; i < emptySlots; i++) {
vendorNPC.produceItem(player.getObjectUUID(), msg.getTotalProduction(), isRandom, msg.getpToken(), msg.getsToken(), msg.getName(), msg.getItemUUID());
}
}
} else
vendorNPC.produceItem(player.getObjectUUID(), msg.getTotalProduction(), isRandom, msg.getpToken(), msg.getsToken(), msg.getName(), msg.getItemUUID());
break;
case ACTION_JUNK:
junkItem(msg.getItemUUID(), vendorNPC, origin);
break;
case ACTION_RECYCLE:
recycleItem(msg.getItemIDtoTypeMap(), vendorNPC, origin);
msg.setActionType(7);
dispatch = Dispatch.borrow(player, msg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
break;
case ACTION_COMPLETE:
vendorNPC.completeItem(msg.getItemUUID());
// ManageNPCMsg outMsg = new ManageNPCMsg(vendorNPC);
// outMsg.setMessageType(1);
//
// dispatch = Dispatch.borrow(player, outMsg);
// DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
break;
case ACTION_DEPOSIT:
depositItem(msg.getItemUUID(), vendorNPC, origin);
break;
case ACTION_SETPRICE:
setItemPrice(msg.getItemType(), msg.getItemUUID(), msg.getItemPrice(), vendorNPC, origin);
break;
case ACTION_TAKE:
takeItem(msg.getItemIDtoTypeMap(), vendorNPC, origin);
dispatch = Dispatch.borrow(player, msg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
break;
}
return true;
}
// Method handles rolling item requests from the client
} }

55
src/engine/net/client/handlers/ObjectActionMsgHandler.java

@ -185,62 +185,41 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
case BUCKET: //water bucket case BUCKET: //water bucket
case POTION: //potions, tears of saedron case POTION: //potions, tears of saedron
case SCROLL: //runes, petition, warrant, scrolls case SCROLL: //runes, petition, warrant, scrolls
if (uuid > 3000 && uuid < 3050) { //Discipline Runes if (uuid > 680069 && uuid < 680074) //Handle Charter, Deed, Petition, Warrant here
if (ApplyRuneMsg.applyRune(uuid, origin, player)) {
itemMan.consume(item);
}
break;
} else if (uuid > 249999 && uuid < 250123) { //stat and mastery runes
if (ApplyRuneMsg.applyRune(uuid, origin, player)) {
itemMan.consume(item);
}
break;
} else if (uuid > 250114 && uuid < 250123) { //mastery runes
if (ApplyRuneMsg.applyRune(uuid, origin, player)) {
itemMan.consume(item);
}
break;
} else if (uuid > 252122 && uuid < 252128) { //mastery runes
if (ApplyRuneMsg.applyRune(uuid, origin, player)) {
itemMan.consume(item);
}
break;
} else if (uuid > 680069 && uuid < 680074) //Handle Charter, Deed, Petition, Warrant here
{
break; break;
} else if (uuid > 910010 && uuid < 910019) {
int rank = uuid - 910010; if (item.template.item_bane_rank > 0) {
if (rank < 1 || rank > 8) {
ChatManager.chatSystemError(player, "Invalid Rank for bane scroll!");
return true;
}
// Only one banestone at a time // Only one banestone at a time
lock.writeLock().lock(); lock.writeLock().lock();
try { try {
if (Bane.summonBanestone(player, origin, rank) == true) if (Bane.summonBanestone(player, origin, item.template.item_bane_rank) == true)
itemMan.consume(item); itemMan.consume(item);
} finally { } finally {
lock.writeLock().unlock(); lock.writeLock().unlock();
} }
break; break;
} else if (uuid == 910010) { //tears of saedron
if (comps.size() > 1) {
AbstractCharacter.removeRune(player, origin, comps.get(1).intValue());
} }
if (uuid == 910010) { //tears of saedron
if (comps.size() > 1)
AbstractCharacter.removeRune(player, origin, comps.get(1).intValue());
break; break;
} else if ((byte) item.chargesRemaining > 0) { }
if (item.chargesRemaining > 0) {
ArrayList<Long> tarList = msg.getTargetCompID(); ArrayList<Long> tarList = msg.getTargetCompID();
AbstractWorldObject target = player; AbstractWorldObject target = player;
if (tarList.size() > 1) { if (tarList.size() > 1) {
long tarID = tarList.get(1); long tarID = tarList.get(1);
if (tarID != 0) { if (tarID != 0) {
AbstractGameObject tarAgo = AbstractGameObject.getFromTypeAndID(tarID); AbstractGameObject tarAgo = AbstractGameObject.getFromTypeAndID(tarID);
if (tarAgo != null && tarAgo instanceof AbstractWorldObject) { if (tarAgo instanceof AbstractWorldObject) {
target = (AbstractWorldObject) tarAgo; target = (AbstractWorldObject) tarAgo;
} }
} }
@ -248,8 +227,6 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
// Bypass for waterbuckets // Bypass for waterbuckets
// test character targeted
if (item.template.item_type.equals(mbEnums.ItemType.BUCKET)) { if (item.template.item_type.equals(mbEnums.ItemType.BUCKET)) {
// test for valid target type // test for valid target type
@ -288,6 +265,10 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
player.cancelOnSpell(); player.cancelOnSpell();
break; break;
case RUNE:
ApplyRuneMsg.applyRune(uuid,origin,player);
itemMan.consume(item);
break;
default: //shouldn't be here, consume item default: //shouldn't be here, consume item
dispatch = Dispatch.borrow(player, msg); dispatch = Dispatch.borrow(player, msg);
DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);

2
src/engine/net/client/handlers/PlaceAssetMsgHandler.java

@ -1358,8 +1358,6 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
if (city == null) if (city == null)
return true; return true;
city.setWarehouseBuildingID(newMesh.getObjectUUID());
return true; return true;
} }
} }

12
src/engine/net/client/handlers/ViewResourcesMsgHandler.java

@ -8,9 +8,8 @@
package engine.net.client.handlers; package engine.net.client.handlers;
import engine.mbEnums.DispatchChannel;
import engine.exception.MsgSendException; import engine.exception.MsgSendException;
import engine.gameManager.BuildingManager; import engine.mbEnums.DispatchChannel;
import engine.net.Dispatch; import engine.net.Dispatch;
import engine.net.DispatchMessage; import engine.net.DispatchMessage;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
@ -46,13 +45,16 @@ public class ViewResourcesMsgHandler extends AbstractClientMsgHandler {
if (city == null) if (city == null)
return true; return true;
Building warehouse = BuildingManager.getBuilding(city.getWarehouseBuildingID()); if (city.warehouse == null)
return true;
Building warehouseBuilding = city.warehouse.building;
if (warehouse == null) if (warehouseBuilding == null)
return true; return true;
ViewResourcesMsg vrm = new ViewResourcesMsg(playerCharacter); ViewResourcesMsg vrm = new ViewResourcesMsg(playerCharacter);
vrm.setWarehouseBuilding(warehouse); vrm.setWarehouseBuilding(warehouseBuilding);
vrm.setGuild(playerCharacter.getGuild()); vrm.setGuild(playerCharacter.getGuild());
vrm.configure(); vrm.configure();

2
src/engine/net/client/msg/AbandonAssetMsg.java

@ -13,7 +13,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class AbandonAssetMsg extends ClientNetMsg { public class AbandonAssetMsg extends ClientNetMsg {

2
src/engine/net/client/msg/AcceptFriendMsg.java

@ -9,7 +9,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;

2
src/engine/net/client/msg/AcceptTradeRequestMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.AbstractGameObject; import engine.objects.AbstractGameObject;
/** /**

6
src/engine/net/client/msg/ActivateNPCMessage.java

@ -10,11 +10,7 @@
package engine.net.client.msg; package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.*;
import engine.net.AbstractNetMsg;
import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter;
import engine.net.client.Protocol;
import engine.objects.Item; import engine.objects.Item;
import java.util.ArrayList; import java.util.ArrayList;

2
src/engine/net/client/msg/AddFriendMessage.java

@ -10,7 +10,7 @@ import engine.mbEnums.GameObjectType;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;

2
src/engine/net/client/msg/AddGoldToTradeWindowMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class AddGoldToTradeWindowMsg extends ClientNetMsg { public class AddGoldToTradeWindowMsg extends ClientNetMsg {

2
src/engine/net/client/msg/AddItemToTradeWindowMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.AbstractGameObject; import engine.objects.AbstractGameObject;
public class AddItemToTradeWindowMsg extends ClientNetMsg { public class AddItemToTradeWindowMsg extends ClientNetMsg {

2
src/engine/net/client/msg/AllianceChangeMsg.java

@ -14,7 +14,7 @@ import engine.mbEnums.GameObjectType;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;

2
src/engine/net/client/msg/AllyEnemyListMsg.java

@ -14,7 +14,7 @@ import engine.mbEnums.GameObjectType;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.Guild; import engine.objects.Guild;
import engine.objects.GuildAlliances; import engine.objects.GuildAlliances;
import engine.objects.GuildTag; import engine.objects.GuildTag;

2
src/engine/net/client/msg/ApplyBuildingEffectMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class ApplyBuildingEffectMsg extends ClientNetMsg { public class ApplyBuildingEffectMsg extends ClientNetMsg {

2
src/engine/net/client/msg/ApplyEffectMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.AbstractWorldObject; import engine.objects.AbstractWorldObject;
public class ApplyEffectMsg extends ClientNetMsg { public class ApplyEffectMsg extends ClientNetMsg {

1
src/engine/net/client/msg/ApplyRuneMsg.java

@ -13,7 +13,6 @@ import engine.gameManager.DbManager;
import engine.mbEnums; import engine.mbEnums;
import engine.net.*; import engine.net.*;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.Protocol;
import engine.objects.CharacterRune; import engine.objects.CharacterRune;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import engine.objects.RuneBase; import engine.objects.RuneBase;

2
src/engine/net/client/msg/ArcLoginNotifyMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class ArcLoginNotifyMsg extends ClientNetMsg { public class ArcLoginNotifyMsg extends ClientNetMsg {

2
src/engine/net/client/msg/ArcMineChangeProductionMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class ArcMineChangeProductionMsg extends ClientNetMsg { public class ArcMineChangeProductionMsg extends ClientNetMsg {

2
src/engine/net/client/msg/ArcMineWindowAvailableTimeMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.Building; import engine.objects.Building;
import engine.objects.Guild; import engine.objects.Guild;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;

2
src/engine/net/client/msg/ArcMineWindowChangeMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class ArcMineWindowChangeMsg extends ClientNetMsg { public class ArcMineWindowChangeMsg extends ClientNetMsg {

2
src/engine/net/client/msg/ArcOwnedMinesListMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.Mine; import engine.objects.Mine;
import java.util.ArrayList; import java.util.ArrayList;

2
src/engine/net/client/msg/ArcSiegeSpireMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class ArcSiegeSpireMsg extends ClientNetMsg { public class ArcSiegeSpireMsg extends ClientNetMsg {

2
src/engine/net/client/msg/ArcViewAssetTransactionsMsg.java

@ -16,7 +16,7 @@ import engine.mbEnums.TransactionType;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.*; import engine.objects.*;
import java.util.ArrayList; import java.util.ArrayList;

2
src/engine/net/client/msg/AssetSupportMsg.java

@ -15,7 +15,7 @@ import engine.mbEnums;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;

2
src/engine/net/client/msg/AttackCmdMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class AttackCmdMsg extends ClientNetMsg { public class AttackCmdMsg extends ClientNetMsg {

2
src/engine/net/client/msg/ChangeAltitudeMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
public class ChangeAltitudeMsg extends ClientNetMsg { public class ChangeAltitudeMsg extends ClientNetMsg {

2
src/engine/net/client/msg/ChangeGuildLeaderMsg.java

@ -14,7 +14,7 @@ import engine.mbEnums.GameObjectType;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class ChangeGuildLeaderMsg extends ClientNetMsg { public class ChangeGuildLeaderMsg extends ClientNetMsg {

2
src/engine/net/client/msg/ChatFilterMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class ChatFilterMsg extends ClientNetMsg { public class ChatFilterMsg extends ClientNetMsg {

2
src/engine/net/client/msg/CityAssetMsg.java

@ -17,7 +17,7 @@ import engine.mbEnums.ProtectionState;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.Building; import engine.objects.Building;
import engine.objects.City; import engine.objects.City;
import engine.objects.Zone; import engine.objects.Zone;

6
src/engine/net/client/msg/CityChoiceMsg.java

@ -10,11 +10,7 @@
package engine.net.client.msg; package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.*;
import engine.net.AbstractNetMsg;
import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter;
import engine.net.client.Protocol;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;

6
src/engine/net/client/msg/CityDataMsg.java

@ -11,11 +11,7 @@ package engine.net.client.msg;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.mbEnums; import engine.mbEnums;
import engine.net.AbstractConnection; import engine.net.*;
import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter;
import engine.net.Network;
import engine.net.client.Protocol;
import engine.objects.AbstractGameObject; import engine.objects.AbstractGameObject;
import engine.objects.City; import engine.objects.City;
import engine.objects.Mine; import engine.objects.Mine;

2
src/engine/net/client/msg/CityZoneMsg.java

@ -13,7 +13,7 @@ import engine.mbEnums.GameObjectType;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.Zone; import engine.objects.Zone;
public class CityZoneMsg extends ClientNetMsg { public class CityZoneMsg extends ClientNetMsg {

2
src/engine/net/client/msg/ClaimAssetMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class ClaimAssetMsg extends ClientNetMsg { public class ClaimAssetMsg extends ClientNetMsg {

2
src/engine/net/client/msg/ClaimGuildTreeMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
/** /**

6
src/engine/net/client/msg/ClientNetMsg.java

@ -11,11 +11,7 @@ package engine.net.client.msg;
import engine.exception.SerializationException; import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.*;
import engine.net.AbstractNetMsg;
import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter;
import engine.net.client.Protocol;
public abstract class ClientNetMsg extends AbstractNetMsg { public abstract class ClientNetMsg extends AbstractNetMsg {

2
src/engine/net/client/msg/CloseTradeWindowMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.AbstractGameObject; import engine.objects.AbstractGameObject;
/** /**

2
src/engine/net/client/msg/CommitToTradeMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
/** /**

2
src/engine/net/client/msg/ConfirmPromoteMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class ConfirmPromoteMsg extends ClientNetMsg { public class ConfirmPromoteMsg extends ClientNetMsg {

2
src/engine/net/client/msg/CostOpenBankMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
/** /**

2
src/engine/net/client/msg/DeclineFriendMsg.java

@ -9,7 +9,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;

2
src/engine/net/client/msg/DeleteItemMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class DeleteItemMsg extends ClientNetMsg { public class DeleteItemMsg extends ClientNetMsg {

2
src/engine/net/client/msg/DestroyBuildingMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class DestroyBuildingMsg extends ClientNetMsg { public class DestroyBuildingMsg extends ClientNetMsg {
private int pad = 0; private int pad = 0;

2
src/engine/net/client/msg/DoorTryOpenMsg.java

@ -22,7 +22,7 @@ import engine.mbEnums.GameObjectType;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class DoorTryOpenMsg extends ClientNetMsg { public class DoorTryOpenMsg extends ClientNetMsg {

2
src/engine/net/client/msg/DropGoldMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class DropGoldMsg extends ClientNetMsg { public class DropGoldMsg extends ClientNetMsg {

2
src/engine/net/client/msg/EnterWorldReceivedMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class EnterWorldReceivedMsg extends ClientNetMsg { public class EnterWorldReceivedMsg extends ClientNetMsg {

1
src/engine/net/client/msg/ErrorPopupMsg.java

@ -11,7 +11,6 @@ package engine.net.client.msg;
import engine.mbEnums; import engine.mbEnums;
import engine.net.*; import engine.net.*;
import engine.net.client.Protocol;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
public class ErrorPopupMsg extends ClientNetMsg { public class ErrorPopupMsg extends ClientNetMsg {

2
src/engine/net/client/msg/FriendRequestMsg.java

@ -9,7 +9,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;

4
src/engine/net/client/msg/FurnitureMsg.java

@ -9,13 +9,13 @@
package engine.net.client.msg; package engine.net.client.msg;
import engine.mbEnums.GameObjectType;
import engine.exception.SerializationException; import engine.exception.SerializationException;
import engine.math.Vector3fImmutable; import engine.math.Vector3fImmutable;
import engine.mbEnums.GameObjectType;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class FurnitureMsg extends ClientNetMsg { public class FurnitureMsg extends ClientNetMsg {

2
src/engine/net/client/msg/GoldFromVaultMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
/** /**
* Transfer gold from vault to inventory * Transfer gold from vault to inventory

4
src/engine/net/client/msg/GoldToVaultMsg.java

@ -9,12 +9,12 @@
package engine.net.client.msg; package engine.net.client.msg;
import engine.mbEnums.GameObjectType;
import engine.exception.SerializationException; import engine.exception.SerializationException;
import engine.mbEnums.GameObjectType;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
/** /**
* Transfer gold from inventory to vault * Transfer gold from inventory to vault

2
src/engine/net/client/msg/GrantExperienceMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
public class GrantExperienceMsg extends ClientNetMsg { public class GrantExperienceMsg extends ClientNetMsg {

2
src/engine/net/client/msg/GuildTreeStatusMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.*; import engine.objects.*;
import java.time.LocalDateTime; import java.time.LocalDateTime;

2
src/engine/net/client/msg/HirelingServiceMsg.java

@ -14,7 +14,7 @@ import engine.mbEnums.GameObjectType;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class HirelingServiceMsg extends ClientNetMsg { public class HirelingServiceMsg extends ClientNetMsg {

2
src/engine/net/client/msg/HotzoneChangeMsg.java

@ -15,7 +15,7 @@ import engine.gameManager.ZoneManager;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;

2
src/engine/net/client/msg/IgnoreListMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import java.util.ArrayList; import java.util.ArrayList;

2
src/engine/net/client/msg/IgnoreMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class IgnoreMsg extends ClientNetMsg { public class IgnoreMsg extends ClientNetMsg {

2
src/engine/net/client/msg/InvalidTradeRequestMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.AbstractGameObject; import engine.objects.AbstractGameObject;
/** /**

2
src/engine/net/client/msg/ItemEffectMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.AbstractWorldObject; import engine.objects.AbstractWorldObject;
public class ItemEffectMsg extends ClientNetMsg { public class ItemEffectMsg extends ClientNetMsg {

2
src/engine/net/client/msg/ItemFromVaultMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
/** /**
* Transfer item from Vault to inventory * Transfer item from Vault to inventory

2
src/engine/net/client/msg/ItemHealthUpdateMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class ItemHealthUpdateMsg extends ClientNetMsg { public class ItemHealthUpdateMsg extends ClientNetMsg {

282
src/engine/net/client/msg/ItemProductionMsg.java

@ -10,53 +10,34 @@
package engine.net.client.msg; package engine.net.client.msg;
import engine.gameManager.BuildingManager; import engine.gameManager.BuildingManager;
import engine.gameManager.PowersManager; import engine.gameManager.ForgeManager;
import engine.loot.WorkOrder;
import engine.mbEnums;
import engine.mbEnums.GameObjectType; import engine.mbEnums.GameObjectType;
import engine.net.AbstractConnection; import engine.net.*;
import engine.net.AbstractNetMsg;
import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter;
import engine.net.client.Protocol;
import engine.objects.Building; import engine.objects.Building;
import engine.objects.Item; import engine.objects.Item;
import engine.objects.MobLoot;
import engine.objects.NPC; import engine.objects.NPC;
import engine.powers.EffectsBase;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
public class ItemProductionMsg extends ClientNetMsg { public class ItemProductionMsg extends ClientNetMsg {
private static final int ACTION_PRODUCE = 1; public int size;
private static final int ACTION_JUNK = 2; public int buildingUUID;
private static final int ACTION_RECYCLE = 3; public int unknown01;
private static final int ACTION_COMPLETE = 4; public int itemUUID;
private static final int ACTION_DEPOSIT = 6; public int itemType;
private static final int ACTION_SETPRICE = 5; public int total_to_produce;
private static final int ACTION_TAKE = 7; public int unknown03;
private static final int ACTION_CONFIRM_SETPRICE = 9; public int pToken;
private static final int ACTION_CONFIRM_DEPOSIT = 10; public int sToken;
private static final int ACTION_CONFIRM_TAKE = 11; // Unsure. Sent by client public String name;
private static final int ACTION_CONFIRM_PRODUCE = 8; public mbEnums.ProductionActionType actionType;
public int npcUUID;
private ArrayList<Long> ItemList; public boolean add;
private int size; public int itemPrice;
private int buildingUUID; public HashMap<Integer, Integer> items;
private int unknown01;
private int itemUUID;
private int itemType;
private int totalProduction;
private int unknown03;
private int pToken;
private int sToken;
private String name;
private int actionType;
private int npcUUID;
private boolean add;
private int itemPrice;
private boolean isMultiple;
private HashMap<Integer, Integer> itemIDtoTypeMap;
/** /**
* This is the general purpose constructor. * This is the general purpose constructor.
@ -64,12 +45,12 @@ public class ItemProductionMsg extends ClientNetMsg {
public ItemProductionMsg() { public ItemProductionMsg() {
super(Protocol.ITEMPRODUCTION); super(Protocol.ITEMPRODUCTION);
this.actionType = 0; this.actionType = mbEnums.ProductionActionType.NONE;
this.size = 0; this.size = 0;
this.buildingUUID = 0; this.buildingUUID = 0;
this.unknown01 = 0; this.unknown01 = 0;
this.itemUUID = 0; this.itemUUID = 0;
this.totalProduction = 0; this.total_to_produce = 0;
this.unknown03 = 0; this.unknown03 = 0;
this.pToken = 0; this.pToken = 0;
this.sToken = 0; this.sToken = 0;
@ -79,9 +60,7 @@ public class ItemProductionMsg extends ClientNetMsg {
} }
; public ItemProductionMsg(Building building, NPC vendor, Item item, mbEnums.ProductionActionType actionType, boolean add) {
public ItemProductionMsg(Building building, NPC vendor, Item item, int actionType, boolean add) {
super(Protocol.ITEMPRODUCTION); super(Protocol.ITEMPRODUCTION);
this.actionType = actionType; this.actionType = actionType;
this.size = 0; this.size = 0;
@ -90,7 +69,7 @@ public class ItemProductionMsg extends ClientNetMsg {
this.itemType = item.getObjectType().ordinal(); this.itemType = item.getObjectType().ordinal();
this.itemUUID = item.getObjectUUID(); this.itemUUID = item.getObjectUUID();
this.unknown01 = 0; this.unknown01 = 0;
this.totalProduction = 0; this.total_to_produce = 0;
this.unknown03 = 0; this.unknown03 = 0;
this.pToken = 0; this.pToken = 0;
this.sToken = 0; this.sToken = 0;
@ -130,7 +109,7 @@ public class ItemProductionMsg extends ClientNetMsg {
return; return;
// Common Header // Common Header
writer.putInt(this.actionType); writer.putInt(this.actionType.ordinal());
writer.putInt(GameObjectType.Building.ordinal()); writer.putInt(GameObjectType.Building.ordinal());
writer.putInt(this.buildingUUID); writer.putInt(this.buildingUUID);
writer.putInt(GameObjectType.NPC.ordinal()); writer.putInt(GameObjectType.NPC.ordinal());
@ -138,7 +117,7 @@ public class ItemProductionMsg extends ClientNetMsg {
switch (this.actionType) { switch (this.actionType) {
case ACTION_CONFIRM_DEPOSIT: case CONFIRM_DEPOSIT:
writer.putInt(0); // Not item ordinal? writer.putInt(0); // Not item ordinal?
writer.putInt(0); // Not item uuid? writer.putInt(0); // Not item uuid?
writer.putInt(1); writer.putInt(1);
@ -146,9 +125,13 @@ public class ItemProductionMsg extends ClientNetMsg {
if (!add) { if (!add) {
writer.put((byte) 1); writer.put((byte) 1);
Item item = Item.getFromCache(this.itemUUID);
Item item;
item = Item.getFromCache(this.itemUUID); // Negative ID items not sent here. Deposit virtual item?
if (item != null) if (item != null)
Item.serializeForClientMsgWithoutSlot(item, writer); Item.serializeForClientMsgWithoutSlot(item, writer);
writer.putInt(building.getStrongboxValue()); writer.putInt(building.getStrongboxValue());
writer.putInt(0); writer.putInt(0);
writer.putInt(0); writer.putInt(0);
@ -159,19 +142,18 @@ public class ItemProductionMsg extends ClientNetMsg {
writer.putInt(0); writer.putInt(0);
writer.putInt(0); writer.putInt(0);
writer.put((byte) 1); writer.put((byte) 1);
Item item;
if (this.itemType == GameObjectType.Item.ordinal()) Item item = Item.getFromCache(this.itemUUID);
item = Item.getFromCache(this.itemUUID);
else
item = MobLoot.getFromCache(this.itemUUID);
if (item != null) if (item != null)
Item.serializeForClientMsgWithoutSlot(item, writer); Item.serializeForClientMsgWithoutSlot(item, writer);
writer.putInt(building.getStrongboxValue()); writer.putInt(building.getStrongboxValue());
writer.putInt(0); writer.putInt(0);
writer.putInt(0); writer.putInt(0);
writer.put((byte) 0); writer.put((byte) 0);
break; break;
case ACTION_CONFIRM_TAKE: case CONFIRM_TAKE:
writer.putInt(this.itemType); writer.putInt(this.itemType);
writer.putInt(this.itemUUID); writer.putInt(this.itemUUID);
writer.putInt(1); writer.putInt(1);
@ -183,7 +165,7 @@ public class ItemProductionMsg extends ClientNetMsg {
writer.putInt(0); writer.putInt(0);
writer.put((byte) 0); writer.put((byte) 0);
break; break;
case ACTION_SETPRICE: case SETPRICE:
writer.putInt(this.itemType); writer.putInt(this.itemType);
writer.putInt(this.itemUUID); writer.putInt(this.itemUUID);
writer.putInt(1); writer.putInt(1);
@ -196,7 +178,7 @@ public class ItemProductionMsg extends ClientNetMsg {
writer.putInt(0); writer.putInt(0);
writer.put((byte) 0); writer.put((byte) 0);
break; break;
case ACTION_CONFIRM_SETPRICE: case CONFIRM_SETPRICE:
writer.putInt(this.itemType); writer.putInt(this.itemType);
writer.putInt(this.itemUUID); writer.putInt(this.itemUUID);
writer.putInt(1); writer.putInt(1);
@ -210,7 +192,7 @@ public class ItemProductionMsg extends ClientNetMsg {
writer.putInt(0); writer.putInt(0);
//writer.put((byte) 0); //writer.put((byte) 0);
break; break;
case ACTION_DEPOSIT: case DEPOSIT:
writer.putInt(this.itemType); writer.putInt(this.itemType);
writer.putInt(this.itemUUID); writer.putInt(this.itemUUID);
writer.putInt(1); writer.putInt(1);
@ -222,9 +204,8 @@ public class ItemProductionMsg extends ClientNetMsg {
writer.putInt(0); writer.putInt(0);
writer.put((byte) 0); writer.put((byte) 0);
break; break;
case ACTION_TAKE: case TAKE:
case ACTION_RECYCLE: case RECYCLE:
writer.putInt(0); writer.putInt(0);
writer.putInt(0); writer.putInt(0);
writer.putInt(1); writer.putInt(1);
@ -235,11 +216,11 @@ public class ItemProductionMsg extends ClientNetMsg {
writer.put((byte) 1); writer.put((byte) 1);
writer.putInt(building.getStrongboxValue()); writer.putInt(building.getStrongboxValue());
if (this.itemIDtoTypeMap != null) { if (this.items != null) {
writer.putInt(this.itemIDtoTypeMap.size()); writer.putInt(this.items.size());
for (int itemID : this.itemIDtoTypeMap.keySet()) { for (int itemID : this.items.keySet()) {
writer.putInt(this.itemIDtoTypeMap.get(itemID)); writer.putInt(this.items.get(itemID));
writer.putInt(itemID); writer.putInt(itemID);
} }
@ -249,28 +230,19 @@ public class ItemProductionMsg extends ClientNetMsg {
writer.putInt(0); writer.putInt(0);
break; break;
case ACTION_CONFIRM_PRODUCE: case CONFIRM_PRODUCE:
writer.putInt(0); writer.putInt(0);
writer.putInt(0); writer.putInt(0);
writer.putInt(1); writer.putInt(1);
MobLoot toRoll = MobLoot.getFromCache(this.itemUUID); Item toRoll = Item.getFromCache(this.itemUUID);
writer.putInt(-1497023830); writer.putInt(-1497023830);
if (toRoll != null && toRoll.getPrefix() != null && !toRoll.getPrefix().isEmpty()) {
EffectsBase eb = PowersManager.getEffectByIDString(toRoll.getPrefix());
if (eb == null)
this.pToken = 0;
else
this.pToken = eb.getToken();
}
if (toRoll != null && toRoll.getSuffix() != null && !toRoll.getSuffix().isEmpty()) { WorkOrder workOrder = ForgeManager.itemWorkOrderLookup.get(toRoll);
EffectsBase eb = PowersManager.getEffectByIDString(toRoll.getSuffix());
if (eb == null) this.pToken = toRoll.prefixToken;
this.sToken = 0; this.sToken = toRoll.suffixToken;
else
this.sToken = eb.getToken(); if (toRoll.isComplete() || (workOrder.prefixToken != 0 && workOrder.suffixToken != 0)) {
}
if (toRoll.isRandom() == false || (toRoll != null && toRoll.isComplete())) {
writer.putInt(this.pToken); writer.putInt(this.pToken);
writer.putInt(this.sToken); writer.putInt(this.sToken);
} else { } else {
@ -279,17 +251,12 @@ public class ItemProductionMsg extends ClientNetMsg {
} }
writer.putString(toRoll.name); writer.putString(toRoll.name);
writer.putInt(GameObjectType.MobLoot.ordinal()); writer.putInt(toRoll.getObjectType().ordinal());
writer.putInt(this.itemUUID); writer.putInt(this.itemUUID);
writer.putInt(0); //items left to produce? writer.putInt(0); //items left to produce?
if (toRoll != null) {
writer.putInt(toRoll.templateID); writer.putInt(toRoll.templateID);
writer.putInt(toRoll.getValue()); writer.putInt(toRoll.getValue());
} else {
writer.putInt(0);
writer.putInt(0);
}
NPC vendor = NPC.getFromCache(this.npcUUID); NPC vendor = NPC.getFromCache(this.npcUUID);
if (vendor != null) { if (vendor != null) {
@ -327,10 +294,10 @@ public class ItemProductionMsg extends ClientNetMsg {
//writer.putInt(0); //error popup //writer.putInt(0); //error popup
break; break;
case ACTION_COMPLETE: case COMPLETE:
writer.putInt(this.itemType); writer.putInt(this.itemType);
writer.putInt(this.itemUUID); writer.putInt(this.itemUUID);
writer.putInt(this.totalProduction); writer.putInt(this.total_to_produce);
writer.putInt(this.unknown03); writer.putInt(this.unknown03);
writer.putInt(this.pToken); writer.putInt(this.pToken);
writer.putInt(this.sToken); writer.putInt(this.sToken);
@ -339,10 +306,10 @@ public class ItemProductionMsg extends ClientNetMsg {
writer.putInt(0); writer.putInt(0);
writer.put((byte) 0); writer.put((byte) 0);
break; break;
case ACTION_JUNK: case JUNK:
writer.putInt(this.itemType); writer.putInt(this.itemType);
writer.putInt(this.itemUUID); writer.putInt(this.itemUUID);
writer.putInt(this.totalProduction); writer.putInt(this.total_to_produce);
writer.putInt(this.unknown03); writer.putInt(this.unknown03);
writer.putInt(this.pToken); writer.putInt(this.pToken);
writer.putInt(this.sToken); writer.putInt(this.sToken);
@ -359,7 +326,6 @@ public class ItemProductionMsg extends ClientNetMsg {
writer.putInt(0); writer.putInt(0);
break; break;
} }
} }
/** /**
@ -370,14 +336,14 @@ public class ItemProductionMsg extends ClientNetMsg {
// Common header // Common header
this.actionType = reader.getInt(); this.actionType = mbEnums.ProductionActionType.values()[reader.getInt()];
reader.getInt(); // Building type padding reader.getInt(); // Building type padding
this.buildingUUID = reader.getInt(); this.buildingUUID = reader.getInt();
reader.getInt(); // NPC type padding reader.getInt(); // NPC type padding
this.npcUUID = reader.getInt(); this.npcUUID = reader.getInt();
switch (this.actionType) { switch (this.actionType) {
case ACTION_SETPRICE: case SETPRICE:
this.itemType = reader.getInt(); this.itemType = reader.getInt();
this.itemUUID = reader.getInt(); this.itemUUID = reader.getInt();
reader.getInt(); reader.getInt();
@ -390,8 +356,8 @@ public class ItemProductionMsg extends ClientNetMsg {
reader.getInt(); reader.getInt();
reader.get(); reader.get();
break; break;
case ACTION_RECYCLE: case RECYCLE:
case ACTION_TAKE: case TAKE:
reader.getInt(); reader.getInt();
reader.getInt(); reader.getInt();
reader.getInt(); reader.getInt();
@ -408,9 +374,9 @@ public class ItemProductionMsg extends ClientNetMsg {
tempIDs.put(this.itemUUID, type); tempIDs.put(this.itemUUID, type);
} }
reader.getInt(); reader.getInt();
this.itemIDtoTypeMap = tempIDs; this.items = tempIDs;
break; break;
case ACTION_DEPOSIT: case DEPOSIT:
this.itemType = reader.getInt(); this.itemType = reader.getInt();
this.itemUUID = reader.getInt(); this.itemUUID = reader.getInt();
reader.getInt(); reader.getInt();
@ -422,10 +388,10 @@ public class ItemProductionMsg extends ClientNetMsg {
reader.getInt(); reader.getInt();
reader.get(); reader.get();
break; break;
case ACTION_JUNK: case JUNK:
this.itemType = reader.getInt(); this.itemType = reader.getInt();
this.itemUUID = reader.getInt(); this.itemUUID = reader.getInt();
this.totalProduction = reader.getInt(); this.total_to_produce = reader.getInt();
this.unknown03 = reader.getInt(); this.unknown03 = reader.getInt();
this.pToken = reader.getInt(); this.pToken = reader.getInt();
this.sToken = reader.getInt(); this.sToken = reader.getInt();
@ -437,132 +403,20 @@ public class ItemProductionMsg extends ClientNetMsg {
default: default:
this.itemType = reader.getInt(); this.itemType = reader.getInt();
this.itemUUID = reader.getInt(); this.itemUUID = reader.getInt();
this.totalProduction = reader.getInt(); this.total_to_produce = reader.getInt();
this.unknown03 = reader.getInt(); this.unknown03 = reader.getInt();
this.pToken = reader.getInt(); this.pToken = reader.getInt();
this.sToken = reader.getInt(); this.sToken = reader.getInt();
this.name = reader.getString(); this.name = reader.getString();
this.isMultiple = reader.getInt() != 0 ? true : false; this.size = reader.getInt();
reader.getInt(); reader.getInt();
if (this.actionType == ACTION_COMPLETE || this.actionType == ACTION_JUNK) if (this.actionType == mbEnums.ProductionActionType.COMPLETE || this.actionType == mbEnums.ProductionActionType.JUNK)
reader.get(); reader.get();
else else
reader.getShort(); reader.getShort();
break; break;
}
}
public int getItemType() {
return itemType;
}
// TODO fix ArrayList Accessability.
public ArrayList<Long> getItemList() {
return this.ItemList;
}
public void setItemList(ArrayList<Long> value) {
this.ItemList = value;
}
public void addItem(Long item) {
this.ItemList.add(item);
}
public int getUnknown01() {
return unknown01;
}
public void setUnknown01(int unknown01) {
this.unknown01 = unknown01;
}
public int getTotalProduction() {
return totalProduction;
}
public void setTotalProduction(int unknown02) {
this.totalProduction = unknown02;
}
public int getUnknown03() {
return unknown03;
}
public void setUnknown03(int unknown03) {
this.unknown03 = unknown03;
}
public int getItemUUID() {
return itemUUID;
}
public void setItemUUID(int itemUUID) {
this.itemUUID = itemUUID;
}
public int getpToken() {
return pToken;
}
public void setpToken(int pToken) {
this.pToken = pToken;
}
public int getsToken() {
return sToken;
}
public void setsToken(int sToken) {
this.sToken = sToken;
}
public String getName() {
return name;
} }
public void setName(String name) {
this.name = name;
}
public int getSize() {
return size;
} }
public void setSize(int size) {
this.size = size;
}
public int getActionType() {
return actionType;
}
public final void setActionType(int actionType) {
this.actionType = actionType;
}
public int getNpcUUID() {
return npcUUID;
}
public HashMap<Integer, Integer> getItemIDtoTypeMap() {
return itemIDtoTypeMap;
}
/**
* @return the itemPrice
*/
public int getItemPrice() {
return itemPrice;
}
public boolean isMultiple() {
return isMultiple;
}
public void setMultiple(boolean isMultiple) {
this.isMultiple = isMultiple;
}
} }

2
src/engine/net/client/msg/ItemToVaultMsg.java

@ -14,7 +14,7 @@ import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
/** /**
* Transfer item from inventory to vault * Transfer item from inventory to vault

2
src/engine/net/client/msg/KeepAliveServerClientMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class KeepAliveServerClientMsg extends ClientNetMsg { public class KeepAliveServerClientMsg extends ClientNetMsg {

2
src/engine/net/client/msg/LeaderboardMessage.java

@ -15,7 +15,7 @@ import engine.mbEnums.ShrineType;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
import engine.objects.Building; import engine.objects.Building;
import engine.objects.Guild; import engine.objects.Guild;
import engine.objects.GuildTag; import engine.objects.GuildTag;

2
src/engine/net/client/msg/LeaveWorldMsg.java

@ -13,7 +13,7 @@ package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.Protocol;
public class LeaveWorldMsg extends ClientNetMsg { public class LeaveWorldMsg extends ClientNetMsg {

6
src/engine/net/client/msg/LoadCharacterMsg.java

@ -10,11 +10,7 @@
package engine.net.client.msg; package engine.net.client.msg;
import engine.exception.SerializationException; import engine.exception.SerializationException;
import engine.net.AbstractConnection; import engine.net.*;
import engine.net.AbstractNetMsg;
import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter;
import engine.net.client.Protocol;
import engine.objects.AbstractCharacter; import engine.objects.AbstractCharacter;
import engine.objects.Corpse; import engine.objects.Corpse;

6
src/engine/net/client/msg/LoadStructureMsg.java

@ -10,11 +10,7 @@
package engine.net.client.msg; package engine.net.client.msg;
import engine.net.AbstractConnection; import engine.net.*;
import engine.net.AbstractNetMsg;
import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter;
import engine.net.client.Protocol;
import engine.objects.Building; import engine.objects.Building;
import java.util.ArrayList; import java.util.ArrayList;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save