blob: bebefba9da077e141817d27a685c45c8f8f87c35 [file] [log] [blame] [raw]
package protocolsupport.protocol;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.text.MessageFormat;
import java.util.Collection;
import org.bukkit.entity.Player;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import io.netty.util.Recycler;
import io.netty.util.Recycler.Handle;
import protocolsupport.api.Connection;
import protocolsupport.api.Connection.PacketListener.PacketEvent;
import protocolsupport.api.Connection.PacketListener.RawPacketEvent;
import protocolsupport.api.ProtocolVersion;
import protocolsupport.api.utils.NetworkState;
import protocolsupport.protocol.packet.handler.IPacketListener;
import protocolsupport.protocol.pipeline.ChannelHandlers;
import protocolsupport.protocol.storage.ProtocolStorage;
import protocolsupport.protocol.storage.netcache.NetworkDataCache;
import protocolsupport.protocol.utils.authlib.GameProfile;
import protocolsupport.zplatform.network.NetworkManagerWrapper;
public class ConnectionImpl extends Connection {
protected static final AttributeKey<ConnectionImpl> key = AttributeKey.valueOf("PSConnectionImpl");
protected final NetworkManagerWrapper networkmanager;
public ConnectionImpl(NetworkManagerWrapper networkmanager) {
this.networkmanager = networkmanager;
}
public NetworkManagerWrapper getNetworkManagerWrapper() {
return networkmanager;
}
@Override
public Object getNetworkManager() {
return networkmanager.unwrap();
}
@Override
public boolean isConnected() {
return networkmanager.isConnected();
}
@Override
public void close() {
networkmanager.close("Force connection close");
}
@Override
public void disconnect(String message) {
Player player = getPlayer();
if (player != null) {
player.kickPlayer(message);
return;
}
Object packetListener = networkmanager.getPacketListener();
if (packetListener instanceof IPacketListener) {
((IPacketListener) packetListener).disconnect(message);
return;
}
close();
}
@Override
public InetSocketAddress getRawAddress() {
return networkmanager.getRawAddress();
}
@Override
public InetSocketAddress getAddress() {
return networkmanager.getAddress();
}
@Override
public void changeAddress(InetSocketAddress newRemote) {
SocketAddress primaryaddr = networkmanager.getRawAddress();
ProtocolStorage.addAddress(primaryaddr, newRemote);
networkmanager.setAddress(newRemote);
}
@Override
public Player getPlayer() {
return networkmanager.getBukkitPlayer();
}
@Override
public GameProfile getProfile() {
return (GameProfile) super.getProfile();
}
@Override
public NetworkState getNetworkState() {
return networkmanager.getNetworkState();
}
@Override
public void sendPacket(Object packet) {
networkmanager.getChannel().eventLoop().submit(() -> {
try {
ChannelHandlerContext ctx = networkmanager.getChannel().pipeline().context(ChannelHandlers.LOGIC);
if (ctx != null) {
ctx.writeAndFlush(packet);
}
} catch (Throwable t) {
System.err.println("Error occured while packet sending");
t.printStackTrace();
}
});
}
@Override
public void receivePacket(Object packet) {
networkmanager.getChannel().eventLoop().submit(() -> {
try {
ChannelHandlerContext ctx = networkmanager.getChannel().pipeline().context(ChannelHandlers.LOGIC);
if (ctx != null) {
ctx.fireChannelRead(packet);
}
} catch (Throwable t) {
System.err.println("Error occured while packet receiving");
t.printStackTrace();
}
});
}
@Override
public void sendRawPacket(byte[] data) {
ByteBuf dataInst = Unpooled.wrappedBuffer(data);
networkmanager.getChannel().eventLoop().submit(() -> {
try {
ChannelHandlerContext ctx = networkmanager.getChannel().pipeline().context(ChannelHandlers.RAW_CAPTURE_SEND);
if (ctx != null) {
ctx.writeAndFlush(dataInst);
}
} catch (Throwable t) {
System.err.println("Error occured while raw packet sending");
t.printStackTrace();
}
});
}
@Override
public void receiveRawPacket(byte[] data) {
ByteBuf dataInst = Unpooled.wrappedBuffer(data);
networkmanager.getChannel().eventLoop().submit(() -> {
try {
ChannelHandlerContext ctx = networkmanager.getChannel().pipeline().context(ChannelHandlers.RAW_CAPTURE_RECEIVE);
if (ctx != null) {
ctx.fireChannelRead(dataInst);
}
} catch (Throwable t) {
System.err.println("Error occured while raw packet receiving");
t.printStackTrace();
}
});
}
public static ConnectionImpl getFromChannel(Channel channel) {
return channel.attr(key).get();
}
public void storeInChannel(Channel channel) {
channel.attr(key).set(this);
}
public void setVersion(ProtocolVersion version) {
this.version = version;
}
protected static class LPacketEvent extends PacketEvent implements AutoCloseable {
protected static final Recycler<LPacketEvent> recycler = new Recycler<LPacketEvent>() {
@Override
protected LPacketEvent newObject(Handle<LPacketEvent> handle) {
return new LPacketEvent(handle);
}
};
public static LPacketEvent create(Object packet) {
LPacketEvent packetevent = recycler.get();
packetevent.mainpacket = packet;
packetevent.packets.add(packet);
return packetevent;
}
protected final Handle<LPacketEvent> handle;
protected LPacketEvent(Handle<LPacketEvent> handle) {
this.handle = handle;
}
public void recycle() {
this.mainpacket = null;
this.packets.clear();
this.cancelled = false;
this.handle.recycle(this);
}
@Override
public void close() {
recycle();
}
}
public void handlePacketSend(Object packet, Collection<Object> storeTo) {
try (LPacketEvent packetevent = LPacketEvent.create(packet)) {
for (PacketListener listener : packetlisteners) {
try {
listener.onPacketSending(packetevent);
} catch (Throwable t) {
System.err.println("Error occured while handling packet sending");
t.printStackTrace();
}
}
if (!packetevent.isCancelled()) {
storeTo.addAll(packetevent.getPackets());
}
}
}
public void handlePacketReceive(Object packet, Collection<Object> storeTo) {
try (LPacketEvent packetevent = LPacketEvent.create(packet)) {
for (PacketListener listener : packetlisteners) {
try {
listener.onPacketReceiving(packetevent);
} catch (Throwable t) {
System.err.println("Error occured while handling packet receiving");
t.printStackTrace();
}
}
if (!packetevent.isCancelled()) {
storeTo.addAll(packetevent.getPackets());
}
}
}
protected static class LRawPacketEvent extends RawPacketEvent implements AutoCloseable {
protected static final Recycler<LRawPacketEvent> recycler = new Recycler<LRawPacketEvent>() {
@Override
protected LRawPacketEvent newObject(Handle<LRawPacketEvent> handle) {
return new LRawPacketEvent(handle);
}
};
public static LRawPacketEvent create(ByteBuf data) {
LRawPacketEvent packetevent = recycler.get();
packetevent.data = data;
packetevent.cancelled = false;
return packetevent;
}
protected final Handle<LRawPacketEvent> handle;
protected LRawPacketEvent(Handle<LRawPacketEvent> handle) {
this.handle = handle;
}
public void recycle() {
this.handle.recycle(this);
}
public ByteBuf getDirectData() {
return this.data;
}
@Override
public void close() {
recycle();
}
}
public ByteBuf handleRawPacketSend(ByteBuf data) {
try (LRawPacketEvent rawpacketevent = LRawPacketEvent.create(data)) {
for (PacketListener listener : packetlisteners) {
try {
listener.onRawPacketSending(rawpacketevent);
} catch (Throwable t) {
System.err.println("Error occured while handling raw packet sending");
t.printStackTrace();
}
}
if (rawpacketevent.isCancelled()) {
rawpacketevent.getDirectData().release();
return null;
} else {
return rawpacketevent.getDirectData();
}
}
}
public ByteBuf handleRawPacketReceive(ByteBuf data) {
try (LRawPacketEvent rawpacketevent = LRawPacketEvent.create(data)) {
for (PacketListener listener : packetlisteners) {
try {
listener.onRawPacketReceiving(rawpacketevent);
} catch (Throwable t) {
System.err.println("Error occured while handling raw packet receiving");
t.printStackTrace();
}
}
if (rawpacketevent.isCancelled()) {
rawpacketevent.getDirectData().release();
return null;
} else {
return rawpacketevent.getDirectData();
}
}
}
protected final NetworkDataCache cache = new NetworkDataCache();
public NetworkDataCache getCache() {
return cache;
}
@Override
public String toString() {
return MessageFormat.format(
"{0}(profile: {1}, player: {2}, address: {3}, rawaddress: {4}, version: {5}, metadata: {6})",
getClass().getName(), getProfile(), getPlayer(), getAddress(), getRawAddress(), getVersion(), metadata
);
}
}