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.
313 lines
9.1 KiB
313 lines
9.1 KiB
3 years ago
|
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||
|
// Magicbane Emulator Project © 2013 - 2022
|
||
|
// www.magicbane.com
|
||
|
|
||
|
package engine.InterestManagement;
|
||
|
|
||
|
import engine.Enum.GridObjectType;
|
||
|
import engine.math.FastMath;
|
||
|
import engine.math.Vector3f;
|
||
|
import engine.math.Vector3fImmutable;
|
||
|
import engine.net.DispatchMessage;
|
||
|
import engine.net.client.ClientConnection;
|
||
|
import engine.net.client.msg.LoadCharacterMsg;
|
||
|
import engine.net.client.msg.LoadStructureMsg;
|
||
|
import engine.net.client.msg.UnloadObjectsMsg;
|
||
|
import engine.objects.*;
|
||
|
import engine.server.MBServerStatics;
|
||
|
|
||
|
import java.util.HashSet;
|
||
|
import java.util.concurrent.ConcurrentHashMap;
|
||
|
|
||
|
|
||
|
public class WorldGrid {
|
||
|
|
||
|
public static ConcurrentHashMap<Integer,AbstractWorldObject>[][] DynamicGridMap;
|
||
|
public static ConcurrentHashMap<Integer,AbstractWorldObject>[][] StaticGridMap;
|
||
|
private static float dynamicBucketScale = 0.00390625f; // 256 bucket size, 1/256
|
||
|
private static float staticBucketScale = 0.00390625f;
|
||
|
public static void startLoadJob() {
|
||
|
|
||
|
Thread loadJobThread;
|
||
|
|
||
|
|
||
|
loadJobThread = new Thread(InterestManager.INTERESTMANAGER);
|
||
|
loadJobThread.setName("InterestManager");
|
||
|
loadJobThread.start();
|
||
|
}
|
||
|
|
||
|
public static boolean moveWorldObject(AbstractWorldObject awo, Vector3fImmutable location) {
|
||
|
awo.setLoc(location);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public static HashSet<AbstractWorldObject> getInRange(Vector3f loc, double r) {
|
||
|
HashSet<AbstractWorldObject> outbound = new HashSet<>();
|
||
|
return outbound;
|
||
|
}
|
||
|
|
||
|
public static HashSet<AbstractWorldObject> getObjectsInRangePartial(Vector3fImmutable loc, double r, int mask) {
|
||
|
HashSet<AbstractWorldObject> outbound = new HashSet<>();
|
||
|
float scale;
|
||
|
|
||
|
if ((mask & MBServerStatics.MASK_STATIC) != 0)
|
||
|
scale = WorldGrid.staticBucketScale;
|
||
|
else
|
||
|
scale = WorldGrid.dynamicBucketScale;
|
||
|
int gridX = (int) Math.abs(loc.x * scale);
|
||
|
int gridZ = (int)Math.abs(loc.z * scale);
|
||
|
int bucketSize = (int) (r *scale) + 1;
|
||
|
//start at top left most corner to scan.
|
||
|
int startingX = gridX - bucketSize;
|
||
|
int startingZ = gridZ + bucketSize;
|
||
|
|
||
|
|
||
|
|
||
|
int limitX = Math.abs((int) (MBServerStatics.MAX_WORLD_WIDTH *scale));
|
||
|
int limitZ = Math.abs((int) (MBServerStatics.MAX_WORLD_HEIGHT *scale)); //LimitZ is negative, remember to flip sign.
|
||
|
|
||
|
if (startingX < 0)
|
||
|
startingX = 0;
|
||
|
|
||
|
if (startingZ < 0)
|
||
|
startingZ = 0;
|
||
|
|
||
|
if (startingX > limitX)
|
||
|
startingX = limitX;
|
||
|
|
||
|
if (startingZ > limitZ)
|
||
|
startingZ = limitZ;
|
||
|
|
||
|
int endX = startingX + (bucketSize * 2);
|
||
|
int endZ = startingZ - (bucketSize * 2);
|
||
|
|
||
|
if (endX < 0)
|
||
|
endX = 0;
|
||
|
|
||
|
if (endZ < 0)
|
||
|
endZ = 0;
|
||
|
|
||
|
if (endX > limitX)
|
||
|
endX = limitX;
|
||
|
|
||
|
if (endZ > limitZ)
|
||
|
endZ = limitZ;
|
||
|
|
||
|
int auditMob = 0;
|
||
|
for (int x = startingX;x<=endX;x++){
|
||
|
for (int z = startingZ;z >= endZ;z--){
|
||
|
|
||
|
ConcurrentHashMap<Integer,AbstractWorldObject> gridMap;
|
||
|
|
||
|
if ((MBServerStatics.MASK_STATIC & mask) != 0)
|
||
|
gridMap = WorldGrid.StaticGridMap[x][z];
|
||
|
else
|
||
|
gridMap = WorldGrid.DynamicGridMap[x][z];
|
||
|
for (AbstractWorldObject gridObject: gridMap.values()){
|
||
|
if ((gridObject.getObjectTypeMask() & mask) == 0)
|
||
|
continue;
|
||
|
if (gridObject.getLoc().distanceSquared2D(loc) <= FastMath.sqr(r))
|
||
|
outbound.add(gridObject);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return outbound;
|
||
|
}
|
||
|
|
||
|
public static HashSet<AbstractWorldObject> getObjectsInRangePartialNecroPets(Vector3fImmutable loc, double r) {
|
||
|
HashSet<AbstractWorldObject> outbound = new HashSet<>();
|
||
|
return outbound;
|
||
|
}
|
||
|
|
||
|
public static HashSet<AbstractWorldObject> getObjectsInRangeContains(Vector3fImmutable loc, double r, int mask) {
|
||
|
HashSet<AbstractWorldObject> outbound = getObjectsInRangePartial(loc,r,mask);
|
||
|
return outbound;
|
||
|
}
|
||
|
|
||
|
public static HashSet<AbstractWorldObject> getObjectsInRangePartial(AbstractWorldObject awo, double range, int mask) {
|
||
|
return getObjectsInRangePartial(awo.getLoc(), range, mask);
|
||
|
}
|
||
|
|
||
|
|
||
|
public static void InitializeGridObjects(){
|
||
|
|
||
|
int dynamicWidth = (int) Math.abs(MBServerStatics.MAX_WORLD_WIDTH *WorldGrid.dynamicBucketScale);
|
||
|
int dynamicHeight = (int) Math.abs(MBServerStatics.MAX_WORLD_HEIGHT*WorldGrid.dynamicBucketScale);
|
||
|
|
||
|
int staticWidth = (int) Math.abs(MBServerStatics.MAX_WORLD_WIDTH *WorldGrid.staticBucketScale);
|
||
|
int staticHeight = (int) Math.abs(MBServerStatics.MAX_WORLD_HEIGHT*WorldGrid.staticBucketScale);
|
||
|
WorldGrid.DynamicGridMap = new ConcurrentHashMap[dynamicWidth+ 1][dynamicHeight + 1];
|
||
|
WorldGrid.StaticGridMap = new ConcurrentHashMap[staticWidth + 1][staticHeight + 1];
|
||
|
//create new hash maps for each bucket
|
||
|
for (int x = 0; x<= staticWidth; x++)
|
||
|
for (int y = 0; y<= staticHeight; y++){
|
||
|
WorldGrid.StaticGridMap[x][y] = new ConcurrentHashMap<Integer,AbstractWorldObject>();
|
||
|
}
|
||
|
|
||
|
for (int x = 0; x<= dynamicWidth; x++)
|
||
|
for (int y = 0; y<= dynamicHeight; y++){
|
||
|
WorldGrid.DynamicGridMap[x][y] = new ConcurrentHashMap<Integer,AbstractWorldObject>();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
public static void RemoveWorldObject(AbstractWorldObject gridObject){
|
||
|
|
||
|
if (gridObject == null)
|
||
|
return;
|
||
|
AbstractWorldObject.RemoveFromWorldGrid(gridObject);
|
||
|
}
|
||
|
|
||
|
public static boolean addObject(AbstractWorldObject gridObject, float x, float z){
|
||
|
|
||
|
if (gridObject == null)
|
||
|
return false;
|
||
|
|
||
|
if (x > MBServerStatics.MAX_WORLD_WIDTH)
|
||
|
return false;
|
||
|
|
||
|
if (z < MBServerStatics.MAX_WORLD_HEIGHT)
|
||
|
return false;
|
||
|
|
||
|
if (x < 0)
|
||
|
return false;
|
||
|
if (z > 0)
|
||
|
return false;
|
||
|
|
||
|
int gridX;
|
||
|
int gridZ;
|
||
|
|
||
|
if (gridObject.getGridObjectType().equals(GridObjectType.STATIC)){
|
||
|
gridX = Math.abs((int) (x *WorldGrid.staticBucketScale));
|
||
|
gridZ = Math.abs((int) (z*WorldGrid.staticBucketScale));
|
||
|
}else{
|
||
|
gridX = Math.abs((int) (x *WorldGrid.dynamicBucketScale));
|
||
|
gridZ = Math.abs((int) (z*WorldGrid.dynamicBucketScale));
|
||
|
}
|
||
|
|
||
|
|
||
|
WorldGrid.RemoveWorldObject(gridObject);
|
||
|
|
||
|
return AbstractWorldObject.AddToWorldGrid(gridObject, gridX, gridZ);
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
public static void unloadObject(AbstractWorldObject awo) {
|
||
|
|
||
|
UnloadObjectsMsg uom = new UnloadObjectsMsg();
|
||
|
uom.addObject(awo);
|
||
|
DispatchMessage.sendToAllInRange(awo, uom);
|
||
|
}
|
||
|
|
||
|
public static void loadObject(AbstractWorldObject awo) {
|
||
|
|
||
|
LoadStructureMsg lsm;
|
||
|
LoadCharacterMsg lcm;
|
||
|
|
||
|
switch (awo.getObjectType()) {
|
||
|
case Building:
|
||
|
lsm = new LoadStructureMsg();
|
||
|
lsm.addObject((Building)awo);
|
||
|
DispatchMessage.sendToAllInRange(awo, lsm);
|
||
|
break;
|
||
|
case NPC:
|
||
|
lcm = new LoadCharacterMsg((NPC) awo, false);
|
||
|
DispatchMessage.sendToAllInRange(awo, lcm);
|
||
|
break;
|
||
|
case Mob:
|
||
|
lcm = new LoadCharacterMsg((Mob) awo, false);
|
||
|
DispatchMessage.sendToAllInRange(awo, lcm);
|
||
|
break;
|
||
|
default:
|
||
|
// *** Refactor: Log error?
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static void loadObject(AbstractWorldObject awo, ClientConnection origin) {
|
||
|
|
||
|
LoadStructureMsg lsm;
|
||
|
LoadCharacterMsg lcm;
|
||
|
|
||
|
switch (awo.getObjectType()) {
|
||
|
|
||
|
case Building:
|
||
|
lsm = new LoadStructureMsg();
|
||
|
lsm.addObject((Building)awo);
|
||
|
DispatchMessage.sendToAllInRange(awo, lsm);
|
||
|
break;
|
||
|
case NPC:
|
||
|
lcm = new LoadCharacterMsg((NPC) awo, false);
|
||
|
DispatchMessage.sendToAllInRange(awo, lcm);
|
||
|
break;
|
||
|
case Mob:
|
||
|
lcm = new LoadCharacterMsg((Mob) awo, false);
|
||
|
DispatchMessage.sendToAllInRange(awo, lcm);
|
||
|
break;
|
||
|
case PlayerCharacter:
|
||
|
lcm = new LoadCharacterMsg((PlayerCharacter) awo, false);
|
||
|
DispatchMessage.sendToAllInRange(awo, lcm);
|
||
|
break;
|
||
|
default:
|
||
|
// *** Refactor: Log error?
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static void unloadObject(AbstractWorldObject awo,
|
||
|
ClientConnection origin) {
|
||
|
UnloadObjectsMsg uom = new UnloadObjectsMsg();
|
||
|
uom.addObject(awo);
|
||
|
DispatchMessage.sendToAllInRange(awo, uom);
|
||
|
}
|
||
|
|
||
|
public static void addObject(AbstractWorldObject awo, PlayerCharacter pc) {
|
||
|
if (pc == null || awo == null)
|
||
|
return;
|
||
|
ClientConnection origin = pc.getClientConnection();
|
||
|
if (origin == null)
|
||
|
return;
|
||
|
loadObject(awo, origin);
|
||
|
}
|
||
|
|
||
|
public static void removeObject(AbstractWorldObject awo, PlayerCharacter pc) {
|
||
|
if (pc == null || awo == null)
|
||
|
return;
|
||
|
ClientConnection origin = pc.getClientConnection();
|
||
|
if (origin == null)
|
||
|
return;
|
||
|
unloadObject(awo, origin);
|
||
|
}
|
||
|
|
||
|
public static void updateObject(AbstractWorldObject awo, PlayerCharacter pc) {
|
||
|
if (pc == null || awo == null)
|
||
|
return;
|
||
|
ClientConnection origin = pc.getClientConnection();
|
||
|
if (origin == null)
|
||
|
return;
|
||
|
unloadObject(awo, origin);
|
||
|
loadObject(awo, origin);
|
||
|
}
|
||
|
|
||
|
public static void updateObject(AbstractWorldObject awo) {
|
||
|
if (awo == null)
|
||
|
return;
|
||
|
unloadObject(awo);
|
||
|
loadObject(awo);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
public static void removeObject(AbstractWorldObject awo) {
|
||
|
if (awo == null)
|
||
|
return;
|
||
|
unloadObject(awo);
|
||
|
}
|
||
|
}
|