write global zone map system to replace earlier zone planner system
This commit is contained in:
parent
1053a74e35
commit
18add8b847
10 changed files with 501 additions and 110 deletions
|
@ -3,6 +3,8 @@ Additions:
|
|||
* **Modularization** - BuildCraft is back to being modules (asie)
|
||||
* Blocks:
|
||||
* 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:
|
||||
* Paintbrush for dyeing pipes and other supported blocks (asie)
|
||||
* Debugger for developer use (asie)
|
||||
|
|
|
@ -227,8 +227,6 @@ public class BuildCraftCore extends BuildCraftMod {
|
|||
|
||||
private static FloatBuffer pos = ByteBuffer.allocateDirect(3 * 4).asFloatBuffer();
|
||||
|
||||
public Thread serverThread;
|
||||
|
||||
@Mod.EventHandler
|
||||
public void loadConfiguration(FMLPreInitializationEvent evt) {
|
||||
BCLog.initLog();
|
||||
|
@ -443,7 +441,6 @@ public class BuildCraftCore extends BuildCraftMod {
|
|||
|
||||
@Mod.EventHandler
|
||||
public void serverStarting(FMLServerStartingEvent event) {
|
||||
serverThread = Thread.currentThread();
|
||||
event.registerServerCommand(new CommandBuildCraft());
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
package buildcraft;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
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.FMLMissingMappingsEvent;
|
||||
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.registry.EntityRegistry;
|
||||
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.recipes.BuildcraftRecipeRegistry;
|
||||
import buildcraft.api.robots.RobotManager;
|
||||
|
@ -126,6 +131,7 @@ import buildcraft.robotics.boards.BoardRobotShovelman;
|
|||
import buildcraft.robotics.boards.BoardRobotShovelmanNBT;
|
||||
import buildcraft.robotics.boards.BoardRobotStripes;
|
||||
import buildcraft.robotics.boards.BoardRobotStripesNBT;
|
||||
import buildcraft.robotics.map.MapManager;
|
||||
import buildcraft.robotics.statements.ActionRobotFilter;
|
||||
import buildcraft.robotics.statements.ActionRobotFilterTool;
|
||||
import buildcraft.robotics.statements.ActionRobotGotoStation;
|
||||
|
@ -187,6 +193,9 @@ public class BuildCraftRobotics extends BuildCraftMod {
|
|||
|
||||
public static List<String> blacklistedRobots;
|
||||
|
||||
public static MapManager manager;
|
||||
private static Thread managerThread;
|
||||
|
||||
@Mod.EventHandler
|
||||
public void preInit(FMLPreInitializationEvent evt) {
|
||||
new BCCreativeTab("boards");
|
||||
|
@ -367,6 +376,38 @@ public class BuildCraftRobotics extends BuildCraftMod {
|
|||
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
|
||||
public void processRequests(FMLInterModComms.IMCEvent event) {
|
||||
InterModComms.processIMC(event);
|
||||
|
|
|
@ -28,6 +28,7 @@ import buildcraft.api.events.BlockInteractionEvent;
|
|||
import buildcraft.core.lib.block.BlockBuildCraft;
|
||||
import buildcraft.core.GuiIds;
|
||||
import buildcraft.core.lib.utils.Utils;
|
||||
import buildcraft.robotics.map.MapWorld;
|
||||
|
||||
public class BlockZonePlan extends BlockBuildCraft {
|
||||
public BlockZonePlan() {
|
||||
|
@ -54,4 +55,23 @@ public class BlockZonePlan extends BlockBuildCraft {
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import net.minecraft.item.ItemStack;
|
|||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
|
||||
import buildcraft.BuildCraftRobotics;
|
||||
import buildcraft.api.core.SafeTimeTracker;
|
||||
import buildcraft.api.items.INamedItem;
|
||||
import buildcraft.core.ItemMapLocation;
|
||||
|
@ -32,76 +33,25 @@ public class TileZonePlan extends TileBuildCraft implements IInventory {
|
|||
private static int RESOLUTION_CHUNKS = RESOLUTION >> 4;
|
||||
|
||||
public int chunkStartX, chunkStartZ;
|
||||
public byte[] colors = new byte[RESOLUTION * RESOLUTION];
|
||||
|
||||
public short progress = 0;
|
||||
|
||||
public String mapName = "";
|
||||
|
||||
private boolean scan = false;
|
||||
private int chunkIt = 0;
|
||||
|
||||
private ZonePlan[] selectedAreas = new ZonePlan[16];
|
||||
private int currentSelectedArea = 0;
|
||||
|
||||
private SimpleInventory inv = new SimpleInventory(2, "inv", 64);
|
||||
|
||||
private SafeTimeTracker zonePlannerScanning = new SafeTimeTracker(5);
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
chunkStartX = (xCoord >> 4) - RESOLUTION_CHUNKS / 2;
|
||||
chunkStartZ = (zCoord >> 4) - RESOLUTION_CHUNKS / 2;
|
||||
|
||||
if (!scan) {
|
||||
chunkIt = 0;
|
||||
scan = true;
|
||||
}
|
||||
}
|
||||
int cx = (xCoord >> 4);
|
||||
int cz = (zCoord >> 4);
|
||||
|
||||
private int[] getCoords() {
|
||||
int chunkCenterX = xCoord >> 4;
|
||||
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};
|
||||
chunkStartX = cx - RESOLUTION_CHUNKS / 2;
|
||||
chunkStartZ = cz - RESOLUTION_CHUNKS / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -112,19 +62,6 @@ public class TileZonePlan extends TileBuildCraft implements IInventory {
|
|||
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
|
||||
&& inv.getStackInSlot(1) == null
|
||||
&& 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
|
||||
public void writeToNBT(NBTTagCompound nbt) {
|
||||
super.writeToNBT(nbt);
|
||||
|
||||
nbt.setBoolean("scan", scan);
|
||||
nbt.setInteger("chunkIt", chunkIt);
|
||||
nbt.setByteArray("colors", colors);
|
||||
nbt.setString("name", mapName);
|
||||
|
||||
NBTTagCompound invNBT = new NBTTagCompound();
|
||||
|
@ -200,21 +110,12 @@ public class TileZonePlan extends TileBuildCraft implements IInventory {
|
|||
public void readFromNBT(NBTTagCompound nbt) {
|
||||
super.readFromNBT(nbt);
|
||||
|
||||
scan = nbt.getBoolean("scan");
|
||||
chunkIt = nbt.getInteger("chunkIt");
|
||||
colors = nbt.getByteArray("colors");
|
||||
mapName = nbt.getString("name");
|
||||
|
||||
if (mapName == null) {
|
||||
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"));
|
||||
|
||||
for (int i = 0; i < selectedAreas.length; ++i) {
|
||||
|
|
|
@ -18,6 +18,7 @@ import net.minecraft.inventory.Slot;
|
|||
import cpw.mods.fml.relauncher.Side;
|
||||
|
||||
import buildcraft.BuildCraftCore;
|
||||
import buildcraft.BuildCraftRobotics;
|
||||
import buildcraft.core.lib.render.DynamicTexturePaletted;
|
||||
import buildcraft.core.ZonePlan;
|
||||
import buildcraft.core.lib.gui.BuildCraftContainer;
|
||||
|
@ -71,8 +72,7 @@ public class ContainerZonePlan extends BuildCraftContainer implements ICommandRe
|
|||
|
||||
public void saveArea(final int index) {
|
||||
BuildCraftCore.instance.sendToServer(new PacketCommand(this, "saveArea", new CommandWriter() {
|
||||
public void write(ByteBuf data) {
|
||||
data.writeByte(index);
|
||||
public void write(ByteBuf data) {data.writeByte(index);
|
||||
currentAreaSelection.writeData(data);
|
||||
}
|
||||
}));
|
||||
|
@ -129,7 +129,8 @@ public class ContainerZonePlan extends BuildCraftContainer implements ICommandRe
|
|||
int iz = z - (map.chunkStartZ << 4);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
80
common/buildcraft/robotics/map/MapChunk.java
Normal file
80
common/buildcraft/robotics/map/MapChunk.java
Normal 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;
|
||||
}
|
||||
}
|
94
common/buildcraft/robotics/map/MapManager.java
Normal file
94
common/buildcraft/robotics/map/MapManager.java
Normal 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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
62
common/buildcraft/robotics/map/MapRegion.java
Normal file
62
common/buildcraft/robotics/map/MapRegion.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
193
common/buildcraft/robotics/map/MapWorld.java
Normal file
193
common/buildcraft/robotics/map/MapWorld.java
Normal 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));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue