Completed Packet Handling Code

Finished implementing all the packet handling code. It could be improved
in the future to compress the initial packet sent to clients. With this,
the code is complete enough to run! Commands have not been fixed yet but
that will come in the future.
This commit is contained in:
SenseiKiwi
2013-09-03 17:25:58 -04:00
parent 3568d223ff
commit 4cd7d3c0ae
10 changed files with 162 additions and 72 deletions

View File

@@ -4,12 +4,11 @@ public class PacketConstants
{ {
private PacketConstants() { } private PacketConstants() { }
public static final String CHANNEL_NAME = "DimDoorsPackets";
public static final byte CLIENT_JOIN_PACKET_ID = 1; public static final byte CLIENT_JOIN_PACKET_ID = 1;
public static final byte CREATE_DIM_PACKET_ID = 2; 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 = 3;
public static final byte DELETE_DIM_PACKET_ID = 4; public static final byte CREATE_LINK_PACKET_ID = 4;
public static final byte CREATE_LINK_PACKET_ID = 5; public static final byte DELETE_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";
} }

View File

@@ -23,7 +23,7 @@ public abstract class DimLink
protected DimLink(Point4D source, int linkType) protected DimLink(Point4D source, int linkType)
{ {
if (linkType < LinkTypes.ENUM_MIN || linkType > LinkTypes.ENUM_MAX && linkType != LinkTypes.UNKNOWN) if (linkType < LinkTypes.ENUM_MIN || linkType > LinkTypes.ENUM_MAX && linkType != LinkTypes.CLIENT_SIDE)
{ {
throw new IllegalArgumentException("The specified link type is invalid."); throw new IllegalArgumentException("The specified link type is invalid.");
} }

View File

@@ -7,7 +7,7 @@ public class LinkTypes
public static final int ENUM_MIN = 0; public static final int ENUM_MIN = 0;
public static final int ENUM_MAX = 8; public static final int ENUM_MAX = 8;
public static final int UNKNOWN = -1337; public static final int CLIENT_SIDE = -1337;
public static final int NORMAL = 0; public static final int NORMAL = 0;
public static final int LIMBO = 1; public static final int LIMBO = 1;

View File

@@ -167,6 +167,11 @@ public abstract class NewDimData
protected NewDimData(int id, NewDimData root) protected NewDimData(int id, NewDimData root)
{ {
// This constructor is meant for client-side code only // This constructor is meant for client-side code only
if (root == null)
{
throw new IllegalArgumentException("root cannot be null.");
}
this.id = id; this.id = id;
this.linkMapping = new TreeMap<Point4D, InnerDimLink>(); //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.linkList = new ArrayList<InnerDimLink>(); //Should be stored in oct tree -- temporary solution
@@ -180,15 +185,7 @@ public abstract class NewDimData
this.dungeon = null; this.dungeon = null;
this.linkWatcher = null; this.linkWatcher = null;
this.depth = 0; this.depth = 0;
if (root != null) this.root = root;
{
this.root = root;
}
else
{
this.root = this;
}
} }
public DimLink findNearestRift(World world, int range, int x, int y, int z) public DimLink findNearestRift(World world, int range, int x, int y, int z)

View File

@@ -17,6 +17,7 @@ import StevenDimDoors.mod_pocketDim.helpers.DeleteFolder;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift;
import StevenDimDoors.mod_pocketDim.util.Point4D; import StevenDimDoors.mod_pocketDim.util.Point4D;
import StevenDimDoors.mod_pocketDim.watcher.ClientDimData; import StevenDimDoors.mod_pocketDim.watcher.ClientDimData;
import StevenDimDoors.mod_pocketDim.watcher.IUpdateSource;
import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher; import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher;
import StevenDimDoors.mod_pocketDim.watcher.UpdateWatcherProxy; import StevenDimDoors.mod_pocketDim.watcher.UpdateWatcherProxy;
@@ -44,11 +45,51 @@ public class PocketManager
// This constructor is meant for client-side code only // This constructor is meant for client-side code only
super(id, root); super(id, root);
} }
}
public InnerDimData(int id) private static class ClientLinkWatcher implements IUpdateWatcher<Point4D>
{
@Override
public void onCreated(Point4D source)
{ {
// This constructor is meant for client-side code only NewDimData dimension = getDimensionData(source.getDimension());
super(id, null); 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);
} }
} }
@@ -302,6 +343,30 @@ public class PocketManager
return 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) public static NewDimData getDimensionData(World world)
{ {
return getDimensionData(world.provider.dimensionId); return getDimensionData(world.provider.dimensionId);
@@ -323,6 +388,11 @@ public class PocketManager
return dimension; return dimension;
} }
public static Iterable<? extends NewDimData> getDimensions()
{
return dimensionData.values();
}
public static void unload() public static void unload()
{ {
save(); save();
@@ -377,6 +447,11 @@ public class PocketManager
return linkWatcher.unregisterReceiver(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 public static void writePacket(DataOutputStream output) throws IOException
{ {
// Write a very compact description of our dimensions and links to be sent to a client // Write a very compact description of our dimensions and links to be sent to a client
@@ -398,8 +473,8 @@ public class PocketManager
// Set up fields // Set up fields
dimensionData = new HashMap<Integer, InnerDimData>(); dimensionData = new HashMap<Integer, InnerDimData>();
dimWatcher = new UpdateWatcherProxy<ClientDimData>(); dimWatcher = null; // Clients shouldn't need to watch dims
linkWatcher = new UpdateWatcherProxy<Point4D>(); linkWatcher = null; // Clients shouldn't need to watch links
// Load compacted client-side dimension data // Load compacted client-side dimension data
Compactor.readDimensions(input, new DimRegistrationCallback()); Compactor.readDimensions(input, new DimRegistrationCallback());
@@ -411,42 +486,4 @@ public class PocketManager
isLoaded = true; isLoaded = true;
isLoading = false; isLoading = 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)
{
// No need to raise events here since this code should only run on the client side
// We assume that the root dimension has already been registered to avoid dependency issues
InnerDimData root = dimensionData.get(rootID);
InnerDimData dimension;
if (rootID != dimensionID)
{
dimension = dimensionData.get(dimensionID);
if (dimension == null)
{
dimension = new InnerDimData(dimensionID, root);
dimensionData.put(dimension.id(), dimension);
}
}
else
{
if (root == null)
{
root = new InnerDimData(rootID);
dimensionData.put(root.id(), root);
}
dimension = root;
}
return dimension;
}
}
} }

View File

@@ -76,7 +76,7 @@ public class Compactor
for (int h = 0; h < linkCount; h++) for (int h = 0; h < linkCount; h++)
{ {
Point4D source = Point4D.read(input); Point4D source = Point4D.read(input);
dimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.UNKNOWN); dimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.CLIENT_SIDE);
} }
} }
} }

