Jump to content

[1.7.10] [SOLVED] Get all blocks in virtual pyramid.


Recommended Posts

Posted

Hi there and thanks for looking in this thread...

My problem is: i'm trying to get all entities and blocks in world within virtual rotated pyramid (similar to AABB, but pyramidal form and is rotated), but it goes not respoding and crashes without leaving any message in console.

Here's code that i'm using:

public class PositionnedRotatedRangedVec3 {

private World worldObj;

private double posX;
private double posY;
private double posZ;

private float rotYaw;
private float rotPitch;
private float rotR;

private double range;

public PositionnedRotatedRangedVec3(World worldObj, double posX, double posY, double posZ, float rotationYaw, float rotationPitch, float rotR, double range) {
	setData(worldObj, posX, posY, posZ, rotationYaw, rotationPitch, rotR, range);
}

public void setData(World worldObj, double posX, double posY, double posZ, float rotationYaw, float rotationPitch, float rotR, double range){
	this.worldObj = worldObj;
	this.posX = posX;
	this.posY = posY;
	this.posZ = posZ;
	this.rotYaw = rotationYaw;
	this.rotPitch = rotationPitch;
	this.rotR = rotR;
	this.range = range;

	/*Vec3 vec = Vec3Utils.getLookVec(rotationYaw + rotR, rotationPitch + rotR);
	adjustX = vec.xCoord;
	adjustY = vec.yCoord;
	adjustZ = vec.zCoord;*/
}

public Set<BlockPos> getAffectedBlocks(){
	Set<BlockPos> blocks = new HashSet<BlockPos>();

	Vec3[] vecs = new Vec3[]{Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ)};

	boolean arrived = false;
	while(!arrived){
		double minX = posX;
		double minY = posY;
		double minZ = posZ;
		double maxX = posX;
		double maxY = posY;
		double maxZ = posZ;

		for(int i = 0; i < 5; i++){
			Vec3 vec = vecs[i];

			if(i == 0){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw, rotPitch);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 1){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw + rotR, rotPitch + rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 2){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw - rotR, rotPitch + rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 3){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw + rotR, rotPitch - rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 4){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw - rotR, rotPitch - rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}

			minX = Math.min(minX, vec.xCoord);
			minY = Math.min(minY, vec.yCoord);
			minZ = Math.min(minZ, vec.zCoord);

			maxX = Math.max(maxX, vec.xCoord);
			maxY = Math.max(maxY, vec.yCoord);
			maxZ = Math.max(maxZ, vec.zCoord);

			vecs[i] = vec;
		}

//			AxisAlignedBB box = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
		for(int i = (int) minX; i <= maxX; i++){
			for(int j = (int) minY; j <= maxY; j++){
				for(int k = (int) minZ; k <= maxZ; k++){
					blocks.add(new BlockPos(i, j, k));
				}
			}
		}

		if(vecs[0].distanceTo(Vec3.createVectorHelper(posX, posY, posZ)) >= range){
			arrived = true;
			break;
		}
	}

	return blocks;
}

public Set<Entity> getAffectedEntities(){
	Set<Entity> entities = new HashSet<Entity>();

	Vec3[] vecs = new Vec3[]{Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ)};

	boolean arrived = false;
	while(!arrived){
		double minX = posX;
		double minY = posY;
		double minZ = posZ;
		double maxX = posX;
		double maxY = posY;
		double maxZ = posZ;

		for(int i = 0; i < 5; i++){
			Vec3 vec = vecs[i];

			if(i == 0){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw, rotPitch);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 1){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw + rotR, rotPitch + rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 2){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw - rotR, rotPitch + rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 3){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw + rotR, rotPitch - rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 4){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw - rotR, rotPitch - rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}

			minX = Math.min(minX, vec.xCoord);
			minY = Math.min(minY, vec.yCoord);
			minZ = Math.min(minZ, vec.zCoord);

			maxX = Math.max(maxX, vec.xCoord);
			maxY = Math.max(maxY, vec.yCoord);
			maxZ = Math.max(maxZ, vec.zCoord);

			vecs[i] = vec;
		}

		AxisAlignedBB box = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
		entities.addAll(worldObj.getEntitiesWithinAABB(Entity.class, box));
	}

	return entities;
}

}

 

Let me explain here: posX, Y, Z are start point of pyramid. Rot yaw and pitch are rotations of pyramid. Rot r is angle of rotations of borders relative to central axis. And finally range is height of pyramid...

