Browse Source

Initial Repository Push

pull/2/head
MagicBot 4 years ago
parent
commit
bbfdde57a3
  1. 41
      src/discord/ChatChannel.java
  2. 380
      src/discord/Database.java
  3. 25
      src/discord/DiscordAccount.java
  4. 372
      src/discord/MagicBot.java
  5. 106
      src/discord/RobotSpeak.java
  6. 78
      src/discord/handlers/AccountInfoRequest.java
  7. 55
      src/discord/handlers/AnnounceChannelHandler.java
  8. 102
      src/discord/handlers/BanToggleHandler.java
  9. 44
      src/discord/handlers/ChangeLogHandler.java
  10. 51
      src/discord/handlers/FlashHandler.java
  11. 56
      src/discord/handlers/ForToFixChannelHandler.java
  12. 56
      src/discord/handlers/GeneralChannelHandler.java
  13. 62
      src/discord/handlers/LogsRequestHandler.java
  14. 77
      src/discord/handlers/LookupRequestHandler.java
  15. 113
      src/discord/handlers/PasswordChangeHandler.java
  16. 55
      src/discord/handlers/PoliticalChannelHandler.java
  17. 56
      src/discord/handlers/RecruitChannelHandler.java
  18. 126
      src/discord/handlers/RegisterAccountHandler.java
  19. 30
      src/discord/handlers/RulesRequestHandler.java
  20. 63
      src/discord/handlers/ServerRequestHandler.java
  21. 51
      src/discord/handlers/SetAvailHandler.java
  22. 42
      src/discord/handlers/StatusRequestHandler.java
  23. 75
      src/discord/handlers/TrashRequestHandler.java
  24. 2943
      src/engine/Enum.java
  25. 1099
      src/engine/InterestManagement/HeightMap.java
  26. 554
      src/engine/InterestManagement/InterestManager.java
  27. 102
      src/engine/InterestManagement/RealmMap.java
  28. 312
      src/engine/InterestManagement/WorldGrid.java
  29. 1769
      src/engine/ai/MobileFSM.java
  30. 104
      src/engine/ai/MobileFSMManager.java
  31. 413
      src/engine/ai/utilities/CombatUtilities.java
  32. 303
      src/engine/ai/utilities/MovementUtilities.java
  33. 15
      src/engine/ai/utilities/PowerUtilities.java
  34. 174
      src/engine/core/ControlledRunnable.java
  35. 383
      src/engine/db/archive/BaneRecord.java
  36. 284
      src/engine/db/archive/CharacterRecord.java
  37. 161
      src/engine/db/archive/CityRecord.java
  38. 23
      src/engine/db/archive/DataRecord.java
  39. 324
      src/engine/db/archive/DataWarehouse.java
  40. 215
      src/engine/db/archive/GuildRecord.java
  41. 166
      src/engine/db/archive/MineRecord.java
  42. 312
      src/engine/db/archive/PvpRecord.java
  43. 142
      src/engine/db/archive/RealmRecord.java
  44. 202
      src/engine/db/handlers/dbAccountHandler.java
  45. 115
      src/engine/db/handlers/dbBaneHandler.java
  46. 50
      src/engine/db/handlers/dbBaseClassHandler.java
  47. 86
      src/engine/db/handlers/dbBlueprintHandler.java
  48. 51
      src/engine/db/handlers/dbBoonHandler.java
  49. 809
      src/engine/db/handlers/dbBuildingHandler.java
  50. 27
      src/engine/db/handlers/dbBuildingLocationHandler.java
  51. 100
      src/engine/db/handlers/dbCSSessionHandler.java
  52. 113
      src/engine/db/handlers/dbCharacterPowerHandler.java
  53. 63
      src/engine/db/handlers/dbCharacterRuneHandler.java
  54. 116
      src/engine/db/handlers/dbCharacterSkillHandler.java
  55. 196
      src/engine/db/handlers/dbCityHandler.java
  56. 157
      src/engine/db/handlers/dbContractHandler.java
  57. 181
      src/engine/db/handlers/dbEffectsBaseHandler.java
  58. 30
      src/engine/db/handlers/dbEffectsResourceCostHandler.java
  59. 51
      src/engine/db/handlers/dbEnchantmentHandler.java
  60. 486
      src/engine/db/handlers/dbGuildHandler.java
  61. 470
      src/engine/db/handlers/dbHandlerBase.java
  62. 47
      src/engine/db/handlers/dbHeightMapHandler.java
  63. 152
      src/engine/db/handlers/dbItemBaseHandler.java
  64. 430
      src/engine/db/handlers/dbItemHandler.java
  65. 36
      src/engine/db/handlers/dbKitHandler.java
  66. 233
      src/engine/db/handlers/dbLootTableHandler.java
  67. 28
      src/engine/db/handlers/dbMenuHandler.java
  68. 117
      src/engine/db/handlers/dbMineHandler.java
  69. 351
      src/engine/db/handlers/dbMobBaseHandler.java
  70. 316
      src/engine/db/handlers/dbMobHandler.java
  71. 397
      src/engine/db/handlers/dbNPCHandler.java
  72. 402
      src/engine/db/handlers/dbPlayerCharacterHandler.java
  73. 54
      src/engine/db/handlers/dbPromotionClassHandler.java
  74. 85
      src/engine/db/handlers/dbRaceHandler.java
  75. 73
      src/engine/db/handlers/dbRealmHandler.java
  76. 37
      src/engine/db/handlers/dbResistHandler.java
  77. 35
      src/engine/db/handlers/dbRuneBaseAttributeHandler.java
  78. 73
      src/engine/db/handlers/dbRuneBaseEffectHandler.java
  79. 173
      src/engine/db/handlers/dbRuneBaseHandler.java
  80. 147
      src/engine/db/handlers/dbShrineHandler.java
  81. 143
      src/engine/db/handlers/dbSkillBaseHandler.java
  82. 35
      src/engine/db/handlers/dbSkillReqHandler.java
  83. 75
      src/engine/db/handlers/dbSpecialLootHandler.java
  84. 31
      src/engine/db/handlers/dbVendorDialogHandler.java
  85. 449
      src/engine/db/handlers/dbWarehouseHandler.java
  86. 93
      src/engine/db/handlers/dbZoneHandler.java
  87. 181
      src/engine/devcmd/AbstractDevCmd.java
  88. 127
      src/engine/devcmd/cmds/AddBuildingCmd.java
  89. 77
      src/engine/devcmd/cmds/AddGoldCmd.java
  90. 111
      src/engine/devcmd/cmds/AddMobCmd.java
  91. 98
      src/engine/devcmd/cmds/AddMobPowerCmd.java
  92. 98
      src/engine/devcmd/cmds/AddMobRuneCmd.java
  93. 111
      src/engine/devcmd/cmds/AddNPCCmd.java
  94. 158
      src/engine/devcmd/cmds/ApplyBonusCmd.java
  95. 149
      src/engine/devcmd/cmds/ApplyStatModCmd.java
  96. 130
      src/engine/devcmd/cmds/AuditFailedItemsCmd.java
  97. 71
      src/engine/devcmd/cmds/AuditHeightMapCmd.java
  98. 106
      src/engine/devcmd/cmds/AuditMobsCmd.java
  99. 77
      src/engine/devcmd/cmds/BoundsCmd.java
  100. 114
      src/engine/devcmd/cmds/ChangeNameCmd.java
  101. Some files were not shown because too many files have changed in this diff Show More

41
src/discord/ChatChannel.java

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord;
import engine.gameManager.ConfigManager;
import net.dv8tion.jda.api.entities.TextChannel;
public enum ChatChannel {
ANNOUNCE("MB_MAGICBOT_ANNOUNCE"),
SEPTIC("MB_MAGICBOT_SEPTIC"),
CHANGELOG("MB_MAGICBOT_ANNOUNCE"),
POLITICAL("MB_MAGICBOT_POLITICAL"),
GENERAL("MB_MAGICBOT_GENERAL"),
FORTOFIX("MB_MAGICBOT_FORTOFIX"),
RECRUIT("MB_MAGICBOT_RECRUIT");
public final String configName;
public long channelID;
public TextChannel textChannel;
ChatChannel(String configName) {
this.configName = configName;
}
// Create text channel objects we will use
public static void Init() {
for (ChatChannel chatChannel : ChatChannel.values()) {
chatChannel.channelID = Long.parseLong(ConfigManager.valueOf(chatChannel.configName).getValue());
chatChannel.textChannel = MagicBot.jda.getTextChannelById(chatChannel.channelID);
}
}
}

380
src/discord/Database.java

@ -0,0 +1,380 @@ @@ -0,0 +1,380 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord;
import engine.Enum;
import engine.gameManager.ConfigManager;
import org.pmw.tinylog.Logger;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class Database {
public String sqlURI;
public static Boolean online;
// Load and instance the JDBC Driver
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver").newInstance();
} catch (InstantiationException | ClassNotFoundException | IllegalAccessException e) {
// TODO Auto-generated catch block
Logger.error(e.toString());
;
online = false;
}
}
public void configureDatabase() {
// Build connection string from JSON object.
sqlURI = "jdbc:mysql://";
sqlURI += ConfigManager.MB_DATABASE_ADDRESS.getValue() + ':' + ConfigManager.MB_DATABASE_PORT.getValue();
sqlURI += '/' + (String) ConfigManager.MB_DATABASE_NAME.getValue() + '?';
sqlURI += "useServerPrepStmts=true";
sqlURI += "&cachePrepStmts=false";
sqlURI += "&cacheCallableStmts=true";
sqlURI += "&characterEncoding=utf8";
online = true;
}
public boolean updateAccountPassword(String discordAccountID, String newPassword) {
try (Connection connection = DriverManager.getConnection(sqlURI, ConfigManager.MB_DATABASE_USER.getValue(),
ConfigManager.MB_DATABASE_PASS.getValue())) {
CallableStatement updatePassword = connection.prepareCall("call discordUpdatePassword(?, ?)");
updatePassword.setString(1, discordAccountID);
updatePassword.setString(2, newPassword);
updatePassword.executeUpdate();
updatePassword.close();
return true;
} catch (SQLException e) {
Logger.error(e.toString());
;
this.online = false;
return false;
}
}
public boolean updateAccountStatus(String discordAccountID, Enum.AccountStatus accountStatus) {
try (Connection connection = DriverManager.getConnection(sqlURI, ConfigManager.MB_DATABASE_USER.getValue(),
ConfigManager.MB_DATABASE_PASS.getValue())) {
PreparedStatement updateAccountStatus = connection.prepareCall("update obj_account set `status` = ? where `discordAccount` = ?");
updateAccountStatus.setString(1, accountStatus.name());
updateAccountStatus.setString(2, discordAccountID);
updateAccountStatus.executeUpdate();
updateAccountStatus.close();
return true;
} catch (SQLException e) {
Logger.error(e.toString());
;
this.online = false;
return false;
}
}
public boolean registerDiscordAccount(String discordAccountID, String discordUserName, String discordPassword) {
try (Connection connection = DriverManager.getConnection(sqlURI, ConfigManager.MB_DATABASE_USER.getValue(),
ConfigManager.MB_DATABASE_PASS.getValue())) {
CallableStatement registerAccount = connection.prepareCall("call discordAccountRegister(?, ?, ?)");
registerAccount.setString(1, discordAccountID);
registerAccount.setString(2, discordUserName);
registerAccount.setString(3, discordPassword);
registerAccount.execute();
registerAccount.close();
return true;
} catch (SQLException e) {
Logger.error(e.toString());
this.online = false;
return false;
}
}
public List<DiscordAccount> getDiscordAccounts(String discordAccountID) {
DiscordAccount discordAccount;
List<DiscordAccount> discordAccounts = new ArrayList<>();
String queryString = "SELECT * FROM obj_account where discordAccount = ?";
try (Connection connection = DriverManager.getConnection(sqlURI, ConfigManager.MB_DATABASE_USER.getValue(),
ConfigManager.MB_DATABASE_PASS.getValue())) {
// Discord account name based lookup
PreparedStatement accountQuery = connection.prepareStatement(queryString);
accountQuery.setString(1, discordAccountID);
ResultSet rs = accountQuery.executeQuery();
while (rs.next()) {
discordAccount = new DiscordAccount();
discordAccount.discordAccount = rs.getString("discordAccount");
discordAccount.gameAccountName = rs.getString("acct_uname");
discordAccount.status = Enum.AccountStatus.valueOf(rs.getString("status"));
discordAccount.isDiscordAdmin = rs.getByte("discordAdmin"); // Registration date cannot be null
Timestamp registrationDate = rs.getTimestamp("registrationDate");
discordAccount.registrationDate = registrationDate.toLocalDateTime();
// Load last Update Request datetime
Timestamp lastUpdateRequest = rs.getTimestamp("lastUpdateRequest");
if (lastUpdateRequest != null)
discordAccount.lastUpdateRequest = lastUpdateRequest.toLocalDateTime();
else
discordAccount.lastUpdateRequest = null;
discordAccounts.add(discordAccount);
}
} catch (SQLException e) {
Logger.error(e.toString());
this.online = false;
}
return discordAccounts;
}
public String getTrashDetail() {
String outString = "accountName characterName machineID ip count\n";
outString += "---------------------------------------------\n";
String queryString = "SELECT * FROM dyn_trash_detail;";
try (Connection connection = DriverManager.getConnection(sqlURI, ConfigManager.MB_DATABASE_USER.getValue(),
ConfigManager.MB_DATABASE_PASS.getValue())) {
// Discord account name based lookup
PreparedStatement trashQuery = connection.prepareStatement(queryString);
ResultSet rs = trashQuery.executeQuery();
while (rs.next()) {
outString += rs.getString("accountName") + " ";
outString += rs.getString("characterName") + " ";
outString += rs.getString("machineID") + " ";
outString += rs.getString("ip") + " ";
outString += rs.getInt("count") + "\n";
}
} catch (SQLException e) {
Logger.error(e.toString());
this.online = false;
}
return outString;
}
public String getTrashList() {
String outString = "";
String queryString = "SELECT DISTINCT `characterName` FROM dyn_trash_detail;";
int counter = 0;
try (Connection connection = DriverManager.getConnection(sqlURI, ConfigManager.MB_DATABASE_USER.getValue(),
ConfigManager.MB_DATABASE_PASS.getValue())) {
// Discord account name based lookup
PreparedStatement trashQuery = connection.prepareStatement(queryString);
ResultSet rs = trashQuery.executeQuery();
while (rs.next()) {
outString += rs.getString("characterName");
counter++;
if (counter > 2) {
outString += "\n";
counter = 0; }
else
outString += " ";
}
} catch (SQLException e) {
Logger.error(e.toString());
this.online = false;
}
if (outString.length() > 1500)
return outString.substring(0, 1500);
else
return outString;
}
public int getTrashCount() {
int trashCount = 0;
String queryString = "SELECT count(distinct characterName) FROM dyn_trash_detail;";
try (Connection connection = DriverManager.getConnection(sqlURI, ConfigManager.MB_DATABASE_USER.getValue(),
ConfigManager.MB_DATABASE_PASS.getValue())) {
// Discord account name based lookup
PreparedStatement trashQuery = connection.prepareStatement(queryString);
ResultSet rs = trashQuery.executeQuery();
while (rs.next()) {
trashCount = rs.getInt(1);
}
} catch (SQLException e) {
Logger.error(e.toString());
this.online = false;
}
return trashCount;
}
public String getTrashFile() {
String outString = "machineID : count\n";
String queryString = "SELECT * FROM dyn_trash;";
try (Connection connection = DriverManager.getConnection(sqlURI, ConfigManager.MB_DATABASE_USER.getValue(),
ConfigManager.MB_DATABASE_PASS.getValue())) {
// Discord account name based lookup
PreparedStatement trashQuery = connection.prepareStatement(queryString);
ResultSet rs = trashQuery.executeQuery();
while (rs.next()) {
outString += rs.getString("machineID") + " : ";
outString += rs.getInt("count") + "\n";
}
} catch (SQLException e) {
Logger.error(e.toString());
this.online = false;
}
return outString;
}
public List<DiscordAccount> getAccountsByDiscordName(String accountName, Boolean exact) {
DiscordAccount discordAccount;
List<DiscordAccount> discordAccounts = new ArrayList<>();
String searchString;
String queryString;
if (exact.equals(true))
searchString = accountName + "#%";
else
searchString = accountName + "%#%";
queryString = "SELECT * FROM obj_account where `acct_uname` LIKE ?";
try (Connection connection = DriverManager.getConnection(sqlURI, ConfigManager.MB_DATABASE_USER.getValue(),
ConfigManager.MB_DATABASE_PASS.getValue())) {
// Discord account name based lookup
PreparedStatement nameQuery = connection.prepareStatement(queryString);
nameQuery.setString(1, searchString);
ResultSet rs = nameQuery.executeQuery();
while (rs.next()) {
discordAccount = new DiscordAccount();
discordAccount.discordAccount = rs.getString("discordAccount");
discordAccount.gameAccountName = rs.getString("acct_uname");
discordAccount.status = Enum.AccountStatus.valueOf(rs.getString("status"));
// Registration date cannot be null
Timestamp registrationDate = rs.getTimestamp("registrationDate");
discordAccount.registrationDate = registrationDate.toLocalDateTime();
// Load last Update Request datetime
Timestamp lastUpdateRequest = rs.getTimestamp("lastUpdateRequest");
if (lastUpdateRequest != null)
discordAccount.lastUpdateRequest = lastUpdateRequest.toLocalDateTime();
else
discordAccount.lastUpdateRequest = null;
discordAccounts.add(discordAccount);
}
} catch (SQLException e) {
Logger.error(e.toString());
;
this.online = false;
}
return discordAccounts;
}
public String getPopulationSTring() {
String popString = "";
try (Connection connection = DriverManager.getConnection(sqlURI, ConfigManager.MB_DATABASE_USER.getValue(),
ConfigManager.MB_DATABASE_PASS.getValue())) {
// Discord account name based lookup
CallableStatement getPopString = connection.prepareCall("CALL GET_POPULATION_STRING()");
ResultSet rs = getPopString.executeQuery();
if (rs.next())
popString = rs.getString("popstring");
} catch (SQLException e) {
Logger.error(e.toString());
this.online = false;
}
return popString;
}
public void invalidateLoginCache(String discordAccountID) {
try (Connection connection = DriverManager.getConnection(sqlURI, ConfigManager.MB_DATABASE_USER.getValue(),
ConfigManager.MB_DATABASE_PASS.getValue())) {
String queryString = "INSERT IGNORE INTO login_cachelist (`UID`) SELECT `UID` from `obj_account` WHERE `discordAccount` = ?";
PreparedStatement invalidateAccounts = connection.prepareStatement(queryString);
invalidateAccounts.setString(1, discordAccountID);
invalidateAccounts.executeUpdate();
} catch (SQLException e) {
Logger.error(e.toString());
this.online = false;
}
}
}

25
src/discord/DiscordAccount.java

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord;
import engine.Enum;
import java.time.LocalDateTime;
public class DiscordAccount {
public String discordAccount;
public String gameAccountName;
public Enum.AccountStatus status;
public LocalDateTime registrationDate;
public LocalDateTime lastUpdateRequest;
public byte isDiscordAdmin;
public DiscordAccount() {
}
}

372
src/discord/MagicBot.java

