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 ;
2023-09-12 14:51:04 -04:00
public float worldAltitude = 0 ;
2023-09-14 13:07:32 -04:00
private float seaLevel = 0f ;
2023-08-01 19:19:39 -05:00
public static final Set < Mob > respawnQue = Collections . newSetFromMap ( new ConcurrentHashMap <> ());
2023-07-27 21:22:20 -05:00
public static long lastRespawn = 0 ;
2023-09-17 07:42:46 -04:00
public Bounds maxBlend ;
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" );
2023-09-17 23:46:00 -04:00
//this needs to be here specifically for new zones created after server boot (e.g. player city zones)
Zone parentZone = ZoneManager . getZoneByUUID ( parentZoneID );
2023-07-15 09:23:48 -04:00
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
2023-09-17 12:23:06 -04:00
writer . putFloat ( Enum . CityBoundsType . ZONE . halfExtents );
writer . putFloat ( Enum . CityBoundsType . ZONE . halfExtents );
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 );
}
}
2022-04-30 09:41:17 -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
// 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
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
2023-09-17 12:23:06 -04:00
bounds . setBounds ( new Vector2f ( this . absX , this . absZ ), new Vector2f ( Enum . CityBoundsType . ZONE . halfExtents , Enum . CityBoundsType . ZONE . halfExtents ), 0 . 0f );
2022-04-30 09:41:17 -04:00
2023-09-17 07:42:46 -04:00
HeightMap heightMap = this . getHeightMap ();
// Set heightmap blending bounds
2023-09-17 12:13:46 -04:00
if ( heightMap == null ) {
this . maxBlend = this . getBounds ();
} else {
2023-09-17 12:15:21 -04:00
this . maxBlend = Bounds . borrow ();
2023-09-17 14:00:00 -04:00
this . maxBlend . setBounds ( new Vector2f ( this . absX , this . absZ ), this . getBounds (). getHalfExtents (). subtract ( heightMap . zone_minBlend , heightMap . zone_minBlend ), 0 . 0f );
2023-09-17 07:42:46 -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 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-09-12 15:06:26 -04:00
// Seafloor
if ( this . parent == null ) {
2023-09-12 15:09:52 -04:00
this . absX = this . xCoord ;
this . absY = MBServerStatics . SEA_FLOOR_ALTITUDE ;
this . absZ = this . zCoord ;
2023-09-12 14:57:47 -04:00
this . seaLevel = 0 ;
2023-09-17 23:53:06 -04:00
this . setBounds ();
2023-09-12 14:57:47 -04:00
return ;
}
2023-09-12 15:09:52 -04:00
this . absX = this . xCoord + parent . absX ;
this . absY = this . yCoord + parent . absY ;
this . absZ = this . zCoord + parent . absZ ;
if ( this . minLvl == 0 || this . maxLvl == 0 ) {
this . minLvl = this . parent . minLvl ;
this . maxLvl = this . parent . maxLvl ;
}
2023-09-17 23:53:06 -04:00
this . setBounds ();
2023-09-14 12:07:08 -04:00
this . worldAltitude = ZoneManager . caclulateWorldAltitude ( this );
2023-09-14 09:13:02 -04:00
if ( this . getParent () == null ) {
2023-09-14 12:07:08 -04:00
this . seaLevel = MBServerStatics . SEA_FLOOR_ALTITUDE ;
2023-09-14 09:13:02 -04:00
return ;
}
if ( this . getHeightMap () == null ) {
this . seaLevel = this . parent . seaLevel ;
return ;
}
2023-09-17 12:53:56 -04:00
if ( this . getHeightMap (). seaLevel != 0 )
this . seaLevel = this . worldAltitude + this . getHeightMap (). seaLevel ;
2023-09-12 14:57:47 -04:00
else
this . seaLevel = this . parent . seaLevel ;
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 ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( this . getNodes (). isEmpty ())
return false ;
2023-03-21 03:20:57 -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
}