BlockPos is class, that i created to store 3 ints of position.

 

It "crashes" when enters one of 2 methods, to scan for blocks/entities...

 

So my questions are:

Is there already existing methods to do what i want, and if not - what should i use or how should i improve mine...

If it's too hard with pyramids, will it be easier with rotated BB?

 

Thanks for help, and again: if you have any questions, need some more code... - Just ask!

 

Ps: i resolved problem by adding loop break (because i forgot it :D, that's why it went not responding and never stopped :D) and changing some more code to make it pyramid.

Here's what i obtained with height 100, border degree 30:

5C1YyW1.png

Posted

I guess try running in debug mode, or add console statements to trace the execution to see if everything is executing as expected.

Okay, i modified code with console statements:

public class PositionnedRotatedRangedVec3 {

private static Logger logger = LogManager.getLogger("Pyramidal Vec3");

private World worldObj;

private double posX;
private double posY;
private double posZ;

private float rotYaw;
private float rotPitch;
private float rotR;

private double range;

public PositionnedRotatedRangedVec3(World worldObj, double posX, double posY, double posZ, float rotationYaw, float rotationPitch, float rotR, double range) {
	setData(worldObj, posX, posY, posZ, rotationYaw, rotationPitch, rotR, range);
}

public void setData(World worldObj, double posX, double posY, double posZ, float rotationYaw, float rotationPitch, float rotR, double range){
	this.worldObj = worldObj;
	this.posX = posX;
	this.posY = posY;
	this.posZ = posZ;
	this.rotYaw = rotationYaw;
	this.rotPitch = rotationPitch;
	this.rotR = rotR;
	this.range = range;

	/*Vec3 vec = Vec3Utils.getLookVec(rotationYaw + rotR, rotationPitch + rotR);
	adjustX = vec.xCoord;
	adjustY = vec.yCoord;
	adjustZ = vec.zCoord;*/
	logger.info("Created new pyramid: " + this);
}

public Set<BlockPos> getAffectedBlocks(){
	logger.info("Starting blocks section");
	Set<BlockPos> blocks = new HashSet<BlockPos>();

	Vec3[] vecs = new Vec3[]{Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ)};

	boolean arrived = false;

	logger.info("Initialized arrays and booleans, starting loop");
	while(!arrived){
		double minX = posX;
		double minY = posY;
		double minZ = posZ;
		double maxX = posX;
		double maxY = posY;
		double maxZ = posZ;

		logger.info("Updating start, values: " + minX + ", " + minY + ", " + minZ + ", " + maxX + ", " + maxY + ", " + maxZ);

		for(int i = 0; i < 5; i++){
			Vec3 vec = vecs[i];

			logger.info("Next vec: " + vec);

			if(i == 0){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw, rotPitch);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 1){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw + rotR, rotPitch + rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 2){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw - rotR, rotPitch + rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 3){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw + rotR, rotPitch - rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 4){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw - rotR, rotPitch - rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}

			minX = Math.min(minX, vec.xCoord);
			minY = Math.min(minY, vec.yCoord);
			minZ = Math.min(minZ, vec.zCoord);

			maxX = Math.max(maxX, vec.xCoord);
			maxY = Math.max(maxY, vec.yCoord);
			maxZ = Math.max(maxZ, vec.zCoord);

			logger.info("Next vec initialized: " + vec);

			vecs[i] = vec;
		}

		logger.info("Updating end, values: " + minX + ", " + minY + ", " + minZ + ", " + maxX + ", " + maxY + ", " + maxZ);

//			AxisAlignedBB box = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
		for(int i = (int) minX; i <= maxX; i++){
			for(int j = (int) minY; j <= maxY; j++){
				for(int k = (int) minZ; k <= maxZ; k++){
					logger.info("Adding next block pos: " + new BlockPos(i, j, k));
					blocks.add(new BlockPos(i, j, k));
				}
			}
		}

		logger.info("Checking for scanned distance");

		double dist = vecs[0].distanceTo(Vec3.createVectorHelper(posX, posY, posZ));

		logger.info("Distance to pass: " + range);
		logger.info("Distance passed: " + dist);

		if(dist >= range){
			logger.info("Finished scanning, breaking loop.");
			arrived = true;
			break;
		}
	}

	logger.info("Finished scanning, exited loop.");
	logger.info("Found blocks poss: " + blocks);

	return blocks;
}

