initial commit

This commit is contained in:
Sen 2025-03-11 00:23:54 +01:00 committed by Sen
parent 3c9ee26b06
commit 22186c33b9
1458 changed files with 282792 additions and 0 deletions

View file

@ -0,0 +1,9 @@
package game.network;
import game.future.ListenableFuture;
public interface IThreadListener
{
ListenableFuture<Object> schedule(Runnable run);
boolean isMainThread();
}

View file

@ -0,0 +1,20 @@
package game.network;
public abstract class LazyLoadBase<T>
{
private T value;
private boolean isLoaded = false;
public T getValue()
{
if (!this.isLoaded)
{
this.isLoaded = true;
this.value = this.load();
}
return this.value;
}
protected abstract T load();
}

View file

@ -0,0 +1,484 @@
package game.network;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Pattern;
import game.Log;
import game.future.ThreadFactoryBuilder;
import game.net.bootstrap.Bootstrap;
import game.net.channel.Channel;
import game.net.channel.ChannelException;
import game.net.channel.ChannelFuture;
import game.net.channel.ChannelFutureListener;
import game.net.channel.ChannelHandler;
import game.net.channel.ChannelHandlerContext;
import game.net.channel.ChannelInitializer;
import game.net.channel.ChannelOption;
import game.net.channel.EventLoopGroup;
import game.net.channel.SimpleChannelInboundHandler;
import game.net.channel.local.LocalChannel;
import game.net.channel.local.LocalEventLoopGroup;
import game.net.channel.local.LocalServerChannel;
import game.net.channel.nio.NioEventLoopGroup;
import game.net.channel.socket.SocketChannel;
import game.net.channel.socket.nio.NioSocketChannel;
import game.net.handler.timeout.ReadTimeoutHandler;
import game.net.handler.timeout.TimeoutException;
import game.net.util.AttributeKey;
import game.net.util.concurrent.Future;
import game.net.util.concurrent.GenericFutureListener;
import game.network.NetHandler.ThreadQuickExitException;
public class NetConnection extends SimpleChannelInboundHandler<Packet>
{
private static final Pattern IP_REPLACER = Pattern.compile("([0-9]*)\\.([0-9]*)\\.[0-9]*\\.[0-9]*");
public static final AttributeKey<PacketRegistry> ATTR_STATE = AttributeKey.<PacketRegistry>valueOf("protocol");
public static final LazyLoadBase<NioEventLoopGroup> CLIENT_NIO_EVENTLOOP = new LazyLoadBase<NioEventLoopGroup>()
{
protected NioEventLoopGroup load()
{
return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Client IO #%d").setDaemon(true).build());
}
};
// public static final LazyLoadBase<EpollEventLoopGroup> CLIENT_EPOLL_EVENTLOOP = new LazyLoadBase<EpollEventLoopGroup>()
// {
// protected EpollEventLoopGroup load()
// {
// return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Client IO #%d").setDaemon(true).build());
// }
// };
public static final LazyLoadBase<LocalEventLoopGroup> CLIENT_LOCAL_EVENTLOOP = new LazyLoadBase<LocalEventLoopGroup>()
{
protected LocalEventLoopGroup load()
{
return new LocalEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Local Client IO #%d").setDaemon(true).build());
}
};
// private final PacketDirection direction;
private final Queue<NetConnection.InboundHandlerTuplePacketListener> outboundPacketsQueue = new ConcurrentLinkedQueue<InboundHandlerTuplePacketListener>();
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private Channel channel;
private SocketAddress socketAddress;
private NetHandler packetListener;
private String terminationReason;
private boolean disconnected;
private boolean local;
// public NetConnection(PacketDirection packetDirection)
// {
// this.direction = packetDirection;
// }
public void channelActive(ChannelHandlerContext p_channelActive_1_) throws Exception
{
super.channelActive(p_channelActive_1_);
this.channel = p_channelActive_1_.channel();
this.local = this.channel instanceof LocalChannel || this.channel instanceof LocalServerChannel;
this.socketAddress = this.channel.remoteAddress();
try
{
this.setConnectionState(PacketRegistry.HANDSHAKE);
}
catch (Throwable throwable)
{
Log.JNI.error(throwable, "Fehler beim Aufbauen der Verbindung für Handshake");
}
}
/**
* Sets the new connection state and registers which packets this channel may send and receive
*/
public void setConnectionState(PacketRegistry newState)
{
this.channel.attr(ATTR_STATE).set(newState);
this.channel.config().setAutoRead(true);
// Log.debug("Automatisches Lesen eingeschaltet");
}
public void channelInactive(ChannelHandlerContext p_channelInactive_1_) throws Exception
{
this.closeChannel("Ende der Datenübertragung");
}
public void exceptionCaught(ChannelHandlerContext p_exceptionCaught_1_, Throwable p_exceptionCaught_2_) throws Exception
{
String comp;
if (p_exceptionCaught_2_ instanceof TimeoutException)
{
comp = "Zeitüberschreitung";
}
else
{
comp = "Interner Fehler: " + p_exceptionCaught_2_;
}
this.closeChannel(comp);
}
protected void channelRead0(ChannelHandlerContext p_channelRead0_1_, Packet p_channelRead0_2_) throws Exception
{
if (this.channel.isOpen())
{
try
{
p_channelRead0_2_.processPacket(this.packetListener);
}
catch (ThreadQuickExitException e)
{
;
}
}
}
/**
* Sets the NetHandler for this NetworkManager, no checks are made if this handler is suitable for the particular
* connection state (protocol)
*/
public void setNetHandler(NetHandler handler)
{
if (handler == null) {
throw new NullPointerException("Handler ist Null");
}
// Log.debug("Setze Handler von " + this + " auf " + handler);
this.packetListener = handler;
}
public void sendPacket(Packet packetIn)
{
if (this.isChannelOpen())
{
this.flushOutboundQueue();
this.dispatchPacket(packetIn, null);
}
else
{
this.readWriteLock.writeLock().lock();
try
{
this.outboundPacketsQueue.add(new NetConnection.InboundHandlerTuplePacketListener(packetIn, null));
}
finally
{
this.readWriteLock.writeLock().unlock();
}
}
}
public void sendPacket(Packet packetIn, GenericFutureListener <? extends Future <? super Void >> listener)
{
if (this.isChannelOpen())
{
this.flushOutboundQueue();
this.dispatchPacket(packetIn, new GenericFutureListener[] {listener});
}
else
{
this.readWriteLock.writeLock().lock();
try
{
this.outboundPacketsQueue.add(new NetConnection.InboundHandlerTuplePacketListener(packetIn, listener));
}
finally
{
this.readWriteLock.writeLock().unlock();
}
}
}
/**
* Will commit the packet to the channel. If the current thread 'owns' the channel it will write and flush the
* packet, otherwise it will add a task for the channel eventloop thread to do that.
*/
private void dispatchPacket(final Packet inPacket, final GenericFutureListener <? extends Future <? super Void >> [] futureListeners)
{
final PacketRegistry enumconnectionstate = PacketRegistry.getType(inPacket);
final PacketRegistry enumconnectionstate1 = (PacketRegistry)this.channel.attr(ATTR_STATE).get();
if (enumconnectionstate1 != enumconnectionstate)
{
// Log.debug("Automatisches Lesen ausgeschaltet");
this.channel.config().setAutoRead(false);
}
if (this.channel.eventLoop().inEventLoop())
{
if (enumconnectionstate != enumconnectionstate1)
{
this.setConnectionState(enumconnectionstate);
}
ChannelFuture channelfuture = this.channel.writeAndFlush(inPacket);
if (futureListeners != null)
{
channelfuture.addListeners(futureListeners);
}
channelfuture.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
}
else
{
this.channel.eventLoop().execute(new Runnable()
{
public void run()
{
if (enumconnectionstate != enumconnectionstate1)
{
NetConnection.this.setConnectionState(enumconnectionstate);
}
ChannelFuture channelfuture1 = NetConnection.this.channel.writeAndFlush(inPacket);
if (futureListeners != null)
{
channelfuture1.addListeners(futureListeners);
}
channelfuture1.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
}
});
}
}
/**
* Will iterate through the outboundPacketQueue and dispatch all Packets
*/
private void flushOutboundQueue()
{
if (this.channel != null && this.channel.isOpen())
{
this.readWriteLock.readLock().lock();
try
{
while (!this.outboundPacketsQueue.isEmpty())
{
NetConnection.InboundHandlerTuplePacketListener networkmanager$inboundhandlertuplepacketlistener = (NetConnection.InboundHandlerTuplePacketListener)this.outboundPacketsQueue.poll();
if(networkmanager$inboundhandlertuplepacketlistener != null) { // NPE Fix
this.dispatchPacket(networkmanager$inboundhandlertuplepacketlistener.packet, networkmanager$inboundhandlertuplepacketlistener.futureListeners);
}
}
}
finally
{
this.readWriteLock.readLock().unlock();
}
}
}
/**
* Checks timeouts and processes all packets received
*/
public void processReceivedPackets()
{
this.flushOutboundQueue();
this.packetListener.update();
// if (this.packetListener instanceof ITickable)
// {
// ((ITickable)this.packetListener).update();
// }
this.channel.flush();
}
// /**
// * Returns the socket address of the remote side. Server-only.
// */
// public SocketAddress getRemoteAddress()
// {
// return this.socketAddress;
// }
public String getCutAddress() {
return this.socketAddress == null ? "?.?.*.*" : IP_REPLACER.matcher(this.socketAddress.toString()).replaceAll("$1.$2.*.*");
}
/**
* Closes the channel, the parameter can be used for an exit message (not certain how it gets sent)
*/
public void closeChannel(String message)
{
if (this.channel.isOpen())
{
this.channel.close().awaitUninterruptibly();
this.terminationReason = message;
}
}
/**
* True if this NetworkManager uses a memory connection (single player game). False may imply both an active TCP
* connection or simply no active connection at all
*/
public boolean isLocalChannel()
{
return this.local;
}
/**
* Create a new NetworkManager from the server host and connect it to the server
*
* @param address The address of the server
* @param serverPort The server port
*/
public static NetConnection createNetworkManagerAndConnect(InetAddress address, int serverPort)
{
final NetConnection networkmanager = new NetConnection();
Class <? extends SocketChannel > oclass;
LazyLoadBase <? extends EventLoopGroup > lazyloadbase;
// if (Epoll.isAvailable())
// {
// oclass = EpollSocketChannel.class;
// lazyloadbase = CLIENT_EPOLL_EVENTLOOP;
// }
// else
// {
oclass = NioSocketChannel.class;
lazyloadbase = CLIENT_NIO_EVENTLOOP;
// }
((Bootstrap)((Bootstrap)((Bootstrap)(new Bootstrap()).group((EventLoopGroup)lazyloadbase.getValue())).handler(new ChannelInitializer<Channel>()
{
protected void initChannel(Channel p_initChannel_1_) throws Exception
{
try
{
p_initChannel_1_.config().setOption(ChannelOption.TCP_NODELAY, Boolean.valueOf(true));
}
catch (ChannelException var3)
{
;
}
p_initChannel_1_.pipeline().addLast((String)"timeout", (ChannelHandler)(new ReadTimeoutHandler(30))).addLast((String)"splitter", (ChannelHandler)(new PacketSplitter())).addLast((String)"decoder", (ChannelHandler)(new PacketDecoder(false))).addLast((String)"prepender", (ChannelHandler)(new PacketPrepender())).addLast((String)"encoder", (ChannelHandler)(new PacketEncoder(true))).addLast((String)"packet_handler", (ChannelHandler)networkmanager);
}
})).channel(oclass)).connect(address, serverPort).syncUninterruptibly();
return networkmanager;
}
/**
* Prepares a clientside NetworkManager: establishes a connection to the socket supplied and configures the channel
* pipeline. Returns the newly created instance.
*/
public static NetConnection provideLocalClient(SocketAddress address)
{
final NetConnection networkmanager = new NetConnection();
((Bootstrap)((Bootstrap)((Bootstrap)(new Bootstrap()).group((EventLoopGroup)CLIENT_LOCAL_EVENTLOOP.getValue())).handler(new ChannelInitializer<Channel>()
{
protected void initChannel(Channel p_initChannel_1_) throws Exception
{
p_initChannel_1_.pipeline().addLast((String)"packet_handler", (ChannelHandler)networkmanager);
}
})).channel(LocalChannel.class)).connect(address).syncUninterruptibly();
return networkmanager;
}
/**
* Returns true if this NetworkManager has an active channel, false otherwise
*/
public boolean isChannelOpen()
{
return this.channel != null && this.channel.isOpen();
}
public boolean hasNoChannel()
{
return this.channel == null;
}
/**
* Gets the current handler for processing packets
*/
public NetHandler getNetHandler()
{
return this.packetListener;
}
/**
* Switches the channel to manual reading modus
*/
public void disableAutoRead()
{
this.channel.config().setAutoRead(false);
}
public void setCompressionTreshold(int treshold)
{
if (treshold >= 0)
{
if (this.channel.pipeline().get("decompress") instanceof NettyCompressionDecoder)
{
((NettyCompressionDecoder)this.channel.pipeline().get("decompress")).setCompressionTreshold(treshold);
}
else
{
this.channel.pipeline().addBefore("decoder", "decompress", new NettyCompressionDecoder(treshold));
}
if (this.channel.pipeline().get("compress") instanceof NettyCompressionEncoder)
{
((NettyCompressionEncoder)this.channel.pipeline().get("compress")).setCompressionTreshold(treshold);
}
else
{
this.channel.pipeline().addBefore("encoder", "compress", new NettyCompressionEncoder(treshold));
}
}
else
{
if (this.channel.pipeline().get("decompress") instanceof NettyCompressionDecoder)
{
this.channel.pipeline().remove("decompress");
}
if (this.channel.pipeline().get("compress") instanceof NettyCompressionEncoder)
{
this.channel.pipeline().remove("compress");
}
}
}
public void checkDisconnected()
{
if (this.channel != null && !this.channel.isOpen())
{
if (!this.disconnected)
{
this.disconnected = true;
if (this.terminationReason != null)
{
this.getNetHandler().onDisconnect(this.terminationReason);
}
else if (this.getNetHandler() != null)
{
this.getNetHandler().onDisconnect("Verbindung getrennt");
}
}
else
{
Log.JNI.warn("handleDisconnection() zweifach aufgerufen");
}
}
}
static class InboundHandlerTuplePacketListener
{
private final Packet packet;
private final GenericFutureListener <? extends Future <? super Void >> [] futureListeners;
public InboundHandlerTuplePacketListener(Packet inPacket, GenericFutureListener <? extends Future <? super Void >> inFutureListener)
{
this.packet = inPacket;
this.futureListeners = inFutureListener == null ? null : new GenericFutureListener[] {inFutureListener};
}
}
}

