Merge branch 'DevBranch' of https://github.com/StevenRS11/DimDoors into DevBranch

This commit is contained in:
StevenRS11 2013-09-03 23:28:43 -04:00
commit fb25fc43eb
41 changed files with 693 additions and 423 deletions

View file

@ -11,7 +11,6 @@ import net.minecraft.network.packet.Packet1Login;
import net.minecraft.network.packet.Packet250CustomPayload;
import net.minecraft.server.MinecraftServer;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.watcher.IOpaqueMessage;
import cpw.mods.fml.common.network.IConnectionHandler;
import cpw.mods.fml.common.network.Player;
@ -41,12 +40,11 @@ public class ConnectionHandler implements IConnectionHandler
//Send information about all the registered dimensions and links to the client
try
{
IOpaqueMessage message = PocketManager.getState();
Packet250CustomPayload packet = new Packet250CustomPayload();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream writer = new DataOutputStream(buffer);
writer.writeByte(PacketConstants.CLIENT_JOIN_PACKET_ID);
message.writeToStream(writer);
PocketManager.writePacket(writer);
writer.close();
packet.channel = PacketConstants.CHANNEL_NAME;
packet.data = buffer.toByteArray();

View file

@ -16,7 +16,8 @@ import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.DimensionManager;
import StevenDimDoors.mod_pocketDim.core.IDimLink;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import StevenDimDoors.mod_pocketDim.world.PocketBuilder;
@ -312,7 +313,7 @@ public class DDTeleporter
* @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, IDimLink link, Entity entity)
public static void traverseDimDoor(World world, DimLink link, Entity entity)
{
if (world == null)
{
@ -349,7 +350,7 @@ public class DDTeleporter
entity.worldObj.playSoundEffect(entity.posX, entity.posY, entity.posZ, "mob.endermen.portal", 1.0F, 1.0F);
}
private static boolean initializeDestination(IDimLink link, DDProperties properties)
private static boolean initializeDestination(DimLink link, DDProperties properties)
{
//FIXME: Change this later to support rooms that have been wiped and must be regenerated.
if (link.hasDestination())
@ -362,11 +363,11 @@ public class DDTeleporter
//FIXME: Add code for restoring the destination-side door.
switch (link.linkType())
{
case IDimLink.TYPE_DUNGEON:
case LinkTypes.DUNGEON:
return PocketBuilder.generateNewDungeonPocket(link, properties);
case IDimLink.TYPE_POCKET:
case LinkTypes.POCKET:
return PocketBuilder.generateNewPocket(link, properties);
case IDimLink.TYPE_NORMAL:
case LinkTypes.NORMAL:
return true;
default:
throw new IllegalArgumentException("link has an unrecognized link type.");

View file

@ -35,9 +35,20 @@ public class EventHookContainer
@ForgeSubscribe
public void onWorldLoad(WorldEvent.Load event)
{
// We need to initialize PocketManager here because onServerAboutToStart fires before we can
// use DimensionManager and onServerStarting fires after the game tries to generate terrain.
// If a gateway tries to generate before PocketManager has initialized, we get a crash.
if (!PocketManager.isLoaded())
{
PocketManager.load();
}
if (PocketManager.isLoaded())
{
RiftRegenerator.regenerateRiftsInAllWorlds();
}
}
@ForgeSubscribe
public void onPlayerFall(LivingFallEvent event)

View file

@ -4,12 +4,11 @@ public class PacketConstants
{
private PacketConstants() { }
public static final String CHANNEL_NAME = "DimDoorsPackets";
public static final byte CLIENT_JOIN_PACKET_ID = 1;
public static final byte CREATE_DIM_PACKET_ID = 2;
public static final byte UPDATE_DIM_PACKET_ID = 3;
public static final byte DELETE_DIM_PACKET_ID = 4;
public static final byte CREATE_LINK_PACKET_ID = 5;
public static final byte UPDATE_LINK_PACKET_ID = 6;
public static final byte DELETE_LINK_PACKET_ID = 7;
public static final String CHANNEL_NAME = "DimDoorsPackets";
public static final byte DELETE_DIM_PACKET_ID = 3;
public static final byte CREATE_LINK_PACKET_ID = 4;
public static final byte DELETE_LINK_PACKET_ID = 5;
}

View file

@ -7,7 +7,8 @@ import java.io.IOException;
import net.minecraft.network.INetworkManager;
import net.minecraft.network.packet.Packet250CustomPayload;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.watcher.IOpaqueMessage;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import StevenDimDoors.mod_pocketDim.watcher.ClientDimData;
import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher;
import cpw.mods.fml.common.network.IPacketHandler;
import cpw.mods.fml.common.network.PacketDispatcher;
@ -22,54 +23,39 @@ public class ServerPacketHandler implements IPacketHandler
}
@Override
public void onPacketData(INetworkManager manager, Packet250CustomPayload packet, Player player)
{
public void onPacketData(INetworkManager manager, Packet250CustomPayload packet, Player player) { }
}
private class DimWatcher implements IUpdateWatcher
private static class DimWatcher implements IUpdateWatcher<ClientDimData>
{
@Override
public void onCreated(IOpaqueMessage message)
public void onCreated(ClientDimData message)
{
sendMessageToAllPlayers(PacketConstants.CREATE_DIM_PACKET_ID, message);
sendDimPacket(PacketConstants.CREATE_DIM_PACKET_ID, message);
}
@Override
public void onUpdated(IOpaqueMessage message)
public void onDeleted(ClientDimData message)
{
sendMessageToAllPlayers(PacketConstants.UPDATE_DIM_PACKET_ID, message);
sendDimPacket(PacketConstants.DELETE_DIM_PACKET_ID, message);
}
}
private static class LinkWatcher implements IUpdateWatcher<Point4D>
{
@Override
public void onCreated(Point4D message)
{
sendLinkPacket(PacketConstants.CREATE_LINK_PACKET_ID, message);
}
@Override
public void onDeleted(IOpaqueMessage message)
public void onDeleted(Point4D message)
{
sendMessageToAllPlayers(PacketConstants.DELETE_DIM_PACKET_ID, message);
sendLinkPacket(PacketConstants.DELETE_LINK_PACKET_ID, message);
}
}
private class LinkWatcher implements IUpdateWatcher
{
@Override
public void onCreated(IOpaqueMessage message)
{
sendMessageToAllPlayers(PacketConstants.CREATE_LINK_PACKET_ID, message);
}
@Override
public void onUpdated(IOpaqueMessage message)
{
sendMessageToAllPlayers(PacketConstants.UPDATE_LINK_PACKET_ID, message);
}
@Override
public void onDeleted(IOpaqueMessage message)
{
sendMessageToAllPlayers(PacketConstants.DELETE_LINK_PACKET_ID, message);
}
}
private static void sendMessageToAllPlayers(byte id, IOpaqueMessage message)
private static void sendDimPacket(byte id, ClientDimData data)
{
try
{
@ -77,7 +63,29 @@ public class ServerPacketHandler implements IPacketHandler
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream writer = new DataOutputStream(buffer);
writer.writeByte(id);
message.writeToStream(writer);
data.write(writer);
writer.close();
packet.channel = PacketConstants.CHANNEL_NAME;
packet.data = buffer.toByteArray();
packet.length = packet.data.length;
PacketDispatcher.sendPacketToAllPlayers(packet);
}
catch (IOException e)
{
//This shouldn't happen...
e.printStackTrace();
}
}
private static void sendLinkPacket(byte id, Point4D data)
{
try
{
Packet250CustomPayload packet = new Packet250CustomPayload();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream writer = new DataOutputStream(buffer);
writer.writeByte(id);
Point4D.write(data, writer);
writer.close();
packet.channel = PacketConstants.CHANNEL_NAME;
packet.data = buffer.toByteArray();

View file

@ -20,7 +20,8 @@ import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.DDTeleporter;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.IDimLink;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.schematic.BlockRotator;
@ -59,7 +60,7 @@ public class DimensionalDoor extends BlockContainer
{
this.onPoweredBlockChange(world, x, y, z, false);
IDimLink link = PocketManager.getLink(x, y, z, world.provider.dimensionId);
DimLink link = PocketManager.getLink(x, y, z, world.provider.dimensionId);
if (link != null)
{
DDTeleporter.traverseDimDoor(world, link, entity);
@ -169,10 +170,10 @@ public class DimensionalDoor extends BlockContainer
if (!world.isRemote && world.getBlockId(x, y - 1, z) == this.blockID)
{
NewDimData dimension = PocketManager.getDimensionData(world);
IDimLink link = dimension.getLink(x, y, z);
DimLink link = dimension.getLink(x, y, z);
if (link == null)
{
dimension.createLink(x, y, z, IDimLink.TYPE_POCKET);
dimension.createLink(x, y, z, LinkTypes.POCKET);
}
}
world.setBlockTileEntity(x, y, z, this.createNewTileEntity(world));

View file

@ -12,7 +12,7 @@ import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDTeleporter;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.IDimLink;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@ -66,7 +66,7 @@ public class TransientDoor extends WarpDoor
{
this.onPoweredBlockChange(world, x, y, z, false);
IDimLink link = PocketManager.getLink(x, y, z, world.provider.dimensionId);
DimLink link = PocketManager.getLink(x, y, z, world.provider.dimensionId);
if (link != null)
{
DDTeleporter.traverseDimDoor(world, link, entity);

View file

@ -7,7 +7,7 @@ import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.IDimLink;
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import cpw.mods.fml.relauncher.Side;
@ -54,7 +54,7 @@ public class UnstableDoor extends DimensionalDoor
if (!world.isRemote && world.getBlockId(x, y - 1, z) == this.blockID)
{
NewDimData dimension = PocketManager.getDimensionData(world);
dimension.createLink(x, y, z, IDimLink.TYPE_RANDOM);
dimension.createLink(x, y, z, LinkTypes.RANDOM);
}
}
}

View file

@ -9,7 +9,8 @@ import net.minecraft.util.Icon;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.IDimLink;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import cpw.mods.fml.relauncher.Side;
@ -38,10 +39,10 @@ public class WarpDoor extends DimensionalDoor
if (!world.isRemote && world.getBlockId(x, y - 1, z) == this.blockID)
{
NewDimData dimension = PocketManager.getDimensionData(world);
IDimLink link = dimension.getLink(x, y, z);
DimLink link = dimension.getLink(x, y, z);
if (link == null)
{
dimension.createLink(x, y, z, IDimLink.TYPE_SAFE_EXIT);
dimension.createLink(x, y, z, LinkTypes.SAFE_EXIT);
}
}
world.setBlockTileEntity(x, y, z, this.createNewTileEntity(world));

View file

@ -4,7 +4,7 @@ import java.util.Collection;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.MathHelper;
import StevenDimDoors.mod_pocketDim.core.IDimLink;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.dungeon.DungeonData;
import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper;
@ -55,7 +55,7 @@ public class CommandCreateDungeonRift extends DDCommandBase
}
else
{
IDimLink link;
DimLink link;
DungeonData result;
int x = MathHelper.floor_double(sender.posX);
int y = MathHelper.floor_double(sender.posY);

View file

@ -0,0 +1,76 @@
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 List<DimLink> children;
protected DimLink(Point4D source, DimLink parent)
{
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)
{
if (linkType < LinkTypes.ENUM_MIN || linkType > LinkTypes.ENUM_MAX && linkType != LinkTypes.CLIENT_SIDE)
{
throw new IllegalArgumentException("The specified link type is invalid.");
}
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 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 String toString()
{
return source + " -> " + (hasDestination() ? destination() : "");
}
}

View file

@ -1,27 +0,0 @@
package StevenDimDoors.mod_pocketDim.core;
import StevenDimDoors.mod_pocketDim.util.Point4D;
public interface IDimLink
{
public final int TYPE_ENUM_MIN = 0;
public final int TYPE_ENUM_MAX = 8;
public final int TYPE_NORMAL = 0;
public final int TYPE_LIMBO = 1;
public final int TYPE_POCKET = 2;
public final int TYPE_DUNGEON = 3;
public final int TYPE_RANDOM = 4;
public final int TYPE_DUNGEON_EXIT = 5;
public final int TYPE_SAFE_EXIT = 6;
public final int TYPE_UNSAFE_EXIT = 7;
public final int TYPE_RANDOM_DUNGEON = 8;
public Point4D source();
public Point4D destination();
public boolean hasDestination();
public Iterable<IDimLink> children();
public int childCount();
public IDimLink parent();
public int linkType();
}

View file

@ -0,0 +1,6 @@
package StevenDimDoors.mod_pocketDim.core;
public interface IDimRegistrationCallback
{
public NewDimData registerDimension(int dimensionID, int rootID);
}

View 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 = 8;
public static final int CLIENT_SIDE = -1337;
public static final int NORMAL = 0;
public static final int LIMBO = 1;
public static final int POCKET = 2;
public static final int DUNGEON = 3;
public static final int RANDOM = 4;
public static final int DUNGEON_EXIT = 5;
public static final int SAFE_EXIT = 6;
public static final int UNSAFE_EXIT = 7;
public static final int RANDOM_DUNGEON = 8;
}

View file

@ -1,4 +1,5 @@
package StevenDimDoors.mod_pocketDim.core;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -10,60 +11,20 @@ import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.dungeon.DungeonData;
import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import StevenDimDoors.mod_pocketDim.watcher.IOpaqueMessage;
import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher;
public abstract class NewDimData
{
private static class DimLink implements IDimLink
private static class InnerDimLink extends DimLink
{
//DimLink is an inner class here to make it immutable to code outside NewDimData
private static final int EXPECTED_CHILDREN = 2;
private Point4D source;
private DimLink parent;
private LinkTail tail;
private ArrayList<IDimLink> children;
public DimLink(Point4D source, DimLink parent)
public InnerDimLink(Point4D source, DimLink parent)
{
this.parent = parent;
this.source = source;
this.tail = parent.tail;
this.children = new ArrayList<IDimLink>(EXPECTED_CHILDREN);
parent.children.add(this);
super(source, parent);
}
public DimLink(Point4D source, int linkType)
public InnerDimLink(Point4D source, int linkType)
{
if (linkType < IDimLink.TYPE_ENUM_MIN || linkType > IDimLink.TYPE_ENUM_MAX)
{
throw new IllegalArgumentException("The specified link type is invalid.");
}
this.parent = null;
this.source = source;
this.tail = new LinkTail(linkType, null);
this.children = new ArrayList<IDimLink>(EXPECTED_CHILDREN);
}
@Override
public Point4D source()
{
return source;
}
@Override
public Point4D destination()
{
return tail.getDestination();
}
@Override
public boolean hasDestination()
{
return (tail.getDestination() != null);
super(source, linkType);
}
public void setDestination(int x, int y, int z, NewDimData dimension)
@ -71,36 +32,12 @@ public abstract class NewDimData
tail.setDestination(new Point4D(x, y, z, dimension.id()));
}
@Override
public Iterable<IDimLink> children()
{
return children;
}
@Override
public int childCount()
{
return children.size();
}
@Override
public IDimLink parent()
{
return parent;
}
@Override
public int linkType()
{
return tail.getLinkType();
}
public void clear()
{
//Release children
for (IDimLink child : children)
for (DimLink child : children)
{
((DimLink) child).parent = null;
((InnerDimLink) child).parent = null;
}
children.clear();
@ -115,7 +52,7 @@ public abstract class NewDimData
tail = new LinkTail(0, null);
}
public void overwrite(DimLink nextParent)
public boolean overwrite(InnerDimLink nextParent)
{
if (nextParent == null)
{
@ -125,13 +62,13 @@ public abstract class NewDimData
if (this == nextParent)
{
//Ignore this request silently
return;
return false;
}
//Release children
for (IDimLink child : children)
for (DimLink child : children)
{
((DimLink) child).parent = null;
((InnerDimLink) child).parent = null;
}
children.clear();
@ -145,14 +82,15 @@ public abstract class NewDimData
parent = nextParent;
tail = nextParent.tail;
nextParent.children.add(this);
return true;
}
public void overwrite(int linkType)
{
//Release children
for (IDimLink child : children)
for (DimLink child : children)
{
((DimLink) child).parent = null;
((InnerDimLink) child).parent = null;
}
children.clear();
@ -166,29 +104,13 @@ public abstract class NewDimData
parent = null;
tail = new LinkTail(linkType, null);
}
@Override
public String toString()
{
return source + " -> " + (hasDestination() ? destination() : "");
}
public IOpaqueMessage toMessage()
{
return null;
}
public IOpaqueMessage toKey()
{
return null;
}
}
private static Random random = new Random();
private final int id;
private final Map<Point4D, DimLink> linkMapping;
private final List<DimLink> linkList;
private final Map<Point4D, InnerDimLink> linkMapping;
private final List<InnerDimLink> linkList;
private final boolean isDungeon;
private boolean isFilled;
private final int depth;
@ -199,14 +121,13 @@ public abstract class NewDimData
private Point4D origin;
private int orientation;
private DungeonData dungeon;
private final IUpdateWatcher dimWatcher;
private final IUpdateWatcher linkWatcher;
private final IUpdateWatcher<Point4D> linkWatcher;
protected NewDimData(int id, NewDimData parent, boolean isPocket, boolean isDungeon,
IUpdateWatcher dimWatcher, IUpdateWatcher linkWatcher)
IUpdateWatcher<Point4D> linkWatcher)
{
//The isPocket flag is redundant. It's meant as an integrity safeguard.
if (isPocket == (parent != null))
// 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.");
}
@ -216,8 +137,8 @@ public abstract class NewDimData
}
this.id = id;
this.linkMapping = new TreeMap<Point4D, DimLink>(); //Should be stored in oct tree -- temporary solution
this.linkList = new ArrayList<DimLink>(); //Should be stored in oct tree -- temporary solution
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;
@ -226,7 +147,6 @@ public abstract class NewDimData
this.orientation = 0;
this.origin = null;
this.dungeon = null;
this.dimWatcher = dimWatcher;
this.linkWatcher = linkWatcher;
//Register with parent
@ -244,10 +164,31 @@ public abstract class NewDimData
}
}
protected abstract IOpaqueMessage toMessage();
protected abstract IOpaqueMessage toKey();
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.");
}
public IDimLink findNearestRift(World world, int range, int x, int y, int z)
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
@ -260,8 +201,8 @@ public abstract class NewDimData
//Note: Only detect rifts at a distance > 1, so we ignore the rift
//that called this function and any adjacent rifts.
IDimLink nearest = null;
IDimLink link;
DimLink nearest = null;
DimLink link;
int distance;
int minDistance = Integer.MAX_VALUE;
@ -296,18 +237,18 @@ public abstract class NewDimData
return Math.abs(i) + Math.abs(j) + Math.abs(k);
}
public IDimLink createLink(int x, int y, int z, int linkType)
public DimLink createLink(int x, int y, int z, int linkType)
{
return createLink(new Point4D(x, y, z, id), linkType);
}
private IDimLink createLink(Point4D source, int linkType)
private DimLink createLink(Point4D source, int linkType)
{
//Return an existing link if there is one to avoid creating multiple links starting at the same point.
DimLink link = linkMapping.get(source);
InnerDimLink link = linkMapping.get(source);
if (link == null)
{
link = new DimLink(source, linkType);
link = new InnerDimLink(source, linkType);
linkMapping.put(source, link);
linkList.add(link);
}
@ -316,53 +257,58 @@ public abstract class NewDimData
link.overwrite(linkType);
}
//Link created!
linkWatcher.onCreated(link.toMessage());
linkWatcher.onCreated(link.source);
return link;
}
public IDimLink createChildLink(int x, int y, int z, IDimLink parent)
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), (DimLink) parent);
return createChildLink(new Point4D(x, y, z, id), (InnerDimLink) parent);
}
private IDimLink createChildLink(Point4D source, DimLink 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.
DimLink link = linkMapping.get(source);
InnerDimLink link = linkMapping.get(source);
if (link == null)
{
link = new DimLink(source, parent);
link = new InnerDimLink(source, parent);
linkMapping.put(source, link);
linkList.add(link);
//Link created!
linkWatcher.onCreated(link.source);
}
else
{
link.overwrite(parent);
}
if (link.overwrite(parent))
{
//Link created!
linkWatcher.onCreated(link.toMessage());
linkWatcher.onCreated(link.source);
}
}
return link;
}
public boolean deleteLink(IDimLink link)
public boolean deleteLink(DimLink link)
{
if (link.source().getDimension() != id)
{
throw new IllegalArgumentException("Attempted to delete a link from another dimension.");
}
DimLink target = linkMapping.remove(link.source());
InnerDimLink target = linkMapping.remove(link.source());
if (target != null)
{
linkList.remove(target);
//Raise deletion event
linkWatcher.onDeleted(target.toKey());
linkWatcher.onDeleted(target.source);
target.clear();
}
return (target != null);
@ -371,24 +317,24 @@ public abstract class NewDimData
public boolean deleteLink(int x, int y, int z)
{
Point4D location = new Point4D(x, y, z, id);
DimLink target = linkMapping.remove(location);
InnerDimLink target = linkMapping.remove(location);
if (target != null)
{
linkList.remove(target);
//Raise deletion event
linkWatcher.onDeleted(target.toKey());
linkWatcher.onDeleted(target.source);
target.clear();
}
return (target != null);
}
public IDimLink getLink(int x, int y, int z)
public DimLink getLink(int x, int y, int z)
{
Point4D location = new Point4D(x, y, z, id);
return linkMapping.get(location);
}
public IDimLink getLink(Point4D location)
public DimLink getLink(Point4D location)
{
if (location.getDimension() != id)
return null;
@ -396,16 +342,16 @@ public abstract class NewDimData
return linkMapping.get(location);
}
public ArrayList<IDimLink> getAllLinks()
public ArrayList<DimLink> getAllLinks()
{
ArrayList<IDimLink> results = new ArrayList<IDimLink>(linkMapping.size());
ArrayList<DimLink> results = new ArrayList<DimLink>(linkMapping.size());
results.addAll(linkMapping.values());
return results;
}
public boolean isPocketDimension()
{
return (parent != null);
return (root != this);
}
public boolean isDungeon()
@ -421,8 +367,6 @@ public abstract class NewDimData
public void setFilled(boolean isFilled)
{
this.isFilled = isFilled;
//Raise the dim update event
dimWatcher.onUpdated(this.toMessage());
}
public int id()
@ -472,7 +416,7 @@ public abstract class NewDimData
public int linkCount()
{
return linkMapping.size();
return linkList.size();
}
public Iterable<NewDimData> children()
@ -480,7 +424,12 @@ public abstract class NewDimData
return children;
}
public void initializeDungeon(int originX, int originY, int originZ, int orientation, IDimLink incoming, DungeonData dungeon)
public Iterable<? extends DimLink> links()
{
return linkList;
}
public void initializeDungeon(int originX, int originY, int originZ, int orientation, DimLink incoming, DungeonData dungeon)
{
if (!isDungeon)
{
@ -496,8 +445,6 @@ public abstract class NewDimData
this.orientation = orientation;
this.dungeon = dungeon;
this.packDepth = calculatePackDepth(parent, dungeon);
//Raise the dim update event
dimWatcher.onUpdated(this.toMessage());
}
private static int calculatePackDepth(NewDimData parent, DungeonData current)
@ -532,7 +479,7 @@ public abstract class NewDimData
}
}
public void initializePocket(int originX, int originY, int originZ, int orientation, IDimLink incoming)
public void initializePocket(int originX, int originY, int originZ, int orientation, DimLink incoming)
{
if (!isPocketDimension())
{
@ -546,19 +493,15 @@ public abstract class NewDimData
setDestination(incoming, originX, originY, originZ);
this.origin = incoming.destination();
this.orientation = orientation;
//Raise the dim update event
dimWatcher.onUpdated(this.toMessage());
}
public void setDestination(IDimLink incoming, int x, int y, int z)
public void setDestination(DimLink incoming, int x, int y, int z)
{
DimLink link = (DimLink) incoming;
InnerDimLink link = (InnerDimLink) incoming;
link.setDestination(x, y, z, this);
//Raise update event
linkWatcher.onUpdated(link.toMessage());
}
public IDimLink getRandomLink()
public DimLink getRandomLink()
{
if (linkMapping.isEmpty())
{

View file

@ -1,9 +1,8 @@
package StevenDimDoors.mod_pocketDim.core;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
@ -13,10 +12,12 @@ import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.helpers.Compactor;
import StevenDimDoors.mod_pocketDim.helpers.DeleteFolder;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import StevenDimDoors.mod_pocketDim.watcher.IOpaqueMessage;
import StevenDimDoors.mod_pocketDim.watcher.ClientDimData;
import StevenDimDoors.mod_pocketDim.watcher.IUpdateSource;
import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher;
import StevenDimDoors.mod_pocketDim.watcher.UpdateWatcherProxy;
@ -28,29 +29,67 @@ public class PocketManager
{
private static class InnerDimData extends NewDimData
{
//This inner 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 without using PocketManager's functions. In turn, that enforces that any
//link destinations must be real dimensions controlled by PocketManager.
// 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, NewDimData parent, boolean isPocket, boolean isDungeon,
IUpdateWatcher dimWatcher, IUpdateWatcher linkWatcher)
public InnerDimData(int id, InnerDimData parent, boolean isPocket, boolean isDungeon,
IUpdateWatcher<Point4D> linkWatcher)
{
super(id, parent, isPocket, isDungeon, dimWatcher, 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);
}
}
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
protected IOpaqueMessage toMessage()
public void onDeleted(Point4D source)
{
// TODO Auto-generated method stub
return null;
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
protected IOpaqueMessage toKey()
public void onDeleted(ClientDimData data)
{
// TODO Auto-generated method stub
return null;
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);
}
}
@ -59,11 +98,11 @@ public class PocketManager
private static volatile boolean isLoading = false;
private static volatile boolean isLoaded = false;
private static volatile boolean isSaving = false;
private static UpdateWatcherProxy linkWatcher = null;
private static UpdateWatcherProxy dimWatcher = null;
private static final UpdateWatcherProxy<Point4D> linkWatcher = new UpdateWatcherProxy<Point4D>();
private static final UpdateWatcherProxy<ClientDimData> dimWatcher = new UpdateWatcherProxy<ClientDimData>();
//HashMap that maps all the dimension IDs registered with DimDoors to their DD data.
private static HashMap<Integer, NewDimData> dimensionData = new HashMap<Integer, NewDimData>();
private static HashMap<Integer, InnerDimData> dimensionData = null;
public static boolean isLoaded()
{
@ -86,17 +125,14 @@ public class PocketManager
}
isLoading = true;
//Set up watcher proxies
dimWatcher = new UpdateWatcherProxy();
linkWatcher = new UpdateWatcherProxy();
loadInternal();
dimensionData = new HashMap<Integer, InnerDimData>();
//Register Limbo
DDProperties properties = DDProperties.instance();
registerDimension(properties.LimboDimensionID, null, false, false);
loadInternal();
//Register pocket dimensions
registerPockets(properties);
@ -134,7 +170,7 @@ public class PocketManager
DeleteFolder.deleteFolder(save);
}
//Raise the dim deleted event
dimWatcher.onDeleted(dimension.toKey());
dimWatcher.onDeleted(new ClientDimData(dimension));
//dimension.implode()??? -- more like delete, but yeah
return true;
}
@ -184,9 +220,7 @@ public class PocketManager
/**
* loads the dim data from the saved hashMap. Also handles compatibility with old saves, see OldSaveHandler
* @return
*/
@SuppressWarnings("unchecked")
private static void loadInternal()
{
// SenseiKiwi: This is a temporary function for testing purposes.
@ -196,10 +230,9 @@ public class PocketManager
DimensionManager.getCurrentSaveRootDirectory() != null)
{
System.out.println("Loading Dimensional Doors save data...");
File saveFile = new File(DimensionManager.getCurrentSaveRootDirectory() + "/dimdoors.dat");
//Missing code for converting the binary data in the file into an IOpaqueMessage
IOpaqueMessage saveData;
setState(saveData);
/*File saveFile = new File(DimensionManager.getCurrentSaveRootDirectory() + "/dimdoors.dat");
setState(saveData);*/
System.out.println("Loaded successfully!");
}
}
@ -228,7 +261,7 @@ public class PocketManager
try
{
System.out.println("Writing Dimensional Doors save data...");
String tempPath = DimensionManager.getCurrentSaveRootDirectory() + "/dimdoors.tmp";
/*String tempPath = DimensionManager.getCurrentSaveRootDirectory() + "/dimdoors.tmp";
String savePath = DimensionManager.getCurrentSaveRootDirectory() + "/dimdoors.dat";
File tempFile = new File(tempPath);
File saveFile = new File(savePath);
@ -236,17 +269,17 @@ public class PocketManager
getState().writeToStream(writer);
writer.close();
saveFile.delete();
tempFile.renameTo(saveFile);
tempFile.renameTo(saveFile);*/
System.out.println("Saved successfully!");
}
catch (FileNotFoundException e)
/*catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}*/
finally
{
isSaving = false;
@ -259,7 +292,7 @@ public class PocketManager
//Does not actually unregister the rift data, see deleteRift for that.
NewDimData dimension = getDimensionData(world);
IDimLink nearest = dimension.findNearestRift(world, range, x, y, z);
DimLink nearest = dimension.findNearestRift(world, range, x, y, z);
if (nearest != null)
{
@ -291,21 +324,45 @@ public class PocketManager
DDProperties properties = DDProperties.instance();
int dimensionID = DimensionManager.getNextFreeDimId();
DimensionManager.registerDimension(dimensionID, properties.PocketProviderID);
return registerDimension(dimensionID, parent, true, isDungeon);
return registerDimension(dimensionID, (InnerDimData) parent, true, isDungeon);
}
private static NewDimData registerDimension(int dimensionID, NewDimData parent, boolean isPocket, boolean 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.");
}
NewDimData dimension = new InnerDimData(dimensionID, parent, isPocket, isDungeon, dimWatcher, linkWatcher);
InnerDimData dimension = new InnerDimData(dimensionID, parent, isPocket, isDungeon, linkWatcher);
dimensionData.put(dimensionID, dimension);
return dimension;
}
private static NewDimData registerClientDimension(int dimensionID, int rootID)
{
// No need to raise events here since this code should only run on the client side
// getDimensionData() always handles root dimensions properly, even if the weren't defined before
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;
}
return dimension;
}
public static NewDimData getDimensionData(World world)
{
return getDimensionData(world.provider.dimensionId);
@ -327,24 +384,30 @@ public class PocketManager
return dimension;
}
public static void unload()
{
save();
unregisterPockets();
dimensionData.clear();
}
public static Iterable<NewDimData> getDimensions()
public static Iterable<? extends NewDimData> getDimensions()
{
return dimensionData.values();
}
public static IDimLink getLink(int x, int y, int z, World world)
public static void unload()
{
if (!isLoaded)
{
throw new IllegalStateException("Pocket dimensions have already been unloaded!");
}
save();
unregisterPockets();
dimensionData = 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 IDimLink getLink(int x, int y, int z, int dimensionID)
public static DimLink getLink(int x, int y, int z, int dimensionID)
{
NewDimData dimension = dimensionData.get(dimensionID);
if (dimension != null)
@ -357,37 +420,59 @@ public class PocketManager
}
}
public static void registerDimWatcher(IUpdateWatcher watcher)
public static void registerDimWatcher(IUpdateWatcher<ClientDimData> watcher)
{
dimWatcher.registerReceiver(watcher);
}
public static boolean unregisterDimWatcher(IUpdateWatcher watcher)
public static boolean unregisterDimWatcher(IUpdateWatcher<ClientDimData> watcher)
{
return dimWatcher.unregisterReceiver(watcher);
}
public static void registerLinkWatcher(IUpdateWatcher watcher)
public static void registerLinkWatcher(IUpdateWatcher<Point4D> watcher)
{
linkWatcher.registerReceiver(watcher);
}
public static boolean unregisterLinkWatcher(IUpdateWatcher watcher)
public static boolean unregisterLinkWatcher(IUpdateWatcher<Point4D> watcher)
{
return linkWatcher.unregisterReceiver(watcher);
}
public static IOpaqueMessage getState()
public static void getWatchers(IUpdateSource updateSource)
{
updateSource.registerWatchers(new ClientDimWatcher(), new ClientLinkWatcher());
}
public static void setState(IOpaqueMessage state)
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 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!");
}
isLoading = true;
dimensionData = new HashMap<Integer, InnerDimData>();
// Load compacted client-side dimension data
Compactor.readDimensions(input, new DimRegistrationCallback());
// Register pocket dimensions
DDProperties properties = DDProperties.instance();
registerPockets(properties);
isLoaded = true;
isLoading = false;
}
}

