Merge pull request #57 from psxlover/PathMarkersOptimization

Path markers optimization
This commit is contained in:
SirSengir 2012-06-14 13:20:49 -07:00
commit e1d4cf14a8
6 changed files with 112 additions and 151 deletions

View file

@ -40,6 +40,7 @@ import net.minecraft.src.buildcraft.builders.BlockFiller;
import net.minecraft.src.buildcraft.builders.BlockMarker;
import net.minecraft.src.buildcraft.builders.BlockPathMarker;
import net.minecraft.src.buildcraft.builders.BptBlockFiller;
import net.minecraft.src.buildcraft.builders.BuildersSaveManager;
import net.minecraft.src.buildcraft.builders.FillerFillAll;
import net.minecraft.src.buildcraft.builders.FillerFillPyramid;
import net.minecraft.src.buildcraft.builders.FillerFillStairs;
@ -61,7 +62,6 @@ import net.minecraft.src.buildcraft.core.BptPlayerIndex;
import net.minecraft.src.buildcraft.core.BptRootIndex;
import net.minecraft.src.buildcraft.core.CoreProxy;
import net.minecraft.src.buildcraft.core.DefaultProps;
import net.minecraft.src.buildcraft.core.WorldIteratorRadius;
import net.minecraft.src.forge.Configuration;
import net.minecraft.src.forge.MinecraftForge;
import net.minecraft.src.forge.Property;
@ -96,6 +96,9 @@ public class BuildCraftBuilders {
// Register gui handler
MinecraftForge.setGuiHandler(mod_BuildCraftBuilders.instance, new GuiHandler());
// Register save handler
MinecraftForge.registerSaveHandler(new BuildersSaveManager());
}
public static void initialize() {
@ -277,9 +280,6 @@ public class BuildCraftBuilders {
new BptBlockWallSide(pathMarkerBlock.blockID);
new BptBlockFiller(fillerBlock.blockID);
// Optimization
WorldIteratorRadius.createPrecomputedList(TilePathMarker.searchSize);
if (BuildCraftCore.loadDefaultRecipes)
loadRecipes();
}

View file

@ -42,7 +42,7 @@ public class BlockPathMarker extends BlockMarker {
public int getBlockTexture(IBlockAccess iblockaccess, int i, int j, int k, int l) {
TilePathMarker marker = (TilePathMarker) iblockaccess.getBlockTileEntity(i, j, k);
if (l == 1 || (marker != null && marker.currentWorldIterator != null)) {
if (l == 1 || (marker != null && marker.tryingToConnect)) {
return 3 * 16 + 11;
} else {
return 3 * 16 + 10;

View file

@ -0,0 +1,38 @@
/**
* Copyright (c) SpaceToad, 2011 http://www.mod-buildcraft.com
*
* BuildCraft is distributed under the terms of the Minecraft Mod Public License
* 1.0, or MMPL. Please check the contents of the license located in
* http://www.mod-buildcraft.com/MMPL-1.0.txt
*/
package net.minecraft.src.buildcraft.builders;
import net.minecraft.src.Chunk;
import net.minecraft.src.NBTTagCompound;
import net.minecraft.src.World;
import net.minecraft.src.forge.ISaveEventHandler;
public class BuildersSaveManager implements ISaveEventHandler {
@Override
public void onWorldLoad(World world) {
//When a world loads clean the list of available markers
TilePathMarker.clearAvailableMarkersList();
}
@Override
public void onWorldSave(World world) {}
@Override
public void onChunkLoad(World world, Chunk chunk) {}
@Override
public void onChunkUnload(World world, Chunk chunk) {}
@Override
public void onChunkSaveData(World world, Chunk chunk, NBTTagCompound data) {}
@Override
public void onChunkLoadData(World world, Chunk chunk, NBTTagCompound data) {}
}

View file

@ -1,3 +1,4 @@
package net.minecraft.src.buildcraft.builders;
import java.util.LinkedList;
@ -10,8 +11,6 @@ import net.minecraft.src.buildcraft.api.Position;
import net.minecraft.src.buildcraft.core.BlockIndex;
import net.minecraft.src.buildcraft.core.DefaultProps;
import net.minecraft.src.buildcraft.core.EntityLaser;
import net.minecraft.src.buildcraft.core.WorldIterator;
import net.minecraft.src.buildcraft.core.WorldIteratorRadius;
public class TilePathMarker extends TileMarker {
@ -19,10 +18,18 @@ public class TilePathMarker extends TileMarker {
public int x0, y0, z0, x1, y1, z1;
public boolean loadLink0 = false, loadLink1 = false;
public boolean tryingToConnect = false;
public TilePathMarker links[] = new TilePathMarker[2];
public static int searchSize = 64; //TODO: this should be moved to default props
//A list with the pathMarkers that aren't fully connected
//It only contains markers within the loaded chunks
private static LinkedList<TilePathMarker> availableMarkers = new LinkedList<TilePathMarker>();
public static int searchSize = 64;
public TilePathMarker() {
availableMarkers.add(this);
}
public boolean isFullyConnected() {
return lasers[0] != null && lasers[1] != null;
@ -40,18 +47,19 @@ public class TilePathMarker extends TileMarker {
lasers[1] = laser;
links[1] = marker;
}
if (isFullyConnected())
availableMarkers.remove(this);
}
public void createLaserAndConnect (TilePathMarker pathMarker) {
public void createLaserAndConnect(TilePathMarker pathMarker) {
if (APIProxy.isClient(worldObj))
return;
EntityLaser laser = new EntityLaser(worldObj,
new Position(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5),
new Position(pathMarker.xCoord + 0.5, pathMarker.yCoord + 0.5, pathMarker.zCoord + 0.5));
EntityLaser laser = new EntityLaser(worldObj, new Position(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5), new Position(pathMarker.xCoord + 0.5, pathMarker.yCoord + 0.5, pathMarker.zCoord + 0.5));
laser.show();
laser.setTexture(DefaultProps.TEXTURE_PATH_ENTITIES + "/laser_1.png");
worldObj.spawnEntityInWorld(laser);
@ -59,7 +67,28 @@ public class TilePathMarker extends TileMarker {
pathMarker.connect(this, laser);
}
WorldIterator currentWorldIterator;
//Searches the availableMarkers list for the nearest available that is within searchSize
private TilePathMarker findNearestAvailablePathMarker() {
TilePathMarker nearestAvailable = null;
double nearestDistance = 0, distance; //The initialization of nearestDistance is only to make the compiler shut up
for (TilePathMarker t : availableMarkers) {
if (t == this || t == this.links[0] || t == this.links[1])
continue;
distance = Math.sqrt(Math.pow(this.xCoord - t.xCoord, 2) + Math.pow(this.yCoord - t.yCoord, 2) + Math.pow(this.zCoord - t.zCoord, 2));
if (distance > searchSize)
continue;
if (nearestAvailable == null || distance < nearestDistance) {
nearestAvailable = t;
nearestDistance = distance;
}
}
return nearestAvailable;
}
@Override
public void tryConnection() {
@ -67,50 +96,21 @@ public class TilePathMarker extends TileMarker {
return;
}
if (currentWorldIterator == null) {
currentWorldIterator = new WorldIteratorRadius(worldObj, xCoord, yCoord, zCoord, searchSize);
worldObj.markBlockNeedsUpdate(xCoord, yCoord, zCoord);
}
tryingToConnect = !tryingToConnect; //Allow the user to stop the path marker from searching for new path markers to connect
worldObj.markBlockNeedsUpdate(xCoord, yCoord, zCoord);
}
@Override
public void updateEntity() {
super.updateEntity();
if (currentWorldIterator != null) {
for (int i = 0; i < 1000; ++i) {
BlockIndex b = currentWorldIterator.iterate();
if (tryingToConnect) {
TilePathMarker nearestPathMarker = findNearestAvailablePathMarker();
if (b == null) {
currentWorldIterator = null;
worldObj.markBlockNeedsUpdate(xCoord, yCoord, zCoord);
break;
}
if (b.i == xCoord && b.j == yCoord && b.k == zCoord) {
continue;
}
TileEntity tile = null;
try {
tile = worldObj.getBlockTileEntity(b.i, b.j, b.k);
} catch (Throwable t) {
// sometimes, tile can't be loaded. Just carry on the
// analysis. We don't even need to log these
}
if (tile instanceof TilePathMarker) {
TilePathMarker pathMarker = (TilePathMarker) tile;
if (!pathMarker.isFullyConnected() && !isLinkedTo(pathMarker)) {
createLaserAndConnect(pathMarker);
worldObj.markBlockNeedsUpdate(xCoord, yCoord, zCoord);
currentWorldIterator = null;
return;
}
}
if (nearestPathMarker != null) {
createLaserAndConnect(nearestPathMarker);
tryingToConnect = false;
worldObj.markBlockNeedsUpdate(xCoord, yCoord, zCoord);
}
}
}
@ -127,13 +127,9 @@ public class TilePathMarker extends TileMarker {
visitedPaths.add(b);
res.add(b);
if (nextTile.links[0] != null
&& !visitedPaths.contains(new BlockIndex(nextTile.links[0].xCoord, nextTile.links[0].yCoord,
nextTile.links[0].zCoord))) {
if (nextTile.links[0] != null && !visitedPaths.contains(new BlockIndex(nextTile.links[0].xCoord, nextTile.links[0].yCoord, nextTile.links[0].zCoord))) {
nextTile = nextTile.links[0];
} else if (nextTile.links[1] != null
&& !visitedPaths.contains(new BlockIndex(nextTile.links[1].xCoord, nextTile.links[1].yCoord,
nextTile.links[1].zCoord))) {
} else if (nextTile.links[1] != null && !visitedPaths.contains(new BlockIndex(nextTile.links[1].xCoord, nextTile.links[1].yCoord, nextTile.links[1].zCoord))) {
nextTile = nextTile.links[1];
} else {
nextTile = null;
@ -160,6 +156,9 @@ public class TilePathMarker extends TileMarker {
lasers = new EntityLaser[2];
links = new TilePathMarker[2];
availableMarkers.remove(this);
tryingToConnect = false;
}
@Override
@ -197,6 +196,9 @@ public class TilePathMarker extends TileMarker {
lasers[1] = null;
links[1] = null;
}
if (!isFullyConnected() && !availableMarkers.contains(this))
availableMarkers.add(this);
}
@Override
@ -231,9 +233,18 @@ public class TilePathMarker extends TileMarker {
}
if (links[1] != null) {
nbttagcompound.setInteger("x0", links[1].xCoord);
nbttagcompound.setInteger("y0", links[1].yCoord);
nbttagcompound.setInteger("z0", links[1].zCoord);
nbttagcompound.setInteger("x1", links[1].xCoord);
nbttagcompound.setInteger("y1", links[1].yCoord);
nbttagcompound.setInteger("z1", links[1].zCoord);
}
}
@Override
public void onChunkUnload() {
availableMarkers.remove(this);
}
public static void clearAvailableMarkersList() {
availableMarkers.clear();
}
}

View file

@ -1,30 +0,0 @@
package net.minecraft.src.buildcraft.core;
import java.util.Iterator;
import net.minecraft.src.World;
public abstract class WorldIterator {
protected World world;
protected int x;
protected int y;
protected int z;
protected Iterator<BlockIndex> iterator;
public WorldIterator(World world, int x, int y, int z) {
this.world = world;
this.x = x;
this.y = y;
this.z = z;
}
public BlockIndex iterate() {
if (iterator.hasNext())
return iterator.next();
else
return null;
}
}

View file

@ -1,58 +0,0 @@
package net.minecraft.src.buildcraft.core;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import net.minecraft.src.World;
public class WorldIteratorRadius extends WorldIterator {
@SuppressWarnings("unchecked")
private static LinkedList<BlockIndex>[] lists = new LinkedList[65];
public WorldIteratorRadius(World world, int px, int py, int pz, int radius) {
super(world, px, py, pz);
createPrecomputedList(radius);
iterator = lists[radius].iterator();
}
@Override
public BlockIndex iterate() {
if (iterator.hasNext()) {
BlockIndex b = iterator.next();
return new BlockIndex(b.i + x, b.j + y, b.k + z);
} else
return null;
}
public static void createPrecomputedList(int radius) {
if (lists[radius] == null) {
lists[radius] = new LinkedList<BlockIndex>();
for (int i = -radius; i <= radius; ++i)
for (int j = -radius; j <= radius; ++j)
for (int k = -radius; k <= radius; ++k)
lists[radius].add(new BlockIndex(i, j, k));
Collections.sort(lists[radius], new Comparator<BlockIndex>() {
@Override
public int compare(BlockIndex o1, BlockIndex o2) {
double d1 = o1.i * o1.i + o1.j * o1.j + o1.k * o1.k;
double d2 = o2.i * o2.i + o2.j * o2.j + o2.k * o2.k;
if (d1 < d2)
return -1;
else if (d1 > d2)
return 1;
else
return 0;
}
});
}
}
}