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.
312 lines
11 KiB
312 lines
11 KiB
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . |
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· |
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ |
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ |
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ |
|
// 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); |
|
} |
|
}
|
|
|