Fixed Bugs in Golden Dimensional Doors

1. We weren't giving old tickets to the doors that owned them. That
would result in doors requesting new tickets and the old ones wouldn't
be released. Each time a server rebooted, a new ticket would be created.
Then Opis would report that many chunks were forcefully loaded in a
pocket because it doesn't consider overlapping tickets. We now give
doors their old tickets when they're reloaded and we release extra
tickets referring to the same door. That will also deal with the excess
tickets that already exist on servers.
2. Rewrote the logic for checking if a Golden Dimensional Door is
allowed to force-load a pocket. We now check if the door is within the
horizontal bounds of the pocket. This prevents the confusing scenario
where someone places a door far away from the pocket but the only chunks
affected are in the pocket.
3. Fixed the calculation for determining which chunks must be
force-loaded to cover a pocket. This has the benefit that fewer chunks
should need to be loaded. It should be enough to load 16 chunks. We
previously loaded 25 chunks just to err on the side of caution.
4. Golden Dimensional Doors only try to initialize as chunk loaders
once. We previously allowed them to keep trying every tick until they
could get a ticket.
This commit is contained in:
SenseiKiwi 2014-07-02 13:38:57 -04:00
parent b2e086e7c1
commit 3d88e72ecb
4 changed files with 166 additions and 78 deletions

View file

@ -4,5 +4,6 @@ import net.minecraftforge.common.ForgeChunkManager.Ticket;
public interface IChunkLoader
{
public void forceChunkLoading(Ticket ticket,int x, int z);
public boolean isInitialized();
public void initialize(Ticket ticket);
}

View file