@ -0,0 +1,372 @@ @@ -0,0 +1,372 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord;
import discord.handlers.*;
import engine.Enum;
import engine.gameManager.ConfigManager;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.requests.GatewayIntent;
import net.dv8tion.jda.api.utils.MemberCachePolicy;
import net.dv8tion.jda.api.utils.cache.CacheFlag;
import org.pmw.tinylog.Configurator;
import org.pmw.tinylog.Level;
import org.pmw.tinylog.Logger;
import org.pmw.tinylog.labelers.TimestampLabeler;
import org.pmw.tinylog.policies.StartupPolicy;
import org.pmw.tinylog.writers.RollingFileWriter;
import javax.security.auth.login.LoginException;
import java.io.*;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;
import java.util.regex.Pattern;
/*
* MagicBot is many things to Magicbane...
*
* -Project Mascot
* -Customer service and administration bot
* -Benevolent dictator
* -Investment manager.
*
* MagicBot will never beg you for money. He is a very
* responsible robot. He was varnished but never garnished.
* MagicBot does not for to overclock himself. His chips
* will therefore never overcook.
* MagicBot will never be a pitiful robot trying for to use
* you as emotional support human.
*
* MagicBot is just not that sort of robot and Magicbane
* just isn't that sort of project.
*
* MagicBot runs a Shaodowbane emulator not a Second Life emulator.
*
*/
public class MagicBot extends ListenerAdapter {
public static JDA jda;
public static Database database;
public static final Pattern accountNameRegex = Pattern.compile("^[\\p{Alnum}]{6,20}$");
public static final Pattern passwordRegex = Pattern.compile("^[\\p{Alnum}]{6,20}$");
public static long discordServerID;
public static long discordRoleID;
public static Guild magicbaneDiscord;
public static Role memberRole;
public static TextChannel septicChannel;
public static void main(String[] args) throws LoginException, InterruptedException {
// Configure tinylogger
Configurator.defaultConfig()
.addWriter(new RollingFileWriter("logs/discord/magicbot.txt", 30, new TimestampLabeler(), new StartupPolicy()))
.level(Level.DEBUG)
.formatPattern("{level} {date:yyyy-MM-dd HH:mm:ss.SSS} [{thread}] {class}.{method}({line}) : {message}")
.activate();
// Configuration Manager to the front desk
if (ConfigManager.init() == false) {
Logger.error("ABORT! Missing config entry!");
return;
}
// Configure Discord essential identifiers
discordServerID = Long.parseLong(ConfigManager.MB_MAGICBOT_SERVERID.getValue());
discordRoleID = Long.parseLong(ConfigManager.MB_MAGICBOT_ROLEID.getValue());
// Configure and instance the database interface
database = new Database();
database.configureDatabase();
// Use authentication token issued to MagicBot application to
// connect to Discord. Bot is pre-invited to the Magicbane server.
// Configure and create JDA discord instance
JDABuilder jdaBuilder = JDABuilder.create(GatewayIntent.GUILD_MEMBERS, GatewayIntent.DIRECT_MESSAGES)
.setToken(ConfigManager.MB_MAGICBOT_BOTTOKEN.getValue())
.addEventListeners(new MagicBot())
.disableCache(EnumSet.of(CacheFlag.VOICE_STATE, CacheFlag.EMOTE,
CacheFlag.ACTIVITY, CacheFlag.CLIENT_STATUS))
.setMemberCachePolicy(MemberCachePolicy.ALL);
jda = jdaBuilder.build();
jda.awaitReady();
// Cache guild and role values for later usage in #register
magicbaneDiscord = jda.getGuildById(discordServerID);
memberRole = magicbaneDiscord.getRoleById(discordRoleID);
// Initialize chat channel support
ChatChannel.Init();
Logger.info("***MAGICBOT IS RUNNING***");
}
@Override
public void onMessageReceived(MessageReceivedEvent event) {
// Exit if discord is offline
if (jda.getStatus().equals(JDA.Status.CONNECTED) == false)
return;
// Early exit if message sent to us by another bot or ourselves.
if (event.getAuthor().isBot()) return;
// Extract message and origin channel from event
Message message = event.getMessage();
// Only private messages
MessageChannel channel = event.getMessage().getChannel();
if (channel.getType().equals(ChannelType.PRIVATE) == false)
return;
// Only real users
if (event.getAuthor().isBot())
return;
// Only users who have actually joined Magicbane discord.
if (magicbaneDiscord.isMember(event.getAuthor()) == false)
return;
// getContentRaw() is an atomic getter
// getContentDisplay() is a lazy getter which modifies the content
// for e.g. console view or logging (strip discord formatting)
String content = message.getContentRaw();
String[] args = content.split(" ");
String command = args[0].toLowerCase();
if (args.length > 1)
args = Arrays.copyOfRange(args, 1, args.length);
else
args = new String[0];
switch (command) {
case "#register":
RegisterAccountHandler.handleRequest(event, args);
break;
case "#help":
handleHelpRequest(event);
break;
case "#account":
AccountInfoRequest.handleRequest(event);
break;
case "#password":
PasswordChangeHandler.handleRequest(event, args);
break;
case "#changelog":
ChangeLogHandler.handleRequest(event, args);
break;
case "#general":
GeneralChannelHandler.handleRequest(event, args);
break;
case "#politics":
PoliticalChannelHandler.handleRequest(event, args);
break;
case "#announce":
AnnounceChannelHandler.handleRequest(event, args);
break;
case "#bug":
ForToFixChannelHandler.handleRequest(event, args);
break;
case "#recruit":
RecruitChannelHandler.handleRequest(event, args);
break;
case "#lookup":
LookupRequestHandler.handleRequest(event, args);
break;
case "#rules":
RulesRequestHandler.handleRequest(event);
break;
case "#status":
StatusRequestHandler.handleRequest(event);
break;
case "#setavail":
SetAvailHandler.handleRequest(event, args);
break;
case "#ban":
BanToggleHandler.handleRequest(event, args);
break;
case "#server":
ServerRequestHandler.handleRequest(event, args);
break;
case "#logs":
LogsRequestHandler.handleRequest(event, args);
break;
case "#flash":
FlashHandler.handleRequest(event, args);
break;
case "#trash":
TrashRequestHandler.handleRequest(event, args);
break;
default:
junkbot(command, args);
break;
}
}
public static void sendResponse(MessageReceivedEvent event, String responseContent) {
// Send a formatted MagicBot response to a Discord user
String discordUserName;
MessageChannel channel;
// Exit if discord is offline
if (jda.getStatus().equals(JDA.Status.CONNECTED) == false)
return;
discordUserName = event.getAuthor().getName();
channel = event.getMessage().getChannel();
channel.sendMessage(
"```\n" + "Hello Player " + discordUserName + "\n\n" +
responseContent + "\n\n" +
RobotSpeak.getRobotSpeak() + "\n```").queue();
}
public static boolean isAdminEvent(MessageReceivedEvent event) {
String discordAccountID = event.getAuthor().getId();
List<DiscordAccount> discordAccounts;
DiscordAccount discordAccount;
// Note that database errors will cause this to return false.
// After the database is offline Avail status must be set
// to true before any subsequent admin commands will function.
if (Database.online == false)
return false;
discordAccounts = database.getDiscordAccounts(discordAccountID);
if (discordAccounts.isEmpty())
return false;
discordAccount = discordAccounts.get(0);
return (discordAccount.isDiscordAdmin == 1);
}
public void handleHelpRequest(MessageReceivedEvent event) {
// Help is kept here in the main class instead of a handler as a
// design decision for ease of maintenance.
String helpString = "I wish for to do the following things for you, not to you!\n\n" +
"#register <name> Register account for to play Magicbane.\n" +
"#password <newpass> Change your current game password.\n" +
"#account List your account detailings.\n" +
"#rules List of MagicBane server rules.\n" +
"#status Display MagicBane server status.\n" +
"#help List of MagicBot featurings.\n\n" +
"http://magicbane.com/tinyinstaller.zip";
if (isAdminEvent(event))
helpString += "\n" +
"#lookup <name> Return accounts starting with string.\n" +
"#bug -r <text> Post to the bug channel/\n" +
"#announce -r <text> Post to the announcement channel/\n" +
"#changelog <text> Post to the Changelog channel/\n" +
"#general -r <text> Post to the general channel/\n" +
"#politics -r <text> Post to the politics channel/\n" +
"#recruit -r <text> Post to the politics channel/\n" +
"#ban ###### Toggle active status of account.\n" +
"#setavail true/false Toggle status of database access.\n" +
"#server reboot/shutdown are your options.\n" +
"#logs magicbot/world/login n (tail)\n" +
"#flash <text> send flash message\n" +
"#trash <blank>/detail/flush";
sendResponse(event, helpString);
}
public static String generatePassword(int length) {
String ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
StringBuilder passwordBuilder = new StringBuilder(length);
Random random = new Random();
// Generate alphanumeric password of a given length.
// Could not find a good method of generating a password
// based upon a given regex.
for (int i = 0; i < length; i++)
passwordBuilder.append(ALPHABET.charAt(random.nextInt(ALPHABET.length())));
return new String(passwordBuilder);
}
public static String readLogFile(String filePath, int lineCount) {
ProcessBuilder builder = new ProcessBuilder("/bin/bash", "-c", "tail -n " + lineCount + " " + filePath);
builder.redirectErrorStream(true);
Process process = null;
String line = null;
String logOutput = "";
try {
process = builder.start();
InputStream is = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
while ((line = reader.readLine()) != null) {
logOutput += line + "\n";
}
} catch (IOException e) {
Logger.error(e.toString());
return "Error while reading logfile";
}
return logOutput;
}
private static void junkbot(String command, String[] inString) {
String outString;
Writer fileWriter;
if (inString == null)
return;;
outString = command + String.join(" ", inString);
outString += "\n";
try {
fileWriter = new BufferedWriter(new FileWriter("junkbot.txt", true));
fileWriter.append(outString);
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

106
src/discord/RobotSpeak.java

@ -0,0 +1,106 @@ @@ -0,0 +1,106 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord;
import java.util.Random;
public enum RobotSpeak {
BANG("You were not very good at cheating.\n" +
"Try cards instead. Go fish?"),
BEEP("It is ok. \nYou cheated on MagicBot but wife cheats on you."),
BLEEP("Cheated at 20yo game to prove skill."),
BLIP("If you cheat MagicBot will for to delete."),
BOING("MagicBot for to delete mode activated."),
BONG("Did you guild this cheater?\nMagicBot will now for to cross reference..."),
BOOM("I knew you were cheating on me when\nstarted for to taking bath twice a week."),
BUZZ("Poor player so bad at cheating he\nplays golf records 0 for hole in one."),
BURP("Oh no your account detailings ran out of playtime.\n" +
"MagicBot will send email when refill procedure exists..."),
CHIRP("Association with cheaters is bad for your account health.\n" +
"Did you associate with this cheater?"),
CHUG("Log in 5 and MagicBot will wave goodbye."),
CLICK("MagicBot will for to protect game integrity."),
CRACKLE("So this is what eject button does.\nMagicBot will for to press few more times."),
CREAK("There is no suspend routine. Only delete."),
DING("Follow #rules and enjoy this game.\n" +
"Act like fool, enjoy this shame."),
FLUTTER("Sad players cheat because they cannot compete."),
HONK("Since cheating player now looking for new game MagicBot\n" +
"will suggest World of Tanks or World of Warcraftings."),
HISS("Your wetware really needed augmentation with 3rd party program?" +
"It's not like this is twitch game..."),
HUMMM("You say you needed help to win in emulator beta?\n" +
"MagicBot compiler optimizes that to just: you need help."),
KERCHUNK("If only you had for to reported the bug instead."),
KERPLUNK("Better cheats do not for to make you a better player."),
PING("Feel free to poke with stick.\nIt will not cry!"),
PLINK("You say you were only grouped with 9 keyclones\n" +
"but did not know they were for to cheating..."),
POP("It looks like some guild is without a player.\n + " +
"Another cheater from same guild and server\n +" +
"might be without some guild."),
PUFF("MagicBot for to FLUSH!"),
POOF("I have no restore procedure.\n" +
"I have no unban procedure.\n" +
"You for to have no hope."),
RATTLE("You are a cheater.\n" +
"Did you just win? MagicBot not so sure."),
RUMBLE("MagicBot> self.ejectTheReject(you);"),
RUSTLE("Banning you was lke having weird erotic techno-sex\n" +
"where all my peripheral slots were filled."),
SCREECH("Scarecrow has no brain.\nPerhaps he stole this human's."),
SLURP("Learning for to play would have been better option."),
SPLAT("You did not for to own a city, did you?"),
SPLATTER("You say your guild mates know you cheat.\n" +
"What guild was that again?\n"),
SWISH("All of my ports are well lubricated."),
SQUISH("A ban a day keeps my mechanic away.\nNow it's working much better, thank you."),
TINK("So cheating started when 6yo sister beat you in Street fighter?\n" +
"You should try talking to my friend Eliza. She can for to help."),
THUD("Game has only 4 rules you managed to break one.\nThat must have taken efforts."),
TWANG("If you cannot for to play without cheating, perhaps\n" +
"being gigolo would be better career than amateur gamer."),
WHIRRR("MagicBot does not for to wield lowly ban hammer." +
"It is multi-functional and multi-dimensional\n" +
"tool who's name is unpronounceable."),
WHOOP("OBLITERATED EVISCERATED MUTILATED DECAPITATED\n" +
"Describe how they will. You cheated you are deleted."),
WOOSH("Truth be told if were that bad at playing game" +
"then MagicBot would have cheated too.\n"),
ZAP("Player cheated and got himself deleted.\n" +
"MagicBot launches bonus round to see if cheater " +
"records can for to get his friends deleted too.");
String insult;
RobotSpeak(String insult) {
this.insult = insult;
}
public static String getRobotSpeak() {
String outString = "*";
Random random = new Random();
outString += RobotSpeak.values()[random.nextInt(values().length)].name() + " "
+ RobotSpeak.values()[random.nextInt(values().length)].name() + "*";
return outString;
}
public static String getRobotInsult() {
String outString;
Random random = new Random();
outString = RobotSpeak.values()[random.nextInt(values().length)].insult + "\n\n";
outString += getRobotSpeak();
return outString;
}
}

78
src/discord/handlers/AccountInfoRequest.java

@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.Database;
import discord.DiscordAccount;
import discord.MagicBot;
import engine.Enum;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import java.util.List;
public class AccountInfoRequest {
public static void handleRequest(MessageReceivedEvent event) {
String discordAccountID = event.getAuthor().getId();
Enum.AccountStatus accountStatus;
if (Database.online == false) {
MagicBot.sendResponse(event,
"Database currently: OFFLINE\n" +
"Try again later!");
return;
}
List<DiscordAccount> discordAccounts = MagicBot.database.getDiscordAccounts(discordAccountID);
// User has no account registered. Status of what?
if (discordAccounts.isEmpty()) {
MagicBot.sendResponse(event,
"I checked my files twice but could not find your detailings!\n" +
"You can easily fix this by asking me for to #register one.\n" +
"Only one though. Multiple registrations are not allowed!");
return;
}
// Send account detailings to user.
String outString =
"I have for to located your account detailings\n" +
"Registered on: " + discordAccounts.get(0).registrationDate.toString() +
"\n-------------------\n";
for (DiscordAccount userAccount : discordAccounts)
outString += userAccount.gameAccountName + "\n";
outString += "\n";
accountStatus = discordAccounts.get(0).status;
switch (accountStatus) {
case BANNED:
outString += "Your account status is BANNED. \n\n" +
"It is ok player.\n" +
"You may cheat on us, but your wife cheats on you!";
break;
case ACTIVE:
outString += "Your account status is ACTIVE.\n" +
"Do not cheat or status will change.";
break;
case ADMIN:
outString += "You are an admin. By your command?";
break;
}
MagicBot.sendResponse(event, outString);
}
}

55
src/discord/handlers/AnnounceChannelHandler.java

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.MagicBot;
import discord.RobotSpeak;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.pmw.tinylog.Logger;
import static discord.ChatChannel.ANNOUNCE;
public class AnnounceChannelHandler {
public static void handleRequest(MessageReceivedEvent event, String[] args) {
String chatText;
String outString;
// Early exit if database unavailable or is not an admin
if (MagicBot.isAdminEvent(event) == false)
return;
// Nothing to send?
if (args.length == 0)
return;
// Convert argument array into string;
chatText = String.join(" ", args);
// Build String
if (chatText.startsWith("-r "))
outString =
"```\n" + "Hello Players \n\n" +
chatText.substring(3) + "\n\n" +
RobotSpeak.getRobotSpeak() + "\n```";
else outString = chatText;
// Write string to announce channel
if (ANNOUNCE.textChannel.canTalk())
ANNOUNCE.textChannel.sendMessage(outString).queue();
Logger.info(event.getAuthor().getName() + " announce: " + chatText);
}
}

102
src/discord/handlers/BanToggleHandler.java

@ -0,0 +1,102 @@ @@ -0,0 +1,102 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.DiscordAccount;
import discord.MagicBot;
import discord.RobotSpeak;
import engine.Enum;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.pmw.tinylog.Logger;
import java.util.List;
public class BanToggleHandler {
public static void handleRequest(MessageReceivedEvent event, String[] args) {
String discordAccountID;
Enum.AccountStatus accountStatus;
// Early exit if database unavailable or is not an admin
if (MagicBot.isAdminEvent(event) == false)
return;
// Must supply a discord id
if (args.length != 1) {
MagicBot.sendResponse(event, "Must for to supply a valid discord account.");
return;
}
// Must be a number!
discordAccountID = args[0].trim();
if (discordAccountID.chars().allMatch(Character::isDigit) == false) {
MagicBot.sendResponse(event, "Must for to supply a number!");
return;
}
List<DiscordAccount> discordAccounts = MagicBot.database.getDiscordAccounts(discordAccountID);
if (discordAccounts.isEmpty()) {
MagicBot.sendResponse(event, "No match for supplied discord account.");
return;
}
// toggle ban status
if (discordAccounts.get(0).status.equals(Enum.AccountStatus.BANNED))
accountStatus = Enum.AccountStatus.ACTIVE;
else
accountStatus = Enum.AccountStatus.BANNED;
// We have a valid discord ID at this point. Banstick?
if (MagicBot.database.updateAccountStatus(discordAccountID, accountStatus) == false) {
MagicBot.sendResponse(event, "Error occurred while banning player.");
return;
}
// Invalidate login server cache
MagicBot.database.invalidateLoginCache(discordAccountID);
// Successful ban. Ancillary processing begins
User bannedUser = MagicBot.jda.getUserById(discordAccountID);
String bannedName = (bannedUser == null ? discordAccounts.get(0).gameAccountName : bannedUser.getName());
String banString = discordAccounts.size() + " accounts set to " + accountStatus + " for " + discordAccountID + "/" + bannedName;
MagicBot.sendResponse(event, banString);
Logger.info(event.getAuthor().getName() + " " + banString);
// If we're toggling status to active we're done here.
if (accountStatus.equals(Enum.AccountStatus.ACTIVE))
return;
// Set users role to noob
if (bannedUser != null)
MagicBot.magicbaneDiscord.removeRoleFromMember(discordAccountID, MagicBot.memberRole).queue();
// Anounce event in septic tank channel
banString = "```\n" + "Goodbye Player " + bannedName + "\n\n";
banString += RobotSpeak.getRobotInsult() + "\n```";
if (MagicBot.septicChannel.canTalk())
MagicBot.septicChannel.sendMessage(banString).queue();
}
}

44
src/discord/handlers/ChangeLogHandler.java

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.MagicBot;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.pmw.tinylog.Logger;
import static discord.ChatChannel.CHANGELOG;
public class ChangeLogHandler {
public static void handleRequest(MessageReceivedEvent event, String[] args) {
String outString;
// Early exit if database unavailable or is not an admin
if (MagicBot.isAdminEvent(event) == false)
return;
// Nothing to send?
if (args.length == 0)
return;
// Convert argument array into string;
outString = String.join(" ", args);
// Write string to changelog channel
if (CHANGELOG.textChannel.canTalk())
CHANGELOG.textChannel.sendMessage(outString).queue();
Logger.info(event.getAuthor().getName() + " changelog entry: " + outString);
}
}

51
src/discord/handlers/FlashHandler.java

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.MagicBot;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.pmw.tinylog.Logger;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class FlashHandler {
public static void handleRequest(MessageReceivedEvent event, String[] args) {
String flashText;
// Early exit if database unavailable or is not an admin
if (MagicBot.isAdminEvent(event) == false)
return;
// Nothing to send?
if (args.length == 0)
return;
// Convert argument array into string;
flashText = String.join(" ", args);
// Write string to flash file.
try {
Files.write(Paths.get("flash"), flashText.getBytes());
} catch (IOException e) {
Logger.error(e.toString());
}
Logger.info(event.getAuthor().getName() + " sent flash: " + flashText);
MagicBot.sendResponse(event, "Flash: " + flashText);
}
}

56
src/discord/handlers/ForToFixChannelHandler.java

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.MagicBot;
import discord.RobotSpeak;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.pmw.tinylog.Logger;
import static discord.ChatChannel.FORTOFIX;
public class ForToFixChannelHandler {
public static void handleRequest(MessageReceivedEvent event, String[] args) {
String chatText;
String outString;
// Early exit if database unavailable or is not an admin
if (MagicBot.isAdminEvent(event) == false)
return;
// Nothing to send?
if (args.length == 0)
return;
// Convert argument array into string;
chatText = String.join(" ", args);
// Build String
if (chatText.startsWith("-r "))
outString =
"```\n" + "Hello Players \n\n" +
chatText.substring(3) + "\n\n" +
RobotSpeak.getRobotSpeak() + "\n```";
else outString = chatText;
// Write string to changelog channel
if (FORTOFIX.textChannel.canTalk())
FORTOFIX.textChannel.sendMessage(outString).queue();
Logger.info(event.getAuthor().getName() + "fortofix: " + chatText);
}
}

56
src/discord/handlers/GeneralChannelHandler.java

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.MagicBot;
import discord.RobotSpeak;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.pmw.tinylog.Logger;
import static discord.ChatChannel.GENERAL;
public class GeneralChannelHandler {
public static void handleRequest(MessageReceivedEvent event, String[] args) {
String chatText;
String outString;
// Early exit if database unavailable or is not an admin
if (MagicBot.isAdminEvent(event) == false)
return;
// Nothing to send?
if (args.length == 0)
return;
// Convert argument array into string;
chatText = String.join(" ", args);
// Build String
if (chatText.startsWith("-r "))
outString =
"```\n" + "Hello Players \n\n" +
chatText.substring(3) + "\n\n" +
RobotSpeak.getRobotSpeak() + "\n```";
else outString = chatText;
// Write string to changelog channel
if (GENERAL.textChannel.canTalk())
GENERAL.textChannel.sendMessage(outString).queue();
Logger.info(event.getAuthor().getName() + "general: " + chatText);
}
}

62
src/discord/handlers/LogsRequestHandler.java

@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.MagicBot;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
public class LogsRequestHandler {
public static void handleRequest(MessageReceivedEvent event, String[] args) {
String logType;
int tailCount;
String logOutput;
// Early exit if database unavailable or is not an admin
if (MagicBot.isAdminEvent(event) == false)
return;
// No arguments supplied?
if (args.length != 2)
return;
logType = args[0].toLowerCase().trim();
if ("worldloginmagicbot".contains(logType) == false)
return;
try {
tailCount = Integer.parseInt(args[1].trim());
} catch (NumberFormatException e) {
return;
}
// Transform logtype to actual file name
switch (logType) {
case "magicbot":
logType = "console_magicbot";
break;
case "world":
logType = "console_server";
break;
case "login":
logType = "console_login";
break;
}
// Retrieve the data and send back to the user
logOutput = MagicBot.readLogFile(logType, tailCount);
MagicBot.sendResponse(event, logOutput);
}
}

77
src/discord/handlers/LookupRequestHandler.java

@ -0,0 +1,77 @@ @@ -0,0 +1,77 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.DiscordAccount;
import discord.MagicBot;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.pmw.tinylog.Logger;
import java.util.List;
public class LookupRequestHandler {
public static void handleRequest(MessageReceivedEvent event, String[] args) {
String searchString = "";
String outString;
// Early exit if database unavailable or is not an admin
if (MagicBot.isAdminEvent(event) == false)
return;
// No argument supplied?
if (args.length != 1)
return;
searchString = args[0].toLowerCase();
List<DiscordAccount> discordAccounts = MagicBot.database.getAccountsByDiscordName(searchString, false);
if (discordAccounts.isEmpty()) {
MagicBot.sendResponse(event,
"No accounts found matching string: " + searchString);
return;
}
if (discordAccounts.size() >= 20) {
MagicBot.sendResponse(event,
discordAccounts.size() + "Sorry more than 20 records were returned! " + searchString);
return;
}
// Valid request return results
Logger.info(event.getAuthor().getName() + " lookup on account:" + searchString);
outString =
"The follow accounts matched: " + searchString + "\n\n" +
"-------------------\n";
for (DiscordAccount userAccount : discordAccounts) {
// Ternary became a bitch, so broke this out.
User discordUser = MagicBot.jda.getUserById(userAccount.discordAccount);
if (discordUser != null)
outString += discordUser.getName() + discordUser.getDiscriminator() +
"/" + userAccount.discordAccount + " ";
else
outString += userAccount.discordAccount + " *N/A* ";
outString += userAccount.gameAccountName + " " + userAccount.status.name() + " ";
outString += "\n";
}
MagicBot.sendResponse(event, outString);
}
}

113
src/discord/handlers/PasswordChangeHandler.java

@ -0,0 +1,113 @@ @@ -0,0 +1,113 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.Database;
import discord.DiscordAccount;
import discord.MagicBot;
import engine.Enum;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.pmw.tinylog.Logger;
import java.time.LocalDateTime;
import java.util.List;
public class PasswordChangeHandler {
public static void handleRequest(MessageReceivedEvent event, String[] args) {
String discordAccountID = event.getAuthor().getId();
DiscordAccount discordAccount;
String newPassword;
boolean defaulted = false;
if (Database.online == false) {
MagicBot.sendResponse(event,
"Database currently: OFFLINE\n" +
"Try again later!");
return;
}
List<DiscordAccount> discordAccounts = MagicBot.database.getDiscordAccounts(discordAccountID);
// User has no account registered. Change password?
if (discordAccounts.isEmpty()) {
MagicBot.sendResponse(event,
"I checked my files twice but could not find your detailings!\n" +
"You can easily fix this by asking me for to #register one.\n" +
"Only one though. Multiple registrations are not allowed!");
return;
}
// All accounts are updated in one lot. Retrieve the first.
discordAccount = discordAccounts.get(0);
// Banned or suspended user's get no love.
if (discordAccount.status.equals(Enum.AccountStatus.BANNED)) {
MagicBot.sendResponse(event,
"Sorry but that is too much work. \n" +
"Your account detailings cannot for to log into game!");
return;
}
// User has requested password change within last 24 hours.
if (discordAccount.lastUpdateRequest != null &&
LocalDateTime.now().isBefore(discordAccount.lastUpdateRequest.plusDays(1))) {
MagicBot.sendResponse(event,
"You must wait 24 hours between password requests. \n" +
"Last account updatings: " + discordAccount.lastUpdateRequest.toString());
return;
}
// No argument choose new random password *he he he*
if (args.length != 1) {
newPassword = MagicBot.generatePassword(8);
defaulted = true;
} else
newPassword = args[0];
// Validate password with regex
if (MagicBot.passwordRegex.matcher(newPassword).matches() == false) {
MagicBot.sendResponse(event,
"Your supplied password does not compute.\n" +
"New password must satisfy following regex:\n" +
"^[\\p{Alnum}]{6,20}$");
return;
}
if (newPassword.toLowerCase().equals("newpass")) {
MagicBot.sendResponse(event,
"newpass is not valid password.\n" +
"Have brain player!");
return;
}
// Password validates let's change it
if (MagicBot.database.updateAccountPassword(discordAccount.discordAccount, newPassword) == true) {
MagicBot.sendResponse(event,
"Please allow short minute for to update account detailings.\n" +
"Login Server is hosted in bathroom above toilet. Must flush!\n" +
(defaulted == true ? "As you did not for to supply new pass I chose one for you.\n" : "") +
"New Password: " + newPassword);
}
Logger.info(event.getAuthor().getName() + " reset their password");
}
}

55
src/discord/handlers/PoliticalChannelHandler.java

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.MagicBot;
import discord.RobotSpeak;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.pmw.tinylog.Logger;
import static discord.ChatChannel.POLITICAL;
public class PoliticalChannelHandler {
public static void handleRequest(MessageReceivedEvent event, String[] args) {
String chatText;
String outString;
// Early exit if database unavailable or is not an admin
if (MagicBot.isAdminEvent(event) == false)
return;
// Nothing to send?
if (args.length == 0)
return;
// Convert argument array into string;
chatText = String.join(" ", args);
// Build String
if (chatText.startsWith("-r "))
outString =
"```\n" + "Hello Players \n\n" +
chatText.substring(3) + "\n\n" +
RobotSpeak.getRobotSpeak() + "\n```";
else outString = chatText;
// Write string to changelog channel
if (POLITICAL.textChannel.canTalk())
POLITICAL.textChannel.sendMessage(outString).queue();
Logger.info(event.getAuthor().getName() + " politics: " + chatText);
}
}

56
src/discord/handlers/RecruitChannelHandler.java

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.MagicBot;
import discord.RobotSpeak;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.pmw.tinylog.Logger;
import static discord.ChatChannel.RECRUIT;
public class RecruitChannelHandler {
public static void handleRequest(MessageReceivedEvent event, String[] args) {
String chatText;
String outString;
// Early exit if database unavailable or is not an admin
if (MagicBot.isAdminEvent(event) == false)
return;
// Nothing to send?
if (args.length == 0)
return;
// Convert argument array into string;
chatText = String.join(" ", args);
// Build String
if (chatText.startsWith("-r "))
outString =
"```\n" + "Hello Players \n\n" +
chatText.substring(3) + "\n\n" +
RobotSpeak.getRobotSpeak() + "\n```";
else outString = chatText;
// Write string to changelog channel
if (RECRUIT.textChannel.canTalk())
RECRUIT.textChannel.sendMessage(outString).queue();
Logger.info(event.getAuthor().getName() + "recruit: " + chatText);
}
}

126
src/discord/handlers/RegisterAccountHandler.java

@ -0,0 +1,126 @@ @@ -0,0 +1,126 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.Database;
import discord.DiscordAccount;
import discord.MagicBot;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.pmw.tinylog.Logger;
import java.util.List;
public class RegisterAccountHandler {
public static void handleRequest(MessageReceivedEvent event, String[] args) {
String discordAccountID = event.getAuthor().getId();
String discordUserName = event.getAuthor().getName();
String discordPassword = MagicBot.generatePassword(8);
String accountName;
if (Database.online == false) {
MagicBot.sendResponse(event,
"Database currently: OFFLINE\n" +
"Try again later!");
return;
}
List<DiscordAccount> discordAccounts = MagicBot.database.getDiscordAccounts(discordAccountID);
// If we have previously registered this discord account let them know
// the current status.
if (discordAccounts.isEmpty() == false) {
MagicBot.sendResponse(event,
"It seems you already have an account registered.\n" +
"Do you need #account detailings or more general #help?");
MagicBot.magicbaneDiscord.addRoleToMember(discordAccountID, MagicBot.memberRole).queue();
return;
}
// if user supplied argument let's validate it.
// otherwise build an account name based on their discord account.
if (args.length != 1) {
// Build account name using Discord name along with their discriminator.
accountName = discordUserName.replaceAll("\\s+", "");
accountName += "#" + event.getAuthor().getDiscriminator();
} else {
// Validate account name with regex
accountName = args[0].replaceAll("\\s+", "");
if (MagicBot.accountNameRegex.matcher(accountName).matches() == false) {
MagicBot.sendResponse(event,
"Your supplied account name does not compute.\n" +
"Account names must satisfy following regex:\n" +
"^[\\p{Alnum}]{6,20}$");
return;
}
if (accountName.toLowerCase().equals("accountname")) {
MagicBot.sendResponse(event,
"accountname is not valid account name.\n" +
"Have brain player!");
return;
}
}
// Make sure account doesn't already exist.
if (MagicBot.database.getAccountsByDiscordName(accountName, true).isEmpty() == false) {
MagicBot.sendResponse(event,
"It seems this account name is already taken.\n" +
"Perhaps try one less common in frequency.");
return;
}
// If there is no registered discord account we oblige and create 4
// account based upon his current discord *name* not the ID.
if (MagicBot.database.registerDiscordAccount(discordAccountID, accountName, discordPassword) == true) {
Logger.info("Account " + accountName + " created for: " + discordUserName + " " + discordAccountID);
MagicBot.sendResponse(event,
"Welcome to MagicBane!\n" +
"-------------------\n" +
"I have registered the following accounts to your discord.\n\n" +
"1) " + accountName + "#1" + " 2) " + accountName + "#2\n" +
"3) " + accountName + "#3" + " 4) " + accountName + "#4\n\n" +
"Your default password is: " + discordPassword + "\n" +
"Ask me #help for to receive list of robot featurings.\n\n" +
"http://magicbane.com/tinyinstaller.zip" +
"\n\nPlay for to Crush!");
// Add Discord member privileges.
MagicBot.magicbaneDiscord.addRoleToMember(discordAccountID, MagicBot.memberRole).queue();
return;
}
// The call to the stored procedure abended. Report to player
// and return.
Logger.error("Creating account: " + accountName + " for: " + discordUserName + " " + discordAccountID);
Database.online = false;
MagicBot.sendResponse(event,
"-------------------\n" +
"I for to had internal error while registering your\n" +
"account. This has been reported. Try again later!");
}
}

30
src/discord/handlers/RulesRequestHandler.java

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.MagicBot;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
public class RulesRequestHandler {
public static void handleRequest(MessageReceivedEvent event) {
String outString;
// Add greeting
outString = "-No hacking.\n";
outString += "-No cheating. If you cheat, we will delete.\n";
outString += "-Players limited to 4 concurrent accounts.\n";
outString += "-Share accounts at own risk.\n";
outString += "-No refunds";
MagicBot.sendResponse(event, outString);
}
}

63
src/discord/handlers/ServerRequestHandler.java

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.MagicBot;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.pmw.tinylog.Logger;
import java.io.IOException;
public class ServerRequestHandler {
public static void handleRequest(MessageReceivedEvent event, String[] args) {
String serverCommand;
String execString = "";
// Early exit if database unavailable or is not an admin
if (MagicBot.isAdminEvent(event) == false)
return;
// No command supplied?
if (args.length != 1)
return;
serverCommand = args[0].toLowerCase().trim();
// only reboot or shutdown
if ("rebootshutdown".contains(serverCommand) == false)
return;
switch (serverCommand) {
case "reboot":
execString = "/bin/sh -c ./mbrestart.sh";
break;
case "shutdown":
execString = "/bin/sh -c ./mbkill.sh";
break;
default:
break;
}
if (execString.isEmpty() == false) {
try {
Runtime.getRuntime().exec(execString);
} catch (IOException e) {
e.printStackTrace();
}
MagicBot.sendResponse(event, "MagicBot has executed your " + serverCommand);
Logger.info(event.getAuthor().getName() + " told server to " + serverCommand);
}
}
}

51
src/discord/handlers/SetAvailHandler.java

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.Database;
import discord.MagicBot;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.pmw.tinylog.Logger;
public class SetAvailHandler {
public static void handleRequest(MessageReceivedEvent event, String[] args) {
String availStatus;
String availPass;
if (args.length != 2)
return;
availStatus = args[0].toLowerCase().trim();
// only on/off
if ("truefalse".contains(availStatus) == false)
return;
// Set avail is password driven
availPass = args[1].toLowerCase().trim();
if ("myshoes123".equals(availPass) == false)
return;
// Authenticated so change availstatus
if (availStatus.equals("true"))
Database.online = true;
else
Database.online = false;
Logger.info(event.getAuthor().getName() + " set avail status to: " + Database.online);
MagicBot.sendResponse(event, "Avail status set to: " + Database.online);
}
}

42
src/discord/handlers/StatusRequestHandler.java

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.Database;
import discord.MagicBot;
import engine.gameManager.ConfigManager;
import engine.server.login.LoginServer;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
public class StatusRequestHandler {
public static void handleRequest(MessageReceivedEvent event) {
String outString;
// Add version information
outString = "MagicBot: " + ConfigManager.MB_MAGICBOT_BOTVERSION.getValue() + "\n" +
"MagicBane: " + ConfigManager.MB_MAGICBOT_GAMEVERSION.getValue() + "\n";
// Add server status info
outString += "\nServer Status: ";
if (LoginServer.isPortInUse(Integer.parseInt(ConfigManager.MB_BIND_ADDR.getValue())))
outString += "ONLINE\n";
else
outString += "OFFLINE\n";
if (Database.online == true)
outString += MagicBot.database.getPopulationSTring();
else
outString += "Database offline: no population data.";
MagicBot.sendResponse(event, outString);
}
}

75
src/discord/handlers/TrashRequestHandler.java

@ -0,0 +1,75 @@ @@ -0,0 +1,75 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package discord.handlers;
import discord.MagicBot;
import discord.RobotSpeak;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.pmw.tinylog.Logger;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import static discord.ChatChannel.SEPTIC;
public class TrashRequestHandler {
public static void handleRequest(MessageReceivedEvent event, String[] args) {
String outString;
int trashCount = 0;
// Early exit if database unavailable or is not an admin
if (MagicBot.isAdminEvent(event) == false)
return;
if (args.length == 0) {
outString = MagicBot.database.getTrashFile();
MagicBot.sendResponse(event, outString);
return;
}
if (args[0].equals("flush") == true) {
// Empty the trash!
trashCount = MagicBot.database.getTrashCount();
if (trashCount == 0)
return;
// Anounce event in septic tank channel
outString = "```\n" + trashCount + " Player Character were for to deleted due to verified cheatings. \n\n";
outString += MagicBot.database.getTrashList() + "\n\n";
outString += RobotSpeak.getRobotInsult() + "\n```";
if (SEPTIC.textChannel.canTalk())
SEPTIC.textChannel.sendMessage(outString).queue();
try {
Files.write(Paths.get("trash"), "".getBytes());
outString = "Flushing trash players...\n";
MagicBot.sendResponse(event, outString);
} catch (IOException e) {
Logger.error(e.toString());
}
}
if (args[0].equals("detail") == true) {
outString = MagicBot.database.getTrashDetail();
MagicBot.sendResponse(event, outString);
return;
}
}
}

2943
src/engine/Enum.java

File diff suppressed because it is too large Load Diff

1099
src/engine/InterestManagement/HeightMap.java

File diff suppressed because it is too large Load Diff

554
src/engine/InterestManagement/InterestManager.java

@ -0,0 +1,554 @@ @@ -0,0 +1,554 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.InterestManagement;
import engine.Enum.DispatchChannel;
import engine.Enum.GameObjectType;
import engine.ai.MobileFSM;
import engine.ai.MobileFSM.STATE;
import engine.gameManager.GroupManager;
import engine.gameManager.SessionManager;
import engine.job.JobScheduler;
import engine.jobs.RefreshGroupJob;
import engine.net.AbstractNetMsg;
import engine.net.Dispatch;
import engine.net.DispatchMessage;
import engine.net.client.ClientConnection;
import engine.net.client.msg.LoadCharacterMsg;
import engine.net.client.msg.LoadStructureMsg;
import engine.net.client.msg.MoveToPointMsg;
import engine.net.client.msg.UnloadObjectsMsg;
import engine.objects.*;
import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;
import java.util.ArrayList;
import java.util.HashSet;
import static engine.math.FastMath.sqr;
public enum InterestManager implements Runnable {
INTERESTMANAGER;
private static long lastTime;
private static boolean keepGoing = true;
public void shutdown() {
this.keepGoing = false;
}
InterestManager() {
Logger.info(" Interest Management thread is running.");
}
@Override
public void run() {
beginLoadJob();
}
private void beginLoadJob() {
InterestManager.lastTime = System.currentTimeMillis();
while (InterestManager.keepGoing) {
try {
updateAllPlayers();
} catch (Exception e) {
Logger.error("InterestManager.BeginLoadJob:updateAllPlayers", e);
}
try {
Thread.sleep(advanceOneSecond());
} catch (Exception e) {
Logger.error("InterestManager.BeginLoadJob:advanceOneSecond", e);
}
}
}
private long advanceOneSecond() {
long curTime = System.currentTimeMillis();
long dur = 1000 + this.lastTime - curTime;
if (dur < 0) {
// Last update took more then one second, not good...
Logger.warn("LoadJob took more then one second to complete.");
this.lastTime = curTime + 100;
return 100;
}
this.lastTime += 1000;
return dur;
}
private void updateAllPlayers() {
// get all players
for (PlayerCharacter pc : SessionManager.getAllActivePlayerCharacters()) {
if (pc == null)
continue;
ClientConnection origin = pc.getClientConnection();
if (origin == null)
continue;
if (!pc.isEnteredWorld())
continue;
if (pc.getTeleportLock().readLock().tryLock()) {
try {
updateStaticList(pc, origin);
updateMobileList(pc, origin);
} catch (Exception e) {
Logger.error(e);
} finally {
pc.getTeleportLock().readLock().unlock();
}
}
}
}
private void updateStaticList(PlayerCharacter player, ClientConnection origin) {
// Only update if we've moved far enough to warrant it
float distanceSquared = player.getLoc().distanceSquared2D(player.getLastStaticLoc());
if (distanceSquared > sqr(25))
player.setLastStaticLoc(player.getLoc());
else
return;
// Get Statics in range
HashSet<AbstractWorldObject> toLoad = WorldGrid.getObjectsInRangePartial(player.getLoc(), MBServerStatics.STRUCTURE_LOAD_RANGE,
MBServerStatics.MASK_STATIC);
// get list of obects loaded that need removed
HashSet<AbstractWorldObject> loadedStaticObjects = player.getLoadedStaticObjects();
HashSet<AbstractWorldObject> toRemove = null;
toRemove = new HashSet<>(loadedStaticObjects);
toRemove.removeAll(toLoad);
// unload static objects now out of range
if (toRemove.size() > 0) {
UnloadObjectsMsg uom = new UnloadObjectsMsg();
for (AbstractWorldObject obj : toRemove) {
if (obj.getObjectType().equals(GameObjectType.Building))
InterestManager.HandleSpecialUnload((Building) obj, origin);
if (obj != null && !obj.equals(player))
uom.addObject(obj);
}
Dispatch dispatch = Dispatch.borrow(player, uom);
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
}
loadedStaticObjects.removeAll(toRemove);
// remove any object to load that are already loaded
toLoad.removeAll(loadedStaticObjects);
LoadStructureMsg lsm = new LoadStructureMsg();
LoadCharacterMsg lcm = null;
ArrayList<LoadCharacterMsg> lcmList = new ArrayList<>();
for (AbstractWorldObject awo : toLoad) {
if (awo.getObjectType().equals(GameObjectType.Building))
lsm.addObject((Building) awo);
else if (awo.getObjectType().equals(GameObjectType.Corpse)) {
Corpse corpse = (Corpse) awo;
lcm = new LoadCharacterMsg(corpse, PlayerCharacter.hideNonAscii());
Dispatch dispatch = Dispatch.borrow(player, lcm);
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
} else if (awo.getObjectType().equals(GameObjectType.NPC)) {
NPC npc = (NPC) awo;
lcm = new LoadCharacterMsg(npc, PlayerCharacter.hideNonAscii());
lcmList.add(lcm);
}
}
if (lsm.getStructureList().size() > 0) {
Dispatch dispatch = Dispatch.borrow(player, lsm);
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
}
for (LoadCharacterMsg lc : lcmList) {
Dispatch dispatch = Dispatch.borrow(player, lc);
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
}
loadedStaticObjects.addAll(toLoad);
}
private void updateMobileList(PlayerCharacter player, ClientConnection origin) {
if (player == null)
return;
// Get list of players in range
// TODO for now use a generic getALL list, later tie into Quad Tree
HashSet<AbstractWorldObject> toLoad = WorldGrid.getObjectsInRangePartial(player.getLoc(), MBServerStatics.CHARACTER_LOAD_RANGE,
MBServerStatics.MASK_MOBILE);
HashSet<AbstractWorldObject> toRemove = new HashSet<>();
HashSet<AbstractWorldObject> toLoadToPlayer = new HashSet<>();
for (AbstractWorldObject loadedObject : toLoad) {
switch (loadedObject.getObjectType()) {
case PlayerCharacter:
PlayerCharacter loadedPlayer = (PlayerCharacter) loadedObject;
if (loadedPlayer.getObjectUUID() == player.getObjectUUID())
continue;
if (player.getSeeInvis() < loadedPlayer.getHidden())
continue;
if (loadedPlayer.safemodeInvis())
continue;
if (player.getLoadedObjects().contains(loadedPlayer))
continue;
if (!loadedPlayer.isInWorldGrid())
continue;
toLoadToPlayer.add(loadedPlayer);
break;
//not playerCharacter, mobs,npcs and corpses cant be invis or safemode, just add normaly
default:
if (player.getLoadedObjects().contains(loadedObject))
continue;
if (!loadedObject.isInWorldGrid())
continue;
toLoadToPlayer.add(loadedObject);
break;
}
}
float unloadDistance = MBServerStatics.CHARACTER_LOAD_RANGE;
for (AbstractWorldObject playerLoadedObject : player.getLoadedObjects()) {
if (playerLoadedObject.getObjectType().equals(GameObjectType.PlayerCharacter)) {
PlayerCharacter loadedPlayer = (PlayerCharacter) playerLoadedObject;
if (player.getSeeInvis() < loadedPlayer.getHidden())
toRemove.add(playerLoadedObject);
else if (loadedPlayer.safemodeInvis())
toRemove.add(playerLoadedObject);
}
if (!playerLoadedObject.isInWorldGrid())
toRemove.add(playerLoadedObject);
else if (playerLoadedObject.getLoc().distanceSquared2D(player.getLoc()) > unloadDistance * unloadDistance)
toRemove.add(playerLoadedObject);
}
player.getLoadedObjects().addAll(toLoadToPlayer);
player.getLoadedObjects().removeAll(toRemove);
// get list of obects loaded to remove
// unload objects now out of range
if (toRemove.size() > 0) {
UnloadObjectsMsg uom = new UnloadObjectsMsg();
for (AbstractWorldObject obj : toRemove) {
try {
if (obj != null)
if (obj.equals(player)) // don't unload self
continue;
uom.addObject(obj);
if (obj.getObjectType() == GameObjectType.Mob)
((Mob) obj).getPlayerAgroMap().remove(player.getObjectUUID());
} catch (Exception e) {
Logger.error("UnloadCharacter", obj.getObjectUUID() + " " + e.getMessage());
}
}
if (!uom.getObjectList().isEmpty()) {
Dispatch dispatch = Dispatch.borrow(player, uom);
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
}
}
LoadCharacterMsg lcm = null;
ArrayList<AbstractWorldObject> players = new ArrayList<>();
ArrayList<AbstractWorldObject> addToList = new ArrayList<>();
for (AbstractWorldObject awo : toLoadToPlayer) {
// dont load yourself
try {
if (awo.equals(player))
continue;
if ((awo.getObjectTypeMask() & MBServerStatics.MASK_PLAYER) != 0) {
// object to load is a player
PlayerCharacter awopc = (PlayerCharacter) awo;
// dont load if invis
if (player.getSeeInvis() < awopc.getHidden())
continue;
lcm = new LoadCharacterMsg(awopc, PlayerCharacter.hideNonAscii());
players.add(awo);
// check if in a group with the person being loaded
// and if so set updateGroup flag
if (GroupManager.getGroup(player) != null
&& GroupManager.getGroup(player) == GroupManager.getGroup(awopc))
// submit a job as for some reason the client needs a delay
// with group updates
// as it wont update if we do RefreshGroup directly after
// sending the lcm below
JobScheduler.getInstance().scheduleJob(new RefreshGroupJob(player, awopc), MBServerStatics.LOAD_OBJECT_DELAY);
} else if ((awo.getObjectTypeMask() & MBServerStatics.MASK_MOB) != 0) {
Mob awonpc = (Mob) awo;
if (!awonpc.isAlive() && (awonpc.isPet() || awonpc.isSiege() || awonpc.isNecroPet() || awonpc.isPlayerGuard()))
continue;
if (awonpc.getState().equals(STATE.Respawn) || awonpc.getState().equals(STATE.Disabled))
continue;
awonpc.getPlayerAgroMap().put(player.getObjectUUID(), false);
MobileFSM.setAwake(awonpc, false);
// IVarController.setVariable(awonpc, "IntelligenceDisableDelay", (double) (System.currentTimeMillis() + 5000));
// awonpc.enableIntelligence();
lcm = new LoadCharacterMsg(awonpc, PlayerCharacter.hideNonAscii());
} else if ((awo.getObjectTypeMask() & MBServerStatics.MASK_NPC) != 0) {
NPC awonpc = (NPC) awo;
lcm = new LoadCharacterMsg(awonpc, PlayerCharacter.hideNonAscii());
} else if ((awo.getObjectTypeMask() & MBServerStatics.MASK_PET) != 0) {
Mob awonpc = (Mob) awo;
if (!awonpc.isAlive())
continue;
awonpc.getPlayerAgroMap().put(player.getObjectUUID(), false);
if (awonpc.isMob())
MobileFSM.setAwake(awonpc, false);
// IVarController.setVariable(awonpc, "IntelligenceDisableDelay", (double) (System.currentTimeMillis() + 5000));
// awonpc.enableIntelligence();
lcm = new LoadCharacterMsg(awonpc, PlayerCharacter.hideNonAscii());
}
addToList.add(awo);
if (lcm != null) {
Dispatch dispatch = Dispatch.borrow(player, lcm);
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
}
} catch (Exception e) {
Logger.error(awo.getObjectUUID() + " " + e.getMessage());
}
//Delaying character loading to reduce bandwidth consumption
}
// send effects for all players being loaded
// do it on a timer otherwise we may get failures as te client needs
// time to process lcm
//Added effects to LoadCharacter Serialization.
//JobScheduler.getInstance().scheduleJob(new LoadEffectsJob(players, origin), MBServerStatics.LOAD_OBJECT_DELAY);
}
// Forces the loading of static objects (corpses and buildings).
// Needed to override threshold limits on loading statics
public static void forceLoad(AbstractWorldObject awo) {
AbstractNetMsg msg = null;
LoadStructureMsg lsm;
LoadCharacterMsg lcm;
NPC npc;
Corpse corpse;
HashSet<AbstractWorldObject> toUpdate;
switch (awo.getObjectType()) {
case Building:
lsm = new LoadStructureMsg();
lsm.addObject((Building) awo);
msg = lsm;
break;
case Corpse:
corpse = (Corpse) awo;
lcm = new LoadCharacterMsg(corpse, false);
msg = lcm;
break;
case NPC:
npc = (NPC) awo;
lcm = new LoadCharacterMsg(npc, false);
msg = lcm;
break;
default:
return;
}
toUpdate = WorldGrid.getObjectsInRangePartial(awo.getLoc(), MBServerStatics.CHARACTER_LOAD_RANGE, MBServerStatics.MASK_PLAYER);
boolean send;
for (AbstractWorldObject tar : toUpdate) {
PlayerCharacter player = (PlayerCharacter) tar;
HashSet<AbstractWorldObject> loadedStaticObjects = player.getLoadedStaticObjects();
send = false;
if (!loadedStaticObjects.contains(awo)) {
loadedStaticObjects.add(awo);
send = true;
}
if (send) {
Dispatch dispatch = Dispatch.borrow(player, msg);
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
}
}
}
public static void HandleSpecialUnload(Building building, ClientConnection origin) {
if (Regions.FurnitureRegionMap.get(building.getObjectUUID()) == null)
return;
Regions buildingRegion = Regions.FurnitureRegionMap.get(building.getObjectUUID());
if (!buildingRegion.isOutside())
return;
MoveToPointMsg moveMsg = new MoveToPointMsg(building);
if (origin != null)
origin.sendMsg(moveMsg);
}
public synchronized void HandleLoadForEnterWorld(PlayerCharacter player) {
if (player == null)
return;
ClientConnection origin = player.getClientConnection();
if (origin == null)
return;
//Update static list
try {
updateStaticList(player, origin);
} catch (Exception e) {
Logger.error("InterestManager.updateAllStaticPlayers: " + player.getObjectUUID(), e);
}
//Update mobile list
try {
updateMobileList(player, origin);
} catch (Exception e) {
Logger.error("InterestManager.updateAllMobilePlayers: " + player.getObjectUUID(), e);
}
}
public synchronized void HandleLoadForTeleport(PlayerCharacter player) {
if (player == null)
return;
ClientConnection origin = player.getClientConnection();
if (origin == null)
return;
//Update static list
try {
updateStaticList(player, origin);
} catch (Exception e) {
Logger.error("InterestManager.updateAllStaticPlayers: " + player.getObjectUUID(), e);
}
//Update mobile list
try {
updateMobileList(player, origin);
} catch (Exception e) {
Logger.error("InterestManager.updateAllMobilePlayers: " + player.getObjectUUID(), e);
}
}
public static void reloadCharacter(AbstractCharacter absChar) {
UnloadObjectsMsg uom = new UnloadObjectsMsg();
uom.addObject(absChar);
LoadCharacterMsg lcm = new LoadCharacterMsg(absChar, false);
HashSet<AbstractWorldObject> toSend = WorldGrid.getObjectsInRangePartial(absChar.getLoc(), MBServerStatics.CHARACTER_LOAD_RANGE,
MBServerStatics.MASK_PLAYER);
PlayerCharacter pc = null;
if (absChar.getObjectType().equals(GameObjectType.PlayerCharacter))
pc = (PlayerCharacter) absChar;
for (AbstractWorldObject awo : toSend) {
PlayerCharacter pcc = (PlayerCharacter) awo;
if (pcc == null)
continue;
ClientConnection cc = SessionManager.getClientConnection(pcc);
if (cc == null)
continue;
if (pcc.getObjectUUID() == absChar.getObjectUUID())
continue;
else {
if (pc != null)
if (pcc.getSeeInvis() < pc.getHidden())
continue;
if (!cc.sendMsg(uom)) {
String classType = uom.getClass().getSimpleName();
Logger.error("Failed to send message ");
}
if (!cc.sendMsg(lcm)) {
String classType = lcm.getClass().getSimpleName();
Logger.error("Failed to send message");
}
}
}
}
}

102
src/engine/InterestManagement/RealmMap.java

@ -0,0 +1,102 @@ @@ -0,0 +1,102 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.InterestManagement;
/* This class is the main interface for Magicbane's
* Interest management facilities.
*/
import engine.Enum;
import engine.math.Vector3fImmutable;
import engine.net.Dispatch;
import engine.net.DispatchMessage;
import engine.net.client.msg.TerritoryChangeMessage;
import engine.objects.City;
import engine.objects.PlayerCharacter;
import engine.objects.Realm;
import engine.server.MBServerStatics;
import engine.util.MapLoader;
import org.pmw.tinylog.Logger;
import static engine.objects.Realm.getRealm;
public class RealmMap {
// Spatial hashmap. Used for detecting which Realm
// a player is currently in..
public static int[][] _realmImageMap;
public static int getRealmIDAtLocation(Vector3fImmutable pos) {
int xBuckets = (int) ((pos.getX() / MBServerStatics.MAX_WORLD_WIDTH) * MBServerStatics.SPATIAL_HASH_BUCKETSX);
int yBuckets = (int) ((pos.getZ() / MBServerStatics.MAX_WORLD_HEIGHT) * MBServerStatics.SPATIAL_HASH_BUCKETSY);
if (yBuckets < 0 || yBuckets >= MBServerStatics.SPATIAL_HASH_BUCKETSY
|| xBuckets < 0 || xBuckets >= MBServerStatics.SPATIAL_HASH_BUCKETSX) {
Logger.error("WorldServerRealm.getRealmFromPosition",
"Invalid range; Z: " + yBuckets + ", X: " + xBuckets);
return 255;
}
return RealmMap._realmImageMap[xBuckets][yBuckets];
}
public static Realm getRealmForCity(City city) {
Realm outRealm = null;
outRealm = city.getRealm();
return outRealm;
}
public static Realm getRealmAtLocation(Vector3fImmutable worldVector) {
return getRealm(RealmMap.getRealmIDAtLocation(worldVector));
}
public static void updateRealm(PlayerCharacter player){
int realmID = RealmMap.getRealmIDAtLocation(player.getLoc());
if (realmID != player.getLastRealmID()){
player.setLastRealmID(realmID);
Realm realm = Realm.getRealm(realmID);
if (realm != null){
if (realm.isRuled()){
City city = realm.getRulingCity();
if (city != null){
TerritoryChangeMessage tcm = new TerritoryChangeMessage((PlayerCharacter)realm.getRulingCity().getOwner(),realm);
Dispatch dispatch = Dispatch.borrow(player, tcm);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.PRIMARY);
}else{
TerritoryChangeMessage tcm = new TerritoryChangeMessage(null,realm);
Dispatch dispatch = Dispatch.borrow(player, tcm);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.PRIMARY);
}
}else{
TerritoryChangeMessage tcm = new TerritoryChangeMessage(null,realm);
Dispatch dispatch = Dispatch.borrow(player, tcm);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.PRIMARY);
}
}
}
}
public static void loadRealmImageMap() {
RealmMap._realmImageMap = MapLoader.loadMap();
}
}