View file

@ -31,7 +31,7 @@ public class DungeonData
int indexB = schematicPath.lastIndexOf('/');
indexA = Math.max(indexA, indexB) + 1;
return schematicPath.substring(indexA, schematicPath.length() - DungeonHelper.SCHEMATIC_FILE_EXTENSION.length() - indexA);
return schematicPath.substring(indexA, schematicPath.length() - DungeonHelper.SCHEMATIC_FILE_EXTENSION.length());
}
public int weight()

View file

@ -17,7 +17,8 @@ import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.Point3D;
import StevenDimDoors.mod_pocketDim.core.IDimLink;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.schematic.BlockRotator;
@ -167,7 +168,7 @@ public class DungeonSchematic extends Schematic {
return new DungeonSchematic(Schematic.copyFromWorld(world, x, y, z, width, height, length, doCompactBounds));
}
public void copyToWorld(World world, Point3D pocketCenter, int dungeonOrientation, IDimLink entryLink, Random random)
public void copyToWorld(World world, Point3D pocketCenter, int dungeonOrientation, DimLink entryLink, Random random)
{
//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,
@ -224,7 +225,7 @@ public class DungeonSchematic extends Schematic {
setUpDungeon(PocketManager.getDimensionData(world), world, pocketCenter, turnAngle, entryLink, random);
}
private void setUpDungeon(NewDimData dimension, World world, Point3D pocketCenter, int turnAngle, IDimLink entryLink, Random random)
private void setUpDungeon(NewDimData dimension, World world, Point3D pocketCenter, int turnAngle, DimLink entryLink, Random random)
{
//Transform dungeon corners
Point3D minCorner = new Point3D(0, 0, 0);
@ -282,9 +283,9 @@ public class DungeonSchematic extends Schematic {
}
}
private static void createEntranceReverseLink(NewDimData dimension, Point3D pocketCenter, IDimLink entryLink)
private static void createEntranceReverseLink(NewDimData dimension, Point3D pocketCenter, DimLink entryLink)
{
IDimLink link = dimension.createLink(pocketCenter.getX(), pocketCenter.getY(), pocketCenter.getZ(), IDimLink.TYPE_NORMAL);
DimLink link = dimension.createLink(pocketCenter.getX(), pocketCenter.getY(), pocketCenter.getZ(), LinkTypes.NORMAL);
Point4D destination = link.source();
NewDimData prevDim = PocketManager.getDimensionData(destination.getDimension());
prevDim.setDestination(link, destination.getX(), destination.getY(), destination.getZ());
@ -295,7 +296,7 @@ public class DungeonSchematic extends Schematic {
//Transform the door's location to the pocket coordinate system
Point3D location = point.clone();
BlockRotator.transformPoint(location, entrance, rotation, pocketCenter);
dimension.createLink(location.getX(), location.getY(), location.getZ(), IDimLink.TYPE_DUNGEON_EXIT);
dimension.createLink(location.getX(), location.getY(), location.getZ(), LinkTypes.DUNGEON_EXIT);
}
private static void createDimensionalDoorLink(NewDimData dimension, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter)
@ -303,7 +304,7 @@ public class DungeonSchematic extends Schematic {
//Transform the door's location to the pocket coordinate system
Point3D location = point.clone();
BlockRotator.transformPoint(location, entrance, rotation, pocketCenter);
dimension.createLink(location.getX(), location.getY(), location.getZ(), IDimLink.TYPE_DUNGEON);
dimension.createLink(location.getX(), location.getY(), location.getZ(), LinkTypes.DUNGEON);
}
private static void spawnMonolith(World world, Point3D point, Point3D entrance, int rotation, Point3D pocketCenter)

View file

@ -0,0 +1,83 @@
package StevenDimDoors.mod_pocketDim.helpers;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.IDimRegistrationCallback;
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.util.Point4D;
public class Compactor
{
private static class DimComparator implements Comparator<NewDimData>
{
@Override
public int compare(NewDimData a, NewDimData b)
{
return a.id() - b.id();
}
}
public static void write(Collection<? extends NewDimData> values, DataOutputStream output) throws IOException
{
// SenseiKiwi: Just encode the data straight up for now. I'll implement fancier compression later.
output.writeInt(values.size());
for (NewDimData dimension : values)
{
output.writeInt(dimension.id());
output.writeInt(dimension.root().id());
output.writeInt(dimension.linkCount());
for (DimLink link : dimension.links())
{
Point4D.write(link.source(), output);
}
}
// Note to self: the root ID can be "compressed" by grouping
// dimensions by their root ID and then only sending it once
/*
// To compress the dimension IDs, we'll sort them by ID
// and write the _difference_ between their ID numbers.
NewDimData[] dimensions = new NewDimData[values.size()];
dimensions = values.toArray(dimensions);
Arrays.sort(dimensions, new DimComparator());
*/
}
public static void readDimensions(DataInputStream input, IDimRegistrationCallback callback) throws IOException
{
// Read in the dimensions one by one. Make sure we register root dimensions before
// attempting to register the dimensions under them.
HashSet<Integer> rootIDs = new HashSet<Integer>();
int dimCount = input.readInt();
for (int k = 0; k < dimCount; k++)
{
int id = input.readInt();
int rootID = input.readInt();
if (rootIDs.add(rootID))
{
callback.registerDimension(rootID, rootID);
}
// Don't check if (id != rootID) - we want to retrieve the reference anyway
NewDimData dimension = callback.registerDimension(id, rootID);
int linkCount = input.readInt();
for (int h = 0; h < linkCount; h++)
{
Point4D source = Point4D.read(input);
dimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.CLIENT_SIDE);
}
}
}
}

View file

@ -21,7 +21,8 @@ import net.minecraft.util.WeightedRandom;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.IDimLink;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.dungeon.DungeonData;
@ -274,11 +275,11 @@ public class DungeonHelper
return pack;
}
public IDimLink createCustomDungeonDoor(World world, int x, int y, int z)
public DimLink createCustomDungeonDoor(World world, int x, int y, int z)
{
//Create a link above the specified position. Link to a new pocket dimension.
NewDimData dimension = PocketManager.getDimensionData(world);
IDimLink link = dimension.createLink(x, y + 1, z, IDimLink.TYPE_POCKET);
DimLink link = dimension.createLink(x, y + 1, z, LinkTypes.POCKET);
//Place a Warp Door linked to that pocket
ItemDimensionalDoor.placeDoorBlock(world, x, y, z, 3, mod_pocketDim.warpDoor);

View file

@ -15,7 +15,7 @@ import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.IDimLink;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
public abstract class BaseItemDoor extends ItemDoor
@ -114,7 +114,7 @@ public abstract class BaseItemDoor extends ItemDoor
{
if (world.getBlockId(hit.blockX, hit.blockY, hit.blockZ) == properties.RiftBlockID)
{
IDimLink link = PocketManager.getLink(hit.blockX, hit.blockY, hit.blockZ, world.provider.dimensionId);
DimLink link = PocketManager.getLink(hit.blockX, hit.blockY, hit.blockZ, world.provider.dimensionId);
if (link != null)
{
int x = hit.blockX;

View file

@ -20,7 +20,7 @@ import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.IDimLink;
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import cpw.mods.fml.relauncher.Side;
@ -187,7 +187,7 @@ public class ItemRiftBlade extends ItemSword
NewDimData dimension = PocketManager.getDimensionData(world);
if (!dimension.isPocketDimension() && dimension.getLink(x, y + 1, z) == null)
{
dimension.createLink(x, y + 1, z, IDimLink.TYPE_POCKET);
dimension.createLink(x, y + 1, z, LinkTypes.POCKET);
player.worldObj.playSoundAtEntity(player,"mods.DimDoors.sfx.riftDoor", 0.6f, 1);
ItemDimensionalDoor.placeDoorBlock(world, x, y, z, orientation, mod_pocketDim.transientDoor);
}

View file

@ -10,7 +10,8 @@ import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.IDimLink;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.util.Point4D;
@ -66,8 +67,8 @@ public class ItemRiftSignature extends Item
//The link was used before and already has an endpoint stored. Create links connecting the two endpoints.
NewDimData sourceDimension = PocketManager.getDimensionData(source.getDimension());
NewDimData destinationDimension = PocketManager.getDimensionData(world);
IDimLink link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), IDimLink.TYPE_NORMAL);
IDimLink reverse = destinationDimension.createLink(x, y, z, IDimLink.TYPE_NORMAL);
DimLink link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.NORMAL);
DimLink reverse = destinationDimension.createLink(x, y, z, LinkTypes.NORMAL);
destinationDimension.setDestination(link, x, y, z);
sourceDimension.setDestination(reverse, source.getX(), source.getY(), source.getZ());

View file

@ -164,7 +164,7 @@ public class mod_pocketDim
//MonolithSpawner should be initialized before any provider instances are created
//Register the other regular tick receivers as well
spawner = new MonolithSpawner(commonTickHandler, properties);
new RiftRegenerator(commonTickHandler, properties); //No need to store the reference
new RiftRegenerator(commonTickHandler); //No need to store the reference
LimboDecay decay = new LimboDecay(commonTickHandler, properties);
transientDoor = (new TransientDoor(properties.TransientDoorID, Material.iron)).setHardness(1.0F) .setUnlocalizedName("transientDoor");
@ -384,6 +384,5 @@ public class mod_pocketDim
CommandCreatePocket.instance().register(event);
CommandTeleportPlayer.instance().register(event);
*/
PocketManager.load();
}
}

