Trying to make a minecraft plugin here. I am trying to make a custom ore generator. The generator is cube, it has no exterior walls on the outside and the middle is filled with ores.
When I create a generator I don't save every single location object because every player can have multiple generator and that would be a massive amount of blocks in no time. What I do instead is that I save the min and max location for the border and for that inside cube(Why save both for border and cube? Well I'll explain in a bit) in a Object called CubeLocation that also stores the cubeId.
So I save the cubes in a HashMap<UUID, PlayerCube> - (This is not the id of a player, but i generate a random uuid when creating each code).
And I also save the Location in a HashSet <CubeLocation
Now for my problem. I need to check if the location of the broken block is inside a cube. What I have at the moment is something like this
public class LocationManager {
private HashMap<UUID, PlayerCube> cubes;
private HashSet<CubeLocation> cubeLocations;
private HashMap<UUID, PlayerHold> playerHolds;
private HashMap<UUID, Integer> tasks;
private HashMap<UUID, UUID> lastKnownGenerator;
public LocationManager() {
cubes = new HashMap<>();
cubeLocations = new HashSet<>();
playerHolds = new HashMap<>();
tasks = new HashMap<>();
lastKnownGenerator = new HashMap<>();
}
public HashMap<UUID, PlayerCube> getCubes(){
return cubes;
}
public HashSet<CubeLocation> getCubeLocations(){
return cubeLocations;
}
public HashMap<UUID, PlayerHold> getPlayerHolds(){
return playerHolds;
}
public HashMap<UUID, Integer> getTasks(){
return tasks;
}
public HashMap<UUID, UUID> getLastKnownGenerator(){
return lastKnownGenerator;
}
public String[] isLocationInsideCube(UUID player, Location loc) {
UUID world = loc.getWorld().getUID();
int x = loc.getBlockX();
int y = loc.getBlockY();
int z = loc.getBlockZ();
String arr[] = {null, null};
UUID last = lastKnownGenerator.get(player);
if(last != null) {
CubeLocation cubeLoc = cubes.get(last).getCubeLocation();
lastKnownGenerator.remove(player);
if(cubeLoc != null && cubeLoc.isInside(world, x, y, z)) {
if(cubeLoc.isCubeLocation(world, x, y, z)) {
arr[1] = last.toString();
return arr;
}
if(arr[0] == null && cubeLoc.isBorderLocation(world, x, y, z)) {
arr[0] = last.toString();
return arr;
}
}
}
for(CubeLocation cubeLoc : cubeLocations) {
if(!cubeLoc.isInside(world, x, y, z))
continue;
String id = cubeLoc.getCubeId().toString();
if(arr[1] == null && cubeLoc.isCubeLocation(world, x, y, z)) {
arr[1] = id;
break;
}
if(arr[0] == null && cubeLoc.isBorderLocation(world, x, y, z)) {
arr[0] = id;
break;
}
}
return arr;
}
}
And this is CubeLocation
public class CubeLocation {
private UUID world;
private int minX;
private int maxX;
private int minY;
private int maxY;
private int minZ;
private int maxZ;
private int bMinX;
private int bMaxX;
private int bMinY;
private int bMaxY;
private int bMinZ;
private int bMaxZ;
private UUID cubeId;
public CubeLocation(UUID world, UUID cubeId) {
this.world = world;
this.cubeId = cubeId;
}
public void setCoords(int x1, int x2, int y1, int y2, int z1, int z2) {
//Border
this.bMinX = x1;
this.bMaxX = x2;
this.bMinY = y1;
this.bMaxY = y2;
this.bMinZ = z1;
this.bMaxZ = z2;
//Cube
this.minX = x1 + 1;
this.maxX = x2 - 1;
this.minY = y1 + 1;
this.maxY = y2 - 1;
this.minZ = z1 + 1;
this.maxZ = z2 - 1;
}
public UUID getCubeId() {
return cubeId;
}
public boolean isInside(UUID world, int x, int y, int z) {
if(!world.equals(this.world))
return false;
return (x >= bMinX && x <= bMaxX) && (y >= bMinY && y <= bMaxY) && (z >= bMinZ && z <= bMaxZ);
}
public boolean isBorderLocation(UUID world, int x, int y, int z) {
if(!world.equals(this.world))
return false;
if(y == bMinY || y == bMaxY) {
return (x == bMinX && (z >= bMinZ || z <= bMaxZ)) || (x == bMaxX && (z >= bMinZ || z <= bMaxZ)) || (z == bMinZ && (x >= bMinX || x <= bMaxX)) || (z == bMaxZ && (x >= bMinX || x <= bMaxX));
}
return (x == bMinX && z == bMinZ) || (x == bMaxX && z == bMinZ) || (x == bMinX && z == bMaxZ) || (x == bMaxX && z == bMaxZ);
}
public boolean isCubeLocation(UUID world, int x, int y, int z) {
if(!world.equals(this.world))
return false;
return (x >= minX && x <= maxX) && (y >= minY && y <= maxY) && (z >= minZ && z <= maxZ);
}
}
This was also why I saved the border separate from the cube. Because I don't want the player to be able to break the border itself but also leave not take the walls into account(Anyways this isn't the problem but I wanted to explain that).
The problem is that every time a block is broken it will check each and every single CubeLocation to check if the location is a generator. That means that every time a block is broken it will do this check every single time (This is why I added the lastKnownGenerator, it'll first check this to see if the player is breaking blocks in the same generator so it doesn't have to do the loop again).
However this does not help if the player breaks blocks that are not inside a generator (For example in a mine, a house or idk) it will do the loop for every single broken block. And this is not even the worst part, the worst part is that BlockBreakEvent (The event that triggers when a player breaks a block) can be trigger dozens of times per second by a single player (If you have enchants on your pickaxe, shovel or axe) and not only that but it can be triggered by multiple players at once.
So image this, there have been like 30k cube placed on the world in total and there are like 30 players with full enchant minning 20 blocks per second each. The means that every second the plugin checks 600k coords per second. This won't do, it's too wasteful.
You also can't save each and every location separate or mark a block with block.setMetadata(key, FixedMetadataValue(plugin, value)); Because you would have to loop through (Let's say all the generator in our case are 11x11x11 which is 1331 per generator) 30.000 * 1331 which is a whopping 39.930.000 blocks so it's even worse than what I'm doing.
What would be the appropriate method to save the cubes and also check if the broken block is inside a cube. Am I completely wrong with what I was trying to do? Any and all suggestion are welcome!