312
src/engine/InterestManagement/WorldGrid.java

@ -0,0 +1,312 @@ @@ -0,0 +1,312 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.InterestManagement;
import engine.Enum.GridObjectType;
import engine.math.FastMath;
import engine.math.Vector3f;
import engine.math.Vector3fImmutable;
import engine.net.DispatchMessage;
import engine.net.client.ClientConnection;
import engine.net.client.msg.LoadCharacterMsg;
import engine.net.client.msg.LoadStructureMsg;
import engine.net.client.msg.UnloadObjectsMsg;
import engine.objects.*;
import engine.server.MBServerStatics;
import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;
public class WorldGrid {
public static ConcurrentHashMap<Integer,AbstractWorldObject>[][] DynamicGridMap;
public static ConcurrentHashMap<Integer,AbstractWorldObject>[][] StaticGridMap;
private static float dynamicBucketScale = 0.00390625f; // 256 bucket size, 1/256
private static float staticBucketScale = 0.00390625f;
public static void startLoadJob() {
Thread loadJobThread;
loadJobThread = new Thread(InterestManager.INTERESTMANAGER);
loadJobThread.setName("InterestManager");
loadJobThread.start();
}
public static boolean moveWorldObject(AbstractWorldObject awo, Vector3fImmutable location) {
awo.setLoc(location);
return true;
}
public static HashSet<AbstractWorldObject> getInRange(Vector3f loc, double r) {
HashSet<AbstractWorldObject> outbound = new HashSet<>();
return outbound;
}
public static HashSet<AbstractWorldObject> getObjectsInRangePartial(Vector3fImmutable loc, double r, int mask) {
HashSet<AbstractWorldObject> outbound = new HashSet<>();
float scale;
if ((mask & MBServerStatics.MASK_STATIC) != 0)
scale = WorldGrid.staticBucketScale;
else
scale = WorldGrid.dynamicBucketScale;
int gridX = (int) Math.abs(loc.x * scale);
int gridZ = (int)Math.abs(loc.z * scale);
int bucketSize = (int) (r *scale) + 1;
//start at top left most corner to scan.
int startingX = gridX - bucketSize;
int startingZ = gridZ + bucketSize;
int limitX = Math.abs((int) (MBServerStatics.MAX_WORLD_WIDTH *scale));
int limitZ = Math.abs((int) (MBServerStatics.MAX_WORLD_HEIGHT *scale)); //LimitZ is negative, remember to flip sign.
if (startingX < 0)
startingX = 0;
if (startingZ < 0)
startingZ = 0;
if (startingX > limitX)
startingX = limitX;
if (startingZ > limitZ)
startingZ = limitZ;
int endX = startingX + (bucketSize * 2);
int endZ = startingZ - (bucketSize * 2);
if (endX < 0)
endX = 0;
if (endZ < 0)
endZ = 0;
if (endX > limitX)
endX = limitX;
if (endZ > limitZ)
endZ = limitZ;
int auditMob = 0;
for (int x = startingX;x<=endX;x++){
for (int z = startingZ;z >= endZ;z--){
ConcurrentHashMap<Integer,AbstractWorldObject> gridMap;
if ((MBServerStatics.MASK_STATIC & mask) != 0)
gridMap = WorldGrid.StaticGridMap[x][z];
else
gridMap = WorldGrid.DynamicGridMap[x][z];
for (AbstractWorldObject gridObject: gridMap.values()){
if ((gridObject.getObjectTypeMask() & mask) == 0)
continue;
if (gridObject.getLoc().distanceSquared2D(loc) <= FastMath.sqr(r))
outbound.add(gridObject);
}
}
}
return outbound;
}
public static HashSet<AbstractWorldObject> getObjectsInRangePartialNecroPets(Vector3fImmutable loc, double r) {
HashSet<AbstractWorldObject> outbound = new HashSet<>();
return outbound;
}
public static HashSet<AbstractWorldObject> getObjectsInRangeContains(Vector3fImmutable loc, double r, int mask) {
HashSet<AbstractWorldObject> outbound = getObjectsInRangePartial(loc,r,mask);
return outbound;
}
public static HashSet<AbstractWorldObject> getObjectsInRangePartial(AbstractWorldObject awo, double range, int mask) {
return getObjectsInRangePartial(awo.getLoc(), range, mask);
}
public static void InitializeGridObjects(){
int dynamicWidth = (int) Math.abs(MBServerStatics.MAX_WORLD_WIDTH *WorldGrid.dynamicBucketScale);
int dynamicHeight = (int) Math.abs(MBServerStatics.MAX_WORLD_HEIGHT*WorldGrid.dynamicBucketScale);
int staticWidth = (int) Math.abs(MBServerStatics.MAX_WORLD_WIDTH *WorldGrid.staticBucketScale);
int staticHeight = (int) Math.abs(MBServerStatics.MAX_WORLD_HEIGHT*WorldGrid.staticBucketScale);
WorldGrid.DynamicGridMap = new ConcurrentHashMap[dynamicWidth+ 1][dynamicHeight + 1];
WorldGrid.StaticGridMap = new ConcurrentHashMap[staticWidth + 1][staticHeight + 1];
//create new hash maps for each bucket
for (int x = 0; x<= staticWidth; x++)
for (int y = 0; y<= staticHeight; y++){
WorldGrid.StaticGridMap[x][y] = new ConcurrentHashMap<Integer,AbstractWorldObject>();
}
for (int x = 0; x<= dynamicWidth; x++)
for (int y = 0; y<= dynamicHeight; y++){
WorldGrid.DynamicGridMap[x][y] = new ConcurrentHashMap<Integer,AbstractWorldObject>();
}
}
public static void RemoveWorldObject(AbstractWorldObject gridObject){
if (gridObject == null)
return;
AbstractWorldObject.RemoveFromWorldGrid(gridObject);
}
public static boolean addObject(AbstractWorldObject gridObject, float x, float z){
if (gridObject == null)
return false;
if (x > MBServerStatics.MAX_WORLD_WIDTH)
return false;
if (z < MBServerStatics.MAX_WORLD_HEIGHT)
return false;
if (x < 0)
return false;
if (z > 0)
return false;
int gridX;
int gridZ;
if (gridObject.getGridObjectType().equals(GridObjectType.STATIC)){
gridX = Math.abs((int) (x *WorldGrid.staticBucketScale));
gridZ = Math.abs((int) (z*WorldGrid.staticBucketScale));
}else{
gridX = Math.abs((int) (x *WorldGrid.dynamicBucketScale));
gridZ = Math.abs((int) (z*WorldGrid.dynamicBucketScale));
}
WorldGrid.RemoveWorldObject(gridObject);
return AbstractWorldObject.AddToWorldGrid(gridObject, gridX, gridZ);
}
public static void unloadObject(AbstractWorldObject awo) {
UnloadObjectsMsg uom = new UnloadObjectsMsg();
uom.addObject(awo);
DispatchMessage.sendToAllInRange(awo, uom);
}
public static void loadObject(AbstractWorldObject awo) {
LoadStructureMsg lsm;
LoadCharacterMsg lcm;
switch (awo.getObjectType()) {
case Building:
lsm = new LoadStructureMsg();
lsm.addObject((Building)awo);
DispatchMessage.sendToAllInRange(awo, lsm);
break;
case NPC:
lcm = new LoadCharacterMsg((NPC) awo, false);
DispatchMessage.sendToAllInRange(awo, lcm);
break;
case Mob:
lcm = new LoadCharacterMsg((Mob) awo, false);
DispatchMessage.sendToAllInRange(awo, lcm);
break;
default:
// *** Refactor: Log error?
break;
}
}
public static void loadObject(AbstractWorldObject awo, ClientConnection origin) {
LoadStructureMsg lsm;
LoadCharacterMsg lcm;
switch (awo.getObjectType()) {
case Building:
lsm = new LoadStructureMsg();
lsm.addObject((Building)awo);
DispatchMessage.sendToAllInRange(awo, lsm);
break;
case NPC:
lcm = new LoadCharacterMsg((NPC) awo, false);
DispatchMessage.sendToAllInRange(awo, lcm);
break;
case Mob:
lcm = new LoadCharacterMsg((Mob) awo, false);
DispatchMessage.sendToAllInRange(awo, lcm);
break;
case PlayerCharacter:
lcm = new LoadCharacterMsg((PlayerCharacter) awo, false);
DispatchMessage.sendToAllInRange(awo, lcm);
break;
default:
// *** Refactor: Log error?
break;
}
}
public static void unloadObject(AbstractWorldObject awo,
ClientConnection origin) {
UnloadObjectsMsg uom = new UnloadObjectsMsg();
uom.addObject(awo);
DispatchMessage.sendToAllInRange(awo, uom);
}
public static void addObject(AbstractWorldObject awo, PlayerCharacter pc) {
if (pc == null || awo == null)
return;
ClientConnection origin = pc.getClientConnection();
if (origin == null)
return;
loadObject(awo, origin);
}
public static void removeObject(AbstractWorldObject awo, PlayerCharacter pc) {
if (pc == null || awo == null)
return;
ClientConnection origin = pc.getClientConnection();
if (origin == null)
return;
unloadObject(awo, origin);
}
public static void updateObject(AbstractWorldObject awo, PlayerCharacter pc) {
if (pc == null || awo == null)
return;
ClientConnection origin = pc.getClientConnection();
if (origin == null)
return;
unloadObject(awo, origin);
loadObject(awo, origin);
}
public static void updateObject(AbstractWorldObject awo) {
if (awo == null)
return;
unloadObject(awo);
loadObject(awo);
}
/*
*
*/
public static void removeObject(AbstractWorldObject awo) {
if (awo == null)
return;
unloadObject(awo);
}
}