View file

@ -0,0 +1,41 @@
package game.network;
public abstract class NetHandler {
private static final ThreadQuickExitException EXIT = new ThreadQuickExitException();
public static final class ThreadQuickExitException extends RuntimeException {
private ThreadQuickExitException() {
this.setStackTrace(new StackTraceElement[0]);
}
public synchronized Throwable fillInStackTrace() {
this.setStackTrace(new StackTraceElement[0]);
return this;
}
}
public abstract void onDisconnect(String reason);
public void update() {
}
public static <T extends NetHandler> void checkThread(final Packet<T> packet, final T handler, IThreadListener listener)
throws ThreadQuickExitException {
if(!listener.isMainThread()) {
listener.schedule(new Runnable() {
public void run() {
packet.processPacket(handler);
}
});
throw EXIT;
}
}
public static <T extends NetHandler> void checkThread(final Packet<T> packet, final T handler, IThreadListener listener, Object check)
throws ThreadQuickExitException {
if(check == null && listener.isMainThread()) {
throw EXIT;
}
checkThread(packet, handler, listener);
}
}

View file

@ -0,0 +1,22 @@
package game.network;
import game.Server;
import game.packet.HPacketHandshake;
public class NetHandlerHandshakeMemory extends NetHandlerHandshakeServer
{
private final Server gmServer;
private final NetConnection networkManager;
public NetHandlerHandshakeMemory(Server gmServerIn, NetConnection networkManagerIn)
{
this.gmServer = gmServerIn;
this.networkManager = networkManagerIn;
}
public void processHandshake(HPacketHandshake packetIn)
{
this.networkManager.setConnectionState(PacketRegistry.LOGIN);
this.networkManager.setNetHandler(new NetHandlerLoginServer(this.gmServer, this.networkManager));
}
}

View file

@ -0,0 +1,12 @@
package game.network;
import game.packet.HPacketHandshake;
public abstract class NetHandlerHandshakeServer extends NetHandler
{
public abstract void processHandshake(HPacketHandshake packetIn);
public void onDisconnect(String reason)
{
}
}

View file

@ -0,0 +1,41 @@
package game.network;
import game.Server;
import game.init.Config;
import game.packet.HPacketHandshake;
import game.packet.RPacketDisconnect;
public class NetHandlerHandshakeTCP extends NetHandlerHandshakeServer
{
private final Server server;
private final NetConnection networkManager;
public NetHandlerHandshakeTCP(Server serverIn, NetConnection netManager)
{
this.server = serverIn;
this.networkManager = netManager;
}
public void processHandshake(HPacketHandshake packetIn)
{
if(packetIn.getProtocolVersion() == 0) {
this.networkManager.closeChannel("Inkompatibel!");
return;
}
this.networkManager.setConnectionState(PacketRegistry.LOGIN);
if (packetIn.getProtocolVersion() != Config.PROTOCOL)
{
String comp;
if(packetIn.getProtocolVersion() < Config.PROTOCOL)
comp = "Der Server nutzt eine neuere Version: " + Config.VERSION;
else
comp = "Der Server nutzt eine ältere Version: " + Config.VERSION;
this.networkManager.sendPacket(new RPacketDisconnect(comp));
this.networkManager.closeChannel(comp);
}
else
{
this.networkManager.setNetHandler(new NetHandlerLoginServer(this.server, this.networkManager));
}
}
}

View file

