Skip to content

Commit

Permalink
Added the packet pipeline
Browse files Browse the repository at this point in the history
  • Loading branch information
fuj1n committed Jan 28, 2014
1 parent 7cded16 commit 6cff414
Show file tree
Hide file tree
Showing 3 changed files with 262 additions and 39 deletions.
60 changes: 21 additions & 39 deletions src/main/java/tconstruct/TConstruct.java
@@ -1,58 +1,35 @@
package tconstruct;

import cpw.mods.fml.common.*;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.event.*;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.registry.*;
import cpw.mods.fml.relauncher.Side;
import net.minecraft.block.material.Material;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.world.gen.structure.MapGenStructureIO;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.EnumHelper;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.*;
import org.apache.logging.log4j.core.config.LoggerConfig;

import tconstruct.achievements.TAchievements;
import tconstruct.client.event.EventCloakRender;
import tconstruct.common.TContent;
import tconstruct.common.TProxyCommon;
import tconstruct.common.TRecipes;
import tconstruct.common.TRepo;
import tconstruct.common.*;
import tconstruct.library.TConstructRegistry;
import tconstruct.library.crafting.Detailing;
import tconstruct.library.crafting.LiquidCasting;
import tconstruct.library.crafting.*;
import tconstruct.library.util.TabTools;
import tconstruct.plugins.PluginController;
import tconstruct.util.EnvironmentChecks;
import tconstruct.util.TCraftingHandler;
import tconstruct.util.TEventHandler;
import tconstruct.util.TEventHandlerAchievement;
import tconstruct.util.config.DimensionBlacklist;
import tconstruct.util.config.PHConstruct;
import tconstruct.util.*;
import tconstruct.util.config.*;
import tconstruct.util.landmine.behavior.Behavior;
import tconstruct.util.landmine.behavior.stackCombo.SpecialStackHandler;
import tconstruct.util.network.packet.PacketPipeline;
import tconstruct.util.player.TPlayerHandler;
import tconstruct.worldgen.SlimeIslandGen;
import tconstruct.worldgen.TBaseWorldGenerator;
import tconstruct.worldgen.TerrainGenEventHandler;
import tconstruct.worldgen.village.ComponentSmeltery;
import tconstruct.worldgen.village.ComponentToolWorkshop;
import tconstruct.worldgen.village.TVillageTrades;
import tconstruct.worldgen.village.VillageSmelteryHandler;
import tconstruct.worldgen.village.VillageToolStationHandler;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.VillagerRegistry;
import cpw.mods.fml.relauncher.Side;
import tconstruct.worldgen.*;
import tconstruct.worldgen.village.*;

/** TConstruct, the tool mod.
* Craft your tools with style, then modify until the original is gone!
Expand Down Expand Up @@ -85,6 +62,9 @@ public class TConstruct
//The name of the enum is accompanied by numbers because I have no idea what will happen if another mod will try to add the same enum, just to be safe
public static EnumCreatureType creatureTypePlayer = EnumHelper.addCreatureType("PLAYER_5821443", EntityPlayer.class, 0, Material.field_151579_a, true);

//The packet pipeline
public static final PacketPipeline packetPipeline = new PacketPipeline();

public TConstruct()
{
LoggerConfig fml = new LoggerConfig(FMLCommonHandler.instance().getFMLLogger().getName(), Level.ALL, true);
Expand All @@ -110,7 +90,7 @@ public TConstruct()
@EventHandler
public void preInit (FMLPreInitializationEvent event)
{

PHConstruct.initProps(event.getSuggestedConfigurationFile());
TConstructRegistry.materialTab = new TabTools("TConstructMaterials");
TConstructRegistry.toolTab = new TabTools("TConstructTools");
Expand Down Expand Up @@ -170,6 +150,7 @@ public void preInit (FMLPreInitializationEvent event)
@EventHandler
public void init (FMLInitializationEvent event)
{
packetPipeline.initalise();
if (event.getSide() == Side.CLIENT)
{
MinecraftForge.EVENT_BUS.register(new EventCloakRender());
Expand All @@ -190,6 +171,7 @@ public void init (FMLInitializationEvent event)
public void postInit (FMLPostInitializationEvent evt)
{
proxy.postInit();
packetPipeline.postInitialise();
Behavior.registerBuiltInBehaviors();
SpecialStackHandler.registerBuiltInStackHandlers();
recipes.modIntegration();
Expand Down
42 changes: 42 additions & 0 deletions src/main/java/tconstruct/util/network/packet/AbstractPacket.java
@@ -0,0 +1,42 @@
package tconstruct.util.network.packet;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import net.minecraft.entity.player.EntityPlayer;

/**
* AbstractPacket class. Should be the parent of all packets wishing to use the PacketPipeline.
* @author sirgingalot
*/
public abstract class AbstractPacket {

/**
* Encode the packet data into the ByteBuf stream. Complex data sets may need specific data handlers (See @link{cpw.mods.fml.common.network.ByteBuffUtils})
*
* @param ctx channel context
* @param buffer the buffer to encode into
*/
public abstract void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer);