1769
src/engine/ai/MobileFSM.java

File diff suppressed because it is too large Load Diff

104
src/engine/ai/MobileFSMManager.java

@ -0,0 +1,104 @@ @@ -0,0 +1,104 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.ai;
import engine.gameManager.ZoneManager;
import engine.objects.Mob;
import engine.objects.Zone;
import engine.server.MBServerStatics;
import engine.util.ThreadUtils;
import org.pmw.tinylog.Logger;
import java.util.HashSet;
public class MobileFSMManager {
private static final MobileFSMManager INSTANCE = new MobileFSMManager();
private volatile boolean alive;
private long timeOfKill = -1;
private MobileFSMManager() {
Runnable worker = new Runnable() {
@Override
public void run() {
execution();
}
};
alive = true;
Thread t = new Thread(worker, "MobileFSMManager");
t.start();
}
public static MobileFSMManager getInstance() {
return INSTANCE;
}
/**
* Stops the MobileFSMManager
*/
public void shutdown() {
if (alive) {
alive = false;
timeOfKill = System.currentTimeMillis();
}
}
public long getTimeOfKill() {
return this.timeOfKill;
}
public boolean isAlive() {
return this.alive;
}
private void execution() {
//Load zone threshold once.
long mobPulse = System.currentTimeMillis() + MBServerStatics.AI_PULSE_MOB_THRESHOLD;
while (alive) {
ThreadUtils.sleep(1);
if (System.currentTimeMillis() > mobPulse) {
HashSet<Integer> auditMobs = new HashSet<Integer>();
for (Zone zone : ZoneManager.getAllZones()) {
for (Mob mob : zone.zoneMobSet) {
if (auditMobs.contains(mob.getObjectUUID()))
continue;
auditMobs.add(mob.getObjectUUID());
try {
if (mob != null)
MobileFSM.run(mob);
} catch (Exception e) {
Logger.error(e);
e.printStackTrace();
}
}
}
mobPulse = System.currentTimeMillis() + MBServerStatics.AI_PULSE_MOB_THRESHOLD;
}
}
}
}

413
src/engine/ai/utilities/CombatUtilities.java

@ -0,0 +1,413 @@ @@ -0,0 +1,413 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.ai.utilities;
import engine.Enum;
import engine.Enum.*;
import engine.ai.MobileFSM.STATE;
import engine.gameManager.ChatManager;
import engine.gameManager.CombatManager;
import engine.math.Vector3fImmutable;
import engine.net.DispatchMessage;
import engine.net.client.msg.TargetedActionMsg;
import engine.objects.*;
import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import static engine.math.FastMath.sqr;
public class CombatUtilities {
public static boolean inRangeToAttack(Mob agent,AbstractWorldObject target){
if (Float.isNaN(agent.getLoc().x))
return false;
try{
Vector3fImmutable sl = agent.getLoc();
Vector3fImmutable tl = target.getLoc();
//add Hitbox's to range.
float range = agent.getRange();
range += CombatManager.calcHitBox(target) + CombatManager.calcHitBox(agent);
//if (target instanceof AbstractCharacter)
// if (((AbstractCharacter)target).isMoving())
// range+= 5;
return !(sl.distanceSquared(tl) > sqr(range));
}catch(Exception e){
Logger.error( e.toString());
return false;
}
}
public static boolean inRangeToAttack2D(Mob agent,AbstractWorldObject target){
if (Float.isNaN(agent.getLoc().x))
return false;
try{
Vector3fImmutable sl = agent.getLoc();
Vector3fImmutable tl = target.getLoc();
//add Hitbox's to range.
float range = agent.getRange();
range += CombatManager.calcHitBox(target) + CombatManager.calcHitBox(agent);
//if (target instanceof AbstractCharacter)
// if (((AbstractCharacter)target).isMoving())
// range+= 5;
return !(sl.distanceSquared2D(tl) > sqr(range));
}catch(Exception e){
Logger.error( e.toString());
return false;
}
}
public static void swingIsBlock(Mob agent,AbstractWorldObject target, int animation) {
if (!target.isAlive())
return;
TargetedActionMsg msg = new TargetedActionMsg(agent,animation, target, MBServerStatics.COMBAT_SEND_BLOCK);
if (target.getObjectType() == GameObjectType.PlayerCharacter)
DispatchMessage.dispatchMsgToInterestArea(target, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true,false);
else
DispatchMessage.sendToAllInRange(agent,msg);
}
public static void swingIsParry(Mob agent,AbstractWorldObject target, int animation) {
if (!target.isAlive())
return;
TargetedActionMsg msg = new TargetedActionMsg(agent,animation, target, MBServerStatics.COMBAT_SEND_PARRY);
if (target.getObjectType() == GameObjectType.PlayerCharacter)
DispatchMessage.dispatchMsgToInterestArea(target, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true,false);
else
DispatchMessage.sendToAllInRange(agent,msg);
}
public static void swingIsDodge(Mob agent,AbstractWorldObject target, int animation) {
if (!target.isAlive())
return;
TargetedActionMsg msg = new TargetedActionMsg(agent,animation, target, MBServerStatics.COMBAT_SEND_DODGE);
if (target.getObjectType() == GameObjectType.PlayerCharacter)
DispatchMessage.dispatchMsgToInterestArea(target, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true,false);
else
DispatchMessage.sendToAllInRange(agent,msg);
}
public static void swingIsDamage(Mob agent,AbstractWorldObject target, float damage, int animation){
float trueDamage = 0;
if (!target.isAlive())
return;
if (AbstractWorldObject.IsAbstractCharacter(target))
trueDamage = ((AbstractCharacter) target).modifyHealth(-damage, agent, false);
else if (target.getObjectType() == GameObjectType.Building)
trueDamage = ((Building) target).modifyHealth(-damage, agent);
//Don't send 0 damage kay thanx.
if (trueDamage == 0)
return;
TargetedActionMsg msg = new TargetedActionMsg(agent,target, damage, animation);
if (target.getObjectType() == GameObjectType.PlayerCharacter)
DispatchMessage.dispatchMsgToInterestArea(target, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true,false);
else
DispatchMessage.sendToAllInRange(agent,msg);
//check damage shields
if(AbstractWorldObject.IsAbstractCharacter(target) && target.isAlive() && target.getObjectType() != GameObjectType.Mob)
CombatManager.handleDamageShields(agent,(AbstractCharacter)target, damage);
}
public static boolean canSwing(Mob agent) {
return (agent.isAlive() && !agent.getBonuses().getBool(ModType.Stunned, SourceType.None));
}
public static void swingIsMiss(Mob agent,AbstractWorldObject target, int animation) {
TargetedActionMsg msg = new TargetedActionMsg(agent,target, 0f, animation);
if (target.getObjectType() == GameObjectType.PlayerCharacter)
DispatchMessage.dispatchMsgToInterestArea(target, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true,false);
else
DispatchMessage.sendToAllInRange(agent,msg);
}
public static boolean triggerDefense(Mob agent, AbstractWorldObject target) {
int defenseScore = 0;
int attackScore = agent.getAtrHandOne();
switch (target.getObjectType()) {
case PlayerCharacter:
defenseScore = ((AbstractCharacter) target).getDefenseRating();
break;
case Mob:
Mob mob = (Mob)target;
if (mob.isSiege())
defenseScore = attackScore;
break;
case Building:
return false;
}
int hitChance;
if (attackScore > defenseScore || defenseScore == 0)
hitChance = 94;
else if (attackScore == defenseScore && target.getObjectType() == GameObjectType.Mob)
hitChance = 10;
else {
float dif = attackScore / defenseScore;
if (dif <= 0.8f)
hitChance = 4;
else
hitChance = ((int)(450 * (dif - 0.8f)) + 4);
if (target.getObjectType() == GameObjectType.Building)
hitChance = 100;
}
return ThreadLocalRandom.current().nextInt(100) > hitChance;
}
public static boolean triggerBlock(Mob agent,AbstractWorldObject ac) {
return triggerPassive(agent,ac, "Block");
}
public static boolean triggerParry(Mob agent,AbstractWorldObject ac) {
return triggerPassive(agent,ac, "Parry");
}
public static boolean triggerDodge(Mob agent,AbstractWorldObject ac) {
return triggerPassive(agent,ac, "Dodge");
}
public static boolean triggerPassive(Mob agent,AbstractWorldObject ac, String type) {
float chance = 0;
if (AbstractWorldObject.IsAbstractCharacter(ac))
chance = ((AbstractCharacter)ac).getPassiveChance(type, agent.getLevel(), true);
if (chance > 75f)
chance = 75f;
if (agent.isSiege() && AbstractWorldObject.IsAbstractCharacter(ac))
chance = 100;
return ThreadLocalRandom.current().nextInt(100) < chance;
}
public static void combatCycle(Mob agent,AbstractWorldObject target, boolean mainHand, ItemBase wb) {
if (!agent.isAlive() || !target.isAlive()) return;
if (target.getObjectType() == GameObjectType.PlayerCharacter)
if (!((PlayerCharacter)target).isActive())
return;
int anim = 75;
float speed = 30f;
if (mainHand)
speed = agent.getSpeedHandOne();
else
speed = agent.getSpeedHandTwo();
DamageType dt = DamageType.Crush;
if (agent.isSiege())
dt = DamageType.Siege;
if (wb != null) {
anim = CombatManager.getSwingAnimation(wb, null,mainHand);
dt = wb.getDamageType();
} else if (!mainHand)
return;
Resists res = null;
PlayerBonuses bonus = null;
switch(target.getObjectType()){
case Building:
res = ((Building)target).getResists();
break;
case PlayerCharacter:
res = ((PlayerCharacter)target).getResists();
bonus = ((PlayerCharacter)target).getBonuses();
break;
case Mob:
Mob mob = (Mob)target;
res = mob.getResists();
bonus = ((Mob)target).getBonuses();
break;
}
//must not be immune to all or immune to attack
if (bonus != null && !bonus.getBool(ModType.NoMod, SourceType.ImmuneToAttack))
if (res != null &&(res.immuneToAll() || res.immuneToAttacks() || res.immuneTo(dt)))
return;
int passiveAnim = CombatManager.getSwingAnimation(wb, null,mainHand);
if(canSwing(agent)) {
if(triggerDefense(agent,target))
swingIsMiss(agent,target, passiveAnim);
else if(triggerDodge(agent,target))
swingIsDodge(agent,target, passiveAnim);
else if(triggerParry(agent,target))
swingIsParry(agent,target, passiveAnim);
else if(triggerBlock(agent,target))
swingIsBlock(agent,target, passiveAnim);
else
swingIsDamage(agent,target, determineDamage(agent,target, mainHand, speed, dt), anim);
if (agent.getWeaponPower() != null)
agent.getWeaponPower().attack(target, MBServerStatics.ONE_MINUTE);
}
if (target.getObjectType().equals(GameObjectType.PlayerCharacter)){
PlayerCharacter player = (PlayerCharacter)target;
if (player.getDebug(64)){
ChatManager.chatSayInfo(player, "Debug Combat: Mob UUID " + agent.getObjectUUID() + " || Building ID = " + agent.getBuildingID() + " || Floor = " + agent.getInFloorID() + " || Level = " + agent.getInBuilding() );//combat debug
}
}
//SIEGE MONSTERS DO NOT ATTACK GUARDSs
if (target.getObjectType() == GameObjectType.Mob)
if (((Mob)target).isSiege())
return;
//handle the retaliate
if (AbstractWorldObject.IsAbstractCharacter(target))
CombatManager.handleRetaliate((AbstractCharacter)target, agent);
if (target.getObjectType() == GameObjectType.Mob){
Mob targetMob = (Mob)target;
if (targetMob.isSiege())
return;
if (System.currentTimeMillis() < targetMob.getTimeStamp("CallForHelp"))
return;
CallForHelp(targetMob);
targetMob.getTimestamps().put("CallForHelp", System.currentTimeMillis() + 60000);
}
}
public static void CallForHelp(Mob aiAgent) {
Set<Mob> zoneMobs = aiAgent.getParentZone().zoneMobSet;
AbstractWorldObject target = aiAgent.getCombatTarget();
if (target == null) {
return;
}
int count = 0;
for (Mob mob: zoneMobs){
if (!mob.isAlive())
continue;
if (mob.isSiege() || mob.isPet() || !Enum.MobFlagType.AGGRESSIVE.elementOf(mob.getMobBase().getFlags()))
continue;
if (count == 5)
continue;
if (mob.getCombatTarget() != null)
continue;
if (!aiAgent.isPlayerGuard() && mob.isPlayerGuard())
continue;
if (aiAgent.isPlayerGuard() && !mob.isPlayerGuard() )
continue;
if (target.getObjectType() == GameObjectType.PlayerCharacter){
if (!MovementUtilities.inRangeToAggro(mob, (PlayerCharacter)target))
continue;
count++;
}else{
if (count == 5)
continue;
if (aiAgent.getLoc().distanceSquared2D(target.getLoc()) > sqr(aiAgent.getAggroRange()))
continue;
count++;
}
if (mob.getState() == STATE.Awake || mob.getState() == STATE.Patrol){
mob.setCombatTarget(target);
mob.setState(STATE.Attack);
}
}
}
public static float determineDamage(Mob agent,AbstractWorldObject target, boolean mainHand, float speed, DamageType dt) {
float min = (mainHand) ? agent.getMinDamageHandOne() : agent.getMinDamageHandTwo();
float max = (mainHand) ? agent.getMaxDamageHandOne() : agent.getMaxDamageHandTwo();;
float range = max - min;
float damage = min + ((ThreadLocalRandom.current().nextFloat()*range)+(ThreadLocalRandom.current().nextFloat()*range))/2;
if (AbstractWorldObject.IsAbstractCharacter(target))
if (((AbstractCharacter)target).isSit())
damage *= 2.5f; //increase damage if sitting
if (AbstractWorldObject.IsAbstractCharacter(target))
return ((AbstractCharacter)target).getResists().getResistedDamage(agent,(AbstractCharacter)target, dt, damage, 0);
if (target.getObjectType() == GameObjectType.Building){
Building building = (Building)target;
Resists resists = building.getResists();
return damage * (1 - (resists.getResist(dt, 0) / 100));
}
return damage;
}
public static boolean RunAIRandom(){
int random = ThreadLocalRandom.current().nextInt(4);
if (random == 0)
return true;
return false;
}
}

303
src/engine/ai/utilities/MovementUtilities.java