@ -0,0 +1,56 @@
package game.network;
import game.Game;
import game.packet.RPacketDisconnect;
import game.packet.RPacketEnableCompression;
import game.packet.RPacketLoginSuccess;
public class NetHandlerLoginClient extends NetHandler {
private final Game gm;
private final NetConnection networkManager;
public NetHandlerLoginClient(NetConnection conn, Game gmIn) {
this.networkManager = conn;
this.gm = gmIn;
}
public void onDisconnect(String reason)
{
this.gm.disconnected(reason);
}
public final void handleDisconnect(RPacketDisconnect packetIn)
{
this.networkManager.closeChannel(packetIn.getReason());
}
public void handleLoginSuccess(RPacketLoginSuccess packetIn)
{
this.networkManager.setConnectionState(PacketRegistry.PLAY);
this.networkManager.setNetHandler(new NetHandlerPlayClient(this.gm, this.networkManager));
}
public final void handleEnableCompression(RPacketEnableCompression packetIn)
{
if (!this.networkManager.isLocalChannel())
{
this.networkManager.setCompressionTreshold(packetIn.getValue());
}
}
// public void handlePasswordRequest(RPacketPasswordRequest packetIn) {
// if(this.server == null) {
// this.networkManager.sendPacket(new LPacketPasswordResponse(this.user, "", ""));
// }
// else if((packetIn.getPasswordRequested() && this.server.pass.isEmpty()) ||
// (packetIn.getPasswordProtected() && this.server.access.isEmpty())) {
//// this.toChange = this.gm.getConnected();
// this.accessRequired = packetIn.getPasswordProtected() && this.server.access.isEmpty();
// this.passwordRequired = packetIn.getPasswordRequested() && this.server.pass.isEmpty();
// this.networkManager.closeChannel("");
// }
// else {
// this.networkManager.sendPacket(new LPacketPasswordResponse(this.user, this.access, this.pass));
// }
// }
}

View file