/**
* Decode the packet data from the ByteBuf stream. Complex data sets may need specific data handlers (See @link{cpw.mods.fml.common.network.ByteBuffUtils})
*
* @param ctx channel context
* @param buffer the buffer to decode from
*/
public abstract void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer);

/**
* Handle a packet on the client side. Note this occurs after decoding has completed.
*
* @param player the player reference
*/
public abstract void handleClientSide(EntityPlayer player);

/**
* Handle a packet on the server side. Note this occurs after decoding has completed.
*
* @param player the player reference
*/
public abstract void handleServerSide(EntityPlayer player);
}
199 changes: 199 additions & 0 deletions src/main/java/tconstruct/util/network/packet/PacketPipeline.java
@@ -0,0 +1,199 @@
package tconstruct.util.network.packet;

import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.network.*;
import cpw.mods.fml.common.network.internal.FMLProxyPacket;
import cpw.mods.fml.relauncher.*;
import io.netty.buffer.*;
import io.netty.channel.*;
import io.netty.handler.codec.MessageToMessageCodec;
import java.util.*;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.*;
import net.minecraft.network.*;

/**
* Packet pipeline class. Directs all registered packet data to be handled by the packets themselves.
* @author sirgingalot
* some code from: cpw
*/
@ChannelHandler.Sharable
public class PacketPipeline extends MessageToMessageCodec<FMLProxyPacket, AbstractPacket> {

private EnumMap<Side, FMLEmbeddedChannel> channels;
private LinkedList<Class<? extends AbstractPacket>> packets = new LinkedList<Class<? extends AbstractPacket>>();
private boolean isPostInitialised = false;

/**
* Register your packet with the pipeline. Discriminators are automatically set.
*
* @param clazz the class to register
*
* @return whether registration was successful. Failure may occur if 256 packets have been registered or if the registry already contains this packet
*/
public boolean registerPacket(Class<? extends AbstractPacket> clazz) {
if (this.packets.size() > 256) {
// You should log here!!
return false;
}

if (this.packets.contains(clazz)) {
// You should log here!!
return false;
}

if (this.isPostInitialised) {
// You should log here!!
return false;
}

this.packets.add(clazz);
return true;
}

// In line encoding of the packet, including discriminator setting
@Override
protected void encode(ChannelHandlerContext ctx, AbstractPacket msg, List<Object> out) throws Exception {
ByteBuf buffer = Unpooled.buffer();
Class<? extends AbstractPacket> clazz = msg.getClass();
if (!this.packets.contains(msg.getClass())) {
throw new NullPointerException("No Packet Registered for: " + msg.getClass().getCanonicalName());
}

byte discriminator = (byte) this.packets.indexOf(clazz);
buffer.writeByte(discriminator);
msg.encodeInto(ctx, buffer);
FMLProxyPacket proxyPacket = new FMLProxyPacket(buffer.copy(), ctx.channel().attr(NetworkRegistry.FML_CHANNEL).get());
out.add(proxyPacket);
}

// In line decoding and handling of the packet
@Override
protected void decode(ChannelHandlerContext ctx, FMLProxyPacket msg, List<Object> out) throws Exception {
ByteBuf payload = msg.payload();
byte discriminator = payload.readByte();
Class<? extends AbstractPacket> clazz = this.packets.get(discriminator);
if (clazz == null) {
throw new NullPointerException("No packet registered for discriminator: " + discriminator);
}

AbstractPacket pkt = clazz.newInstance();
pkt.decodeInto(ctx, payload.slice());

EntityPlayer player;
switch (FMLCommonHandler.instance().getEffectiveSide()) {
case CLIENT:
player = this.getClientPlayer();
pkt.handleClientSide(player);
break;

case SERVER:
INetHandler netHandler = ctx.channel().attr(NetworkRegistry.NET_HANDLER).get();
player = ((NetHandlerPlayServer) netHandler).field_147369_b;
pkt.handleServerSide(player);
break;

default:
}

out.add(pkt);
}

// Method to call from FMLInitializationEvent
public void initalise() {
this.channels = NetworkRegistry.INSTANCE.newChannel("TUT", this);
}

// Method to call from FMLPostInitializationEvent
// Ensures that packet discriminators are common between server and client by using logical sorting
public void postInitialise() {
if (this.isPostInitialised) {
return;
}

this.isPostInitialised = true;
Collections.sort(this.packets, new Comparator<Class<? extends AbstractPacket>>() {

@Override
public int compare(Class<? extends AbstractPacket> clazz1, Class<? extends AbstractPacket> clazz2) {
int com = String.CASE_INSENSITIVE_ORDER.compare(clazz1.getCanonicalName(), clazz2.getCanonicalName());
if (com == 0) {
com = clazz1.getCanonicalName().compareTo(clazz2.getCanonicalName());
}

return com;
}
});
}

@SideOnly(Side.CLIENT)
private EntityPlayer getClientPlayer() {
return Minecraft.getMinecraft().thePlayer;
}

/**
* Send this message to everyone.
* <p/>
* Adapted from CPW's code in cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper
*
* @param message The message to send
*/
public void sendToAll(AbstractPacket message) {
this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALL);
this.channels.get(Side.SERVER).writeAndFlush(message);
}

