Files
BattleBane/src/engine/gameManager/ZoneManager.java
T

437 lines
13 KiB
Java
Raw Normal View History

2022-04-30 09:41:17 -04:00
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.gameManager;
import engine.mbEnums;
2023-10-08 09:18:43 -04:00
import engine.InterestManagement.Terrain;
2022-04-30 09:41:17 -04:00
import engine.math.Bounds;
import engine.math.Vector2f;
import engine.math.Vector3f;
import engine.math.Vector3fImmutable;
import engine.objects.Building;
import engine.objects.City;
import engine.objects.Zone;
2023-10-20 15:50:04 -04:00
import engine.objects.ZoneTemplate;
2022-04-30 09:41:17 -04:00
import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;
import java.time.Instant;
2023-02-18 15:04:34 -06:00
import java.time.LocalDateTime;
import java.time.ZoneId;
2023-10-20 15:50:04 -04:00
import java.util.*;
2022-04-30 09:41:17 -04:00
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
/*
* Class contains methods and structures which
* track in-game Zones
*/
public enum ZoneManager {
2023-02-22 08:34:10 -05:00
ZONEMANAGER;
2023-10-20 15:50:04 -04:00
public static HashMap<Integer, ZoneTemplate> _zone_templates = new HashMap<>();
2023-05-23 10:27:03 -04:00
public static final Set<Zone> macroZones = Collections.newSetFromMap(new ConcurrentHashMap<>());
2023-02-22 08:34:10 -05:00
private static final ConcurrentHashMap<Integer, Zone> zonesByID = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD);
private static final ConcurrentHashMap<Integer, Zone> zonesByUUID = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD);
private static final ConcurrentHashMap<String, Zone> zonesByName = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD);
private static final Set<Zone> npcCityZones = Collections.newSetFromMap(new ConcurrentHashMap<>());
private static final Set<Zone> playerCityZones = Collections.newSetFromMap(new ConcurrentHashMap<>());
2023-05-23 10:27:03 -04:00
public static Instant hotZoneLastUpdate;
public static Zone hotZone = null;
public static int hotZoneCycle = 0; // Used with HOTZONE_DURATION from config.
2023-10-09 06:04:37 -04:00
2023-05-23 10:27:03 -04:00
/* Instance variables */
2023-10-09 06:16:25 -04:00
public static Zone seaFloor = null;
2023-02-24 00:32:18 -05:00
2023-02-22 08:34:10 -05:00
// Find all zones coordinates fit into, starting with Sea Floor
public static ArrayList<Zone> getAllZonesIn(final Vector3fImmutable loc) {
ArrayList<Zone> allIn = new ArrayList<>();
Zone zone;
zone = ZoneManager.findSmallestZone(loc);
if (zone != null) {
allIn.add(zone);
2023-09-20 15:43:01 -04:00
while (zone.parent != null) {
zone = zone.parent;
2023-02-22 08:34:10 -05:00
allIn.add(zone);
}
}
return allIn;
}
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
// Find smallest zone coordinates fit into.
2022-04-30 09:41:17 -04:00
2023-10-09 06:04:37 -04:00
public static Zone findSmallestZone(final Vector3fImmutable loc) {
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
Zone zone = ZoneManager.seaFloor;
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
if (zone == null)
return null;
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
boolean childFound = true;
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
while (childFound) {
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
childFound = false;
2022-04-30 09:41:17 -04:00
2023-10-18 08:33:49 -04:00
ArrayList<Zone> nodes = zone.nodes;
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
// Logger.info("soze", "" + nodes.size());
if (nodes != null)
for (Zone child : nodes) {
2022-04-30 09:41:17 -04:00
2023-10-09 06:04:37 -04:00
if (Bounds.collide(loc, child.bounds)) {
2023-02-22 08:34:10 -05:00
zone = child;
childFound = true;
break;
}
}
}
return zone;
}
2022-04-30 09:41:17 -04:00
2023-02-24 00:32:18 -05:00
// Returns the number of available hotZones
// remaining in this cycle (1am)
2023-02-24 01:04:29 -05:00
2023-02-24 00:32:18 -05:00
public static int availableHotZones() {
int count = 0;
for (Zone zone : ZoneManager.macroZones)
2023-02-24 01:04:29 -05:00
if (ZoneManager.validHotZone(zone))
2023-02-24 00:32:18 -05:00
count = count + 1;
return count;
}
// Resets the availability of hotZones
// for this cycle
public static void resetHotZones() {
for (Zone zone : ZoneManager.macroZones)
2023-10-23 00:43:23 -04:00
if (zone.wasHotzonw)
zone.wasHotzonw = false;
2023-02-24 00:32:18 -05:00
}
2023-02-22 08:34:10 -05:00
public static Zone getZoneByUUID(final int zoneUUID) {
return ZoneManager.zonesByUUID.get(zoneUUID);
}
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
public static Zone getZoneByZoneID(final int zoneID) {
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
return ZoneManager.zonesByID.get(zoneID);
}
2022-04-30 09:41:17 -04:00
2023-06-27 16:45:47 -04:00
public static Zone getZoneByName(final String zoneName) {
return ZoneManager.zonesByName.get(zoneName);
}
2023-10-09 06:04:37 -04:00
public static Collection<Zone> getAllZones() {
2023-02-22 08:34:10 -05:00
return ZoneManager.zonesByUUID.values();
}
2022-04-30 09:41:17 -04:00
2023-10-09 06:04:37 -04:00
public static void setHotZone(final Zone zone) {
2023-02-22 08:34:10 -05:00
if (!zone.isMacroZone())
return;
ZoneManager.hotZone = zone;
ZoneManager.hotZoneCycle = 1; // Used with HOTZONE_DURATION from config.
2023-10-23 00:43:23 -04:00
zone.wasHotzonw = true;
2023-02-24 09:08:45 -05:00
ZoneManager.hotZoneLastUpdate = LocalDateTime.now().withMinute(0).withSecond(0).atZone(ZoneId.systemDefault()).toInstant();
2023-02-22 08:34:10 -05:00
}
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
public static boolean inHotZone(final Vector3fImmutable loc) {
2022-04-30 09:41:17 -04:00
if (ZoneManager.hotZone == null)
2023-02-22 08:34:10 -05:00
return false;
2022-04-30 09:41:17 -04:00
2023-10-09 06:04:37 -04:00
return (Bounds.collide(loc, ZoneManager.hotZone.bounds));
2023-02-22 08:34:10 -05:00
}
2022-04-30 09:41:17 -04:00
2023-10-18 08:25:05 -04:00
public static void populateZoneCollections(final Zone zone) {
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
// Zones are added to separate
// collections for quick access
// based upon their type.
2022-04-30 09:41:17 -04:00
ZoneManager.zonesByID.put(zone.templateID, zone);
2023-10-18 08:25:05 -04:00
ZoneManager.zonesByUUID.put(zone.getObjectUUID(), zone);
ZoneManager.zonesByName.put(zone.zoneName.toLowerCase(), zone);
2023-02-22 08:34:10 -05:00
if (zone.isMacroZone()) {
addMacroZone(zone);
return;
}
2022-04-30 09:41:17 -04:00
2023-09-20 16:05:57 -04:00
if (zone.guild_zone) {
2023-10-18 09:38:19 -04:00
ZoneManager.playerCityZones.add(zone);
2023-02-22 08:34:10 -05:00
return;
}
2022-04-30 09:41:17 -04:00
2023-09-20 15:43:01 -04:00
if (zone.isNPCCity)
2023-02-22 08:34:10 -05:00
addNPCCityZone(zone);
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
}
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
private static void addMacroZone(final Zone zone) {
ZoneManager.macroZones.add(zone);
}
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
private static void addNPCCityZone(final Zone zone) {
2023-09-20 15:43:01 -04:00
zone.isNPCCity = true;
2023-02-22 08:34:10 -05:00
ZoneManager.npcCityZones.add(zone);
}
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
public static final void generateAndSetRandomHotzone() {
2022-04-30 09:41:17 -04:00
2023-02-26 07:31:26 -05:00
Zone hotZone;
2023-02-22 08:34:10 -05:00
ArrayList<Integer> zoneArray = new ArrayList<>();
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
if (ZoneManager.macroZones.isEmpty())
return;
2022-04-30 09:41:17 -04:00
2023-02-24 08:34:25 -05:00
// Reset hotZone availability if none are left.
2022-04-30 09:41:17 -04:00
2023-02-24 08:34:25 -05:00
if (ZoneManager.availableHotZones() == 0)
ZoneManager.resetHotZones();
for (Zone zone : ZoneManager.macroZones)
2023-02-22 08:34:10 -05:00
if (validHotZone(zone))
zoneArray.add(zone.getObjectUUID());
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
int entryIndex = ThreadLocalRandom.current().nextInt(zoneArray.size());
2022-04-30 09:41:17 -04:00
2023-02-26 07:31:26 -05:00
hotZone = ZoneManager.getZoneByUUID(zoneArray.get(entryIndex));
2022-04-30 09:41:17 -04:00
2023-02-26 07:31:26 -05:00
if (hotZone == null) {
2023-02-22 08:34:10 -05:00
Logger.error("Hotzone is null");
return;
}
2022-04-30 09:41:17 -04:00
2023-02-26 07:31:26 -05:00
ZoneManager.setHotZone(hotZone);
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
}
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
public static final boolean validHotZone(Zone zone) {
2022-04-30 09:41:17 -04:00
2023-09-20 16:05:57 -04:00
if (zone.peace_zone == (byte) 1)
2023-02-22 08:34:10 -05:00
return false; // no safe zone hotzones// if (this.hotzone == null)
2022-04-30 09:41:17 -04:00
2023-10-18 09:08:41 -04:00
if (zone.equals(ZoneManager.seaFloor))
2023-02-22 08:34:10 -05:00
return false;
2022-04-30 09:41:17 -04:00
2023-10-18 09:08:41 -04:00
if (zone.nodes.isEmpty())
2023-02-22 08:34:10 -05:00
return false;
2023-02-23 16:46:55 -05:00
//no duplicate hotZones
2023-10-23 00:43:23 -04:00
if (zone.wasHotzonw == true)
2023-02-23 16:46:55 -05:00
return false;
// Enforce min level
2023-09-20 16:07:50 -04:00
if (zone.min_level < Integer.parseInt(ConfigManager.MB_HOTZONE_MIN_LEVEL.getValue()))
2023-02-22 08:34:10 -05:00
return false;
2022-04-30 09:41:17 -04:00
if (ZoneManager.hotZone != null)
return ZoneManager.hotZone.getObjectUUID() != zone.getObjectUUID();
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
return true;
}
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
// Converts world coordinates to coordinates local to a given zone.
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
public static Vector3fImmutable worldToLocal(Vector3fImmutable worldVector,
2023-10-11 17:20:23 -04:00
Zone zone) {
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
Vector3fImmutable localCoords;
2022-04-30 09:41:17 -04:00
2023-10-11 17:20:23 -04:00
localCoords = new Vector3fImmutable(worldVector.x - zone.absX,
worldVector.y - zone.absY, worldVector.z
- zone.absZ);
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
return localCoords;
}
2022-04-30 09:41:17 -04:00
2023-10-11 16:50:52 -04:00
public static Vector2f worldToZoneOffset(Vector3fImmutable worldLoc,
2023-10-11 17:20:23 -04:00
Zone zone) {
2023-10-11 16:50:52 -04:00
2023-10-15 13:42:28 -04:00
Vector2f zoneLoc;
2023-10-11 16:50:52 -04:00
2023-10-15 13:42:28 -04:00
zoneLoc = new Vector2f(worldLoc.x, worldLoc.z).subtract(zone.getLoc().x, zone.getLoc().z);
zoneLoc.y *= -1;
2023-10-11 16:50:52 -04:00
2023-10-15 13:42:28 -04:00
return zoneLoc;
2023-10-11 16:50:52 -04:00
}
public static Vector2f worldToTerrainSpace(Vector3fImmutable worldLoc,
2023-10-11 17:20:23 -04:00
Zone zone) {
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
Vector2f localCoords;
Vector2f zoneOrigin;
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
// Top left corner of zone is calculated in world space by the center and it's extents.
2022-04-30 09:41:17 -04:00
2023-10-11 17:20:23 -04:00
zoneOrigin = new Vector2f(zone.getLoc().x, zone.getLoc().z);
zoneOrigin = zoneOrigin.subtract(new Vector2f(zone.bounds.getHalfExtents().x, zone.bounds.getHalfExtents().y));
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
// Local coordinate in world space translated to an offset from the calculated zone origin.
2022-04-30 09:41:17 -04:00
2023-10-11 16:50:52 -04:00
localCoords = new Vector2f(worldLoc.x, worldLoc.z);
2023-02-22 08:34:10 -05:00
localCoords = localCoords.subtract(zoneOrigin);
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
return localCoords;
}
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
// Converts local zone coordinates to world coordinates
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
/**
* Converts from local (relative to this building) to world.
*
* @param localPos position in local reference (relative to this building)
* @return position relative to world
*/
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
public static Vector3fImmutable convertLocalToWorld(Building building, Vector3fImmutable localPos) {
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
// convert from SB rotation value to radians
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
if (building.getBounds().getQuaternion() == null)
return building.getLoc();
2023-05-07 10:20:53 -04:00
2023-10-19 16:10:53 -04:00
// handle building rotation
2023-02-22 08:34:10 -05:00
Vector3fImmutable rotatedLocal = Vector3fImmutable.rotateAroundPoint(Vector3fImmutable.ZERO, localPos, building.getBounds().getQuaternion());
2023-05-07 10:20:53 -04:00
2023-02-22 08:34:10 -05:00
// handle building translation
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
return building.getLoc().add(rotatedLocal.x, rotatedLocal.y, rotatedLocal.z);
}
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
//used for regions, Building bounds not set yet.
public static Vector3f convertLocalToWorld(Building building, Vector3f localPos, Bounds bounds) {
2022-04-30 09:41:17 -04:00
2023-10-19 16:10:53 -04:00
// handle building rotation
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
Vector3f rotatedLocal = Vector3f.rotateAroundPoint(Vector3f.ZERO, localPos, bounds.getQuaternion());
2023-05-07 10:20:53 -04:00
2023-02-22 08:34:10 -05:00
// handle building translation
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
return new Vector3f(building.getLoc().add(rotatedLocal.x, rotatedLocal.y, rotatedLocal.z));
}
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
public static Vector3fImmutable convertWorldToLocal(Building building, Vector3fImmutable WorldPos) {
Vector3fImmutable convertLoc = Vector3fImmutable.rotateAroundPoint(building.getLoc(), WorldPos, -building.getBounds().getQuaternion().angleY);
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
convertLoc = convertLoc.subtract(building.getLoc());
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
// convert from SB rotation value to radians
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
return convertLoc;
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
}
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
// Method returns a city if the given location is within
2023-05-07 10:20:53 -04:00
// a city zone.
2023-02-22 08:34:10 -05:00
public static City getCityAtLocation(Vector3fImmutable worldLoc) {
Zone currentZone;
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
currentZone = ZoneManager.findSmallestZone(worldLoc);
2022-04-30 09:41:17 -04:00
2023-09-20 16:05:57 -04:00
if (currentZone.guild_zone)
2023-09-20 15:53:41 -04:00
return City.getCity(currentZone.playerCityUUID);
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
return null;
}
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
/* Method is called when creating a new player city to
* validate that the new zone does not overlap any other
* zone that might currently exist
*/
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
public static boolean validTreePlacementLoc(Zone currentZone, float positionX, float positionZ) {
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
// Member Variable declaration
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
ArrayList<Zone> zoneList;
boolean validLocation = true;
Bounds treeBounds;
2022-04-30 09:41:17 -04:00
2023-03-21 03:20:57 -04:00
if (currentZone.isContinent() == false)
2023-02-22 08:34:10 -05:00
return false;
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
treeBounds = Bounds.borrow();
treeBounds.setBounds(new Vector2f(positionX, positionZ), new Vector2f(mbEnums.CityBoundsType.PLACEMENT.halfExtents, mbEnums.CityBoundsType.PLACEMENT.halfExtents), 0.0f);
2022-04-30 09:41:17 -04:00
2023-10-18 08:33:49 -04:00
zoneList = currentZone.nodes;
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
for (Zone zone : zoneList) {
2022-04-30 09:41:17 -04:00
2023-03-21 03:20:57 -04:00
if (zone.isContinent())
2023-02-22 08:34:10 -05:00
continue;
2022-04-30 09:41:17 -04:00
2023-09-20 15:43:01 -04:00
if (Bounds.collide(treeBounds, zone.bounds, 0.0f))
2023-02-22 08:34:10 -05:00
validLocation = false;
}
2022-04-30 09:41:17 -04:00
2023-02-22 08:34:10 -05:00
treeBounds.release();
return validLocation;
2022-04-30 09:41:17 -04:00
}
2023-05-21 15:55:15 -04:00
2023-10-12 06:19:22 -04:00
public static float calculateGlobalZoneHeight(Zone zone) {
2023-09-12 14:51:04 -04:00
2023-10-19 16:10:53 -04:00
float worldAltitude = MBServerStatics.SEA_FLOOR_ALTITUDE;
2023-09-12 14:51:04 -04:00
2023-09-12 15:27:00 -04:00
// Seafloor
2023-10-09 04:32:57 -04:00
if (ZoneManager.seaFloor.equals(zone))
2023-10-19 16:10:53 -04:00
return worldAltitude;
2023-09-12 14:51:04 -04:00
2023-09-12 16:25:46 -04:00
// Children of seafloor
2023-09-12 15:27:00 -04:00
2023-10-07 13:57:20 -04:00
if (ZoneManager.seaFloor.equals(zone.parent))
2023-10-19 16:10:53 -04:00
return worldAltitude + zone.yOffset;
2023-09-12 15:27:00 -04:00
// return height from heightmap engine at zone location
2023-09-12 14:51:04 -04:00
2023-10-19 16:10:53 -04:00
worldAltitude = Terrain.getWorldHeight(zone.parent, zone.getLoc());
2023-09-12 14:51:04 -04:00
2023-09-12 16:24:47 -04:00
// Add zone offset to value
2023-09-13 07:29:29 -04:00
2023-10-19 16:10:53 -04:00
worldAltitude += zone.yOffset;
2023-09-12 16:24:47 -04:00
2023-10-19 16:10:53 -04:00
return worldAltitude;
2023-09-12 14:51:04 -04:00
}
2023-09-20 14:31:48 -04:00
public static boolean isLocUnderwater(Vector3fImmutable currentLoc) {
2023-10-08 09:18:43 -04:00
float localAltitude = Terrain.getWorldHeight(currentLoc);
2023-09-20 14:31:48 -04:00
Zone zone = findSmallestZone(currentLoc);
2023-10-20 17:01:42 -04:00
return localAltitude < zone.sea_level;
2023-09-20 14:31:48 -04:00
}
2022-04-30 09:41:17 -04:00
}