View File

@@ -164,7 +164,7 @@ public class mod_pocketDim
//MonolithSpawner should be initialized before any provider instances are created //MonolithSpawner should be initialized before any provider instances are created
//Register the other regular tick receivers as well //Register the other regular tick receivers as well
spawner = new MonolithSpawner(commonTickHandler, properties); 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); LimboDecay decay = new LimboDecay(commonTickHandler, properties);
transientDoor = (new TransientDoor(properties.TransientDoorID, Material.iron)).setHardness(1.0F) .setUnlocalizedName("transientDoor"); transientDoor = (new TransientDoor(properties.TransientDoorID, Material.iron)).setHardness(1.0F) .setUnlocalizedName("transientDoor");

View File

@@ -7,22 +7,16 @@ import StevenDimDoors.mod_pocketDim.mod_pocketDim;
import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.DimLink;
import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.NewDimData;
import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.core.PocketManager;
import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift;
import StevenDimDoors.mod_pocketDim.util.Point4D; import StevenDimDoors.mod_pocketDim.util.Point4D;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.relauncher.Side;
public class RiftRegenerator implements IRegularTickReceiver { public class RiftRegenerator implements IRegularTickReceiver {
private static final int RIFT_REGENERATION_INTERVAL = 200; //Regenerate random rifts every 200 ticks private static final int RIFT_REGENERATION_INTERVAL = 200; //Regenerate random rifts every 200 ticks
private static final int RIFTS_REGENERATED_PER_DIMENSION = 5; private static final int RIFTS_REGENERATED_PER_DIMENSION = 5;
private DDProperties properties; public RiftRegenerator(IRegularTickSender sender)
public RiftRegenerator(IRegularTickSender sender, DDProperties properties)
{ {
sender.registerForTicking(this, RIFT_REGENERATION_INTERVAL, false); sender.registerForTicking(this, RIFT_REGENERATION_INTERVAL, false);
this.properties = properties;
} }
@Override @Override

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,15 +1,70 @@
package StevenDimDoors.mod_pocketDimClient; package StevenDimDoors.mod_pocketDimClient;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import net.minecraft.network.INetworkManager; import net.minecraft.network.INetworkManager;
import net.minecraft.network.packet.Packet250CustomPayload; 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.IPacketHandler;
import cpw.mods.fml.common.network.Player; 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 @Override
public void onPacketData(INetworkManager manager, Packet250CustomPayload packet, Player player) 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;
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();
}
} }
} }