public Set<Entity> getAffectedEntities(){
	Set<Entity> entities = new HashSet<Entity>();

	Vec3[] vecs = new Vec3[]{Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ), Vec3.createVectorHelper(posX, posY, posZ)};

	boolean arrived = false;
	while(!arrived){
		double minX = posX;
		double minY = posY;
		double minZ = posZ;
		double maxX = posX;
		double maxY = posY;
		double maxZ = posZ;

		for(int i = 0; i < 5; i++){
			Vec3 vec = vecs[i];

			if(i == 0){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw, rotPitch);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 1){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw + rotR, rotPitch + rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 2){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw - rotR, rotPitch + rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 3){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw + rotR, rotPitch - rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}
			if(i == 4){
				Vec3 vec2 = Vec3Utils.getLookVec(rotYaw - rotR, rotPitch - rotR);
				vec = vec.addVector(vec2.xCoord, vec2.yCoord, vec2.zCoord);
			}

			minX = Math.min(minX, vec.xCoord);
			minY = Math.min(minY, vec.yCoord);
			minZ = Math.min(minZ, vec.zCoord);

			maxX = Math.max(maxX, vec.xCoord);
			maxY = Math.max(maxY, vec.yCoord);
			maxZ = Math.max(maxZ, vec.zCoord);

			vecs[i] = vec;
		}

		AxisAlignedBB box = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
		entities.addAll(worldObj.getEntitiesWithinAABB(Entity.class, box));
	}

	return entities;
}

@Override
public String toString() {
	return "PyramidalVec3{Pos:{" + posX + ", " + posY + ", " + posZ + "}, Rot:{" + rotYaw + ", " + rotPitch + "}, Borders degree: " + rotR + ", Height: " + range + "}";
}

}

 

I'll let it run for few minutes and see what is going on...

 

 

Hmm, that's interesting, it's working fine for small range values, and for once, but maybe each tick is too much...

Nope, each tick is fine for small range values, like 5 - 10.

 

Found good lag source: print in console, trying to remove...

Let's retry with range 25.

... (Time passes, tons of tests)

 

 

Okay it seems to be laggy on range 50+, so i hope nobody will use it.

 

And also it doesn't do it in pyramidal form... Something is wrong with block detection maybe...

Nope, i need to check all calculations, and see what's wrong with vec movement.

Strange, mc uses similar code to get entity looking vec, here i'm just adding 40 degrees to it... Do you have any ideas???

Posted

Looking at your code... you are making the vector pyramid... okay.. You have a pyramid.

 

Then you turn it in a bounding box. Your pyramid is a square now.

 

Then you iterate through every block in that square and a new BlockPos to your map.

 

 

how big is your bounding box?

Its a simple matter of x * x to see how many blocks it is and how long it takes to iterate.

Like a bounding box of 25x25x25 = 15625 new Objects to create in memory, assign to a map, update map.

 

Doing that once per tick I can see how this could potentially getting laggy.

 

Lets just say for arguments sake a blockpos takes up 100 bits of space. you are creating within a tick(50ms) 1562500 bytes of data which is 190kb. which is not too bad.

Times 20 for a second its 3,72MB. which is also not too bad.

But then remember all the vectors you are creating and not cleaning up yourself. Each vector wil aslo be about 100 bits of data each, so now we have 3 vectors * 100 * 15625 = 572kb of data per tick, which is 11mb of data you are creating and discarding.

 

So our tally is already at 15mb per second roughly.

Now you are also adding it all to the hashset individually. This means the hashset has to allocate, check, add, do stuff. Which also costs memory.

 

Then you return the hashset.

 

Overall, I count this as a very expensive operation, that gets exponentially more expensive with each block larger radius(26 large Boudning box takes up 16mb per second, 30 block bounding box 25mb)

 

Now we have the garbage collector. It has to check and verify every object in the set if it's still bound, has a reference somewhere, if not, unset it. But until it does that your ram will fill up with your objects with a rate of 15-25mb the second. if not more.

 

In other words, you are giving your pc a lot of work to do, and I assume you are discarding the hashset each tick too since you are calculating each tick.

 

You are simply giving java and the garbage collector a lot of work to do in terms of memory management.

 

Wouldn' t it be more dreadfully efficient to just save the bounding box since you are returning everything within that cube wether its air or not...

 