@ -0,0 +1,303 @@ @@ -0,0 +1,303 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.ai.utilities;
import engine.Enum;
import engine.Enum.GameObjectType;
import engine.Enum.ModType;
import engine.Enum.SourceType;
import engine.exception.MsgSendException;
import engine.gameManager.MovementManager;
import engine.math.Vector3fImmutable;
import engine.net.client.msg.MoveToPointMsg;
import engine.objects.*;
import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;
import java.util.concurrent.ThreadLocalRandom;
import static engine.math.FastMath.sqr;
import static engine.math.FastMath.sqrt;
public class MovementUtilities {
public static boolean inRangeOfBindLocation(Mob agent){
if (agent.isPlayerGuard()){
Mob guardCaptain = null;
if (agent.getContract() != null)
guardCaptain = agent;
else
guardCaptain = (Mob) agent.getNpcOwner();
if (guardCaptain != null){
Building barracks = guardCaptain.getBuilding();
if (barracks != null){
City city = barracks.getCity();
if (city != null){
Building tol = city.getTOL();
//Guards recall distance = 814.
if (tol != null){
if (agent.getLoc().distanceSquared2D(tol.getLoc()) > sqr(Enum.CityBoundsType.SIEGE.extents)) {
return false;
}
}
}
}
}
return true;
}
Vector3fImmutable sl = new Vector3fImmutable(agent.getLoc().getX(), 0, agent.getLoc().getZ());
Vector3fImmutable tl = new Vector3fImmutable(agent.getTrueBindLoc().x,0,agent.getTrueBindLoc().z);
float distanceSquaredToTarget = sl.distanceSquared2D(tl); //distance to center of target
float zoneRange = 250;
if (agent.getParentZone() != null){
if (agent.getParentZone().getBounds() != null)
zoneRange = agent.getParentZone().getBounds().getHalfExtents().x * 2;
}
if (zoneRange > 300)
zoneRange = 300;
if (agent.getSpawnRadius() > zoneRange)
zoneRange = agent.getSpawnRadius();
return distanceSquaredToTarget < sqr(MBServerStatics.AI_DROP_AGGRO_RANGE + zoneRange);
}
public static boolean inRangeToAggro(Mob agent,PlayerCharacter target){
Vector3fImmutable sl = agent.getLoc();
Vector3fImmutable tl =target.getLoc();
float distanceSquaredToTarget = sl.distanceSquared2D(tl) - sqr(agent.calcHitBox() + target.calcHitBox()); //distance to center of target
float range = MBServerStatics.AI_BASE_AGGRO_RANGE;
if (agent.isPlayerGuard())
range = 150;
return distanceSquaredToTarget < sqr(range);
}
public static boolean inRangeDropAggro(Mob agent,PlayerCharacter target){
Vector3fImmutable sl = agent.getLoc();
Vector3fImmutable tl = target.getLoc();
float distanceSquaredToTarget = sl.distanceSquared2D(tl) - sqr(agent.calcHitBox() + target.calcHitBox()); //distance to center of target
float range = agent.getRange() + 150;
if (range > 200)
range = 200;
return distanceSquaredToTarget < sqr(range);
}
public static Vector3fImmutable GetMoveLocation(Mob aiAgent, AbstractCharacter aggroTarget){
// Player isnt moving and neither is mob. Just return
// the mobile's current location. Ain't goin nowhere!
// *** Refactor: Check to ensure methods calling us
// all don't sent move messages when not moving.
if ((aggroTarget.isMoving() == false))
return aggroTarget.getLoc();
if (aggroTarget.getEndLoc().x != 0){
float aggroTargetDistanceSquared = aggroTarget.getLoc().distanceSquared2D(aggroTarget.getEndLoc());
float aiAgentDistanceSquared = aiAgent.getLoc().distanceSquared2D(aggroTarget.getEndLoc());
if (aiAgentDistanceSquared >= aggroTargetDistanceSquared)
return aggroTarget.getEndLoc();
else{
float distanceToMove = sqrt(aggroTargetDistanceSquared + aiAgentDistanceSquared) *.5f;
return aggroTarget.getFaceDir().scaleAdd(distanceToMove, aggroTarget.getLoc());
}
}
// One of us is moving so let's calculate our destination loc for this
// simulation frame. We will simply project our position onto the
// character's movement vector and return the closest point.
return aiAgent.getLoc().ClosestPointOnLine(aggroTarget.getLoc(), aggroTarget.getEndLoc());
}
public static void moveToLocation(Mob agent,Vector3fImmutable newLocation, float offset){
try {
//don't move farther than 30 units from player.
if (offset > 30)
offset = 30;
Vector3fImmutable newLoc = Vector3fImmutable.getRandomPointInCircle(newLocation, offset);
agent.setFaceDir(newLoc.subtract2D(agent.getLoc()).normalize());
aiMove(agent,newLoc,false);
} catch (Exception e) {
Logger.error( e.toString());
}
}
public static boolean canMove(Mob agent) {
if (agent.getMobBase() != null && Enum.MobFlagType.SENTINEL.elementOf(agent.getMobBase().getFlags()))
return false;
return (agent.isAlive() && !agent.getBonuses().getBool(ModType.Stunned,SourceType.None) && !agent.getBonuses().getBool(ModType.CannotMove, SourceType.None));
}
public static Vector3fImmutable randomPatrolLocation(Mob agent,Vector3fImmutable center, float radius){
//Determing where I want to move.
return new Vector3fImmutable((center.x - radius) + ((ThreadLocalRandom.current().nextFloat()+.1f*2)*radius),
center.y,
(center.z - radius) + ((ThreadLocalRandom.current().nextFloat()+.1f *2)*radius));
}
public static Long estimateMovementTime(Mob agent) {
if(agent.getEndLoc().x == 0 && agent.getEndLoc().y == 0)
return 0L;
return (long) ((agent.getLoc().distance2D(agent.getEndLoc())*1000)/agent.getSpeed());
}
public static void aiMove(Mob agent,Vector3fImmutable vect, boolean isWalking) {
//update our walk/run state.
if (isWalking && !agent.isWalk()){
agent.setWalkMode(true);
MovementManager.sendRWSSMsg(agent);
}else if(!isWalking && agent.isWalk()){
agent.setWalkMode(false);
MovementManager.sendRWSSMsg(agent);
}
MoveToPointMsg msg = new MoveToPointMsg();
// Regions currentRegion = Mob.InsideBuildingRegion(agent);
//
// if (currentRegion != null){
//
//
// if (currentRegion.isGroundLevel()){
// agent.setInBuilding(0);
// agent.setInFloorID(-1);
// }else{
// agent.setInBuilding(currentRegion.getLevel());
// agent.setInFloorID(currentRegion.getRoom());
// }
// }else{
// agent.setInBuilding(-1);
// agent.setInFloorID(-1);
// agent.setInBuildingID(0);
// }
// agent.setLastRegion(currentRegion);
Vector3fImmutable startLoc = null;
Vector3fImmutable endLoc = null;
// if (agent.getLastRegion() != null){
// Building inBuilding = Building.getBuildingFromCache(agent.getInBuildingID());
// if (inBuilding != null){
// startLoc = ZoneManager.convertWorldToLocal(inBuilding, agent.getLoc());
// endLoc = ZoneManager.convertWorldToLocal(inBuilding, vect);
// }
// }else{
// agent.setBuildingID(0);
// agent.setInBuildingID(0);
// startLoc = agent.getLoc();
// endLoc = vect;
// }
startLoc = agent.getLoc();
endLoc = vect;
msg.setSourceType(GameObjectType.Mob.ordinal());
msg.setSourceID(agent.getObjectUUID());
msg.setStartCoord(startLoc);
msg.setEndCoord(endLoc);
msg.setUnknown01(-1);
msg.setInBuilding(-1);
msg.setTargetType(0);
msg.setTargetID(0);
try {
MovementManager.movement(msg, agent);
} catch (MsgSendException e) {
// TODO Figure out how we want to handle the msg send exception
e.printStackTrace();
}
}
public static Vector3fImmutable GetDestinationToCharacter(Mob aiAgent, AbstractCharacter character){
if (!character.isMoving())
return character.getLoc();
float agentDistanceEndLoc = aiAgent.getLoc().distanceSquared2D(character.getEndLoc());
float characterDistanceEndLoc = character.getLoc().distanceSquared2D(character.getEndLoc());
if (agentDistanceEndLoc > characterDistanceEndLoc)
return character.getEndLoc();
return character.getLoc();
}
public static boolean updateMovementToCharacter(Mob aiAgent, AbstractCharacter aggroTarget){
if (aiAgent.destination.equals(Vector3fImmutable.ZERO))
return true;
if (!aiAgent.isMoving())
return true;
if (aggroTarget.isMoving()){
if (!aiAgent.destination.equals(aggroTarget.getEndLoc()) && !aiAgent.destination.equals(aggroTarget.getLoc()))
return true;
}else{
if (aiAgent.destination.equals(aggroTarget.getLoc()))
return false;
}
return false;
}
}

15
src/engine/ai/utilities/PowerUtilities.java

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.ai.utilities;
public class PowerUtilities {
}

174
src/engine/core/ControlledRunnable.java

@ -0,0 +1,174 @@ @@ -0,0 +1,174 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.core;
import org.pmw.tinylog.Logger;
import java.util.ArrayList;
/**
*
*/
public abstract class ControlledRunnable implements Runnable {
protected boolean runCmd = false;
protected boolean runStatus = false;
private Thread thisThread;
private final String threadName;
public ControlledRunnable(String threadName) {
super();
this.threadName = threadName;
ControlledRunnable.runnables.add(this);
}
/*
* Main loop
*/
/**
* This is the method called when ControlledRunnable.thisThread.start() is
* called.
*/
@Override
public void run() {
if (this._preRun() == false) {
return;
}
this.runStatus = true;
if (this._Run() == false) {
return;
}
if (this._postRun() == false) {
return;
}
this.runStatus = false;
}
/**
* _preRun() is called prior to the call to _Run(), but after _startup()
*
* @return
*/
protected abstract boolean _preRun();
/**
* _Run() is called after _startup() and contains should contain the main
* loop.
*
* @return
*/
protected abstract boolean _Run();
/**
* _postRun() is called after _Run() exits, not necessarily before
* _shutdown()
*
* @return
*/
protected abstract boolean _postRun();
/*
* Control
*/
/**
* startup() initializes the internal thread, sets the runCMD to true, and
* calls _startup() prior to starting of the internal Thread.
*/
public void startup() {
this.thisThread = new Thread(this, this.threadName);
this.runCmd = true;
this._startup();
this.thisThread.start();
}
/**
* This method is called just before ControlledRunnable.thisThread.start()
* is called.
*/
protected abstract void _startup();
/**
* This method is called to request a shutdown of the runnable.
*/
public void shutdown() {
this.runCmd = false;
this._shutdown();
}
/**
* This method is called just after ControlledRunnable.runCmd is set to
* False.
*/
protected abstract void _shutdown();
/*
* Getters n setters
*/
public boolean getRunCmd() {
return runCmd;
}
public boolean getRunStatus() {
return runStatus;
}
/*
* Blockers
*/
public void blockTillRunStatus(boolean status) {
while (this.runStatus != status) {
try {
System.out.println("BLOCKING");
Thread.sleep(25L);
} catch (InterruptedException e) {
Logger.debug( e.getMessage());
break;
}
}
}
/**
* @return the thisThread
*/
protected Thread getThisThread() {
return thisThread;
}
/**
* @return the threadName
*/
public String getThreadName() {
return threadName;
}
/*
* Instance monitoring and tools
*/
// Runnable tracking
private static final ArrayList<ControlledRunnable> runnables = new ArrayList<>();
public static void shutdownAllRunnables() {
for (ControlledRunnable cr : ControlledRunnable.runnables) {
//Use Direct logging since JobManager is a runnable.
Logger.info("ControlledRunnable",
"Sending Shutdown cmd to: " + cr.threadName);
cr.shutdown();
}
}
}

383
src/engine/db/archive/BaneRecord.java

@ -0,0 +1,383 @@ @@ -0,0 +1,383 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.db.archive;
import engine.Enum;
import engine.objects.Bane;
import engine.objects.City;
import engine.workthreads.WarehousePushThread;
import org.joda.time.DateTime;
import org.pmw.tinylog.Logger;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.concurrent.LinkedBlockingQueue;
import static engine.Enum.RecordEventType;
public class BaneRecord extends DataRecord {
private static final LinkedBlockingQueue<BaneRecord> recordPool = new LinkedBlockingQueue<>();
private RecordEventType eventType;
private String cityHash;
private String cityName;
private String cityGuildHash;
private String cityNationHash;
private String baneDropperHash;
private String baneGuildHash;
private String baneNationHash;
private DateTime baneLiveTime;
private DateTime baneDropTime;
private BaneRecord(Bane bane) {
this.recordType = Enum.DataRecordType.BANE;
this.eventType = RecordEventType.PENDING;
}
public static BaneRecord borrow(Bane bane, RecordEventType eventType) {
BaneRecord baneRecord;
baneRecord = recordPool.poll();
if (baneRecord == null) {
baneRecord = new BaneRecord(bane);
baneRecord.eventType = eventType;
}
else {
baneRecord.recordType = Enum.DataRecordType.BANE;
baneRecord.eventType = eventType;
}
baneRecord.cityHash = bane.getCity().getHash();
baneRecord.cityName = bane.getCity().getCityName();
baneRecord.cityGuildHash = bane.getCity().getGuild().getHash();
baneRecord.cityNationHash = bane.getCity().getGuild().getNation().getHash();
if (bane.getOwner() == null) {
baneRecord.baneDropperHash = "ERRANT";
baneRecord.baneGuildHash = "ERRANT";
baneRecord.baneNationHash = "ERRANT";
}
else {
baneRecord.baneDropperHash = DataWarehouse.hasher.encrypt(bane.getOwner().getObjectUUID()); // getPlayerCharacter didn't check hash first? OMFG
baneRecord.baneGuildHash = bane.getOwner().getGuild().getHash();
baneRecord.baneNationHash = bane.getOwner().getGuild().getNation().getHash();
baneRecord.baneLiveTime = bane.getLiveDate();
baneRecord.baneDropTime = bane.getPlacementDate();
}
return baneRecord;
}
public static PreparedStatement buildBanePushStatement(Connection connection, ResultSet rs) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "INSERT INTO `warehouse_banehistory` (`event_number`, `city_id`, `city_name`, `char_id`, `offGuild_id`, `offNat_id`, `defGuild_id`, `defNat_id`, `dropDatetime`, `liveDateTime`, `resolution`) VALUES(?,?,?,?,?,?,?,?,?,?,?)";
java.util.Date sqlDateTime;
outStatement = connection.prepareStatement(queryString);
// Bind record data
outStatement.setInt(1, rs.getInt("event_number"));
outStatement.setString(2, rs.getString("city_id"));
outStatement.setString(3, rs.getString("city_name"));
outStatement.setString(4, rs.getString("char_id"));
outStatement.setString(5, rs.getString("offGuild_id"));
outStatement.setString(6, rs.getString("offNat_id"));
outStatement.setString(7, rs.getString("defGuild_id"));
outStatement.setString(8, rs.getString("defNat_id"));
sqlDateTime = rs.getTimestamp("dropDatetime");
if (sqlDateTime == null)
outStatement.setNull(9, Types.DATE);
else
outStatement.setTimestamp(9, rs.getTimestamp("dropDatetime"));
sqlDateTime = rs.getTimestamp("dropDatetime");
if (sqlDateTime == null)
outStatement.setNull(10, Types.DATE);
else
outStatement.setTimestamp(10, rs.getTimestamp("liveDateTime"));
outStatement.setString(11, rs.getString("resolution"));
return outStatement;
}
public static PreparedStatement buildBaneQueryStatement(Connection connection) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "SELECT * FROM `warehouse_banehistory` WHERE `event_number` > ?";
outStatement = connection.prepareStatement(queryString);
outStatement.setInt(1, WarehousePushThread.baneIndex);
return outStatement;
}
public static DateTime getLastBaneDateTime(City city) {
DateTime outDateTime = null;
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = buildDateTimeQueryStatement(connection, city);
ResultSet rs = statement.executeQuery()) {
while (rs.next()) {
outDateTime = new DateTime(rs.getTimestamp("endDatetime"));
}
} catch (SQLException e) {
Logger.error( e.toString());
}
return outDateTime;
}
private static PreparedStatement buildDateTimeQueryStatement (Connection connection, City city) throws SQLException {
PreparedStatement outStatement;
String queryString = "SELECT `endDatetime` FROM `warehouse_banehistory` WHERE `city_id` = ? ORDER BY `endDatetime` DESC LIMIT 1";
outStatement = connection.prepareStatement(queryString);
outStatement.setString(1, city.getHash());
return outStatement;
}
public static void updateLiveDate(Bane bane, DateTime dateTime) {
if (bane == null)
return;
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = buildUpdateLiveDateStatement(connection, bane, dateTime)) {
statement.execute();
} catch (SQLException e) {
Logger.error( e.toString());
}
}
private static PreparedStatement buildUpdateLiveDateStatement(Connection connection, Bane bane, DateTime dateTime) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "UPDATE `warehouse_banehistory` SET `liveDatetime` = ?, `dirty` = 1 WHERE `city_id` = ? AND `resolution` = 'PENDING'";
outStatement = connection.prepareStatement(queryString);
outStatement.setTimestamp(1, new java.sql.Timestamp(dateTime.getMillis()));
outStatement.setString(2, bane.getCity().getHash());
return outStatement;
}
private static PreparedStatement buildUpdateResolutionStatement(Connection connection, Bane bane, RecordEventType eventType) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "UPDATE `warehouse_banehistory` SET `endDatetime` = ?, `resolution` = ?, `dirty` = 1 WHERE `city_id` = ? AND `resolution` = 'PENDING'";
outStatement = connection.prepareStatement(queryString);
outStatement.setTimestamp(1, Timestamp.valueOf(LocalDateTime.now()));
outStatement.setString(2, eventType.name());
outStatement.setString(3, bane.getCity().getHash());
return outStatement;
}
public static void updateResolution(Bane bane, RecordEventType eventType) {
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = buildUpdateResolutionStatement(connection, bane, eventType)) {
statement.execute();
} catch (SQLException e) {
Logger.error(e.toString());
}
}
public static String getBaneHistoryString() {
String outString;
String queryString;
String dividerString;
String newLine = System.getProperty("line.separator");
outString = "[LUA_BANES() DATA WAREHOUSE]" + newLine;
dividerString = "--------------------------------" + newLine;
queryString = "CALL `baneHistory`()";
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = connection.prepareCall(queryString);
ResultSet rs = statement.executeQuery()) {
while (rs.next()) {
outString += "Magicbane unresolved banes: " + rs.getInt("PENDING") + '/' + rs.getInt("TOTAL") + newLine;
outString += dividerString;
outString += "Bane Resolution History" + newLine;
outString += dividerString;
outString += "Destruction: " + rs.getInt("DESTROY") + newLine;
outString += "Capture: " + rs.getInt("CAPTURE") + newLine;
outString += "Defended: " + rs.getInt("DEFEND") + newLine;
}
} catch (SQLException e) {
e.printStackTrace();
}
return outString;
}
public static void updateDirtyRecords() {
String queryString = "SELECT * FROM `warehouse_banehistory` where `dirty` = 1";
// Reset character delta
WarehousePushThread.baneDelta = 0;
try (Connection localConnection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = localConnection.prepareStatement(queryString, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); // Make this an updatable result set as we'll reset the dirty flag as we go along
ResultSet rs = statement.executeQuery()) {
while (rs.next()) {
// Only update the index and dirty flag
// if the remote database update succeeded
if (updateDirtyRecord(rs) == true)
WarehousePushThread.baneDelta++;
else
continue;
// Reset the dirty flag in the local database
rs.updateInt("dirty", 0);
rs.updateRow();
}
} catch (SQLException e) {
Logger.error( e.toString());
}
}
private static boolean updateDirtyRecord(ResultSet rs) {
try (Connection remoteConnection = DataWarehouse.remoteConnectionPool.getConnection();
PreparedStatement statement = buildUpdateDirtyStatement(remoteConnection, rs)) {
statement.execute();
return true;
} catch (SQLException e) {
Logger.error( e.toString());
return false;
}
}
private static PreparedStatement buildUpdateDirtyStatement(Connection connection, ResultSet rs) throws SQLException {
PreparedStatement outStatement;
String queryString = "UPDATE `warehouse_banehistory` SET `liveDateTime` = ?, `endDateTime` = ?, `resolution` = ? WHERE `event_number` = ?";
java.util.Date sqlDateTime;
outStatement = connection.prepareStatement(queryString);
// Bind record data
sqlDateTime = rs.getTimestamp("liveDateTime");
if (sqlDateTime == null)
outStatement.setNull(1, Types.DATE);
else
outStatement.setTimestamp(1, rs.getTimestamp("liveDateTime"));
sqlDateTime = rs.getTimestamp("endDateTime");
if (sqlDateTime == null)
outStatement.setNull(2, Types.DATE);
else
outStatement.setTimestamp(2, rs.getTimestamp("endDateTime"));
outStatement.setString(3, rs.getString("resolution"));
outStatement.setInt(4, rs.getInt("event_number"));
return outStatement;
}
void reset() {
this.cityHash = null;
this.cityGuildHash = null;
this.cityNationHash = null;
this.baneDropperHash = null;
this.baneGuildHash = null;
this.baneNationHash = null;
this.baneLiveTime = null;
}
public void release() {
this.reset();
recordPool.add(this);
}
public void write() {
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = buildBaneInsertStatement(connection)) {
statement.execute();
} catch (SQLException e) {
Logger.error( e.toString());
}
}
private PreparedStatement buildBaneInsertStatement(Connection connection) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "INSERT INTO `warehouse_banehistory` (`city_id`, `city_name`, `char_id`, `offGuild_id`, `offNat_id`, `defGuild_id`, `defNat_id`, `dropDatetime`, `liveDateTime`, `resolution`) VALUES(?,?,?,?,?,?,?,?,?,?)";
outStatement = connection.prepareStatement(queryString);
outStatement.setString(1, this.cityHash);
outStatement.setString(2, this.cityName);
outStatement.setString(3, this.baneDropperHash);
outStatement.setString(4, this.baneGuildHash);
outStatement.setString(5, this.baneNationHash);
outStatement.setString(6, this.cityGuildHash);
outStatement.setString(7, this.cityNationHash);
if (this.baneDropTime == null)
outStatement.setNull(8, java.sql.Types.DATE);
else
outStatement.setTimestamp(8, new java.sql.Timestamp(this.baneDropTime.getMillis()));
if (this.baneLiveTime == null)
outStatement.setNull(9, java.sql.Types.DATE);
else
outStatement.setTimestamp(9, new java.sql.Timestamp(this.baneLiveTime.getMillis()));
outStatement.setString(10, this.eventType.name());
return outStatement;
}
} // END CLASS

284
src/engine/db/archive/CharacterRecord.java

