Compare commits

..
Author SHA1 Message Date
SlaveOfMagicbot 86062cf712 fix: null-safe upgradeDateTime conversion in BuildingManager.setUpgradeDateTime
Placing a banestone (and other callers) pass null to clear a fresh
building's upgrade timer, but the inline .atZone(...).toInstant() NPE'd
on null. Convert only when non-null; the DB layer already handles null.
2026-10-12 16:47:26 -05:00
SlaveOfMagicbot 85cd4e0c14 fix: use LocalDateTime for mine late-window calc in ArcMineWindowAvailableTimeMsg
Instant has no hour-of-day field, so .with(HOUR_OF_DAY, ...) threw
UnsupportedTemporalTypeException. Switch lateTime to LocalDateTime so the
late-window (midnight) time can be set and the seconds-remaining computed.
2026-10-12 12:44:27 -05:00
SlaveOfMagicbot 8a136d84f4 refactor: migrate JodaTime to java.time (rebuild on subdate2 ab96cfc)
Complete the JodaTime -> java.time migration across 30 files on the
correct subdate2 base. No org.joda references remain.
2026-10-09 20:12:23 -05:00
47 changed files with 282 additions and 1766 deletions

No files matched your search

@@ -468,12 +468,7 @@ public enum InterestManager implements Runnable {
continue;
awonpc.playerAgroMap.put(player.getObjectUUID(), 0f);
// siege engines keep firing at their target when a new player loads them
if (!awonpc.isSiege())
((Mob) awonpc).setCombatTarget(null);
((Mob) awonpc).setCombatTarget(null);
lcm = new LoadCharacterMsg(awonpc, PlayerCharacter.hideNonAscii());
} else if ((awo.getObjectTypeMask() & MBServerStatics.MASK_NPC) != 0) {
+10 -11
View File
@@ -14,7 +14,6 @@ import engine.mbEnums;
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.*;
@@ -34,8 +33,8 @@ public class BaneRecord extends DataRecord {
private String baneDropperHash;
private String baneGuildHash;
private String baneNationHash;
private DateTime baneLiveTime;
private DateTime baneDropTime;
private LocalDateTime baneLiveTime;
private LocalDateTime baneDropTime;
private BaneRecord(Bane bane) {
this.recordType = mbEnums.DataRecordType.BANE;
@@ -129,9 +128,9 @@ public class BaneRecord extends DataRecord {
return outStatement;
}
public static DateTime getLastBaneDateTime(City city) {
public static LocalDateTime getLastBaneDateTime(City city) {
DateTime outDateTime = null;
LocalDateTime outDateTime = null;
try (Connection connection = DbManager.getConnection();
PreparedStatement statement = buildDateTimeQueryStatement(connection, city);
@@ -139,7 +138,7 @@ public class BaneRecord extends DataRecord {
while (rs.next()) {
outDateTime = new DateTime(rs.getTimestamp("endDatetime"));
outDateTime = rs.getTimestamp("endDatetime").toLocalDateTime();
}
@@ -160,7 +159,7 @@ public class BaneRecord extends DataRecord {
}
public static void updateLiveDate(Bane bane, DateTime dateTime) {
public static void updateLiveDate(Bane bane, LocalDateTime dateTime) {
if (bane == null)
return;
@@ -175,13 +174,13 @@ public class BaneRecord extends DataRecord {
}
}
private static PreparedStatement buildUpdateLiveDateStatement(Connection connection, Bane bane, DateTime dateTime) throws SQLException {
private static PreparedStatement buildUpdateLiveDateStatement(Connection connection, Bane bane, LocalDateTime 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.setTimestamp(1, Timestamp.valueOf(dateTime));
outStatement.setString(2, bane.getCity().getHash());
return outStatement;
@@ -366,12 +365,12 @@ public class BaneRecord extends DataRecord {
if (this.baneDropTime == null)
outStatement.setNull(8, java.sql.Types.DATE);
else
outStatement.setTimestamp(8, new java.sql.Timestamp(this.baneDropTime.getMillis()));
outStatement.setTimestamp(8, Timestamp.valueOf(this.baneDropTime));
if (this.baneLiveTime == null)
outStatement.setNull(9, java.sql.Types.DATE);
else
outStatement.setTimestamp(9, new java.sql.Timestamp(this.baneLiveTime.getMillis()));
outStatement.setTimestamp(9, Timestamp.valueOf(this.baneLiveTime));
outStatement.setString(10, this.eventType.name());
+3 -3
View File
@@ -14,7 +14,7 @@ import engine.objects.Bane;
import engine.objects.Building;
import engine.objects.City;
import engine.objects.PlayerCharacter;
import org.joda.time.DateTime;
import java.time.LocalDateTime;
import org.pmw.tinylog.Logger;
import java.sql.Connection;
@@ -71,12 +71,12 @@ public class dbBaneHandler extends dbHandlerBase {
}
public boolean SET_BANE_TIME(DateTime toSet, int cityUUID) {
public boolean SET_BANE_TIME(LocalDateTime toSet, int cityUUID) {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE `dyn_banes` SET `liveDate`=? WHERE `cityUUID`=?")) {
preparedStatement.setTimestamp(1, new java.sql.Timestamp(toSet.getMillis()));
preparedStatement.setTimestamp(1, java.sql.Timestamp.valueOf(toSet));
preparedStatement.setLong(2, cityUUID);
preparedStatement.execute();
@@ -17,7 +17,9 @@ import engine.mbEnums.DbObjectType;
import engine.mbEnums.ProtectionState;
import engine.mbEnums.TaxType;
import engine.objects.*;
import org.joda.time.DateTime;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import org.pmw.tinylog.Logger;
import java.sql.Connection;
@@ -40,7 +42,7 @@ public class dbBuildingHandler extends dbHandlerBase {
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) {
Instant upgradeDate, int blueprintUUID, float w, float rotY) {
Building building = null;
@@ -61,7 +63,7 @@ public class dbBuildingHandler extends dbHandlerBase {
preparedStatement.setInt(12, rank);
if (upgradeDate != null)
preparedStatement.setTimestamp(13, new java.sql.Timestamp(upgradeDate.getMillis()));
preparedStatement.setTimestamp(13, new java.sql.Timestamp(upgradeDate.toEpochMilli()));
else
preparedStatement.setNull(13, java.sql.Types.DATE);
@@ -749,7 +751,7 @@ public class dbBuildingHandler extends dbHandlerBase {
return false;
}
public boolean updateBuildingUpgradeTime(LocalDateTime upgradeDateTime, Building toUpgrade, int costToUpgrade) {
public boolean updateBuildingUpgradeTime(Instant upgradeDateTime, Building toUpgrade, int costToUpgrade) {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE obj_building SET upgradeDate=?, currentGold=? "
@@ -758,8 +760,7 @@ public class dbBuildingHandler extends dbHandlerBase {
if (upgradeDateTime == null)
preparedStatement.setNull(1, java.sql.Types.DATE);
else
preparedStatement.setTimestamp(1, new java.sql.Timestamp(upgradeDateTime.atZone(ZoneId.systemDefault())
.toInstant().toEpochMilli()));
preparedStatement.setTimestamp(1, new java.sql.Timestamp(upgradeDateTime.toEpochMilli()));
preparedStatement.setInt(2, toUpgrade.getStrongboxValue() - costToUpgrade);
preparedStatement.setInt(3, toUpgrade.getObjectUUID());
@@ -838,7 +839,7 @@ public class dbBuildingHandler extends dbHandlerBase {
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE obj_building SET taxDate=? "
+ "WHERE UID = ?")) {
preparedStatement.setTimestamp(1, new java.sql.Timestamp(DateTime.now().plusDays(7).getMillis()));
preparedStatement.setTimestamp(1, new java.sql.Timestamp(Instant.now().plus(7, java.time.temporal.ChronoUnit.DAYS).toEpochMilli()));
preparedStatement.setInt(2, building.getObjectUUID());
return (preparedStatement.executeUpdate() > 0);
+3 -3
View File
@@ -14,7 +14,7 @@ import engine.mbEnums;
import engine.mbEnums.GuildHistoryType;
import engine.objects.*;
import engine.server.world.WorldServer;
import org.joda.time.DateTime;
import java.time.Instant;
import org.pmw.tinylog.Logger;
import java.sql.*;
@@ -125,7 +125,7 @@ public class dbGuildHandler extends dbHandlerBase {
return false;
}
public boolean ADD_TO_GUILDHISTORY(int target, PlayerCharacter playerCharacter, DateTime historyDate, GuildHistoryType historyType) {
public boolean ADD_TO_GUILDHISTORY(int target, PlayerCharacter playerCharacter, Instant historyDate, GuildHistoryType historyType) {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO `dyn_character_guildhistory` (`GuildID`, `CharacterID`, `historyDate`, `historyType`) VALUES (?,?,?,?)")) {
@@ -136,7 +136,7 @@ public class dbGuildHandler extends dbHandlerBase {
if (historyDate == null)
preparedStatement.setNull(3, java.sql.Types.DATE);
else
preparedStatement.setTimestamp(3, new Timestamp(historyDate.getMillis()));
preparedStatement.setTimestamp(3, java.sql.Timestamp.from(historyDate));
preparedStatement.setString(4, historyType.name());
+4 -3
View File
@@ -12,7 +12,8 @@ package engine.db.handlers;
import engine.gameManager.DbManager;
import engine.mbEnums;
import engine.objects.Mob;
import org.joda.time.DateTime;
import java.time.LocalDateTime;
import java.time.ZoneId;
import org.pmw.tinylog.Logger;
import java.sql.Connection;
@@ -82,7 +83,7 @@ public class dbMobHandler extends dbHandlerBase {
return mobileList;
}
public boolean updateUpgradeTime(Mob mob, DateTime upgradeDateTime) {
public boolean updateUpgradeTime(Mob mob, LocalDateTime upgradeDateTime) {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE obj_mob SET upgradeDate=? "
@@ -91,7 +92,7 @@ public class dbMobHandler extends dbHandlerBase {
if (upgradeDateTime == null)
preparedStatement.setNull(1, java.sql.Types.DATE);
else
preparedStatement.setTimestamp(1, new java.sql.Timestamp(upgradeDateTime.getMillis()));
preparedStatement.setTimestamp(1, new java.sql.Timestamp(upgradeDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()));
preparedStatement.setInt(2, mob.getObjectUUID());
+4 -3
View File
@@ -15,7 +15,8 @@ import engine.mbEnums;
import engine.mbEnums.ProfitType;
import engine.objects.NPC;
import engine.objects.NPCProfits;
import org.joda.time.DateTime;
import java.time.LocalDateTime;
import java.time.ZoneId;
import org.pmw.tinylog.Logger;
import java.sql.Connection;
@@ -240,7 +241,7 @@ public class dbNPCHandler extends dbHandlerBase {
}
}
public boolean updateUpgradeTime(NPC npc, DateTime upgradeDateTime) {
public boolean updateUpgradeTime(NPC npc, LocalDateTime upgradeDateTime) {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE obj_npc SET upgradeDate=? "
@@ -249,7 +250,7 @@ public class dbNPCHandler extends dbHandlerBase {
if (upgradeDateTime == null)
preparedStatement.setNull(1, java.sql.Types.DATE);
else
preparedStatement.setTimestamp(1, new java.sql.Timestamp(upgradeDateTime.getMillis()));
preparedStatement.setTimestamp(1, new java.sql.Timestamp(upgradeDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()));
preparedStatement.setInt(2, npc.getObjectUUID());
+3 -3
View File
@@ -16,7 +16,7 @@ import engine.mbEnums.ProtectionState;
import engine.objects.AbstractGameObject;
import engine.objects.Building;
import engine.objects.Shrine;
import org.joda.time.DateTime;
import java.time.Instant;
import org.pmw.tinylog.Logger;
import java.sql.Connection;
@@ -53,7 +53,7 @@ public class dbShrineHandler extends dbHandlerBase {
public ArrayList<AbstractGameObject> CREATE_SHRINE(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, String shrineType) {
Instant upgradeDate, int blueprintUUID, float w, float rotY, String shrineType) {
ArrayList<AbstractGameObject> shrineList = new ArrayList<>();
@@ -74,7 +74,7 @@ public class dbShrineHandler extends dbHandlerBase {
preparedStatement.setInt(12, rank);
if (upgradeDate != null)
preparedStatement.setTimestamp(13, new java.sql.Timestamp(upgradeDate.getMillis()));
preparedStatement.setTimestamp(13, java.sql.Timestamp.from(upgradeDate));
else
preparedStatement.setNull(13, java.sql.Types.DATE);
@@ -20,7 +20,7 @@ import engine.objects.City;
import engine.objects.Transaction;
import engine.objects.Warehouse;
import engine.server.MBServerStatics;
import org.joda.time.DateTime;
import java.time.Instant;
import org.json.JSONArray;
import org.json.JSONObject;
import org.pmw.tinylog.Logger;
@@ -40,7 +40,7 @@ public class dbWarehouseHandler extends dbHandlerBase {
}
public boolean CREATE_TRANSACTION(int warehouseBuildingID, GameObjectType targetType, int targetUUID, TransactionType transactionType, mbEnums.ResourceType resource, int amount, DateTime date) {
public boolean CREATE_TRANSACTION(int warehouseBuildingID, GameObjectType targetType, int targetUUID, TransactionType transactionType, mbEnums.ResourceType resource, int amount, Instant date) {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO `dyn_warehouse_transactions` (`warehouseUID`, `targetType`,`targetUID`, `type`,`resource`,`amount`,`date` ) VALUES (?,?,?,?,?,?,?)")) {
@@ -51,7 +51,7 @@ public class dbWarehouseHandler extends dbHandlerBase {
preparedStatement.setString(4, transactionType.name());
preparedStatement.setString(5, resource.name());
preparedStatement.setInt(6, amount);
preparedStatement.setTimestamp(7, new java.sql.Timestamp(date.getMillis()));
preparedStatement.setTimestamp(7, new java.sql.Timestamp(date.toEpochMilli()));
return (preparedStatement.executeUpdate() > 0);
+3 -1
View File
@@ -25,6 +25,7 @@ import engine.objects.*;
import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
@@ -274,7 +275,8 @@ public enum BuildingManager {
if (building == null)
return;
if (!DbManager.BuildingQueries.updateBuildingUpgradeTime(upgradeDateTime, building, rankCost)) {
Instant instant = (upgradeDateTime == null) ? null : upgradeDateTime.atZone(ZoneId.systemDefault()).toInstant();
if (!DbManager.BuildingQueries.updateBuildingUpgradeTime(instant, building, rankCost)) {
Logger.error("Failed to set upgradeTime for building " + building.getObjectUUID());
return;
}
+5 -110
View File
@@ -14,7 +14,6 @@ import engine.jobs.AttackJob;
import engine.jobs.DeferredPowerJob;
import engine.mbEnums;
import engine.net.client.ClientConnection;
import engine.net.client.msg.PowerProjectileMsg;
import engine.net.client.msg.TargetedActionMsg;
import engine.net.client.msg.UpdateStateMsg;
import engine.objects.*;
@@ -147,19 +146,11 @@ public enum CombatManager {
rangeMod += bonus.getFloatPercentAll(mbEnums.ModType.WeaponRange, mbEnums.SourceType.None);
attackRange += weapon.template.item_weapon_max_range * rangeMod;
} else if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) {
//unarmed mob, add the natural attack range from its rune (0 for most melee mobs)
if (bonus != null)
rangeMod += bonus.getFloatPercentAll(mbEnums.ModType.WeaponRange, mbEnums.SourceType.None);
attackRange += getNaturalAttackRange(attacker, slot) * rangeMod;
}
if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob))
if (((Mob) attacker).isSiege())
attackRange = getSiegeRange((Mob) attacker);
attackRange = 300;
float distanceSquared = attacker.loc.distanceSquared(target.loc);
@@ -223,22 +214,6 @@ public enum CombatManager {
wepSpeed = 10; //Old was 10, but it can be reached lower with legit buffs,effects.
delay = (long)wepSpeed * 100L;
} else {
//unarmed, use the natural attack speed from the mob or race rune
float naturalSpeed = getNaturalAttackSpeed(attacker, slot);
if (naturalSpeed > 0) {
if (attacker.getBonuses() != null && attacker.getBonuses().getFloatPercentAll(mbEnums.ModType.AttackDelay, mbEnums.SourceType.None) != 0f) //add effects speed bonus
naturalSpeed *= (1 + attacker.getBonuses().getFloatPercentAll(mbEnums.ModType.AttackDelay, mbEnums.SourceType.None));
if (naturalSpeed < 10)
naturalSpeed = 10;
delay = (long) naturalSpeed * 100L;
}
}
if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob))
@@ -257,8 +232,7 @@ public enum CombatManager {
//handle retaliate
//siege engines only retaliate on damage, see AbstractCharacter.modifyHealth
if (AbstractCharacter.IsAbstractCharacter(target) && !(target.getObjectType().equals(mbEnums.GameObjectType.Mob) && ((Mob) target).isSiege())) {
if (AbstractCharacter.IsAbstractCharacter(target)) {
if (((AbstractCharacter) target).combatTarget == null || !((AbstractCharacter) target).combatTarget.isAlive()) {
((AbstractCharacter) target).combatTarget = attacker;
if (target.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter) && ((AbstractCharacter) target).isCombat())
@@ -345,7 +319,7 @@ public enum CombatManager {
DispatchManager.sendToAllInRange(attacker, msg);
//we need to send the animation even if the attacker misses
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon == null ? null : weapon.template, null, slot));
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon.template, null, slot));
DispatchManager.sendToAllInRange(target, cmm);
//set auto attack job
@@ -385,7 +359,7 @@ public enum CombatManager {
DispatchManager.dispatchMsgToInterestArea(target, msg, mbEnums.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
//we need to send the animation even if the attacker misses
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon == null ? null : weapon.template, null, slot));
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon.template, null, slot));
DispatchManager.sendToAllInRange(target, cmm);
//set auto attack job
setAutoAttackJob(attacker, slot, delay);
@@ -473,7 +447,7 @@ public enum CombatManager {
if (resists.immuneTo(damageType)) {
//set auto attack job
//we need to send the animation even if the attacker misses
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon == null ? null : weapon.template, null, slot));
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) 0, getSwingAnimation(weapon.template, null, slot));
DispatchManager.sendToAllInRange(target, cmm);
setAutoAttackJob(attacker, slot, delay);
return;
@@ -505,15 +479,6 @@ public enum CombatManager {
}
TargetedActionMsg cmm = new TargetedActionMsg(attacker, target, (float) damage, attackAnim);
DispatchManager.sendToAllInRange(target, cmm);
//siege projectile is sent once per hit, not per AI pulse
if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob) && ((Mob) attacker).isSiege()
&& target.getObjectType().equals(mbEnums.GameObjectType.Building)) {
PowerProjectileMsg ppm = new PowerProjectileMsg(attacker, target);
ppm.setRange(50);
DispatchManager.dispatchMsgToInterestArea(attacker, ppm, mbEnums.DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);
}
}
}
@@ -671,76 +636,6 @@ public enum CombatManager {
}
public static float getNaturalAttackSpeed(AbstractCharacter attacker, mbEnums.EquipSlotType slot) {
// Returns the rune natural attack speed (x100 ms) for this hand, or 0 if the rune has none.
float[] attack = getNaturalAttack(attacker, slot);
if (attack == null || attack.length < 1)
return 0;
return attack[0];
}
public static float getNaturalAttackRange(AbstractCharacter attacker, mbEnums.EquipSlotType slot) {
// Returns the rune natural attack range for this hand, or 0 if the rune has none.
float[] attack = getNaturalAttack(attacker, slot);
if (attack == null || attack.length < 2)
return 0;
return attack[1];
}
public static float getSiegeRange(Mob siegeEngine) {
// Siege engines use the range from their rune natural attack (350 for all three), 300 if the rune has none.
float range = getNaturalAttackRange(siegeEngine, mbEnums.EquipSlotType.RHELD);
if (range <= 0)
return 300;
return range;
}
public static float[] getNaturalAttack(AbstractCharacter attacker, mbEnums.EquipSlotType slot) {
// Returns the rune natural attack entry for this hand, or null if the rune has none.
// Mobs use their mobbase rune, players use their race rune.
int runeID;
ItemTemplate rune;
int hand = slot.equals(mbEnums.EquipSlotType.LHELD) ? 2 : 1;
switch (attacker.getObjectType()) {
case Mob:
runeID = ((Mob) attacker).loadID;
break;
case PlayerCharacter:
runeID = ((PlayerCharacter) attacker).getRaceID();
break;
default:
return null;
}
rune = ItemTemplate.templates.get(runeID);
if (rune == null || rune.rune_natural_attacks.isEmpty())
return null;
for (float[] attack : rune.rune_natural_attacks)
if (attack.length > 3 && (int) attack[3] == hand)
return attack;
// No entry for this hand, fall back to the first natural attack
return rune.rune_natural_attacks.get(0);
}
public static int calculatePetDamage(AbstractCharacter agent) {
//damage calc for pet
float range;
+5 -5
View File
@@ -16,7 +16,7 @@ import engine.net.client.ClientConnection;
import engine.net.client.msg.guild.AcceptInviteToGuildMsg;
import engine.net.client.msg.guild.GuildInfoMsg;
import engine.objects.*;
import org.joda.time.DateTime;
import java.time.Instant;
public enum GuildManager {
@@ -67,8 +67,8 @@ public enum GuildManager {
return false;
if (playerCharacter.getGuild() != null && !playerCharacter.getGuild().isEmptyGuild()) {
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(playerCharacter.getGuildUUID(), playerCharacter, DateTime.now(), GuildHistoryType.LEAVE)) {
GuildHistory guildHistory = new GuildHistory(playerCharacter.getGuildUUID(), playerCharacter.getGuild().getName(), DateTime.now(), GuildHistoryType.LEAVE);
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(playerCharacter.getGuildUUID(), playerCharacter, Instant.now(), GuildHistoryType.LEAVE)) {
GuildHistory guildHistory = new GuildHistory(playerCharacter.getGuildUUID(), playerCharacter.getGuild().getName(), Instant.now(), GuildHistoryType.LEAVE);
playerCharacter.getGuildHistory().add(guildHistory);
}
}
@@ -90,8 +90,8 @@ public enum GuildManager {
dispatch = Dispatch.borrow(playerCharacter, msg);
DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
}
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(guild.getObjectUUID(), playerCharacter, DateTime.now(), historyType)) {
GuildHistory guildHistory = new GuildHistory(guild.getObjectUUID(), guild.getName(), DateTime.now(), historyType);
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(guild.getObjectUUID(), playerCharacter, Instant.now(), historyType)) {
GuildHistory guildHistory = new GuildHistory(guild.getObjectUUID(), guild.getName(), Instant.now(), historyType);
playerCharacter.getGuildHistory().add(guildHistory);
}
+3 -6
View File
@@ -11,7 +11,7 @@ package engine.jobs;
import engine.job.AbstractScheduleJob;
import engine.objects.Bane;
import org.joda.time.DateTime;
import java.time.LocalDateTime;
public class BaneDefaultTimeJob extends AbstractScheduleJob {
@@ -31,11 +31,8 @@ public class BaneDefaultTimeJob extends AbstractScheduleJob {
return;
}
DateTime defaultTime = new DateTime(this.bane.getPlacementDate());
defaultTime = defaultTime.plusDays(2);
defaultTime = defaultTime.hourOfDay().setCopy(22);
defaultTime = defaultTime.minuteOfHour().setCopy(0);
defaultTime = defaultTime.secondOfMinute().setCopy(0);
LocalDateTime defaultTime = this.bane.getPlacementDate()
.plusDays(2).withHour(22).withMinute(0).withSecond(0).withNano(0);
this.bane.setLiveDate(defaultTime);
}
+20 -22
View File
@@ -824,7 +824,6 @@ public class mbEnums {
ACID,
DISEASE,
UNKNOWN,
ANTISIEGE,
// these added for immunities
ATTACK,
POWERS,
@@ -843,26 +842,34 @@ public class mbEnums {
public static DamageType getDamageType(String modName) {
String name;
if (modName.isEmpty())
return DamageType.NONE;
// Client and DB strings vary in case and punctuation ("Fire", "Anti-Siege")
if(modName.toLowerCase().equals("blind"))
modName = "BLINDNESS";
name = modName.replaceAll("[\\s,-]", "").toUpperCase();
if(modName.toLowerCase().equals("powerblock"))
modName = "POWERINHIBITOR";
if (name.equals("BLIND"))
name = "BLINDNESS";
//validity check for not looking up damage type that doesn't exist
boolean valid = false;
for(DamageType type : DamageType.values()){
if(type.name().equals(modName))
valid = true;
}
if (name.equals("POWERBLOCK"))
name = "POWERINHIBITOR";
if(!valid)
return DamageType.NONE;
for (DamageType type : DamageType.values())
if (type.name().equals(name))
return type;
DamageType damageType;
return DamageType.NONE;
try {
damageType = DamageType.valueOf(modName.replace(",", "").toUpperCase());
} catch (Exception e) {
Logger.error(e);
return DamageType.NONE;
}
return damageType;
}
}
@@ -1502,15 +1509,6 @@ public class mbEnums {
}
}
// rune_type values from the client cache data (COBJECTS/RUNE)
public enum RuneType {
CLASS,
DISCIPLINE,
RACE,
TALENT
}
public enum ShrineType {
Aelfborn(1701900, -75506007, true),
+56 -50
View File
@@ -14,10 +14,12 @@ import engine.gameManager.*;
import engine.math.Vector3f;
import engine.math.Vector3fImmutable;
import engine.mbEnums;
import engine.mbEnums.DispatchChannel;
import engine.mobileAI.Threads.MobAIThread;
import engine.mobileAI.Threads.ReSpawner;
import engine.mobileAI.utilities.MovementUtilities;
import engine.net.client.msg.PerformActionMsg;
import engine.net.client.msg.PowerProjectileMsg;
import engine.objects.*;
import engine.powers.ActionsBase;
import engine.powers.PowersBase;
@@ -44,11 +46,6 @@ public class MobAI {
//
// CombatManager.class implements shared combat routines for all avatars.
// Pet aggro scan in checkForAggro stays off until it checks rune enemy lists,
// filters its targets and keeps pet targets (MBDATA/docs/plan-mask-pet.md steps 2-4).
private static final boolean PET_AGGRO_ENABLED = false;
private static void attackTarget(Mob mob, AbstractWorldObject target) {
try {
@@ -96,7 +93,7 @@ public class MobAI {
mob.updateLocation();
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget" + " " + e.getMessage());
}
}
@@ -115,9 +112,7 @@ public class MobAI {
if (mob.behaviourType.callsForHelp)
mobCallForHelp(mob);
// siege engines drop targets on their own attack range in determineAction
if (!mob.isSiege() && !MovementUtilities.inRangeDropAggro(mob, target)) {
if (!MovementUtilities.inRangeDropAggro(mob, target)) {
mob.setCombatTarget(null);
return;
}
@@ -138,7 +133,7 @@ public class MobAI {
target.getPet().setCombatTarget(mob);
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackPlayer");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackPlayer" + " " + e.getMessage());
}
}
@@ -160,10 +155,20 @@ public class MobAI {
if (guard.getCombatTarget() == null && !guard.getGuild().equals(mob.getGuild()))
guard.setCombatTarget(mob);
if (mob.isSiege())
MovementManager.sendRWSSMsg(mob);
CombatManager.combatCycle(mob, target);
if (mob.isSiege()) {
PowerProjectileMsg ppm = new PowerProjectileMsg(mob, target);
ppm.setRange(50);
DispatchManager.dispatchMsgToInterestArea(mob, ppm, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);
}
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackBuilding");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackBuilding" + " " + e.getMessage());
}
}
@@ -181,7 +186,7 @@ public class MobAI {
CombatManager.combatCycle(mob, target);
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackMob");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackMob" + " " + e.getMessage());
}
}
@@ -243,7 +248,7 @@ public class MobAI {
MovementUtilities.aiMove(mob, mob.destination, true);
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: Patrol");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget" + " " + e.getMessage());
}
}
@@ -285,7 +290,7 @@ public class MobAI {
return mob.nextCastTime <= System.currentTimeMillis();
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: canCast");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: canCast" + " " + e.getMessage());
}
return false;
}
@@ -382,7 +387,7 @@ public class MobAI {
return true;
}
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCast");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCast" + " " + e.getMessage());
}
return false;
}
@@ -447,7 +452,7 @@ public class MobAI {
mob.nextCallForHelp = System.currentTimeMillis() + 60000;
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCallForHelp");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCallForHelp" + " " + e.getMessage());
}
}
@@ -513,16 +518,7 @@ public class MobAI {
boolean bypassLoadedPlayerCheck = false;
if (mob.isPlayerGuard() || mob.isSiege()) {
bypassLoadedPlayerCheck = true;
if (mob.isSiege()) {
// siege engines hold a character target until it dies or leaves their attack range
if (mob.combatTarget != null && AbstractCharacter.IsAbstractCharacter(mob.combatTarget))
if (mob.combatTarget.loc.distanceSquared(mob.loc) > mob.getRange() * mob.getRange())
mob.setCombatTarget(null);
} else if (mob.combatTarget != null && mob.combatTarget.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter))
if (mob.combatTarget != null && mob.combatTarget.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter))
if (mob.combatTarget.loc.distanceSquared(mob.loc) > 10000)
mob.setCombatTarget(null);
}
@@ -548,7 +544,7 @@ public class MobAI {
PlayerCharacter target = (PlayerCharacter) mob.getCombatTarget();
if (!mob.isSiege() && !mob.playerAgroMap.containsKey(target.getObjectUUID())) {
if (!mob.playerAgroMap.containsKey(target.getObjectUUID())) {
mob.setCombatTarget(null);
return;
}
@@ -579,7 +575,7 @@ public class MobAI {
break;
}
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: DetermineAction");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: DetermineAction" + " " + e.getMessage());
}
}
@@ -634,7 +630,7 @@ public class MobAI {
}
}
if (PET_AGGRO_ENABLED && aiAgent.getCombatTarget() == null) {
if (aiAgent.getCombatTarget() == null) {
//look for pets to aggro if no players found to aggro
@@ -653,7 +649,7 @@ public class MobAI {
}
}
} catch (Exception e) {
Logger.error(e, aiAgent.getObjectUUID() + " " + aiAgent.getName() + " Failed At: CheckForAggro");
Logger.info(aiAgent.getObjectUUID() + " " + aiAgent.getName() + " Failed At: CheckForAggro" + " " + e.getMessage());
}
}
@@ -706,7 +702,7 @@ public class MobAI {
}
}
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckMobMovement");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckMobMovement" + " " + e.getMessage());
}
}
@@ -750,7 +746,7 @@ public class MobAI {
ReSpawner.respawnQueue.put(aiAgent);
}
} catch (Exception e) {
Logger.error(e, aiAgent.getObjectUUID() + " " + aiAgent.getName() + " Failed At: CheckForRespawn");
Logger.info(aiAgent.getObjectUUID() + " " + aiAgent.getName() + " Failed At: CheckForRespawn" + " " + e.getMessage());
}
}
@@ -765,7 +761,7 @@ public class MobAI {
if (mob.getCombatTarget() == null)
return;
if (mob.getCombatTarget().getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter) && !MovementUtilities.inRangeDropAggro(mob, (PlayerCharacter) mob.getCombatTarget()) && !mob.agentType.equals(mbEnums.AIAgentType.PET) && !mob.isSiege()) {
if (mob.getCombatTarget().getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter) && !MovementUtilities.inRangeDropAggro(mob, (PlayerCharacter) mob.getCombatTarget()) && !mob.agentType.equals(mbEnums.AIAgentType.PET)) {
mob.setCombatTarget(null);
return;
@@ -773,7 +769,7 @@ public class MobAI {
attackTarget(mob, mob.getCombatTarget());
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForAttack");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForAttack" + " " + e.getMessage());
}
}
@@ -816,7 +812,7 @@ public class MobAI {
mob.playerAgroMap.replaceAll((e, v) -> 0f);
}
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckToSendMobHome");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckToSendMobHome" + " " + e.getMessage());
}
}
@@ -855,7 +851,7 @@ public class MobAI {
mob.updateMovementState();
mob.updateLocation();
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: chaseTarget");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: chaseTarget" + " " + e.getMessage());
}
}
@@ -881,17 +877,13 @@ public class MobAI {
if (aggroMob.agentType.equals(mbEnums.AIAgentType.PET))
continue;
//don't attack siege engines
if (aggroMob.isSiege())
continue;
if (mob.getLoc().distanceSquared2D(aggroMob.getLoc()) > sqr(50))
continue;
mob.setCombatTarget(aggroMob);
}
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: SafeGuardAggro");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: SafeGuardAggro" + " " + e.getMessage());
}
}
@@ -921,7 +913,7 @@ public class MobAI {
checkForAttack(mob); //only check to attack if combat target is not null
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardLogic");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardLogic" + " " + e.getMessage());
}
}
@@ -954,7 +946,7 @@ public class MobAI {
mob.setHealth(mob.getHealthMax());
}
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: PetLogic");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: PetLogic" + " " + e.getMessage());
}
}
@@ -978,7 +970,7 @@ public class MobAI {
}
checkForAttack(mob);
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: HamletGuardLogic");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: HamletGuardLogic" + " " + e.getMessage());
}
}
@@ -1051,7 +1043,7 @@ public class MobAI {
checkForAttack(mob);
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: DefaultLogic");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: DefaultLogic" + " " + e.getMessage());
}
}
@@ -1107,11 +1099,25 @@ public class MobAI {
return;
}
}
if (mob.getCombatTarget() == null) {
// guards never auto-aggro siege engines; they only respond when one damages a city building
//look for siege equipment to aggro if no players found to aggro
HashSet<AbstractWorldObject> awoList = WorldGrid.getObjectsInRangePartial(mob, MobAIThread.AI_BASE_AGGRO_RANGE, MBServerStatics.MASK_SIEGE);
for (AbstractWorldObject awoMob : awoList) {
Mob aggroMob = (Mob) awoMob;
if (guardCanAggro(mob, aggroMob)) {
mob.setCombatTarget(aggroMob);
return;
}
}
}
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForPlayerGuardAggro");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForPlayerGuardAggro" + e.getMessage());
}
}
@@ -1174,7 +1180,7 @@ public class MobAI {
}
}
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardCanAggro");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardCanAggro" + " " + e.getMessage());
}
return false;
}
@@ -1226,7 +1232,7 @@ public class MobAI {
}
}
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: randomGuardPatrolPoints");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: randomGuardPatrolPoints" + " " + e);
}
}
@@ -1261,7 +1267,7 @@ public class MobAI {
}
return mostHatedTarget;
} catch (Exception e) {
Logger.error(e, mob.getObjectUUID() + " " + mob.getName() + " Failed At: ChangeTargetFromMostHated");
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: ChangeTargetFromMostHated" + " " + e.getMessage());
}
return null;
}
+9 -8
View File
@@ -12,7 +12,8 @@ package engine.net;
import engine.math.Vector3f;
import engine.math.Vector3fImmutable;
import engine.util.ByteBufferUtils;
import org.joda.time.DateTime;
import java.time.Instant;
import java.time.ZoneId;
import java.nio.ByteBuffer;
import java.time.LocalDateTime;
@@ -57,13 +58,13 @@ public class ByteBufferWriter {
this.bb.putLong(x);
}
public synchronized void putDateTime(DateTime dateTime) {
this.put((byte) dateTime.getDayOfMonth());
this.put((byte) ((byte) dateTime.getMonthOfYear() - 1));
this.putInt(dateTime.getYear() - 1900);
this.put((byte) dateTime.getHourOfDay());
this.put((byte) dateTime.getMinuteOfHour());
this.put((byte) dateTime.getSecondOfDay());
public synchronized void putDateTime(Instant dateTime) {
this.put((byte) dateTime.atZone(ZoneId.systemDefault()).toLocalDate().getDayOfMonth());
this.put((byte) ((byte) dateTime.atZone(ZoneId.systemDefault()).toLocalDate().getMonthValue() - 1));
this.putInt(dateTime.atZone(ZoneId.systemDefault()).toLocalDate().getYear() - 1900);
this.put((byte) dateTime.atZone(ZoneId.systemDefault()).toLocalTime().getHour());
this.put((byte) dateTime.atZone(ZoneId.systemDefault()).toLocalTime().getMinute());
this.put((byte) dateTime.atZone(ZoneId.systemDefault()).toLocalTime().getSecond());
}
public synchronized void putLocalDateTime(LocalDateTime dateTime) {
+2 -2
View File
@@ -14,7 +14,7 @@ import engine.gameManager.ChatManager;
import engine.net.client.ClientConnection;
import engine.objects.PlayerCharacter;
import engine.server.MBServerStatics;
import org.joda.time.DateTime;
import java.time.Instant;
import org.pmw.tinylog.Logger;
import java.lang.reflect.Constructor;
@@ -85,7 +85,7 @@ public class NetMsgFactory {
if (protocolMsg == Protocol.NONE) {
String errorString = DateTime.now().toString() + origin.lastProtocol.name();
String errorString = Instant.now().toString() + origin.lastProtocol.name();
int errorCode = errorString.hashCode();
@@ -22,7 +22,7 @@ import engine.net.client.msg.guild.GuildInfoMsg;
import engine.objects.Guild;
import engine.objects.GuildHistory;
import engine.objects.PlayerCharacter;
import org.joda.time.DateTime;
import java.time.Instant;
public class AcceptInviteToGuildHandler extends AbstractClientMsgHandler {
@@ -90,8 +90,8 @@ public class AcceptInviteToGuildHandler extends AbstractClientMsgHandler {
//Add to guild History
if (player.getGuild() != null) {
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(player.getGuildUUID(), player, DateTime.now(), GuildHistoryType.JOIN)) {
GuildHistory guildHistory = new GuildHistory(player.getGuildUUID(), player.getGuild().getName(), DateTime.now(), GuildHistoryType.JOIN);
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(player.getGuildUUID(), player, Instant.now(), GuildHistoryType.JOIN)) {
GuildHistory guildHistory = new GuildHistory(player.getGuildUUID(), player.getGuild().getName(), Instant.now(), GuildHistoryType.JOIN);
player.getGuildHistory().add(guildHistory);
}
}
@@ -25,7 +25,7 @@ import engine.objects.Guild;
import engine.objects.GuildHistory;
import engine.objects.GuildStatusController;
import engine.objects.PlayerCharacter;
import org.joda.time.DateTime;
import java.time.Instant;
public class BanishUnbanishHandler extends AbstractClientMsgHandler {
@@ -95,8 +95,8 @@ public class BanishUnbanishHandler extends AbstractClientMsgHandler {
//Set guild history
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(guild.getObjectUUID(), toBanish, DateTime.now(), GuildHistoryType.BANISHED)) {
GuildHistory guildHistory = new GuildHistory(toBanish.getGuildUUID(), toBanish.getGuild().getName(), DateTime.now(), GuildHistoryType.BANISHED);
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(guild.getObjectUUID(), toBanish, Instant.now(), GuildHistoryType.BANISHED)) {
GuildHistory guildHistory = new GuildHistory(toBanish.getGuildUUID(), toBanish.getGuild().getName(), Instant.now(), GuildHistoryType.BANISHED);
toBanish.getGuildHistory().add(guildHistory);
}
}
@@ -15,7 +15,7 @@ import engine.net.client.msg.ErrorPopupMsg;
import engine.net.client.msg.ManageCityAssetsMsg;
import engine.net.client.msg.PlaceAssetMsg;
import engine.objects.*;
import org.joda.time.DateTime;
import java.time.LocalDateTime;
/*
* @Author:
@@ -251,11 +251,10 @@ public class ManageCityAssetMsgHandler extends AbstractClientMsgHandler {
return true;
}
DateTime baneLive = new DateTime(bane.getPlacementDate());
LocalDateTime baneLive = bane.getPlacementDate();
baneLive = baneHour == 24 ? baneLive.plusDays(3) : baneLive.plusDays(2);
baneLive = baneHour == 24 ? baneLive.hourOfDay().setCopy(0) : baneLive.hourOfDay().setCopy(baneHour);
baneLive = baneLive.minuteOfHour().setCopy(0);
baneLive = baneLive.secondOfMinute().setCopy(1);
baneLive = baneHour == 24 ? baneLive.withHour(0) : baneLive.withHour(baneHour);
baneLive = baneLive.withMinute(0).withSecond(1).withNano(0);
bane.setLiveDate(baneLive);
outMsg.actionType = 18;
@@ -19,7 +19,7 @@ import engine.net.client.msg.PlaceAssetMsg;
import engine.net.client.msg.PlaceAssetMsg.PlacementInfo;
import engine.objects.*;
import engine.server.MBServerStatics;
import org.joda.time.DateTime;
import java.time.Instant;
import org.pmw.tinylog.Logger;
import java.time.LocalDateTime;
@@ -1142,7 +1142,7 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
Blueprint blueprint;
Building newMesh;
DateTime completionDate;
Instant completionDate;
float vendorRotation;
float buildingRotation;
@@ -1157,9 +1157,9 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
if ((blueprint.getBuildingGroup().equals(BuildingGroup.SIEGETENT))
|| (blueprint.getBuildingGroup().equals(BuildingGroup.BULWARK)))
completionDate = DateTime.now().plusMinutes(15);
completionDate = Instant.now().plusSeconds(15 * 60);
else
completionDate = DateTime.now().plusHours(blueprint.getRankTime(1));
completionDate = Instant.now().plusSeconds(blueprint.getRankTime(1) * 3600);
Vector3fImmutable localLoc = new Vector3fImmutable(ZoneManager.worldToLocal(buildingInfo.getLoc(), currentZone));
@@ -1228,7 +1228,7 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
ArrayList<AbstractGameObject> shrineObjects = DbManager.ShrineQueries.CREATE_SHRINE(
currentZone.getObjectUUID(), player.getObjectUUID(), blueprint.getName(), blueprint.getMeshForRank(0),
localLoc, 1.0f, blueprint.getMaxHealth(0), ProtectionState.PROTECTED, 0, 0,
DateTime.now().plusHours(blueprint.getRankTime(1)), blueprint.getMeshForRank(0), vendorRotation, buildingRotation, shrineType.name());
Instant.now().plusSeconds(blueprint.getRankTime(1) * 3600), blueprint.getMeshForRank(0), vendorRotation, buildingRotation, shrineType.name());
if (shrineObjects == null) {
PlaceAssetMsg.sendPlaceAssetError(player.getClientConnection(), 1, "A Serious error has occurred. Please post details for to ensure transaction integrity");
@@ -1288,7 +1288,7 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
float buildingRotation = buildingInfo.getRot().y;
float vendorRotation = buildingInfo.getW();
DateTime completionDate = DateTime.now().plusHours(blueprint.getRankTime(1));
Instant completionDate = Instant.now().plusSeconds(blueprint.getRankTime(1) * 3600);
newMesh = DbManager.BuildingQueries.CREATE_BUILDING(
@@ -1333,7 +1333,7 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
warehouseBuilding = DbManager.BuildingQueries.CREATE_BUILDING(
currentZone.getObjectUUID(), player.getObjectUUID(), blueprint.getName(), blueprint.getMeshForRank(0),
localLoc, 1.0f, blueprint.getMaxHealth(0), ProtectionState.NONE, 0, 0,
DateTime.now().plusHours(blueprint.getRankTime(1)), blueprint.getMeshForRank(0), vendorRotation, buildingRotation);
Instant.now().plusSeconds(blueprint.getRankTime(1) * 3600), blueprint.getMeshForRank(0), vendorRotation, buildingRotation);
if (warehouseBuilding == null) {
PlaceAssetMsg.sendPlaceAssetError(player.getClientConnection(), 1, "A Serious error has occurred. Please post details for to ensure transaction integrity");
@@ -17,8 +17,8 @@ import engine.net.Protocol;
import engine.objects.Building;
import engine.objects.Guild;
import engine.server.MBServerStatics;
import org.joda.time.DateTime;
import org.joda.time.Seconds;
import java.time.LocalDateTime;
import java.time.Duration;
public class ArcMineWindowAvailableTimeMsg extends ClientNetMsg {
@@ -26,8 +26,8 @@ public class ArcMineWindowAvailableTimeMsg extends ClientNetMsg {
private Building treeOfLife;
private int currentMineHour;
private Seconds secondsLeft;
private DateTime lateTime;
private Duration secondsLeft;
private LocalDateTime lateTime;
private int late;
/**
@@ -72,15 +72,15 @@ public class ArcMineWindowAvailableTimeMsg extends ClientNetMsg {
currentMineHour = guild.getMineTime();
late = MBServerStatics.MINE_LATE_WINDOW;
lateTime = DateTime.now();
lateTime = LocalDateTime.now();
if (late == 0)
lateTime = lateTime.plusDays(1);
lateTime = lateTime.hourOfDay().setCopy(late);
lateTime = lateTime.withHour(late);
late = ((late > 23) ? (late - 24) : late);
secondsLeft = Seconds.secondsBetween(DateTime.now(), lateTime);
secondsLeft = Duration.between(LocalDateTime.now(), lateTime);
}
/**
@@ -106,4 +106,4 @@ public class ArcMineWindowAvailableTimeMsg extends ClientNetMsg {
public void setBuildingUUID(int buildingUUID) {
this.buildingUUID = buildingUUID;
}
}
}
@@ -18,9 +18,6 @@ import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter;
import engine.net.Protocol;
import engine.objects.*;
import org.joda.time.DateTime;
import org.joda.time.Period;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Set;
@@ -397,37 +394,33 @@ public class ManageCityAssetsMsg extends ClientNetMsg {
else
writer.put((byte) 0);
DateTime placedOn = bane.getLiveDate();
LocalDateTime placedOn = bane.getLiveDate();
if (placedOn == null)
placedOn = new DateTime(DateTime.now());
placedOn = LocalDateTime.now();
//set Calander to date of bane live.
DateTime now = DateTime.now();
DateTime defaultTime = new DateTime(bane.getPlacementDate());
DateTime playerEnterWorldTime = new DateTime(this.assetManager.getTimeStamp("EnterWorld"));
Period period = new Period(playerEnterWorldTime.getMillis(), now.getMillis());
int hoursLoggedIn = period.getHours();
LocalDateTime now = LocalDateTime.now();
LocalDateTime defaultTime = bane.getPlacementDate();
LocalDateTime playerEnterWorldTime = LocalDateTime.ofInstant(java.time.Instant.ofEpochMilli(this.assetManager.getTimeStamp("EnterWorld")), ZoneId.systemDefault());
int hoursLoggedIn = (int) java.time.Duration.between(playerEnterWorldTime, now).toHours();
hoursLoggedIn = hoursLoggedIn < 0 ? 0 : hoursLoggedIn;
defaultTime = defaultTime.plusDays(2);
defaultTime = defaultTime.hourOfDay().setCopy(22);
defaultTime = defaultTime.minuteOfHour().setCopy(0);
defaultTime = defaultTime.secondOfMinute().setCopy(0);
defaultTime = defaultTime.plusDays(2).withHour(22).withMinute(0).withSecond(0).withNano(0);
long curTime = now.getMillis();
long curTime = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
long timeLeft = 0;
if (bane.getLiveDate() != null)
timeLeft = bane.getLiveDate().getMillis() - curTime;
timeLeft = bane.getLiveDate().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() - curTime;
else
timeLeft = defaultTime.getMillis() - curTime + 1000;
timeLeft = defaultTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() - curTime + 1000;
//DO not touch these. They are static formula's until i get the correct converter for SB Time.
writer.put((byte) placedOn.dayOfMonth().get());
writer.put((byte) placedOn.monthOfYear().get());
writer.putInt(placedOn.year().get() - 1900);
writer.put((byte) placedOn.getDayOfMonth());
writer.put((byte) placedOn.getMonthValue());
writer.putInt(placedOn.getYear() - 1900);
writer.put((byte) 0);
writer.put((byte) 0);
writer.put((byte) 0);
+20 -24
View File
@@ -19,9 +19,8 @@ import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter;
import engine.net.Protocol;
import engine.objects.*;
import org.joda.time.DateTime;
import org.joda.time.Period;
import org.joda.time.Seconds;
import java.time.Duration;
import java.time.LocalDateTime;
import org.pmw.tinylog.Logger;
import java.util.ArrayList;
@@ -137,7 +136,6 @@ public class ManageNPCMsg extends ClientNetMsg {
@Override
protected void _serialize(ByteBufferWriter writer) {
Period upgradePeriod;
int upgradePeriodInSeconds;
try {
@@ -199,21 +197,20 @@ public class ManageNPCMsg extends ClientNetMsg {
writer.putInt(npc.getUpgradeCost());
if (npc.isRanking() && npc.getUpgradeDateTime().isAfter(DateTime.now()))
upgradePeriod = new Period(DateTime.now(), npc.getUpgradeDateTime());
else
upgradePeriod = new Period(0);
long upgradeTotalSecs = 0;
if (npc.isRanking() && npc.getUpgradeDateTime().isAfter(LocalDateTime.now()))
upgradeTotalSecs = Duration.between(LocalDateTime.now(), npc.getUpgradeDateTime()).getSeconds();
writer.put((byte) upgradePeriod.getDays()); //for timer
writer.put((byte) (int) (upgradeTotalSecs / 86400)); //for timer
writer.put((byte) unknown26);//unknown
writer.putInt(100); //unknown
writer.put((byte) upgradePeriod.getHours()); //for timer
writer.put((byte) upgradePeriod.getMinutes()); //for timer
writer.put((byte) upgradePeriod.getSeconds()); //for timer
writer.put((byte) (int) ((upgradeTotalSecs % 86400) / 3600)); //for timer
writer.put((byte) (int) ((upgradeTotalSecs % 3600) / 60)); //for timer
writer.put((byte) (int) (upgradeTotalSecs % 60)); //for timer
if (npc.isRanking() && npc.getUpgradeDateTime().isAfter(DateTime.now()))
upgradePeriodInSeconds = Seconds.secondsBetween(DateTime.now(), npc.getUpgradeDateTime()).getSeconds();
if (npc.isRanking() && npc.getUpgradeDateTime().isAfter(LocalDateTime.now()))
upgradePeriodInSeconds = (int) upgradeTotalSecs;
else
upgradePeriodInSeconds = 0;
@@ -589,21 +586,20 @@ public class ManageNPCMsg extends ClientNetMsg {
writer.putInt(Mob.getUpgradeCost(mobA));
if (mobA.isRanking() && mobA.getUpgradeDateTime().isAfter(DateTime.now()))
upgradePeriod = new Period(DateTime.now(), mobA.getUpgradeDateTime());
else
upgradePeriod = new Period(0);
long upgradeTotalSecs = 0;
if (mobA.isRanking() && mobA.getUpgradeDateTime().isAfter(LocalDateTime.now()))
upgradeTotalSecs = Duration.between(LocalDateTime.now(), mobA.getUpgradeDateTime()).getSeconds();
writer.put((byte) upgradePeriod.getDays()); //for timer
writer.put((byte) (int) (upgradeTotalSecs / 86400)); //for timer
writer.put((byte) unknown26);//unknown
writer.putInt(100); //unknown
writer.put((byte) upgradePeriod.getHours()); //for timer
writer.put((byte) upgradePeriod.getMinutes()); //for timer
writer.put((byte) upgradePeriod.getSeconds()); //for timer
writer.put((byte) (int) ((upgradeTotalSecs % 86400) / 3600)); //for timer
writer.put((byte) (int) ((upgradeTotalSecs % 3600) / 60)); //for timer
writer.put((byte) (int) (upgradeTotalSecs % 60)); //for timer
if (mobA.isRanking() && mobA.getUpgradeDateTime().isAfter(DateTime.now()))
upgradePeriodInSeconds = Seconds.secondsBetween(DateTime.now(), mobA.getUpgradeDateTime()).getSeconds();
if (mobA.isRanking() && mobA.getUpgradeDateTime().isAfter(LocalDateTime.now()))
upgradePeriodInSeconds = (int) upgradeTotalSecs;
else
upgradePeriodInSeconds = 0;
@@ -17,7 +17,7 @@ import engine.net.ByteBufferWriter;
import engine.net.Protocol;
import engine.net.client.msg.ClientNetMsg;
import engine.objects.*;
import org.joda.time.DateTime;
import java.time.Instant;
public class GuildInfoMsg extends ClientNetMsg {
@@ -306,7 +306,7 @@ class GuildInfoMessageType4 extends GuildInfoMessageType {
writer.putString(guildLeaderName);
writer.putString(pc.getName());
writer.putDateTime(DateTime.now());
writer.putDateTime(Instant.now());
writer.put((byte) 1);
writer.put((byte) 1);
writer.put((byte) 1);
@@ -401,7 +401,7 @@ class GuildInfoMessageType5 extends GuildInfoMessageType {
writer.putString("Guild Leader");
writer.putString(""); //Nation Leader - I believe
DateTime now = DateTime.now();
Instant now = Instant.now();
writer.putDateTime(now);
writer.put((byte) 1);
+10 -90
View File
@@ -656,30 +656,12 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
AssignDamageAtrForPlayers(abstractCharacter, equipped.get(EquipSlotType.LHELD), false, equipped.get(EquipSlotType.LHELD));
if (abstractCharacter.getObjectType().equals(GameObjectType.Mob)) {
Mob mob = (Mob) abstractCharacter;
ItemTemplate rune = ItemTemplate.templates.get(mob.loadID);
float minDamage = mob.mobBase.getDamageMin();
float maxDamage = mob.mobBase.getDamageMax();
int attackRating = mob.mobBase.getAttackRating();
// The client (ArcMobile, 0x46D200) takes mob damage straight from the rune MINDAMAGE/MAXDAMAGE,
// with no stat scaling. Use the rune when it has damage, otherwise keep the mobbase value.
if (rune != null && rune.rune_max_damage > 0) {
minDamage = rune.rune_min_damage;
maxDamage = rune.rune_max_damage;
}
// Likewise ATR comes straight from the rune ATTACK for mobiles (0x466570).
if (rune != null && rune.rune_attack > 0)
attackRating = rune.rune_attack;
abstractCharacter.minDamageHandOne = (int) minDamage;
abstractCharacter.minDamageHandTwo = (int) minDamage;
abstractCharacter.maxDamageHandOne = (int) maxDamage;
abstractCharacter.maxDamageHandTwo = (int) maxDamage;
abstractCharacter.atrHandOne = attackRating;
abstractCharacter.atrHandTwo = attackRating;
abstractCharacter.minDamageHandOne = (int) mob.mobBase.getDamageMin();
abstractCharacter.minDamageHandTwo = (int) mob.mobBase.getDamageMin();
abstractCharacter.maxDamageHandOne = (int) mob.mobBase.getDamageMax();
abstractCharacter.maxDamageHandTwo = (int) mob.mobBase.getDamageMax();
abstractCharacter.atrHandOne = mob.mobBase.getAttackRating();
abstractCharacter.atrHandTwo = mob.mobBase.getAttackRating();
abstractCharacter.defenseRating = mob.mobBase.getDefenseRating();
}
}
@@ -735,18 +717,9 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
mastDam = CharacterSkill.getQuickMastery(abstractCharacter, "Unarmed Combat Mastery");
else
mastDam = masteryPercentage;
// Base fist damage from the race rune natural attack (1-4 for all races), scaled below like a weapon.
// Matches the client's unarmed damage calc (0x46D200).
float[] naturalAttack = CombatManager.getNaturalAttack(abstractCharacter, mainHand ? EquipSlotType.RHELD : EquipSlotType.LHELD);
if (naturalAttack != null && naturalAttack.length > 9) {
min = (int) naturalAttack[8];
max = (int) naturalAttack[9];
} else {
min = 1;
max = 3;
}
// TODO Correct these
min = 1;
max = 3;
} else {
if (mainHand)
@@ -1503,22 +1476,13 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
Mob mob = (Mob) this;
if (mob.isSiege()) {
return CombatManager.getSiegeRange(mob);
return 300;
}
float range = 8;
if ((this).charItemManager.equipped.get(EquipSlotType.RHELD) != null) {
range = ((Mob) this).charItemManager.equipped.get(EquipSlotType.RHELD).template.item_weapon_max_range;
} else if (((Mob) this).charItemManager.equipped.get(EquipSlotType.LHELD) != null) {
range = ((Mob) this).charItemManager.equipped.get(EquipSlotType.LHELD).template.item_weapon_max_range;
} else {
// Unarmed: use the rune natural attack range when it has one (e.g. Gasser 150), not clamped.
// Most melee runes have 0, so they keep the default of 8.
float naturalRange = CombatManager.getNaturalAttackRange(mob, EquipSlotType.RHELD);
if (naturalRange > 0)
return naturalRange;
}
// TODO Is this clamp from live?
@@ -1863,15 +1827,6 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
if (this.getObjectType().equals(GameObjectType.Mob)) {
//handle hate value addition
Mob target = (Mob) this;
// Siege engines switch to whoever damages them, players and pets alike.
// Misses and non-damaging powers do not pull them.
if (target.isSiege() && value < 0f && attacker != null && !attacker.equals(target)) {
target.setCombatTarget(attacker);
flagSiegeAttackerHostile(target, attacker);
}
if (attacker.getObjectType().equals(GameObjectType.PlayerCharacter)) {
if (target.playerAgroMap.containsKey(attacker.getObjectUUID()))
@@ -1905,41 +1860,6 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
return 0;
}
private static void flagSiegeAttackerHostile(Mob siegeEngine, AbstractCharacter attacker) {
// Damaging a siege engine on a city grid flags the player hostile to that
// city, unless they belong to the city's nation or an allied nation.
// Pets flag their owner.
City city;
AbstractCharacter flagged;
Guild cityNation;
city = ZoneManager.getCityAtLocation(siegeEngine.loc);
if (city == null)
return;
flagged = attacker;
if (attacker.getObjectType().equals(GameObjectType.Mob))
flagged = ((Mob) attacker).guardCaptain;
if (flagged == null || !flagged.getObjectType().equals(GameObjectType.PlayerCharacter))
return;
cityNation = city.getGuild().getNation();
if (flagged.getGuild().getNation().equals(cityNation))
return;
if (cityNation.getAllyList().contains(flagged.getGuild().getNation()))
return;
if (!city.cityOutlaws.contains(flagged.getObjectUUID()))
city.cityOutlaws.add(flagged.getObjectUUID());
}
public float getCurrentHitpoints() {
return this.health.get();
}
@@ -148,20 +148,9 @@ public abstract class AbstractIntelligenceAgent extends AbstractCharacter {
public void dismiss() {
boolean isSiegeEngine;
isSiegeEngine = this.getObjectType() == GameObjectType.Mob && ((Mob) this).isSiege();
if (this.isPet()) {
if (isSiegeEngine) {
// Released siege engines stay in place, alive, and keep firing at
// their current target until a Rod of Command takes them again.
this.agentType = mbEnums.AIAgentType.MOBILE;
} else if ((this.agentType.equals(mbEnums.AIAgentType.PET))) { //delete summoned pet
if ((this.agentType.equals(mbEnums.AIAgentType.PET))) { //delete summoned pet
WorldGrid.RemoveWorldObject(this);
@@ -178,8 +167,7 @@ public abstract class AbstractIntelligenceAgent extends AbstractCharacter {
// clear owner and set not alive
if (!isSiegeEngine)
this.isAlive.set(false);
this.isAlive.set(false);
PlayerCharacter owner = (PlayerCharacter) this.guardCaptain;
@@ -200,8 +188,6 @@ public abstract class AbstractIntelligenceAgent extends AbstractCharacter {
this.guardCaptain = null;
}
if (isSiegeEngine && this.isAlive())
WorldGrid.updateObject(this);
}
}
+18 -22
View File
@@ -25,7 +25,8 @@ import engine.net.client.ClientConnection;
import engine.net.client.msg.PlaceAssetMsg;
import engine.net.client.msg.chat.ChatSystemMsg;
import engine.server.MBServerStatics;
import org.joda.time.DateTime;
import java.time.LocalDateTime;
import java.time.ZoneId;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet;
@@ -40,8 +41,8 @@ public final class Bane {
private final int cityUUID;
private final int stoneUUID;
private int ownerUUID;
private DateTime placementDate = null;
private DateTime liveDate = null;
private LocalDateTime placementDate = null;
private LocalDateTime liveDate = null;
private BaneDefaultTimeJob defaultTimeJob;
// Internal cache for banes
@@ -62,12 +63,12 @@ public final class Bane {
sqlDateTime = rs.getTimestamp("placementDate");
if (sqlDateTime != null)
this.placementDate = new DateTime(sqlDateTime);
this.placementDate = LocalDateTime.ofInstant(sqlDateTime.toInstant(), ZoneId.systemDefault());
sqlDateTime = rs.getTimestamp("liveDate");
if (sqlDateTime != null)
this.liveDate = new DateTime(sqlDateTime);
this.liveDate = LocalDateTime.ofInstant(sqlDateTime.toInstant(), ZoneId.systemDefault());
switch (this.getSiegePhase()) {
@@ -81,7 +82,7 @@ public final class Bane {
this.activateBaneJob.cancelJob();
abtj = new ActivateBaneJob(cityUUID);
JobScheduler.getInstance().scheduleJob(abtj, this.liveDate.getMillis());
JobScheduler.getInstance().scheduleJob(abtj, this.liveDate.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
this.activateBaneJob = abtj;
break;
@@ -93,7 +94,7 @@ public final class Bane {
this.activateBaneJob.cancelJob();
abtj = new ActivateBaneJob(cityUUID);
JobScheduler.getInstance().scheduleJob(abtj, this.liveDate.getMillis());
JobScheduler.getInstance().scheduleJob(abtj, this.liveDate.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
this.activateBaneJob = abtj;
break;
@@ -353,7 +354,7 @@ public final class Bane {
return phase;
}
if (DateTime.now().isAfter(this.liveDate)) {
if (LocalDateTime.now().isAfter(this.liveDate)) {
phase = SiegePhase.WAR; //war
return phase;
}
@@ -368,15 +369,10 @@ public final class Bane {
private void setDefaultTime() {
DateTime timeToSetDefault = new DateTime(this.placementDate);
timeToSetDefault = timeToSetDefault.plusDays(1);
LocalDateTime timeToSetDefault = this.placementDate.plusDays(1);
DateTime currentTime = DateTime.now();
DateTime defaultTime = new DateTime(this.placementDate);
defaultTime = defaultTime.plusDays(2);
defaultTime = defaultTime.hourOfDay().setCopy(22);
defaultTime = defaultTime.minuteOfHour().setCopy(0);
defaultTime = defaultTime.secondOfMinute().setCopy(0);
LocalDateTime currentTime = LocalDateTime.now();
LocalDateTime defaultTime = this.placementDate.plusDays(2).withHour(22).withMinute(0).withSecond(0);
if (currentTime.isAfter(timeToSetDefault))
this.setLiveDate(defaultTime);
@@ -386,7 +382,7 @@ public final class Bane {
this.defaultTimeJob.cancelJob();
BaneDefaultTimeJob bdtj = new BaneDefaultTimeJob(this);
JobScheduler.getInstance().scheduleJob(bdtj, timeToSetDefault.getMillis());
JobScheduler.getInstance().scheduleJob(bdtj, timeToSetDefault.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
this.defaultTimeJob = bdtj;
}
}
@@ -453,7 +449,7 @@ public final class Bane {
return true;
}
public final DateTime getPlacementDate() {
public final LocalDateTime getPlacementDate() {
return placementDate;
}
@@ -462,14 +458,14 @@ public final class Bane {
return (this.getSiegePhase() != SiegePhase.CHALLENGE);
}
public final DateTime getLiveDate() {
public final LocalDateTime getLiveDate() {
return liveDate;
}
public void setLiveDate(DateTime baneTime) {
public void setLiveDate(LocalDateTime baneTime) {
if (DbManager.BaneQueries.SET_BANE_TIME(baneTime, this.getCity().getObjectUUID())) {
this.liveDate = new DateTime(baneTime);
this.liveDate = baneTime;
// Push event to warehouse
@@ -511,7 +507,7 @@ public final class Bane {
ActivateBaneJob abtj = new ActivateBaneJob(cityUUID);
JobScheduler.getInstance().scheduleJob(abtj, this.liveDate.getMillis());
JobScheduler.getInstance().scheduleJob(abtj, this.liveDate.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
this.activateBaneJob = abtj;
} else {
Logger.debug("error with city " + this.getCity().getName());
+1 -3
View File
@@ -395,10 +395,8 @@ public class Building extends AbstractWorldObject {
//friendly building has been attacked, add attacker to city outlaw list
if (!playerCity.cityOutlaws.contains(attacker.getObjectUUID()) && attacker.getObjectType().equals(GameObjectType.PlayerCharacter))
playerCity.cityOutlaws.add(attacker.getObjectUUID());
//only city guards respond; siege engines and pets in the zone are left alone
for (Mob guard : playerCity.getParent().zoneMobSet)
if (guard.isPlayerGuard() && guard.combatTarget == null)
if (guard.combatTarget == null)
guard.setCombatTarget(attacker);
}
}
+3 -3
View File
@@ -22,7 +22,7 @@ import engine.net.client.msg.ErrorPopupMsg;
import engine.net.client.msg.UpdateClientAlliancesMsg;
import engine.net.client.msg.guild.GuildInfoMsg;
import engine.server.world.WorldServer;
import org.joda.time.DateTime;
import java.time.Instant;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet;
@@ -612,8 +612,8 @@ public class Guild extends AbstractWorldObject {
//Add to Guild History
if (pc.getGuild() != null) {
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(pc.getGuildUUID(), pc, DateTime.now(), historyType)) {
GuildHistory guildHistory = new GuildHistory(pc.getGuildUUID(), pc.getGuild().name, DateTime.now(), historyType);
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(pc.getGuildUUID(), pc, Instant.now(), historyType)) {
GuildHistory guildHistory = new GuildHistory(pc.getGuildUUID(), pc.getGuild().name, Instant.now(), historyType);
pc.getGuildHistory().add(guildHistory);
}
}
+8 -7
View File
@@ -13,10 +13,11 @@ package engine.objects;
import engine.mbEnums.GameObjectType;
import engine.mbEnums.GuildHistoryType;
import engine.net.ByteBufferWriter;
import org.joda.time.DateTime;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
public class GuildHistory {
@@ -24,12 +25,12 @@ public class GuildHistory {
private int guildID;
private String guildName;
private DateTime time;
private Instant time;
private GuildHistoryType historyType;
public GuildHistory(int guildID, String guildName,
DateTime dateTime, GuildHistoryType historyType) {
Instant dateTime, GuildHistoryType historyType) {
super();
this.guildID = guildID;
this.guildName = guildName;
@@ -49,9 +50,9 @@ public class GuildHistory {
sqlDateTime = rs.getTimestamp("historyDate");
if (sqlDateTime != null)
this.time = new DateTime(sqlDateTime);
this.time = sqlDateTime.toInstant();
else
this.time = DateTime.now().minusYears(1);
this.time = Instant.now().minus(1, ChronoUnit.YEARS);
this.historyType = GuildHistoryType.valueOf(rs.getString("historyType"));
}
@@ -77,11 +78,11 @@ public class GuildHistory {
writer.putDateTime(this.time);
}
public DateTime getTime() {
public Instant getTime() {
return time;
}
public void setTime(DateTime time) {
public void setTime(Instant time) {
this.time = time;
}
-26
View File
@@ -90,14 +90,8 @@ public class ItemTemplate {
public final EnumSet<mbEnums.DisciplineType> item_disc_res = EnumSet.noneOf(mbEnums.DisciplineType.class);
public int item_level_req;
public mbEnums.SexType item_sex_req;
// Lossy: some runes list the same power several times with different
// arguments (a step table, e.g. PET_DISC). Only the last entry is kept.
// engine.parsers.objects.RuneTemplate keeps the full list.
public final HashMap<String, int[]> item_user_power_action = new HashMap<>();
public final HashMap<String, Integer> item_power_grant = new HashMap<>();
// Lossy: some runes carry up to 35 power_actions entries per power
// (a step table, e.g. HNT-031). Only the first entry is kept.
// engine.parsers.objects.RuneTemplate keeps the full list.
public final HashMap<String, int[]> item_power_action = new HashMap<>();
public final HashMap<mbEnums.ResourceType, Integer> item_resource_cost = new HashMap<>();
public int modTable;
@@ -144,11 +138,6 @@ public class ItemTemplate {
public final EnumSet<mbEnums.MobBehaviourType> rune_group_role_set = EnumSet.noneOf(mbEnums.MobBehaviourType.class);
public boolean rune_renderable = false;
public int rune_natural_power_attack;
// One float[] per rune_naturalattacks entry. Same "attack info" struct as a weapon (verified in IDA, see
// MBDATA/docs/client-map.md): [0] attack speed (WEPSPEED), [1] range (MAXRANGE), [2] unknown int,
// [3] equip slot (1 = RHELD, 2 = LHELD), [4] projectile template id, [5] projectile speed, [6] swing anim,
// [7] damage type, [8] min damage, [9] max damage
public final ArrayList<float[]> rune_natural_attacks = new ArrayList<>();
public final HashMap<String, String> rune_sparse_data = new HashMap<>();
public final HashMap<String, int[]> rune_skill_adj = new HashMap<>();
public final EnumSet<mbEnums.MonsterType> rune_enemy_monster_types = EnumSet.noneOf(mbEnums.MonsterType.class);
@@ -565,21 +554,6 @@ public class ItemTemplate {
rune_renderable = jsonObject.getBoolean("rune_renderable");
rune_natural_power_attack = jsonObject.getInt("rune_natural_power_attack");
if (jsonObject.has("rune_naturalattacks")) {
JSONArray natural_attacks_json = jsonObject.getJSONArray("rune_naturalattacks");
for (Object attackEntry : natural_attacks_json) {
JSONArray attackArray = (JSONArray) attackEntry;
float[] attack = new float[attackArray.length()];
for (int i = 0; i < attackArray.length(); i++)
attack[i] = attackArray.getFloat(i);
rune_natural_attacks.add(attack);
}
}
JSONObject rune_sparse_json = jsonObject.getJSONObject("rune_sparse_data");
for (String sparseType : rune_sparse_json.keySet()) {
+9 -19
View File
@@ -24,7 +24,8 @@ import engine.net.client.msg.PetMsg;
import engine.net.client.msg.PlaceAssetMsg;
import engine.server.MBServerStatics;
import org.jetbrains.annotations.NotNull;
import org.joda.time.DateTime;
import java.time.LocalDateTime;
import java.time.ZoneId;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet;
@@ -71,7 +72,7 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
public long nextAttackTime = System.currentTimeMillis();
private int lastMobPowerToken = 0;
private DeferredPowerJob weaponPower;
private DateTime upgradeDateTime = null;
private LocalDateTime upgradeDateTime = null;
private boolean lootSync = false;
// New Mobile constructor. Fill in the blanks and then call
@@ -126,7 +127,7 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
sqlDateTime = rs.getTimestamp("upgradeDate");
if (sqlDateTime != null)
upgradeDateTime = new DateTime(sqlDateTime);
upgradeDateTime = LocalDateTime.ofInstant(sqlDateTime.toInstant(), ZoneId.systemDefault());
else
upgradeDateTime = null;
@@ -552,12 +553,6 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
petMinion.despawned = false;
petMinion.runAfterLoad();
// Summoned pets carry MASK_PET. Necro pets keep their own NecroPet handling.
if (!petMinion.isNecroPet())
petMinion.setObjectTypeMask(petMinion.getObjectTypeMask() | MBServerStatics.MASK_PET);
DbManager.addToCache(petMinion);
petMinion.setLoc(petMinion.bindLoc);
@@ -599,8 +594,8 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
// Submit upgrade job for future date or current instant
if (mob.getUpgradeDateTime().isAfter(DateTime.now()))
JobScheduler.getInstance().scheduleJob(new UpgradeNPCJob(mob), mob.getUpgradeDateTime().getMillis());
if (mob.getUpgradeDateTime().isAfter(LocalDateTime.now()))
JobScheduler.getInstance().scheduleJob(new UpgradeNPCJob(mob), mob.getUpgradeDateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
else
JobScheduler.getInstance().scheduleJob(new UpgradeNPCJob(mob), 0);
@@ -626,7 +621,7 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
return upgradeCost;
}
public static void setUpgradeDateTime(Mob mob, DateTime upgradeDateTime) {
public static void setUpgradeDateTime(Mob mob, LocalDateTime upgradeDateTime) {
if (!DbManager.MobQueries.updateUpgradeTime(mob, upgradeDateTime)) {
Logger.error("Failed to set upgradeTime for building " + mob.currentID);
@@ -1324,11 +1319,6 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
if (!ac.getObjectType().equals(GameObjectType.PlayerCharacter))
return;
// siege engines only switch targets on damage, see AbstractCharacter.modifyHealth
if (this.isSiege())
return;
if (this.getCombatTarget() == null)
this.setCombatTarget(ac);
@@ -1364,7 +1354,7 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
this.weaponPower = weaponPower;
}
public DateTime getUpgradeDateTime() {
public LocalDateTime getUpgradeDateTime() {
lock.readLock().lock();
@@ -1444,7 +1434,7 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
if (!building.transferGold(-rankCost, false))
return;
DateTime dateToUpgrade = DateTime.now().plusHours(Mob.getUpgradeTime(this));
LocalDateTime dateToUpgrade = LocalDateTime.now().plusHours(Mob.getUpgradeTime(this));
Mob.setUpgradeDateTime(this, dateToUpgrade);
// Schedule upgrade job
+10 -9
View File
@@ -24,7 +24,8 @@ import engine.net.Dispatch;
import engine.net.client.msg.PetMsg;
import engine.net.client.msg.PlaceAssetMsg;
import engine.server.MBServerStatics;
import org.joda.time.DateTime;
import java.time.LocalDateTime;
import java.time.ZoneId;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet;
@@ -67,7 +68,7 @@ public class NPC extends AbstractCharacter {
protected int symbol;
// Variables NOT to be stored in db
protected boolean isStatic = false;
private DateTime upgradeDateTime = null;
private LocalDateTime upgradeDateTime = null;
private HashSet<Integer> canRoll = null;
public int parentZoneUUID;
public int equipmentSetID = 0;
@@ -131,7 +132,7 @@ public class NPC extends AbstractCharacter {
sqlDateTime = rs.getTimestamp("upgradeDate");
if (sqlDateTime != null)
upgradeDateTime = new DateTime(sqlDateTime);
upgradeDateTime = LocalDateTime.ofInstant(sqlDateTime.toInstant(), ZoneId.systemDefault());
else
upgradeDateTime = null;
@@ -527,9 +528,9 @@ public class NPC extends AbstractCharacter {
// Submit upgrade job for future date or current instant
if (this.getUpgradeDateTime().isAfter(DateTime.now()))
if (this.getUpgradeDateTime().isAfter(LocalDateTime.now()))
jc = JobScheduler.getInstance().scheduleJob(new UpgradeNPCJob(this),
this.getUpgradeDateTime().getMillis());
this.getUpgradeDateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
else
JobScheduler.getInstance().scheduleJob(new UpgradeNPCJob(this), 0);
@@ -907,7 +908,7 @@ public class NPC extends AbstractCharacter {
return new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
}
public DateTime getUpgradeDateTime() {
public LocalDateTime getUpgradeDateTime() {
lock.readLock().lock();
try {
return upgradeDateTime;
@@ -916,7 +917,7 @@ public class NPC extends AbstractCharacter {
}
}
public void setUpgradeDateTime(DateTime upgradeDateTime) {
public void setUpgradeDateTime(LocalDateTime upgradeDateTime) {
if (!DbManager.NPCQueries.updateUpgradeTime(this, upgradeDateTime)) {
Logger.error("Failed to set upgradeTime for building " + currentID);
@@ -1059,7 +1060,7 @@ public class NPC extends AbstractCharacter {
int rankCost;
Building building;
DateTime dateToUpgrade;
LocalDateTime dateToUpgrade;
this.lock.writeLock().lock();
@@ -1102,7 +1103,7 @@ public class NPC extends AbstractCharacter {
if (!building.transferGold(-rankCost, false))
return;
dateToUpgrade = DateTime.now().plusHours(this.getUpgradeTime());
dateToUpgrade = LocalDateTime.now().plusHours(this.getUpgradeTime());
this.setUpgradeDateTime(dateToUpgrade);
+7 -6
View File
@@ -37,7 +37,8 @@ import engine.server.MBServerStatics;
import engine.server.login.LoginServer;
import engine.server.world.WorldServer;
import engine.util.MiscUtils;
import org.joda.time.DateTime;
import java.time.Instant;
import java.time.ZoneId;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet;
@@ -702,11 +703,11 @@ public class PlayerCharacter extends AbstractCharacter {
writer.putInt(token);
writer.putInt((int) timeLeft / 1000);
}
DateTime enterWorld = new DateTime(playerCharacter.timestamps.get("EnterWorld"));
Instant enterWorld = Instant.ofEpochMilli(playerCharacter.timestamps.get("EnterWorld"));
writer.putDateTime(enterWorld);
writer.putInt(0x49EF1E98); //DUnno what playerCharacter is.
writer.putFloat(DateTime.now().hourOfDay().get()); //daylight in float.
writer.putFloat(Instant.now().atZone(ZoneId.systemDefault()).toLocalTime().getHour()); //daylight in float.
writer.putFloat(6); //interval of light to change per game hour //float
//writer.putInt(1637194901); //playerCharacter is actually an opcode taht is in recordings, no clue what it is, dumped it and it changes nothing
} else {
@@ -4184,9 +4185,8 @@ public class PlayerCharacter extends AbstractCharacter {
} else if (currentPet.isSiege()) {
currentPet.agentType = AIAgentType.MOBILE;
// released siege engine keeps its current target
currentPet.guardCaptain = null;
currentPet.setCombatTarget(null);
if (currentPet.isAlive())
WorldGrid.updateObject(currentPet);
}
@@ -4194,6 +4194,7 @@ public class PlayerCharacter extends AbstractCharacter {
toCommand.setPet(this, false);
this.setPet(toCommand);
toCommand.setCombatTarget(null);
PetMsg petMsg = new PetMsg(6, toCommand);
Dispatch dispatch = Dispatch.borrow(this, petMsg);
DispatchManager.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
@@ -4364,7 +4365,7 @@ public class PlayerCharacter extends AbstractCharacter {
}
if (count > 0) {
this.timestamps.put("RealmClaim", DateTime.now().plusMinutes(3).getMillis());
this.timestamps.put("RealmClaim", Instant.now().plusSeconds(180).toEpochMilli());
for (PlayerCharacter toSend : SessionManager.getAllActivePlayerCharacters()) {
ChatManager.chatSystemInfo(toSend, this.getCombinedName() + " is seeking to claim a realm and already has " + count + " blessngs!");
}
+6 -6
View File
@@ -12,7 +12,7 @@ package engine.objects;
import engine.mbEnums;
import engine.mbEnums.GameObjectType;
import engine.mbEnums.TransactionType;
import org.joda.time.DateTime;
import java.time.Instant;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -24,7 +24,7 @@ public class Transaction implements Comparable<Transaction> {
private final int warehouseUUID;
private final int targetUUID;
private final mbEnums.ResourceType resource;
private final DateTime date;
private final Instant date;
private final int amount;
private final TransactionType transactionType;
private GameObjectType targetType;
@@ -41,15 +41,15 @@ public class Transaction implements Comparable<Transaction> {
Date sqlDateTime = rs.getTimestamp("date");
if (sqlDateTime != null)
this.date = new DateTime(sqlDateTime);
this.date = sqlDateTime.toInstant();
else
this.date = DateTime.now();
this.date = Instant.now();
}
public Transaction(int warehouseUUID, GameObjectType targetType, int targetUUID, TransactionType transactionType, mbEnums.ResourceType resource, int amount,
DateTime date) {
Instant date) {
this.warehouseUUID = warehouseUUID;
this.targetUUID = targetUUID;
this.resource = resource;
@@ -75,7 +75,7 @@ public class Transaction implements Comparable<Transaction> {
}
public DateTime getDate() {
public Instant getDate() {
return date;
}
+3 -3
View File
@@ -18,7 +18,7 @@ import engine.net.Dispatch;
import engine.net.client.ClientConnection;
import engine.net.client.msg.*;
import engine.server.MBServerStatics;
import org.joda.time.DateTime;
import java.time.Instant;
import org.json.JSONArray;
import org.json.JSONObject;
import org.pmw.tinylog.Logger;
@@ -576,10 +576,10 @@ public class Warehouse {
public static void AddTransactionToWarehouse(Warehouse warehouse, mbEnums.GameObjectType targetType, int targetUUID, mbEnums.TransactionType transactionType, mbEnums.ResourceType resource, int amount) {
if (!DbManager.WarehouseQueries.CREATE_TRANSACTION(warehouse.building.getObjectUUID(), targetType, targetUUID, transactionType, resource, amount, DateTime.now()))
if (!DbManager.WarehouseQueries.CREATE_TRANSACTION(warehouse.building.getObjectUUID(), targetType, targetUUID, transactionType, resource, amount, Instant.now()))
return;
Transaction transaction = new Transaction(warehouse.building.getObjectUUID(), targetType, targetUUID, transactionType, resource, amount, DateTime.now());
Transaction transaction = new Transaction(warehouse.building.getObjectUUID(), targetType, targetUUID, transactionType, resource, amount, Instant.now());
warehouse.transactions.add(transaction);
}
-307
View File
@@ -1,307 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.parsers.cache;
import engine.math.Vector3fImmutable;
import engine.parsers.objects.PowerGrant;
import engine.parsers.objects.UserPowerAction;
import org.json.JSONArray;
import org.json.JSONObject;
import org.pmw.tinylog.Logger;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
// Shared JSON helpers for the COBJECTS cache parsers.
// Only generic reading lives here; each parser owns its own field mapping.
public class CacheParserUtil {
// Files are named <template id>.json
public static File[] listJsonFiles(String folderPath) {
File folder = new File(folderPath);
File[] jsonFiles = folder.listFiles((dir, name) -> name.endsWith(".json"));
if (jsonFiles == null) {
Logger.error("Cache folder not found: " + folder.getAbsolutePath());
return new File[0];
}
return jsonFiles;
}
public static int templateIdFromFile(File jsonFile) {
String fileName = jsonFile.getName();
return Integer.parseInt(fileName.substring(0, fileName.length() - ".json".length()));
}
public static JSONObject readJsonFile(File jsonFile) throws IOException {
byte[] fileData = Files.readAllBytes(jsonFile.toPath());
return new JSONObject(new String(fileData, StandardCharsets.UTF_8));
}
// [x, y, z] -> vector. Returns null for an empty array.
public static Vector3fImmutable readVector3(JSONArray vectorJson) {
if (vectorJson.length() < 3)
return null;
return new Vector3fImmutable(vectorJson.getFloat(0), vectorJson.getFloat(1), vectorJson.getFloat(2));
}
// Client strings carry spaces, hyphens and commas that enum constants
// can't ("Half-Giant", "Battle Magus").
public static String enumName(String value) {
String name = value;
name = name.replaceAll("\\s", "");
name = name.replaceAll("-", "");
name = name.replaceAll(",", "");
return name;
}
// Exact match on the cleaned name first, then upper case (ResourceType).
// Unknown values are logged and returned as null so one bad value
// doesn't drop the whole template.
public static <E extends Enum<E>> E readEnum(Class<E> enumClass, String value, int templateId, String fieldName) {
String name = enumName(value);
try {
return Enum.valueOf(enumClass, name);
} catch (IllegalArgumentException e) {
// fall through to upper case
}
try {
return Enum.valueOf(enumClass, name.toUpperCase());
} catch (IllegalArgumentException e) {
Logger.error(templateId + ": " + fieldName + " has no " + enumClass.getSimpleName() + " for '" + value + "'");
return null;
}
}
public static <E extends Enum<E>> EnumSet<E> readEnumSet(Class<E> enumClass, JSONArray valuesJson, int templateId, String fieldName) {
EnumSet<E> enumSet = EnumSet.noneOf(enumClass);
E enumValue;
for (int i = 0; i < valuesJson.length(); i++) {
enumValue = readEnum(enumClass, valuesJson.getString(i), templateId, fieldName);
if (enumValue != null)
enumSet.add(enumValue);
}
return enumSet;
}
// [{keyName: "Strength", valueName: 40}, ...] -> enum map
// Negative values are stored unsigned in the JSON (-5 is 4294967291),
// so values are read as long and wrapped to int.
public static <E extends Enum<E>> EnumMap<E, Integer> readEnumValueMap(Class<E> enumClass, JSONArray entriesJson,
String keyName, String valueName,
int templateId, String fieldName) {
EnumMap<E, Integer> enumMap = new EnumMap<>(enumClass);
JSONObject entry;
E enumValue;
for (int i = 0; i < entriesJson.length(); i++) {
entry = entriesJson.getJSONObject(i);
enumValue = readEnum(enumClass, entry.getString(keyName), templateId, fieldName);
if (enumValue != null)
enumMap.put(enumValue, (int) entry.getLong(valueName));
}
return enumMap;
}
// [{keyName: "Sword", valueName: 20}, ...] -> map in file order
public static LinkedHashMap<String, Integer> readStringValueMap(JSONArray entriesJson, String keyName, String valueName) {
LinkedHashMap<String, Integer> valueMap = new LinkedHashMap<>();
JSONObject entry;
for (int i = 0; i < entriesJson.length(); i++) {
entry = entriesJson.getJSONObject(i);
valueMap.put(entry.getString(keyName), (int) entry.getLong(valueName));
}
return valueMap;
}
// {"SLASHING": 0.0, ...} -> enum map
public static <E extends Enum<E>> EnumMap<E, Float> readEnumFloatMap(Class<E> enumClass, JSONObject mapJson,
int templateId, String fieldName) {
EnumMap<E, Float> enumMap = new EnumMap<>(enumClass);
E enumValue;
for (String key : mapJson.keySet()) {
enumValue = readEnum(enumClass, key, templateId, fieldName);
if (enumValue != null)
enumMap.put(enumValue, mapJson.getFloat(key));
}
return enumMap;
}
// Values are read as long and wrapped to int so unsigned 32-bit hashes survive.
public static int[] readIntArray(JSONArray valuesJson) {
int[] values = new int[valuesJson.length()];
for (int i = 0; i < valuesJson.length(); i++)
values[i] = (int) valuesJson.getLong(i);
return values;
}
public static float[] readFloatArray(JSONArray valuesJson) {
float[] values = new float[valuesJson.length()];
for (int i = 0; i < valuesJson.length(); i++)
values[i] = valuesJson.getFloat(i);
return values;
}
public static ArrayList<Integer> readIntList(JSONArray valuesJson) {
ArrayList<Integer> values = new ArrayList<>();
for (int i = 0; i < valuesJson.length(); i++)
values.add((int) valuesJson.getLong(i));
return values;
}
// [[a, b], [a, b], ...] -> list of int[]
public static ArrayList<int[]> readIntArrays(JSONArray arraysJson) {
ArrayList<int[]> arrays = new ArrayList<>();
for (int i = 0; i < arraysJson.length(); i++)
arrays.add(readIntArray(arraysJson.getJSONArray(i)));
return arrays;
}
// Sparse data values are mixed bool/int/string; stored as strings.
public static HashMap<String, String> readSparseData(JSONObject sparseJson) {
HashMap<String, String> sparseData = new HashMap<>();
for (String key : sparseJson.keySet())
sparseData.put(key, sparseJson.get(key).toString());
return sparseData;
}
// Some fields are a name when set and the number 0 when not
// (obj_sound_table, item_skill_used). The number becomes "".
public static String readLabel(JSONObject json, String key) {
Object value = json.get(key);
if (value instanceof String)
return (String) value;
return "";
}
public static ArrayList<UserPowerAction> readUserPowerActions(JSONArray actionsJson) {
ArrayList<UserPowerAction> userPowerActions = new ArrayList<>();
JSONObject entry;
for (int i = 0; i < actionsJson.length(); i++) {
entry = actionsJson.getJSONObject(i);
userPowerActions.add(new UserPowerAction(entry.getString("power"), readIntArray(entry.getJSONArray("arguments"))));
}
return userPowerActions;
}
public static ArrayList<PowerGrant> readPowerGrants(JSONArray grantsJson) {
ArrayList<PowerGrant> powerGrants = new ArrayList<>();
JSONObject entry;
PowerGrant powerGrant;
for (int i = 0; i < grantsJson.length(); i++) {
entry = grantsJson.getJSONObject(i);
powerGrant = new PowerGrant();
powerGrant.power_type = entry.getString("power_type");
powerGrant.power_value = entry.getInt("power_value");
powerGrant.power_granted_attrs = entry.getJSONArray("power_granted_attrs");
powerGrant.power_granted_skills.addAll(readIntArrays(entry.getJSONArray("power_granted_skills")));
powerGrant.power_granted_powers.addAll(readIntArrays(entry.getJSONArray("power_granted_powers")));
powerGrant.power_monster_types = entry.getJSONArray("power_monster_types");
powerGrants.add(powerGrant);
}
return powerGrants;
}
// [{power_type: "X", power_actions: [{power_arguments: [a, b]}, ...]}, ...]
// -> power_type -> list of argument arrays (one per power_actions entry)
public static LinkedHashMap<String, ArrayList<int[]>> readPowerActions(JSONArray actionsJson) {
LinkedHashMap<String, ArrayList<int[]>> powerActions = new LinkedHashMap<>();
JSONObject entry;
JSONArray argumentsJson;
ArrayList<int[]> arguments;
for (int i = 0; i < actionsJson.length(); i++) {
entry = actionsJson.getJSONObject(i);
argumentsJson = entry.getJSONArray("power_actions");
arguments = new ArrayList<>();
for (int j = 0; j < argumentsJson.length(); j++)
arguments.add(readIntArray(argumentsJson.getJSONObject(j).getJSONArray("power_arguments")));
powerActions.put(entry.getString("power_type"), arguments);
}
return powerActions;
}
}
-179
View File
@@ -1,179 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.parsers.cache;
import engine.gameManager.ConfigManager;
import engine.mbEnums;
import engine.parsers.objects.DeedTemplate;
import org.json.JSONArray;
import org.json.JSONObject;
import org.pmw.tinylog.Logger;
import java.io.File;
import java.util.HashMap;
// Loads DEED templates from the client cache JSON (COBJECTS/DEED/<id>.json).
// Not yet wired into server startup.
public class DeedParser {
private static final String deedPath = ConfigManager.DEFAULT_DATA_DIR + "COBJECTS/DEED/";
public static HashMap<Integer, DeedTemplate> parseDeedFolder() {
HashMap<Integer, DeedTemplate> deedTemplates = new HashMap<>();
File[] deedFiles = CacheParserUtil.listJsonFiles(deedPath);
int templateId;
JSONObject deedJson;
for (File deedFile : deedFiles) {
try {
templateId = CacheParserUtil.templateIdFromFile(deedFile);
deedJson = CacheParserUtil.readJsonFile(deedFile);
deedTemplates.put(templateId, parseDeedEntry(templateId, deedJson));
} catch (Exception e) {
Logger.error(deedFile.getName() + ": " + e);
}
}
Logger.info("Loaded " + deedTemplates.size() + " of " + deedFiles.length + " deed templates");
return deedTemplates;
}
private static DeedTemplate parseDeedEntry(int templateId, JSONObject deedJson) {
DeedTemplate deed = new DeedTemplate();
JSONObject raceReq;
JSONObject classReq;
JSONObject discReq;
JSONArray itemFlags;
String flag;
mbEnums.ItemFlags itemFlag;
deed.template_id = templateId;
// obj_
deed.obj_name = deedJson.getString("obj_name");
deed.obj_pickable = deedJson.getBoolean("obj_pickable");
deed.obj_gravity = deedJson.getFloat("obj_gravity");
deed.obj_cull_distance = deedJson.getFloat("obj_cull_distance");
deed.obj_scale = CacheParserUtil.readVector3(deedJson.getJSONArray("obj_scale"));
deed.obj_render_object = deedJson.getInt("obj_render_object");
deed.obj_double_fusion = deedJson.getBoolean("obj_double_fusion");
deed.obj_forward_vector = CacheParserUtil.readVector3(deedJson.getJSONArray("obj_forward_vector"));
deed.obj_tracking_name = deedJson.getString("obj_tracking_name");
deed.obj_max_tracking_distance = deedJson.getFloat("obj_max_tracking_distance");
deed.obj_icon = deedJson.getInt("obj_icon");
deed.obj_gravity_f = deedJson.getFloat("obj_gravity_f");
deed.obj_sound_events.putAll(CacheParserUtil.readStringValueMap(deedJson.getJSONArray("obj_sound_events"), "sound_type", "sound_event"));
deed.obj_arc_hardpoint_list = deedJson.getJSONArray("obj_arc_hardpoint_list");
deed.obj_sparse_data.putAll(CacheParserUtil.readSparseData(deedJson.getJSONObject("obj_sparse_data")));
deed.obj_render_object_low_detail = deedJson.getInt("obj_render_object_low_detail");
deed.obj_default_alignment = CacheParserUtil.readVector3(deedJson.getJSONArray("obj_default_alignment"));
deed.obj_sound_table = CacheParserUtil.readLabel(deedJson, "obj_sound_table");
// combat_
deed.combat_health_current = deedJson.getFloat("combat_health_current");
deed.combat_health_full = deedJson.getFloat("combat_health_full");
deed.combat_attack_resist.putAll(CacheParserUtil.readEnumFloatMap(mbEnums.DamageType.class, deedJson.getJSONObject("combat_attack_resist"),
templateId, "combat_attack_resist"));
deed.combat_powers = deedJson.getJSONArray("combat_powers");
// item_
deed.item_type = CacheParserUtil.readEnum(mbEnums.ItemType.class, deedJson.getString("item_type"), templateId, "item_type");
deed.item_eq_slots_value = deedJson.getInt("item_eq_slots_value");
deed.item_eq_slots_type = deedJson.getBoolean("item_eq_slots_type");
deed.item_eq_slots_or.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, deedJson.getJSONArray("item_eq_slots_or"), templateId, "item_eq_slots_or"));
deed.item_eq_slots_and.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, deedJson.getJSONArray("item_eq_slots_and"), templateId, "item_eq_slots_and"));
deed.item_takeable = deedJson.getBoolean("item_takeable");
deed.item_value = deedJson.getInt("item_value");
deed.item_wt = deedJson.getInt("item_wt");
deed.item_passive_defense_mod = deedJson.getFloat("item_passive_defense_mod");
deed.item_base_name = deedJson.getString("item_base_name");
deed.item_dsc = deedJson.getString("item_dsc");
deed.item_render_object_female = deedJson.getInt("item_render_object_female");
deed.item_health_full = deedJson.getFloat("item_health_full");
deed.item_skill_used = CacheParserUtil.readLabel(deedJson, "item_skill_used");
deed.item_skill_mastery_used = CacheParserUtil.readLabel(deedJson, "item_skill_mastery_used");
deed.item_parry_anim_id = deedJson.getInt("item_parry_anim_id");
deed.item_offering_info.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ShrineType.class, deedJson.getJSONArray("item_offering_info"),
"offering_type", "offering_value", templateId, "item_offering_info"));
// "None" is the client's empty marker, not a flag
itemFlags = deedJson.getJSONArray("item_flags");
for (int i = 0; i < itemFlags.length(); i++) {
flag = itemFlags.getString(i);
if (flag.equals("None"))
continue;
itemFlag = CacheParserUtil.readEnum(mbEnums.ItemFlags.class, flag, templateId, "item_flags");
if (itemFlag != null)
deed.item_flags.add(itemFlag);
}
deed.item_use_flags.addAll(CacheParserUtil.readEnumSet(mbEnums.ItemUseFlags.class, deedJson.getJSONArray("item_use_flags"), templateId, "item_use_flags"));
deed.item_post_item_id = deedJson.getInt("item_post_item_id");
deed.item_initial_charges = deedJson.getInt("item_initial_charges");
deed.item_book_arcana = deedJson.getInt("item_book_arcana");
deed.item_skill_req.putAll(CacheParserUtil.readStringValueMap(deedJson.getJSONArray("item_skill_req"), "skill_type", "skill_level"));
raceReq = deedJson.getJSONObject("item_race_req");
deed.item_race_req_restrict = raceReq.getBoolean("restrict");
deed.item_race_req.addAll(CacheParserUtil.readEnumSet(mbEnums.MonsterType.class, raceReq.getJSONArray("races"), templateId, "item_race_req"));
classReq = deedJson.getJSONObject("item_class_req");
deed.item_class_req_restrict = classReq.getBoolean("restrict");
deed.item_class_req.addAll(CacheParserUtil.readEnumSet(mbEnums.ClassType.class, classReq.getJSONArray("classes"), templateId, "item_class_req"));
discReq = deedJson.getJSONObject("item_disc_req");
deed.item_disc_req_restrict = discReq.getBoolean("restrict");
deed.item_disc_req.addAll(CacheParserUtil.readEnumSet(mbEnums.DisciplineType.class, discReq.getJSONArray("discs"), templateId, "item_disc_req"));
deed.item_attr_req.putAll(CacheParserUtil.readEnumValueMap(mbEnums.AttributeType.class, deedJson.getJSONArray("item_attr_req"),
"attr_type", "attr_value", templateId, "item_attr_req"));
deed.item_level_req = deedJson.getInt("item_level_req");
deed.item_rank_req = deedJson.getInt("item_rank_req");
deed.item_sex_req = CacheParserUtil.readEnum(mbEnums.SexType.class, deedJson.getString("item_sex_req"), templateId, "item_sex_req");
deed.item_user_power_action.addAll(CacheParserUtil.readUserPowerActions(deedJson.getJSONArray("item_user_power_action")));
deed.item_power_grant.addAll(CacheParserUtil.readPowerGrants(deedJson.getJSONArray("item_power_grant")));
deed.item_power_action.putAll(CacheParserUtil.readPowerActions(deedJson.getJSONArray("item_power_action")));
deed.item_sheathable = deedJson.getBoolean("item_sheathable");
deed.item_has_stub = deedJson.getBoolean("item_has_stub");
deed.item_offering_adjustments.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ShrineType.class, deedJson.getJSONArray("item_offering_adjustments"),
"offering_type", "offering_value", templateId, "item_offering_adjustments"));
deed.item_resource_costs.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ResourceType.class, deedJson.getJSONArray("item_resource_costs"),
"resource_type", "resource_value", templateId, "item_resource_costs"));
deed.item_bane_rank = deedJson.getInt("item_bane_rank");
deed.item_ignore_saved_actions = deedJson.getBoolean("item_ignore_saved_actions");
// deed_
deed.deed_type = deedJson.getInt("deed_type");
deed.deed_furniture_id = deedJson.getInt("deed_furniture_id");
deed.deed_target_id = deedJson.getInt("deed_target_id");
deed.deed_employment = deedJson.getInt("deed_employment");
deed.deed_start_rank = deedJson.getInt("deed_start_rank");
deed.deed_name_lookup = deedJson.getInt("deed_name_lookup");
deed.deed_indoors = deedJson.getBoolean("deed_indoors");
deed.deed_is_fortress = deedJson.getBoolean("deed_is_fortress");
deed.deed_namelookup_val = deedJson.getFloat("deed_namelookup_val");
deed.deed_custom_city = deedJson.getBoolean("deed_custom_city");
deed.deed_structure_id = deedJson.getInt("deed_structure_id");
return deed;
}
}
-333
View File
@@ -1,333 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.parsers.cache;
import engine.gameManager.ConfigManager;
import engine.mbEnums;
import engine.parsers.objects.RuneTemplate;
import org.json.JSONArray;
import org.json.JSONObject;
import org.pmw.tinylog.Logger;
import java.io.File;
import java.util.HashMap;
// Loads RUNE templates from the client cache JSON (COBJECTS/RUNE/<id>.json).
// Not yet wired into server startup.
public class RuneParser {
private static final String runePath = ConfigManager.DEFAULT_DATA_DIR + "COBJECTS/RUNE/";
public static HashMap<Integer, RuneTemplate> parseRuneFolder() {
HashMap<Integer, RuneTemplate> runeTemplates = new HashMap<>();
File[] runeFiles = CacheParserUtil.listJsonFiles(runePath);
int templateId;
JSONObject runeJson;
for (File runeFile : runeFiles) {
try {
templateId = CacheParserUtil.templateIdFromFile(runeFile);
runeJson = CacheParserUtil.readJsonFile(runeFile);
runeTemplates.put(templateId, parseRuneEntry(templateId, runeJson));
} catch (Exception e) {
Logger.error(runeFile.getName() + ": " + e);
}
}
Logger.info("Loaded " + runeTemplates.size() + " of " + runeFiles.length + " rune templates");
return runeTemplates;
}
private static RuneTemplate parseRuneEntry(int templateId, JSONObject runeJson) {
RuneTemplate rune = new RuneTemplate();
JSONObject raceReq;
JSONObject classReq;
JSONObject discReq;
JSONArray itemFlags;
String flag;
mbEnums.ItemFlags itemFlag;
Object subType;
JSONObject speedJson;
mbEnums.MovementType movementType;
JSONObject groupJson;
JSONArray skillGrantsJson;
JSONObject skillGrantJson;
RuneTemplate.SkillGrant skillGrant;
JSONArray skillAdjJson;
JSONObject skillAdjEntry;
JSONArray naturalAttacksJson;
JSONArray inventoryJson;
JSONObject inventoryEntryJson;
RuneTemplate.InventoryEntry inventoryEntry;
JSONArray bodyPartsJson;
JSONObject bodyPartJson;
RuneTemplate.BodyPart bodyPart;
rune.template_id = templateId;
// obj_
rune.obj_name = runeJson.getString("obj_name");
rune.obj_pickable = runeJson.getBoolean("obj_pickable");
rune.obj_gravity = runeJson.getFloat("obj_gravity");
rune.obj_cull_distance = runeJson.getFloat("obj_cull_distance");
rune.obj_scale = CacheParserUtil.readVector3(runeJson.getJSONArray("obj_scale"));
rune.obj_render_object = runeJson.getInt("obj_render_object");
rune.obj_double_fusion = runeJson.getBoolean("obj_double_fusion");
rune.obj_forward_vector = CacheParserUtil.readVector3(runeJson.getJSONArray("obj_forward_vector"));
rune.obj_tracking_name = runeJson.getString("obj_tracking_name");
rune.obj_max_tracking_distance = runeJson.getFloat("obj_max_tracking_distance");
rune.obj_icon = runeJson.getInt("obj_icon");
rune.obj_gravity_f = runeJson.getFloat("obj_gravity_f");
rune.obj_sound_events.putAll(CacheParserUtil.readStringValueMap(runeJson.getJSONArray("obj_sound_events"), "sound_type", "sound_event"));
rune.obj_arc_hardpoint_list = runeJson.getJSONArray("obj_arc_hardpoint_list");
rune.obj_sparse_data.putAll(CacheParserUtil.readSparseData(runeJson.getJSONObject("obj_sparse_data")));
rune.obj_render_object_low_detail = runeJson.getInt("obj_render_object_low_detail");
rune.obj_default_alignment = CacheParserUtil.readVector3(runeJson.getJSONArray("obj_default_alignment"));
rune.obj_sound_table = CacheParserUtil.readLabel(runeJson, "obj_sound_table");
// combat_
rune.combat_health_current = runeJson.getFloat("combat_health_current");
rune.combat_health_full = runeJson.getFloat("combat_health_full");
rune.combat_attack_resist.putAll(CacheParserUtil.readEnumFloatMap(mbEnums.DamageType.class, runeJson.getJSONObject("combat_attack_resist"),
templateId, "combat_attack_resist"));
rune.combat_powers = runeJson.getJSONArray("combat_powers");
// item_
rune.item_type = CacheParserUtil.readEnum(mbEnums.ItemType.class, runeJson.getString("item_type"), templateId, "item_type");
rune.item_eq_slots_value = runeJson.getInt("item_eq_slots_value");
rune.item_eq_slots_type = runeJson.getBoolean("item_eq_slots_type");
rune.item_eq_slots_or.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, runeJson.getJSONArray("item_eq_slots_or"), templateId, "item_eq_slots_or"));
rune.item_eq_slots_and.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, runeJson.getJSONArray("item_eq_slots_and"), templateId, "item_eq_slots_and"));
rune.item_takeable = runeJson.getBoolean("item_takeable");
rune.item_value = runeJson.getInt("item_value");
rune.item_wt = runeJson.getInt("item_wt");
rune.item_passive_defense_mod = runeJson.getFloat("item_passive_defense_mod");
rune.item_base_name = runeJson.getString("item_base_name");
rune.item_dsc = runeJson.getString("item_dsc");
rune.item_render_object_female = runeJson.getInt("item_render_object_female");
rune.item_health_full = runeJson.getFloat("item_health_full");
rune.item_skill_used = CacheParserUtil.readLabel(runeJson, "item_skill_used");
rune.item_skill_mastery_used = CacheParserUtil.readLabel(runeJson, "item_skill_mastery_used");
rune.item_parry_anim_id = runeJson.getInt("item_parry_anim_id");
rune.item_offering_info.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ShrineType.class, runeJson.getJSONArray("item_offering_info"),
"offering_type", "offering_value", templateId, "item_offering_info"));
// "None" is the client's empty marker, not a flag
itemFlags = runeJson.getJSONArray("item_flags");
for (int i = 0; i < itemFlags.length(); i++) {
flag = itemFlags.getString(i);
if (flag.equals("None"))
continue;
itemFlag = CacheParserUtil.readEnum(mbEnums.ItemFlags.class, flag, templateId, "item_flags");
if (itemFlag != null)
rune.item_flags.add(itemFlag);
}
rune.item_use_flags.addAll(CacheParserUtil.readEnumSet(mbEnums.ItemUseFlags.class, runeJson.getJSONArray("item_use_flags"), templateId, "item_use_flags"));
rune.item_post_item_id = runeJson.getInt("item_post_item_id");
rune.item_initial_charges = runeJson.getInt("item_initial_charges");
rune.item_book_arcana = runeJson.getInt("item_book_arcana");
rune.item_skill_req.putAll(CacheParserUtil.readStringValueMap(runeJson.getJSONArray("item_skill_req"), "skill_type", "skill_level"));
raceReq = runeJson.getJSONObject("item_race_req");
rune.item_race_req_restrict = raceReq.getBoolean("restrict");
rune.item_race_req.addAll(CacheParserUtil.readEnumSet(mbEnums.MonsterType.class, raceReq.getJSONArray("races"), templateId, "item_race_req"));
classReq = runeJson.getJSONObject("item_class_req");
rune.item_class_req_restrict = classReq.getBoolean("restrict");
rune.item_class_req.addAll(CacheParserUtil.readEnumSet(mbEnums.ClassType.class, classReq.getJSONArray("classes"), templateId, "item_class_req"));
discReq = runeJson.getJSONObject("item_disc_req");
rune.item_disc_req_restrict = discReq.getBoolean("restrict");
rune.item_disc_req.addAll(CacheParserUtil.readEnumSet(mbEnums.DisciplineType.class, discReq.getJSONArray("discs"), templateId, "item_disc_req"));
rune.item_attr_req.putAll(CacheParserUtil.readEnumValueMap(mbEnums.AttributeType.class, runeJson.getJSONArray("item_attr_req"),
"attr_type", "attr_value", templateId, "item_attr_req"));
rune.item_level_req = runeJson.getInt("item_level_req");
rune.item_rank_req = runeJson.getInt("item_rank_req");
rune.item_sex_req = CacheParserUtil.readEnum(mbEnums.SexType.class, runeJson.getString("item_sex_req"), templateId, "item_sex_req");
rune.item_user_power_action.addAll(CacheParserUtil.readUserPowerActions(runeJson.getJSONArray("item_user_power_action")));
rune.item_power_grant.addAll(CacheParserUtil.readPowerGrants(runeJson.getJSONArray("item_power_grant")));
rune.item_power_action.putAll(CacheParserUtil.readPowerActions(runeJson.getJSONArray("item_power_action")));
rune.item_sheathable = runeJson.getBoolean("item_sheathable");
rune.item_has_stub = runeJson.getBoolean("item_has_stub");
rune.item_offering_adjustments.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ShrineType.class, runeJson.getJSONArray("item_offering_adjustments"),
"offering_type", "offering_value", templateId, "item_offering_adjustments"));
rune.item_resource_costs.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ResourceType.class, runeJson.getJSONArray("item_resource_costs"),
"resource_type", "resource_value", templateId, "item_resource_costs"));
rune.item_bane_rank = runeJson.getInt("item_bane_rank");
rune.item_ignore_saved_actions = runeJson.getBoolean("item_ignore_saved_actions");
// rune_
rune.rune_type = CacheParserUtil.readEnum(mbEnums.RuneType.class, runeJson.getString("rune_type"), templateId, "rune_type");
subType = runeJson.get("rune_sub_type");
if (subType instanceof String) {
rune.rune_sub_type = (String) subType;
} else {
rune.rune_sub_type = "";
rune.rune_sub_type_hash = (int) runeJson.getLong("rune_sub_type");
}
rune.rune_is_standard_character_creation = runeJson.getBoolean("rune_is_standard_character_creation");
rune.rune_creation_cost = runeJson.getInt("rune_creation_cost");
rune.rune_rank = runeJson.getInt("rune_rank");
rune.rune_pracs_per_level = runeJson.getInt("rune_pracs_per_level");
rune.rune_exp_req_to_level = runeJson.getFloat("rune_exp_req_to_level");
rune.rune_sex = CacheParserUtil.readEnum(mbEnums.SexType.class, runeJson.getString("rune_sex"), templateId, "rune_sex");
rune.rune_class_icon = runeJson.getInt("rune_class_icon");
rune.rune_health = runeJson.getInt("rune_health");
rune.rune_mana = runeJson.getInt("rune_mana");
rune.rune_stamina = runeJson.getInt("rune_stamina");
rune.rune_min_damage = runeJson.getFloat("rune_min_damage");
rune.rune_max_damage = runeJson.getFloat("rune_max_damage");
rune.rune_attack = runeJson.getInt("rune_attack");
rune.rune_defense = runeJson.getInt("rune_defense");
rune.rune_level = runeJson.getInt("rune_level");
speedJson = runeJson.getJSONObject("rune_speed");
for (String speedKey : speedJson.keySet()) {
movementType = CacheParserUtil.readEnum(mbEnums.MovementType.class, speedKey, templateId, "rune_speed");
if (movementType != null)
rune.rune_speed.put(movementType, speedJson.getFloat(speedKey));
}
groupJson = runeJson.getJSONObject("rune_group");
rune.rune_group_type = groupJson.getInt("group_type");
rune.rune_group_is_faction = groupJson.getBoolean("group_is_faction");
rune.rune_group_is_guild = groupJson.getBoolean("group_is_guild");
rune.rune_dsc = runeJson.getString("rune_dsc");
rune.rune_fx_txt = runeJson.getString("rune_fx_txt");
rune.rune_group_tactics = runeJson.getLong("rune_group_tactics");
rune.rune_group_role_set = runeJson.getLong("rune_group_role_set");
rune.rune_enemy_monster_types.addAll(CacheParserUtil.readEnumSet(mbEnums.MonsterType.class, runeJson.getJSONArray("rune_enemy_monster_types"),
templateId, "rune_enemy_monster_types"));
rune.rune_groupee_monster_types.addAll(CacheParserUtil.readIntList(runeJson.getJSONArray("rune_groupee_monster_types")));
rune.rune_helper_monster_types.addAll(CacheParserUtil.readIntList(runeJson.getJSONArray("rune_helper_monster_types")));
rune.rune_not_enemy_monster_types.addAll(CacheParserUtil.readEnumSet(mbEnums.MonsterType.class, runeJson.getJSONArray("rune_not_enemy_monster_types"),
templateId, "rune_not_enemy_monster_types"));
rune.rune_enemy_gender = runeJson.getJSONArray("rune_enemy_gender");
skillGrantsJson = runeJson.getJSONArray("rune_skill_grant");
for (int i = 0; i < skillGrantsJson.length(); i++) {
skillGrantJson = skillGrantsJson.getJSONObject(i);
skillGrant = new RuneTemplate.SkillGrant();
skillGrant.skill_type = skillGrantJson.getString("skill_type");
skillGrant.skill_value = skillGrantJson.getInt("skill_value");
skillGrant.skill_granted_attrs = skillGrantJson.getJSONArray("skill_granted_attrs");
skillGrant.skill_granted_skills.addAll(CacheParserUtil.readIntArrays(skillGrantJson.getJSONArray("skill_granted_skills")));
skillGrant.skill_granted_powers = skillGrantJson.getJSONArray("skill_granted_powers");
skillGrant.skill_monster_types = skillGrantJson.getJSONArray("skill_monster_types");
rune.rune_skill_grant.add(skillGrant);
}
skillAdjJson = runeJson.getJSONArray("rune_skill_adj");
for (int i = 0; i < skillAdjJson.length(); i++) {
skillAdjEntry = skillAdjJson.getJSONObject(i);
rune.rune_skill_adj.put(skillAdjEntry.getString("skill_type"),
CacheParserUtil.readIntArrays(skillAdjEntry.getJSONArray("skill_adjusts")));
}
rune.rune_attr_adj.putAll(CacheParserUtil.readEnumValueMap(mbEnums.AttributeType.class, runeJson.getJSONArray("rune_attr_adj"),
"attr_type", "attr_value", templateId, "rune_attr_adj"));
rune.rune_max_attr_adj.putAll(CacheParserUtil.readEnumValueMap(mbEnums.AttributeType.class, runeJson.getJSONArray("rune_max_attr_adj"),
"attr_type", "attr_value", templateId, "rune_max_attr_adj"));
naturalAttacksJson = runeJson.getJSONArray("rune_naturalattacks");
for (int i = 0; i < naturalAttacksJson.length(); i++)
rune.rune_naturalattacks.add(CacheParserUtil.readFloatArray(naturalAttacksJson.getJSONArray(i)));
rune.rune_enchantment_type = runeJson.getJSONArray("rune_enchantment_type");
inventoryJson = runeJson.getJSONArray("rune_inventory_contents");
for (int i = 0; i < inventoryJson.length(); i++) {
inventoryEntryJson = inventoryJson.getJSONObject(i);
inventoryEntry = new RuneTemplate.InventoryEntry();
inventoryEntry.type = inventoryEntryJson.getString("type");
if (inventoryEntryJson.has("gold"))
inventoryEntry.values = CacheParserUtil.readFloatArray(inventoryEntryJson.getJSONArray("gold"));
else if (inventoryEntryJson.has("table"))
inventoryEntry.values = CacheParserUtil.readFloatArray(inventoryEntryJson.getJSONArray("table"));
else
Logger.error(templateId + ": rune_inventory_contents entry of type " + inventoryEntry.type + " has no values");
rune.rune_inventory_contents.add(inventoryEntry);
}
rune.rune_renderable = runeJson.getBoolean("rune_renderable");
// Render fields are absent on some runes
if (runeJson.has("rune_scale_factor"))
rune.rune_scale_factor = CacheParserUtil.readVector3(runeJson.getJSONArray("rune_scale_factor"));
if (runeJson.has("rune_skeleton"))
rune.rune_skeleton = runeJson.getInt("rune_skeleton");
if (runeJson.has("rune_slope_hugger"))
rune.rune_slope_hugger = runeJson.getBoolean("rune_slope_hugger");
if (runeJson.has("rune_can_fly"))
rune.rune_can_fly = runeJson.getBoolean("rune_can_fly");
if (runeJson.has("rune_death_effect"))
rune.rune_death_effect = runeJson.getInt("rune_death_effect");
if (runeJson.has("rune_tombstone_id"))
rune.rune_tombstone_id = runeJson.getInt("rune_tombstone_id");
if (runeJson.has("rune_body_parts")) {
bodyPartsJson = runeJson.getJSONArray("rune_body_parts");
for (int i = 0; i < bodyPartsJson.length(); i++) {
bodyPartJson = bodyPartsJson.getJSONObject(i);
bodyPart = new RuneTemplate.BodyPart();
bodyPart.body_part_render = bodyPartJson.getInt("body_part_render");
bodyPart.body_part_position = CacheParserUtil.readVector3(bodyPartJson.getJSONArray("body_part_position"));
rune.rune_body_parts.add(bodyPart);
}
}
if (runeJson.has("rune_hair"))
rune.rune_hair.addAll(CacheParserUtil.readIntList(runeJson.getJSONArray("rune_hair")));
if (runeJson.has("rune_beard"))
rune.rune_beard.addAll(CacheParserUtil.readIntList(runeJson.getJSONArray("rune_beard")));
rune.rune_natural_power_attack = runeJson.getInt("rune_natural_power_attack");
rune.rune_sparse_data.putAll(CacheParserUtil.readSparseData(runeJson.getJSONObject("rune_sparse_data")));
return rune;
}
}
@@ -1,120 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.parsers.objects;
import engine.math.Vector3fImmutable;
import engine.mbEnums;
import org.json.JSONArray;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
// Deed template as defined by the client's cache data
// (MBDATA/data/COBJECTS/DEED). Field names match the JSON keys.
//
// Values are kept as the client defines them: no req/res splitting,
// no defaults substituted. Strings with a matching enum in mbEnums
// are stored as that enum; everything else stays a String.
//
// Read only once loaded.
public class DeedTemplate {
public int template_id;
// obj_
public String obj_name;
public boolean obj_pickable;
public float obj_gravity;
public float obj_cull_distance;
public Vector3fImmutable obj_scale;
public int obj_render_object;
public boolean obj_double_fusion;
public Vector3fImmutable obj_forward_vector;
public String obj_tracking_name;
public float obj_max_tracking_distance;
public int obj_icon;
public float obj_gravity_f;
public final LinkedHashMap<String, Integer> obj_sound_events = new LinkedHashMap<>();
public JSONArray obj_arc_hardpoint_list;
public final HashMap<String, String> obj_sparse_data = new HashMap<>();
public int obj_render_object_low_detail;
public Vector3fImmutable obj_default_alignment;
public String obj_sound_table;
// combat_
public float combat_health_current;
public float combat_health_full;
public final EnumMap<mbEnums.DamageType, Float> combat_attack_resist = new EnumMap<>(mbEnums.DamageType.class);
public JSONArray combat_powers;
// item_
public mbEnums.ItemType item_type;
public int item_eq_slots_value;
public boolean item_eq_slots_type;
public final EnumSet<mbEnums.EquipSlotType> item_eq_slots_or = EnumSet.noneOf(mbEnums.EquipSlotType.class);
public final EnumSet<mbEnums.EquipSlotType> item_eq_slots_and = EnumSet.noneOf(mbEnums.EquipSlotType.class);
public boolean item_takeable;
public int item_value;
public int item_wt;
public float item_passive_defense_mod;
public String item_base_name;
public String item_dsc;
public int item_render_object_female;
public float item_health_full;
public String item_skill_used;
public String item_skill_mastery_used;
public int item_parry_anim_id;
public final EnumMap<mbEnums.ShrineType, Integer> item_offering_info = new EnumMap<>(mbEnums.ShrineType.class);
public final EnumSet<mbEnums.ItemFlags> item_flags = EnumSet.noneOf(mbEnums.ItemFlags.class);
public final EnumSet<mbEnums.ItemUseFlags> item_use_flags = EnumSet.noneOf(mbEnums.ItemUseFlags.class);
public int item_post_item_id;
public int item_initial_charges;
public int item_book_arcana;
public final LinkedHashMap<String, Integer> item_skill_req = new LinkedHashMap<>();
public boolean item_race_req_restrict;
public final EnumSet<mbEnums.MonsterType> item_race_req = EnumSet.noneOf(mbEnums.MonsterType.class);
public boolean item_class_req_restrict;
public final EnumSet<mbEnums.ClassType> item_class_req = EnumSet.noneOf(mbEnums.ClassType.class);
public boolean item_disc_req_restrict;
public final EnumSet<mbEnums.DisciplineType> item_disc_req = EnumSet.noneOf(mbEnums.DisciplineType.class);
public final EnumMap<mbEnums.AttributeType, Integer> item_attr_req = new EnumMap<>(mbEnums.AttributeType.class);
public int item_level_req;
public int item_rank_req;
public mbEnums.SexType item_sex_req;
public final ArrayList<UserPowerAction> item_user_power_action = new ArrayList<>();
public final ArrayList<PowerGrant> item_power_grant = new ArrayList<>();
public final LinkedHashMap<String, ArrayList<int[]>> item_power_action = new LinkedHashMap<>();
public boolean item_sheathable;
public boolean item_has_stub;
public final EnumMap<mbEnums.ShrineType, Integer> item_offering_adjustments = new EnumMap<>(mbEnums.ShrineType.class);
public final EnumMap<mbEnums.ResourceType, Integer> item_resource_costs = new EnumMap<>(mbEnums.ResourceType.class);
public int item_bane_rank;
public boolean item_ignore_saved_actions;
// deed_
public int deed_type;
public int deed_furniture_id;
public int deed_target_id;
public int deed_employment;
public int deed_start_rank;
public int deed_name_lookup;
public boolean deed_indoors;
public boolean deed_is_fortress;
public float deed_namelookup_val;
public boolean deed_custom_city;
public int deed_structure_id;
}
@@ -1,33 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.parsers.objects;
import org.json.JSONArray;
import java.util.ArrayList;
// One entry of item_power_grant.
//
// power_granted_skills and power_granted_powers entries look like
// [hash, value] pairs (first element is a 32-bit string hash, some
// exceed Integer.MAX_VALUE in the JSON and are stored wrapped to int).
// This reading is from the data only and has not been confirmed in the client.
//
// power_granted_attrs and power_monster_types are empty in every DEED and
// RUNE file, so their shape is unknown and they are kept as raw JSON.
public class PowerGrant {
public String power_type;
public int power_value;
public JSONArray power_granted_attrs;
public final ArrayList<int[]> power_granted_skills = new ArrayList<>();
public final ArrayList<int[]> power_granted_powers = new ArrayList<>();
public JSONArray power_monster_types;
}
@@ -1,225 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.parsers.objects;
import engine.math.Vector3fImmutable;
import engine.mbEnums;
import org.json.JSONArray;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
// Rune template as defined by the client's cache data
// (MBDATA/data/COBJECTS/RUNE). Field names match the JSON keys.
//
// Covers every rune the client knows about: player races, classes,
// disciplines, talents and mob/pet/npc runes alike.
//
// Values are kept as the client defines them: no req/res splitting,
// no defaults substituted. Strings with a matching enum in mbEnums
// are stored as that enum; everything else stays a String.
//
// Read only once loaded.
public class RuneTemplate {
public int template_id;
// obj_
public String obj_name;
public boolean obj_pickable;
public float obj_gravity;
public float obj_cull_distance;
public Vector3fImmutable obj_scale;
public int obj_render_object;
public boolean obj_double_fusion;
public Vector3fImmutable obj_forward_vector;
public String obj_tracking_name;
public float obj_max_tracking_distance;
public int obj_icon;
public float obj_gravity_f;
public final LinkedHashMap<String, Integer> obj_sound_events = new LinkedHashMap<>();
public JSONArray obj_arc_hardpoint_list;
public final HashMap<String, String> obj_sparse_data = new HashMap<>();
public int obj_render_object_low_detail;
public Vector3fImmutable obj_default_alignment;
public String obj_sound_table;
// combat_
public float combat_health_current;
public float combat_health_full;
public final EnumMap<mbEnums.DamageType, Float> combat_attack_resist = new EnumMap<>(mbEnums.DamageType.class);
public JSONArray combat_powers;
// item_
public mbEnums.ItemType item_type;
public int item_eq_slots_value;
public boolean item_eq_slots_type;
public final EnumSet<mbEnums.EquipSlotType> item_eq_slots_or = EnumSet.noneOf(mbEnums.EquipSlotType.class);
public final EnumSet<mbEnums.EquipSlotType> item_eq_slots_and = EnumSet.noneOf(mbEnums.EquipSlotType.class);
public boolean item_takeable;
public int item_value;
public int item_wt;
public float item_passive_defense_mod;
public String item_base_name;
public String item_dsc;
public int item_render_object_female;
public float item_health_full;
public String item_skill_used;
public String item_skill_mastery_used;
public int item_parry_anim_id;
public final EnumMap<mbEnums.ShrineType, Integer> item_offering_info = new EnumMap<>(mbEnums.ShrineType.class);
public final EnumSet<mbEnums.ItemFlags> item_flags = EnumSet.noneOf(mbEnums.ItemFlags.class);
public final EnumSet<mbEnums.ItemUseFlags> item_use_flags = EnumSet.noneOf(mbEnums.ItemUseFlags.class);
public int item_post_item_id;
public int item_initial_charges;
public int item_book_arcana;
public final LinkedHashMap<String, Integer> item_skill_req = new LinkedHashMap<>();
public boolean item_race_req_restrict;
public final EnumSet<mbEnums.MonsterType> item_race_req = EnumSet.noneOf(mbEnums.MonsterType.class);
public boolean item_class_req_restrict;
public final EnumSet<mbEnums.ClassType> item_class_req = EnumSet.noneOf(mbEnums.ClassType.class);
public boolean item_disc_req_restrict;
public final EnumSet<mbEnums.DisciplineType> item_disc_req = EnumSet.noneOf(mbEnums.DisciplineType.class);
public final EnumMap<mbEnums.AttributeType, Integer> item_attr_req = new EnumMap<>(mbEnums.AttributeType.class);
public int item_level_req;
public int item_rank_req;
public mbEnums.SexType item_sex_req;
public final ArrayList<UserPowerAction> item_user_power_action = new ArrayList<>();
public final ArrayList<PowerGrant> item_power_grant = new ArrayList<>();
public final LinkedHashMap<String, ArrayList<int[]>> item_power_action = new LinkedHashMap<>();
public boolean item_sheathable;
public boolean item_has_stub;
public final EnumMap<mbEnums.ShrineType, Integer> item_offering_adjustments = new EnumMap<>(mbEnums.ShrineType.class);
public final EnumMap<mbEnums.ResourceType, Integer> item_resource_costs = new EnumMap<>(mbEnums.ResourceType.class);
public int item_bane_rank;
public boolean item_ignore_saved_actions;
// rune_
public mbEnums.RuneType rune_type;
public String rune_sub_type;
// A handful of runes carry a number instead of a name in rune_sub_type.
// These look like string hashes the cache converter could not resolve.
// Stored here (wrapped to int) with rune_sub_type left empty.
public int rune_sub_type_hash;
public boolean rune_is_standard_character_creation;
public int rune_creation_cost;
public int rune_rank;
public int rune_pracs_per_level;
public float rune_exp_req_to_level;
public mbEnums.SexType rune_sex;
public int rune_class_icon;
public int rune_health;
public int rune_mana;
public int rune_stamina;
public float rune_min_damage;
public float rune_max_damage;
public int rune_attack;
public int rune_defense;
public int rune_level;
public final EnumMap<mbEnums.MovementType, Float> rune_speed = new EnumMap<>(mbEnums.MovementType.class);
public int rune_group_type;
public boolean rune_group_is_faction;
public boolean rune_group_is_guild;
public String rune_dsc;
public String rune_fx_txt;
// Bit vectors. The existing ItemTemplate decodes these as MobBehaviourType.
public long rune_group_tactics;
public long rune_group_role_set;
public final EnumSet<mbEnums.MonsterType> rune_enemy_monster_types = EnumSet.noneOf(mbEnums.MonsterType.class);
public final ArrayList<Integer> rune_groupee_monster_types = new ArrayList<>();
public final ArrayList<Integer> rune_helper_monster_types = new ArrayList<>();
public final EnumSet<mbEnums.MonsterType> rune_not_enemy_monster_types = EnumSet.noneOf(mbEnums.MonsterType.class);
// Empty in every RUNE file; shape unknown.
public JSONArray rune_enemy_gender;
public final ArrayList<SkillGrant> rune_skill_grant = new ArrayList<>();
// skill_type -> list of [value, value] pairs, in file order.
public final LinkedHashMap<String, ArrayList<int[]>> rune_skill_adj = new LinkedHashMap<>();
public final EnumMap<mbEnums.AttributeType, Integer> rune_attr_adj = new EnumMap<>(mbEnums.AttributeType.class);
public final EnumMap<mbEnums.AttributeType, Integer> rune_max_attr_adj = new EnumMap<>(mbEnums.AttributeType.class);
// One float[10] per natural attack. Same "attack info" struct as a weapon
// (see MBDATA/docs/client-map.md): [0] attack speed, [1] range, [2] unknown,
// [3] equip slot (1 = RHELD, 2 = LHELD), [4] projectile template id,
// [5] projectile speed, [6] swing anim, [7] damage type, [8] min damage,
// [9] max damage
public final ArrayList<float[]> rune_naturalattacks = new ArrayList<>();
// Empty in every RUNE file; shape unknown.
public JSONArray rune_enchantment_type;
public final ArrayList<InventoryEntry> rune_inventory_contents = new ArrayList<>();
public boolean rune_renderable;
// The following fields are only present when the rune is renderable
// (missing from 315 of 2695 files). They keep their defaults otherwise.
public Vector3fImmutable rune_scale_factor;
public int rune_skeleton;
public boolean rune_slope_hugger;
public boolean rune_can_fly;
public int rune_death_effect;
public int rune_tombstone_id;
public final ArrayList<BodyPart> rune_body_parts = new ArrayList<>();
public final ArrayList<Integer> rune_hair = new ArrayList<>();
public final ArrayList<Integer> rune_beard = new ArrayList<>();
public int rune_natural_power_attack;
public final HashMap<String, String> rune_sparse_data = new HashMap<>();
// One entry of rune_skill_grant.
// skill_granted_skills entries look like [hash, value] pairs; not confirmed in the client.
// skill_granted_attrs, skill_granted_powers and skill_monster_types are empty
// in every RUNE file, so they are kept as raw JSON.
public static class SkillGrant {
public String skill_type;
public int skill_value;
public JSONArray skill_granted_attrs;
public final ArrayList<int[]> skill_granted_skills = new ArrayList<>();
public JSONArray skill_granted_powers;
public JSONArray skill_monster_types;
}
// One entry of rune_body_parts.
public static class BodyPart {
public int body_part_render;
public Vector3fImmutable body_part_position;
}
// One entry of rune_inventory_contents.
// type is GOLD or BOOTYTABLE.
// GOLD carries "gold": three floats (meaning not yet confirmed).
// BOOTYTABLE carries "table": two numbers (meaning not yet confirmed).
public static class InventoryEntry {
public String type;
public float[] values;
}
}
@@ -1,24 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.parsers.objects;
// One entry of item_user_power_action.
// The same power can appear more than once on a single template,
// so these are kept in a list rather than a map keyed by power.
public class UserPowerAction {
public String power;
public int[] arguments;
public UserPowerAction(String power, int[] arguments) {
this.power = power;
this.arguments = arguments;
}
}
-11
View File
@@ -1,11 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
// Parsers for the client's .wpak configuration files (powers, effects, etc).
package engine.parsers.wpak;
@@ -246,9 +246,7 @@ public class ApplyEffectPowerAction extends AbstractPowerAction {
if (this.effectID.equals("TAUNT")) {
// siege engines only switch targets on damage, see AbstractCharacter.modifyHealth
if (awo != null && awo.getObjectType() == GameObjectType.Mob && !((Mob) awo).isSiege()) {
if (awo != null && awo.getObjectType() == GameObjectType.Mob) {
((Mob) awo).setCombatTarget(source);
ChatSystemMsg msg = ChatManager.CombatInfo(source, awo);
DispatchManager.sendToAllInRange(source, msg);
+1 -2
View File
@@ -18,7 +18,6 @@ import engine.net.MessageDispatcher;
import engine.net.client.msg.chat.ChatSystemMsg;
import engine.objects.*;
import engine.server.world.WorldServer;
import org.joda.time.DateTime;
import org.pmw.tinylog.Logger;
import java.time.LocalDateTime;
@@ -292,7 +291,7 @@ public class HourlyJobThread implements Runnable {
public static void processBanes() {
//handle banes
for (Bane bane : Bane.banes.values()) {
if (bane.getLiveDate() != null && DateTime.now().isAfter(bane.getLiveDate().minusMinutes(1)) && bane.isStarted == false)
if (bane.getLiveDate() != null && LocalDateTime.now().isAfter(bane.getLiveDate().minusMinutes(1)) && bane.isStarted == false)
bane.startBane();
}
}