You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
7.2 KiB
233 lines
7.2 KiB
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . |
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· |
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ |
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ |
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ |
|
// Magicbane Emulator Project © 2013 - 2022 |
|
// www.magicbane.com |
|
|
|
|
|
package engine.objects; |
|
|
|
import engine.Enum.GameObjectType; |
|
import engine.gameManager.BuildingManager; |
|
import engine.gameManager.DbManager; |
|
import engine.job.JobContainer; |
|
import engine.job.JobScheduler; |
|
import engine.jobs.DatabaseUpdateJob; |
|
import engine.server.MBServerStatics; |
|
import org.pmw.tinylog.Logger; |
|
|
|
import java.sql.ResultSet; |
|
import java.sql.SQLException; |
|
import java.util.concurrent.ConcurrentHashMap; |
|
|
|
|
|
public abstract class AbstractGameObject { |
|
private GameObjectType objectType = GameObjectType.unknown; |
|
private int objectUUID; |
|
|
|
private byte ver = 1; |
|
|
|
private ConcurrentHashMap<String, JobContainer> databaseJobs = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); |
|
|
|
/** |
|
* No Table ID Constructor |
|
*/ |
|
public AbstractGameObject() { |
|
super(); |
|
setObjectType(); |
|
this.objectUUID = MBServerStatics.NO_DB_ROW_ASSIGNED_YET; |
|
} |
|
|
|
/** |
|
* Normal Constructor |
|
*/ |
|
public AbstractGameObject(int objectUUID) { |
|
this(); |
|
this.objectUUID = objectUUID; |
|
} |
|
|
|
/** |
|
* ResultSet Constructor |
|
* |
|
* @param rs ResultSet containing record for this object |
|
*/ |
|
public AbstractGameObject(ResultSet rs, int objectUUID) throws SQLException { |
|
this(); |
|
this.objectUUID = objectUUID; |
|
} |
|
|
|
/** |
|
* ResultSet Constructor; assumes first column in ResultSet is ID |
|
* |
|
* @param rs ResultSet containing record for this object |
|
*/ |
|
public AbstractGameObject(ResultSet rs) throws SQLException { |
|
this(rs, rs.getInt(1)); |
|
} |
|
|
|
public static int extractUUID(GameObjectType type, long compositeID) { |
|
if (type == null || type == GameObjectType.unknown || compositeID == 0L) { |
|
return -1; |
|
} |
|
int out = (int) compositeID; |
|
if (out > Long.MAX_VALUE || out < 0) { |
|
Logger.error("There was a problem reverse calculating a UUID from a compositeID. \tcomposID: " |
|
+ compositeID + " \ttype: " + type.toString() + "\tresult: " + out); |
|
} |
|
return out; |
|
} |
|
|
|
public static GameObjectType extractTypeID(long compositeID) { |
|
int ordinal = (int) (compositeID >>> 32); |
|
return GameObjectType.values()[ordinal]; |
|
} |
|
|
|
/** |
|
* Generates a {@link PreparedStatementShared} based on the specified query. |
|
* <p> |
|
* If {@link AbstractGameObject} Database functions will properly release |
|
* the PreparedStatementShared upon completion. If these functions are not |
|
* used, then {@link PreparedStatementShared#release release()} must be |
|
* called when finished with this object. |
|
* |
|
* @param sql The SQL string used to generate the PreparedStatementShared |
|
* @return {@link PreparedStatementShared} |
|
* @throws {@link SQLException} |
|
**/ |
|
protected static PreparedStatementShared prepareStatement(String sql) throws SQLException { |
|
return new PreparedStatementShared(sql); |
|
} |
|
|
|
public static AbstractGameObject getFromTypeAndID(long compositeID) { |
|
int objectTypeID = extractTypeOrdinal(compositeID); |
|
int tableID = extractTableID(objectTypeID, compositeID); |
|
GameObjectType objectType = GameObjectType.values()[objectTypeID]; |
|
|
|
switch (objectType) { |
|
case PlayerCharacter: |
|
return PlayerCharacter.getPlayerCharacter(tableID); |
|
|
|
case NPC: |
|
return NPC.getNPC(tableID); |
|
|
|
case Mob: |
|
return Mob.getMob(tableID); |
|
|
|
case Building: |
|
return BuildingManager.getBuilding(tableID); |
|
|
|
case Guild: |
|
return Guild.getGuild(tableID); |
|
|
|
case Item: |
|
return Item.getFromCache(tableID); |
|
|
|
case MobLoot: |
|
return MobLoot.getFromCache(tableID); |
|
|
|
default: |
|
Logger.error("Failed to convert compositeID to AbstractGameObject. " + "Unsupported type encountered. " |
|
+ "CompositeID: " + compositeID + " ObjectType: 0x" + Integer.toHexString(objectTypeID) + " TableID: " + tableID); |
|
} |
|
return null; |
|
} |
|
|
|
public static int extractTypeOrdinal(long compositeID) { |
|
return (int) (compositeID >>> 32); |
|
} |
|
|
|
public static int extractTableID(int type, long compositeID) { |
|
if (type == 0 || compositeID == 0L) { |
|
return -1; |
|
} |
|
return (int) compositeID; |
|
} |
|
|
|
/* |
|
* Util |
|
*/ |
|
|
|
/* |
|
* Getters |
|
*/ |
|
public GameObjectType getObjectType() { |
|
return this.objectType; |
|
} |
|
|
|
protected final void setObjectType() { |
|
try { |
|
this.objectType = GameObjectType.valueOf(this.getClass().getSimpleName()); |
|
} catch (SecurityException | IllegalArgumentException e) { |
|
Logger.error("Failed to find class " + this.getClass().getSimpleName() |
|
+ " in GameObjectTypes file. Defaulting ObjectType to 0."); |
|
} |
|
} |
|
|
|
public int getObjectUUID() { |
|
return this.objectUUID; |
|
} |
|
|
|
protected void setObjectUUID(int objectUUID) { |
|
this.objectUUID = objectUUID; |
|
} |
|
|
|
public byte getVer() { |
|
return this.ver; |
|
} |
|
|
|
public void incVer() { |
|
this.ver++; |
|
if (this.ver == (byte) -1) //-1 reserved |
|
this.ver++; |
|
} |
|
|
|
public boolean equals(AbstractGameObject obj) { |
|
|
|
if (obj == null) |
|
return false; |
|
|
|
if (obj.objectType != this.objectType) { |
|
return false; |
|
} |
|
|
|
return obj.getObjectUUID() == this.getObjectUUID(); |
|
} |
|
|
|
public void removeFromCache() { |
|
DbManager.removeFromCache(this); |
|
} |
|
|
|
public ConcurrentHashMap<String, JobContainer> getDatabaseJobs() { |
|
return this.databaseJobs; |
|
} |
|
|
|
public void addDatabaseJob(String type, int duration) { |
|
DatabaseUpdateJob updateJob; |
|
|
|
if (databaseJobs.containsKey(type)) |
|
return; |
|
|
|
updateJob = new DatabaseUpdateJob(this, type); |
|
JobContainer jc = JobScheduler.getInstance().scheduleJob(updateJob, duration); |
|
databaseJobs.put(type, jc); |
|
} |
|
|
|
public void removeDatabaseJob(String type, boolean canceled) { |
|
if (databaseJobs.containsKey(type)) { |
|
if (canceled) { |
|
JobContainer jc = databaseJobs.get(type); |
|
if (jc != null) |
|
jc.cancelJob(); |
|
} |
|
databaseJobs.remove(type); |
|
} |
|
} |
|
|
|
/* |
|
* Abstract Methods |
|
*/ |
|
|
|
public abstract void updateDatabase(); |
|
}
|
|
|