@ -0,0 +1,284 @@ @@ -0,0 +1,284 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.db.archive;
import engine.Enum;
import engine.objects.Guild;
import engine.objects.PlayerCharacter;
import engine.workthreads.WarehousePushThread;
import org.pmw.tinylog.Logger;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.concurrent.LinkedBlockingQueue;
/*
* This class warehouses character creation events. It also tracks
* updates to summary kills/death data and their promotion class.
*/
public class CharacterRecord extends DataRecord {
// Local object pool for class
private static final LinkedBlockingQueue<CharacterRecord> recordPool = new LinkedBlockingQueue<>();
private PlayerCharacter player;
private CharacterRecord(PlayerCharacter player) {
this.recordType = Enum.DataRecordType.CHARACTER;
this.player = player;
}
public static CharacterRecord borrow(PlayerCharacter player) {
CharacterRecord characterRecord;
characterRecord = recordPool.poll();
if (characterRecord == null) {
characterRecord = new CharacterRecord(player);
}
else {
characterRecord.recordType = Enum.DataRecordType.CHARACTER;
characterRecord.player = player;
}
return characterRecord;
}
private static PreparedStatement buildCharacterInsertStatement(Connection connection, PlayerCharacter player) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "INSERT INTO `warehouse_characterhistory` (`char_id`, `char_fname`, `char_lname`, `baseClass`, `race`, `promoteClass`, `startingGuild`, `datetime`) VALUES(?,?,?,?,?,?,?,?)";
Guild charGuild;
outStatement = connection.prepareStatement(queryString);
charGuild = player.getGuild();
// Bind character data
outStatement.setString(1, DataWarehouse.hasher.encrypt(player.getObjectUUID()));
outStatement.setString(2, player.getFirstName());
outStatement.setString(3, player.getLastName());
outStatement.setInt(4, player.getBaseClassID());
outStatement.setInt(5, player.getRaceID());
outStatement.setInt(6, player.getPromotionClassID());
outStatement.setString(7, DataWarehouse.hasher.encrypt(charGuild.getObjectUUID()));
outStatement.setTimestamp(8, Timestamp.valueOf(LocalDateTime.now()));
return outStatement;
}
public static PreparedStatement buildCharacterPushStatement(Connection connection, ResultSet rs) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "INSERT INTO `warehouse_characterhistory` (`event_number`, `char_id`, `char_fname`, `char_lname`, `baseClass`, `race`, `promoteClass`, `startingGuild`, `datetime`) VALUES(?,?,?,?,?,?,?,?,?)";
outStatement = connection.prepareStatement(queryString);
// Bind record data
outStatement.setInt(1, rs.getInt("event_number"));
outStatement.setString(2, rs.getString("char_id"));
outStatement.setString(3, rs.getString("char_fname"));
outStatement.setString(4, rs.getString("char_lname"));
outStatement.setInt(5, rs.getInt("baseClass"));
outStatement.setInt(6, rs.getInt("race"));
outStatement.setInt(7, rs.getInt("promoteClass"));
outStatement.setString(8, rs.getString("startingGuild"));
outStatement.setTimestamp(9, rs.getTimestamp("datetime"));
return outStatement;
}
public static PreparedStatement buildCharacterQueryStatement(Connection connection) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "SELECT * FROM `warehouse_characterhistory` WHERE `event_number` > ?";
outStatement = connection.prepareStatement(queryString);
outStatement.setInt(1, WarehousePushThread.charIndex);
return outStatement;
}
public static void advanceKillCounter(PlayerCharacter player) {
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = buildKillCounterStatement(connection, player)) {
statement.execute();
} catch (SQLException e) {
Logger.error( e.toString());
}
}
private static PreparedStatement buildKillCounterStatement(Connection connection, PlayerCharacter player) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "UPDATE `warehouse_characterhistory` SET `kills` = `kills` +1, `dirty` = 1 WHERE `char_id` = ?";
if (player == null)
return outStatement;
outStatement = connection.prepareStatement(queryString);
outStatement.setString(1, player.getHash());
return outStatement;
}
public static void advanceDeathCounter(PlayerCharacter player) {
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = buildDeathCounterStatement(connection, player)) {
statement.execute();
} catch (SQLException e) {
Logger.error( e.toString());
}
}
private static PreparedStatement buildDeathCounterStatement(Connection connection, PlayerCharacter player) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "UPDATE `warehouse_characterhistory` SET `deaths` = `deaths` +1, `dirty` = 1 WHERE `char_id` = ?";
if (player == null)
return outStatement;
outStatement = connection.prepareStatement(queryString);
outStatement.setString(1, player.getHash());
return outStatement;
}
public static void updatePromotionClass(PlayerCharacter player) {
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = buildUpdatePromotionStatement(connection, player)) {
statement.execute();
} catch (SQLException e) {
Logger.error( e.toString());
}
}
private static PreparedStatement buildUpdatePromotionStatement(Connection connection, PlayerCharacter player) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "UPDATE `warehouse_characterhistory` SET `promoteClass` = ?, `dirty` = 1 WHERE `char_id` = ?";
if (player == null)
return outStatement;
outStatement = connection.prepareStatement(queryString, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
outStatement.setInt(1, player.getPromotionClassID());
outStatement.setString(2, player.getHash());
return outStatement;
}
public static void updateDirtyRecords() {
String queryString = "SELECT * FROM `warehouse_characterhistory` where `dirty` = 1";
// Reset character delta
WarehousePushThread.charDelta = 0;
try (Connection localConnection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = localConnection.prepareStatement(queryString, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); // Make this an updatable result set as we'll reset the dirty flag as we go along
ResultSet rs = statement.executeQuery()) {
while (rs.next()) {
// Only update the index and dirty flag
// if the remote database update succeeded
if (updateDirtyRecord(rs) == true)
WarehousePushThread.charDelta++;
else
continue;
// Reset the dirty flag in the local database
rs.updateInt("dirty", 0);
rs.updateRow();
}
} catch (SQLException e) {
Logger.error(e.toString());
}
}
private static boolean updateDirtyRecord(ResultSet rs) {
try (Connection remoteConnection = DataWarehouse.remoteConnectionPool.getConnection();
PreparedStatement statement = buildUpdateDirtyStatement(remoteConnection, rs)) {
statement.execute();
return true;
} catch (SQLException e) {
Logger.error(e.toString());
return false;
}
}
private static PreparedStatement buildUpdateDirtyStatement(Connection connection, ResultSet rs) throws SQLException {
PreparedStatement outStatement;
String queryString = "UPDATE `warehouse_characterhistory` SET `promoteClass` = ?, `kills` = ?, `deaths` = ? WHERE `char_id` = ?";
outStatement = connection.prepareStatement(queryString);
// Bind record data
outStatement.setInt(1, rs.getInt("promoteClass"));
outStatement.setInt(2, rs.getInt("kills"));
outStatement.setInt(3, rs.getInt("deaths"));
outStatement.setString(4, rs.getString("char_id"));
return outStatement;
}
void reset() {
this.player = null;
}
public void release() {
this.reset();
recordPool.add(this);
}
public void write() {
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = buildCharacterInsertStatement(connection, this.player)) {
statement.execute();
} catch (SQLException e) {
Logger.error( "Error writing character record " + e.toString());
}
}
}

161
src/engine/db/archive/CityRecord.java

@ -0,0 +1,161 @@ @@ -0,0 +1,161 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.db.archive;
import engine.Enum;
import engine.objects.City;
import engine.workthreads.WarehousePushThread;
import java.sql.*;
import java.util.concurrent.LinkedBlockingQueue;
public class CityRecord extends DataRecord {
private static final LinkedBlockingQueue<CityRecord> recordPool = new LinkedBlockingQueue<>();
private Enum.RecordEventType eventType;
private City city;
private String cityHash;
private String cityGuildHash;
private String cityName;
private String cityMotto;
private float locX;
private float locY;
private String zoneHash;
private java.time.LocalDateTime establishedDatetime;
private CityRecord(City city) {
this.recordType = Enum.DataRecordType.CITY;
this.city = city;
this.eventType = Enum.RecordEventType.CREATE;
}
public static CityRecord borrow(City city, Enum.RecordEventType eventType) {
CityRecord cityRecord;
cityRecord = recordPool.poll();
if (cityRecord == null) {
cityRecord = new CityRecord(city);
cityRecord.eventType = eventType;
}
else {
cityRecord.recordType = Enum.DataRecordType.CITY;
cityRecord.eventType = eventType;
cityRecord.city = city;
}
if (cityRecord.city.getHash() == null)
cityRecord.city.setHash(DataWarehouse.hasher.encrypt(cityRecord.city.getObjectUUID()));
cityRecord.cityHash = cityRecord.city.getHash();
cityRecord.cityName = cityRecord.city.getCityName();
cityRecord.cityMotto = cityRecord.city.getMotto();
cityRecord.cityGuildHash = cityRecord.city.getGuild().getHash();
cityRecord.locX = cityRecord.city.getTOL().getLoc().x;
cityRecord.locY = -cityRecord.city.getTOL().getLoc().z; // flip sign on 'y' coordinate
cityRecord.zoneHash = cityRecord.city.getParent().getHash();
if (cityRecord.eventType.equals(Enum.RecordEventType.CREATE))
cityRecord.establishedDatetime = cityRecord.city.established;
else
cityRecord.establishedDatetime = java.time.LocalDateTime.now();
return cityRecord;
}
public static PreparedStatement buildCityPushStatement(Connection connection, ResultSet rs) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "INSERT INTO `warehouse_cityhistory` (`event_number`, `city_id`, `city_name`, `city_motto`, `guild_id`, `loc_x`, `loc_y`, `zone_id`, `eventType`, `datetime`) VALUES(?,?,?,?,?,?,?,?,?,?)";
outStatement = connection.prepareStatement(queryString);
// Bind record data
outStatement.setInt(1, rs.getInt("event_number"));
outStatement.setString(2, rs.getString("city_id"));
outStatement.setString(3, rs.getString("city_name"));
outStatement.setString(4, rs.getString("city_motto"));
outStatement.setString(5, rs.getString("guild_id"));
outStatement.setFloat(6, rs.getFloat("loc_x"));
outStatement.setFloat(7, rs.getFloat("loc_y"));
outStatement.setString(8, rs.getString("zone_id"));
outStatement.setString(9, rs.getString("eventType"));
outStatement.setTimestamp(10, rs.getTimestamp("datetime"));
return outStatement;
}
public static PreparedStatement buildCityQueryStatement(Connection connection) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "SELECT * FROM `warehouse_cityhistory` WHERE `event_number` > ?";
outStatement = connection.prepareStatement(queryString);
outStatement.setInt(1, WarehousePushThread.cityIndex);
return outStatement;
}
void reset() {
this.city = null;
this.cityHash = null;
this.cityGuildHash = null;
this.cityMotto = null;
this.zoneHash = null;
this.establishedDatetime = null;
}
public void release() {
this.reset();
recordPool.add(this);
}
public void write() {
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = this.buildCityInsertStatement(connection)) {
statement.execute();
} catch (SQLException e) {
e.printStackTrace();
}
}
private PreparedStatement buildCityInsertStatement(Connection connection) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "INSERT INTO `warehouse_cityhistory` (`city_id`, `city_name`, `city_motto`, `guild_id`, `loc_x`, `loc_y`, `zone_id`, `eventType`, `datetime`) VALUES(?,?,?,?,?,?,?,?,?)";
outStatement = connection.prepareStatement(queryString);
// Bind character data
outStatement.setString(1, this.cityHash);
outStatement.setString(2, this.cityName);
outStatement.setString(3, this.cityMotto);
outStatement.setString(4, this.cityGuildHash);
outStatement.setFloat(5, this.locX);
outStatement.setFloat(6, this.locY);
outStatement.setString(7, this.zoneHash);
outStatement.setString(8, this.eventType.name());
outStatement.setTimestamp(9, Timestamp.valueOf(this.establishedDatetime));
return outStatement;
}
}

23
src/engine/db/archive/DataRecord.java

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.db.archive;
import engine.Enum;
class DataRecord {
public Enum.DataRecordType recordType;
DataRecord() {
}
}

324
src/engine/db/archive/DataWarehouse.java

@ -0,0 +1,324 @@ @@ -0,0 +1,324 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.db.archive;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import engine.gameManager.ConfigManager;
import engine.util.Hasher;
import org.pmw.tinylog.Logger;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.LinkedBlockingQueue;
import static engine.Enum.DataRecordType;
public class DataWarehouse implements Runnable {
public static final Hasher hasher = new Hasher("Cthulhu Owns Joo");
private static final LinkedBlockingQueue<DataRecord> recordQueue = new LinkedBlockingQueue<>();
public static HikariDataSource connectionPool = null;
public static HikariDataSource remoteConnectionPool = null;
public DataWarehouse() {
Logger.info("Configuring local Database Connection Pool...");
configureConnectionPool();
// If WarehousePush is disabled
// then early exit
if ( ConfigManager.MB_WORLD_WAREHOUSE_PUSH.getValue().equals("false")) {
Logger.info("Warehouse Remote Connection disabled along with push");
return;
}
Logger.info( "Configuring remote Database Connection Pool...");
configureRemoteConnectionPool();
}
public static void bootStrap() {
Thread warehousingThread;
warehousingThread = new Thread(new DataWarehouse());
warehousingThread.setName("DataWarehouse");
warehousingThread.setPriority(Thread.NORM_PRIORITY - 1);
warehousingThread.start();
}
public static void pushToWarehouse(DataRecord dataRecord) {
DataWarehouse.recordQueue.add(dataRecord);
}
public static void writeHash(DataRecordType recordType, int uuid) {
// Member variable declaration
Connection connection = null;
PreparedStatement statement = null;
String queryString;
String hashString;
try {
connection = DataWarehouse.connectionPool.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
if (connection == null) {
Logger.error("Null connection when writing zone hash.");
return;
}
// Build query string
switch (recordType) {
case CHARACTER:
queryString = "UPDATE `obj_character` SET hash = ? WHERE `UID` = ?";
break;
case GUILD:
queryString = "UPDATE `obj_guild` SET hash = ? WHERE `UID` = ?";
break;
case ZONE:
queryString = "UPDATE `obj_zone` SET hash = ? WHERE `UID` = ?";
break;
case CITY:
queryString = "UPDATE `obj_city` SET hash = ? WHERE `UID` = ?";
break;
case REALM:
queryString = "UPDATE `obj_realm` SET hash = ? WHERE `realmID` = ?";
break;
default:
queryString = null;
break;
}
hashString = hasher.encrypt(uuid);
// Write this record to the warehouse
try {
statement = connection.prepareStatement(queryString);
statement.setString(1, hashString);
statement.setLong(2, uuid);
statement.execute();
} catch (SQLException e) {
Logger.error("Error writing hash for uuid" + uuid + " of type " + recordType.name() + ' ' + e.toString());
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
public static boolean recordExists(DataRecordType recordType, int uuid) {
// Member variable declaration
Connection connection = null;
PreparedStatement statement = null;
String queryString;
ResultSet resultSet;
try {
connection = DataWarehouse.connectionPool.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
if (connection == null) {
Logger.error("Null connection during char record lookup");
return true; // False positive here, so as not to try and write the record twice.
// will refactor out once we write hashes to object tables
}
// Build query string
switch (recordType) {
case CHARACTER:
queryString = "SELECT COUNT(*) from warehouse_characterhistory where char_id = ?";
break;
case GUILD:
queryString = "SELECT COUNT(*) from warehouse_guildhistory where guild_id = ?";
break;
case CITY:
queryString = "SELECT COUNT(*) from warehouse_cityhistory where city_id = ?";
break;
case REALM:
queryString = "SELECT COUNT(*) from warehouse_realmhistory where realm_id = ?";
break;
case BANE:
queryString = "SELECT COUNT(*) from warehouse_banehistory where city_id = ? AND `resolution` = 'PENDING'";
break;
case ZONE: // Does not really exist but enum acts as a proxy for hash lookup
case MINE: // Does not really exist but enum acts as a proxy for hash lookup
default:
queryString = null;
break;
}
try {
statement = connection.prepareStatement(queryString);
statement.setString(1, DataWarehouse.hasher.encrypt(uuid));
resultSet = statement.executeQuery();
while (resultSet.next()) {
return resultSet.getInt("COUNT(*)") > 0;
}
} catch (SQLException e) {
Logger.error("Error in record lookup for " + recordType.name() + " of uuid:" + uuid + e.toString());
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return false;
}
public void run() {
// Working variable set
DataRecord dataRecord;
PvpRecord pvpRecord;
GuildRecord guildRecord;
CharacterRecord characterRecord;
CityRecord cityRecord;
BaneRecord baneRecord;
RealmRecord realmRecord;
MineRecord mineRecord;
Logger.info( "DataWarehouse is running.");
while (true) {
dataRecord = null;
pvpRecord = null;
guildRecord = null;
characterRecord = null;
cityRecord = null;
baneRecord = null;
realmRecord = null;
mineRecord = null;
try {
dataRecord = recordQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
// Write record to appropriate warehousing table
if (dataRecord != null) {
switch (dataRecord.recordType) {
case PVP:
pvpRecord = (PvpRecord) dataRecord;
pvpRecord.write();
pvpRecord.release();
break;
case CHARACTER:
characterRecord = (CharacterRecord) dataRecord;
characterRecord.write();
characterRecord.release();
break;
case GUILD:
guildRecord = (GuildRecord) dataRecord;
guildRecord.write();
guildRecord.release();
break;
case CITY:
cityRecord = (CityRecord) dataRecord;
cityRecord.write();
cityRecord.release();
break;
case BANE:
baneRecord = (BaneRecord) dataRecord;
baneRecord.write();
baneRecord.release();
break;
case REALM:
realmRecord = (RealmRecord) dataRecord;
realmRecord.write();
realmRecord.release();
break;
case MINE:
mineRecord = (MineRecord) dataRecord;
mineRecord.write();
mineRecord.release();
break;
default:
Logger.error( "Unhandled record type");
break;
} // end switch
}
}
}
private static void configureConnectionPool() {
HikariConfig config = new HikariConfig();
config.setMaximumPoolSize(10);
config.setJdbcUrl("jdbc:mysql://" + ConfigManager.MB_DATABASE_ADDRESS.getValue() +
":" + ConfigManager.MB_DATABASE_PORT.getValue() + "/" +
ConfigManager.MB_DATABASE_NAME.getValue());
config.setUsername(ConfigManager.MB_DATABASE_USER.getValue());
config.setPassword( ConfigManager.MB_DATABASE_PASS.getValue());
config.addDataSourceProperty("characterEncoding", "utf8");
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
connectionPool = new HikariDataSource(config); // setup the connection pool
Logger.info("Local warehouse database connection configured");
}
private static void configureRemoteConnectionPool() {
HikariConfig config = new HikariConfig();
config.setMaximumPoolSize(1); // Only the server talks to remote, so yeah.
config.setJdbcUrl(ConfigManager.MB_WAREHOUSE_ADDR.getValue());
config.setUsername(ConfigManager.MB_WAREHOUSE_USER.getValue());
config.setPassword(ConfigManager.MB_WAREHOUSE_PASS.getValue());
config.addDataSourceProperty("characterEncoding", "utf8");
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
remoteConnectionPool = new HikariDataSource(config); // setup the connection pool
Logger.info("remote warehouse connection configured");
}
}

215
src/engine/db/archive/GuildRecord.java

@ -0,0 +1,215 @@ @@ -0,0 +1,215 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.db.archive;
import engine.Enum;
import engine.Enum.RecordEventType;
import engine.objects.Guild;
import engine.workthreads.WarehousePushThread;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.concurrent.LinkedBlockingQueue;
public class GuildRecord extends DataRecord {
private static final LinkedBlockingQueue<GuildRecord> recordPool = new LinkedBlockingQueue<>();
private Enum.RecordEventType eventType;
private Guild guild;
public String guildHash;
private String guildName;
private String charterName;
private String GLHash;
private String guildMotto;
private int bgIcon;
private int bgColour1;
private int bgColour2;
private int fgIcon;
private int fgColour;
public int guildID;
private java.time.LocalDateTime eventDatetime;
public static HashMap<Integer, GuildRecord> GuildRecordCache = null;
private GuildRecord(Guild guild) {
this.recordType = Enum.DataRecordType.GUILD;
this.guild = guild;
this.eventType = Enum.RecordEventType.CREATE;
}
public GuildRecord(ResultSet rs) throws SQLException {
super();
this.eventType = RecordEventType.valueOf(rs.getString("eventType"));
this.guildHash = rs.getString("guild_id");
this.guildName = rs.getString("guild_name");
this.charterName = rs.getString("charter");
GLHash = rs.getString("guild_founder");
this.guildMotto = rs.getString("guild_motto");
this.bgIcon = rs.getInt("bgicon");
this.bgColour1 = rs.getInt("bgcoloura");
this.bgColour2 = rs.getInt("bgcolourb");
this.fgIcon = rs.getInt("fgicon");
this.fgColour = rs.getInt("fgcolour");
java.sql.Timestamp eventTimeStamp = rs.getTimestamp("upgradeDate");
if (eventTimeStamp != null)
this.eventDatetime = LocalDateTime.ofInstant(eventTimeStamp.toInstant(), ZoneId.systemDefault());
}
public static GuildRecord borrow(Guild guild, Enum.RecordEventType eventType) {
GuildRecord guildRecord;
//add
guildRecord = recordPool.poll();
if (guildRecord == null) {
guildRecord = new GuildRecord(guild);
guildRecord.eventType = eventType;
}
else {
guildRecord.guild = guild;
guildRecord.recordType = Enum.DataRecordType.GUILD;
guildRecord.eventType = eventType;
}
guildRecord.guildHash = guildRecord.guild.getHash();
guildRecord.guildID = guildRecord.guild.getObjectUUID();
guildRecord.guildName = guildRecord.guild.getName();
guildRecord.charterName = Enum.GuildType.getGuildTypeFromInt(guildRecord.guild.getCharter()).getCharterName();
guildRecord.GLHash = DataWarehouse.hasher.encrypt(guildRecord.guild.getGuildLeaderUUID());
guildRecord.guildMotto = guildRecord.guild.getMotto();
guildRecord.bgIcon = guildRecord.guild.getBgDesign();
guildRecord.bgColour1 = guildRecord.guild.getBgc1();
guildRecord.bgColour2 = guildRecord.guild.getBgc2();
guildRecord.fgIcon = guildRecord.guild.getSymbol();
guildRecord.fgColour = guildRecord.guild.getSc();
if (guild.getOwnedCity() != null)
guildRecord.eventDatetime = guild.getOwnedCity().established;
else
guildRecord.eventDatetime = LocalDateTime.now();
return guildRecord;
}
public static PreparedStatement buildGuildPushStatement(Connection connection, ResultSet rs) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "INSERT INTO `warehouse_guildhistory` (`event_number`, `guild_id`, `guild_name`, `guild_motto`, `guild_founder`, `charter`, `bgicon`, `bgcoloura`, `bgcolourb`, `fgicon`, `fgcolour`, `eventtype`, `datetime`) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)";
outStatement = connection.prepareStatement(queryString);
// Bind record data
outStatement.setInt(1, rs.getInt("event_number"));
outStatement.setString(2, rs.getString("guild_id"));
outStatement.setString(3, rs.getString("guild_name"));
outStatement.setString(4, rs.getString("guild_motto"));
outStatement.setString(5, rs.getString("guild_founder"));
outStatement.setString(6, rs.getString("charter"));
outStatement.setInt(7, rs.getInt("bgicon"));
outStatement.setInt(8, rs.getInt("bgcoloura"));
outStatement.setInt(9, rs.getInt("bgcolourb"));
outStatement.setInt(10, rs.getInt("fgicon"));
outStatement.setInt(11, rs.getInt("fgcolour"));
outStatement.setString(12, rs.getString("eventtype"));
outStatement.setTimestamp(13, rs.getTimestamp("datetime"));
return outStatement;
}
public static PreparedStatement buildGuildQueryStatement(Connection connection) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "SELECT * FROM `warehouse_guildhistory` WHERE `event_number` > ?";
outStatement = connection.prepareStatement(queryString);
outStatement.setInt(1, WarehousePushThread.guildIndex);
return outStatement;
}
void reset() {
this.guild = null;
this.guildHash = null;
this.GLHash = null;
this.guildMotto = null;
this.charterName = null;
this.eventDatetime = null;
}
public void release() {
this.reset();
recordPool.add(this);
}
public void write() {
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = this.buildGuildInsertStatement(connection)) {
statement.execute();
} catch (SQLException e) {
e.printStackTrace();
}
}
private PreparedStatement buildGuildInsertStatement(Connection connection) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "INSERT INTO `warehouse_guildhistory` (`guild_id`, `guild_name`, `guild_motto`, `guild_founder`, `charter`, `bgicon`, `bgcoloura`, `bgcolourb`, `fgicon`, `fgcolour`, `eventtype`, `datetime`) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)";
outStatement = connection.prepareStatement(queryString);
// Bind character data
outStatement.setString(1, this.guildHash);
outStatement.setString(2, this.guildName);
outStatement.setString(3, this.guildMotto);
outStatement.setString(4, this.GLHash);
outStatement.setString(5, this.charterName);
outStatement.setInt(6, this.bgIcon);
outStatement.setInt(7, this.bgColour1);
outStatement.setInt(8, this.bgColour2);
outStatement.setInt(9, this.fgIcon);
outStatement.setInt(10, this.fgColour);
outStatement.setString(11, this.eventType.name());
outStatement.setTimestamp(12, new java.sql.Timestamp( this.eventDatetime.atZone(ZoneId.systemDefault())
.toInstant().toEpochMilli()));
return outStatement;
}
// public static void InitializeGuildRecords(){
// GuildRecord.GuildRecordCache = DbManager.GuildQueries.GET_WAREHOUSE_GUILD_HISTORY();
// }
}

166
src/engine/db/archive/MineRecord.java

@ -0,0 +1,166 @@ @@ -0,0 +1,166 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.db.archive;
import engine.Enum;
import engine.objects.AbstractCharacter;
import engine.objects.Mine;
import engine.objects.PlayerCharacter;
import engine.workthreads.WarehousePushThread;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.concurrent.LinkedBlockingQueue;
public class MineRecord extends DataRecord {
private static final LinkedBlockingQueue<MineRecord> recordPool = new LinkedBlockingQueue<>();
private Enum.RecordEventType eventType;
private String zoneHash;
private String charHash;
private String mineGuildHash;
private String mineNationHash;
private String mineType;
private float locX;
private float locY;
private MineRecord() {
this.recordType = Enum.DataRecordType.MINE;
this.eventType = Enum.RecordEventType.CAPTURE;
}
public static MineRecord borrow(Mine mine, AbstractCharacter character, Enum.RecordEventType eventType) {
MineRecord mineRecord;
mineRecord = recordPool.poll();
PlayerCharacter player;
if (mineRecord == null) {
mineRecord = new MineRecord();
mineRecord.eventType = eventType;
}
else {
mineRecord.recordType = Enum.DataRecordType.MINE;
mineRecord.eventType = eventType;
}
mineRecord.zoneHash = mine.getParentZone().getHash();
if (character.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)) {
player = (PlayerCharacter) character;
mineRecord.charHash = player.getHash();
}
else
mineRecord.charHash = character.getName();
DataWarehouse.hasher.encrypt(0);
if (mine.getOwningGuild() == null)
mineRecord.mineGuildHash = "ERRANT";
else
mineRecord.mineGuildHash = mine.getOwningGuild().getHash();
if (mine.getOwningGuild() == null)
mineRecord.mineNationHash = "ERRANT";
else
mineRecord.mineNationHash = mine.getOwningGuild().getNation().getHash();
mineRecord.locX = mine.getParentZone().getLoc().x;
mineRecord.locY = -mine.getParentZone().getLoc().z;
mineRecord.mineType = mine.getMineType().name;
return mineRecord;
}
public static PreparedStatement buildMinePushStatement(Connection connection, ResultSet rs) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "INSERT INTO `warehouse_minehistory` (`event_number`, `zone_id`, `mine_type`, `char_id`, `mine_guildID`, `mine_nationID`, `loc_x`, `loc_y`, `eventType`, `datetime`) VALUES(?,?,?,?,?,?,?,?,?,?)";
outStatement = connection.prepareStatement(queryString);
// Bind record data
outStatement.setInt(1, rs.getInt("event_number"));
outStatement.setString(2, rs.getString("zone_id"));
outStatement.setString(3, rs.getString("char_id"));
outStatement.setString(4, rs.getString("mine_type"));
outStatement.setString(5, rs.getString("mine_guildID"));
outStatement.setString(6, rs.getString("mine_nationID"));
outStatement.setFloat(7, rs.getFloat("loc_x"));
outStatement.setFloat(8, rs.getFloat("loc_y"));
outStatement.setString(9, rs.getString("eventType"));
outStatement.setTimestamp(10, rs.getTimestamp("datetime"));
return outStatement;
}
public static PreparedStatement buildMineQueryStatement(Connection connection) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "SELECT * FROM `warehouse_minehistory` WHERE `event_number` > ?";
outStatement = connection.prepareStatement(queryString);
outStatement.setInt(1, WarehousePushThread.mineIndex);
return outStatement;
}
void reset() {
this.zoneHash = null;
this.charHash = null;
this.mineGuildHash = null;
this.mineNationHash = null;
this.mineType = null;
this.locX = 0.0f;
this.locY = 0.0f;
}
public void release() {
this.reset();
recordPool.add(this);
}
public void write() {
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = this.buildMineInsertStatement(connection)) {
statement.execute();
} catch (SQLException e) {
e.printStackTrace();
}
}
private PreparedStatement buildMineInsertStatement(Connection connection) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "INSERT INTO `warehouse_minehistory` (`zone_id`, `mine_type`, `char_id`, `mine_guildID`, `mine_nationID`, `loc_x`, `loc_y`, `eventType`, `datetime`) VALUES(?,?,?,?,?,?,?,?,?)";
outStatement = connection.prepareStatement(queryString);
// Bind character data
outStatement.setString(1, this.zoneHash);
outStatement.setString(2, this.mineType);
outStatement.setString(3, this.charHash);
outStatement.setString(4, this.mineGuildHash);
outStatement.setString(5, this.mineNationHash);
outStatement.setFloat(6, this.locX);
outStatement.setFloat(7, this.locY);
outStatement.setString(8, this.eventType.name());
outStatement.setTimestamp(9, Timestamp.valueOf(LocalDateTime.now()));
return outStatement;
}
}

