2022-04-30 09:41:17 -04:00
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.objects ;
import engine.Enum ;
2023-10-08 09:18:43 -04:00
import engine.InterestManagement.Terrain ;
2022-04-30 09:41:17 -04:00
import engine.db.archive.DataWarehouse ;
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 ;
2023-10-18 08:03:47 -04:00
public class Zone extends AbstractWorldObject {
2022-04-30 09:41:17 -04:00
2023-10-18 08:42:40 -04:00
public static final Set < Mob > respawnQue = Collections . newSetFromMap ( new ConcurrentHashMap <> ());
public static long lastRespawn = 0 ;
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 <> ());
2023-09-20 15:53:41 -04:00
public final int playerCityUUID ;
2023-09-20 15:43:01 -04:00
public final String zoneName ;
2023-09-20 15:53:41 -04:00
public final float xOffset ;
public final float zOffset ;
public final float yOffset ;
2023-09-20 16:06:57 -04:00
public final int template ;
2023-09-20 16:05:57 -04:00
public final byte peace_zone ;
2023-09-20 16:07:50 -04:00
public final String icon1 ;
public final String icon2 ;
public final String icon3 ;
2023-07-15 09:23:48 -04:00
public float absX = 0 . 0f ;
public float absY = 0 . 0f ;
public float absZ = 0 . 0f ;
2023-09-20 16:07:50 -04:00
public int min_level ;
public int max_level ;
2023-07-15 09:23:48 -04:00
public boolean hasBeenHotzone = false ;
2023-09-20 15:43:01 -04:00
public ArrayList < Zone > nodes = null ;
public int parentZoneID ;
public Zone parent = null ;
public Bounds bounds ;
public boolean isNPCCity = false ;
2023-09-20 16:05:57 -04:00
public boolean guild_zone ;
2023-09-20 15:43:01 -04:00
public String hash ;
2023-10-12 06:19:22 -04:00
public float global_height = 0 ;
2023-09-20 15:43:01 -04:00
public float seaLevel = 0f ;
2023-10-08 09:59:13 -04:00
public float sea_level_offset = 0 ;
2023-09-20 16:24:00 -04:00
public float major_radius ;
public float minor_radius ;
public float min_blend ;
public float max_blend ;
public String sea_level_type ;
public float sea_level ;
public String terrain_type ;
public float terrain_max_y ;
public int terrain_image ;
2023-09-17 07:42:46 -04:00
2023-10-08 09:49:49 -04:00
public Terrain terrain = null ;
2023-07-15 09:23:48 -04:00
/**
* ResultSet Constructor
*/
public Zone ( ResultSet rs ) throws SQLException {
2023-10-08 23:05:41 -04:00
super ( rs );
2023-07-15 09:23:48 -04:00
2023-10-18 08:42:40 -04:00
this . parentZoneID = rs . getInt ( "parent" );
this . playerCityUUID = rs . getInt ( "playerCityUUID" );
this . guild_zone = this . playerCityUUID != 0 ;
this . zoneName = rs . getString ( "zone_name" );
this . xOffset = rs . getFloat ( "xOffset" );
this . zOffset = rs . getFloat ( "zOffset" );
this . yOffset = rs . getFloat ( "yOffset" );
this . template = rs . getInt ( "template" );
this . peace_zone = rs . getByte ( "peace_zone" );
this . icon1 = rs . getString ( "icon1" );
this . icon2 = rs . getString ( "icon2" );
this . icon3 = rs . getString ( "icon3" );
this . min_level = rs . getInt ( "min_level" );
this . max_level = rs . getInt ( "max_level" );
2023-10-18 08:25:05 -04:00
this . major_radius = rs . getFloat ( "major_radius" );
this . minor_radius = rs . getFloat ( "minor_radius" );
this . min_blend = rs . getFloat ( "min_blend" );
this . max_blend = rs . getFloat ( "max_blend" );
this . sea_level_type = rs . getString ( "sea_level_type" );
this . sea_level_offset = rs . getFloat ( "sea_level" );
this . terrain_type = rs . getString ( "terrain_type" );
this . terrain_max_y = rs . getFloat ( "terrain_max_y" );
this . terrain_image = rs . getInt ( "terrain_image" );
// Configuration for player cities
if ( this . guild_zone ) {
this . max_blend = 128 ;
this . min_blend = 128 ;
this . terrain_max_y = 5 ;
this . major_radius = ( int ) Enum . CityBoundsType . ZONE . halfExtents ;
this . minor_radius = ( int ) Enum . CityBoundsType . ZONE . halfExtents ;
this . terrain_type = "PLANAR" ;
}
2023-07-15 09:23:48 -04:00
// 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 ) {
2023-09-20 16:06:57 -04:00
if ( zone . template == 0 && zone . playerCityUUID == 0 )
2023-07-15 09:23:48 -04:00
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.
2023-09-20 15:53:41 -04:00
if ( zone . playerCityUUID > 0 ) {
2023-07-15 09:23:48 -04:00
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
2023-09-20 15:53:41 -04:00
writer . putFloat ( zone . xOffset );
writer . putFloat ( zone . zOffset );
writer . putFloat ( zone . yOffset );
2023-07-15 09:23:48 -04:00
writer . putInt ( 0 );
writer . putInt ( 0 );
2023-09-20 16:06:57 -04:00
writer . putInt ( zone . template );
2023-07-15 09:23:48 -04:00
2023-09-20 15:53:41 -04:00
if ( zone . playerCityUUID > 0 ) {
City k = City . getCity ( zone . playerCityUUID );
2023-07-15 09:23:48 -04:00
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 ());
2023-09-20 15:53:41 -04:00
City city = City . getCity ( zone . playerCityUUID );
2023-07-15 09:23:48 -04:00
if ( city != null )
writer . putString ( city . getCityName ());
else
writer . putString ( zone . zoneName );
2023-09-20 16:05:57 -04:00
writer . put ( zone . peace_zone );
2023-09-20 16:07:50 -04:00
writer . putString ( zone . icon1 );
writer . putString ( zone . icon2 );
writer . putString ( zone . icon3 );
2023-07-15 09:23:48 -04:00
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-10-18 08:42:40 -04:00
@Override
public void runAfterLoad () {
// First zone is always the seafloor
if ( ZoneManager . seaFloor == null )
ZoneManager . seaFloor = this ;
if ( this . terrain_type . equals ( "NONE" ))
this . terrain = null ;
else
this . terrain = new Terrain ( this );
this . setParent ();
if ( this . min_level == 0 && this . parent != null ) {
this . min_level = this . parent . min_level ;
this . max_level = this . parent . max_level ;
}
ZoneManager . populateZoneCollections ( this );
}
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 ();
2023-10-09 06:04:37 -04:00
this . bounds . setBounds ( new Vector2f ( this . absX , this . absZ ), new Vector2f ( this . major_radius , this . minor_radius ), 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-10-18 08:42:40 -04:00
public void setParent () {
2023-05-23 10:27:03 -04:00
2023-10-18 08:51:46 -04:00
this . parent = ZoneManager . getZoneByUUID ( parentZoneID );
2023-05-23 10:27:03 -04:00
2023-09-12 15:06:26 -04:00
// Seafloor
2023-10-18 08:42:40 -04:00
if ( ZoneManager . seaFloor . equals ( this )) {
2023-09-20 15:53:41 -04:00
this . absX = this . xOffset ;
2023-09-12 15:09:52 -04:00
this . absY = MBServerStatics . SEA_FLOOR_ALTITUDE ;
2023-10-15 15:57:58 -04:00
this . global_height = MBServerStatics . SEA_FLOOR_ALTITUDE ;
2023-09-20 15:53:41 -04:00
this . absZ = this . zOffset ;
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-20 15:53:41 -04:00
this . absX = this . xOffset + parent . absX ;
this . absY = this . yOffset + parent . absY ;
this . absZ = this . zOffset + parent . absZ ;
2023-09-12 15:09:52 -04:00
2023-09-20 16:07:50 -04:00
if ( this . min_level == 0 || this . max_level == 0 ) {
this . min_level = this . parent . min_level ;
this . max_level = this . parent . max_level ;
2023-09-12 15:09:52 -04:00
}
2023-09-17 23:53:06 -04:00
this . setBounds ();
2023-10-12 06:19:22 -04:00
this . global_height = ZoneManager . calculateGlobalZoneHeight ( this );
2023-10-08 09:59:13 -04:00
setSeaLevel ();
}
private void setSeaLevel () {
int world_sea_level = 0 ;
2023-09-20 15:43:01 -04:00
if ( this . parent == null ) {
2023-10-08 09:59:13 -04:00
this . sea_level = world_sea_level ;
2023-09-14 09:13:02 -04:00
return ;
}
2023-10-08 09:59:13 -04:00
switch ( this . sea_level_type ) {
case "WORLD" :
this . sea_level = world_sea_level + this . sea_level_offset ;
break ;
case "PARENT" :
this . sea_level = this . parent . sea_level + this . sea_level_offset ;
break ;
case "SELF" :
2023-10-12 06:19:22 -04:00
this . sea_level = this . global_height + this . sea_level_offset ;
2023-10-08 09:59:13 -04:00
break ;
2023-09-14 09:13:02 -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 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-10-18 08:42:40 -04:00
if ( this . guild_zone )
2023-07-15 09:23:48 -04:00
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-09-20 16:07:50 -04:00
return ! icon1 . equals ( "" );
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 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
/*
* 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-10-09 06:16:25 -04:00
if ( this . equals ( ZoneManager . seaFloor ))
2023-07-15 09:23:48 -04:00
return false ;
2023-03-21 03:20:57 -04:00
2023-10-18 08:33:49 -04:00
if ( this . nodes . isEmpty ())
2023-07-15 09:23:48 -04:00
return false ;
2022-04-30 09:41:17 -04:00
2023-10-18 08:33:49 -04:00
if ( this . nodes . get ( 0 ). isMacroZone ())
2023-07-15 09:23:48 -04:00
return true ;
2023-03-21 03:20:57 -04:00
2023-10-09 06:16:25 -04:00
return this . parent . equals ( ZoneManager . seaFloor );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
}
2023-10-18 08:42:40 -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
}