/**
* Send this message to the specified player.
* <p/>
* Adapted from CPW's code in cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper
*
* @param message The message to send
* @param player The player to send it to
*/
public void sendTo(AbstractPacket message, EntityPlayerMP player) {
this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.PLAYER);
this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(player);
this.channels.get(Side.SERVER).writeAndFlush(message);
}

/**
* Send this message to everyone within a certain range of a point.
* <p/>
* Adapted from CPW's code in cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper
*
* @param message The message to send
* @param point The {@link cpw.mods.fml.common.network.NetworkRegistry.TargetPoint} around which to send
*/
public void sendToAllAround(AbstractPacket message, NetworkRegistry.TargetPoint point) {
this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALLAROUNDPOINT);
this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(point);
this.channels.get(Side.SERVER).writeAndFlush(message);
}

/**
* Send this message to everyone within the supplied dimension.
* <p/>
* Adapted from CPW's code in cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper
*
* @param message The message to send
* @param dimensionId The dimension id to target
*/
public void sendToDimension(AbstractPacket message, int dimensionId) {
this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.DIMENSION);
this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(dimensionId);
this.channels.get(Side.SERVER).writeAndFlush(message);
}

/**
* Send this message to the server.
* <p/>
* Adapted from CPW's code in cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper
*
* @param message The message to send
*/
public void sendToServer(AbstractPacket message) {
this.channels.get(Side.CLIENT).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.TOSERVER);
this.channels.get(Side.CLIENT).writeAndFlush(message);
}
}

0 comments on commit 6cff414

Please sign in to comment.