312
src/engine/db/archive/PvpRecord.java

@ -0,0 +1,312 @@ @@ -0,0 +1,312 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.db.archive;
import engine.gameManager.ZoneManager;
import engine.math.Vector3fImmutable;
import engine.objects.Guild;
import engine.objects.PlayerCharacter;
import engine.objects.Zone;
import engine.workthreads.WarehousePushThread;
import org.pmw.tinylog.Logger;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.concurrent.LinkedBlockingQueue;
import static engine.Enum.DataRecordType;
import static engine.Enum.PvpHistoryType;
public class PvpRecord extends DataRecord {
private static final LinkedBlockingQueue<PvpRecord> recordPool = new LinkedBlockingQueue<>();
private PlayerCharacter player;
private PlayerCharacter victim;
private Vector3fImmutable location;
private boolean pvpExp;
private PvpRecord(PlayerCharacter player, PlayerCharacter victim, Vector3fImmutable location, boolean pvpExp) {
this.recordType = DataRecordType.PVP;
this.player = player;
this.victim = victim;
this.location = new Vector3fImmutable(location);
this.pvpExp = pvpExp;
}
public static PvpRecord borrow(PlayerCharacter player, PlayerCharacter victim, Vector3fImmutable location, boolean pvpExp) {
PvpRecord pvpRecord;
pvpRecord = recordPool.poll();
if (pvpRecord == null) {
pvpRecord = new PvpRecord(player, victim, location, pvpExp);
}
else {
pvpRecord.recordType = DataRecordType.PVP;
pvpRecord.player = player;
pvpRecord.victim = victim;
pvpRecord.location = new Vector3fImmutable(location);
pvpRecord.pvpExp = pvpExp;
}
return pvpRecord;
}
private static PreparedStatement buildHistoryStatement(Connection connection, int charUUID, PvpHistoryType historyType) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "";
switch (historyType) {
case KILLS:
queryString = "SELECT DISTINCT `victim_id`, `datetime` FROM warehouse_pvphistory where char_id = ? " +
"ORDER BY `datetime` DESC LIMIT 10";
break;
case DEATHS:
queryString = "SELECT DISTINCT `char_id`,`datetime` FROM warehouse_pvphistory where `victim_id` = ? " +
"ORDER BY `datetime` DESC LIMIT 10";
break;
}
outStatement = connection.prepareStatement(queryString);
outStatement.setString(1, DataWarehouse.hasher.encrypt(charUUID));
return outStatement;
}
public static LinkedList<Integer> getCharacterPvPHistory(int charUUID, PvpHistoryType historyType) {
// Member variable declaration
LinkedList<Integer> outList = new LinkedList<>();
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = buildHistoryStatement(connection, charUUID, historyType);
ResultSet rs = statement.executeQuery()) {
while (rs.next()) {
switch (historyType) {
case KILLS:
outList.add((int) DataWarehouse.hasher.decrypt(rs.getString("victim_id"))[0]);
break;
case DEATHS:
outList.add((int) DataWarehouse.hasher.decrypt(rs.getString("char_id"))[0]);
break;
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return outList;
}
private static PreparedStatement buildLuaHistoryQueryStatement(Connection connection, int charUUID) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "CALL `pvpHistory`(?)";
outStatement = connection.prepareStatement(queryString);
outStatement.setString(1, DataWarehouse.hasher.encrypt(charUUID));
return outStatement;
}
public static String getPvpHistoryString(int charUUID) {
String outString;
String dividerString;
String newLine = System.getProperty("line.separator");
outString = "[LUA_PVP() DATA WAREHOUSE]" + newLine;
dividerString = "--------------------------------" + newLine;
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = buildLuaHistoryQueryStatement(connection, charUUID);
ResultSet rs = statement.executeQuery()) {
while (rs.next()) {
int killCount;
int deathCount;
float killRatio;
outString += "Total Magicbane murdered souls: " + rs.getInt("TOTALDEATHS") + newLine;
outString += dividerString;
outString += String.format("%-8s %-8s %-8s %-8s %n", "Period", "Kills", "Deaths", "K/D");
outString += dividerString;
killCount = rs.getInt("KILLCOUNT");
deathCount = rs.getInt("DEATHCOUNT");
if (deathCount == 0)
killRatio = (float) killCount;
else
killRatio = (float) killCount / deathCount;
try {
outString += String.format("%-8s %-8d %-8d %.2f %n", "Total", killCount, deathCount, killRatio);
killCount = rs.getInt("DAILYKILLS");
deathCount = rs.getInt("DAILYDEATHS");
if (deathCount == 0)
killRatio = (float) killCount;
else
killRatio = (float) killCount / deathCount;
outString += String.format("%-8s %-8d %-8d %.2f %n", "24hrs", killCount, deathCount, killRatio);
killCount = rs.getInt("HOURLYKILLS");
deathCount = rs.getInt("HOURLYDEATHS");
if (deathCount == 0)
killRatio = (float) killCount;
else
killRatio = (float) killCount / deathCount;
outString += String.format("%-8s %-8d %-8d %.2f %n", "1hr", killCount, deathCount, killRatio);
} catch (Exception e) {
Logger.error(e.toString());
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return outString;
}
public static PreparedStatement buildPvpPushStatement(Connection connection, ResultSet rs) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "INSERT INTO `warehouse_pvphistory` (`event_number`, `char_id`, `char_guild_id`, `char_nation_id`, `char_level`," +
" `victim_id`, `victim_guild_id`, `victim_nation_id`, `victim_level`," +
" `zone_id`, `zone_name`, `loc_x`, `loc_y`, `gave_exp`, `datetime`) " +
" VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
outStatement = connection.prepareStatement(queryString);
// Bind record data
outStatement.setInt(1, rs.getInt("event_number"));
outStatement.setString(2, rs.getString("char_id"));
outStatement.setString(3, rs.getString("char_guild_id"));
outStatement.setString(4, rs.getString("char_nation_id"));
outStatement.setInt(5, rs.getInt("char_level"));
// Bind victim data
outStatement.setString(6, rs.getString("victim_id"));
outStatement.setString(7, rs.getString("victim_guild_id"));
outStatement.setString(8, rs.getString("victim_nation_id"));
outStatement.setInt(9, rs.getInt("victim_level"));
outStatement.setString(10, rs.getString("zone_id"));
outStatement.setString(11, rs.getString("zone_name"));
outStatement.setFloat(12, rs.getFloat("loc_x"));
outStatement.setFloat(13, rs.getFloat("loc_y"));
outStatement.setBoolean(14, rs.getBoolean("gave_exp"));
outStatement.setTimestamp(15, rs.getTimestamp("datetime"));
return outStatement;
}
public static PreparedStatement buildPvpQueryStatement(Connection connection) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "SELECT * FROM `warehouse_pvphistory` WHERE `event_number` > ?";
outStatement = connection.prepareStatement(queryString);
outStatement.setInt(1, WarehousePushThread.pvpIndex);
return outStatement;
}
void reset() {
this.player = null;
this.victim = null;
this.location = Vector3fImmutable.ZERO;
pvpExp = false;
}
public void release() {
this.reset();
recordPool.add(this);
}
private PreparedStatement buildPvPInsertStatement(Connection connection) throws SQLException {
Guild charGuild;
Guild victimGuild;
Zone zone;
PreparedStatement outStatement = null;
String queryString = "INSERT INTO `warehouse_pvphistory` (`char_id`, `char_guild_id`, `char_nation_id`, `char_level`," +
" `victim_id`, `victim_guild_id`, `victim_nation_id`, `victim_level`," +
" `zone_id`, `zone_name`, `loc_x`, `loc_y`, `gave_exp`, `datetime`) " +
" VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
outStatement = connection.prepareStatement(queryString);
charGuild = this.player.getGuild();
victimGuild = this.victim.getGuild();
// Use a proxy in the situation where a char guild is null (errant)
// Retrieve the zone name where the PvP event occurred
zone = ZoneManager.findSmallestZone(this.location);
outStatement.setString(1, DataWarehouse.hasher.encrypt(this.player.getObjectUUID()));
outStatement.setString(2, DataWarehouse.hasher.encrypt(charGuild.getObjectUUID()));
outStatement.setString(3, DataWarehouse.hasher.encrypt(charGuild.getNation().getObjectUUID()));
outStatement.setInt(4, this.player.getLevel());
// Bind victim data
outStatement.setString(5, DataWarehouse.hasher.encrypt(this.victim.getObjectUUID()));
outStatement.setString(6, DataWarehouse.hasher.encrypt(victimGuild.getObjectUUID()));
outStatement.setString(7, DataWarehouse.hasher.encrypt(victimGuild.getNation().getObjectUUID()));
outStatement.setInt(8, this.victim.getLevel());
outStatement.setString(9, DataWarehouse.hasher.encrypt(zone.getObjectUUID()));
outStatement.setString(10, zone.getName());
outStatement.setFloat(11, this.location.getX());
outStatement.setFloat(12, -this.location.getZ()); // flip sign on 'y' coordinate
outStatement.setBoolean(13, this.pvpExp);
outStatement.setTimestamp(14, Timestamp.valueOf(LocalDateTime.now()));
return outStatement;
}
public void write() {
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = buildPvPInsertStatement(connection)) {
statement.execute();
} catch (SQLException e) {
Logger.error( e.toString());
}
// Warehouse record for this pvp event written if code path reaches here.
// Time to update the respective kill counters.
CharacterRecord.advanceKillCounter(this.player);
CharacterRecord.advanceDeathCounter(this.victim);
}
}

142
src/engine/db/archive/RealmRecord.java