@ -1,40 +1,84 @@
package StevenDimDoors.mod_pocketDim.helpers;
import StevenDimDoors.mod_pocketDim.IChunkLoader;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import cpw.mods.fml.common.event.FMLServerStartingEvent;
import java.io.File;
import java.util.List;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.ForgeChunkManager;
import net.minecraftforge.common.ForgeChunkManager.LoadingCallback;
import net.minecraftforge.common.ForgeChunkManager.Ticket;
import net.minecraftforge.common.ForgeChunkManager.Type;
import StevenDimDoors.experimental.BoundingBox;
import StevenDimDoors.mod_pocketDim.IChunkLoader;
import StevenDimDoors.mod_pocketDim.Point3D;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.world.PocketBuilder;
import cpw.mods.fml.common.event.FMLServerStartingEvent;
public class ChunkLoaderHelper implements LoadingCallback
{
@Override
public void ticketsLoaded(List<Ticket> tickets, World world)
{
for (Ticket ticket : tickets)
{
int goldDimDoorX = ticket.getModData().getInteger("goldDimDoorX");
int goldDimDoorY = ticket.getModData().getInteger("goldDimDoorY");
int goldDimDoorZ = ticket.getModData().getInteger("goldDimDoorZ");
if(world.getBlockId(goldDimDoorX, goldDimDoorY, goldDimDoorZ) != mod_pocketDim.properties.GoldenDimensionalDoorID)
boolean loaded = false;
int x = ticket.getModData().getInteger("goldDimDoorX");
int y = ticket.getModData().getInteger("goldDimDoorY");
int z = ticket.getModData().getInteger("goldDimDoorZ");
if (world.getBlockId(x, y, z) == mod_pocketDim.properties.GoldenDimensionalDoorID)
{
IChunkLoader loader = (IChunkLoader) world.getBlockTileEntity(x, y, z);
if (!loader.isInitialized())
{
loader.initialize(ticket);
loaded = true;
}
}
if (!loaded)
{
ForgeChunkManager.releaseTicket(ticket);
}
else
}
}
public static Ticket createTicket(int x, int y, int z, World world)
{
IChunkLoader tile = (IChunkLoader) world.getBlockTileEntity(goldDimDoorX, goldDimDoorY, goldDimDoorZ);
tile.forceChunkLoading(ticket,goldDimDoorX,goldDimDoorZ);
NBTTagCompound data;
Ticket ticket = ForgeChunkManager.requestTicket(mod_pocketDim.instance, world, Type.NORMAL);
if (ticket != null)
{
data = ticket.getModData();
data.setInteger("goldDimDoorX", x);
data.setInteger("goldDimDoorY", y);
data.setInteger("goldDimDoorZ", z);
}
return ticket;
}
public static void forcePocketChunks(NewDimData pocket, Ticket ticket)
{
BoundingBox bounds = PocketBuilder.calculateDefaultBounds(pocket);
Point3D minCorner = bounds.minCorner();
Point3D maxCorner = bounds.maxCorner();
int minX = minCorner.getX() >> 4;
int minZ = minCorner.getZ() >> 4;
int maxX = maxCorner.getX() >> 4;
int maxZ = maxCorner.getZ() >> 4;
int chunkX;
int chunkZ;
for (chunkX = minX; chunkX <= maxX; chunkX++)
{
for (chunkZ = minZ; chunkZ <= maxZ; chunkZ++)
{
ForgeChunkManager.forceChunk(ticket, new ChunkCoordIntPair(chunkX, chunkZ));
}
}
}

View file

@ -1,85 +1,93 @@
package StevenDimDoors.mod_pocketDim.tileentities;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraftforge.common.ForgeChunkManager;
import net.minecraftforge.common.ForgeChunkManager.Ticket;
import net.minecraftforge.common.ForgeChunkManager.Type;
import StevenDimDoors.mod_pocketDim.IChunkLoader;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import StevenDimDoors.mod_pocketDim.helpers.ChunkLoaderHelper;
import StevenDimDoors.mod_pocketDim.world.PocketBuilder;
public class TileEntityDimDoorGold extends TileEntityDimDoor implements IChunkLoader
{
private Ticket chunkTicket;
private boolean initialized = false;
@Override
public boolean canUpdate()
{
return true;
return !initialized;
}
@Override
public boolean isInitialized()
{
return initialized;
}
@Override
public void updateEntity()
{ // every tick?
if (PocketManager.getDimensionData(this.worldObj) != null &&
PocketManager.getDimensionData(this.worldObj).isPocketDimension() &&
!this.worldObj.isRemote)
{
if(PocketManager.getLink(this.xCoord,this.yCoord,this.zCoord,this.worldObj)==null)
if (!initialized)
{
return;
}
if (this.chunkTicket == null)
{
chunkTicket = ForgeChunkManager.requestTicket(mod_pocketDim.instance, worldObj, Type.NORMAL);
if(chunkTicket == null)
{
return;
}
chunkTicket.getModData().setInteger("goldDimDoorX", xCoord);
chunkTicket.getModData().setInteger("goldDimDoorY", yCoord);
chunkTicket.getModData().setInteger("goldDimDoorZ", zCoord);
forceChunkLoading(chunkTicket,this.xCoord,this.zCoord);
}
initialize(null);
}
}
@Override
public void forceChunkLoading(Ticket chunkTicket,int x,int z)
public void initialize(Ticket ticket)
{
Point4D origin = PocketManager.getDimensionData(this.worldObj).origin();
int orientation = PocketManager.getDimensionData(this.worldObj).orientation();
initialized = true;
chunkTicket = ticket;
int xOffset=0;
int zOffset=0;
switch(orientation)
// Only do anything if this function is running on the server side
// NOTE: We don't have to check whether this block is the upper door
// block or the lower one because only one of them should have a
// link associated with it.
if (!worldObj.isRemote)
{
case 0:
xOffset = PocketBuilder.DEFAULT_POCKET_SIZE/2;
break;
case 1:
zOffset = PocketBuilder.DEFAULT_POCKET_SIZE/2;
NewDimData dimension = PocketManager.getDimensionData(worldObj);
break;
case 2:
xOffset = -PocketBuilder.DEFAULT_POCKET_SIZE/2;
break;
case 3:
zOffset = -PocketBuilder.DEFAULT_POCKET_SIZE/2;
break;
}
for(int chunkX = -2; chunkX<3;chunkX++)
// Check whether a ticket has already been assigned to this door
if (chunkTicket == null)
{
for(int chunkZ = -2; chunkZ<3;chunkZ++)
// No ticket yet.
// Check if this area should be loaded and request a new ticket.
if (isValidChunkLoaderSetup(dimension))
{
ForgeChunkManager.forceChunk(chunkTicket, new ChunkCoordIntPair((origin.getX()+xOffset >> 4)+chunkX, (origin.getZ()+zOffset >> 4)+chunkZ));
chunkTicket = ChunkLoaderHelper.createTicket(xCoord, yCoord, zCoord, worldObj);
}
}
else
{
// A ticket has already been provided.
// Check if this area should be loaded. If not, release the ticket.
if (!isValidChunkLoaderSetup(dimension))
{
ForgeChunkManager.releaseTicket(chunkTicket);
chunkTicket = null;
}
}
// If chunkTicket isn't null at this point, then this is a valid door setup.
// The last step is to request force loading of the pocket's chunks.
if (chunkTicket != null)
{
ChunkLoaderHelper.forcePocketChunks(dimension, chunkTicket);
}
}
}
private boolean isValidChunkLoaderSetup(NewDimData dimension)
{
// Check the various conditions that make this a valid door setup.
// 1. The door must be inside the pocket's XZ boundaries,
// to prevent loading of chunks with a distant door
// 2. The dimension must be a pocket dimension
// 3. The door must be linked so that it's clear that it's not a normal door
return (dimension.isPocketDimension() && dimension.getLink(xCoord, yCoord, zCoord) != null &&
PocketBuilder.calculateDefaultBounds(dimension).contains(xCoord, yCoord, zCoord));
}
@Override

View file

@ -8,7 +8,7 @@ import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraftforge.common.DimensionManager;
import StevenDimDoors.experimental.MazeBuilder;
import StevenDimDoors.experimental.BoundingBox;
import StevenDimDoors.mod_pocketDim.Point3D;
import StevenDimDoors.mod_pocketDim.blocks.IDimDoor;
import StevenDimDoors.mod_pocketDim.config.DDProperties;
@ -21,10 +21,10 @@ import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic;
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPackConfig;
import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper;
import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper;
import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor;
import StevenDimDoors.mod_pocketDim.schematic.BlockRotator;
import StevenDimDoors.mod_pocketDim.util.Pair;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor;
public class PocketBuilder
{
@ -559,4 +559,39 @@ public class PocketBuilder
extBlockStorage.setExtBlockMetadata(localX, y & 15, localZ, metadata);
chunk.setChunkModified();
}
public static BoundingBox calculateDefaultBounds(NewDimData pocket)
{
// Calculate the XZ bounds of this pocket assuming that it has the default size
// The Y bounds will be set to encompass the height of a chunk.
int minX = 0;
int minZ = 0;
Point4D origin = pocket.origin();
int orientation = pocket.orientation();
if (orientation < 0 || orientation > 3)
{
throw new IllegalArgumentException("pocket has an invalid orientation value.");
}
switch (orientation)
{
case 0:
minX = origin.getX() - DEFAULT_POCKET_WALL_THICKNESS + 1;
minZ = origin.getZ() - DEFAULT_POCKET_SIZE / 2;
break;
case 1:
minX = origin.getX() - DEFAULT_POCKET_SIZE / 2;
minZ = origin.getZ() - DEFAULT_POCKET_WALL_THICKNESS + 1;
break;
case 2:
minX = origin.getX() + DEFAULT_POCKET_WALL_THICKNESS - DEFAULT_POCKET_SIZE;
minZ = origin.getZ() - DEFAULT_POCKET_SIZE / 2;
break;
case 3:
minX = origin.getX() - DEFAULT_POCKET_SIZE / 2;
minZ = origin.getZ() + DEFAULT_POCKET_WALL_THICKNESS - DEFAULT_POCKET_SIZE;
break;
}
return new BoundingBox(minX, 0, minZ, DEFAULT_POCKET_SIZE, 255, DEFAULT_POCKET_SIZE);
}
}