Fixed Client Gateway Notification and NPE

Fixed the issue with clients not receiving notifications of gateways
being built into the world because we were modifying chunk data
directly. Our schematic classes now support building through World
instead of directly writing to the underlying chunks. Also fixed an NPE
that was introduced last night when I changed which line
GatewayGenerator was initialized on in mod_pocketDim.
This commit is contained in:
SenseiKiwi 2014-03-06 13:44:31 -04:00
parent 9bba789f0b
commit bbd0b1d0fe
8 changed files with 131 additions and 59 deletions

View file

@ -24,12 +24,15 @@ import StevenDimDoors.mod_pocketDim.core.LinkTypes;
import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.schematic.BlockRotator; import StevenDimDoors.mod_pocketDim.schematic.BlockRotator;
import StevenDimDoors.mod_pocketDim.schematic.ChunkBlockSetter;
import StevenDimDoors.mod_pocketDim.schematic.CompoundFilter; import StevenDimDoors.mod_pocketDim.schematic.CompoundFilter;
import StevenDimDoors.mod_pocketDim.schematic.IBlockSetter;
import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException; import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException;
import StevenDimDoors.mod_pocketDim.schematic.ReplacementFilter; import StevenDimDoors.mod_pocketDim.schematic.ReplacementFilter;
import StevenDimDoors.mod_pocketDim.schematic.Schematic; import StevenDimDoors.mod_pocketDim.schematic.Schematic;
import StevenDimDoors.mod_pocketDim.ticking.MobMonolith; import StevenDimDoors.mod_pocketDim.schematic.WorldBlockSetter;
import StevenDimDoors.mod_pocketDim.ticking.CustomLimboPopulator; import StevenDimDoors.mod_pocketDim.ticking.CustomLimboPopulator;
import StevenDimDoors.mod_pocketDim.ticking.MobMonolith;
import StevenDimDoors.mod_pocketDim.util.Point4D; import StevenDimDoors.mod_pocketDim.util.Point4D;
public class DungeonSchematic extends Schematic { public class DungeonSchematic extends Schematic {
@ -176,7 +179,21 @@ public class DungeonSchematic extends Schematic {
return new DungeonSchematic(Schematic.copyFromWorld(world, x, y, z, width, height, length, doCompactBounds)); return new DungeonSchematic(Schematic.copyFromWorld(world, x, y, z, width, height, length, doCompactBounds));
} }
public void copyToWorld(World world, Point3D pocketCenter, int targetOrientation, DimLink entryLink, Random random, DDProperties properties) public void copyToWorld(World world, Point3D pocketCenter, int targetOrientation, DimLink entryLink,
Random random, DDProperties properties, boolean notifyClients)
{
if (notifyClients)
{
copyToWorld(world, pocketCenter, targetOrientation, entryLink, random, properties, new WorldBlockSetter(false, true));
}
else
{
copyToWorld(world, pocketCenter, targetOrientation, entryLink, random, properties, new ChunkBlockSetter());
}
}
public void copyToWorld(World world, Point3D pocketCenter, int targetOrientation, DimLink entryLink,
Random random, DDProperties properties, IBlockSetter blockSetter)
{ {
//TODO: This function is an improvised solution so we can get the release moving. In the future, //TODO: This function is an improvised solution so we can get the release moving. In the future,
//we should generalize block transformations and implement support for them at the level of Schematic, //we should generalize block transformations and implement support for them at the level of Schematic,
@ -208,7 +225,7 @@ public class DungeonSchematic extends Schematic {
blockMeta = BlockRotator.transformMetadata(metadata[index], turnAngle, blockID); blockMeta = BlockRotator.transformMetadata(metadata[index], turnAngle, blockID);
//In the future, we might want to make this more efficient by building whole chunks at a time //In the future, we might want to make this more efficient by building whole chunks at a time
setBlockDirectly(world, pocketPoint.getX(), pocketPoint.getY(), pocketPoint.getZ(), blockID, blockMeta); blockSetter.setBlock(world, pocketPoint.getX(), pocketPoint.getY(), pocketPoint.getZ(), blockID, blockMeta);
index++; index++;
} }
} }
@ -230,10 +247,10 @@ public class DungeonSchematic extends Schematic {
world.setBlockTileEntity(pocketPoint.getX(), pocketPoint.getY(), pocketPoint.getZ(), TileEntity.createAndLoadEntity(tileTag)); world.setBlockTileEntity(pocketPoint.getX(), pocketPoint.getY(), pocketPoint.getZ(), TileEntity.createAndLoadEntity(tileTag));
} }
setUpDungeon(PocketManager.getDimensionData(world), world, pocketCenter, turnAngle, entryLink, random, properties); setUpDungeon(PocketManager.getDimensionData(world), world, pocketCenter, turnAngle, entryLink, random, properties, blockSetter);
} }
private void setUpDungeon(NewDimData dimension, World world, Point3D pocketCenter, int turnAngle, DimLink entryLink, Random random, DDProperties properties) private void setUpDungeon(NewDimData dimension, World world, Point3D pocketCenter, int turnAngle, DimLink entryLink, Random random, DDProperties properties, IBlockSetter blockSetter)
{ {
//Transform dungeon corners //Transform dungeon corners
Point3D minCorner = new Point3D(0, 0, 0); Point3D minCorner = new Point3D(0, 0, 0);
@ -256,14 +273,14 @@ public class DungeonSchematic extends Schematic {
//Set up link data for exit door //Set up link data for exit door
for (Point3D location : exitDoorLocations) for (Point3D location : exitDoorLocations)
{ {
createExitDoorLink(world, dimension, location, entranceDoorLocation, turnAngle, pocketCenter); createExitDoorLink(world, dimension, location, entranceDoorLocation, turnAngle, pocketCenter, blockSetter);
} }
//Remove end portal frames and spawn Monoliths, if allowed //Remove end portal frames and spawn Monoliths, if allowed
boolean canSpawn = CustomLimboPopulator.isMobSpawningAllowed(); boolean canSpawn = CustomLimboPopulator.isMobSpawningAllowed();
for (Point3D location : monolithSpawnLocations) for (Point3D location : monolithSpawnLocations)
{ {
spawnMonolith(world, location, entranceDoorLocation, turnAngle, pocketCenter, canSpawn); spawnMonolith(world, location, entranceDoorLocation, turnAngle, pocketCenter, canSpawn, blockSetter);
} }
// If this is a Nether dungeon, search for a sign near the entry door and write the dimension's depth. // If this is a Nether dungeon, search for a sign near the entry door and write the dimension's depth.
@ -312,7 +329,7 @@ public class DungeonSchematic extends Schematic {
initDoorTileEntity(world, pocketCenter); initDoorTileEntity(world, pocketCenter);
} }
private static void createExitDoorLink(World world, NewDimData dimension, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter) private static void createExitDoorLink(World world, NewDimData dimension, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter, IBlockSetter blockSetter)
{ {
//Transform the door's location to the pocket coordinate system //Transform the door's location to the pocket coordinate system
Point3D location = point.clone(); Point3D location = point.clone();
@ -327,7 +344,7 @@ public class DungeonSchematic extends Schematic {
{ {
int blockID = world.getBlockId(x, y, z); int blockID = world.getBlockId(x, y, z);
int metadata = world.getBlockMetadata(x, y, z); int metadata = world.getBlockMetadata(x, y, z);
setBlockDirectly(world, x, y + 1, z, blockID, metadata); blockSetter.setBlock(world, x, y + 1, z, blockID, metadata);
} }
initDoorTileEntity(world, location); initDoorTileEntity(world, location);
} }
@ -343,13 +360,13 @@ public class DungeonSchematic extends Schematic {
initDoorTileEntity(world, location); initDoorTileEntity(world, location);
} }
private static void spawnMonolith(World world, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter, boolean canSpawn) private static void spawnMonolith(World world, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter, boolean canSpawn, IBlockSetter blockSetter)
{ {
//Transform the frame block's location to the pocket coordinate system //Transform the frame block's location to the pocket coordinate system
Point3D location = point.clone(); Point3D location = point.clone();
BlockRotator.transformPoint(location, entrance, rotation, pocketCenter); BlockRotator.transformPoint(location, entrance, rotation, pocketCenter);
//Remove frame block //Remove frame block
setBlockDirectly(world, location.getX(), location.getY(), location.getZ(), 0, 0); blockSetter.setBlock(world, location.getX(), location.getY(), location.getZ(), 0, 0);
//Spawn Monolith //Spawn Monolith
if (canSpawn) if (canSpawn)
{ {
@ -377,7 +394,7 @@ public class DungeonSchematic extends Schematic {
private static void writeDepthSign(World world, Point3D pocketCenter, int depth) private static void writeDepthSign(World world, Point3D pocketCenter, int depth)
{ {
final int SEARCH_RANGE = 5; final int SEARCH_RANGE = 6;
int x, y, z, block; int x, y, z, block;
int dx, dy, dz; int dx, dy, dz;

View file

@ -210,8 +210,6 @@ public class mod_pocketDim
mod_pocketDim.limboBiome = (new BiomeGenLimbo(properties.LimboBiomeID)); mod_pocketDim.limboBiome = (new BiomeGenLimbo(properties.LimboBiomeID));
mod_pocketDim.pocketBiome = (new BiomeGenPocket(properties.PocketBiomeID)); mod_pocketDim.pocketBiome = (new BiomeGenPocket(properties.PocketBiomeID));
GameRegistry.registerWorldGenerator(mod_pocketDim.gatewayGenerator);
GameRegistry.registerBlock(goldenDoor, "Golden Door"); GameRegistry.registerBlock(goldenDoor, "Golden Door");
GameRegistry.registerBlock(goldenDimensionalDoor, "Golden Dimensional Door"); GameRegistry.registerBlock(goldenDimensionalDoor, "Golden Dimensional Door");
GameRegistry.registerBlock(unstableDoor, "Unstable Door"); GameRegistry.registerBlock(unstableDoor, "Unstable Door");
@ -253,14 +251,12 @@ public class mod_pocketDim
LanguageRegistry.addName(itemRiftBlade, "Rift Blade"); LanguageRegistry.addName(itemRiftBlade, "Rift Blade");
LanguageRegistry.addName(itemWorldThread, "World Thread"); LanguageRegistry.addName(itemWorldThread, "World Thread");
/** /**
* Add names for multiblock inventory item * Add names for multiblock inventory item
*/ */
LanguageRegistry.addName(new ItemStack(blockDimWall, 1, 0), "Fabric of Reality"); LanguageRegistry.addName(new ItemStack(blockDimWall, 1, 0), "Fabric of Reality");
LanguageRegistry.addName(new ItemStack(blockDimWall, 1, 1), "Ancient Fabric"); LanguageRegistry.addName(new ItemStack(blockDimWall, 1, 1), "Ancient Fabric");
LanguageRegistry.instance().addStringLocalization("itemGroup.dimDoorsCustomTab", "en_US", "Dimensional Doors Items"); LanguageRegistry.instance().addStringLocalization("itemGroup.dimDoorsCustomTab", "en_US", "Dimensional Doors Items");
GameRegistry.registerTileEntity(TileEntityDimDoor.class, "TileEntityDimDoor"); GameRegistry.registerTileEntity(TileEntityDimDoor.class, "TileEntityDimDoor");
@ -276,6 +272,7 @@ public class mod_pocketDim
CraftingManager.registerRecipes(properties); CraftingManager.registerRecipes(properties);
DungeonHelper.initialize(); DungeonHelper.initialize();
gatewayGenerator = new GatewayGenerator(properties); gatewayGenerator = new GatewayGenerator(properties);
GameRegistry.registerWorldGenerator(mod_pocketDim.gatewayGenerator);
// Register loot chests // Register loot chests
DDLoot.registerInfo(properties); DDLoot.registerInfo(properties);

View file

@ -0,0 +1,46 @@
package StevenDimDoors.mod_pocketDim.schematic;
import net.minecraft.block.Block;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
public class ChunkBlockSetter implements IBlockSetter
{
public ChunkBlockSetter() { }
public void setBlock(World world, int x, int y, int z, int blockID, int metadata)
{
if (blockID != 0 && Block.blocksList[blockID] == null)
{
return;
}
int cX = x >> 4;
int cZ = z >> 4;
int cY = y >> 4;
Chunk chunk;
int localX = (x % 16) < 0 ? (x % 16) + 16 : (x % 16);
int localZ = (z % 16) < 0 ? (z % 16) + 16 : (z % 16);
ExtendedBlockStorage extBlockStorage;
try
{
chunk = world.getChunkFromChunkCoords(cX, cZ);
extBlockStorage = chunk.getBlockStorageArray()[cY];
if (extBlockStorage == null)
{
extBlockStorage = new ExtendedBlockStorage(cY << 4, !world.provider.hasNoSky);
chunk.getBlockStorageArray()[cY] = extBlockStorage;
}
extBlockStorage.setExtBlockID(localX, y & 15, localZ, blockID);
extBlockStorage.setExtBlockMetadata(localX, y & 15, localZ, metadata);
chunk.setChunkModified();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}

View file

@ -0,0 +1,8 @@
package StevenDimDoors.mod_pocketDim.schematic;
import net.minecraft.world.World;
public interface IBlockSetter
{
public void setBlock(World world, int x, int y, int z, int blockID, int metadata);
}

View file

@ -118,7 +118,7 @@ public class Schematic {
public static Schematic readFromFile(File schematicFile) throws FileNotFoundException, InvalidSchematicException public static Schematic readFromFile(File schematicFile) throws FileNotFoundException, InvalidSchematicException
{ {
// TODO: fix resource leaks here // There is no resource leak... readFromStream() closes the stream TWICE.
return readFromStream(new FileInputStream(schematicFile)); return readFromStream(new FileInputStream(schematicFile));
} }
@ -362,7 +362,19 @@ public class Schematic {
return filter.apply(this, this.blocks, this.metadata); return filter.apply(this, this.blocks, this.metadata);
} }
public void copyToWorld(World world, int x, int y, int z) public void copyToWorld(World world, int x, int y, int z, boolean notifyClients)
{
if (notifyClients)
{
copyToWorld(world, x, y, z, new WorldBlockSetter(false, true));
}
else
{
copyToWorld(world, x, y, z, new ChunkBlockSetter());
}
}
protected void copyToWorld(World world, int x, int y, int z, IBlockSetter blockSetter)
{ {
//This isn't implemented as a WorldOperation because it doesn't quite fit the structure of those operations. //This isn't implemented as a WorldOperation because it doesn't quite fit the structure of those operations.
//It's not worth the trouble in this case. //It's not worth the trouble in this case.
@ -378,11 +390,12 @@ public class Schematic {
{ {
for (dx = 0; dx < width; dx++) for (dx = 0; dx < width; dx++)
{ {
setBlockDirectly(world, x + dx, y + dy, z + dz, blocks[index], metadata[index]); blockSetter.setBlock(world, x + dx, y + dy, z + dz, blocks[index], metadata[index]);
index++; index++;
} }
} }
} }
//Copy tile entities into the world //Copy tile entities into the world
count = tileEntities.tagCount(); count = tileEntities.tagCount();
for (index = 0; index < count; index++) for (index = 0; index < count; index++)
@ -399,39 +412,4 @@ public class Schematic {
world.setBlockTileEntity(dx, dy, dz, TileEntity.createAndLoadEntity(tileTag)); world.setBlockTileEntity(dx, dy, dz, TileEntity.createAndLoadEntity(tileTag));
} }
} }
protected static void setBlockDirectly(World world, int x, int y, int z, int blockID, int metadata)
{
if (blockID != 0 && Block.blocksList[blockID] == null)
{
return;
}
int cX = x >> 4;
int cZ = z >> 4;
int cY = y >> 4;
Chunk chunk;
int localX = (x % 16) < 0 ? (x % 16) + 16 : (x % 16);
int localZ = (z % 16) < 0 ? (z % 16) + 16 : (z % 16);
ExtendedBlockStorage extBlockStorage;
try
{
chunk = world.getChunkFromChunkCoords(cX, cZ);
extBlockStorage = chunk.getBlockStorageArray()[cY];
if (extBlockStorage == null)
{
extBlockStorage = new ExtendedBlockStorage(cY << 4, !world.provider.hasNoSky);
chunk.getBlockStorageArray()[cY] = extBlockStorage;
}
extBlockStorage.setExtBlockID(localX, y & 15, localZ, blockID);
extBlockStorage.setExtBlockMetadata(localX, y & 15, localZ, metadata);
chunk.setChunkModified();
}
catch(Exception e)
{
e.printStackTrace();
}
}
} }

View file

@ -0,0 +1,26 @@
package StevenDimDoors.mod_pocketDim.schematic;
import net.minecraft.block.Block;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
public class WorldBlockSetter implements IBlockSetter
{
public final int BLOCK_UPDATES_FLAG = 1;
public final int NOTIFY_CLIENT_FLAG = 2;
private int flags;
public WorldBlockSetter(boolean doBlockUpdates, boolean notifyClients)
{
flags = 0;
flags += doBlockUpdates ? BLOCK_UPDATES_FLAG : 0;
flags += notifyClients ? NOTIFY_CLIENT_FLAG : 0;
}
public void setBlock(World world, int x, int y, int z, int blockID, int metadata)
{
world.setBlock(x, y, z, blockID, metadata, flags);
}
}

View file

@ -105,7 +105,7 @@ public class PocketBuilder
} }
Point3D destination = new Point3D(incomingLink.destination()); Point3D destination = new Point3D(incomingLink.destination());
loadAndValidateDungeon(dimension.dungeon(), properties).copyToWorld(world, destination, originLink.orientation(), incomingLink, random, properties); loadAndValidateDungeon(dimension.dungeon(), properties).copyToWorld(world, destination, originLink.orientation(), incomingLink, random, properties, false);
dimension.setFilled(true); dimension.setFilled(true);
return true; return true;
} }
@ -136,7 +136,7 @@ public class PocketBuilder
destination.setY( yCoordHelper.adjustDestinationY(destination.getY(), world.getHeight(), schematic.getEntranceDoorLocation().getY(), schematic.getHeight()) ); destination.setY( yCoordHelper.adjustDestinationY(destination.getY(), world.getHeight(), schematic.getEntranceDoorLocation().getY(), schematic.getHeight()) );
//Generate the dungeon //Generate the dungeon
schematic.copyToWorld(world, destination, orientation, link, random, properties); schematic.copyToWorld(world, destination, orientation, link, random, properties, false);
//Finish up destination initialization //Finish up destination initialization
dimension.initializeDungeon(destination.getX(), destination.getY(), destination.getZ(), orientation, link, dungeon); dimension.initializeDungeon(destination.getX(), destination.getY(), destination.getZ(), orientation, link, dungeon);

View file

@ -67,7 +67,7 @@ public abstract class BaseGateway
// messes up the calculation. ~SenseiKiwi // messes up the calculation. ~SenseiKiwi
//schematic.copyToWorld(world, x - doorLocation.getX(), y, z - doorLocation.getZ()); //schematic.copyToWorld(world, x - doorLocation.getX(), y, z - doorLocation.getZ());
schematic.copyToWorld(world, x - doorLocation.getX(), y + 1 - doorLocation.getY(), z - doorLocation.getZ()); schematic.copyToWorld(world, x - doorLocation.getX(), y + 1 - doorLocation.getY(), z - doorLocation.getZ(), true);
} }
this.generateRandomBits(world, x, y, z); this.generateRandomBits(world, x, y, z);