@ -0,0 +1,147 @@
package game.network;
import game.Log;
import game.Server;
import game.color.TextColor;
import game.init.Config;
import game.init.NameRegistry;
import game.packet.LPacketPasswordResponse;
import game.packet.RPacketDisconnect;
import game.rng.Random;
public class NetHandlerLoginServer extends NetHandler
{
private static enum LoginState {
PASSWORD, READY_TO_ACCEPT, ACCEPTED;
}
private final Server server;
public final NetConnection netManager;
private LoginState state = LoginState.PASSWORD;
private int timer;
private String loginUser;
private String loginPass;
public NetHandlerLoginServer(Server server, NetConnection netManager)
{
this.netManager = netManager;
this.server = server;
}
public void closeConnection(String reason)
{
try
{
Log.JNI.info("Trenne " + this.getConnectionInfo());
this.netManager.sendPacket(new RPacketDisconnect(reason));
this.netManager.closeChannel(reason);
}
catch (Exception exception)
{
Log.JNI.error(exception, "Fehler beim Trennen des Spielers beim Login");
}
}
public void onDisconnect(String reason)
{
Log.JNI.info(this.getConnectionInfo() + " wurde beim Login getrennt: " + TextColor.stripCodes(reason));
}
public String getConnectionInfo()
{
return this.loginUser != null ? (this.loginUser + " (" + this.netManager.getCutAddress()
+ ")") : this.netManager.getCutAddress();
}
public void update()
{
if(this.state == LoginState.READY_TO_ACCEPT)
this.tryAcceptPlayer();
// else if (this.currentLoginState == LoginState.DELAY_ACCEPT)
// {
// if (this.server.getPlayer(this.loginUser) == null)
// {
// this.currentLoginState = LoginState.ACCEPTED;
// this.server.addPlayer(this.networkManager, this.loginUser);
// }
// }
if(this.timer++ == 600)
this.closeConnection("Anmeldung dauerte zu lange");
}
private void tryAcceptPlayer()
{
if(!this.netManager.isLocalChannel()) {
// SocketAddress address = this.netManager.getRemoteAddress();
// if(this.server.isBanned(address)) {
//// Ban ban = this.server.getBanEntryIp(address);
// this.closeConnection("Deine IP-Adresse ist von diesem Server gebannt");
// return;
// }
// if(this.server.isBanned(this.loginUser)) {
// Ban ban = this.server.getBanEntry(this.loginUser);
// this.closeConnection(ban.format(true, 0L));
// return;
// }
if(this.server.getPlayer(this.loginUser) != null) {
this.closeConnection("Nutzername '" + this.loginUser + "' ist bereits vergeben.");
return;
}
}
// if (this.server.getPlayer(this.loginUser) != null)
// {
// this.closeConnection("Nutzername '" + this.loginUser + "' ist bereits vergeben.");
// return;
//// this.currentLoginState = LoginState.DELAY_ACCEPT;
//// player.netHandler.kick("Du hast dich von einen anderen Ort verbunden");
// }
// this.networkManager.sendPacket(new RPacketLoginSuccess());
String kick = this.server.addPlayer(this.netManager, this.loginUser, this.loginPass);
if(kick != null)
this.closeConnection(kick);
else
this.state = LoginState.ACCEPTED;
}
// public void processLoginStart(LPacketLoginStart packetIn)
// {
// if(this.state != LoginState.HELLO)
// throw new IllegalStateException("Unerwartetes Start-Paket");
// if(!this.netManager.isLocalChannel()) {
// this.state = LoginState.PASSWORD;
// this.netManager.sendPacket(new RPacketPasswordRequest()); // !Config.password.isEmpty(), Config.auth
// }
// }
public void processPasswordResponse(LPacketPasswordResponse packetIn) {
if(this.state != LoginState.PASSWORD)
throw new IllegalStateException("Unerwartetes Passwort-Paket");
this.loginUser = packetIn.getUser();
if(this.netManager.isLocalChannel()) {
this.loginPass = "";
// this.loginUser = Config.localUser;
if(this.loginUser.length() > NetHandlerPlayServer.MAX_USER_LENGTH || (!this.loginUser.isEmpty() && !NetHandlerPlayServer.isValidUser(this.loginUser))) {
Random rand = new Random();
do {
this.loginUser = NameRegistry.FANTASY.generate(rand, rand.range(2, 4)).toLowerCase();
}
while(this.loginUser.length() > NetHandlerPlayServer.MAX_USER_LENGTH || !NetHandlerPlayServer.isValidUser(this.loginUser)); // || this.server.getPlayer(this.loginUser) != null);
// this.server.setVar("local_user", this.loginUser);
}
this.server.setLocalUser(this.loginUser);
}
else {
this.loginPass = packetIn.getPassword();
if(this.loginUser.isEmpty() || !NetHandlerPlayServer.isValidUser(this.loginUser))
throw new IllegalStateException("Ungültiger Nutzername!");
// if(!this.checkConnect(packetIn.getAccess()))
// return;
if(!Config.password.isEmpty() && !Config.password.equals(packetIn.getAccess())) {
this.closeConnection("Falsches Zugangspasswort");
return;
}
}
this.state = LoginState.READY_TO_ACCEPT;
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,62 @@
package game.network;
import java.util.List;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import game.net.buffer.ByteBuf;
import game.net.buffer.Unpooled;
import game.net.channel.ChannelHandlerContext;
import game.net.handler.codec.ByteToMessageDecoder;
import game.net.handler.codec.DecoderException;
public class NettyCompressionDecoder extends ByteToMessageDecoder
{
private final Inflater inflater;
private int treshold;
public NettyCompressionDecoder(int treshold)
{
this.treshold = treshold;
this.inflater = new Inflater();
}
protected void decode(ChannelHandlerContext p_decode_1_, ByteBuf p_decode_2_, List<Object> p_decode_3_) throws DataFormatException, Exception
{
if (p_decode_2_.readableBytes() != 0)
{
PacketBuffer packetbuffer = new PacketBuffer(p_decode_2_);
int i = packetbuffer.readVarIntFromBuffer();
if (i == 0)
{
p_decode_3_.add(packetbuffer.readBytes(packetbuffer.readableBytes()));
}
else
{
if (i < this.treshold)
{
throw new DecoderException("Badly compressed packet - size of " + i + " is below server threshold of " + this.treshold);
}
if (i > 2097152)
{
throw new DecoderException("Badly compressed packet - size of " + i + " is larger than protocol maximum of " + 2097152);
}
byte[] abyte = new byte[packetbuffer.readableBytes()];
packetbuffer.readBytes(abyte);
this.inflater.setInput(abyte);
byte[] abyte1 = new byte[i];
this.inflater.inflate(abyte1);
p_decode_3_.add(Unpooled.wrappedBuffer(abyte1));
this.inflater.reset();
}
}
}
public void setCompressionTreshold(int treshold)
{
this.treshold = treshold;
}
}

View file

@ -0,0 +1,53 @@
package game.network;
import java.util.zip.Deflater;
import game.net.buffer.ByteBuf;
import game.net.channel.ChannelHandlerContext;
import game.net.handler.codec.MessageToByteEncoder;
public class NettyCompressionEncoder extends MessageToByteEncoder<ByteBuf>
{
private final byte[] buffer = new byte[8192];
private final Deflater deflater;
private int treshold;
public NettyCompressionEncoder(int treshold)
{
this.treshold = treshold;
this.deflater = new Deflater();
}
protected void encode(ChannelHandlerContext p_encode_1_, ByteBuf p_encode_2_, ByteBuf p_encode_3_) throws Exception
{
int i = p_encode_2_.readableBytes();
PacketBuffer packetbuffer = new PacketBuffer(p_encode_3_);
if (i < this.treshold)
{
packetbuffer.writeVarIntToBuffer(0);
packetbuffer.writeBytes(p_encode_2_);
}
else
{
byte[] abyte = new byte[i];
p_encode_2_.readBytes(abyte);
packetbuffer.writeVarIntToBuffer(abyte.length);
this.deflater.setInput(abyte, 0, i);
this.deflater.finish();
while (!this.deflater.finished())
{
int j = this.deflater.deflate(this.buffer);
packetbuffer.writeBytes((byte[])this.buffer, 0, j);
}
this.deflater.reset();
}
}
public void setCompressionTreshold(int treshold)
{
this.treshold = treshold;
}
}

View file

@ -0,0 +1,10 @@
package game.network;
import java.io.IOException;
public interface Packet<T extends NetHandler>
{
void readPacketData(PacketBuffer buf) throws IOException;
void writePacketData(PacketBuffer buf) throws IOException;
void processPacket(T handler);
}

View file

@ -0,0 +1,463 @@
package game.network;
import java.io.IOException;
import java.nio.charset.Charset;
import game.init.ItemRegistry;
import game.item.ItemStack;
import game.nbt.NBTLoader;
import game.nbt.NBTSizeTracker;
import game.nbt.NBTTagCompound;
import game.net.buffer.ByteBuf;
import game.net.buffer.ByteBufInputStream;
import game.net.buffer.ByteBufOutputStream;
import game.net.handler.codec.DecoderException;
import game.net.handler.codec.EncoderException;
import game.world.BlockPos;
public class PacketBuffer
{
private static final Charset UTF_8 = Charset.forName("UTF-8");
private final ByteBuf buf;
public PacketBuffer(ByteBuf wrapped)
{
this.buf = wrapped;
}
/**
* Calculates the number of bytes required to fit the supplied int (0-5) if it were to be read/written using
* readVarIntFromBuffer or writeVarIntToBuffer
*/
public static int getVarIntSize(int input)
{
for (int i = 1; i < 5; ++i)
{
if ((input & -1 << i * 7) == 0)
{
return i;
}
}
return 5;
}
public void writeByteArray(byte[] array)
{
this.writeVarIntToBuffer(array.length);
this.writeBytes(array);
}
public byte[] readByteArray()
{
byte[] abyte = new byte[this.readVarIntFromBuffer()];
this.readBytes(abyte);
return abyte;
}
public BlockPos readBlockPos()
{
// return new BlockPos(this.readInt(), this.readInt(), this.readInt());
return BlockPos.fromLong(this.readLong());
}
public void writeBlockPos(BlockPos pos)
{
this.writeLong(pos.toLong());
// this.writeInt(pos.getX());
// this.writeInt(pos.getY());
// this.writeInt(pos.getZ());
}
// public Text readChatComponent() throws IOException
// {
// return Text.toComponent(this.readNBTTagCompoundFromBuffer());
// }
//
// public void writeChatComponent(Text component) throws IOException
// {
// this.writeNBTTagCompoundToBuffer(Text.toNbt(component));
//// String s = ;
//// if(s.length() > 32767) {
//// s = component.getFormattedText();
//// s = s.length() > 32720 ? s.substring(0, 32720) : s;
//// s = TextSerializer.toNbt(new TextComponent(s + ChatFormat.GRAY + ChatFormat.ITALIC + " [...]"));
//// }
//// this.writeString(s);
// }
public <T extends Enum<T>> T readEnumValue(Class<T> enumClass)
{
return (T)((Enum[])enumClass.getEnumConstants())[this.readVarIntFromBuffer()];
}
public <T extends Enum<T>> T readEnumOrNull(Class<T> enumClass)
{
int n = this.readVarIntFromBuffer();
return n < 0 ? null : (T)((Enum[])enumClass.getEnumConstants())[n];
}
public void writeEnumValue(Enum<?> value)
{
this.writeVarIntToBuffer(value.ordinal());
}
public void writeEnumOrNull(Enum<?> value)
{
this.writeVarIntToBuffer(value == null ? -1 : value.ordinal());
}
/**
* Reads a compressed int from the buffer. To do so it maximally reads 5 byte-sized chunks whose most significant
* bit dictates whether another byte should be read.
*/
public int readVarIntFromBuffer()
{
int i = 0;
int j = 0;
while (true)
{
byte b0 = this.readByte();
i |= (b0 & 127) << j++ * 7;
if (j > 5)
{
throw new RuntimeException("VarInt too big");
}
if ((b0 & 128) != 128)
{
break;
}
}
return i;
}
public long readVarLong()
{
long i = 0L;
int j = 0;
while (true)
{
byte b0 = this.readByte();
i |= (long)(b0 & 127) << j++ * 7;
if (j > 10)
{
throw new RuntimeException("VarLong too big");
}
if ((b0 & 128) != 128)
{
break;
}
}
return i;
}
// public void writeUuid(UUID uuid)
// {
// this.writeLong(uuid.getMostSignificantBits());
// this.writeLong(uuid.getLeastSignificantBits());
// }
//
// public UUID readUuid()
// {
// return new UUID(this.readLong(), this.readLong());
// }
/**
* Writes a compressed int to the buffer. The smallest number of bytes to fit the passed int will be written. Of
* each such byte only 7 bits will be used to describe the actual value since its most significant bit dictates
* whether the next byte is part of that same int. Micro-optimization for int values that are expected to have
* values below 128.
*/
public void writeVarIntToBuffer(int input)
{
while ((input & -128) != 0)
{
this.writeByte(input & 127 | 128);
input >>>= 7;
}
this.writeByte(input);
}
public void writeVarLong(long value)
{
while ((value & -128L) != 0L)
{
this.writeByte((int)(value & 127L) | 128);
value >>>= 7;
}
this.writeByte((int)value);
}
/**
* Writes a compressed NBTTagCompound to this buffer
*/
public void writeNBTTagCompoundToBuffer(NBTTagCompound nbt)
{
if (nbt == null)
{
this.writeByte(0);
}
else
{
try
{
NBTLoader.write(nbt, new ByteBufOutputStream(this.buf));
}
catch (IOException ioexception)
{
throw new EncoderException(ioexception);
}
}
}
/**
* Reads a compressed NBTTagCompound from this buffer
*/
public NBTTagCompound readNBTTagCompoundFromBuffer() throws IOException
{
int i = this.buf.readerIndex();
byte b0 = this.readByte();
if (b0 == 0)
{
return null;
}
else
{
this.buf.readerIndex(i);
return NBTLoader.read(new ByteBufInputStream(this.buf), new NBTSizeTracker(2097152L));
}
}
/**
* Writes the ItemStack's ID (short), then size (byte), then damage. (short)
*/
public void writeItemStackToBuffer(ItemStack stack)
{
if (stack == null)
{
this.writeShort(-1);
}
else
{
this.writeShort(ItemRegistry.getIdFromItem(stack.getItem()));
this.writeVarIntToBuffer(stack.stackSize);
this.writeShort(stack.getMetadata());
NBTTagCompound nbttagcompound = null;
if (stack.getItem().isDamageable() || stack.getItem().getShareTag())
{
nbttagcompound = stack.getTagCompound();
}
this.writeNBTTagCompoundToBuffer(nbttagcompound);
}
}
/**
* Reads an ItemStack from this buffer
*/
public ItemStack readItemStackFromBuffer() throws IOException
{
ItemStack itemstack = null;
int i = this.readShort();
if (i >= 0)
{
int j = this.readVarIntFromBuffer();
int k = this.readShort();
itemstack = new ItemStack(ItemRegistry.getItemById(i), j, k);
itemstack.setTagCompound(this.readNBTTagCompoundFromBuffer());
}
return itemstack;
}
/**
* Reads a string from this buffer. Expected parameter is maximum allowed string length. Will throw IOException if
* string length exceeds this value!
*/
public String readStringFromBuffer(int maxLength)
{
int i = this.readVarIntFromBuffer();
if (i > maxLength * 4)
{
throw new DecoderException("The received encoded string buffer length is longer than maximum allowed (" + i + " > " + maxLength * 4 + ")");
}
else if (i < 0)
{
throw new DecoderException("The received encoded string buffer length is less than zero! Weird string!");
}
else
{
String s = new String(this.readBytes(i).array(), UTF_8);
if (s.length() > maxLength)
{
throw new DecoderException("The received string length is longer than maximum allowed (" + i + " > " + maxLength + ")");
}
else
{
return s;
}
}
}
public PacketBuffer writeString(String string)
{
byte[] abyte = string.getBytes(UTF_8);
if (abyte.length > 32767)
{
throw new EncoderException("String too big (was " + string.length() + " bytes encoded, max " + 32767 + ")");
}
else
{
this.writeVarIntToBuffer(abyte.length);
this.writeBytes(abyte);
return this;
}
}
public int readableBytes()
{
return this.buf.readableBytes();
}
public ByteBuf ensureWritable(int p_ensureWritable_1_)
{
return this.buf.ensureWritable(p_ensureWritable_1_);
}
public boolean readBoolean()
{
return this.buf.readBoolean();
}
public byte readByte()
{
return this.buf.readByte();
}
public short readUnsignedByte()
{
return this.buf.readUnsignedByte();
}
public short readShort()
{
return this.buf.readShort();
}
public int readUnsignedShort()
{
return this.buf.readUnsignedShort();
}
public int readInt()
{
return this.buf.readInt();
}
public long readUnsignedInt()
{
return this.buf.readUnsignedInt();
}
public long readLong()
{
return this.buf.readLong();
}
public float readFloat()
{
return this.buf.readFloat();
}
public double readDouble()
{
return this.buf.readDouble();
}
public ByteBuf readBytes(int p_readBytes_1_)
{
return this.buf.readBytes(p_readBytes_1_);
}
public ByteBuf readBytes(byte[] p_readBytes_1_)
{
return this.buf.readBytes(p_readBytes_1_);
}
public ByteBuf writeBoolean(boolean p_writeBoolean_1_)
{
return this.buf.writeBoolean(p_writeBoolean_1_);
}
public ByteBuf writeByte(int p_writeByte_1_)
{
return this.buf.writeByte(p_writeByte_1_);
}
public ByteBuf writeShort(int p_writeShort_1_)
{
return this.buf.writeShort(p_writeShort_1_);
}
public ByteBuf writeInt(int p_writeInt_1_)
{
return this.buf.writeInt(p_writeInt_1_);
}
public ByteBuf writeLong(long p_writeLong_1_)
{
return this.buf.writeLong(p_writeLong_1_);
}
public ByteBuf writeFloat(float p_writeFloat_1_)
{
return this.buf.writeFloat(p_writeFloat_1_);
}
public ByteBuf writeDouble(double p_writeDouble_1_)
{
return this.buf.writeDouble(p_writeDouble_1_);
}
public ByteBuf writeBytes(ByteBuf p_writeBytes_1_)
{
return this.buf.writeBytes(p_writeBytes_1_);
}
public ByteBuf writeBytes(ByteBuf p_writeBytes_1_, int p_writeBytes_2_, int p_writeBytes_3_)
{
return this.buf.writeBytes(p_writeBytes_1_, p_writeBytes_2_, p_writeBytes_3_);
}
public ByteBuf writeBytes(byte[] p_writeBytes_1_)
{
return this.buf.writeBytes(p_writeBytes_1_);
}
public ByteBuf writeBytes(byte[] p_writeBytes_1_, int p_writeBytes_2_, int p_writeBytes_3_)
{
return this.buf.writeBytes(p_writeBytes_1_, p_writeBytes_2_, p_writeBytes_3_);
}
public boolean release()
{
return this.buf.release();
}
}

View file

@ -0,0 +1,51 @@
package game.network;
import java.io.IOException;
import java.util.List;
import game.net.buffer.ByteBuf;
import game.net.channel.ChannelHandlerContext;
import game.net.handler.codec.ByteToMessageDecoder;
public class PacketDecoder extends ByteToMessageDecoder
{
private final boolean client;
public PacketDecoder(boolean client)
{
this.client = client;
}
protected void decode(ChannelHandlerContext p_decode_1_, ByteBuf p_decode_2_, List<Object> p_decode_3_) throws IOException, InstantiationException, IllegalAccessException, Exception
{
if (p_decode_2_.readableBytes() != 0)
{
PacketBuffer packetbuffer = new PacketBuffer(p_decode_2_);
int i = packetbuffer.readVarIntFromBuffer();
Packet packet = ((PacketRegistry)p_decode_1_.channel().attr(NetConnection.ATTR_STATE).get()).getPacket(this.client, i);
if (packet == null)
{
throw new IOException("Ungültige Paket-ID " + i);
}
else
{
packet.readPacketData(packetbuffer);
if (packetbuffer.readableBytes() > 0)
{
throw new IOException("Paket " + ((PacketRegistry)p_decode_1_.channel().attr(NetConnection.ATTR_STATE).get()).ordinal() + "/" + i + " (" + packet.getClass() + ") war größer als erwartet, " + packetbuffer.readableBytes() + " weitere Bytes wurden beim Lesen von Paket " + i + " gefunden");
}
else
{
p_decode_3_.add(packet);
// if (Log.isTraceEnabled())
// {
// Log.debug("EIN: [" + p_decode_1_.channel().attr(NetConnection.ATTR_STATE).get() + ":" + i + "] " + packet.getClass().getName());
// }
}
}
}
}
}

View file

@ -0,0 +1,47 @@
package game.network;
import java.io.IOException;
import game.Log;
import game.net.buffer.ByteBuf;
import game.net.channel.ChannelHandlerContext;
import game.net.handler.codec.MessageToByteEncoder;
public class PacketEncoder extends MessageToByteEncoder<Packet>
{
private final boolean client;
public PacketEncoder(boolean client)
{
this.client = client;
}
protected void encode(ChannelHandlerContext p_encode_1_, Packet p_encode_2_, ByteBuf p_encode_3_) throws IOException, Exception
{
Integer integer = ((PacketRegistry)p_encode_1_.channel().attr(NetConnection.ATTR_STATE).get()).getId(this.client, p_encode_2_);
// if (Log.isTraceEnabled())
// {
// Log.debug("AUS: [" + p_encode_1_.channel().attr(NetConnection.ATTR_STATE).get() + ":" + integer + "] " + p_encode_2_.getClass().getName());
// }
if (integer == null)
{
throw new IOException("Kann nicht registriertes Paket nicht serialisieren");
}
else
{
PacketBuffer packetbuffer = new PacketBuffer(p_encode_3_);
packetbuffer.writeVarIntToBuffer(integer.intValue());
try
{
p_encode_2_.writePacketData(packetbuffer);
}
catch (Throwable throwable)
{
Log.JNI.error(throwable, "Fehler beim Schreiben der Paketdaten");
}
}
}
}

View file

@ -0,0 +1,26 @@
package game.network;
import game.net.buffer.ByteBuf;
import game.net.channel.ChannelHandlerContext;
import game.net.handler.codec.MessageToByteEncoder;
public class PacketPrepender extends MessageToByteEncoder<ByteBuf>
{
protected void encode(ChannelHandlerContext p_encode_1_, ByteBuf p_encode_2_, ByteBuf p_encode_3_) throws Exception
{
int i = p_encode_2_.readableBytes();
int j = PacketBuffer.getVarIntSize(i);
if (j > 3)
{
throw new IllegalArgumentException("unable to fit " + i + " into " + 3);
}
else
{
PacketBuffer packetbuffer = new PacketBuffer(p_encode_3_);
packetbuffer.ensureWritable(j + i);
packetbuffer.writeVarIntToBuffer(i);
packetbuffer.writeBytes(p_encode_2_, p_encode_2_.readerIndex(), i);
}
}
}

View file

@ -0,0 +1,252 @@
package game.network;
import java.util.Map;
import game.collect.BiMap;
import game.collect.HashBiMap;
import game.collect.Maps;
import game.packet.CPacketAction;
import game.packet.CPacketBook;
import game.packet.CPacketBreak;
import game.packet.CPacketCheat;
import game.packet.CPacketClick;
import game.packet.CPacketComplete;
import game.packet.CPacketInput;
import game.packet.CPacketKeepAlive;
import game.packet.CPacketMessage;
import game.packet.CPacketPlace;
import game.packet.CPacketPlayer;
import game.packet.CPacketSign;
import game.packet.CPacketSkin;
import game.packet.HPacketHandshake;
import game.packet.LPacketPasswordResponse;
import game.packet.RPacketDisconnect;
import game.packet.RPacketEnableCompression;
import game.packet.RPacketLoginSuccess;
import game.packet.S14PacketEntity;
import game.packet.S18PacketEntityTeleport;
import game.packet.S19PacketEntityHeadLook;
import game.packet.S1APacketEntityStatus;
import game.packet.S1BPacketEntityAttach;
import game.packet.S1CPacketEntityMetadata;
import game.packet.S1DPacketEntityEffect;
import game.packet.S1EPacketRemoveEntityEffect;
import game.packet.S20PacketEntityProperties;
import game.packet.S27PacketExplosion;
import game.packet.S28PacketEffect;
import game.packet.S29PacketSoundEffect;
import game.packet.S2APacketParticles;
import game.packet.S2BPacketChangeGameState;
import game.packet.S2CPacketSpawnGlobalEntity;
import game.packet.S2DPacketOpenWindow;
import game.packet.S2EPacketCloseWindow;
import game.packet.S2FPacketSetSlot;
import game.packet.S30PacketWindowItems;
import game.packet.S31PacketWindowProperty;
import game.packet.S32PacketConfirmTransaction;
import game.packet.S33PacketUpdateSign;
import game.packet.S35PacketUpdateTileEntity;
import game.packet.S36PacketSignEditorOpen;
import game.packet.S38PacketPlayerListItem;
import game.packet.S39PacketPlayerAbilities;
import game.packet.S3APacketTabComplete;
import game.packet.S43PacketUpdateEntityNBT;
import game.packet.SPacketAnimation;
import game.packet.SPacketBiomes;
import game.packet.SPacketBlockAction;
import game.packet.SPacketBlockBreakAnim;
import game.packet.SPacketBlockChange;
import game.packet.SPacketCamera;
import game.packet.SPacketChunkData;
import game.packet.SPacketCollectItem;
import game.packet.SPacketDestroyEntities;
import game.packet.SPacketDimensionName;
import game.packet.SPacketDisconnect;
import game.packet.SPacketEntityEquipment;
import game.packet.SPacketEntityVelocity;
import game.packet.SPacketHeldItemChange;
import game.packet.SPacketJoinGame;
import game.packet.SPacketKeepAlive;
import game.packet.SPacketMapChunkBulk;
import game.packet.SPacketMessage;
import game.packet.SPacketMultiBlockChange;
import game.packet.SPacketPlayerPosLook;
import game.packet.SPacketRespawn;
import game.packet.SPacketSetExperience;
import game.packet.SPacketSkin;
import game.packet.SPacketSpawnMob;
import game.packet.SPacketSpawnObject;
import game.packet.SPacketSpawnPlayer;
import game.packet.SPacketTimeUpdate;
import game.packet.SPacketTrades;
import game.packet.SPacketUpdateHealth;
import game.packet.SPacketWorld;
public enum PacketRegistry
{
HANDSHAKE
{
{
this.client(HPacketHandshake.class);
}
},
LOGIN
{
{
this.server(RPacketDisconnect.class);
this.server(RPacketLoginSuccess.class);
this.server(RPacketEnableCompression.class);
// this.server(RPacketPasswordRequest.class);
// this.client(LPacketLoginStart.class);
this.client(LPacketPasswordResponse.class);
}
},
PLAY
{
{
this.server(SPacketKeepAlive.class);
this.server(SPacketJoinGame.class);
this.server(SPacketMessage.class);
// this.server(SPacketMessage.class);
this.server(SPacketTimeUpdate.class);
this.server(SPacketEntityEquipment.class);
this.server(SPacketUpdateHealth.class);
this.server(SPacketRespawn.class);
this.server(SPacketPlayerPosLook.class);
this.server(SPacketHeldItemChange.class);
this.server(SPacketAnimation.class);
this.server(SPacketSpawnPlayer.class);
this.server(SPacketCollectItem.class);
this.server(SPacketSpawnObject.class);
this.server(SPacketSpawnMob.class);
// this.server(SPacketSpawnPainting.class);
// this.server(SPacketSpawnExperienceOrb.class);
this.server(SPacketEntityVelocity.class);
this.server(SPacketDestroyEntities.class);
this.server(S14PacketEntity.class);
this.server(S14PacketEntity.S15PacketEntityRelMove.class);
this.server(S14PacketEntity.S16PacketEntityLook.class);
this.server(S14PacketEntity.S17PacketEntityLookMove.class);
this.server(S18PacketEntityTeleport.class);
this.server(S19PacketEntityHeadLook.class);
this.server(S1APacketEntityStatus.class);
this.server(S1BPacketEntityAttach.class);
this.server(S1CPacketEntityMetadata.class);
this.server(S1DPacketEntityEffect.class);
this.server(S1EPacketRemoveEntityEffect.class);
this.server(SPacketSetExperience.class);
this.server(S20PacketEntityProperties.class);
this.server(SPacketChunkData.class);
this.server(SPacketMultiBlockChange.class);
this.server(SPacketBlockChange.class);
this.server(SPacketBlockAction.class);
this.server(SPacketBlockBreakAnim.class);
this.server(SPacketMapChunkBulk.class);
this.server(S27PacketExplosion.class);
this.server(S28PacketEffect.class);
this.server(S29PacketSoundEffect.class);
this.server(S2APacketParticles.class);
this.server(S2BPacketChangeGameState.class);
this.server(S2CPacketSpawnGlobalEntity.class);
this.server(S2DPacketOpenWindow.class);
this.server(S2EPacketCloseWindow.class);
this.server(S2FPacketSetSlot.class);
this.server(S30PacketWindowItems.class);
this.server(S31PacketWindowProperty.class);
this.server(S32PacketConfirmTransaction.class);
this.server(S33PacketUpdateSign.class);
// this.server(S34PacketMaps.class);
this.server(S35PacketUpdateTileEntity.class);
this.server(S36PacketSignEditorOpen.class);
// this.server(S37PacketStatistics.class);
this.server(S38PacketPlayerListItem.class);
this.server(S39PacketPlayerAbilities.class);
this.server(S3APacketTabComplete.class);
// this.server(SPacketDisplay.class);
this.server(SPacketSkin.class);
this.server(SPacketDisconnect.class);
this.server(SPacketWorld.class);
// this.server(SPacketCapes.class);
this.server(SPacketCamera.class);
this.server(SPacketBiomes.class);
// this.server(S42PacketTitle.class);
this.server(S43PacketUpdateEntityNBT.class);
// this.server(SPacketBook.class);
this.server(SPacketTrades.class);
// this.server(SPacketNotify.class);
this.server(SPacketDimensionName.class);
this.client(CPacketKeepAlive.class);
this.client(CPacketMessage.class);
this.client(CPacketAction.class);
this.client(CPacketPlayer.class);
this.client(CPacketPlayer.C04PacketPlayerPosition.class);
this.client(CPacketPlayer.C05PacketPlayerLook.class);
this.client(CPacketPlayer.C06PacketPlayerPosLook.class);
this.client(CPacketBreak.class);
this.client(CPacketPlace.class);
this.client(CPacketInput.class);
this.client(CPacketClick.class);
this.client(CPacketCheat.class);
this.client(CPacketComplete.class);
this.client(CPacketSkin.class);
this.client(CPacketSign.class);
this.client(CPacketBook.class);
// this.client(CPacketCmdBlock.class);
}
};
private static final Map<Class<? extends Packet>, PacketRegistry> STATES = Maps.<Class<? extends Packet>, PacketRegistry>newHashMap();
private final BiMap<Integer, Class<? extends Packet>> server = HashBiMap.<Integer, Class<? extends Packet>>create();
private final BiMap<Integer, Class<? extends Packet>> client = HashBiMap.<Integer, Class<? extends Packet>>create();
protected void server(Class <? extends Packet > clazz)
{
if(this.server.containsValue(clazz))
throw new IllegalArgumentException("S-Paket " + clazz + " ist bereits bekannt unter ID " + this.server.inverse().get(clazz));
this.server.put(Integer.valueOf(this.server.size()), clazz);
}
protected void client(Class <? extends Packet > clazz)
{
if(this.client.containsValue(clazz))
throw new IllegalArgumentException("C-Paket " + clazz + " ist bereits bekannt unter ID " + this.client.inverse().get(clazz));
this.client.put(Integer.valueOf(this.client.size()), clazz);
}
public Integer getId(boolean client, Packet packet)
{
return (client ? this.client : this.server).inverse().get(packet.getClass());
}
public Packet getPacket(boolean client, int id) throws InstantiationException, IllegalAccessException {
Class<? extends Packet> oclass = (client ? this.client : this.server).get(id);
return oclass == null ? null : oclass.newInstance();
}
public static PacketRegistry getType(Packet packetIn)
{
return STATES.get(packetIn.getClass());
}
static {
for(PacketRegistry reg : values()) {
for(BiMap<Integer, Class<? extends Packet>> map : new BiMap[] {reg.server, reg.client}) {
for(Class<? extends Packet> clazz : map.values()) {
if(STATES.containsKey(clazz) && STATES.get(clazz) != reg) {
throw new Error("Paket " + clazz + " ist bereits zu ID " + STATES.get(clazz)
+ " zugewiesen - kann nicht auf " + reg + " neu zuweisen");
}
try {
clazz.newInstance();
}
catch(Throwable e) {
throw new Error("Paket " + clazz + " kann nicht instanziert werden!");
}
STATES.put(clazz, reg);
}
}
}
}
}

View file

@ -0,0 +1,55 @@
package game.network;
import java.util.List;
import game.net.buffer.ByteBuf;
import game.net.buffer.Unpooled;
import game.net.channel.ChannelHandlerContext;
import game.net.handler.codec.ByteToMessageDecoder;
import game.net.handler.codec.CorruptedFrameException;
public class PacketSplitter extends ByteToMessageDecoder
{
protected void decode(ChannelHandlerContext p_decode_1_, ByteBuf p_decode_2_, List<Object> p_decode_3_) throws Exception
{
p_decode_2_.markReaderIndex();
byte[] abyte = new byte[3];
for (int i = 0; i < abyte.length; ++i)
{
if (!p_decode_2_.isReadable())
{
p_decode_2_.resetReaderIndex();
return;
}
abyte[i] = p_decode_2_.readByte();
if (abyte[i] >= 0)
{
PacketBuffer packetbuffer = new PacketBuffer(Unpooled.wrappedBuffer(abyte));
try
{
int j = packetbuffer.readVarIntFromBuffer();
if (p_decode_2_.readableBytes() >= j)
{
p_decode_3_.add(p_decode_2_.readBytes(j));
return;
}
p_decode_2_.resetReaderIndex();
}
finally
{
packetbuffer.release();
}
return;
}
}
throw new CorruptedFrameException("length wider than 21-bit");
}
}

View file

@ -0,0 +1,603 @@
package game.network;
import game.Game;
import game.audio.PositionedSound;
import game.block.Block;
import game.entity.Entity;
import game.entity.npc.EntityNPC;
import game.init.BlockRegistry;
import game.init.EntityRegistry;
import game.item.ItemBlock;
import game.item.ItemControl;
import game.item.ItemStack;
import game.material.Material;
import game.packet.CPacketAction;
import game.packet.CPacketBreak;
import game.packet.CPacketClick;
import game.packet.CPacketPlace;
import game.world.BlockPos;
import game.world.Facing;
import game.world.State;
import game.world.Vec3;
import game.world.World;
import game.world.WorldClient;
public class PlayerController
{
private final Game gm;
private final NetHandlerPlayClient netClientHandler;
private BlockPos currentBlock = new BlockPos(-1, -1, -1);
private ItemStack currentItemHittingBlock;
private float curBlockDamageMP;
private float stepSoundTickCounter;
private int blockHitDelay;
private boolean isHittingBlock;
private boolean noclip;
private int currentPlayerItem;
private boolean interacting;
public PlayerController(Game gmIn, NetHandlerPlayClient netHandler)
{
this.gm = gmIn;
this.netClientHandler = netHandler;
}
// public static void clickBlockCreative(Game gmIn, PlayerController playerController, BlockPos pos, Facing facing)
// {
// if (!gmIn.theWorld.extinguishFire(gmIn.thePlayer, pos, facing))
// {
// playerController.onPlayerDestroyBlock(pos, facing);
// }
// }
// public void setPlayerCapabilities()
// {
// this.gm.thePlayer.flying &= this.gm.thePlayer.hasEffect(Potion.flying) || this.gm.thePlayer.noclip;
// }
// public boolean isNoclip()
// {
// return this.gm.thePlayer.capabilities.noClip;
// }
// public void setNoclip(boolean noclip)
// {
// this.noclip = noclip;
// }
// public void setCheat(boolean cheat)
// {
// this.cheat = cheat;
// this.setPlayerCapabilities();
// }
// public boolean shouldDrawHUD()
// {
// return !this.creative;
// }
/**
* Called when a player completes the destruction of a block
*/
public boolean onPlayerDestroyBlock(BlockPos pos, Facing side)
{
// if (this.gamemode.isAdventure())
// {
// if (this.gamemode == Gamemode.SPECTATOR)
// {
// return false;
// }
// if (!this.gm.thePlayer.isAllowEdit())
// {
// Block block = this.gm.theWorld.getBlockState(pos).getBlock();
// ItemStack itemstack = this.gm.thePlayer.getCurrentEquippedItem();
//
// if (itemstack == null)
// {
// return false;
// }
//
// if (!itemstack.canDestroy(block))
// {
// return false;
// }
// }
// }
// if (this.gm.thePlayer.getHeldItem() != null && !this.gm.thePlayer.getHeldItem().getItem().canBreakBlocks())
// {
// return false;
// }
// else
// {
World world = this.gm.theWorld;
State iblockstate = world.getState(pos);
Block block1 = iblockstate.getBlock();
if (block1.getMaterial() == Material.air)
{
return false;
}
else
{
world.playAuxSFX(2001, pos, BlockRegistry.getStateId(iblockstate));
boolean flag = world.setBlockToAir(pos);
if (flag)
{
block1.onBlockDestroyedByPlayer(world, pos, iblockstate);
}
this.currentBlock = new BlockPos(this.currentBlock.getX(), -1, this.currentBlock.getZ());
// if (!this.creative)
// {
ItemStack itemstack1 = this.gm.thePlayer.getCurrentEquippedItem();
if (itemstack1 != null)
{
itemstack1.onBlockDestroyed(world, block1, pos, this.gm.thePlayer);
if (itemstack1.stackSize == 0)
{
this.gm.thePlayer.destroyCurrentEquippedItem();
}
}
// }
return flag;
}
// }
}
/**
* Called when the player is hitting a block with an item.
*/
public boolean clickBlock(BlockPos loc, Facing face)
{
// if (this.gamemode.isAdventure())
// {
// if (this.gamemode == Gamemode.SPECTATOR)
// {
// return false;
// }
// if (!this.gm.thePlayer.isAllowEdit())
// {
// Block block = this.gm.theWorld.getBlockState(loc).getBlock();
// ItemStack itemstack = this.gm.thePlayer.getCurrentEquippedItem();
//
// if (itemstack == null)
// {
// return false;
// }
//
// if (!itemstack.canDestroy(block))
// {
// return false;
// }
// }
// }
if (!World.isValidXZ(loc))
{
return false;
}
else
{
ItemStack stack = this.gm.thePlayer.getHeldItem();
if(stack != null && stack.getItem().onAction(stack, this.gm.thePlayer, this.gm.theWorld, ItemControl.PRIMARY, loc)) {
this.interacting = true;
this.netClientHandler.addToSendQueue(new CPacketBreak(CPacketBreak.Action.START_DESTROY_BLOCK, loc, face));
return true;
}
// if (this.creative)
// {
// this.netClientHandler.addToSendQueue(new CPacketBreak(CPacketBreak.Action.START_DESTROY_BLOCK, loc, face));
// clickBlockCreative(this.gm, this, loc, face);
// this.blockHitDelay = 5;
// }
// else
if (!this.isHittingBlock || !this.isHittingPosition(loc))
{
if (this.isHittingBlock)
{
this.netClientHandler.addToSendQueue(new CPacketBreak(CPacketBreak.Action.ABORT_DESTROY_BLOCK, this.currentBlock, face));
}
this.netClientHandler.addToSendQueue(new CPacketBreak(CPacketBreak.Action.START_DESTROY_BLOCK, loc, face));
Block block1 = this.gm.theWorld.getState(loc).getBlock();
boolean flag = block1.getMaterial() != Material.air;
if (flag && this.curBlockDamageMP == 0.0F)
{
block1.onBlockClicked(this.gm.theWorld, loc, this.gm.thePlayer);
}
if (flag && block1.getPlayerRelativeBlockHardness(this.gm.thePlayer, this.gm.thePlayer.worldObj, loc) >= 1.0F)
{
this.onPlayerDestroyBlock(loc, face);
// if(this.cheat && block1.getPlayerRelativeBlockHardness(this.gm.thePlayer, this.gm.thePlayer.worldObj, loc) < 1.0F)
this.blockHitDelay = 3;
}
else
{
this.isHittingBlock = true;
this.currentBlock = loc;
this.currentItemHittingBlock = this.gm.thePlayer.getHeldItem();
this.curBlockDamageMP = 0.0F;
this.stepSoundTickCounter = 0.0F;
this.gm.theWorld.sendBlockBreakProgress(this.gm.thePlayer.getId(), this.currentBlock, (int)(this.curBlockDamageMP * 10.0F) - 1);
}
}
return true;
}
}
/**
* Resets current block damage and isHittingBlock
*/
public void resetBlockRemoving()
{
if (this.isHittingBlock)
{
this.netClientHandler.addToSendQueue(new CPacketBreak(CPacketBreak.Action.ABORT_DESTROY_BLOCK, this.currentBlock, Facing.DOWN));
this.isHittingBlock = false;
this.curBlockDamageMP = 0.0F;
this.gm.theWorld.sendBlockBreakProgress(this.gm.thePlayer.getId(), this.currentBlock, -1);
}
}
public void resetInteraction()
{
this.interacting = false;
}
public boolean onPlayerDamageBlock(BlockPos posBlock, Facing directionFacing)
{
if(this.interacting)
return false;
this.syncCurrentPlayItem();
if (this.blockHitDelay > 0)
{
--this.blockHitDelay;
return true;
}
// else if (this.creative && World.isValidXZ(posBlock))
// {
// this.blockHitDelay = 5;
// this.netClientHandler.addToSendQueue(new CPacketBreak(CPacketBreak.Action.START_DESTROY_BLOCK, posBlock, directionFacing));
// clickBlockCreative(this.gm, this, posBlock, directionFacing);
// return true;
// }
else if (this.isHittingPosition(posBlock))
{
Block block = this.gm.theWorld.getState(posBlock).getBlock();
if (block.getMaterial() == Material.air)
{
this.isHittingBlock = false;
return false;
}
else
{
this.curBlockDamageMP += block.getPlayerRelativeBlockHardness(this.gm.thePlayer, this.gm.thePlayer.worldObj, posBlock);
if (this.stepSoundTickCounter % 4.0F == 0.0F && block.sound.getStepSound() != null)
{
this.gm.getSoundManager().playSound(new PositionedSound(block.sound.getStepSound(), (block.sound.getVolume() + 1.0F) / 8.0F, /* block.sound.getFrequency() * 0.5F, */ (float)posBlock.getX() + 0.5F, (float)posBlock.getY() + 0.5F, (float)posBlock.getZ() + 0.5F));
}
++this.stepSoundTickCounter;
if (this.curBlockDamageMP >= 1.0F)
{
this.isHittingBlock = false;
this.netClientHandler.addToSendQueue(new CPacketBreak(CPacketBreak.Action.STOP_DESTROY_BLOCK, posBlock, directionFacing));
this.onPlayerDestroyBlock(posBlock, directionFacing);
this.curBlockDamageMP = 0.0F;
this.stepSoundTickCounter = 0.0F;
this.blockHitDelay = 5;
}
this.gm.theWorld.sendBlockBreakProgress(this.gm.thePlayer.getId(), this.currentBlock, (int)(this.curBlockDamageMP * 10.0F) - 1);
return true;
}
}
else
{
return this.clickBlock(posBlock, directionFacing);
}
}
// /**
// * player reach distance = 4F
// */
// public float getBlockReachDistance()
// {
// return ;
// }
public void updateController()
{
this.syncCurrentPlayItem();
if (this.netClientHandler.getNetworkManager().isChannelOpen())
{
this.netClientHandler.getNetworkManager().processReceivedPackets();
}
else
{
this.netClientHandler.getNetworkManager().checkDisconnected();
}
}
private boolean isHittingPosition(BlockPos pos)
{
ItemStack itemstack = this.gm.thePlayer.getHeldItem();
boolean flag = this.currentItemHittingBlock == null && itemstack == null;
if (this.currentItemHittingBlock != null && itemstack != null)
{
flag = itemstack.getItem() == this.currentItemHittingBlock.getItem() && ItemStack.areItemStackTagsEqual(itemstack, this.currentItemHittingBlock) && (itemstack.isItemStackDamageable() || itemstack.getMetadata() == this.currentItemHittingBlock.getMetadata());
}
return pos.equals(this.currentBlock) && flag;
}
/**
* Syncs the current player item with the server
*/
private void syncCurrentPlayItem()
{
int i = this.gm.thePlayer.inventory.currentItem;
if (i != this.currentPlayerItem)
{
this.currentPlayerItem = i;
this.netClientHandler.addToSendQueue(new CPacketAction(CPacketAction.Action.SET_ITEMSLOT, this.currentPlayerItem));
}
}
public boolean onPlayerRightClick(EntityNPC player, WorldClient worldIn, ItemStack heldStack, BlockPos hitPos, Facing side, Vec3 hitVec)
{
this.syncCurrentPlayItem();
float f = (float)(hitVec.xCoord - (double)hitPos.getX());
float f1 = (float)(hitVec.yCoord - (double)hitPos.getY());
float f2 = (float)(hitVec.zCoord - (double)hitPos.getZ());
boolean flag = false;
if (!World.isValidXZ(hitPos))
{
return false;
}
else
{
if(heldStack == null || !heldStack.getItem().onAction(heldStack, player, worldIn, ItemControl.SECONDARY, hitPos)) {
// if (this.gamemode != Gamemode.SPECTATOR)
// {
State iblockstate = worldIn.getState(hitPos);
if ((!player.isSneaking() || player.getHeldItem() == null) // && (player.getHeldItem() == null || !player.getHeldItem().getItem().ignoresBlocks())
&& iblockstate.getBlock().onBlockActivated(worldIn, hitPos, iblockstate, player, side, f, f1, f2))
{
flag = true;
}
if (!flag && heldStack != null && heldStack.getItem() instanceof ItemBlock)
{
ItemBlock itemblock = (ItemBlock)heldStack.getItem();
if (!itemblock.canPlaceBlockOnSide(worldIn, hitPos, side, player, heldStack))
{
return false;
}
}
// }
}
else {
heldStack.getItem().onItemUse(heldStack, player, worldIn, hitPos, side, f, f1, f2);
flag = true;
}
this.netClientHandler.addToSendQueue(new CPacketPlace(hitPos, side.getIndex(), player.inventory.getCurrentItem(), f, f1, f2));
if (!flag) // && this.gamemode != Gamemode.SPECTATOR)
{
if (heldStack == null)
{
return false;
}
// else if (this.creative)
// {
// int i = heldStack.getMetadata();
// int j = heldStack.stackSize;
// boolean flag1 = heldStack.onItemUse(player, worldIn, hitPos, side, f, f1, f2);
// heldStack.setItemDamage(i);
// heldStack.stackSize = j;
// return flag1;
// }
else
{
return heldStack.onItemUse(player, worldIn, hitPos, side, f, f1, f2);
}
}
else
{
return true;
}
}
}
/**
* Notifies the server of things like consuming food, etc...
*/
public boolean sendUseItem(EntityNPC playerIn, World worldIn, ItemStack itemStackIn)
{
// if (this.gamemode == Gamemode.SPECTATOR)
// {
// return false;
// }
// else
// {
this.syncCurrentPlayItem();
this.netClientHandler.addToSendQueue(new CPacketPlace(playerIn.inventory.getCurrentItem()));
int i = itemStackIn.stackSize;
ItemStack itemstack = itemStackIn.useItemRightClick(worldIn, playerIn);
if (itemstack != itemStackIn || itemstack != null && itemstack.stackSize != i)
{
playerIn.inventory.mainInventory[playerIn.inventory.currentItem] = itemstack;
if (itemstack.stackSize == 0)
{
playerIn.inventory.mainInventory[playerIn.inventory.currentItem] = null;
}
return true;
}
else
{
return false;
}
// }
}
public EntityNPC createPlayerEntity(WorldClient worldIn, int type)
{
EntityNPC player = (EntityNPC)EntityRegistry.createEntityByID(type, worldIn);
player.setClientPlayer(this.gm, this.netClientHandler);
return player;
}
/**
* Attacks an entity
*/
public void attackEntity(EntityNPC playerIn, Entity targetEntity)
{
this.syncCurrentPlayItem();
this.netClientHandler.addToSendQueue(new CPacketAction(CPacketAction.Action.ATTACK, targetEntity.getId()));
// if (this.gamemode != Gamemode.SPECTATOR)
// {
playerIn.attackTargetEntityWithCurrentItem(targetEntity);
// }
}
/**
* Send packet to server - player is interacting with another entity (left click)
*/
public boolean interactWithEntitySendPacket(EntityNPC playerIn, Entity targetEntity)
{
this.syncCurrentPlayItem();
this.netClientHandler.addToSendQueue(new CPacketAction(CPacketAction.Action.INTERACT, targetEntity.getId()));
return /* this.gamemode != Gamemode.SPECTATOR && */ playerIn.interactWith(targetEntity);
}
// /**
// * Return true when the player rightclick on an entity
// *
// * @param player The player's instance
// * @param entityIn The entity clicked
// * @param movingObject The object clicked
// */
// public boolean isPlayerRightClickingOnEntity(EntityNPC player, Entity entityIn, MovingObjectPosition movingObject)
// {
// this.syncCurrentPlayItem();
// Vec3 vec3 = new Vec3(movingObject.hitVec.xCoord - entityIn.posX, movingObject.hitVec.yCoord - entityIn.posY, movingObject.hitVec.zCoord - entityIn.posZ);
// this.netClientHandler.addToSendQueue(new C02PacketUseEntity(entityIn, vec3));
// return this.gamemode != Gamemode.SPECTATOR && entityIn.interactAt(player, vec3);
// }
/**
* Handles slot clicks sends a packet to the server.
*/
public ItemStack windowClick(int windowId, int slotId, int mouseButtonClicked, int mode, EntityNPC playerIn)
{
short short1 = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
ItemStack itemstack = playerIn.openContainer.slotClick(slotId, mouseButtonClicked, mode, playerIn);
this.netClientHandler.addToSendQueue(new CPacketClick(windowId, slotId, mouseButtonClicked, mode, itemstack, short1));
return itemstack;
}
/**
* GuiEnchantment uses this during multiplayer to tell PlayerControllerMP to send a packet indicating the
* enchantment action the player has taken.
*
* @param windowID The ID of the current window
* @param button The button id (enchantment selected)
*/
public void sendEnchantPacket(int windowID, int button)
{
this.netClientHandler.addToSendQueue(new CPacketAction(CPacketAction.Action.ENCHANT_ITEM, windowID | (button << 8)));
}
// /**
// * Used in PlayerControllerMP to update the server with an ItemStack in a slot.
// */
// public void sendCheatPacket(ItemStack itemStackIn, boolean full)
// {
// }
// /**
// * Sends a Packet107 to the server to drop the item on the ground
// */
// public void sendPacketDropItem(ItemStack itemStackIn)
// {
// if (this.creative && itemStackIn != null)
// {
// this.netClientHandler.addToSendQueue(new CPacketCreative(-1, itemStackIn));
// }
// }
public void onStoppedUsingItem(EntityNPC playerIn)
{
this.syncCurrentPlayItem();
this.netClientHandler.addToSendQueue(new CPacketBreak(CPacketBreak.Action.RELEASE_USE_ITEM, BlockPos.ORIGIN, Facing.DOWN));
playerIn.stopUsingItem();
}
// /**
// * Checks if the player is not creative, used for checking if it should break a block instantly
// */
// public boolean isNotCreative()
// {
// return !this.creative;
// }
// /**
// * returns true if player is in creative mode
// */
// public boolean isCreative()
// {
// return this.creative;
// }
// /**
// * Checks if the player is riding a horse, used to chose the GUI to open
// */
// public boolean isRidingHorse()
// {
// return ;
// }
// public Gamemode getGamemode()
// {
// return this.gamemode;
// }
/**
* Return isHittingBlock
*/
public boolean getIsHittingBlock()
{
return this.isHittingBlock;
}
}