I am making a house plugin for my private server and I need help. When I set a house, I specify two points, each with the x, y and z. I need to count every block in between these two points and store it into a Collection. How would I do this advance operation and what Collection should I use? x1, y1, z1 is the X, Y and Z for the first point, and so on.
Some rough pseudo code to give you an idea of what you’re looking at:
/*
* We are going to assume we have some fancy Vector class, but in reality this is
* just a x, y and z coordinate set that you can recreate in many, many ways.
*/
Vector pointA = new Vector(20, 20, 20);;
Vector pointB = new Vector(40, 40, 40);
//I think Collection is an interface and not a class, but I'm too lazy to look it up.
//You would replace Collection with whatever subclass is best suited for your task.
Collection<Block> blockCollection = new Collection();
//And so the fun part begins
for (int x = pointA.getX(); x <= pointB.getX(); x++) {
for (int y = pointA.getY(); y <= pointB.getY(); y++) {
for (int z = pointA.getZ(); z <= pointB.getZ(); z++) {
//This line is about 98% pseudo code
blockCollection.add(World.getBlockAtLocation(x, y, z);
}
}
}
And if my midnight-trying-to-find-reasons-to-stay-awake self is right, that should give you a collection with every single block in between two points. There isn’t much that is more efficient than a nested for loop as far as iteration goes… If you have three dimensions to go through, it kinda just has to happen. The performance hits in this case are going to be in situations where you have thousands of blocks to iterate through at a time. Not to mention Collections aren’t quite known for being swift at setting/returning values.
I hope my thoughts are somewhat collective… I feel like I just rambled.
Edit: This is in fact horribly inefficient as stated below by others.
Why do you need to store every block? You can find the number of blocks with simple math, and check if a person is inside that area, again, with simple math. No need for a Collection of the blocks themselves.
I’m not using any Sponge code, so don’t expect to copy/paste this.
public boolean isPlayerInArea(Location a, Location b, Location playerLoc) {
int ax = a.getX(); int ay = a.getY(); int az = a.getZ();
int bx = b.getX(); int by = b.getY(); int bz = b.getZ();
int px = playerLoc.getX(); int py = playerLoc.getY(); int pz = playerLog.getZ();
return px >= ax && px <= bx && py >= ay
&& py <= by && pz >= az && pz <= bz;
}
You dont necessarily need to store the block itself; storing the block holds no purpose. Instead what you should be tracking is the points of the area where they can build, and check if their location is within those values.
Yeah idiot me didn’t think about that when I wrote that code block above. You wouldn’t be storing a horribly large collection if you just checked if a block being placed or destroyed falls within the bounds. No need to store the actual blocks anywhere unless your goal is to chew up memory and CPU time.
@frogocomics Above details how to detect if there is a location between two points, which is what you originally asked for.
Assuming that the space you’re referring to is not a rectangle, you would have to track additional points (and repeat the math suggested above for said points).
I want to make it so that when you use a command and specify two coordinates, it plugin creates with a Collection with all the coordinates. This command could be used twice, and the coordinates specified by these two commands are merged together and save to the configuration. If there is a better way to do this, please reply, email me at [email protected] or PM me.
/* Example Scenario:
* Point 1 is situated at -192, 70, 89
* Point 2 is situated at -162, 100, 105
*
* Objective: find out if something is within those points
*/
// Reminder that this is example pseudocode. The best way to store this is to instantiate a new Location or a Vector3, instead of an array of 3 values.
private int[] loc1 = new int[3] {-192, 70, 89};
private int[] loc2 = new int[3] {-162, 100, 105};
/**
* Figures out which of the two given values is the lesser
* one, and returns it.
*/
public int lowerBound(int i1, int i2) {
return i1 <= i2 ? i1 : i2;
}
/**
* Figures out which of the two given values is the greater
* one, and returns it.
*/
public int upperBound(int i1, i2} {
return i1 >= i2 ? i1 : i2;
}
/* We need the above two methods to be able to easily compare the values in order to figure out whether or not the location is within the specified boundaries. We do this by checking every axis, if the checked location's x is between the lower bound and the upper bound values of the two boundaries. */
public boolean isInArea(Location loc) {
if(loc.x < lowerBound(loc1[0], loc2[0]) || loc.x > upperBound(loc1[0], loc2[0])) {
// Here, we're checking the X axis. If the location's X is lesser than the lower boundary, or greater than the upper boundary, then we return false, since its not in between.
return false;
}
//We do the same for the other two axes.
if(loc.y < lowerBound(loc1[1], loc2[1]) || loc.x > upperBound(loc1[1], loc2[1])) {
return false;
}
if(loc.z < lowerBound(loc1[2], loc2[2]) || loc.z > upperBound(loc1[2], loc2[2])) {
return false;
}
// If the code has reached this point, then it means all above checks have passed; the location's xyz values are in between the boundaries. So we'll just return true.
return true;
}
Code is not guaranteed to work. Which you shouldn’t care about; the point of me posting examples is for you to read, understand, and learn from; not to copy and be uneducated, which’ll lead to the same question time and time again. There’re improvements on this code you can make, like replacing the int[] arrays I used to store the locations with a Location or a Vector3 object.
EDIT:
This is also gonna obviously be different for a different shape; this is for a cube area. If you were to do a polygon with no generic shape, you’ll have to figure out how checking that would work.