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 16:17:40 +00:00
|
|
|
|
2013-12-11 23:46:25 +00:00
|
|
|
import io.netty.channel.ChannelHandlerContext;
|
|
|
|
import io.netty.channel.ChannelOutboundHandlerAdapter;
|
|
|
|
import io.netty.channel.ChannelPromise;
|
2014-01-20 16:26:54 +00:00
|
|
|
import io.netty.channel.embedded.EmbeddedChannel;
|
2013-12-11 23:46:25 +00:00
|
|
|
import io.netty.util.AttributeKey;
|
2014-09-23 05:01:24 +00:00
|
|
|
|
2013-12-06 16:17:40 +00:00
|
|
|
import java.util.List;
|
2018-04-01 08:42:55 +00:00
|
|
|
import java.util.Set;
|
2014-09-23 05:01:24 +00:00
|
|
|
|
2018-04-01 08:42:55 +00:00
|
|
|
import net.minecraft.entity.Entity;
|
|
|
|
import net.minecraft.entity.player.EntityPlayer;
|
2013-12-11 23:46:25 +00:00
|
|
|
import net.minecraft.entity.player.EntityPlayerMP;
|
|
|
|
import net.minecraft.network.NetworkManager;
|
2018-04-01 08:42:55 +00:00
|
|
|
import net.minecraft.server.management.PlayerChunkMap;
|
|
|
|
import net.minecraft.server.management.PlayerChunkMapEntry;
|
|
|
|
import net.minecraft.util.math.MathHelper;
|
|
|
|
import net.minecraft.world.WorldServer;
|
|
|
|
import net.minecraftforge.common.DimensionManager;
|
2016-08-13 20:37:58 +00:00
|
|
|
import net.minecraftforge.common.util.FakePlayer;
|
2014-09-23 05:01:24 +00:00
|
|
|
import net.minecraftforge.fml.common.FMLCommonHandler;
|
|
|
|
import net.minecraftforge.fml.common.network.NetworkRegistry.TargetPoint;
|
|
|
|
import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher;
|
|
|
|
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;
|
2018-06-21 19:37:32 +00:00
|
|
|
import net.minecraftforge.api.distmarker.Dist;
|
2014-09-23 05:01:24 +00:00
|
|
|
|
2013-12-11 23:46:25 +00:00
|
|
|
import com.google.common.collect.ImmutableList;
|
2014-01-20 16:26:54 +00:00
|
|
|
import com.google.common.collect.ImmutableSet;
|
|
|
|
import com.google.common.collect.Sets;
|
2013-12-06 16:17:40 +00:00
|
|
|
|
2017-01-11 23:17:56 +00:00
|
|
|
import javax.annotation.Nullable;
|
|
|
|
|
2013-12-06 16:17:40 +00:00
|
|
|
public class FMLOutboundHandler extends ChannelOutboundHandlerAdapter {
|
2015-11-27 03:38:21 +00:00
|
|
|
public static final AttributeKey<OutboundTarget> FML_MESSAGETARGET = AttributeKey.valueOf("fml:outboundTarget");
|
|
|
|
public static final AttributeKey<Object> FML_MESSAGETARGETARGS = AttributeKey.valueOf("fml:outboundTargetArgs");
|
2013-12-11 23:46:25 +00:00
|
|
|
public enum OutboundTarget {
|
2014-01-20 16:26:54 +00:00
|
|
|
/**
|
|
|
|
* The packet is sent nowhere. It will be on the {@link EmbeddedChannel#outboundMessages()} Queue.
|
|
|
|
*
|
|
|
|
* @author cpw
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
NOWHERE(Sets.immutableEnumSet(Side.CLIENT, Side.SERVER))
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public void validateArgs(Object args)
|
|
|
|
{
|
|
|
|
// NOOP
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-01-11 23:17:56 +00:00
|
|
|
@Nullable
|
2014-01-12 18:20:41 +00:00
|
|
|
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
2014-01-20 16:26:54 +00:00
|
|
|
/**
|
|
|
|
* The packet is sent to the {@link NetworkDispatcher} supplied as an argument.
|
|
|
|
*
|
|
|
|
* @author cpw
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
DISPATCHER(Sets.immutableEnumSet(Side.SERVER))
|
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public void validateArgs(Object args)
|
|
|
|
{
|
|
|
|
if (!(args instanceof NetworkDispatcher))
|
|
|
|
{
|
|
|
|
throw new RuntimeException("DISPATCHER expects a NetworkDispatcher");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
|
|
|
{
|
|
|
|
return ImmutableList.of((NetworkDispatcher)args);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* The packet is sent to the originator of the packet. This requires the inbound packet
|
|
|
|
* to have it's originator information set.
|
|
|
|
*
|
|
|
|
* @author cpw
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
REPLY(Sets.immutableEnumSet(Side.SERVER))
|
2014-01-12 18:20:41 +00:00
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public void validateArgs(Object args)
|
|
|
|
{
|
|
|
|
// NOOP
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
|
|
|
{
|
|
|
|
return ImmutableList.of(packet.getDispatcher());
|
|
|
|
}
|
|
|
|
},
|
2014-01-20 16:26:54 +00:00
|
|
|
/**
|
|
|
|
* The packet is sent to the {@link EntityPlayerMP} supplied as an argument.
|
|
|
|
*
|
|
|
|
* @author cpw
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
PLAYER(Sets.immutableEnumSet(Side.SERVER))
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public void validateArgs(Object args)
|
|
|
|
{
|
|
|
|
if (!(args instanceof EntityPlayerMP))
|
|
|
|
{
|
|
|
|
throw new RuntimeException("PLAYER target expects a Player arg");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@Override
|
2014-01-12 18:20:41 +00:00
|
|
|
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
|
|
|
EntityPlayerMP player = (EntityPlayerMP) args;
|
2016-08-13 20:37:58 +00:00
|
|
|
NetworkDispatcher dispatcher = (player == null || player instanceof FakePlayer) ? null : player.connection.netManager.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
|
2014-06-03 02:12:13 +00:00
|
|
|
return dispatcher == null ? ImmutableList.<NetworkDispatcher>of() : ImmutableList.of(dispatcher);
|
2013-12-11 23:46:25 +00:00
|
|
|
}
|
|
|
|
},
|
2014-01-20 16:26:54 +00:00
|
|
|
/**
|
|
|
|
* The packet is dispatched to all players connected to the server.
|
|
|
|
* @author cpw
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
ALL(Sets.immutableEnumSet(Side.SERVER))
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public void validateArgs(Object args)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
@Override
|
2014-01-12 18:20:41 +00:00
|
|
|
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
2016-03-23 14:34:48 +00:00
|
|
|
ImmutableList.Builder<NetworkDispatcher> builder = ImmutableList.builder();
|
2016-12-21 23:52:30 +00:00
|
|
|
for (EntityPlayerMP player : FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().getPlayers())
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
2016-05-18 12:11:56 +00:00
|
|
|
NetworkDispatcher dispatcher = player.connection.netManager.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
|
2014-05-13 12:13:55 +00:00
|
|
|
if (dispatcher != null) builder.add(dispatcher);
|
2013-12-11 23:46:25 +00:00
|
|
|
}
|
|
|
|
return builder.build();
|
|
|
|
}
|
|
|
|
},
|
2014-01-20 16:26:54 +00:00
|
|
|
/**
|
|
|
|
* The packet is sent to all players in the dimension identified by the integer argument.
|
|
|
|
* @author cpw
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
DIMENSION(Sets.immutableEnumSet(Side.SERVER))
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public void validateArgs(Object args)
|
|
|
|
{
|
|
|
|
if (!(args instanceof Integer))
|
|
|
|
{
|
|
|
|
throw new RuntimeException("DIMENSION expects an integer argument");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@Override
|
2014-01-12 18:20:41 +00:00
|
|
|
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
|
|
|
int dimension = (Integer)args;
|
2016-03-23 14:34:48 +00:00
|
|
|
ImmutableList.Builder<NetworkDispatcher> builder = ImmutableList.builder();
|
2016-12-21 23:52:30 +00:00
|
|
|
for (EntityPlayerMP player : FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().getPlayers())
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
2014-03-19 07:15:53 +00:00
|
|
|
if (dimension == player.dimension)
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
2016-05-18 12:11:56 +00:00
|
|
|
NetworkDispatcher dispatcher = player.connection.netManager.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
|
2014-05-13 12:13:55 +00:00
|
|
|
// Null dispatchers may exist for fake players - skip them
|
|
|
|
if (dispatcher != null) builder.add(dispatcher);
|
2013-12-11 23:46:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return builder.build();
|
|
|
|
}
|
|
|
|
},
|
2014-01-20 16:26:54 +00:00
|
|
|
/**
|
|
|
|
* The packet is sent to all players within range of the {@link TargetPoint} argument supplied.
|
|
|
|
*
|
|
|
|
* @author cpw
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
ALLAROUNDPOINT(Sets.immutableEnumSet(Side.SERVER))
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public void validateArgs(Object args)
|
|
|
|
{
|
|
|
|
if (!(args instanceof TargetPoint))
|
|
|
|
{
|
|
|
|
throw new RuntimeException("ALLAROUNDPOINT expects a TargetPoint argument");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2014-01-12 18:20:41 +00:00
|
|
|
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
|
|
|
TargetPoint tp = (TargetPoint)args;
|
2016-03-23 14:34:48 +00:00
|
|
|
ImmutableList.Builder<NetworkDispatcher> builder = ImmutableList.builder();
|
2016-12-21 23:52:30 +00:00
|
|
|
for (EntityPlayerMP player : FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().getPlayers())
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
2014-03-19 07:15:53 +00:00
|
|
|
if (player.dimension == tp.dimension)
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
2014-03-19 07:15:53 +00:00
|
|
|
double d4 = tp.x - player.posX;
|
|
|
|
double d5 = tp.y - player.posY;
|
|
|
|
double d6 = tp.z - player.posZ;
|
2013-12-11 23:46:25 +00:00
|
|
|
|
|
|
|
if (d4 * d4 + d5 * d5 + d6 * d6 < tp.range * tp.range)
|
|
|
|
{
|
2016-05-18 12:11:56 +00:00
|
|
|
NetworkDispatcher dispatcher = player.connection.netManager.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
|
2014-05-13 12:13:55 +00:00
|
|
|
if (dispatcher != null) builder.add(dispatcher);
|
2013-12-11 23:46:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return builder.build();
|
|
|
|
}
|
|
|
|
},
|
2018-04-01 08:42:55 +00:00
|
|
|
/**
|
|
|
|
* The packet is sent to all players that are watching the Chunk containing the supplied {@link TargetPoint}.
|
|
|
|
* The {@code range} field of the {@link TargetPoint} is ignored.
|
|
|
|
*/
|
|
|
|
TRACKING_POINT(Sets.immutableEnumSet(Side.SERVER))
|
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public void validateArgs(Object args)
|
|
|
|
{
|
|
|
|
if (!(args instanceof TargetPoint))
|
|
|
|
{
|
|
|
|
throw new RuntimeException("TRACKING_POINT expects a TargetPoint argument");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Nullable
|
|
|
|
@Override
|
|
|
|
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
|
|
|
{
|
|
|
|
TargetPoint tp = (TargetPoint)args;
|
|
|
|
WorldServer world = DimensionManager.getWorld(tp.dimension);
|
|
|
|
if (world == null)
|
|
|
|
{
|
|
|
|
return ImmutableList.of();
|
|
|
|
}
|
|
|
|
|
|
|
|
PlayerChunkMapEntry entry = world.getPlayerChunkMap().getEntry(MathHelper.floor(tp.x) >> 4, MathHelper.floor(tp.z) >> 4);
|
|
|
|
if (entry == null)
|
|
|
|
{
|
|
|
|
return ImmutableList.of();
|
|
|
|
}
|
|
|
|
|
|
|
|
ImmutableList.Builder<NetworkDispatcher> builder = ImmutableList.builder();
|
|
|
|
for (EntityPlayerMP player : entry.getWatchingPlayers())
|
|
|
|
{
|
|
|
|
NetworkDispatcher dispatcher = player.connection.netManager.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
|
|
|
|
if (dispatcher != null) builder.add(dispatcher);
|
|
|
|
}
|
|
|
|
return builder.build();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* The packet is sent to all players tracking the supplied {@link Entity}. This is different from {@link #TRACKING_POINT} because Entities
|
|
|
|
* can have different tracking distances depending on their type.
|
|
|
|
*/
|
|
|
|
TRACKING_ENTITY(Sets.immutableEnumSet(Side.SERVER))
|
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public void validateArgs(Object args)
|
|
|
|
{
|
|
|
|
if (!(args instanceof Entity))
|
|
|
|
{
|
|
|
|
throw new RuntimeException("TRACKING_ENTITY expects an Entity argument");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Nullable
|
|
|
|
@Override
|
|
|
|
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
|
|
|
{
|
|
|
|
Entity e = (Entity)args;
|
|
|
|
Set<? extends EntityPlayer> players = FMLCommonHandler.instance().getMinecraftServerInstance()
|
|
|
|
.getWorld(e.dimension).getEntityTracker().getTrackingPlayers(e);
|
|
|
|
|
|
|
|
ImmutableList.Builder<NetworkDispatcher> builder = ImmutableList.builder();
|
|
|
|
for (EntityPlayer player : players)
|
|
|
|
{
|
|
|
|
NetworkDispatcher dispatcher = ((EntityPlayerMP) player).connection.netManager.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
|
|
|
|
if (dispatcher != null) builder.add(dispatcher);
|
|
|
|
}
|
|
|
|
return builder.build();
|
|
|
|
}
|
|
|
|
},
|
2014-01-20 16:26:54 +00:00
|
|
|
/**
|
|
|
|
* The packet is sent to the server this client is currently conversing with.
|
|
|
|
* @author cpw
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
TOSERVER(Sets.immutableEnumSet(Side.CLIENT))
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public void validateArgs(Object args)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
@Override
|
2014-01-12 18:20:41 +00:00
|
|
|
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
2013-12-11 23:46:25 +00:00
|
|
|
{
|
|
|
|
NetworkManager clientConnection = FMLCommonHandler.instance().getClientToServerNetworkManager();
|
2014-06-03 02:12:13 +00:00
|
|
|
return clientConnection == null || clientConnection.channel().attr(NetworkDispatcher.FML_DISPATCHER).get() == null ? ImmutableList.<NetworkDispatcher>of() : ImmutableList.of(clientConnection.channel().attr(NetworkDispatcher.FML_DISPATCHER).get());
|
2013-12-11 23:46:25 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-01-20 16:26:54 +00:00
|
|
|
private OutboundTarget(ImmutableSet<Side> sides)
|
|
|
|
{
|
|
|
|
this.allowed = sides;
|
|
|
|
}
|
|
|
|
public final ImmutableSet<Side> allowed;
|
2013-12-11 23:46:25 +00:00
|
|
|
public abstract void validateArgs(Object args);
|
2017-01-11 23:17:56 +00:00
|
|
|
@Nullable
|
2014-01-12 18:20:41 +00:00
|
|
|
public abstract List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet);
|
2013-12-11 23:46:25 +00:00
|
|
|
}
|
|
|
|
|
2013-12-06 16:17:40 +00:00
|
|
|
@Override
|
|
|
|
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception
|
|
|
|
{
|
|
|
|
if (!(msg instanceof FMLProxyPacket))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2014-01-12 18:20:41 +00:00
|
|
|
FMLProxyPacket pkt = (FMLProxyPacket) msg;
|
2013-12-06 16:17:40 +00:00
|
|
|
OutboundTarget outboundTarget;
|
|
|
|
Object args = null;
|
2013-12-12 23:01:09 +00:00
|
|
|
NetworkDispatcher dispatcher = ctx.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
|
|
|
|
// INTERNAL message callback - let it pass out
|
|
|
|
if (dispatcher != null)
|
|
|
|
{
|
|
|
|
ctx.write(msg, promise);
|
|
|
|
return;
|
|
|
|
}
|
2014-01-20 16:26:54 +00:00
|
|
|
|
|
|
|
outboundTarget = ctx.channel().attr(FML_MESSAGETARGET).get();
|
|
|
|
Side channelSide = ctx.channel().attr(NetworkRegistry.CHANNEL_SOURCE).get();
|
|
|
|
if (outboundTarget != null && outboundTarget.allowed.contains(channelSide))
|
|
|
|
{
|
|
|
|
args = ctx.channel().attr(FML_MESSAGETARGETARGS).get();
|
|
|
|
outboundTarget.validateArgs(args);
|
|
|
|
}
|
|
|
|
else if (channelSide == Side.CLIENT)
|
2013-12-06 16:17:40 +00:00
|
|
|
{
|
|
|
|
outboundTarget = OutboundTarget.TOSERVER;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-01-20 16:26:54 +00:00
|
|
|
throw new FMLNetworkException("Packet arrived at the outbound handler without a valid target!");
|
2013-12-06 16:17:40 +00:00
|
|
|
}
|
2014-01-20 16:26:54 +00:00
|
|
|
|
2014-01-12 18:20:41 +00:00
|
|
|
List<NetworkDispatcher> dispatchers = outboundTarget.selectNetworks(args, ctx, pkt);
|
2013-12-06 16:17:40 +00:00
|
|
|
|
2013-12-11 23:46:25 +00:00
|
|
|
// This will drop the messages into the output queue at the embedded channel
|
|
|
|
if (dispatchers == null)
|
|
|
|
{
|
|
|
|
ctx.write(msg, promise);
|
|
|
|
return;
|
|
|
|
}
|
2013-12-12 23:01:09 +00:00
|
|
|
for (NetworkDispatcher targetDispatcher : dispatchers)
|
2013-12-06 16:17:40 +00:00
|
|
|
{
|
2017-11-19 19:47:51 +00:00
|
|
|
pkt.payload().retain();
|
|
|
|
targetDispatcher.sendProxy(pkt);
|
2013-12-06 16:17:40 +00:00
|
|
|
}
|
2017-11-19 19:47:51 +00:00
|
|
|
pkt.payload().release();
|
2013-12-06 16:17:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|