2016-06-23 03:49:47 +00:00
/ *
* Minecraft Forge
2018-07-01 21:17:28 +00:00
* Copyright ( c ) 2016 - 2018 .
2016-06-23 03:49:47 +00:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2 . 1
* of the License .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
* /
2014-09-23 05:01:24 +00:00
package net.minecraftforge.fml.common.network ;
2013-12-06 08:11:03 +00:00
import io.netty.buffer.ByteBuf ;
import io.netty.buffer.Unpooled ;
2013-12-06 16:17:40 +00:00
import io.netty.channel.ChannelHandler.Sharable ;
2014-01-20 03:08:19 +00:00
import io.netty.channel.ChannelHandlerContext ;
2013-12-06 08:11:03 +00:00
import io.netty.handler.codec.MessageToMessageCodec ;
2014-01-20 21:02:26 +00:00
import io.netty.util.AttributeKey ;
2014-09-20 00:24:36 +00:00
2014-05-06 05:14:13 +00:00
import java.lang.ref.WeakReference ;
2014-01-20 03:08:19 +00:00
import java.util.List ;
2014-09-20 00:24:36 +00:00
2018-06-27 18:29:09 +00:00
import it.unimi.dsi.fastutil.bytes.Byte2ObjectMap ;
import it.unimi.dsi.fastutil.bytes.Byte2ObjectOpenHashMap ;
import it.unimi.dsi.fastutil.objects.Object2ByteMap ;
import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap ;
2014-09-20 00:24:36 +00:00
import net.minecraft.network.PacketBuffer ;
2014-09-23 05:01:24 +00:00
import net.minecraftforge.fml.common.FMLLog ;
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket ;
2014-09-20 00:24:36 +00:00
2013-12-06 16:17:40 +00:00
@Sharable
2018-06-27 18:29:09 +00:00
public abstract class FMLIndexedMessageToMessageCodec < A > extends MessageToMessageCodec < FMLProxyPacket , A >
{
private final Byte2ObjectMap < Class < ? extends A > > discriminators = new Byte2ObjectOpenHashMap < > ( ) ;
private final Object2ByteMap < Class < ? extends A > > types = new Object2ByteOpenHashMap < > ( ) ;
2013-12-06 08:11:03 +00:00
2014-01-20 16:58:14 +00:00
/ * *
* Make this accessible to subclasses
* /
2014-01-20 21:02:26 +00:00
2015-11-27 03:38:21 +00:00
public static final AttributeKey < ThreadLocal < WeakReference < FMLProxyPacket > > > INBOUNDPACKETTRACKER = AttributeKey . valueOf ( " fml:inboundpacket " ) ;
2014-01-20 21:02:26 +00:00
@Override
public void handlerAdded ( ChannelHandlerContext ctx ) throws Exception
{
super . handlerAdded ( ctx ) ;
2017-10-31 18:22:55 +00:00
ctx . channel ( ) . attr ( INBOUNDPACKETTRACKER ) . set ( new ThreadLocal < WeakReference < FMLProxyPacket > > ( ) ) ;
2014-01-20 21:02:26 +00:00
}
2014-01-20 16:58:14 +00:00
2013-12-11 23:46:25 +00:00
public FMLIndexedMessageToMessageCodec < A > addDiscriminator ( int discriminator , Class < ? extends A > type )
2013-12-06 08:11:03 +00:00
{
2013-12-11 23:46:25 +00:00
discriminators . put ( ( byte ) discriminator , type ) ;
types . put ( type , ( byte ) discriminator ) ;
2013-12-06 08:11:03 +00:00
return this ;
}
public abstract void encodeInto ( ChannelHandlerContext ctx , A msg , ByteBuf target ) throws Exception ;
2016-03-23 14:34:48 +00:00
2013-12-06 08:11:03 +00:00
@Override
protected final void encode ( ChannelHandlerContext ctx , A msg , List < Object > out ) throws Exception
{
2018-04-22 21:42:05 +00:00
String channel = ctx . channel ( ) . attr ( NetworkRegistry . FML_CHANNEL ) . get ( ) ;
Class < ? > clazz = msg . getClass ( ) ;
if ( ! types . containsKey ( clazz ) )
{
2018-07-05 02:58:36 +00:00
throw new RuntimeException ( " Undefined discriminator for message type " + clazz . getName ( ) + " in channel " + channel ) ;
2018-04-22 21:42:05 +00:00
}
2018-06-27 18:29:09 +00:00
byte discriminator = types . getByte ( clazz ) ;
2014-09-20 00:24:36 +00:00
PacketBuffer buffer = new PacketBuffer ( Unpooled . buffer ( ) ) ;
2013-12-06 08:11:03 +00:00
buffer . writeByte ( discriminator ) ;
encodeInto ( ctx , msg , buffer ) ;
2018-04-22 21:42:05 +00:00
FMLProxyPacket proxy = new FMLProxyPacket ( buffer , channel ) ;
2017-10-31 18:22:55 +00:00
WeakReference < FMLProxyPacket > ref = ctx . channel ( ) . attr ( INBOUNDPACKETTRACKER ) . get ( ) . get ( ) ;
2014-05-06 05:14:13 +00:00
FMLProxyPacket old = ref = = null ? null : ref . get ( ) ;
2014-01-20 21:02:26 +00:00
if ( old ! = null )
{
proxy . setDispatcher ( old . getDispatcher ( ) ) ;
}
2013-12-06 08:11:03 +00:00
out . add ( proxy ) ;
}
public abstract void decodeInto ( ChannelHandlerContext ctx , ByteBuf source , A msg ) ;
@Override
protected final void decode ( ChannelHandlerContext ctx , FMLProxyPacket msg , List < Object > out ) throws Exception
{
2014-01-20 03:08:19 +00:00
testMessageValidity ( msg ) ;
2016-02-20 21:04:31 +00:00
ByteBuf payload = msg . payload ( ) . duplicate ( ) ;
2016-02-20 04:18:16 +00:00
if ( payload . readableBytes ( ) < 1 )
{
2017-06-23 05:33:11 +00:00
FMLLog . log . error ( " The FMLIndexedCodec has received an empty buffer on channel {}, likely a result of a LAN server issue. Pipeline parts : {} " , ctx . channel ( ) . attr ( NetworkRegistry . FML_CHANNEL ) , ctx . pipeline ( ) . toString ( ) ) ;
2016-02-20 04:18:16 +00:00
}
2013-12-06 08:11:03 +00:00
byte discriminator = payload . readByte ( ) ;
Class < ? extends A > clazz = discriminators . get ( discriminator ) ;
2014-01-19 10:21:24 +00:00
if ( clazz = = null )
{
throw new NullPointerException ( " Undefined message for discriminator " + discriminator + " in channel " + msg . channel ( ) ) ;
}
2013-12-06 08:11:03 +00:00
A newMsg = clazz . newInstance ( ) ;
2017-10-31 18:22:55 +00:00
ctx . channel ( ) . attr ( INBOUNDPACKETTRACKER ) . get ( ) . set ( new WeakReference < FMLProxyPacket > ( msg ) ) ;
2013-12-06 08:11:03 +00:00
decodeInto ( ctx , payload . slice ( ) , newMsg ) ;
out . add ( newMsg ) ;
2017-11-11 23:19:00 +00:00
payload . release ( ) ;
2013-12-06 08:11:03 +00:00
}
2014-01-20 03:08:19 +00:00
/ * *
* Called to verify the message received . This can be used to hard disconnect in case of an unexpected packet ,
* say due to a weird protocol mismatch . Use with caution .
* @param msg
* /
protected void testMessageValidity ( FMLProxyPacket msg )
{
}
2014-01-20 21:02:26 +00:00
@Override
public void exceptionCaught ( ChannelHandlerContext ctx , Throwable cause ) throws Exception
{
2017-06-23 05:33:11 +00:00
FMLLog . log . error ( " FMLIndexedMessageCodec exception caught " , cause ) ;
2014-01-20 21:02:26 +00:00
super . exceptionCaught ( ctx , cause ) ;
}
2013-12-06 08:11:03 +00:00
}