Files
Server/src/engine/objects/Zone.java
T

427 lines
12 KiB
Java
Raw Normal View History

2022-04-30 09:41:17 -04:00
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.objects;
import engine.Enum;
import engine.InterestManagement.HeightMap;
import engine.db.archive.DataWarehouse;
import engine.gameManager.DbManager;
import engine.gameManager.ZoneManager;
import engine.math.Bounds;
import engine.math.Vector2f;
import engine.math.Vector3fImmutable;
import engine.net.ByteBufferWriter;
import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class Zone extends AbstractGameObject {
2023-07-15 09:23:48 -04:00
public final Set<Building> zoneBuildingSet = Collections.newSetFromMap(new ConcurrentHashMap<>());
public final Set<NPC> zoneNPCSet = Collections.newSetFromMap(new ConcurrentHashMap<>());
public final Set<Mob> zoneMobSet = Collections.newSetFromMap(new ConcurrentHashMap<>());
private final int playerCityID;
private final String zoneName;
private final float xCoord;
private final float zCoord;
private final float yCoord;
private final int loadNum;
private final byte safeZone;
private final String Icon1;
private final String Icon2;
private final String Icon3;
public float absX = 0.0f;
public float absY = 0.0f;
public float absZ = 0.0f;
public int minLvl;
public int maxLvl;
public boolean hasBeenHotzone = false;
private ArrayList<Zone> nodes = null;
private int parentZoneID;
private Zone parent = null;
private Bounds bounds;
private boolean isNPCCity = false;
private boolean isPlayerCity = false;
private String hash;
private float worldAltitude = 0;
private float seaLevel = 0;
2023-08-01 19:19:39 -05:00
//public static ArrayList<Mob> respawnQue = new ArrayList<>();
public static final Set<Mob> respawnQue = Collections.newSetFromMap(new ConcurrentHashMap<>());
2023-07-27 21:22:20 -05:00
public static long lastRespawn = 0;
2023-07-15 09:23:48 -04:00
/**
* ResultSet Constructor
*/
public Zone(ResultSet rs) throws SQLException {
super(rs);
this.parentZoneID = rs.getInt("parent");
this.playerCityID = rs.getInt("isPlayerCity");
this.isPlayerCity = this.playerCityID != 0;
this.zoneName = rs.getString("Name");
this.xCoord = rs.getFloat("XCoord");
this.zCoord = rs.getFloat("ZCoord");
this.yCoord = rs.getFloat("YOffset");
this.loadNum = rs.getInt("LoadNum");
this.safeZone = rs.getByte("SafeZone");
this.Icon1 = rs.getString("Icon1");
this.Icon2 = rs.getString("Icon2");
this.Icon3 = rs.getString("Icon3");
this.hash = rs.getString("hash");
this.minLvl = rs.getInt("minLvl");
this.maxLvl = rs.getInt("maxLvl");
//this needs to be here specifically for new zones created after server boot (e.g. player city zones)
Zone parentZone = ZoneManager.getZoneByUUID(parentZoneID);
this.setParent(parentZone);
if (this.minLvl == 0 && parentZone != null) {
this.minLvl = parentZone.minLvl;
this.maxLvl = parentZone.maxLvl;
}
if (parentZone != null)
parentZone.addNode(this);
// If zone doesn't yet hava a hash then write it back to the zone table
if (hash == null)
setHash();
}
public static void serializeForClientMsg(Zone zone, ByteBufferWriter writer) {
if (zone.loadNum == 0 && zone.playerCityID == 0)
Logger.warn("Warning! WorldServerMap with ID " + zone.getObjectUUID() + " has a loadnum of 0 (player city) and no city linked. This will probably crash the client!");
// Player City Terraform values serialized here.
if (zone.playerCityID > 0) {
writer.put((byte) 1); // Player City - True
2024-06-11 20:29:30 -05:00
writer.putFloat(Enum.CityBoundsType.GRID.extents);
writer.putFloat(Enum.CityBoundsType.GRID.extents);
2023-07-15 09:23:48 -04:00
} else
writer.put((byte) 0); // Player City - False
writer.putFloat(zone.xCoord);
writer.putFloat(zone.zCoord);
writer.putFloat(zone.yCoord);
writer.putInt(0);
writer.putInt(0);
writer.putInt(zone.loadNum);
if (zone.playerCityID > 0) {
City k = City.getCity(zone.playerCityID);
if (k != null) {
writer.putInt(k.getObjectType().ordinal());
writer.putInt(k.getObjectUUID());
} else
writer.putLong(0x0);
} else {
writer.putInt(zone.getObjectType().ordinal());
writer.putInt(zone.getObjectUUID());
}
writer.putInt(zone.nodes.size());
City city = City.getCity(zone.playerCityID);
if (city != null)
writer.putString(city.getCityName());
else
writer.putString(zone.zoneName);
writer.put(zone.safeZone);
writer.putString(zone.Icon1);
writer.putString(zone.Icon2);
writer.putString(zone.Icon3);
writer.put((byte) 0); // Pad
2023-05-23 10:27:03 -04:00
2023-07-15 09:23:48 -04:00
for (Zone child : zone.nodes) {
Zone.serializeForClientMsg(child, writer);
}
}
2023-05-23 10:27:03 -04:00
2023-07-15 09:23:48 -04:00
/* Method sets a default value for player cities
* otherwise using values derived from the loadnum
* field in the obj_zone database table.
*/
public void setBounds() {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
float halfExtentX;
float halfExtentY;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Set initial bounds object
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
this.bounds = Bounds.borrow();
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Player cities are assigned default value
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if (this.loadNum == 0) {
bounds.setBounds(new Vector2f(this.absX, this.absZ), new Vector2f(Enum.CityBoundsType.ZONE.extents, Enum.CityBoundsType.ZONE.extents), 0.0f);
return;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
Vector2f zoneSize = ZoneManager._zone_size_data.get(this.loadNum);
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Default to player zone size on error? Maybe log this
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if (zoneSize != null)
this.bounds.setBounds(new Vector2f(this.absX, this.absZ), zoneSize, 0.0f);
else
bounds.setBounds(new Vector2f(this.absX, this.absZ), new Vector2f(Enum.CityBoundsType.ZONE.extents, Enum.CityBoundsType.ZONE.extents), 0.0f);
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public int getPlayerCityUUID() {
return this.playerCityID;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public String getName() {
return zoneName;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public float getXCoord() {
return xCoord;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public float getYCoord() {
return yCoord;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public float getZCoord() {
return zCoord;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public int getLoadNum() {
return loadNum;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public byte getSafeZone() {
return safeZone;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public String getIcon1() {
return Icon1;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public void generateWorldAltitude() {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if (ZoneManager.getSeaFloor().getObjectUUID() == this.getObjectUUID()) {
this.worldAltitude = MBServerStatics.SEA_FLOOR_ALTITUDE;
return;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
Zone parentZone = this.parent;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
Zone currentZone = this;
float altitude = this.absY;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
//seafloor only zone with null parent;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
while (parentZone != ZoneManager.getSeaFloor()) {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if (parentZone.getHeightMap() != null) {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
Vector2f zoneLoc = ZoneManager.worldToZoneSpace(currentZone.getLoc(), parentZone);
altitude += parentZone.getHeightMap().getInterpolatedTerrainHeight(zoneLoc);
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
}
currentZone = parentZone;
parentZone = parentZone.parent;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
this.worldAltitude = altitude;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if (ZoneManager.getSeaFloor().equals(this))
this.seaLevel = 0;
else if
(this.getHeightMap() != null && this.getHeightMap().getSeaLevel() == 0) {
this.seaLevel = this.parent.seaLevel;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
} else if (this.getHeightMap() != null) {
this.seaLevel = this.worldAltitude + this.getHeightMap().getSeaLevel();
} else {
this.seaLevel = this.parent.seaLevel;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public Zone getParent() {
return this.parent;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public void setParent(final Zone value) {
2023-05-23 10:27:03 -04:00
2023-07-15 09:23:48 -04:00
this.parent = value;
this.parentZoneID = (this.parent != null) ? this.parent.getObjectUUID() : 0;
2023-05-23 10:27:03 -04:00
2023-07-15 09:23:48 -04:00
if (this.parent != null) {
this.absX = this.xCoord + parent.absX;
this.absY = this.yCoord + parent.absY;
this.absZ = this.zCoord + parent.absZ;
2023-05-23 10:27:03 -04:00
2023-07-15 09:23:48 -04:00
if (this.minLvl == 0 || this.maxLvl == 0) {
this.minLvl = this.parent.minLvl;
this.maxLvl = this.parent.maxLvl;
}
} else { //only the Sea Floor zone does not have a parent
this.absX = this.xCoord;
this.absY = MBServerStatics.SEA_FLOOR_ALTITUDE;
this.absZ = this.zCoord;
}
2023-05-23 10:27:03 -04:00
2023-07-15 09:23:48 -04:00
// Zone AABB is set here as it's coordinate space is world requiring a parent.
this.setBounds();
2023-05-23 10:27:03 -04:00
2023-07-15 09:23:48 -04:00
if (this.getHeightMap() != null && this.getHeightMap().getSeaLevel() != 0)
this.seaLevel = this.getHeightMap().getSeaLevel();
2023-05-23 10:27:03 -04:00
2023-07-15 09:23:48 -04:00
}
2023-05-23 10:27:03 -04:00
2023-07-15 09:23:48 -04:00
public float getAbsX() {
return this.absX;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public float getAbsY() {
return this.absY;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public float getAbsZ() {
return this.absZ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public boolean isMacroZone() {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Macro zones have icons.
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if (this.isPlayerCity == true)
return false;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if (this.parent == null)
return false;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
return !this.getIcon1().equals("");
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public boolean isNPCCity() {
return this.isNPCCity;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public void setNPCCity(boolean value) {
this.isNPCCity = value;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public boolean isPlayerCity() {
return this.isPlayerCity;
}
2023-05-23 10:27:03 -04:00
2023-07-15 09:23:48 -04:00
public void setPlayerCity(boolean value) {
this.isPlayerCity = value;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public Vector3fImmutable getLoc() {
return new Vector3fImmutable(this.absX, this.absY, this.absZ);
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public int getParentZoneID() {
return this.parentZoneID;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public ArrayList<Zone> getNodes() {
if (this.nodes == null) {
this.nodes = DbManager.ZoneQueries.GET_MAP_NODES(super.getObjectUUID());
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
//Add reverse lookup for child->parent
if (this.nodes != null)
for (Zone zone : this.nodes) {
zone.setParent(this);
}
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
return nodes;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
/*
* Serializing
*/
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public void addNode(Zone child) {
this.nodes.add(child);
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
@Override
public void updateDatabase() {
// TODO Auto-generated method stub
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public boolean isContinent() {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if (this.equals(ZoneManager.getSeaFloor()))
return false;
2023-03-21 03:20:57 -04:00
2023-07-15 09:23:48 -04:00
if (this.getNodes().isEmpty())
return false;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if (this.getNodes().get(0).isMacroZone())
return true;
2023-03-21 03:20:57 -04:00
2023-07-15 09:23:48 -04:00
return this.getParent().equals(ZoneManager.getSeaFloor());
2023-04-03 15:56:36 -04:00
2023-07-15 09:23:48 -04:00
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
/**
* @return the bounds
*/
public Bounds getBounds() {
return bounds;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public String getHash() {
return hash;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public void setHash() {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
this.hash = DataWarehouse.hasher.encrypt(this.getObjectUUID());
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Write hash to player character table
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
DataWarehouse.writeHash(Enum.DataRecordType.ZONE, this.getObjectUUID());
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Return heightmap for this Zone.
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public HeightMap getHeightMap() {
2023-05-23 10:27:03 -04:00
2023-07-15 09:23:48 -04:00
if (this.isPlayerCity)
return HeightMap.PlayerCityHeightMap;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
return HeightMap.heightmapByLoadNum.get(this.loadNum);
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public float getSeaLevel() {
return seaLevel;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public float getWorldAltitude() {
return worldAltitude;
}
2022-04-30 09:41:17 -04:00
}