How much wood could a woodchuck chuck if a wood chuck could chuck wood - Guybrush Treepwood

 

I wrote my own mod ish... still a few bugs to fix. http://thaumcraft.duckdns.org/downloads/MagicCookies-1.0.6.4.jar

Posted

If you read carefully through code, i'm not converting pyramid in one bounding box, but in tons of small ones that are created each tick from min and max coords written before, just to detect blocks & entities...

Here's aproximative image:

wB7a0jf.png

 

You said, that i'm not cleaning up behind me. So how do i do it? I Can't just nullifiy objects - only references will be nullified...

Posted

Ah, okay. It would still be more efficient to pass an array of bounding boxes though.

A bounding box has 6 ints to store, and you can use them as easy to loop through as you do with your blockpos set. And its more memory efficient.

Looping through and storing block posses only makes sense if you test for specific blocks. And not all blocks like you are doing now.

 

Setting to null actually does make sense. For all your vectors that you store in your array, and in the loop, set them to null when you are done.

Those are the only existing references to that object. By setting it to null you are actively saying that they are ready to be cleaned up. That way the garbage collector has a few references less to check.

 

You can also set them to final, then the gc also has an easier job to check stuff because it's not mutable. I prefer nulling stuff, then I know what state a thing is in what point in code. And nullpointer exceptions can help track variables through a maze of code if it does get passed by reference when it shouldn't.

 

You are initialising the vectors, so you can clean them up because after the method they are not needed, they are not passed on to other objects, so you can safely discard them, telling the gc it can clean them up.

 

 

Now back to your code. I would simply make an array of bounding boxes, because looking at your bounding box reference they are overlapping, so you would have a lot of overlapping spaces.

 

Then you can use the bounding boxes to calculate trails that you can iterate over.

I'm doing this from memory, so not all method names will be correct but you can get the gist.

 

//bounding boxes being the array you iterate over from your first vector set
// preinitialising ints so we only take up ten spots on the stack.
int c,x,y,z,startx,starty,startz,endx,endy,endz;
boolean escapeHatch = false;;
for(c=0;c<boundingboxes.length;c++) {
      escapeHatch = false;
      AxisAlignedBB current = boundingboxes[c];
    
      else {
           startx = current.minX < current.maxX ? current.minX : current.maxX;
           starty = current.minY < current.maxY ? current.minY : current.maxY;
           startz = current.minZ < current.maxZ ? current.minZ : current.maxZ;
           endx = current.minX > current.maxX ? current.minX : current.maxX;
           endy = current.minY > current.maxY ? current.minY : current.maxY;
           endz = current.minZ > current.maxZ ? current.minZ : current.maxZ;

           for(x=startx;x<endx;x++) {
               for(y=starty;y<endy;y++) {
                   for(z=startz;z<endz;z++) {
                         if(boundingboxes[c+1].intersectsWith(x,y,z)) {
                              // See if you will make a new object if it needs it or you simply check manually(more memory efficient)
                              //check if we intersect with the next one, which will always be larger, thus preferable I really think this one is messed up in my memory 
                             escapeHatch  = true; // let us know we need to escape!
                                 break;// continue to the preferable set. 
                         }

                        //do whatever you ultimately need to do with all the blocks. Setting a meteor on them seems fun?
                   }
              if(escapeHatch) {break;}
              }
              if(escapeHatch) {break;}
           }
          if(escapeHatch) {break;}
      }
      
}

How much wood could a woodchuck chuck if a wood chuck could chuck wood - Guybrush Treepwood

 

I wrote my own mod ish... still a few bugs to fix. http://thaumcraft.duckdns.org/downloads/MagicCookies-1.0.6.4.jar

Posted

Actually:

1) it depends on conditions of player, for block to be removed.

2) I managed to find lag problem: entities detection (blocks one doesn't cause any lag at all, with nullifying)

3) It happens because, it's iterating through everybody. There's no other way? Or there's?

Posted

Entities can be a pain yea. Is it only living entities?

 

Try worldObj.getEntitiesWithinAABB(Boundingbox)

 

That way only entities within the bounding box are selected.

I know that. I was speaking about scanning them for each bounding box is too much... And i found a  way to avoid it: in the beginning i collect all entities in range in special list, and then, in each bounding box, just checking entities from list. Like that i'm doing worldObj.getEntitiesWithinAABB(Boundingbox) only once...

 

And it works, without lag on range 25!!!

 

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.