View file

@ -4,25 +4,19 @@ import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.IDimLink;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift;
import StevenDimDoors.mod_pocketDim.util.Point4D;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.relauncher.Side;
public class RiftRegenerator implements IRegularTickReceiver {
private static final int RIFT_REGENERATION_INTERVAL = 200; //Regenerate random rifts every 200 ticks
private static final int RIFTS_REGENERATED_PER_DIMENSION = 5;
private DDProperties properties;
public RiftRegenerator(IRegularTickSender sender, DDProperties properties)
public RiftRegenerator(IRegularTickSender sender)
{
sender.registerForTicking(this, RIFT_REGENERATION_INTERVAL, false);
this.properties = properties;
}
@Override
@ -46,7 +40,7 @@ public class RiftRegenerator implements IRegularTickReceiver {
{
for (int count = 0; count < RIFTS_REGENERATED_PER_DIMENSION; count++)
{
IDimLink link = dimension.getRandomLink();
DimLink link = dimension.getRandomLink();
Point4D source = link.source();
if (!mod_pocketDim.blockRift.isBlockImmune(world, source.getX(), source.getY(), source.getZ())&& world.getChunkProvider().chunkExists(source.getX() >> 4, source.getZ() >> 4))
{

View file

@ -17,7 +17,7 @@ import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.MathHelper;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.IDimLink;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.util.Point4D;
@ -38,7 +38,7 @@ public class TileEntityRift extends TileEntity
public int age = 0;
public HashMap<Integer, double[]> renderingCenters = new HashMap<Integer, double[]>();
public IDimLink nearestRiftData;
public DimLink nearestRiftData;
public int spawnedEndermenID=0;
DataWatcher watcher = new DataWatcher();
@ -240,7 +240,7 @@ public class TileEntityRift extends TileEntity
if (growCount < 100)
{
NewDimData dimension = PocketManager.getDimensionData(worldObj);
IDimLink link = dimension.getLink(xCoord, yCoord, zCoord);
DimLink link = dimension.getLink(xCoord, yCoord, zCoord);
if (link != null)
{
if (!this.hasGrownRifts && random.nextInt(3) == 0)

View file

@ -1,5 +1,9 @@
package StevenDimDoors.mod_pocketDim.util;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public final class Point4D implements Comparable<Point4D>
{
@ -155,4 +159,28 @@ public final class Point4D implements Comparable<Point4D>
{
return "(" + x + ", " + y + ", " + z + ", " + dimension + ")";
}
public static void write(Point4D point, DataOutputStream stream) throws IOException
{
stream.writeBoolean(point != null);
if (point != null)
{
stream.writeInt(point.x);
stream.writeInt(point.y);
stream.writeInt(point.z);
stream.writeInt(point.dimension);
}
}
public static Point4D read(DataInputStream stream) throws IOException
{
if (stream.readBoolean())
{
return new Point4D( stream.readInt(), stream.readInt(), stream.readInt(), stream.readInt() );
}
else
{
return null;
}
}
}

View file

@ -0,0 +1,37 @@
package StevenDimDoors.mod_pocketDim.watcher;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
public class ClientDimData
{
//We'll use public fields since this is just a data container and it's immutable
public final int ID;
public final int RootID;
public ClientDimData(int id, int rootID)
{
ID = id;
RootID = rootID;
}
public ClientDimData(NewDimData dimension)
{
ID = dimension.id();
RootID = dimension.root().id();
}
public void write(DataOutputStream output) throws IOException
{
output.writeInt(ID);
output.writeInt(RootID);
}
public static ClientDimData read(DataInputStream input) throws IOException
{
return new ClientDimData(input.readInt(), input.readInt());
}
}

View file

@ -1,8 +0,0 @@
package StevenDimDoors.mod_pocketDim.watcher;
import java.io.DataOutputStream;
public interface IOpaqueMessage
{
void writeToStream(DataOutputStream stream);
}

View file

@ -1,8 +0,0 @@
package StevenDimDoors.mod_pocketDim.watcher;
import com.google.common.io.ByteArrayDataInput;
public interface IOpaqueReader
{
IOpaqueMessage read(ByteArrayDataInput source);
}

View file

@ -0,0 +1,8 @@
package StevenDimDoors.mod_pocketDim.watcher;
import StevenDimDoors.mod_pocketDim.util.Point4D;
public interface IUpdateSource
{
public void registerWatchers(IUpdateWatcher<ClientDimData> dimWatcher, IUpdateWatcher<Point4D> linkWatcher);
}

View file

@ -1,8 +1,7 @@
package StevenDimDoors.mod_pocketDim.watcher;
public interface IUpdateWatcher
public interface IUpdateWatcher<T>
{
public void onCreated(IOpaqueMessage message);
public void onUpdated(IOpaqueMessage message);
public void onDeleted(IOpaqueMessage message);
public void onCreated(T message);
public void onDeleted(T message);
}

View file

@ -3,48 +3,39 @@ package StevenDimDoors.mod_pocketDim.watcher;
import java.util.ArrayList;
import java.util.List;
public class UpdateWatcherProxy implements IUpdateWatcher
public class UpdateWatcherProxy<T> implements IUpdateWatcher<T>
{
private List<IUpdateWatcher> watchers;
private List<IUpdateWatcher<T>> watchers;
public UpdateWatcherProxy()
{
watchers = new ArrayList<IUpdateWatcher>();
watchers = new ArrayList<IUpdateWatcher<T>>();
}
@Override
public void onCreated(IOpaqueMessage message)
public void onCreated(T message)
{
for (IUpdateWatcher receiver : watchers)
for (IUpdateWatcher<T> receiver : watchers)
{
receiver.onCreated(message);
}
}
@Override
public void onUpdated(IOpaqueMessage message)
public void onDeleted(T message)
{
for (IUpdateWatcher receiver : watchers)
{
receiver.onUpdated(message);
}
}
@Override
public void onDeleted(IOpaqueMessage message)
{
for (IUpdateWatcher receiver : watchers)
for (IUpdateWatcher<T> receiver : watchers)
{
receiver.onDeleted(message);
}
}
public void registerReceiver(IUpdateWatcher receiver)
public void registerReceiver(IUpdateWatcher<T> receiver)
{
watchers.add(receiver);
}
public boolean unregisterReceiver(IUpdateWatcher receiver)
public boolean unregisterReceiver(IUpdateWatcher<T> receiver)
{
return watchers.remove(receiver);
}

View file

@ -9,7 +9,8 @@ import net.minecraft.world.chunk.IChunkProvider;
import net.minecraftforge.common.DimensionManager;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.IDimLink;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.LinkTypes;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor;
@ -57,7 +58,7 @@ public class GatewayGenerator implements IWorldGenerator
int attempts;
int correction;
boolean valid;
IDimLink link;
DimLink link;
NewDimData dimension;
//Check if we're generating things in the Nether
@ -97,7 +98,7 @@ public class GatewayGenerator implements IWorldGenerator
if (link == null)
{
dimension = PocketManager.getDimensionData(world);
link = dimension.createLink(x, y + 1, z, IDimLink.TYPE_POCKET);
link = dimension.createLink(x, y + 1, z, LinkTypes.POCKET);
}
else
{
@ -132,7 +133,7 @@ public class GatewayGenerator implements IWorldGenerator
{
//Create a partial link to a dungeon.
dimension = PocketManager.getDimensionData(world);
link = dimension.createLink(x, y + 1, z, IDimLink.TYPE_DUNGEON);
link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON);
//If the current dimension isn't Limbo, build a Rift Gateway out of Stone Bricks
if (dimension.id() != properties.LimboDimensionID)

View file

@ -10,7 +10,7 @@ import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraftforge.common.DimensionManager;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.Point3D;
import StevenDimDoors.mod_pocketDim.core.IDimLink;
import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.dungeon.DungeonData;
@ -36,7 +36,7 @@ public class PocketBuilder
private PocketBuilder() { }
public static boolean generateNewDungeonPocket(IDimLink link, DDProperties properties)
public static boolean generateNewDungeonPocket(DimLink link, DDProperties properties)
{
if (link == null)
{
@ -214,7 +214,7 @@ public class PocketBuilder
schematic.getLength() <= DungeonHelper.MAX_DUNGEON_LENGTH);
}
public static boolean generateNewPocket(IDimLink link, DDProperties properties)
public static boolean generateNewPocket(DimLink link, DDProperties properties)
{
return generateNewPocket(link, DEFAULT_POCKET_SIZE, DEFAULT_POCKET_WALL_THICKNESS, properties);
}
@ -240,7 +240,7 @@ public class PocketBuilder
return orientation;
}
public static boolean generateNewPocket(IDimLink link, int size, int wallThickness, DDProperties properties)
public static boolean generateNewPocket(DimLink link, int size, int wallThickness, DDProperties properties)
{
if (link == null)
{

View file

@ -1,15 +1,75 @@
package StevenDimDoors.mod_pocketDimClient;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import net.minecraft.network.INetworkManager;
import net.minecraft.network.packet.Packet250CustomPayload;
import StevenDimDoors.mod_pocketDim.PacketConstants;
import StevenDimDoors.mod_pocketDim.core.PocketManager;
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 cpw.mods.fml.common.network.IPacketHandler;
import cpw.mods.fml.common.network.Player;
public class ClientPacketHandler implements IPacketHandler
public class ClientPacketHandler implements IPacketHandler, IUpdateSource
{
private IUpdateWatcher<Point4D> linkWatcher;
private IUpdateWatcher<ClientDimData> dimWatcher;
public ClientPacketHandler()
{
PocketManager.getWatchers(this);
}
@Override
public void registerWatchers(IUpdateWatcher<ClientDimData> dimWatcher, IUpdateWatcher<Point4D> linkWatcher)
{
this.dimWatcher = dimWatcher;
this.linkWatcher = linkWatcher;
}
@Override
public void onPacketData(INetworkManager manager, Packet250CustomPayload packet, Player player)
{
// TODO: Is this even necessary? I'm not convinced we can receive packets from other channels anyway!
if (!packet.channel.equals(PacketConstants.CHANNEL_NAME))
return;
// If this is a memory connection, then our client is running an integrated server.
// We can tell by checking if packet size is 0.
if (manager.packetSize() == 0)
return;
try
{
DataInputStream input = new DataInputStream(new ByteArrayInputStream(packet.data));
byte packetID = input.readByte();
switch (packetID)
{
case PacketConstants.CLIENT_JOIN_PACKET_ID:
PocketManager.readPacket(input);
break;
case PacketConstants.CREATE_DIM_PACKET_ID:
dimWatcher.onCreated( ClientDimData.read(input) );
break;
case PacketConstants.CREATE_LINK_PACKET_ID:
linkWatcher.onCreated( Point4D.read(input) );
break;
case PacketConstants.DELETE_DIM_PACKET_ID:
dimWatcher.onDeleted( ClientDimData.read(input) );
break;
case PacketConstants.DELETE_LINK_PACKET_ID:
linkWatcher.onDeleted( Point4D.read(input) );
break;
}
}
catch (Exception e)
{
System.err.println("An exception occurred while processing a data packet:");
e.printStackTrace();
}
}
}

View file

@ -1,19 +1,10 @@
package StevenDimDoors.mod_pocketDimClient;
import java.io.File;
import cpw.mods.fml.client.FMLClientHandler;
import cpw.mods.fml.client.registry.ClientRegistry;
import cpw.mods.fml.client.registry.RenderingRegistry;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.src.ModLoader;
import net.minecraftforge.client.MinecraftForgeClient;
import StevenDimDoors.mod_pocketDim.CommonProxy;
import StevenDimDoors.mod_pocketDim.Spells;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.ticking.CommonTickHandler;
import StevenDimDoors.mod_pocketDim.ticking.MobMonolith;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift;
import cpw.mods.fml.client.registry.ClientRegistry;
import cpw.mods.fml.client.registry.RenderingRegistry;
public class ClientProxy extends CommonProxy
@ -22,41 +13,24 @@ public class ClientProxy extends CommonProxy
@Override
public void registerRenderers()
{
//MinecraftForgeClient.preloadTexture(BLOCK_PNG);
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityDimDoor.class, new RenderDimDoor());
//This code activates the new rift rendering, as well as a bit of code in TileEntityRift
//ClientRegistry.bindTileEntitySpecialRenderer(TileEntityRift.class, new RenderRift());
//MinecraftForgeClient.preloadTexture(RIFT2_PNG);
RenderingRegistry.registerEntityRenderingHandler(MobMonolith.class, new RenderMobObelisk(.5F));
}
@Override
public void loadTextures()
{
}
@Override
public void printStringClient(String string)
{
ModLoader.getMinecraftInstance().ingameGUI.getChatGUI().printChatMessage(string);
}

View file

@ -1,9 +1,6 @@
package StevenDimDoors.mod_pocketDimClient;
import java.util.EnumSet;
import StevenDimDoors.mod_pocketDim.Spells;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import cpw.mods.fml.common.ITickHandler;

View file

@ -3,11 +3,9 @@ package StevenDimDoors.mod_pocketDimClient;
import java.nio.FloatBuffer;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.tileentity.TileEntity;
@ -15,7 +13,6 @@ import org.lwjgl.opengl.GL11;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.blocks.DimensionalDoor;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;

View file

@ -1,9 +1,6 @@
package StevenDimDoors.mod_pocketDimClient;
import StevenDimDoors.mod_pocketDim.ticking.MobMonolith;
import net.minecraft.client.renderer.entity.RenderLiving;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;

View file

@ -1,24 +1,19 @@
package StevenDimDoors.mod_pocketDimClient;
import java.nio.FloatBuffer;
import java.util.HashMap;
import java.util.Random;
import static org.lwjgl.opengl.GL11.GL_BLEND;
import static org.lwjgl.opengl.GL11.GL_LIGHTING;
import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_DST_COLOR;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.GL_ZERO;
import static org.lwjgl.opengl.GL11.glBlendFunc;
import java.util.HashMap;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.tileentity.TileEntity;
import org.lwjgl.opengl.GL11;
import static org.lwjgl.opengl.GL11.*;
import StevenDimDoors.mod_pocketDim.DDProperties;
import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.blocks.DimensionalDoor;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;