# getting all the blocks in a chunk

Discussion in 'Plugin Development' started by LRFLEW, Mar 1, 2011.

Not open for further replies.
1. Offline

### LRFLEW

I am trying to access all the blocks in a chunk to run through a for loop, but there is no
getBlocks() : Block[]
command . I found Chunk.getX() and Chunk.getZ(), but how would I get it?

I'm guessing the range is from
X = [getX(), getX() + C], Z = [getZ(), getZ() +C], Y = [0, 127]

Is that right? What is C?

#1
2. Offline

#2
3. Offline

### Afforess

No idea what you are planning, but I can already tell you that's a terrible, terrible, terrible idea. There are 16*16*128 (32,768 if you can't do that in your head. ) blocks in a chunk. That loop, if run even semi-often would lag the server. I expect that running it for 10, or 20 chunks would cause a 5-10 second lag.

#3
4. Offline

### LRFLEW

Not really the answer to my question, but ok.

It's more of a test/toy anyways. I would never do anything like that for a real plugin .

#4
5. Offline

### Cheesier

Then i misunderstood, so what is it that you want to do?

You could just loop thru the chunk and put it all in a 3D array, as this would be easier to manage. Getting a single block would be the way that i explained.

#5
6. Offline

### LRFLEW

If i can loop through the chunk, I wouldn't be asking . The point is that I can't figure out what blocks belong to what chunk. For any one chunk, there is getX() and getZ(), but I don't know how to then figure out the bounds of the chunk . How big is a chunk anyways?
--- merged: Mar 3, 2011 6:50 PM ---
UPDATE: by experimentation, I found the getX() and getZ() will need some sort of multiplication to get the right block. I just dont know .

#6
7. Offline

### Cheesier

A chunk is 16*128*16 (x, y, z), the chunk at a given location can be calculated by the following:
Code:
```chunkX = Math.floor(blockX / 16);
chunkZ = Math.floor(blockZ / 16);```
Or simply block.getChunk() will get you the chunk that the block is located in. (Math is more fun )

#7
8. Offline

### LRFLEW

Ok, but I was looking for the other way .

To try to make more sense:
I have a chunk! I want to run a for loop through all blocks in the chunk!
does that help?

#8
9. Offline

### Cheesier

reverse my math and get the X and Y, Like this
Code:
```blockX = 16*chunkX
blockZ = 16*chunkZ```
This should get you the coordinates of the first block, provide it with Y tho 0 is the first block.

Then just
Code:
`server.getBlockAt(blockX, 0, blockZ);`

#9
10. Offline

### LRFLEW

Ok, I thought so. I tried it, but... well... just look. The code (and yes, I used an inner class. What are you going to do about it):
Code:
```package com.LRFLEW.tnt;

import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Priority;
import org.bukkit.event.world.WorldListener;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;

public class Tnt extends JavaPlugin {

private final WorldEvents worldListener = new WorldEvents(this);

@Override
public void onDisable() {
PluginDescriptionFile pdfFile = this.getDescription();
System.out.println( pdfFile.getName() + " says Goodbye!" );
}

@Override
public void onEnable() {
// Register our events
PluginManager pm = getServer().getPluginManager();

PluginDescriptionFile pdfFile = this.getDescription();
System.out.println( pdfFile.getName() + " version " + pdfFile.getVersion() + " is enabled!" );
}

@Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
if (cmd.getName().equals("tnt") && sender instanceof Player) {
Player player = (Player)sender;
player.sendMessage(Integer.toString(player.getLocation().getBlock().getChunk().getX()).toString());
player.sendMessage(Integer.toString(player.getLocation().getBlock().getChunk().getZ()).toString());
}
return false;
}

private class WorldEvents extends WorldListener {

@SuppressWarnings("unused")
private final Tnt plugin;

public WorldEvents (Tnt instance) {
this.plugin = instance;
}

@Override
int X = event.getChunk().getX() * 16;
int Z = event.getChunk().getZ() * 16;
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
for (int y = 0; y < 128; y++) {
if (event.getWorld().getBlockAt(X+x, y, Z+z).getType().equals(Material.GLASS)) {
event.getWorld().getBlockAt(X+x, y, Z+z).setType(Material.TNT);
}
}
}
}
}

}

}```
And the console:

#10
11. Offline

### Raphfrk

The easiest way is to use the shift operator.

Code:
```int bx = chunk.getX()<<4;
int bz = chunk.getZ()<<4;

World world = event.getWorld();

for(int xx = bx; xx < bx+16; xx++) {
for(int zz = bz; zz < bz+16; zz++) {
for(int yy = 0; yy < 128; yy++) {
int typeId = world.getBlockTypeIdAt(xx, yy, zz);
if(typeId == 20) {
world.getBlockAt(xx,yy,zz).setType(Material.TNT);
}
}
}
}
```

This means you ran out of memory. Bukkit doesn't handle large scale block updates very well. The reason is that when you read a block, the server caches it. The cache ends up massive if you update a huge number of blocks.

By using:

world.getBlockTypeIdAt(x,y,z)

This method allows you to get the type of a block without updating the cache.

The cache will still be needed to be used to actually set the glass to TNT, but that should be a lot less than scanning the entire chunk.

#11
cseraphi and Premm like this.
12. Offline

### Afforess

Kinda pointless since he still needs to call block.setTypeId(), which will fill the cache just as fast.

#12
13. Offline

### Infernus

Would be quite funny to put this on a well-used server people would be like "WT* HAPPENED TO MY BUILDING ITS FILLED WITH TNT !!!!". lol

#13
14. Offline

### LRFLEW

What should I do then?

Who has grass in their house

A side note, the chunks around the spawn are never "Loaded" and hence never get called. Is there a way to figure out which chunks are part of the spawn area, even if it's just a matter of math?

#14
15. Offline

### 4am

WorldEdit seems to be able to do huge updates without breaking the cache - maybe break up your operation into multiple segments to allow the cache to clear? Or perhaps I've never made an edit big enough to cause problems...

#15
16. Offline

### Afforess

WorldEdit uses a queue to avoid slamming the server.

#16
17. Offline

### cjc343

I've made edits big enough to cause problems... on my server at least...

If it had a few more gigs of RAM, it might handle edits a tad larger.

#17
18. Offline

### LRFLEW

I don't know what kind of computer you think I'm using, but "a few more gigs" is a lot to put on one little computer
--- merged: Mar 4, 2011 4:58 AM ---
Is there some way I can force the cache to clear?

What do you mean by a queue?

#18
19. Offline

### Afforess

WorldEdit limits block changes per tick (or second, not sure), and only completes part of a change at each interval. You can grab their source.

#19
20. Offline

### LRFLEW

Once I do that, will I have to reload the chunk to get it to look right to the client?

#20
21. Offline

### Afforess

Nope. Changing a block id should force the server to send an update to the client.

#21
22. Offline

### Raphfrk

I think my suggestion would help a lot.

Your method checks every block in the chunk. This adds them all to the cache.

My suggestion checks every block using the cache bypassing method. This adds nothing to the cache. Setting the block to TNT will add just that block to the cache.

If you run this on a chunk where 1% of the blocks are glass, then it only adds 1% as many blocks to the cache.

#22
joehot2000 likes this.
23. Offline

### Infernus

Still quite funny to have TNT grass though, will be hard for miners

#23
24. Offline

### LRFLEW

Thanks. I'm going to try some of this now .

#24
25. Offline

### Afforess

Oh yep, you're correct. Need to learn to read, not skim.

#25