THE UPDATE
Merging months of dev work into master. The update is playable, but untested.
This commit is contained in:
702
StevenDimDoors/mod_pocketDim/core/DDTeleporter.java
Normal file
702
StevenDimDoors/mod_pocketDim/core/DDTeleporter.java
Normal file
@@ -0,0 +1,702 @@
|
||||
package StevenDimDoors.mod_pocketDim.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityList;
|
||||
import net.minecraft.entity.item.EntityMinecart;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemDoor;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.packet.Packet41EntityEffect;
|
||||
import net.minecraft.network.packet.Packet43Experience;
|
||||
import net.minecraft.network.packet.Packet9Respawn;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
import StevenDimDoors.mod_pocketDim.DDProperties;
|
||||
import StevenDimDoors.mod_pocketDim.Point3D;
|
||||
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
|
||||
import StevenDimDoors.mod_pocketDim.blocks.BlockRift;
|
||||
import StevenDimDoors.mod_pocketDim.blocks.IDimDoor;
|
||||
import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper;
|
||||
import StevenDimDoors.mod_pocketDim.items.BaseItemDoor;
|
||||
import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor;
|
||||
import StevenDimDoors.mod_pocketDim.schematic.BlockRotator;
|
||||
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor;
|
||||
import StevenDimDoors.mod_pocketDim.util.Point4D;
|
||||
import StevenDimDoors.mod_pocketDim.world.PocketBuilder;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
|
||||
public class DDTeleporter
|
||||
{
|
||||
private static final Random random = new Random();
|
||||
private static final int END_DIMENSION_ID = 1;
|
||||
private static final int MAX_ROOT_SHIFT_CHANCE = 100;
|
||||
private static final int START_ROOT_SHIFT_CHANCE = 0;
|
||||
private static final int ROOT_SHIFT_CHANCE_PER_LEVEL = 5;
|
||||
|
||||
public static int cooldown = 0;
|
||||
|
||||
private DDTeleporter() { }
|
||||
|
||||
/**Checks if the destination supplied is valid, ie, filled by any non-replaceable block.
|
||||
*
|
||||
* @param entity
|
||||
* @param world
|
||||
* @param destination
|
||||
* @param properties
|
||||
* @return
|
||||
*/
|
||||
public static boolean CheckDestination(Entity entity, WorldServer world, Point4D destination,DDProperties properties)
|
||||
{
|
||||
int x = destination.getX();
|
||||
int y = destination.getY();
|
||||
int z = destination.getZ();
|
||||
int blockIDTop;
|
||||
int blockIDBottom;
|
||||
|
||||
Point3D point;
|
||||
|
||||
int orientation;
|
||||
|
||||
orientation = getDestinationOrientation(destination, properties);
|
||||
entity.rotationYaw = (orientation * 90) + 90;
|
||||
switch (orientation)
|
||||
{
|
||||
case 0:
|
||||
point= new Point3D(MathHelper.floor_double(x - 0.5), y - 1, MathHelper.floor_double(z + 0.5));
|
||||
break;
|
||||
case 1:
|
||||
point= new Point3D(MathHelper.floor_double(x + 0.5), y - 1, MathHelper.floor_double(z - 0.5));
|
||||
break;
|
||||
case 2:
|
||||
point = new Point3D(MathHelper.floor_double(x + 1.5), y - 1, MathHelper.floor_double(z + 0.5));
|
||||
break;
|
||||
case 3:
|
||||
point = new Point3D(MathHelper.floor_double(x + 0.5), y - 1, MathHelper.floor_double(z + 1.5));
|
||||
break;
|
||||
default:
|
||||
point = new Point3D(x, y - 1, z);
|
||||
break;
|
||||
}
|
||||
blockIDBottom = world.getBlockId(point.getX(), point.getY(), point.getZ());
|
||||
blockIDTop = world.getBlockId(point.getX(), point.getY()+1, point.getZ());
|
||||
|
||||
if(!(Block.blocksList[blockIDBottom]==null))
|
||||
{
|
||||
if(!Block.blocksList[blockIDBottom].isBlockReplaceable(world, point.getX(), point.getY(), point.getZ()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(!(Block.blocksList[blockIDTop]==null))
|
||||
{
|
||||
if(!Block.blocksList[blockIDTop].isBlockReplaceable(world, point.getX(), point.getY()+1, point.getZ()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
|
||||
}
|
||||
private static void placeInPortal(Entity entity, WorldServer world, Point4D destination, DDProperties properties, boolean checkOrientation)
|
||||
{
|
||||
int x = destination.getX();
|
||||
int y = destination.getY();
|
||||
int z = destination.getZ();
|
||||
|
||||
int orientation;
|
||||
if (checkOrientation)
|
||||
{
|
||||
orientation = getDestinationOrientation(destination, properties);
|
||||
entity.rotationYaw = (orientation * 90) + 90;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Teleport the entity to the precise destination point
|
||||
orientation = -1;
|
||||
}
|
||||
|
||||
if(!CheckDestination(entity, world, destination, properties))
|
||||
{
|
||||
if(entity instanceof EntityPlayerMP)
|
||||
{
|
||||
EntityPlayer player = (EntityPlayer) entity;
|
||||
player.rotationYaw=(orientation * 90)+90;
|
||||
switch (orientation)
|
||||
{
|
||||
case 0:
|
||||
player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5);
|
||||
break;
|
||||
case 1:
|
||||
player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5);
|
||||
break;
|
||||
case 2:
|
||||
player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5);
|
||||
break;
|
||||
case 3:
|
||||
player.setPositionAndUpdate(x + 0.5, y - 1, z + .5);
|
||||
break;
|
||||
default:
|
||||
player.setPositionAndUpdate(x, y - 1, z);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (entity instanceof EntityPlayer)
|
||||
{
|
||||
EntityPlayer player = (EntityPlayer) entity;
|
||||
switch (orientation)
|
||||
{
|
||||
case 0:
|
||||
player.setPositionAndUpdate(x - 0.5, y - 1, z + 0.5);
|
||||
break;
|
||||
case 1:
|
||||
player.setPositionAndUpdate(x + 0.5, y - 1, z - 0.5);
|
||||
break;
|
||||
case 2:
|
||||
player.setPositionAndUpdate(x + 1.5, y - 1, z + 0.5);
|
||||
break;
|
||||
case 3:
|
||||
player.setPositionAndUpdate(x + 0.5, y - 1, z + 1.5);
|
||||
break;
|
||||
default:
|
||||
player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (entity instanceof EntityMinecart)
|
||||
{
|
||||
entity.motionX = 0;
|
||||
entity.motionZ = 0;
|
||||
entity.motionY = 0;
|
||||
switch (orientation)
|
||||
{
|
||||
case 0:
|
||||
DDTeleporter.setEntityPosition(entity, x - 0.5, y, z + 0.5);
|
||||
entity.motionX = -0.39;
|
||||
entity.worldObj.updateEntityWithOptionalForce(entity, false);
|
||||
break;
|
||||
case 1:
|
||||
DDTeleporter.setEntityPosition(entity, x + 0.5, y, z - 0.5);
|
||||
entity.motionZ = -0.39;
|
||||
entity.worldObj.updateEntityWithOptionalForce(entity, false);
|
||||
break;
|
||||
case 2:
|
||||
DDTeleporter.setEntityPosition(entity, x + 1.5, y, z + 0.5);
|
||||
entity.motionX = 0.39;
|
||||
entity.worldObj.updateEntityWithOptionalForce(entity, false);
|
||||
break;
|
||||
case 3:
|
||||
DDTeleporter.setEntityPosition(entity, x + 0.5, y, z + 1.5 );
|
||||
entity.motionZ = 0.39;
|
||||
entity.worldObj.updateEntityWithOptionalForce(entity, false);
|
||||
break;
|
||||
default:
|
||||
DDTeleporter.setEntityPosition(entity, x + 0.5, y, z + 0.5);
|
||||
entity.worldObj.updateEntityWithOptionalForce(entity, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (orientation)
|
||||
{
|
||||
case 0:
|
||||
setEntityPosition(entity, x - 0.5, y, z + 0.5);
|
||||
break;
|
||||
case 1:
|
||||
setEntityPosition(entity, x + 0.5, y, z - 0.5);
|
||||
break;
|
||||
case 2:
|
||||
setEntityPosition(entity, x + 1.5, y, z + 0.5);
|
||||
break;
|
||||
case 3:
|
||||
setEntityPosition(entity, x + 0.5, y, z + 1.5);
|
||||
break;
|
||||
default:
|
||||
setEntityPosition(entity, x + 0.5, y, z + 0.5);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setEntityPosition(Entity entity, double x, double y, double z)
|
||||
{
|
||||
entity.lastTickPosX = entity.prevPosX = entity.posX = x;
|
||||
entity.lastTickPosY = entity.prevPosY = entity.posY = y + (double)entity.yOffset;
|
||||
entity.lastTickPosZ = entity.prevPosZ = entity.posZ = z;
|
||||
entity.setPosition(x, y, z);
|
||||
}
|
||||
|
||||
private static int getDestinationOrientation(Point4D door, DDProperties properties)
|
||||
{
|
||||
World world = DimensionManager.getWorld(door.getDimension());
|
||||
if (world == null)
|
||||
{
|
||||
throw new IllegalStateException("The destination world should be loaded!");
|
||||
}
|
||||
|
||||
//Check if the block below that point is actually a door
|
||||
int blockID = world.getBlockId(door.getX(), door.getY() - 1, door.getZ());
|
||||
if (blockID != properties.DimensionalDoorID && blockID != properties.WarpDoorID &&
|
||||
blockID != properties.TransientDoorID && blockID != properties.UnstableDoorID
|
||||
&& blockID != properties.GoldDimDoorID)
|
||||
{
|
||||
//Return the pocket's orientation instead
|
||||
return PocketManager.getDimensionData(door.getDimension()).orientation();
|
||||
}
|
||||
|
||||
//Return the orientation portion of its metadata
|
||||
return world.getBlockMetadata(door.getX(), door.getY() - 1, door.getZ()) & 3;
|
||||
}
|
||||
|
||||
public static Entity teleportEntity(Entity entity, Point4D destination, boolean checkOrientation)
|
||||
{
|
||||
if (entity == null)
|
||||
{
|
||||
throw new IllegalArgumentException("entity cannot be null.");
|
||||
}
|
||||
if (destination == null)
|
||||
{
|
||||
throw new IllegalArgumentException("destination cannot be null.");
|
||||
}
|
||||
|
||||
//This beautiful teleport method is based off of xCompWiz's teleport function.
|
||||
|
||||
WorldServer oldWorld = (WorldServer) entity.worldObj;
|
||||
WorldServer newWorld;
|
||||
EntityPlayerMP player = (entity instanceof EntityPlayerMP) ? (EntityPlayerMP) entity : null;
|
||||
DDProperties properties = DDProperties.instance();
|
||||
|
||||
// Is something riding? Handle it first.
|
||||
if (entity.riddenByEntity != null)
|
||||
{
|
||||
return teleportEntity(entity.riddenByEntity, destination, checkOrientation);
|
||||
}
|
||||
|
||||
// Are we riding something? Dismount and tell the mount to go first.
|
||||
Entity cart = entity.ridingEntity;
|
||||
if (cart != null)
|
||||
{
|
||||
entity.mountEntity(null);
|
||||
cart = teleportEntity(cart, destination, checkOrientation);
|
||||
// We keep track of both so we can remount them on the other side.
|
||||
}
|
||||
|
||||
// Determine if our destination is in another realm.
|
||||
boolean difDest = entity.dimension != destination.getDimension();
|
||||
if (difDest)
|
||||
{
|
||||
// Destination isn't loaded? Then we need to load it.
|
||||
newWorld = PocketManager.loadDimension(destination.getDimension());
|
||||
}
|
||||
else
|
||||
{
|
||||
newWorld = (WorldServer) oldWorld;
|
||||
}
|
||||
|
||||
|
||||
// GreyMaria: What is this even accomplishing? We're doing the exact same thing at the end of this all.
|
||||
// TODO Check to see if this is actually vital.
|
||||
DDTeleporter.placeInPortal(entity, newWorld, destination, properties, checkOrientation);
|
||||
|
||||
if (difDest) // Are we moving our target to a new dimension?
|
||||
{
|
||||
if(player != null) // Are we working with a player?
|
||||
{
|
||||
// We need to do all this special stuff to move a player between dimensions.
|
||||
|
||||
// Set the new dimension and inform the client that it's moving to a new world.
|
||||
player.dimension = destination.getDimension();
|
||||
player.playerNetServerHandler.sendPacketToPlayer(new Packet9Respawn(player.dimension, (byte)player.worldObj.difficultySetting, newWorld.getWorldInfo().getTerrainType(), newWorld.getHeight(), player.theItemInWorldManager.getGameType()));
|
||||
|
||||
// GreyMaria: Used the safe player entity remover before.
|
||||
// This should fix an apparently unreported bug where
|
||||
// the last non-sleeping player leaves the Overworld
|
||||
// for a pocket dimension, causing all sleeping players
|
||||
// to remain asleep instead of progressing to day.
|
||||
oldWorld.removePlayerEntityDangerously(player);
|
||||
player.isDead = false;
|
||||
|
||||
// Creates sanity by ensuring that we're only known to exist where we're supposed to be known to exist.
|
||||
oldWorld.getPlayerManager().removePlayer(player);
|
||||
newWorld.getPlayerManager().addPlayer(player);
|
||||
|
||||
player.theItemInWorldManager.setWorld(newWorld);
|
||||
|
||||
// Synchronize with the server so the client knows what time it is and what it's holding.
|
||||
player.mcServer.getConfigurationManager().updateTimeAndWeatherForPlayer(player, newWorld);
|
||||
player.mcServer.getConfigurationManager().syncPlayerInventory(player);
|
||||
for(Object potionEffect : player.getActivePotionEffects())
|
||||
{
|
||||
PotionEffect effect = (PotionEffect)potionEffect;
|
||||
player.playerNetServerHandler.sendPacketToPlayer(new Packet41EntityEffect(player.entityId, effect));
|
||||
}
|
||||
|
||||
player.playerNetServerHandler.sendPacketToPlayer(new Packet43Experience(player.experience, player.experienceTotal, player.experienceLevel));
|
||||
}
|
||||
|
||||
// Creates sanity by removing the entity from its old location's chunk entity list, if applicable.
|
||||
int entX = entity.chunkCoordX;
|
||||
int entZ = entity.chunkCoordZ;
|
||||
if ((entity.addedToChunk) && (oldWorld.getChunkProvider().chunkExists(entX, entZ)))
|
||||
{
|
||||
oldWorld.getChunkFromChunkCoords(entX, entZ).removeEntity(entity);
|
||||
oldWorld.getChunkFromChunkCoords(entX, entZ).isModified = true;
|
||||
}
|
||||
// Memory concerns.
|
||||
oldWorld.releaseEntitySkin(entity);
|
||||
|
||||
if (player == null) // Are we NOT working with a player?
|
||||
{
|
||||
NBTTagCompound entityNBT = new NBTTagCompound();
|
||||
entity.isDead = false;
|
||||
entity.addEntityID(entityNBT);
|
||||
entity.isDead = true;
|
||||
entity = EntityList.createEntityFromNBT(entityNBT, newWorld);
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
// TODO FIXME IMPLEMENT NULL CHECKS THAT ACTUALLY DO SOMETHING.
|
||||
/*
|
||||
* shit ourselves in an organized fashion, preferably
|
||||
* in a neat pile instead of all over our users' games
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Finally, respawn the entity in its new home.
|
||||
newWorld.spawnEntityInWorld(entity);
|
||||
entity.setWorld(newWorld);
|
||||
}
|
||||
entity.worldObj.updateEntityWithOptionalForce(entity, false);
|
||||
|
||||
// Hey, remember me? It's time to remount.
|
||||
if (cart != null)
|
||||
{
|
||||
// Was there a player teleported? If there was, it's important that we update shit.
|
||||
if (player != null)
|
||||
{
|
||||
entity.worldObj.updateEntityWithOptionalForce(entity, true);
|
||||
}
|
||||
entity.mountEntity(cart);
|
||||
}
|
||||
|
||||
// Did we teleport a player? Load the chunk for them.
|
||||
if (player != null)
|
||||
{
|
||||
newWorld.getChunkProvider().loadChunk(MathHelper.floor_double(entity.posX) >> 4, MathHelper.floor_double(entity.posZ) >> 4);
|
||||
|
||||
// Tell Forge we're moving its players so everyone else knows.
|
||||
// Let's try doing this down here in case this is what's killing NEI.
|
||||
GameRegistry.onPlayerChangedDimension((EntityPlayer)entity);
|
||||
|
||||
}
|
||||
DDTeleporter.placeInPortal(entity, newWorld, destination, properties, checkOrientation);
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary function used to teleport the player using doors. Performs numerous null checks, and also generates the destination door/pocket if it has not done so already.
|
||||
* Also ensures correct orientation relative to the door.
|
||||
* @param world - world the player is currently in
|
||||
* @param link - the link the player is using to teleport; sends the player to its destination
|
||||
* @param player - the instance of the player to be teleported
|
||||
*/
|
||||
public static void traverseDimDoor(World world, DimLink link, Entity entity, Block door)
|
||||
{
|
||||
if (world == null)
|
||||
{
|
||||
throw new IllegalArgumentException("world cannot be null.");
|
||||
}
|
||||
if (link == null)
|
||||
{
|
||||
throw new IllegalArgumentException("link cannot be null.");
|
||||
}
|
||||
if (entity == null)
|
||||
{
|
||||
throw new IllegalArgumentException("entity cannot be null.");
|
||||
}
|
||||
if (world.isRemote)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (cooldown == 0 || entity instanceof EntityPlayer)
|
||||
{
|
||||
cooldown = 2 + random.nextInt(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!initializeDestination(link, DDProperties.instance(),door))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (link.linkType() == LinkTypes.RANDOM)
|
||||
{
|
||||
Point4D randomDestination = getRandomDestination();
|
||||
if (randomDestination != null)
|
||||
{
|
||||
entity = teleportEntity(entity, randomDestination, true);
|
||||
entity.worldObj.playSoundEffect(entity.posX, entity.posY, entity.posZ, "mob.endermen.portal", 1.0F, 1.0F);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buildExitDoor(door, link, DDProperties.instance());
|
||||
entity = teleportEntity(entity, link.destination(), link.linkType() != LinkTypes.UNSAFE_EXIT);
|
||||
entity.worldObj.playSoundEffect(entity.posX, entity.posY, entity.posZ, "mob.endermen.portal", 1.0F, 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean initializeDestination(DimLink link, DDProperties properties, Block door)
|
||||
{
|
||||
if (link.hasDestination())
|
||||
{
|
||||
if(PocketManager.isBlackListed(link.destination().getDimension()))
|
||||
{
|
||||
link=PocketManager.getDimensionData(link.source().getDimension()).createLink(link.source,LinkTypes.SAFE_EXIT,link.orientation);
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the destination type and respond accordingly
|
||||
switch (link.linkType())
|
||||
{
|
||||
case LinkTypes.DUNGEON:
|
||||
return PocketBuilder.generateNewDungeonPocket(link, properties);
|
||||
case LinkTypes.POCKET:
|
||||
return PocketBuilder.generateNewPocket(link, properties,door);
|
||||
case LinkTypes.SAFE_EXIT:
|
||||
return generateSafeExit(link, properties);
|
||||
case LinkTypes.DUNGEON_EXIT:
|
||||
return generateDungeonExit(link, properties);
|
||||
case LinkTypes.UNSAFE_EXIT:
|
||||
return generateUnsafeExit(link);
|
||||
case LinkTypes.NORMAL:
|
||||
case LinkTypes.REVERSE:
|
||||
case LinkTypes.RANDOM:
|
||||
return true;
|
||||
default:
|
||||
throw new IllegalArgumentException("link has an unrecognized link type.");
|
||||
}
|
||||
}
|
||||
|
||||
private static Point4D getRandomDestination()
|
||||
{
|
||||
// Our aim is to return a random link's source point
|
||||
// so that a link of type RANDOM can teleport a player there.
|
||||
|
||||
// Restrictions:
|
||||
// 1. Ignore links with their source inside a pocket dimension.
|
||||
// 2. Ignore links with link type RANDOM.
|
||||
|
||||
// Iterate over the root dimensions. Pocket dimensions cannot be roots.
|
||||
// Don't just pick a random root and a random link within that root
|
||||
// because we want to have unbiased selection among all links.
|
||||
ArrayList<Point4D> matches = new ArrayList<Point4D>();
|
||||
for (NewDimData dimension : PocketManager.getRootDimensions())
|
||||
{
|
||||
for (DimLink link : dimension.getAllLinks())
|
||||
{
|
||||
if (link.linkType() != LinkTypes.RANDOM)
|
||||
{
|
||||
matches.add(link.source());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pick a random point, if any is available
|
||||
if (!matches.isEmpty())
|
||||
{
|
||||
return matches.get( random.nextInt(matches.size()) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean generateUnsafeExit(DimLink link)
|
||||
{
|
||||
// An unsafe exit teleports the user to the first available air space
|
||||
// in the pocket's root dimension. X and Z are kept roughly the same
|
||||
// as the source location, but Y is set by searching down. We don't
|
||||
// place a platform at the destination. We also don't place a reverse
|
||||
// link at the destination, so it's a one-way trip. Good luck!
|
||||
|
||||
// To avoid loops, don't generate a destination if the player is
|
||||
// already in a non-pocket dimension.
|
||||
|
||||
NewDimData current = PocketManager.getDimensionData(link.source.getDimension());
|
||||
if (current.isPocketDimension())
|
||||
{
|
||||
Point4D source = link.source();
|
||||
World world = PocketManager.loadDimension(current.root().id());
|
||||
if (world == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Point3D destination = yCoordHelper.findDropPoint(world, source.getX(), source.getY() + 1, source.getZ());
|
||||
if (destination != null)
|
||||
{
|
||||
current.root().setDestination(link, destination.getX(), destination.getY(), destination.getZ());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void buildExitDoor(Block door,DimLink link, DDProperties prop)
|
||||
{
|
||||
World startWorld = PocketManager.loadDimension(link.source().getDimension());
|
||||
World destWorld = PocketManager.loadDimension(link.destination().getDimension());
|
||||
TileEntity doorTE = startWorld.getBlockTileEntity(link.source().getX(), link.source().getY(), link.source.getZ());
|
||||
if(doorTE instanceof TileEntityDimDoor)
|
||||
{
|
||||
if((TileEntityDimDoor.class.cast(doorTE).hasGennedPair))
|
||||
{
|
||||
return;
|
||||
}
|
||||
TileEntityDimDoor.class.cast(doorTE).hasGennedPair=true;
|
||||
Block blockToReplace = Block.blocksList[destWorld.getBlockId(link.destination().getX(), link.destination().getY(), link.destination().getZ())];
|
||||
|
||||
if(!destWorld.isAirBlock(link.destination().getX(), link.destination().getY(), link.destination().getZ()))
|
||||
{
|
||||
if(!blockToReplace.isBlockReplaceable(destWorld, link.destination().getX(), link.destination().getY(), link.destination().getZ()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BaseItemDoor.placeDoorBlock(destWorld, link.destination().getX(), link.destination().getY()-1, link.destination().getZ(),link.getDestinationOrientation(), door);
|
||||
TileEntity doorDestTE = startWorld.getBlockTileEntity(link.destination().getX(), link.destination().getY(), link.destination().getZ());
|
||||
|
||||
if(doorDestTE instanceof TileEntityDimDoor)
|
||||
{
|
||||
TileEntityDimDoor.class.cast(doorDestTE).hasGennedPair=true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
private static boolean generateSafeExit(DimLink link, DDProperties properties)
|
||||
{
|
||||
NewDimData current = PocketManager.getDimensionData(link.source.getDimension());
|
||||
return generateSafeExit(current.root(), link, properties);
|
||||
}
|
||||
|
||||
private static boolean generateDungeonExit(DimLink link, DDProperties properties)
|
||||
{
|
||||
// A dungeon exit acts the same as a safe exit, but has the chance of
|
||||
// taking the user to any non-pocket dimension, excluding Limbo and The End.
|
||||
|
||||
NewDimData current = PocketManager.getDimensionData(link.source.getDimension());
|
||||
ArrayList<NewDimData> roots = PocketManager.getRootDimensions();
|
||||
int shiftChance = START_ROOT_SHIFT_CHANCE + ROOT_SHIFT_CHANCE_PER_LEVEL * (current.packDepth() - 1);
|
||||
|
||||
if (random.nextInt(MAX_ROOT_SHIFT_CHANCE) < shiftChance)
|
||||
{
|
||||
for (int attempts = 0; attempts < 10; attempts++)
|
||||
{
|
||||
NewDimData selection = roots.get( random.nextInt(roots.size()) );
|
||||
if (selection.id() != END_DIMENSION_ID &&
|
||||
selection.id() != properties.LimboDimensionID &&
|
||||
selection != current.root())
|
||||
{
|
||||
return generateSafeExit(selection, link, properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Yes, this could lead you back into Limbo. That's intentional.
|
||||
return generateSafeExit(current.root(), link, properties);
|
||||
}
|
||||
|
||||
private static boolean generateSafeExit(NewDimData destinationDim, DimLink link, DDProperties properties)
|
||||
{
|
||||
// A safe exit attempts to place a Warp Door in a dimension with
|
||||
// some precautions to protect the player. The X and Z coordinates
|
||||
// are fixed to match the source (mostly - may be shifted a little),
|
||||
// but the Y coordinate is chosen by searching for the nearest
|
||||
// a safe location to place the door.
|
||||
|
||||
Point4D source = link.source();
|
||||
World world = PocketManager.loadDimension(destinationDim.id());
|
||||
if (world == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int startY = source.getY() - 2;
|
||||
Point3D destination;
|
||||
Point3D locationUp = yCoordHelper.findSafeCubeUp(world, source.getX(), startY, source.getZ());
|
||||
Point3D locationDown = yCoordHelper.findSafeCubeDown(world, source.getX(), startY, source.getZ());
|
||||
|
||||
if (locationUp == null)
|
||||
{
|
||||
destination = locationDown;
|
||||
}
|
||||
else if (locationDown == null)
|
||||
{
|
||||
destination = locationUp;
|
||||
}
|
||||
else if (locationUp.getY() - startY <= startY - locationDown.getY())
|
||||
{
|
||||
destination = locationUp;
|
||||
}
|
||||
else
|
||||
{
|
||||
destination = locationDown;
|
||||
}
|
||||
if (destination != null)
|
||||
{
|
||||
// Set up a 3x3 platform at the destination
|
||||
int x = destination.getX();
|
||||
int y = destination.getY();
|
||||
int z = destination.getZ();
|
||||
for (int dx = -1; dx <= 1; dx++)
|
||||
{
|
||||
for (int dz = -1; dz <= 1; dz++)
|
||||
{
|
||||
world.setBlock(x + dx, y, z + dz, properties.FabricBlockID);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a reverse link for returning
|
||||
int orientation = getDestinationOrientation(source, properties);
|
||||
NewDimData sourceDim = PocketManager.getDimensionData(link.source().getDimension());
|
||||
DimLink reverse = destinationDim.createLink(x, y + 2, z, LinkTypes.REVERSE,orientation);
|
||||
sourceDim.setDestination(reverse, source.getX(), source.getY(), source.getZ());
|
||||
|
||||
// Set up the warp door at the destination
|
||||
orientation = BlockRotator.transformMetadata(orientation, 2, properties.WarpDoorID);
|
||||
ItemDimensionalDoor.placeDoorBlock(world, x, y + 1, z, orientation, mod_pocketDim.warpDoor);
|
||||
|
||||
// Complete the link to the destination
|
||||
// This comes last so the destination isn't set unless everything else works first
|
||||
destinationDim.setDestination(link, x, y + 2, z);
|
||||
}
|
||||
|
||||
return (destination != null);
|
||||
}
|
||||
}
|
||||
91
StevenDimDoors/mod_pocketDim/core/DimLink.java
Normal file
91
StevenDimDoors/mod_pocketDim/core/DimLink.java
Normal file
@@ -0,0 +1,91 @@
|
||||
package StevenDimDoors.mod_pocketDim.core;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import StevenDimDoors.mod_pocketDim.util.Point4D;
|
||||
|
||||
public abstract class DimLink
|
||||
{
|
||||
protected Point4D source;
|
||||
protected DimLink parent;
|
||||
protected LinkTail tail;
|
||||
protected int orientation;
|
||||
protected List<DimLink> children;
|
||||
|
||||
protected DimLink(Point4D source, DimLink parent, int orientation)
|
||||
{
|
||||
|
||||
if (parent.source.getDimension() != source.getDimension())
|
||||
{
|
||||
// Ban having children in other dimensions to avoid serialization issues with cross-dimensional tails
|
||||
throw new IllegalArgumentException("source and parent.source must have the same dimension.");
|
||||
}
|
||||
this.orientation=orientation;
|
||||
this.parent = parent;
|
||||
this.source = source;
|
||||
this.tail = parent.tail;
|
||||
this.children = new LinkedList<DimLink>();
|
||||
parent.children.add(this);
|
||||
}
|
||||
|
||||
protected DimLink(Point4D source, int linkType, int orientation)
|
||||
{
|
||||
if ((linkType < LinkTypes.ENUM_MIN || linkType > LinkTypes.ENUM_MAX) && linkType != LinkTypes.CLIENT_SIDE)
|
||||
{
|
||||
throw new IllegalArgumentException("The specified link type is invalid.");
|
||||
}
|
||||
this.orientation = orientation;
|
||||
this.parent = null;
|
||||
this.source = source;
|
||||
this.tail = new LinkTail(linkType, null);
|
||||
this.children = new LinkedList<DimLink>();
|
||||
}
|
||||
|
||||
public Point4D source()
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
public Point4D destination()
|
||||
{
|
||||
return tail.getDestination();
|
||||
}
|
||||
public int getDestinationOrientation()
|
||||
{
|
||||
return PocketManager.getLink(source.getX(), source.getY(), source.getZ(), source.getDimension()).orientation();
|
||||
}
|
||||
public boolean hasDestination()
|
||||
{
|
||||
return (tail.getDestination() != null);
|
||||
}
|
||||
|
||||
public Iterable<DimLink> children()
|
||||
{
|
||||
return children;
|
||||
}
|
||||
|
||||
public int childCount()
|
||||
{
|
||||
return children.size();
|
||||
}
|
||||
|
||||
public DimLink parent()
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
|
||||
public int linkType()
|
||||
{
|
||||
return tail.getLinkType();
|
||||
}
|
||||
public int orientation()
|
||||
{
|
||||
return orientation;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return source + " -> " + (hasDestination() ? destination() : "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package StevenDimDoors.mod_pocketDim.core;
|
||||
|
||||
public interface IDimRegistrationCallback
|
||||
{
|
||||
public NewDimData registerDimension(int dimensionID, int rootID);
|
||||
}
|
||||
32
StevenDimDoors/mod_pocketDim/core/LinkTail.java
Normal file
32
StevenDimDoors/mod_pocketDim/core/LinkTail.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package StevenDimDoors.mod_pocketDim.core;
|
||||
|
||||
import StevenDimDoors.mod_pocketDim.util.Point4D;
|
||||
|
||||
class LinkTail
|
||||
{
|
||||
private Point4D destination;
|
||||
private int linkType;
|
||||
|
||||
public LinkTail(int linkType, Point4D destination)
|
||||
{
|
||||
this.linkType = linkType;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public Point4D getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public void setDestination(Point4D destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public int getLinkType() {
|
||||
return linkType;
|
||||
}
|
||||
|
||||
public void setLinkType(int linkType) {
|
||||
this.linkType = linkType;
|
||||
}
|
||||
|
||||
}
|
||||
21
StevenDimDoors/mod_pocketDim/core/LinkTypes.java
Normal file
21
StevenDimDoors/mod_pocketDim/core/LinkTypes.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package StevenDimDoors.mod_pocketDim.core;
|
||||
|
||||
public class LinkTypes
|
||||
{
|
||||
private LinkTypes() { }
|
||||
|
||||
public static final int ENUM_MIN = 0;
|
||||
public static final int ENUM_MAX = 7;
|
||||
|
||||
public static final int CLIENT_SIDE = -1337;
|
||||
|
||||
// WARNING: Don't modify these values carelessly or you'll risk breaking links in existing worlds!
|
||||
public static final int NORMAL = 0;
|
||||
public static final int POCKET = 1;
|
||||
public static final int DUNGEON = 2;
|
||||
public static final int RANDOM = 3;
|
||||
public static final int DUNGEON_EXIT = 4;
|
||||
public static final int SAFE_EXIT = 5;
|
||||
public static final int UNSAFE_EXIT = 6;
|
||||
public static final int REVERSE = 7;
|
||||
}
|
||||
551
StevenDimDoors/mod_pocketDim/core/NewDimData.java
Normal file
551
StevenDimDoors/mod_pocketDim/core/NewDimData.java
Normal file
@@ -0,0 +1,551 @@
|
||||
package StevenDimDoors.mod_pocketDim.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
import StevenDimDoors.mod_pocketDim.DDProperties;
|
||||
import StevenDimDoors.mod_pocketDim.Point3D;
|
||||
import StevenDimDoors.mod_pocketDim.dungeon.DungeonData;
|
||||
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack;
|
||||
import StevenDimDoors.mod_pocketDim.util.Point4D;
|
||||
import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher;
|
||||
|
||||
public abstract class NewDimData
|
||||
{
|
||||
private static class InnerDimLink extends DimLink
|
||||
{
|
||||
public InnerDimLink(Point4D source, DimLink parent,int orientation)
|
||||
{
|
||||
super(source, parent,orientation);
|
||||
}
|
||||
|
||||
public InnerDimLink(Point4D source, int linkType, int orientation)
|
||||
{
|
||||
super(source, linkType,orientation);
|
||||
}
|
||||
|
||||
public void setDestination(int x, int y, int z, NewDimData dimension)
|
||||
{
|
||||
tail.setDestination(new Point4D(x, y, z, dimension.id()));
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
//Release children
|
||||
for (DimLink child : children)
|
||||
{
|
||||
((InnerDimLink) child).parent = null;
|
||||
}
|
||||
children.clear();
|
||||
|
||||
//Release parent
|
||||
if (parent != null)
|
||||
{
|
||||
parent.children.remove(this);
|
||||
}
|
||||
|
||||
parent = null;
|
||||
source = null;
|
||||
tail = new LinkTail(0, null);
|
||||
}
|
||||
|
||||
public boolean overwrite(InnerDimLink nextParent,int orientation)
|
||||
{
|
||||
if (nextParent == null)
|
||||
{
|
||||
throw new IllegalArgumentException("nextParent cannot be null.");
|
||||
}
|
||||
if (this == nextParent)
|
||||
{
|
||||
//Ignore this request silently
|
||||
return false;
|
||||
}
|
||||
if (nextParent.source.getDimension() != source.getDimension())
|
||||
{
|
||||
// Ban having children in other dimensions to avoid serialization issues with cross-dimensional tails
|
||||
throw new IllegalArgumentException("source and parent.source must have the same dimension.");
|
||||
}
|
||||
|
||||
//Release children
|
||||
for (DimLink child : children)
|
||||
{
|
||||
((InnerDimLink) child).parent = null;
|
||||
}
|
||||
children.clear();
|
||||
|
||||
//Release parent
|
||||
if (parent != null)
|
||||
{
|
||||
parent.children.remove(this);
|
||||
}
|
||||
|
||||
//Attach to new parent
|
||||
parent = nextParent;
|
||||
tail = nextParent.tail;
|
||||
nextParent.children.add(this);
|
||||
this.orientation=orientation;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void overwrite(int linkType, int orientation)
|
||||
{
|
||||
//Release children
|
||||
for (DimLink child : children)
|
||||
{
|
||||
((InnerDimLink) child).parent = null;
|
||||
}
|
||||
children.clear();
|
||||
|
||||
//Release parent
|
||||
if (parent != null)
|
||||
{
|
||||
parent.children.remove(this);
|
||||
}
|
||||
|
||||
//Attach to new parent
|
||||
parent = null;
|
||||
tail = new LinkTail(linkType, null);
|
||||
//Set new orientation
|
||||
this.orientation=orientation;
|
||||
}
|
||||
}
|
||||
|
||||
protected static Random random = new Random();
|
||||
|
||||
protected int id;
|
||||
protected Map<Point4D, InnerDimLink> linkMapping;
|
||||
protected List<InnerDimLink> linkList;
|
||||
protected boolean isDungeon;
|
||||
protected boolean isFilled;
|
||||
protected int depth;
|
||||
protected int packDepth;
|
||||
protected NewDimData parent;
|
||||
protected NewDimData root;
|
||||
protected List<NewDimData> children;
|
||||
protected Point4D origin;
|
||||
protected int orientation;
|
||||
protected DungeonData dungeon;
|
||||
protected IUpdateWatcher<Point4D> linkWatcher;
|
||||
|
||||
protected NewDimData(int id, NewDimData parent, boolean isPocket, boolean isDungeon,
|
||||
IUpdateWatcher<Point4D> linkWatcher)
|
||||
{
|
||||
// The isPocket flag is redundant. It's meant as an integrity safeguard.
|
||||
if (isPocket && (parent == null))
|
||||
{
|
||||
throw new NullPointerException("Dimensions can be pocket dimensions if and only if they have a parent dimension.");
|
||||
}
|
||||
if (isDungeon && !isPocket)
|
||||
{
|
||||
throw new IllegalArgumentException("A dimensional dungeon must also be a pocket dimension.");
|
||||
}
|
||||
|
||||
this.id = id;
|
||||
this.linkMapping = new TreeMap<Point4D, InnerDimLink>(); //Should be stored in oct tree -- temporary solution
|
||||
this.linkList = new ArrayList<InnerDimLink>(); //Should be stored in oct tree -- temporary solution
|
||||
this.children = new ArrayList<NewDimData>();
|
||||
this.parent = parent;
|
||||
this.packDepth = 0;
|
||||
this.isDungeon = isDungeon;
|
||||
this.isFilled = false;
|
||||
this.orientation = 0;
|
||||
this.origin = null;
|
||||
this.dungeon = null;
|
||||
this.linkWatcher = linkWatcher;
|
||||
|
||||
//Register with parent
|
||||
if (parent != null)
|
||||
{
|
||||
//We don't need to raise an update event for adding a child because the child's creation will be signaled.
|
||||
this.root = parent.root;
|
||||
this.depth = parent.depth + 1;
|
||||
parent.children.add(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.root = this;
|
||||
this.depth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected NewDimData(int id, NewDimData root)
|
||||
{
|
||||
// This constructor is meant for client-side code only
|
||||
if (root == null)
|
||||
{
|
||||
throw new IllegalArgumentException("root cannot be null.");
|
||||
}
|
||||
|
||||
this.id = id;
|
||||
this.linkMapping = new TreeMap<Point4D, InnerDimLink>(); //Should be stored in oct tree -- temporary solution
|
||||
this.linkList = new ArrayList<InnerDimLink>(); //Should be stored in oct tree -- temporary solution
|
||||
this.children = new ArrayList<NewDimData>();
|
||||
this.parent = null;
|
||||
this.packDepth = 0;
|
||||
this.isDungeon = false;
|
||||
this.isFilled = false;
|
||||
this.orientation = 0;
|
||||
this.origin = null;
|
||||
this.dungeon = null;
|
||||
this.linkWatcher = null;
|
||||
this.depth = 0;
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
public DimLink findNearestRift(World world, int range, int x, int y, int z)
|
||||
{
|
||||
//TODO: Rewrite this later to use an octtree
|
||||
|
||||
//Sanity check...
|
||||
if (world.provider.dimensionId != id)
|
||||
{
|
||||
throw new IllegalArgumentException("Attempted to search for links in a World instance for a different dimension!");
|
||||
}
|
||||
|
||||
//Note: Only detect rifts at a distance > 1, so we ignore the rift
|
||||
//that called this function and any adjacent rifts.
|
||||
|
||||
DimLink nearest = null;
|
||||
DimLink link;
|
||||
|
||||
int distance;
|
||||
int minDistance = Integer.MAX_VALUE;
|
||||
int i, j, k;
|
||||
DDProperties properties = DDProperties.instance();
|
||||
|
||||
for (i = -range; i <= range; i++)
|
||||
{
|
||||
for (j = -range; j <= range; j++)
|
||||
{
|
||||
for (k = -range; k <= range; k++)
|
||||
{
|
||||
distance = getAbsoluteSum(i, j, k);
|
||||
if (distance > 1 && distance < minDistance && world.getBlockId(x + i, y + j, z + k) == properties.RiftBlockID)
|
||||
{
|
||||
link = getLink(x+i, y+j, z+k);
|
||||
if (link != null)
|
||||
{
|
||||
nearest = link;
|
||||
minDistance = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nearest;
|
||||
}
|
||||
|
||||
private static int getAbsoluteSum(int i, int j, int k)
|
||||
{
|
||||
return Math.abs(i) + Math.abs(j) + Math.abs(k);
|
||||
}
|
||||
public DimLink createLink(int x, int y, int z, int linkType)
|
||||
{
|
||||
return createLink(new Point4D(x, y, z, id), linkType,0);
|
||||
}
|
||||
public DimLink createLink(int x, int y, int z, int linkType,int orientation)
|
||||
{
|
||||
return createLink(new Point4D(x, y, z, id), linkType,orientation);
|
||||
}
|
||||
|
||||
public DimLink createLink(Point4D source, int linkType,int orientation)
|
||||
{
|
||||
//Return an existing link if there is one to avoid creating multiple links starting at the same point.
|
||||
InnerDimLink link = linkMapping.get(source);
|
||||
if (link == null)
|
||||
{
|
||||
link = new InnerDimLink(source, linkType,orientation);
|
||||
linkMapping.put(source, link);
|
||||
linkList.add(link);
|
||||
}
|
||||
else
|
||||
{
|
||||
link.overwrite(linkType,orientation);
|
||||
}
|
||||
//Link created!
|
||||
if(linkType!=LinkTypes.CLIENT_SIDE)
|
||||
{
|
||||
linkWatcher.onCreated(link.source);
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
||||
public DimLink createChildLink(int x, int y, int z, DimLink parent)
|
||||
{
|
||||
if (parent == null)
|
||||
{
|
||||
throw new IllegalArgumentException("parent cannot be null.");
|
||||
}
|
||||
|
||||
return createChildLink(new Point4D(x, y, z, id), (InnerDimLink) parent);
|
||||
}
|
||||
|
||||
private DimLink createChildLink(Point4D source, InnerDimLink parent)
|
||||
{
|
||||
//To avoid having multiple links at a single point, if we find an existing link then we overwrite
|
||||
//its destination data instead of creating a new instance.
|
||||
|
||||
InnerDimLink link = linkMapping.get(source);
|
||||
if (link == null)
|
||||
{
|
||||
link = new InnerDimLink(source, parent, parent.orientation);
|
||||
linkMapping.put(source, link);
|
||||
linkList.add(link);
|
||||
|
||||
//Link created!
|
||||
linkWatcher.onCreated(link.source);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (link.overwrite(parent, parent.orientation))
|
||||
{
|
||||
//Link created!
|
||||
linkWatcher.onCreated(link.source);
|
||||
}
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
||||
public boolean deleteLink(DimLink link)
|
||||
{
|
||||
if (link.source().getDimension() != id)
|
||||
{
|
||||
throw new IllegalArgumentException("Attempted to delete a link from another dimension.");
|
||||
}
|
||||
InnerDimLink target = linkMapping.remove(link.source());
|
||||
if (target != null)
|
||||
{
|
||||
linkList.remove(target);
|
||||
//Raise deletion event
|
||||
linkWatcher.onDeleted(target.source);
|
||||
target.clear();
|
||||
}
|
||||
return (target != null);
|
||||
}
|
||||
|
||||
public boolean deleteLink(int x, int y, int z)
|
||||
{
|
||||
Point4D location = new Point4D(x, y, z, id);
|
||||
InnerDimLink target = linkMapping.remove(location);
|
||||
if (target != null)
|
||||
{
|
||||
linkList.remove(target);
|
||||
//Raise deletion event
|
||||
linkWatcher.onDeleted(target.source);
|
||||
target.clear();
|
||||
}
|
||||
return (target != null);
|
||||
}
|
||||
|
||||
public DimLink getLink(int x, int y, int z)
|
||||
{
|
||||
Point4D location = new Point4D(x, y, z, id);
|
||||
return linkMapping.get(location);
|
||||
}
|
||||
|
||||
public DimLink getLink(Point3D location)
|
||||
{
|
||||
return linkMapping.get(new Point4D(location.getX(),location.getY(),location.getZ(),this.id));
|
||||
}
|
||||
|
||||
public DimLink getLink(Point4D location)
|
||||
{
|
||||
if (location.getDimension() != id)
|
||||
return null;
|
||||
|
||||
return linkMapping.get(location);
|
||||
}
|
||||
|
||||
public ArrayList<DimLink> getAllLinks()
|
||||
{
|
||||
ArrayList<DimLink> results = new ArrayList<DimLink>(linkMapping.size());
|
||||
results.addAll(linkMapping.values());
|
||||
return results;
|
||||
}
|
||||
|
||||
public boolean isPocketDimension()
|
||||
{
|
||||
return (root != this);
|
||||
}
|
||||
|
||||
public boolean isDungeon()
|
||||
{
|
||||
return isDungeon;
|
||||
}
|
||||
|
||||
public boolean isFilled()
|
||||
{
|
||||
return isFilled;
|
||||
}
|
||||
|
||||
public void setFilled(boolean isFilled)
|
||||
{
|
||||
this.isFilled = isFilled;
|
||||
}
|
||||
|
||||
public int id()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public int depth()
|
||||
{
|
||||
return depth;
|
||||
}
|
||||
|
||||
public int packDepth()
|
||||
{
|
||||
return packDepth;
|
||||
}
|
||||
|
||||
public Point4D origin()
|
||||
{
|
||||
return origin;
|
||||
}
|
||||
|
||||
public NewDimData parent()
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
|
||||
public NewDimData root()
|
||||
{
|
||||
return root;
|
||||
}
|
||||
|
||||
public int orientation()
|
||||
{
|
||||
return orientation;
|
||||
}
|
||||
|
||||
public DungeonData dungeon()
|
||||
{
|
||||
return dungeon;
|
||||
}
|
||||
|
||||
public boolean isInitialized()
|
||||
{
|
||||
return (origin != null);
|
||||
}
|
||||
|
||||
public int linkCount()
|
||||
{
|
||||
return linkList.size();
|
||||
}
|
||||
|
||||
public Iterable<NewDimData> children()
|
||||
{
|
||||
return children;
|
||||
}
|
||||
|
||||
public Iterable<? extends DimLink> links()
|
||||
{
|
||||
return linkList;
|
||||
}
|
||||
|
||||
public void initializeDungeon(int originX, int originY, int originZ, int orientation, DimLink incoming, DungeonData dungeon)
|
||||
{
|
||||
if (!isDungeon)
|
||||
{
|
||||
throw new IllegalStateException("Cannot invoke initializeDungeon() on a non-dungeon dimension.");
|
||||
}
|
||||
if (isInitialized())
|
||||
{
|
||||
throw new IllegalStateException("The dimension has already been initialized.");
|
||||
}
|
||||
if (orientation < 0 || orientation > 3)
|
||||
{
|
||||
throw new IllegalArgumentException("orientation must be between 0 and 3, inclusive.");
|
||||
}
|
||||
setDestination(incoming, originX, originY, originZ);
|
||||
this.origin = incoming.destination();
|
||||
this.orientation = orientation;
|
||||
this.dungeon = dungeon;
|
||||
this.packDepth = calculatePackDepth(parent, dungeon);
|
||||
}
|
||||
|
||||
/**
|
||||
* effectivly moves the dungeon to the 'top' of a chain as far as dungeon generation is concerend.
|
||||
*/
|
||||
public void setParentToRoot()
|
||||
{
|
||||
this.depth=1;
|
||||
this.parent=this.root;
|
||||
this.root.children.add(this);
|
||||
}
|
||||
|
||||
public static int calculatePackDepth(NewDimData parent, DungeonData current)
|
||||
{
|
||||
DungeonData predecessor = parent.dungeon();
|
||||
if (current == null)
|
||||
{
|
||||
throw new IllegalArgumentException("current cannot be null.");
|
||||
}
|
||||
if (predecessor == null)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
DungeonPack predOwner = predecessor.dungeonType().Owner;
|
||||
DungeonPack currentOwner = current.dungeonType().Owner;
|
||||
if (currentOwner == null)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (predOwner == null)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (predOwner == currentOwner)
|
||||
{
|
||||
return parent.packDepth + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void initializePocket(int originX, int originY, int originZ, int orientation, DimLink incoming)
|
||||
{
|
||||
if (!isPocketDimension())
|
||||
{
|
||||
throw new IllegalStateException("Cannot invoke initializePocket() on a non-pocket dimension.");
|
||||
}
|
||||
if (isInitialized())
|
||||
{
|
||||
throw new IllegalStateException("The dimension has already been initialized.");
|
||||
}
|
||||
|
||||
setDestination(incoming, originX, originY, originZ);
|
||||
this.origin = incoming.destination();
|
||||
this.orientation = orientation;
|
||||
}
|
||||
|
||||
public void setDestination(DimLink incoming, int x, int y, int z)
|
||||
{
|
||||
InnerDimLink link = (InnerDimLink) incoming;
|
||||
link.setDestination(x, y, z, this);
|
||||
}
|
||||
|
||||
public DimLink getRandomLink()
|
||||
{
|
||||
if (linkMapping.isEmpty())
|
||||
{
|
||||
throw new IllegalStateException("There are no links to select from in this dimension.");
|
||||
}
|
||||
if (linkList.size() > 1)
|
||||
{
|
||||
return linkList.get(random.nextInt(linkList.size()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return linkList.get(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
671
StevenDimDoors/mod_pocketDim/core/PocketManager.java
Normal file
671
StevenDimDoors/mod_pocketDim/core/PocketManager.java
Normal file
@@ -0,0 +1,671 @@
|
||||
package StevenDimDoors.mod_pocketDim.core;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
import StevenDimDoors.mod_pocketDim.DDProperties;
|
||||
import StevenDimDoors.mod_pocketDim.Point3D;
|
||||
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
|
||||
import StevenDimDoors.mod_pocketDim.helpers.Compactor;
|
||||
import StevenDimDoors.mod_pocketDim.helpers.DeleteFolder;
|
||||
import StevenDimDoors.mod_pocketDim.saving.DDSaveHandler;
|
||||
import StevenDimDoors.mod_pocketDim.saving.IPackable;
|
||||
import StevenDimDoors.mod_pocketDim.saving.OldSaveImporter;
|
||||
import StevenDimDoors.mod_pocketDim.saving.PackedDimData;
|
||||
import StevenDimDoors.mod_pocketDim.saving.PackedDungeonData;
|
||||
import StevenDimDoors.mod_pocketDim.saving.PackedLinkData;
|
||||
import StevenDimDoors.mod_pocketDim.saving.PackedLinkTail;
|
||||
import StevenDimDoors.mod_pocketDim.util.Point4D;
|
||||
import StevenDimDoors.mod_pocketDim.watcher.ClientDimData;
|
||||
import StevenDimDoors.mod_pocketDim.watcher.IUpdateSource;
|
||||
import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher;
|
||||
import StevenDimDoors.mod_pocketDim.watcher.UpdateWatcherProxy;
|
||||
|
||||
/**
|
||||
* This class regulates all the operations involving the storage and manipulation of dimensions. It handles saving dim data, teleporting the player, and
|
||||
* creating/registering new dimensions as well as loading old dimensions on startup
|
||||
*/
|
||||
public class PocketManager
|
||||
{
|
||||
private static class InnerDimData extends NewDimData implements IPackable<PackedDimData>
|
||||
{
|
||||
// This class allows us to instantiate NewDimData indirectly without exposing
|
||||
// a public constructor from NewDimData. It's meant to stop us from constructing
|
||||
// instances of NewDimData going through PocketManager. In turn, that enforces
|
||||
// that any link destinations must be real dimensions controlled by PocketManager.
|
||||
|
||||
public InnerDimData(int id, InnerDimData parent, boolean isPocket, boolean isDungeon,
|
||||
IUpdateWatcher<Point4D> linkWatcher)
|
||||
{
|
||||
super(id, parent, isPocket, isDungeon, linkWatcher);
|
||||
}
|
||||
|
||||
public InnerDimData(int id, InnerDimData root)
|
||||
{
|
||||
// This constructor is meant for client-side code only
|
||||
super(id, root);
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
// If this dimension has a parent, remove it from its parent's list of children
|
||||
if (parent != null)
|
||||
{
|
||||
parent.children.remove(this);
|
||||
}
|
||||
// Remove this dimension as the parent of its children
|
||||
for (NewDimData child : children)
|
||||
{
|
||||
child.parent = null;
|
||||
}
|
||||
// Clear all fields
|
||||
id = Integer.MIN_VALUE;
|
||||
linkMapping.clear();
|
||||
linkMapping = null;
|
||||
linkList.clear();
|
||||
linkList = null;
|
||||
children.clear();
|
||||
children = null;
|
||||
isDungeon = false;
|
||||
isFilled = false;
|
||||
depth = Integer.MIN_VALUE;
|
||||
packDepth = Integer.MIN_VALUE;
|
||||
origin = null;
|
||||
orientation = Integer.MIN_VALUE;
|
||||
dungeon = null;
|
||||
linkWatcher = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return String.valueOf(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PackedDimData pack()
|
||||
{
|
||||
ArrayList<Integer> ChildIDs = new ArrayList<Integer>();
|
||||
ArrayList<PackedLinkData> Links = new ArrayList<PackedLinkData>();
|
||||
ArrayList<PackedLinkTail> Tails = new ArrayList<PackedLinkTail>();
|
||||
PackedDungeonData packedDungeon=null;
|
||||
|
||||
if(this.dungeon!=null)
|
||||
{
|
||||
packedDungeon= new PackedDungeonData(dungeon.weight(), dungeon.isOpen(), dungeon.isInternal(),
|
||||
dungeon.schematicPath(), dungeon.schematicName(), dungeon.dungeonType().Name,
|
||||
dungeon.dungeonType().Owner.getName());
|
||||
}
|
||||
//Make a list of children
|
||||
for(NewDimData data : this.children)
|
||||
{
|
||||
ChildIDs.add(data.id);
|
||||
}
|
||||
for(DimLink link:this.links())
|
||||
{
|
||||
ArrayList<Point3D> children = new ArrayList<Point3D>();
|
||||
Point3D parentPoint = new Point3D(-1,-1,-1);
|
||||
if(link.parent!=null)
|
||||
{
|
||||
parentPoint=link.parent.source.toPoint3D();
|
||||
}
|
||||
|
||||
for(DimLink childLink : link.children)
|
||||
{
|
||||
children.add(childLink.source().toPoint3D());
|
||||
}
|
||||
PackedLinkTail tail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType());
|
||||
Links.add(new PackedLinkData(link.source,parentPoint,tail,link.orientation,children));
|
||||
|
||||
PackedLinkTail tempTail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType());
|
||||
if(Tails.contains(tempTail))
|
||||
{
|
||||
Tails.add(tempTail);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
int parentID=this.id;
|
||||
Point3D originPoint=new Point3D(0,0,0);
|
||||
if(this.parent!=null)
|
||||
{
|
||||
parentID = this.parent.id;
|
||||
}
|
||||
if(this.origin!=null)
|
||||
{
|
||||
originPoint=this.origin.toPoint3D();
|
||||
}
|
||||
return new PackedDimData(this.id, depth, this.packDepth, parentID, this.root().id(), orientation,
|
||||
isDungeon, isFilled,packedDungeon, originPoint, ChildIDs, Links, Tails);
|
||||
// FIXME: IMPLEMENTATION PLZTHX
|
||||
//I tried
|
||||
}
|
||||
}
|
||||
|
||||
private static class ClientLinkWatcher implements IUpdateWatcher<Point4D>
|
||||
{
|
||||
@Override
|
||||
public void onCreated(Point4D source)
|
||||
{
|
||||
NewDimData dimension = getDimensionData(source.getDimension());
|
||||
dimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.CLIENT_SIDE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleted(Point4D source)
|
||||
{
|
||||
NewDimData dimension = getDimensionData(source.getDimension());
|
||||
dimension.deleteLink(source.getX(), source.getY(), source.getZ());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ClientDimWatcher implements IUpdateWatcher<ClientDimData>
|
||||
{
|
||||
@Override
|
||||
public void onCreated(ClientDimData data)
|
||||
{
|
||||
registerClientDimension(data.ID, data.RootID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleted(ClientDimData data)
|
||||
{
|
||||
deletePocket(getDimensionData(data.ID), false);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DimRegistrationCallback implements IDimRegistrationCallback
|
||||
{
|
||||
// We use this class to provide Compactor with the ability to send us dim data without
|
||||
// having to instantiate a bunch of data containers and without exposing an "unsafe"
|
||||
// creation method for anyone to call. Integrity protection for the win! It's like
|
||||
// exposing a private constructor ONLY to a very specific trusted class.
|
||||
|
||||
@Override
|
||||
public NewDimData registerDimension(int dimensionID, int rootID)
|
||||
{
|
||||
return registerClientDimension(dimensionID, rootID);
|
||||
}
|
||||
}
|
||||
|
||||
private static int OVERWORLD_DIMENSION_ID = 0;
|
||||
|
||||
private static volatile boolean isLoading = false;
|
||||
private static volatile boolean isLoaded = false;
|
||||
private static volatile boolean isSaving = false;
|
||||
private static final UpdateWatcherProxy<Point4D> linkWatcher = new UpdateWatcherProxy<Point4D>();
|
||||
private static final UpdateWatcherProxy<ClientDimData> dimWatcher = new UpdateWatcherProxy<ClientDimData>();
|
||||
private static ArrayList<NewDimData> rootDimensions = null;
|
||||
|
||||
//HashMap that maps all the dimension IDs registered with DimDoors to their DD data.
|
||||
private static HashMap<Integer, InnerDimData> dimensionData = null;
|
||||
//ArrayList that stores the dimension IDs of any dimension that has been deleted.
|
||||
private static ArrayList<Integer> dimensionIDBlackList = null;
|
||||
|
||||
public static boolean isLoaded()
|
||||
{
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* simple method called on startup to register all dims saved in the dim list. Only tries to register pocket dims, though. Also calls load()
|
||||
* @return
|
||||
*/
|
||||
public static void load()
|
||||
{
|
||||
if (isLoaded)
|
||||
{
|
||||
throw new IllegalStateException("Pocket dimensions have already been loaded!");
|
||||
}
|
||||
if (isLoading)
|
||||
{
|
||||
return;
|
||||
}
|
||||
isLoading = true;
|
||||
|
||||
dimensionData = new HashMap<Integer, InnerDimData>();
|
||||
rootDimensions = new ArrayList<NewDimData>();
|
||||
dimensionIDBlackList = new ArrayList<Integer>();
|
||||
|
||||
if(FMLCommonHandler.instance().getEffectiveSide().isClient())
|
||||
{
|
||||
//Shouldnt try to load everything if we are a client
|
||||
//This was preventing onPacket from loading properly
|
||||
isLoading=false;
|
||||
return;
|
||||
}
|
||||
//Register Limbo
|
||||
DDProperties properties = DDProperties.instance();
|
||||
registerDimension(properties.LimboDimensionID, null, false, false);
|
||||
|
||||
loadInternal();
|
||||
|
||||
//Register pocket dimensions
|
||||
registerPockets(properties);
|
||||
|
||||
isLoaded = true;
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
public static boolean registerPackedDimData(PackedDimData packedData)
|
||||
{
|
||||
InnerDimData dimData;
|
||||
|
||||
if(packedData.ID==packedData.ParentID)
|
||||
{
|
||||
dimData = new InnerDimData(packedData.ID, null, false, false, linkWatcher);
|
||||
dimData.root=dimData;
|
||||
dimData.parent=dimData;
|
||||
dimData.isFilled=packedData.IsFilled;
|
||||
|
||||
PocketManager.rootDimensions.add(dimData);
|
||||
}
|
||||
else
|
||||
{
|
||||
InnerDimData test = PocketManager.dimensionData.get(packedData.ParentID);
|
||||
dimData = new InnerDimData(packedData.ID, test,true, packedData.IsDungeon, linkWatcher);
|
||||
dimData.isFilled=packedData.IsFilled;
|
||||
|
||||
dimData.root=PocketManager.getDimensionData(packedData.RootID);
|
||||
|
||||
if(packedData.DungeonData!=null)
|
||||
{
|
||||
dimData.dungeon=DDSaveHandler.unpackDungeonData(packedData.DungeonData);
|
||||
}
|
||||
|
||||
}
|
||||
PocketManager.dimensionData.put(dimData.id, dimData);
|
||||
dimWatcher.onCreated(new ClientDimData(dimData));
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
public static boolean deletePocket(NewDimData target, boolean deleteFolder)
|
||||
{
|
||||
// We can't delete the dimension if it's currently loaded or if it's not actually a pocket.
|
||||
// We cast to InnerDimData so that if anyone tries to be a smartass and create their
|
||||
// own version of NewDimData, this will throw an exception.
|
||||
InnerDimData dimension = (InnerDimData) target;
|
||||
if (dimension.isPocketDimension() && DimensionManager.getWorld(dimension.id()) == null)
|
||||
{
|
||||
if (deleteFolder)
|
||||
{
|
||||
deleteDimensionFolder(target);
|
||||
}
|
||||
dimensionIDBlackList.add(dimension.id);
|
||||
deleteDimensionData(dimension.id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static boolean deleteDimensionFolder(NewDimData target)
|
||||
{
|
||||
InnerDimData dimension = (InnerDimData) target;
|
||||
if (dimension.isPocketDimension() && DimensionManager.getWorld(dimension.id()) == null)
|
||||
{
|
||||
File saveDirectory = new File(DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/pocketDimID" + dimension.id());
|
||||
DeleteFolder.deleteFolder(saveDirectory);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static boolean deleteDimensionData(int dimensionID)
|
||||
{
|
||||
if(dimensionData.containsKey(dimensionID)&& DimensionManager.getWorld(dimensionID) == null)
|
||||
{
|
||||
NewDimData target = PocketManager.getDimensionData(dimensionID);
|
||||
InnerDimData dimension = (InnerDimData) target;
|
||||
|
||||
dimensionData.remove(dimensionID);
|
||||
// Raise the dim deleted event
|
||||
dimWatcher.onDeleted(new ClientDimData(dimension));
|
||||
dimension.clear();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void registerPockets(DDProperties properties)
|
||||
{
|
||||
for (NewDimData dimension : dimensionData.values())
|
||||
{
|
||||
if (dimension.isPocketDimension())
|
||||
{
|
||||
try
|
||||
{
|
||||
DimensionManager.registerDimension(dimension.id(), properties.PocketProviderID);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
System.err.println("Could not register pocket dimension #" + dimension.id() + ". Probably caused by a version update/save data corruption/other mods.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void unregisterPockets()
|
||||
{
|
||||
for (NewDimData dimension : dimensionData.values())
|
||||
{
|
||||
if (dimension.isPocketDimension())
|
||||
{
|
||||
try
|
||||
{
|
||||
DimensionManager.unregisterDimension(dimension.id());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
System.err.println("An unexpected error occurred while unregistering pocket dimension #" + dimension.id() + ":");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* loads the dim data from the saved hashMap. Also handles compatibility with old saves, see OldSaveHandler
|
||||
*/
|
||||
private static void loadInternal()
|
||||
{
|
||||
System.out.println(!FMLCommonHandler.instance().getSide().isClient());
|
||||
|
||||
File saveDir = DimensionManager.getCurrentSaveRootDirectory();
|
||||
if (saveDir != null)
|
||||
{
|
||||
// Load and register blacklisted dimension IDs
|
||||
File oldSaveData = new File(saveDir+"/DimensionalDoorsData");
|
||||
if(oldSaveData.exists())
|
||||
{
|
||||
try
|
||||
{
|
||||
System.out.println("Importing old DD save data...");
|
||||
OldSaveImporter.importOldSave(oldSaveData);
|
||||
oldSaveData.delete();
|
||||
|
||||
System.out.println("Import Succesful!");
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//TODO handle fail cases
|
||||
System.out.println("Import failed!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Load save data
|
||||
System.out.println("Loading Dimensional Doors save data...");
|
||||
if (DDSaveHandler.loadAll())
|
||||
{
|
||||
System.out.println("Loaded successfully!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void save()
|
||||
{
|
||||
if (!isLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
World world = DimensionManager.getWorld(OVERWORLD_DIMENSION_ID);
|
||||
if (world == null || world.isRemote || DimensionManager.getCurrentSaveRootDirectory() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//Check this last to make sure we set the flag shortly after.
|
||||
if (isSaving)
|
||||
{
|
||||
return;
|
||||
}
|
||||
isSaving = true;
|
||||
|
||||
try
|
||||
{
|
||||
System.out.println("Writing Dimensional Doors save data...");
|
||||
if ( DDSaveHandler.saveAll(dimensionData.values()) )
|
||||
{
|
||||
System.out.println("Saved successfully!");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Wrap the exception in a RuntimeException so functions that call
|
||||
// PocketManager.save() don't need to catch it. We want MC to
|
||||
// crash if something really bad happens rather than ignoring it!
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
isSaving = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static WorldServer loadDimension(int id)
|
||||
{
|
||||
WorldServer world = DimensionManager.getWorld(id);
|
||||
if (world == null)
|
||||
{
|
||||
DimensionManager.initDimension(id);
|
||||
world = DimensionManager.getWorld(id);
|
||||
}
|
||||
else if (world.provider == null)
|
||||
{
|
||||
DimensionManager.initDimension(id);
|
||||
world = DimensionManager.getWorld(id);
|
||||
}
|
||||
return world;
|
||||
}
|
||||
|
||||
public static NewDimData registerDimension(World world)
|
||||
{
|
||||
return registerDimension(world.provider.dimensionId, null, false, false);
|
||||
}
|
||||
|
||||
public static NewDimData registerPocket(NewDimData parent, boolean isDungeon)
|
||||
{
|
||||
if (parent == null)
|
||||
{
|
||||
throw new IllegalArgumentException("parent cannot be null. A pocket dimension must always have a parent dimension.");
|
||||
}
|
||||
|
||||
DDProperties properties = DDProperties.instance();
|
||||
int dimensionID = DimensionManager.getNextFreeDimId();
|
||||
DimensionManager.registerDimension(dimensionID, properties.PocketProviderID);
|
||||
return registerDimension(dimensionID, (InnerDimData) parent, true, isDungeon);
|
||||
}
|
||||
|
||||
private static NewDimData registerDimension(int dimensionID, InnerDimData parent, boolean isPocket, boolean isDungeon)
|
||||
{
|
||||
if (dimensionData.containsKey(dimensionID))
|
||||
{
|
||||
throw new IllegalArgumentException("Cannot register a dimension with ID = " + dimensionID + " because it has already been registered.");
|
||||
}
|
||||
//TODO blacklist stuff probably should happen here
|
||||
InnerDimData dimension = new InnerDimData(dimensionID, parent, isPocket, isDungeon, linkWatcher);
|
||||
dimensionData.put(dimensionID, dimension);
|
||||
if (!dimension.isPocketDimension())
|
||||
{
|
||||
rootDimensions.add(dimension);
|
||||
}
|
||||
dimWatcher.onCreated(new ClientDimData(dimension));
|
||||
|
||||
return dimension;
|
||||
}
|
||||
|
||||
private static NewDimData registerClientDimension(int dimensionID, int rootID)
|
||||
{
|
||||
// No need to raise events heres since this code should only run on the client side
|
||||
// getDimensionData() always handles root dimensions properly, even if the weren't defined before
|
||||
|
||||
// SenseiKiwi: I'm a little worried about how getDimensionData will raise
|
||||
// an event when it creates any root dimensions... Needs checking later.
|
||||
|
||||
InnerDimData root = (InnerDimData) getDimensionData(rootID);
|
||||
InnerDimData dimension;
|
||||
|
||||
if (rootID != dimensionID)
|
||||
{
|
||||
dimension = dimensionData.get(dimensionID);
|
||||
if (dimension == null)
|
||||
{
|
||||
dimension = new InnerDimData(dimensionID, root);
|
||||
dimensionData.put(dimension.id(), dimension);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dimension = root;
|
||||
}
|
||||
if(dimension.isPocketDimension())
|
||||
{
|
||||
//Im registering pocket dims here. I *think* we can assume that if its a pocket and we are
|
||||
//registering its dim data, we also need to register it with forge.
|
||||
DimensionManager.registerDimension(dimensionID, mod_pocketDim.properties.PocketProviderID);
|
||||
}
|
||||
return dimension;
|
||||
}
|
||||
|
||||
public static NewDimData getDimensionData(World world)
|
||||
{
|
||||
return getDimensionData(world.provider.dimensionId);
|
||||
}
|
||||
|
||||
public static NewDimData getDimensionData(int dimensionID)
|
||||
{
|
||||
//Retrieve the data for a dimension. If we don't have a record for that dimension,
|
||||
//assume it's a non-pocket dimension that hasn't been initialized with us before
|
||||
//and create a NewDimData instance for it.
|
||||
//Any pocket dimension must be listed with PocketManager to have a dimension ID
|
||||
//assigned, so it's safe to assume that any unknown dimensions don't belong to us.
|
||||
|
||||
NewDimData dimension = PocketManager.dimensionData.get(dimensionID);
|
||||
if (dimension == null)
|
||||
{
|
||||
dimension = registerDimension(dimensionID, null, false, false);
|
||||
}
|
||||
return dimension;
|
||||
}
|
||||
|
||||
public static Iterable<? extends NewDimData> getDimensions()
|
||||
{
|
||||
return dimensionData.values();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static ArrayList<NewDimData> getRootDimensions()
|
||||
{
|
||||
return (ArrayList<NewDimData>) rootDimensions.clone();
|
||||
}
|
||||
|
||||
public static void unload()
|
||||
{
|
||||
if (!isLoaded)
|
||||
{
|
||||
throw new IllegalStateException("Pocket dimensions have already been unloaded!");
|
||||
}
|
||||
|
||||
save();
|
||||
unregisterPockets();
|
||||
dimensionData = null;
|
||||
rootDimensions = null;
|
||||
isLoaded = false;
|
||||
}
|
||||
|
||||
public static DimLink getLink(int x, int y, int z, World world)
|
||||
{
|
||||
return getLink(x, y, z, world.provider.dimensionId);
|
||||
}
|
||||
|
||||
public static DimLink getLink(Point4D point)
|
||||
{
|
||||
return getLink(point.getX(), point.getY(), point.getZ(), point.getDimension());
|
||||
}
|
||||
|
||||
public static DimLink getLink(int x, int y, int z, int dimensionID)
|
||||
{
|
||||
NewDimData dimension = dimensionData.get(dimensionID);
|
||||
if (dimension != null)
|
||||
{
|
||||
return dimension.getLink(x, y, z);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isBlackListed(int dimensionID)
|
||||
{
|
||||
return PocketManager.dimensionIDBlackList.contains(dimensionID);
|
||||
}
|
||||
public static void registerDimWatcher(IUpdateWatcher<ClientDimData> watcher)
|
||||
{
|
||||
dimWatcher.registerReceiver(watcher);
|
||||
}
|
||||
|
||||
public static boolean unregisterDimWatcher(IUpdateWatcher<ClientDimData> watcher)
|
||||
{
|
||||
return dimWatcher.unregisterReceiver(watcher);
|
||||
}
|
||||
|
||||
public static void registerLinkWatcher(IUpdateWatcher<Point4D> watcher)
|
||||
{
|
||||
linkWatcher.registerReceiver(watcher);
|
||||
}
|
||||
|
||||
public static boolean unregisterLinkWatcher(IUpdateWatcher<Point4D> watcher)
|
||||
{
|
||||
return linkWatcher.unregisterReceiver(watcher);
|
||||
}
|
||||
|
||||
public static void getWatchers(IUpdateSource updateSource)
|
||||
{
|
||||
updateSource.registerWatchers(new ClientDimWatcher(), new ClientLinkWatcher());
|
||||
}
|
||||
|
||||
public static void writePacket(DataOutputStream output) throws IOException
|
||||
{
|
||||
// Write a very compact description of our dimensions and links to be sent to a client
|
||||
Compactor.write(dimensionData.values(), output);
|
||||
}
|
||||
|
||||
public static boolean isRegisteredInternally(int dimensionID)
|
||||
{
|
||||
return dimensionData.containsKey(dimensionID);
|
||||
}
|
||||
|
||||
public static void readPacket(DataInputStream input) throws IOException
|
||||
{
|
||||
if (isLoaded)
|
||||
{
|
||||
throw new IllegalStateException("Pocket dimensions have already been loaded!");
|
||||
}
|
||||
if (isLoading)
|
||||
{
|
||||
throw new IllegalStateException("Pocket dimensions are already loading!");
|
||||
}
|
||||
// Load compacted client-side dimension data
|
||||
Compactor.readDimensions(input, new DimRegistrationCallback());
|
||||
|
||||
// Register pocket dimensions
|
||||
DDProperties properties = DDProperties.instance();
|
||||
registerPockets(properties);
|
||||
|
||||
isLoaded = true;
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user