write global zone map system to replace earlier zone planner system

This commit is contained in:
asiekierka 2015-03-19 22:01:46 +01:00
parent 1053a74e35
commit 18add8b847
10 changed files with 501 additions and 110 deletions

View file

@ -3,6 +3,8 @@ Additions:
* **Modularization** - BuildCraft is back to being modules (asie) * **Modularization** - BuildCraft is back to being modules (asie)
* Blocks: * Blocks:
* Blueprint Library renamed to Electronic Library, supports copying books - and soon other things! (asie) * Blueprint Library renamed to Electronic Library, supports copying books - and soon other things! (asie)
* Rewritten Zone Planner map system - should have much less lag and take up less disk space!
* **Note** - all existing zone planner previews will disappear. To reload them, simply break and place the zone planner!
* Items: * Items:
* Paintbrush for dyeing pipes and other supported blocks (asie) * Paintbrush for dyeing pipes and other supported blocks (asie)
* Debugger for developer use (asie) * Debugger for developer use (asie)

View file

@ -227,8 +227,6 @@ public class BuildCraftCore extends BuildCraftMod {
private static FloatBuffer pos = ByteBuffer.allocateDirect(3 * 4).asFloatBuffer(); private static FloatBuffer pos = ByteBuffer.allocateDirect(3 * 4).asFloatBuffer();
public Thread serverThread;
@Mod.EventHandler @Mod.EventHandler
public void loadConfiguration(FMLPreInitializationEvent evt) { public void loadConfiguration(FMLPreInitializationEvent evt) {
BCLog.initLog(); BCLog.initLog();
@ -443,7 +441,6 @@ public class BuildCraftCore extends BuildCraftMod {
@Mod.EventHandler @Mod.EventHandler
public void serverStarting(FMLServerStartingEvent event) { public void serverStarting(FMLServerStartingEvent event) {
serverThread = Thread.currentThread();
event.registerServerCommand(new CommandBuildCraft()); event.registerServerCommand(new CommandBuildCraft());
} }

View file

@ -8,6 +8,7 @@
*/ */
package buildcraft; package buildcraft;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -22,9 +23,13 @@ import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLInterModComms; import cpw.mods.fml.common.event.FMLInterModComms;
import cpw.mods.fml.common.event.FMLMissingMappingsEvent; import cpw.mods.fml.common.event.FMLMissingMappingsEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.event.FMLServerStartingEvent;
import cpw.mods.fml.common.event.FMLServerStoppingEvent;
import cpw.mods.fml.common.network.NetworkRegistry; import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.registry.EntityRegistry; import cpw.mods.fml.common.registry.EntityRegistry;
import cpw.mods.fml.common.registry.GameRegistry; import cpw.mods.fml.common.registry.GameRegistry;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.MinecraftForge;
import buildcraft.api.boards.RedstoneBoardRegistry; import buildcraft.api.boards.RedstoneBoardRegistry;
import buildcraft.api.recipes.BuildcraftRecipeRegistry; import buildcraft.api.recipes.BuildcraftRecipeRegistry;
import buildcraft.api.robots.RobotManager; import buildcraft.api.robots.RobotManager;
@ -126,6 +131,7 @@ import buildcraft.robotics.boards.BoardRobotShovelman;
import buildcraft.robotics.boards.BoardRobotShovelmanNBT; import buildcraft.robotics.boards.BoardRobotShovelmanNBT;
import buildcraft.robotics.boards.BoardRobotStripes; import buildcraft.robotics.boards.BoardRobotStripes;
import buildcraft.robotics.boards.BoardRobotStripesNBT; import buildcraft.robotics.boards.BoardRobotStripesNBT;
import buildcraft.robotics.map.MapManager;
import buildcraft.robotics.statements.ActionRobotFilter; import buildcraft.robotics.statements.ActionRobotFilter;
import buildcraft.robotics.statements.ActionRobotFilterTool; import buildcraft.robotics.statements.ActionRobotFilterTool;
import buildcraft.robotics.statements.ActionRobotGotoStation; import buildcraft.robotics.statements.ActionRobotGotoStation;
@ -187,6 +193,9 @@ public class BuildCraftRobotics extends BuildCraftMod {
public static List<String> blacklistedRobots; public static List<String> blacklistedRobots;
public static MapManager manager;
private static Thread managerThread;
@Mod.EventHandler @Mod.EventHandler
public void preInit(FMLPreInitializationEvent evt) { public void preInit(FMLPreInitializationEvent evt) {
new BCCreativeTab("boards"); new BCCreativeTab("boards");
@ -367,6 +376,38 @@ public class BuildCraftRobotics extends BuildCraftMod {
BuildcraftRecipeRegistry.integrationTable.addRecipe(new RobotIntegrationRecipe("buildcraft:robotIntegration")); BuildcraftRecipeRegistry.integrationTable.addRecipe(new RobotIntegrationRecipe("buildcraft:robotIntegration"));
} }
@Mod.EventHandler
public void serverUnload(FMLServerStoppingEvent event) {
if (managerThread != null) {
manager.stop();
manager.saveAllWorlds();
managerThread.interrupt();
MinecraftForge.EVENT_BUS.unregister(manager);
}
managerThread = null;
manager = null;
}
@Mod.EventHandler
public void serverLoad(FMLServerStartingEvent event) {
File f = new File(DimensionManager.getCurrentSaveRootDirectory(), "buildcraft/zonemap");
try {
f.mkdirs();
} catch (Exception e) {
e.printStackTrace();
}
manager = new MapManager(f);
managerThread = new Thread(manager);
managerThread.start();
MinecraftForge.EVENT_BUS.register(manager);
}
@Mod.EventHandler @Mod.EventHandler
public void processRequests(FMLInterModComms.IMCEvent event) { public void processRequests(FMLInterModComms.IMCEvent event) {
InterModComms.processIMC(event); InterModComms.processIMC(event);

View file

@ -28,6 +28,7 @@ import buildcraft.api.events.BlockInteractionEvent;
import buildcraft.core.lib.block.BlockBuildCraft; import buildcraft.core.lib.block.BlockBuildCraft;
import buildcraft.core.GuiIds; import buildcraft.core.GuiIds;
import buildcraft.core.lib.utils.Utils; import buildcraft.core.lib.utils.Utils;
import buildcraft.robotics.map.MapWorld;
public class BlockZonePlan extends BlockBuildCraft { public class BlockZonePlan extends BlockBuildCraft {
public BlockZonePlan() { public BlockZonePlan() {
@ -54,4 +55,23 @@ public class BlockZonePlan extends BlockBuildCraft {
return true; return true;
} }
@Override
public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase entity, ItemStack stack) {
super.onBlockPlacedBy(world, x, y, z, entity, stack);
if (!world.isRemote) {
int r = TileZonePlan.RESOLUTION >> 4;
int cox = (x >> 4);
int coz = (z >> 4);
MapWorld w = BuildCraftRobotics.manager.getWorld(world);
for (int cx = -r; cx < r; cx++) {
for (int cz = -r; cz < r; cz++) {
int dist = cx * cx + cz * cz;
w.queueChunkForUpdateIfEmpty(cox + cx, coz + cz, dist);
}
}
}
}
} }

View file

@ -17,6 +17,7 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import buildcraft.BuildCraftRobotics;
import buildcraft.api.core.SafeTimeTracker; import buildcraft.api.core.SafeTimeTracker;
import buildcraft.api.items.INamedItem; import buildcraft.api.items.INamedItem;
import buildcraft.core.ItemMapLocation; import buildcraft.core.ItemMapLocation;
@ -32,76 +33,25 @@ public class TileZonePlan extends TileBuildCraft implements IInventory {
private static int RESOLUTION_CHUNKS = RESOLUTION >> 4; private static int RESOLUTION_CHUNKS = RESOLUTION >> 4;
public int chunkStartX, chunkStartZ; public int chunkStartX, chunkStartZ;
public byte[] colors = new byte[RESOLUTION * RESOLUTION];
public short progress = 0; public short progress = 0;
public String mapName = ""; public String mapName = "";
private boolean scan = false;
private int chunkIt = 0;
private ZonePlan[] selectedAreas = new ZonePlan[16]; private ZonePlan[] selectedAreas = new ZonePlan[16];
private int currentSelectedArea = 0; private int currentSelectedArea = 0;
private SimpleInventory inv = new SimpleInventory(2, "inv", 64); private SimpleInventory inv = new SimpleInventory(2, "inv", 64);
private SafeTimeTracker zonePlannerScanning = new SafeTimeTracker(5);
@Override @Override
public void initialize() { public void initialize() {
super.initialize(); super.initialize();
chunkStartX = (xCoord >> 4) - RESOLUTION_CHUNKS / 2;
chunkStartZ = (zCoord >> 4) - RESOLUTION_CHUNKS / 2;
if (!scan) { int cx = (xCoord >> 4);
chunkIt = 0; int cz = (zCoord >> 4);
scan = true;
}
}
private int[] getCoords() { chunkStartX = cx - RESOLUTION_CHUNKS / 2;
int chunkCenterX = xCoord >> 4; chunkStartZ = cz - RESOLUTION_CHUNKS / 2;
int chunkCenterZ = zCoord >> 4;
if (chunkIt == 0) {
return new int[] {chunkCenterX, chunkCenterZ};
}
int radius = 1;
int left = chunkIt;
while (radius < RESOLUTION_CHUNKS / 2) {
int lineLength = radius * 2;
int perimeter = lineLength * 4;
if (left <= perimeter) {
int chunkX = 0, chunkZ = 0;
int remained = (left - 1) % lineLength;
if ((left - 1) / lineLength == 0) {
chunkX = chunkCenterX + radius;
chunkZ = chunkCenterZ - lineLength / 2 + remained;
} else if ((left - 1) / lineLength == 1) {
chunkX = chunkCenterX - radius;
chunkZ = chunkCenterZ - lineLength / 2 + remained + 1;
} else if ((left - 1) / lineLength == 2) {
chunkX = chunkCenterX - lineLength / 2 + remained + 1;
chunkZ = chunkCenterZ + radius;
} else {
chunkX = chunkCenterX - lineLength / 2 + remained;
chunkZ = chunkCenterZ - radius;
}
return new int[] {chunkX, chunkZ};
} else {
left -= perimeter;
}
radius += 1;
}
return new int[] {chunkCenterX, chunkCenterZ};
} }
@Override @Override
@ -112,19 +62,6 @@ public class TileZonePlan extends TileBuildCraft implements IInventory {
return; return;
} }
if (scan && zonePlannerScanning.markTimeIfDelay(worldObj)) {
int[] coords = getCoords();
Chunk chunk = worldObj.getChunkFromChunkCoords(coords[0], coords[1]);
loadChunk(chunk);
if (chunkIt > RESOLUTION_CHUNKS * RESOLUTION_CHUNKS) {
scan = false;
chunkIt = 0;
} else {
chunkIt++;
}
}
if (inv.getStackInSlot(0) != null if (inv.getStackInSlot(0) != null
&& inv.getStackInSlot(1) == null && inv.getStackInSlot(1) == null
&& inv.getStackInSlot(0).getItem() instanceof ItemMapLocation) { && inv.getStackInSlot(0).getItem() instanceof ItemMapLocation) {
@ -151,36 +88,9 @@ public class TileZonePlan extends TileBuildCraft implements IInventory {
} }
} }
private void loadChunk(Chunk chunk) {
for (int cx = 0; cx < 16; ++cx) {
for (int cz = 0; cz < 16; ++cz) {
int x = (chunk.xPosition << 4) + cx;
int z = (chunk.zPosition << 4) + cz;
int y = getWorldObj().getHeightValue(x, z);
int color;
while ((color = chunk.getBlock(cx, y, cz).getMapColor(0).colorIndex) == MapColor.airColor.colorIndex) {
y--;
if (y < 0) {
break;
}
}
int ix = x - chunkStartX * 16;
int iz = z - chunkStartZ * 16;
colors[ix + iz * RESOLUTION] = (byte) color;
}
}
}
@Override @Override
public void writeToNBT(NBTTagCompound nbt) { public void writeToNBT(NBTTagCompound nbt) {
super.writeToNBT(nbt); super.writeToNBT(nbt);
nbt.setBoolean("scan", scan);
nbt.setInteger("chunkIt", chunkIt);
nbt.setByteArray("colors", colors);
nbt.setString("name", mapName); nbt.setString("name", mapName);
NBTTagCompound invNBT = new NBTTagCompound(); NBTTagCompound invNBT = new NBTTagCompound();
@ -200,21 +110,12 @@ public class TileZonePlan extends TileBuildCraft implements IInventory {
public void readFromNBT(NBTTagCompound nbt) { public void readFromNBT(NBTTagCompound nbt) {
super.readFromNBT(nbt); super.readFromNBT(nbt);
scan = nbt.getBoolean("scan");
chunkIt = nbt.getInteger("chunkIt");
colors = nbt.getByteArray("colors");
mapName = nbt.getString("name"); mapName = nbt.getString("name");
if (mapName == null) { if (mapName == null) {
mapName = ""; mapName = "";
} }
if (colors.length != RESOLUTION * RESOLUTION || chunkIt >= RESOLUTION_CHUNKS * RESOLUTION_CHUNKS) {
colors = new byte[RESOLUTION * RESOLUTION];
scan = true;
chunkIt = 0;
}
inv.readFromNBT(nbt.getCompoundTag("inv")); inv.readFromNBT(nbt.getCompoundTag("inv"));
for (int i = 0; i < selectedAreas.length; ++i) { for (int i = 0; i < selectedAreas.length; ++i) {

View file

@ -18,6 +18,7 @@ import net.minecraft.inventory.Slot;
import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.Side;
import buildcraft.BuildCraftCore; import buildcraft.BuildCraftCore;
import buildcraft.BuildCraftRobotics;
import buildcraft.core.lib.render.DynamicTexturePaletted; import buildcraft.core.lib.render.DynamicTexturePaletted;
import buildcraft.core.ZonePlan; import buildcraft.core.ZonePlan;
import buildcraft.core.lib.gui.BuildCraftContainer; import buildcraft.core.lib.gui.BuildCraftContainer;
@ -71,8 +72,7 @@ public class ContainerZonePlan extends BuildCraftContainer implements ICommandRe
public void saveArea(final int index) { public void saveArea(final int index) {
BuildCraftCore.instance.sendToServer(new PacketCommand(this, "saveArea", new CommandWriter() { BuildCraftCore.instance.sendToServer(new PacketCommand(this, "saveArea", new CommandWriter() {
public void write(ByteBuf data) { public void write(ByteBuf data) {data.writeByte(index);
data.writeByte(index);
currentAreaSelection.writeData(data); currentAreaSelection.writeData(data);
} }
})); }));
@ -129,7 +129,8 @@ public class ContainerZonePlan extends BuildCraftContainer implements ICommandRe
int iz = z - (map.chunkStartZ << 4); int iz = z - (map.chunkStartZ << 4);
if (ix >= 0 && iz >= 0 && ix < TileZonePlan.RESOLUTION && iz < TileZonePlan.RESOLUTION) { if (ix >= 0 && iz >= 0 && ix < TileZonePlan.RESOLUTION && iz < TileZonePlan.RESOLUTION) {
textureData[i + j * width] = map.colors[ix + iz * TileZonePlan.RESOLUTION]; textureData[i + j * width] = (byte) BuildCraftRobotics.manager.getWorld(map.getWorldObj())
.getColor(x, z);
} }
} }
} }

View file

@ -0,0 +1,80 @@
package buildcraft.robotics.map;
import net.minecraft.block.material.MapColor;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.chunk.Chunk;
import buildcraft.api.core.BCLog;
public class MapChunk {
private static final int VERSION = 1;
private int x, z;
private byte[] data;
public MapChunk(int x, int y) {
this.x = x;
this.z = z;
data = new byte[256];
}
public MapChunk(NBTTagCompound compound) {
readFromNBT(compound);
}
public int getX() {
return x;
}
public int getZ() {
return z;
}
public int getColor(int x, int z) {
return (int) data[((z & 15) << 4) | (x & 15)];
}
public void update(Chunk chunk) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int y = chunk.getHeightValue(x, z);
int color;
while ((color = chunk.getBlock(x, y, z).getMapColor(0).colorIndex) == MapColor.airColor.colorIndex) {
y--;
if (y < 0) {
break;
}
}
data[(z << 4) | x] = (byte) color;
}
}
}
public void readFromNBT(NBTTagCompound compound) {
int version = compound.getShort("version");
if (version > MapChunk.VERSION) {
BCLog.logger.error("Unsupported MapChunk version: " + version);
return;
}
x = compound.getInteger("x");
z = compound.getInteger("z");
data = compound.getByteArray("data");
if (data.length != 256) {
BCLog.logger.error("Invalid MapChunk data length: " + data.length);
data = new byte[256];
}
}
public void writeToNBT(NBTTagCompound compound) {
compound.setShort("version", (short) VERSION);
compound.setInteger("x", x);
compound.setInteger("z", z);
compound.setByteArray("data", data);
}
@Override
public int hashCode() {
return 31 * x + z;
}
}

View file

@ -0,0 +1,94 @@
package buildcraft.robotics.map;
import java.io.File;
import java.util.Date;
import com.google.common.collect.HashBiMap;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.event.world.ChunkEvent;
public class MapManager implements Runnable {
private final HashBiMap<World, MapWorld> worldMap = HashBiMap.create();
private final File location;
private boolean stop = false;
private long lastSaveTime;
public MapManager(File location) {
this.location = location;
}
public void stop() {
stop = true;
}
public MapWorld getWorld(World world) {
if (world.isRemote) {
return null;
}
if (!worldMap.containsKey(world)) {
worldMap.put(world, new MapWorld(world, location));
}
return worldMap.get(world);
}
@SubscribeEvent
public void chunkLoaded(ChunkEvent.Load event) {
MapWorld world = getWorld(event.getChunk().worldObj);
if (world != null) {
world.queueChunkForUpdateIfEmpty(event.getChunk().xPosition, event.getChunk().zPosition, 99999);
}
}
@SubscribeEvent
public void blockPlaced(BlockEvent.PlaceEvent placeEvent) {
Chunk chunk = placeEvent.world.getChunkFromBlockCoords(placeEvent.x, placeEvent.z);
MapWorld world = getWorld(placeEvent.world);
if (world != null) {
world.queueChunkForUpdate(chunk.xPosition, chunk.zPosition, 512);
}
}
@SubscribeEvent
public void blockBroken(BlockEvent.BreakEvent placeEvent) {
Chunk chunk = placeEvent.world.getChunkFromBlockCoords(placeEvent.x, placeEvent.z);
MapWorld world = getWorld(placeEvent.world);
if (world != null) {
world.queueChunkForUpdate(chunk.xPosition, chunk.zPosition, 512);
}
}
public void saveAllWorlds() {
for (MapWorld world : worldMap.values()) {
world.save();
}
}
@Override
public void run() {
lastSaveTime = (new Date()).getTime();
while (!stop) {
for (MapWorld world : worldMap.values()) {
world.updateChunkInQueue();
}
long now = (new Date()).getTime();
if (now - lastSaveTime > 120000) {
saveAllWorlds();
lastSaveTime = now;
}
try {
Thread.sleep(50 * worldMap.size());
} catch (Exception e) {
}
}
}
}

View file

@ -0,0 +1,62 @@
package buildcraft.robotics.map;
import gnu.trove.map.hash.TIntObjectHashMap;
import net.minecraft.nbt.NBTTagCompound;
import buildcraft.api.core.INBTStoreable;
public class MapRegion implements INBTStoreable {
private final TIntObjectHashMap<MapChunk> chunks = new TIntObjectHashMap<MapChunk>();
private final int x, z;
public MapRegion(int x, int z) {
this.x = x;
this.z = z;
}
public int getX() {
return x;
}
public int getZ() {
return z;
}
public boolean hasChunk(int x, int z) {
return chunks.contains((z << 4) | x);
}
public MapChunk getChunk(int x, int z) {
int id = (z << 4) | x;
MapChunk chunk = chunks.get(id);
if (chunk == null) {
chunk = new MapChunk(x, z);
chunks.put(id, chunk);
}
return chunk;
}
@Override
public void readFromNBT(NBTTagCompound tag) {
chunks.clear();
for (int i = 0; i < 256; i++) {
if (tag.hasKey("r" + i)) {
MapChunk chunk = new MapChunk(tag.getCompoundTag("r" + i));
chunks.put(i, chunk);
}
}
}
@Override
public void writeToNBT(NBTTagCompound tag) {
for (int i = 0; i < 256; i++) {
MapChunk chunk = chunks.get(i);
if (chunk != null) {
NBTTagCompound chunkNBT = new NBTTagCompound();
chunk.writeToNBT(chunkNBT);
tag.setTag("r" + i, chunkNBT);
}
}
}
}

View file

@ -0,0 +1,193 @@
package buildcraft.robotics.map;
import gnu.trove.iterator.TLongIterator;
import gnu.trove.map.hash.TLongObjectHashMap;
import gnu.trove.set.hash.TLongHashSet;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Set;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import buildcraft.core.lib.utils.NBTUtils;
public class MapWorld {
private final World world;
private final TLongObjectHashMap<MapRegion> regionMap;
private final Set<QueuedXZ> regionUpdateSet = new HashSet<QueuedXZ>();
private final Queue<QueuedXZ> queuedChunks;
private final File location;
private long lastForcedChunkLoad;
private class QueuedXZ {
int x, z, p;
QueuedXZ(int x, int z, int p) {
this.x = x;
this.z = z;
this.p = p;
}
@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof QueuedXZ)) {
return false;
}
return ((QueuedXZ) other).x == x && ((QueuedXZ) other).z == z;
}
@Override
public int hashCode() {
return x * 31 + z;
}
}
public MapWorld(World world, File location) {
this.world = world;
regionMap = new TLongObjectHashMap<MapRegion>();
queuedChunks = new PriorityQueue<QueuedXZ>(new Comparator<QueuedXZ>() {
@Override
public int compare(QueuedXZ c1, QueuedXZ c2) {
return c1.p - c2.p;
}
});
String saveFolder = world.provider.getSaveFolder();
if (saveFolder == null) {
saveFolder = "world";
}
this.location = new File(location, saveFolder);
try {
this.location.mkdirs();
} catch (Exception e) {
e.printStackTrace();
}
}
private long getXzId(int x, int z) {
return (x << 24) | z;
}
private MapRegion getRegion(int x, int z) {
long id = getXzId(x, z);
MapRegion region = regionMap.get(id);
if (region == null) {
region = new MapRegion(x, z);
// Check in the location first
File target = new File(location, "r" + x + "," + z + ".nbt");
if (target.exists()) {
try {
FileInputStream f = new FileInputStream(target);
byte [] data = new byte [(int) target.length()];
f.read(data);
f.close();
region.readFromNBT(NBTUtils.load(data));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
regionMap.put(id, region);
}
return region;
}
private MapChunk getChunk(int x, int z) {
MapRegion region = getRegion(x >> 4, z >> 4);
return region.getChunk(x & 15, z & 15);
}
public boolean hasChunk(int x, int z) {
MapRegion region = getRegion(x >> 4, z >> 4);
return region.hasChunk(x & 15, z & 15);
}
public void queueChunkForUpdate(int x, int z, int priority) {
long id = getXzId(x, z);
queuedChunks.add(new QueuedXZ(x, z, priority));
}
public void queueChunkForUpdateIfEmpty(int x, int z, int priority) {
if (!hasChunk(x, z)) {
queueChunkForUpdate(x, z, priority);
}
}
public void updateChunkInQueue() {
if (queuedChunks.size() == 0) {
return;
}
QueuedXZ q = queuedChunks.remove();
if (q == null) {
return;
}
if (!world.getChunkProvider().chunkExists(q.x, q.z)) {
long now = (new Date()).getTime();
if (now - lastForcedChunkLoad < 5000) {
q.p++; // Increase priority so it gets looked at later
queuedChunks.add(q);
return;
} else {
lastForcedChunkLoad = now;
}
}
updateChunk(q.x, q.z);
}
public void save() {
Iterator<QueuedXZ> i = regionUpdateSet.iterator();
while (i.hasNext()) {
QueuedXZ id = i.next();
i.remove();
MapRegion region = regionMap.get(getXzId(id.x, id.z));
if (region == null) {
continue;
}
NBTTagCompound output = new NBTTagCompound();
region.writeToNBT(output);
byte[] data = NBTUtils.save(output);
File file = new File(location, "r" + id.x + "," + id.z + ".nbt");
try {
FileOutputStream f = new FileOutputStream(file);
f.write(data);
f.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public int getColor(int x, int z) {
MapChunk chunk = getChunk(x >> 4, z >> 4);
return chunk.getColor(x & 15, z & 15);
}
protected void updateChunk(int x, int z) {
MapChunk chunk = getChunk(x, z);
chunk.update(world.getChunkFromChunkCoords(x, z));
regionUpdateSet.add(new QueuedXZ(x >> 4, z >> 4, 0));
// priority does not matter - see equals
queuedChunks.remove(new QueuedXZ(x, z, 0));
}
}