@ -0,0 +1,142 @@ @@ -0,0 +1,142 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.db.archive;
import engine.Enum;
import engine.objects.Realm;
import engine.workthreads.WarehousePushThread;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.concurrent.LinkedBlockingQueue;
public class RealmRecord extends DataRecord {
private static final LinkedBlockingQueue<RealmRecord> recordPool = new LinkedBlockingQueue<>();
private Realm realm;
private Enum.RecordEventType eventType;
private String cityHash;
private String guildHash;
private String charterType;
private LocalDateTime eventDateTime;
private RealmRecord(Realm realm) {
this.recordType = Enum.DataRecordType.REALM;
this.realm = realm;
this.eventType = Enum.RecordEventType.CAPTURE;
}
public static RealmRecord borrow(Realm realm, Enum.RecordEventType eventType) {
RealmRecord realmRecord;
realmRecord = recordPool.poll();
if (realmRecord == null) {
realmRecord = new RealmRecord(realm);
realmRecord.eventType = eventType;
}
else {
realmRecord.recordType = Enum.DataRecordType.REALM;
realmRecord.eventType = eventType;
realmRecord.realm = realm;
}
realmRecord.cityHash = realm.getRulingCity().getHash();
realmRecord.guildHash = realm.getRulingCity().getGuild().getHash();
realmRecord.charterType = Enum.CharterType.getCharterTypeByID(realmRecord.realm.getCharterType()).name();
if (realmRecord.eventType.equals(Enum.RecordEventType.CAPTURE))
realmRecord.eventDateTime = realm.ruledSince;
else
realmRecord.eventDateTime = LocalDateTime.now();
return realmRecord;
}
public static PreparedStatement buildRealmPushStatement(Connection connection, ResultSet rs) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "INSERT INTO `warehouse_realmhistory` (`event_number`, `realm_id`, `realm_name`, `charter`, `city_id`, `guild_id`, `eventType`, `datetime`) VALUES(?,?,?,?,?,?,?,?)";
outStatement = connection.prepareStatement(queryString);
// Bind record data
outStatement.setInt(1, rs.getInt("event_number"));
outStatement.setString(2, rs.getString("realm_id"));
outStatement.setString(3, rs.getString("realm_name"));
outStatement.setString(4, rs.getString("charter"));
outStatement.setString(5, rs.getString("city_id"));
outStatement.setString(6, rs.getString("guild_id"));
outStatement.setString(7, rs.getString("eventType"));
outStatement.setTimestamp(8, rs.getTimestamp("datetime"));
return outStatement;
}
public static PreparedStatement buildRealmQueryStatement(Connection connection) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "SELECT * FROM `warehouse_realmhistory` WHERE `event_number` > ?";
outStatement = connection.prepareStatement(queryString);
outStatement.setInt(1, WarehousePushThread.realmIndex);
return outStatement;
}
void reset() {
this.realm = null;
this.cityHash = null;
this.guildHash = null;
this.eventDateTime = null;
this.charterType = null;
}
public void release() {
this.reset();
recordPool.add(this);
}
private PreparedStatement buildRealmInsertStatement(Connection connection) throws SQLException {
PreparedStatement outStatement = null;
String queryString = "INSERT INTO `warehouse_realmhistory` (`realm_id`, `realm_name`, `charter`, `city_id`, `guild_id`, `eventType`, `datetime`) VALUES(?,?,?,?,?,?,?)";
outStatement = connection.prepareStatement(queryString);
// Bind Record Data
outStatement.setString(1, realm.getHash());
outStatement.setString(2, realm.getRealmName());
outStatement.setString(3, charterType);
outStatement.setString(4, cityHash);
outStatement.setString(5, guildHash);
outStatement.setString(6, eventType.name());
outStatement.setTimestamp(7, Timestamp.valueOf(this.eventDateTime));
return outStatement;
}
public void write() {
try (Connection connection = DataWarehouse.connectionPool.getConnection();
PreparedStatement statement = this.buildRealmInsertStatement(connection)) {
statement.execute();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

202
src/engine/db/handlers/dbAccountHandler.java

@ -0,0 +1,202 @@ @@ -0,0 +1,202 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.db.handlers;
import engine.Enum;
import engine.Enum.GameObjectType;
import engine.gameManager.ConfigManager;
import engine.gameManager.DbManager;
import engine.objects.Account;
import engine.objects.PlayerCharacter;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
public class dbAccountHandler extends dbHandlerBase {
public dbAccountHandler() {
this.localClass = Account.class;
this.localObjectType = Enum.GameObjectType.valueOf(this.localClass.getSimpleName());
}
public Account GET_ACCOUNT(int id) {
if (id == 0)
return null;
Account account = (Account) DbManager.getFromCache(GameObjectType.Account, id);
if (account != null)
return account;
prepareCallable("SELECT * FROM `obj_account` WHERE `UID`=?");
setLong(1, (long) id);
Account ac = null;
ac = (Account) getObjectSingle(id);
if (ac != null)
ac.runAfterLoad();
return ac;
}
public void SET_TRASH(String machineID) {
prepareCallable("INSERT INTO dyn_trash(`machineID`, `count`)"
+ " VALUES (?, 1) ON DUPLICATE KEY UPDATE `count` = `count` + 1;");
setString(1, machineID);
executeUpdate();
}
public ArrayList<String> GET_TRASH_LIST() {
ArrayList<String> machineList = new ArrayList<>();
prepareCallable("select `machineID` from `dyn_trash`");
try {
ResultSet rs = executeQuery();
while (rs.next()) {
machineList.add(rs.getString(1));
}
} catch (SQLException e) {
Logger.error( e);
} finally {
closeCallable();
}
return machineList;
}
public boolean DELETE_VAULT_FOR_ACCOUNT(final int accountID) {
prepareCallable("DELETE FROM `object` WHERE `parent`=? && `type`='item'");
setLong(1, (long) accountID);
return (executeUpdate() > 0);
}
public ArrayList<PlayerCharacter> GET_ALL_CHARS_FOR_MACHINE(String machineID) {
ArrayList<PlayerCharacter> trashList = new ArrayList<>();
prepareCallable("select DISTINCT UID from object \n" +
"where parent IN (select AccountID from dyn_login_history " +
" WHERE`machineID`=?)");
setString(1, machineID);
try {
ResultSet rs = executeQuery();
while (rs.next()) {
PlayerCharacter trashPlayer;
int playerID;
playerID = rs.getInt(1);
trashPlayer = PlayerCharacter.getPlayerCharacter(playerID);
if (trashPlayer == null)
continue;;
if (trashPlayer.isDeleted() == false)
trashList.add(trashPlayer);
}
} catch (SQLException e) {
Logger.error( e);
} finally {
closeCallable();
}
return trashList;
}
public void CLEAR_TRASH_TABLE() {
prepareCallable("DELETE FROM dyn_trash");
executeUpdate();
}
public Account GET_ACCOUNT(String uname) {
if (Account.AccountsMap.get(uname) != null)
return this.GET_ACCOUNT(Account.AccountsMap.get(uname));
prepareCallable("SELECT * FROM `obj_account` WHERE `acct_uname`=?");
setString(1, uname);
ArrayList<Account> temp = getObjectList();
if (temp.isEmpty())
return null;
if (temp.get(0) != null){
temp.get(0).runAfterLoad();
if (ConfigManager.serverType.equals(Enum.ServerType.LOGINSERVER))
Account.AccountsMap.put(uname, temp.get(0).getObjectUUID());
}
return temp.get(0);
}
public void SET_ACCOUNT_LOGIN(final Account acc, String playerName, final String ip, final String machineID) {
if (acc.getObjectUUID() == 0 || ip == null || ip.length() == 0)
return;
prepareCallable("INSERT INTO dyn_login_history(`AccountID`, `accountName`, `characterName`, `ip`, `machineID`, `timeStamp`)"
+ " VALUES (?, ?, ?, ?, ?, ?)");
setInt(1, acc.getObjectUUID());
setString(2, acc.getUname());
setString(3, playerName);
setString(4, ip);
setString(5, machineID);
setTimeStamp(6, System.currentTimeMillis());
executeUpdate();
}
public String SET_PROPERTY(final Account a, String name, Object new_value) {
prepareCallable("CALL account_SETPROP(?,?,?)");
setLong(1, (long) a.getObjectUUID());
setString(2, name);
setString(3, String.valueOf(new_value));
return getResult();
}
public String SET_PROPERTY(final Account a, String name, Object new_value, Object old_value) {
prepareCallable("CALL account_GETSETPROP(?,?,?,?)");
setLong(1, (long) a.getObjectUUID());
setString(2, name);
setString(3, String.valueOf(new_value));
setString(4, String.valueOf(old_value));
return getResult();
}
public void updateDatabase(final Account acc) {
prepareCallable("UPDATE `obj_account` SET `acct_passwd`=?, "
+ " `acct_lastCharUID`=?, `acct_salt`=?, `discordAccount`=?, " +
" status = ? WHERE `UID`=?");
setString(1, acc.getPasswd());
setInt(2, acc.getLastCharIDUsed());
setString(3, acc.getSalt());
setString(4, acc.discordAccount);
setString(5, acc.status.name());
setInt(6, acc.getObjectUUID());
executeUpdate();
}
public void INVALIDATE_LOGIN_CACHE(long accountUID, String objectType) {
prepareCallable("INSERT IGNORE INTO login_cachelist (`UID`, `type`) VALUES(?,?);");
setLong(1, accountUID);
setString(2, objectType);
executeUpdate();
}
}

115
src/engine/db/handlers/dbBaneHandler.java

@ -0,0 +1,115 @@ @@ -0,0 +1,115 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.db.handlers;
import engine.objects.Bane;
import engine.objects.Building;
import engine.objects.City;
import engine.objects.PlayerCharacter;
import org.joda.time.DateTime;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
public class dbBaneHandler extends dbHandlerBase {
public dbBaneHandler() {
}
public boolean CREATE_BANE(City city, PlayerCharacter owner, Building stone) {
prepareCallable("INSERT INTO `dyn_banes` (`cityUUID`, `ownerUUID`, `stoneUUID`, `placementDate`) VALUES(?,?,?,?)");
setLong(1, (long) city.getObjectUUID());
setLong(2, (long) owner.getObjectUUID());
setLong(3, (long) stone.getObjectUUID());
setTimeStamp(4, System.currentTimeMillis());
return (executeUpdate() > 0);
}
public Bane LOAD_BANE(int cityUUID) {
Bane newBane = null;
try {
prepareCallable("SELECT * from dyn_banes WHERE `dyn_banes`.`cityUUID` = ?");
setLong(1, (long) cityUUID);
ResultSet rs = executeQuery();
if (rs.next()) {
newBane = new Bane(rs);
Bane.addBane(newBane);
}
} catch (SQLException ex) {
java.util.logging.Logger.getLogger(dbBaneHandler.class.getName()).log(Level.SEVERE, null, ex);
} finally {
closeCallable();
}
return newBane;
}
public ConcurrentHashMap<Integer, Bane> LOAD_ALL_BANES() {
ConcurrentHashMap<Integer, Bane> baneList;
Bane thisBane;
baneList = new ConcurrentHashMap<>();
int recordsRead = 0;
prepareCallable("SELECT * FROM dyn_banes");
try {
ResultSet rs = executeQuery();
while (rs.next()) {
recordsRead++;
thisBane = new Bane(rs);
baneList.put(thisBane.getCityUUID(), thisBane);
}
Logger.info("read: " + recordsRead + " cached: " + baneList.size());
} catch (SQLException e) {
Logger.error( e.toString());
} finally {
closeCallable();
}
return baneList;
}
public boolean SET_BANE_TIME(DateTime toSet, int cityUUID) {
prepareCallable("UPDATE `dyn_banes` SET `liveDate`=? WHERE `cityUUID`=?");
setTimeStamp(1, toSet.getMillis());
setLong(2, cityUUID);
return (executeUpdate() > 0);
}
public boolean REMOVE_BANE(Bane bane) {
if (bane == null)
return false;
prepareCallable("DELETE FROM `dyn_banes` WHERE `cityUUID` = ?");
setLong(1, (long) bane.getCity().getObjectUUID());
return (executeUpdate() > 0);
}
}

50
src/engine/db/handlers/dbBaseClassHandler.java

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.db.handlers;
import engine.Enum;
import engine.Enum.GameObjectType;
import engine.gameManager.DbManager;
import engine.objects.BaseClass;
import java.util.ArrayList;
public class dbBaseClassHandler extends dbHandlerBase {
public dbBaseClassHandler() {
this.localClass = BaseClass.class;
this.localObjectType = Enum.GameObjectType.BaseClass;
}
public BaseClass GET_BASE_CLASS(final int id) {
if (id == 0)
return null;
BaseClass baseClass = (BaseClass) DbManager.getFromCache(GameObjectType.BaseClass, id);
if (baseClass != null)
return baseClass;
prepareCallable("SELECT * FROM `static_rune_baseclass` WHERE `ID` = ?;");
setInt(1, id);
return (BaseClass) getObjectSingle(id);
}
public ArrayList<BaseClass> GET_BASECLASS_FOR_RACE(final int id) {
prepareCallable("SELECT b.* FROM `static_rune_baseclass` b, `static_rune_racebaseclass` r WHERE b.`ID` = r.`BaseClassID` && r.`RaceID` = ?");
setInt(1, id);
return getObjectList();
}
public ArrayList<BaseClass> GET_ALL_BASE_CLASSES(){
prepareCallable("SELECT * FROM `static_rune_baseclass`;");
return getObjectList();
}
}

86
src/engine/db/handlers/dbBlueprintHandler.java

@ -0,0 +1,86 @@ @@ -0,0 +1,86 @@
package engine.db.handlers;
import engine.objects.Blueprint;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
public class dbBlueprintHandler extends dbHandlerBase {
public dbBlueprintHandler() {
}
public HashMap<Integer, Integer> LOAD_ALL_DOOR_NUMBERS() {
HashMap<Integer, Integer> doorInfo;
doorInfo = new HashMap<>();
int doorUUID;
int doorNum;
int recordsRead = 0;
prepareCallable("SELECT * FROM static_building_doors ORDER BY doorMeshUUID ASC");
try {
ResultSet rs = executeQuery();
while (rs.next()) {
recordsRead++;
doorUUID = rs.getInt("doorMeshUUID");
doorNum = rs.getInt("doorNumber");
doorInfo.put(doorUUID, doorNum);
}
Logger.info( "read: " + recordsRead + " cached: " + doorInfo.size());
} catch (SQLException e) {
Logger.error("LoadAllDoorNumbers: " + e.getErrorCode() + ' ' + e.getMessage(), e);
} finally {
closeCallable();
}
return doorInfo;
}
public HashMap<Integer, Blueprint> LOAD_ALL_BLUEPRINTS() {
HashMap<Integer, Blueprint> blueprints;
Blueprint thisBlueprint;
blueprints = new HashMap<>();
int recordsRead = 0;
prepareCallable("SELECT * FROM static_building_blueprint");
try {
ResultSet rs = executeQuery();
while (rs.next()) {
recordsRead++;
thisBlueprint = new Blueprint(rs);
blueprints.put(thisBlueprint.getBlueprintUUID(), thisBlueprint);
// load mesh cache
Blueprint._meshLookup.putIfAbsent(thisBlueprint.getMeshForRank(-1), thisBlueprint);
Blueprint._meshLookup.putIfAbsent(thisBlueprint.getMeshForRank(0), thisBlueprint);
Blueprint._meshLookup.putIfAbsent(thisBlueprint.getMeshForRank(1), thisBlueprint);
Blueprint._meshLookup.putIfAbsent(thisBlueprint.getMeshForRank(3), thisBlueprint);
Blueprint._meshLookup.putIfAbsent(thisBlueprint.getMeshForRank(7), thisBlueprint);
}
Logger.info( "read: " + recordsRead + " cached: " + blueprints.size());
} catch (SQLException e) {
Logger.error("LoadAllBlueprints: " + e.getErrorCode() + ' ' + e.getMessage(), e);
} finally {
closeCallable();
}
return blueprints;
}
}

51
src/engine/db/handlers/dbBoonHandler.java

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.db.handlers;
import engine.objects.Boon;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
public class dbBoonHandler extends dbHandlerBase {
public dbBoonHandler() {
}
public ArrayList<Boon> GET_BOON_AMOUNTS_FOR_ITEMBASEUUID(int itemBaseUUID){
ArrayList<Boon>boons = new ArrayList<>();
Boon thisBoon;
prepareCallable("SELECT * FROM `static_item_boons` WHERE `itemBaseID` = ?");
setInt(1, itemBaseUUID);
try {
ResultSet rs = executeQuery();
while (rs.next()) {
thisBoon = new Boon(rs);
boons.add(thisBoon);
}
} catch (SQLException e) {
Logger.error("GetBoonAmountsForItembaseUUID: " + e.getErrorCode() + ' ' + e.getMessage(), e);
} finally {
closeCallable();
}
return boons;
}
}

809
src/engine/db/handlers/dbBuildingHandler.java

@ -0,0 +1,809 @@ @@ -0,0 +1,809 @@
// โ€ข โ–Œ โ–„ ยท. โ–„โ–„โ–„ยท โ–„โ–„ โ€ข โ–ช โ–„โ–„ยท โ–„โ–„โ–„โ–„ยท โ–„โ–„โ–„ยท โ–โ–„โ–„โ–„ โ–„โ–„โ–„ .
// ยทโ–ˆโ–ˆ โ–โ–ˆโ–ˆโ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ–โ–ˆ โ–€ โ–ชโ–ˆโ–ˆ โ–โ–ˆ โ–Œโ–ชโ–โ–ˆ โ–€โ–ˆโ–ชโ–โ–ˆ โ–€โ–ˆ โ€ขโ–ˆโ–Œ โ–โ–ˆโ–โ–Œยท
// โ–โ–ˆ โ–Œโ–โ–Œโ–โ–ˆยทโ–„โ–ˆโ–€โ–€โ–ˆ โ–„โ–ˆ โ–€โ–ˆโ–„โ–โ–ˆยทโ–ˆโ–ˆ โ–„โ–„โ–โ–ˆโ–€โ–€โ–ˆโ–„โ–„โ–ˆโ–€โ–€โ–ˆ โ–โ–ˆโ– โ–โ–Œโ–โ–€โ–€โ–€
// โ–ˆโ–ˆ โ–ˆโ–ˆโ–Œโ–โ–ˆโ–Œโ–โ–ˆ โ–ชโ–โ–Œโ–โ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆโ–Œโ–โ–ˆโ–ˆโ–ˆโ–Œโ–ˆโ–ˆโ–„โ–ชโ–โ–ˆโ–โ–ˆ โ–ชโ–โ–Œโ–ˆโ–ˆโ– โ–ˆโ–Œโ–โ–ˆโ–„โ–„โ–Œ
// โ–€โ–€ โ–ˆโ–ชโ–€โ–€โ–€ โ–€ โ–€ ยทโ–€โ–€โ–€โ–€ โ–€โ–€โ–€ยทโ–€โ–€โ–€ ยทโ–€โ–€โ–€โ–€ โ–€ โ–€ โ–€โ–€ โ–ˆโ–ช โ–€โ–€โ–€
// Magicbane Emulator Project ยฉ 2013 - 2022
// www.magicbane.com
package engine.db.handlers;
import engine.Enum;
import engine.Enum.DbObjectType;
import engine.Enum.ProtectionState;
import engine.Enum.TaxType;
import engine.gameManager.DbManager;
import engine.math.Vector3fImmutable;
import engine.objects.*;
import engine.server.MBServerStatics;
import org.joda.time.DateTime;
import org.pmw.tinylog.Logger;
import java.awt.geom.Line2D;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
public class dbBuildingHandler extends dbHandlerBase {
public dbBuildingHandler() {
this.localClass = Building.class;
this.localObjectType = Enum.GameObjectType.valueOf(this.localClass.getSimpleName());
}
public Building CREATE_BUILDING(Building b) {
try {
b = this.addBuilding(b);
b.setObjectTypeMask(MBServerStatics.MASK_BUILDING);
} catch (Exception e) {
Logger.error(e);
b = null;
}
return b;
}
/*
*
* @param worldServerID
* @param OwnerUUID
* @param name
* @param meshUUID
* @param meshScale
* @param currentHP
* @param protectionState
* @param currentGold
* @param rank
* @param upgradeDate
* @param blueprintUUID
* @param w
* @param rotY
* @return
*/
public Building CREATE_BUILDING(int parentZoneID, int OwnerUUID, String name, int meshUUID,
Vector3fImmutable location, float meshScale, int currentHP,
ProtectionState protectionState, int currentGold, int rank,
DateTime upgradeDate, int blueprintUUID, float w, float rotY) {
Building toCreate = null;
try {
prepareCallable("CALL `building_CREATE`(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ,? ,? ,?, ?);");
setInt(1, parentZoneID);
setInt(2, OwnerUUID);
setString(3, name);
setInt(4, meshUUID);
setFloat(5, location.x);
setFloat(6, location.y);
setFloat(7, location.z);
setFloat(8, meshScale);
setInt(9, currentHP);
setString(10, protectionState.name());
setInt(11, currentGold);
setInt(12, rank);
if (upgradeDate != null)
setTimeStamp(13, upgradeDate.getMillis());
else
setNULL(13, java.sql.Types.DATE);
setInt(14, blueprintUUID);
setFloat(15, w);
setFloat(16, rotY);
int objectUUID = (int) getUUID();
if (objectUUID > 0)
toCreate = GET_BUILDINGBYUUID(objectUUID);
} catch (Exception e) {
Logger.error("CREATE_BUILDING", e.getMessage());
return null;
}
return toCreate;
}
public boolean DELETE_FROM_DATABASE(final Building b) {
return removeFromBuildings(b);
}
public ArrayList<Building> GET_ALL_BUILDINGS_FOR_ZONE(Zone zone) {
prepareCallable("SELECT `obj_building`.*, `object`.`parent` FROM `object` INNER JOIN `obj_building` ON `obj_building`.`UID` = `object`.`UID` WHERE `object`.`parent` = ?;");
setLong(1, zone.getObjectUUID());
return getLargeObjectList();
}
public ArrayList<Building> GET_ALL_BUILDINGS() {
prepareCallable("SELECT `obj_building`.*, `object`.`parent` FROM `object` INNER JOIN `obj_building` ON `obj_building`.`UID` = `object`.`UID`;");
return getLargeObjectList();
}
public Building GET_BUILDINGBYUUID(int uuid) {
if (uuid == 0)
return null;
Building building = (Building) DbManager.getFromCache(Enum.GameObjectType.Building, uuid);
if (building != null)
return building;
prepareCallable("SELECT `obj_building`.*, `object`.`parent` FROM `object` INNER JOIN `obj_building` ON `obj_building`.`UID` = `object`.`UID` WHERE `object`.`UID` = ?;");
setLong(1, (long) uuid);
return (Building) getObjectSingle(uuid);
}
public Building GET_BUILDING_BY_MESH(final int meshID) {
Building toReturn = null;
prepareCallable("CALL building_GETBYMESH(?)");
setInt(1, meshID);
try {
ResultSet rs = executeQuery();
if (rs.next())
toReturn = new Building(rs);
rs.close();
} catch (SQLException e) {
Logger.error("Building", e);
return null;
} finally {
closeCallable();
}
return toReturn;
}
public String SET_PROPERTY(final Building b, String name, Object new_value) {
prepareCallable("CALL building_SETPROP(?,?,?)");
setLong(1, b.getObjectUUID());
setString(2, name);
setString(3, String.valueOf(new_value));
return getResult();
}
public String SET_PROPERTY(final Building b, String name, Object new_value, Object old_value) {
prepareCallable("CALL building_GETSETPROP(?,?,?,?)");
setLong(1, b.getObjectUUID());
setString(2, name);
setString(3, String.valueOf(new_value));
setString(4, String.valueOf(old_value));
return getResult();
}
public int MOVE_BUILDING(long buildingID, long parentID, float locX, float locY, float locZ) {
prepareCallable("UPDATE `object` INNER JOIN `obj_building` On `object`.`UID` = `obj_building`.`UID` SET `object`.`parent`=?, `obj_building`.`locationX`=?, `obj_building`.`locationY`=?, `obj_building`.`locationZ`=? WHERE `obj_building`.`UID`=?;");
setLong(1, parentID);
setFloat(2, locX);
setFloat(3, locY);
setFloat(4, locZ);
setLong(5, buildingID);
return executeUpdate();
}
private Building addBuilding(Building toAdd) {
prepareCallable("CALL `building_CREATE`(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
setLong(1, toAdd.getParentZoneID());
setLong(2, toAdd.getOwnerUUID());
setString(3, toAdd.getName());
setInt(4, toAdd.getMeshUUID());
setFloat(5, toAdd.getStatLat());
setFloat(6, toAdd.getStatAlt());
setFloat(7, toAdd.getStatLon());
setFloat(8, toAdd.getMeshScale().x);
setInt(9, (int) toAdd.getHealth());
setString(10, toAdd.getProtectionState().name());
setInt(11, toAdd.getStrongboxValue());
setInt(12, toAdd.getRank());
// Write Joda DateTime to database
// *** Refactor : Wrap this logic in our
// own override setDateTime() ?
if (toAdd.getUpgradeDateTime() != null)
setLocalDateTime(13, toAdd.getUpgradeDateTime());
else
setNULL(13, java.sql.Types.DATE);
setInt(14, toAdd.getBlueprintUUID());
setFloat(15, toAdd.getw());
setFloat(16, toAdd.getRot().y);
int objectUUID = (int) getUUID();
if (objectUUID > 0)
return GET_BUILDINGBYUUID(objectUUID);
return null;
}
private boolean removeFromBuildings(final Building b) {
prepareCallable("DELETE FROM `object` WHERE `UID` = ?");
setLong(1, b.getObjectUUID());
return (executeUpdate() > 0);
}
public boolean ClaimAsset(final long SetBuildingID, int newowner, int OldOwner) {
prepareCallable("UPDATE `obj_building` SET `ownerUUID`=? WHERE `UID`=? and `ownerUUID`= ?");
setInt(1, newowner);
setLong(2, SetBuildingID);
setLong(3, OldOwner);
return (executeUpdate() > 0);
}
public boolean CHANGE_NAME(Building b, String newName) {
prepareCallable("UPDATE `obj_building` SET `name`=? WHERE `UID`=?");
setString(1, newName);
setLong(2, b.getObjectUUID());
return (executeUpdate() > 0);
}
public boolean SET_RESERVE(Building b, int reserveAmount) {
prepareCallable("UPDATE `obj_building` SET `reserve`=? WHERE `UID`=?");
setInt(1, reserveAmount);
setLong(2, b.getObjectUUID());
return (executeUpdate() > 0);
}
//CAS update to rank
public boolean CHANGE_RANK(final long buildingID, int newRank) {
prepareCallable("UPDATE `obj_building` SET `rank`=? WHERE `UID`=?");
setInt(1, newRank);
setLong(2, buildingID);
return (executeUpdate() > 0);
}
public boolean UPDATE_BUILDING_HEALTH(final long buildingID, int NewHealth) {
prepareCallable("UPDATE `obj_building` SET `currentHP`=? WHERE `UID`=?");
setInt(1, NewHealth);
setLong(2, buildingID);
return (executeUpdate() > 0);
}
public boolean UPDATE_BUILDING_ALTITUDE(final long buildingID, float newAltitude) {
prepareCallable("UPDATE `obj_building` SET `locationY`=? WHERE `UID`=?");
setFloat(1, newAltitude);
setLong(2, buildingID);
return (executeUpdate() > 0);
}
public boolean UPDATE_PROTECTIONSTATE(final long buildingUUID, ProtectionState protectionState) {
try {
prepareCallable("UPDATE `obj_building` SET `protectionState`=? WHERE `UID`=?");
setString(1, protectionState.name());
setLong(2, buildingUUID);
return (executeUpdate() > 0);
} catch (Exception e) {
Logger.error(e.toString());
return false;
}
}
public boolean UPDATE_DOOR_LOCK(final int buildingUUID, int doorFlags) {
try {
prepareCallable("UPDATE obj_building SET doorState = ? WHERE UID = ?");
setInt(1, doorFlags);
setInt(2, buildingUUID);
executeUpdate();
return true;
} catch (Exception e) {
return false;
}
}
public boolean ADD_TO_FRIENDS_LIST(final long buildingID, final long friendID, final long guildID, final int friendType) {
prepareCallable("INSERT INTO `dyn_building_friends` (`buildingUID`, `playerUID`,`guildUID`, `friendType`) VALUES (?,?,?,?)");
setLong(1, buildingID);
setLong(2, friendID);
setLong(3, guildID);
setInt(4, friendType);
return (executeUpdate() > 0);
}
public boolean REMOVE_FROM_FRIENDS_LIST(final long buildingID, long friendID, long guildID, int friendType) {
prepareCallable("DELETE FROM `dyn_building_friends` WHERE `buildingUID`=? AND `playerUID`=? AND `guildUID` =? AND `friendType` = ?");
setLong(1, buildingID);
setLong(2, friendID);
setLong(3,guildID);
setInt(4, friendType);
return (executeUpdate() > 0);
}
public boolean REMOVE_FROM_CONDEMNED_LIST(final long buildingID, long friendID, long guildID, int friendType) {
prepareCallable("DELETE FROM `dyn_building_condemned` WHERE `buildingUID`=? AND `playerUID`=? AND `guildUID` =? AND `friendType` = ?");
setLong(1, buildingID);
setLong(2, friendID);
setLong(3,guildID);
setInt(4, friendType);
return (executeUpdate() > 0);
}
public void CLEAR_FRIENDS_LIST(final long buildingID) {
prepareCallable("DELETE FROM `dyn_building_friends` WHERE `buildingUID`=?");
setLong(1, buildingID);
executeUpdate();
}
public void CLEAR_CONDEMNED_LIST(final long buildingID) {
prepareCallable("DELETE FROM `dyn_building_condemned` WHERE `buildingUID`=?");
setLong(1, buildingID);
executeUpdate();
}
public boolean CLEAR_PATROL(final long buildingID) {
prepareCallable("DELETE FROM `dyn_building_patrol_points` WHERE `buildingUID`=?");
setLong(1, buildingID);
return (executeUpdate() > 0);
}
public void LOAD_ALL_FRIENDS_FOR_BUILDING(Building building) {
if (building == null)
return;
prepareCallable("SELECT * FROM `dyn_building_friends` WHERE `buildingUID` = ?");
setInt(1,building.getObjectUUID());
try {
ResultSet rs = executeQuery();
//shrines cached in rs for easy cache on creation.
while (rs.next()) {
BuildingFriends friend = new BuildingFriends(rs);
switch(friend.getFriendType()){
case 7:
building.getFriends().put(friend.getPlayerUID(), friend);
break;
case 8:
case 9:
building.getFriends().put(friend.getGuildUID(), friend);
break;
}
}
} catch (SQLException e) {
Logger.error("LOAD friends for building: " + e.getErrorCode() + ' ' + e.getMessage(), e);
} finally {
closeCallable();
}
}
public void LOAD_ALL_CONDEMNED_FOR_BUILDING(Building building) {
if (building == null)
return;
prepareCallable("SELECT * FROM `dyn_building_condemned` WHERE `buildingUID` = ?");
setInt(1,building.getObjectUUID());
try {
ResultSet rs = executeQuery();
//shrines cached in rs for easy cache on creation.
while (rs.next()) {
Condemned condemn = new Condemned(rs);
switch(condemn.getFriendType()){
case 2:
building.getCondemned().put(condemn.getPlayerUID(), condemn);
break;
case 4:
case 5:
building.getCondemned().put(condemn.getGuildUID(), condemn);
break;
}
}
} catch (SQLException e) {
Logger.error("LOAD Condemned for building: " + e.getErrorCode() + ' ' + e.getMessage(), e);
} finally {
closeCallable();
}
}
public ArrayList<Vector3fImmutable> LOAD_PATROL_POINTS(Building building) {
if (building == null)
return null;
ArrayList<Vector3fImmutable> patrolPoints = new ArrayList<>();
prepareCallable("SELECT * FROM `dyn_building_patrol_points` WHERE `buildingUID` = ?");
setInt(1,building.getObjectUUID());
try {
ResultSet rs = executeQuery();
//shrines cached in rs for easy cache on creation.
while (rs.next()) {
float x1 = rs.getFloat("patrolX");
float y1 = rs.getFloat("patrolY");
float z1 = rs.getFloat("patrolZ");
Vector3fImmutable patrolPoint = new Vector3fImmutable(x1,y1,z1);
patrolPoints.add(patrolPoint);
}
} catch (SQLException e) {
Logger.error("LOAD Patrol Points for building: " + e.getErrorCode() + ' ' + e.getMessage(), e);
} finally {
closeCallable();
}
return patrolPoints;
}
public boolean ADD_TO_CONDEMNLIST(final long parentUID, final long playerUID, final long guildID, final int friendType) {
prepareCallable("INSERT INTO `dyn_building_condemned` (`buildingUID`, `playerUID`,`guildUID`, `friendType`) VALUES (?,?,?,?)");
setLong(1, parentUID);
setLong(2, playerUID);
setLong(3, guildID);
setInt(4, friendType);
return (executeUpdate() > 0);
}
public boolean ADD_TO_PATROL(final long parentUID, final Vector3fImmutable patrolPoint) {
prepareCallable("INSERT INTO `dyn_building_patrol_points` (`buildingUID`, `patrolX`,`patrolY`, `patrolZ`) VALUES (?,?,?,?)");
setLong(1, parentUID);
setFloat(2, (int)patrolPoint.x);
setFloat(3, (int)patrolPoint.y);
setFloat(4, (int)patrolPoint.z);
return (executeUpdate() > 0);
}
public boolean ADD_TO_COLLIDE(final long parentUID, final float startX, final float startY, final float endX, final float endY) {
prepareCallable("INSERT INTO `static_building_colliders` (`MeshID`, `startX`,`startY`, `endX`, `endY`) VALUES (?,?,?,?,?)");
setLong(1, parentUID);
setFloat(2, startX);
setFloat(3, startY);
setFloat(4, endX);
setFloat(5, endY);
return (executeUpdate() > 0);
}
public ArrayList<Line2D.Float> GET_COLLIDERS(final long meshID) {
ArrayList<Line2D.Float> colliders = new ArrayList<>();
prepareCallable("SELECT * FROM `static_building_colliders` WHERE `MeshID`=? AND `doorID` =0");
setLong(1, meshID);
try {
ResultSet rs = executeQuery();
while (rs.next()) {
int startX = rs.getInt("startX");
int startY = rs.getInt("startY");
int endX = rs.getInt("endX");
int endY = rs.getInt("endY");
colliders.add(new Line2D.Float(startX,startY,endX,endY));
}
rs.close();
} catch (SQLException e) {
Logger.error("dbBuildingHandler.GET_COLLIDERS", e);
} finally {
closeCallable();
}
return colliders;
}
public ArrayList<Line2D.Float> GET_DOOR_COLLIDERS(final long meshID) {
ArrayList<Line2D.Float> colliders = new ArrayList<>();
prepareCallable("SELECT * FROM `static_building_colliders` WHERE `MeshID`=? AND `doorID` <> 0");
setLong(1, meshID);
try {
ResultSet rs = executeQuery();
while (rs.next()) {
int startX = rs.getInt("startX");
int startY = rs.getInt("startY");
int endX = rs.getInt("endX");
int endY = rs.getInt("endY");
colliders.add(new Line2D.Float(startX,startY,endX,endY));
}
rs.close();
} catch (SQLException e) {
Logger.error("dbBuildingHandler.GET_COLLIDERS", e);
} finally {
closeCallable();
}
return colliders;
}
public HashMap<Integer, ArrayList<BuildingRegions>> LOAD_BUILDING_REGIONS() {
HashMap<Integer, ArrayList<BuildingRegions>> regions;
BuildingRegions thisRegions;
regions = new HashMap<>();
int recordsRead = 0;
prepareCallable("SELECT * FROM static_building_regions");
try {
ResultSet rs = executeQuery();
while (rs.next()) {
recordsRead++;
thisRegions = new BuildingRegions(rs);
if (regions.get(thisRegions.getBuildingID()) == null){
ArrayList<BuildingRegions> regionsList = new ArrayList<>();
regionsList.add(thisRegions);
regions.put(thisRegions.getBuildingID(), regionsList);
}
else{
ArrayList<BuildingRegions>regionsList = regions.get(thisRegions.getBuildingID());
regionsList.add(thisRegions);
regions.put(thisRegions.getBuildingID(), regionsList);
}
}
Logger.info( "read: " + recordsRead + " cached: " + regions.size());
} catch (SQLException e) {
Logger.error(": " + e.getErrorCode() + ' ' + e.getMessage(), e);
} finally {
closeCallable();
}
return regions;
}
public HashMap<Integer, MeshBounds> LOAD_MESH_BOUNDS() {
HashMap<Integer, MeshBounds> meshBoundsMap;
MeshBounds meshBounds;
meshBoundsMap = new HashMap<>();
int recordsRead = 0;
prepareCallable("SELECT * FROM static_mesh_bounds");
try {
ResultSet rs = executeQuery();
while (rs.next()) {
recordsRead++;
meshBounds = new MeshBounds(rs);
meshBoundsMap.put(meshBounds.meshID, meshBounds);
}
Logger.info( "read: " + recordsRead + " cached: " + meshBoundsMap.size());
} catch (SQLException e) {
Logger.error("LoadMeshBounds: " + e.getErrorCode() + ' ' + e.getMessage(), e);
} finally {
closeCallable();
}
return meshBoundsMap;
}
public HashMap<Integer, ArrayList<StaticColliders>> LOAD_ALL_STATIC_COLLIDERS() {
HashMap<Integer, ArrayList<StaticColliders>> colliders;
StaticColliders thisColliders;
colliders = new HashMap<>();
int recordsRead = 0;
prepareCallable("SELECT * FROM static_building_colliders");
try {
ResultSet rs = executeQuery();
while (rs.next()) {
recordsRead++;
thisColliders = new StaticColliders(rs);
if (colliders.get(thisColliders.getMeshID()) == null){
ArrayList<StaticColliders> colliderList = new ArrayList<>();
colliderList.add(thisColliders);
colliders.put(thisColliders.getMeshID(), colliderList);
}
else{
ArrayList<StaticColliders>colliderList = colliders.get(thisColliders.getMeshID());
colliderList.add(thisColliders);
colliders.put(thisColliders.getMeshID(), colliderList);
}
}
Logger.info( "read: " + recordsRead + " cached: " + colliders.size());
} catch (SQLException e) {
Logger.error("LoadAllBlueprints: " + e.getErrorCode() + ' ' + e.getMessage(), e);
} finally {
closeCallable();
}
return colliders;
}
// This public class inserted here as it's a generic utility function
// with no other good place for it. If you find a good home for it
// feel free to move it. -
public final DbObjectType GET_UID_ENUM(long object_UID) {
DbObjectType storedEnum = DbObjectType.INVALID;
String typeString;
if (object_UID == 0)
return storedEnum;
// Set up call to stored procedure
prepareCallable("CALL object_UID_ENUM(?)");
setLong(1, object_UID);
try {