diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ServerApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ServerApi.java index 35fef56f8..4a0379701 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ServerApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ServerApi.java @@ -37,9 +37,6 @@ import org.apache.logging.log4j.Logger; /** * This holds the methods that should be called by the host mod loader (Fabric, * Forge, etc.). Specifically server events. - * - * @author James Seibel - * @version 2022-9-16 */ public class ServerApi { @@ -160,11 +157,11 @@ public class ServerApi } } } - + public void serverPlayerJoinEvent(IServerPlayerWrapper player) { IDhServerWorld serverWorld = SharedApi.getIDhServerWorld(); - if (serverWorld instanceof DhServerWorld) + if (serverWorld instanceof DhServerWorld) // TODO add support for DhClientServerWorld's (lan worlds) as well { LOGGER.debug("Waiting for player to connect: " + player.getUUID()); ((DhServerWorld) serverWorld).addPlayer(player); @@ -173,10 +170,11 @@ public class ServerApi public void serverPlayerDisconnectEvent(IServerPlayerWrapper player) { IDhServerWorld serverWorld = SharedApi.getIDhServerWorld(); - if (serverWorld instanceof DhServerWorld) + if (serverWorld instanceof DhServerWorld) // TODO add support for DhClientServerWorld's (lan worlds) as well { LOGGER.debug("Removing player from connect wait list: " + player.getUUID()); ((DhServerWorld) serverWorld).removePlayer(player); } } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/NetworkClient.java b/core/src/main/java/com/seibel/distanthorizons/core/network/NetworkClient.java index a3fc3138e..f9b4b9dbc 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/NetworkClient.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/NetworkClient.java @@ -4,8 +4,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.network.messages.CloseMessage; import com.seibel.distanthorizons.core.network.messages.CloseReasonMessage; import com.seibel.distanthorizons.core.network.messages.HelloMessage; -import com.seibel.distanthorizons.core.network.protocol.DhNetworkChannelInitializer; -import com.seibel.distanthorizons.core.network.protocol.MessageHandler; +import com.seibel.distanthorizons.core.network.protocol.NetworkChannelInitializer; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; @@ -18,110 +17,138 @@ import org.apache.logging.log4j.Logger; import java.net.InetSocketAddress; import java.util.concurrent.TimeUnit; -public class NetworkClient extends NetworkEventSource implements AutoCloseable { +public class NetworkClient extends NetworkEventSource implements AutoCloseable +{ private static final Logger LOGGER = DhLoggerBuilder.getLogger(); - - private enum State { + + private enum EConnectionState + { OPEN, RECONNECT, RECONNECT_FORCE, CLOSE_WAIT, CLOSED } - + private static final int FAILURE_RECONNECT_DELAY_SEC = 5; private static final int FAILURE_RECONNECT_ATTEMPTS = 5; - - // TODO move to config of some sort + + // TODO move to payload of some sort private final InetSocketAddress address; - + private final EventLoopGroup workerGroup = new NioEventLoopGroup(); private final Bootstrap clientBootstrap = new Bootstrap() - .group(workerGroup) + .group(this.workerGroup) .channel(NioSocketChannel.class) .option(ChannelOption.SO_KEEPALIVE, true) - .handler(new DhNetworkChannelInitializer(messageHandler)); - - private State state; + .handler(new NetworkChannelInitializer(this.messageHandler)); + + private EConnectionState connectionState; private Channel channel; private int reconnectAttempts = FAILURE_RECONNECT_ATTEMPTS; - - public NetworkClient(String host, int port) { + + + + public NetworkClient(String host, int port) + { this.address = new InetSocketAddress(host, port); - - registerHandlers(); - connect(); + + this.registerHandlers(); + this.connect(); } - - private void registerHandlers() { - registerHandler(HelloMessage.class, (msg, ctx) -> { - LOGGER.info("Connected to server: {}", ctx.channel().remoteAddress()); + + private void registerHandlers() + { + this.registerHandler(HelloMessage.class, (helloMessage, channelContext) -> + { + LOGGER.info("Connected to server: "+channelContext.channel().remoteAddress()); }); - - registerHandler(CloseReasonMessage.class, (msg, ctx) -> { - LOGGER.info(msg.reason); - state = State.CLOSE_WAIT; + + this.registerHandler(CloseReasonMessage.class, (closeReasonMessage, channelContext) -> + { + LOGGER.info(closeReasonMessage.reason); + this.connectionState = EConnectionState.CLOSE_WAIT; }); - - registerHandler(CloseMessage.class, (msg, ctx) -> { - LOGGER.info("Disconnected from server: {}", ctx.channel().remoteAddress()); - if (state == State.CLOSE_WAIT) - close(); + + this.registerHandler(CloseMessage.class, (closeMessage, channelContext) -> + { + LOGGER.info("Disconnected from server: "+channelContext.channel().remoteAddress()); + if (this.connectionState == EConnectionState.CLOSE_WAIT) + { + this.close(); + } }); } - private void connect() { - LOGGER.info("Connecting to server: {}", address); - state = State.OPEN; + private void connect() + { + LOGGER.info("Connecting to server: "+this.address); + this.connectionState = EConnectionState.OPEN; - ChannelFuture connectFuture = clientBootstrap.connect(address); - connectFuture.addListener((ChannelFuture channelFuture) -> { - if (!channelFuture.isSuccess()) { - LOGGER.warn("Connection failed: {}", channelFuture.cause()); + ChannelFuture connectFuture = this.clientBootstrap.connect(this.address); + connectFuture.addListener((ChannelFuture channelFuture) -> + { + if (!channelFuture.isSuccess()) + { + LOGGER.warn("Connection failed: "+channelFuture.cause()); return; } - channel.writeAndFlush(new HelloMessage()); + + this.channel.writeAndFlush(new HelloMessage()); }); - - channel = connectFuture.channel(); - channel.closeFuture().addListener((ChannelFuture channelFuture) -> { - switch (state) { - case OPEN: - reconnectAttempts--; - LOGGER.info("Reconnection attempts left: {} of {}", reconnectAttempts, FAILURE_RECONNECT_ATTEMPTS); - if (reconnectAttempts == 0) { - state = State.CLOSE_WAIT; - return; - } - - state = State.RECONNECT; - workerGroup.schedule(this::connect, FAILURE_RECONNECT_DELAY_SEC, TimeUnit.SECONDS); - break; - case RECONNECT_FORCE: - LOGGER.info("Reconnecting forcefully."); - reconnectAttempts = FAILURE_RECONNECT_ATTEMPTS; - - state = State.RECONNECT; - workerGroup.schedule(this::connect, 0, TimeUnit.SECONDS); - break; - } + + this.channel = connectFuture.channel(); + this. channel.closeFuture().addListener((ChannelFuture channelFuture) -> + { + switch (this.connectionState) + { + case OPEN: + this.reconnectAttempts--; + LOGGER.info("Reconnection attempts left: ["+this.reconnectAttempts+"] of ["+FAILURE_RECONNECT_ATTEMPTS+"]."); + if (this.reconnectAttempts == 0) + { + this.connectionState = EConnectionState.CLOSE_WAIT; + return; + } + + this.connectionState = EConnectionState.RECONNECT; + this.workerGroup.schedule(this::connect, FAILURE_RECONNECT_DELAY_SEC, TimeUnit.SECONDS); + break; + + case RECONNECT_FORCE: + LOGGER.info("Reconnecting forcefully."); + this.reconnectAttempts = FAILURE_RECONNECT_ATTEMPTS; + + this.connectionState = EConnectionState.RECONNECT; + this.workerGroup.schedule(this::connect, 0, TimeUnit.SECONDS); + break; + } }); } /** Kills the current connection, triggering auto-reconnection immediately. */ - public void reconnect() { - state = State.RECONNECT_FORCE; - channel.disconnect(); + public void reconnect() + { + this.connectionState = EConnectionState.RECONNECT_FORCE; + this.channel.disconnect(); } @Override - public void close() { - if (closeReason != null) - LOGGER.error(closeReason); + public void close() + { + if (this.closeReason != null) + { + LOGGER.error(this.closeReason); + } - if (state == State.CLOSED) return; - state = State.CLOSED; - workerGroup.shutdownGracefully().syncUninterruptibly(); - channel.close().syncUninterruptibly(); + if (this.connectionState == EConnectionState.CLOSED) + { + return; + } + + this.connectionState = EConnectionState.CLOSED; + this.workerGroup.shutdownGracefully().syncUninterruptibly(); + this.channel.close().syncUninterruptibly(); } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/NetworkEventSource.java b/core/src/main/java/com/seibel/distanthorizons/core/network/NetworkEventSource.java index e14bdc1da..f12967cb6 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/NetworkEventSource.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/NetworkEventSource.java @@ -1,44 +1,63 @@ package com.seibel.distanthorizons.core.network; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.network.messages.AckMessage; import com.seibel.distanthorizons.core.network.messages.HelloMessage; import com.seibel.distanthorizons.core.network.protocol.INetworkMessage; import com.seibel.distanthorizons.core.network.protocol.MessageHandler; import com.seibel.distanthorizons.coreapi.ModInfo; import io.netty.channel.ChannelHandlerContext; +import org.apache.logging.log4j.Logger; import java.util.function.BiConsumer; import java.util.function.Consumer; -public abstract class NetworkEventSource implements AutoCloseable { - protected final MessageHandler messageHandler = new MessageHandler(); - protected String closeReason = null; - - public NetworkEventSource() { - registerHandler(HelloMessage.class, (msg, ctx) -> { - if (msg.version != ModInfo.PROTOCOL_VERSION) { - try { - close("Protocol version mismatch"); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - }); - } - - public void registerHandler(Class clazz, BiConsumer handler) { - messageHandler.registerHandler(clazz, handler); - } - - public void registerAckHandler(Class clazz, Consumer handler) { - messageHandler.registerHandler(AckMessage.class, (msg, ctx) -> { - if (msg.messageType == clazz) - handler.accept(ctx); - }); - } - - public void close(String reason) throws Exception { - closeReason = reason; - close(); - } +public abstract class NetworkEventSource implements AutoCloseable +{ + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); + + protected final MessageHandler messageHandler = new MessageHandler(); + protected String closeReason = null; + + + + public NetworkEventSource() + { + this.registerHandler(HelloMessage.class, (helloMessage, channelContext) -> + { + if (helloMessage.version != ModInfo.PROTOCOL_VERSION) + { + try + { + String closeReason = "Ignoring message from channel ["+channelContext.name()+"], due to version mismatch. Expected version: ["+ModInfo.PROTOCOL_VERSION+"], received version: ["+helloMessage.version+"]."; + LOGGER.info(closeReason); + this.close(closeReason); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + }); + } + + public void registerHandler(Class clazz, BiConsumer handler) { this.messageHandler.registerHandler(clazz, handler); } + + public void registerAckHandler(Class clazz, Consumer handler) + { + this.messageHandler.registerHandler(AckMessage.class, (ackMessage, channelContext) -> + { + if (ackMessage.messageType == clazz) + { + handler.accept(channelContext); + } + }); + } + + public void close(String reason) throws Exception + { + this.closeReason = reason; + this.close(); + } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/NetworkServer.java b/core/src/main/java/com/seibel/distanthorizons/core/network/NetworkServer.java index 3d3c70a4d..b66e79879 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/NetworkServer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/NetworkServer.java @@ -1,10 +1,10 @@ package com.seibel.distanthorizons.core.network; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; -import com.seibel.distanthorizons.core.network.messages.CloseMessage; import com.seibel.distanthorizons.core.network.messages.CloseReasonMessage; +import com.seibel.distanthorizons.core.network.messages.CloseMessage; import com.seibel.distanthorizons.core.network.messages.HelloMessage; -import com.seibel.distanthorizons.core.network.protocol.DhNetworkChannelInitializer; +import com.seibel.distanthorizons.core.network.protocol.NetworkChannelInitializer; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; @@ -13,72 +13,91 @@ import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import org.apache.logging.log4j.Logger; -public class NetworkServer extends NetworkEventSource implements AutoCloseable { - private static final Logger LOGGER = DhLoggerBuilder.getLogger(); - - // TODO move to config of some sort - private final int port; - - private final EventLoopGroup bossGroup = new NioEventLoopGroup(1); - private final EventLoopGroup workerGroup = new NioEventLoopGroup(); - private Channel channel; - private boolean isClosed = false; - - public NetworkServer(int port) { - this.port = port; - - LOGGER.info("Starting server on port {}", port); - registerHandlers(); - bind(); - } - - private void registerHandlers() { - registerHandler(HelloMessage.class, (msg, ctx) -> { - LOGGER.info("Client connected: {}", ctx.channel().remoteAddress()); - ctx.channel().writeAndFlush(new HelloMessage()); - }); - - registerHandler(CloseMessage.class, (msg, ctx) -> { - LOGGER.info("Client disconnected: {}", ctx.channel().remoteAddress()); - }); - } - - private void bind() { - ServerBootstrap bootstrap = new ServerBootstrap() - .group(bossGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .handler(new LoggingHandler(LogLevel.DEBUG)) - .childHandler(new DhNetworkChannelInitializer(messageHandler)); - - ChannelFuture bindFuture = bootstrap.bind(port); - bindFuture.addListener((ChannelFuture channelFuture) -> { - if (!channelFuture.isSuccess()) - throw new RuntimeException("Failed to bind: " + channelFuture.cause()); - - LOGGER.info("Server is started on port {}", port); - }); - - channel = bindFuture.channel(); - channel.closeFuture().addListener(future -> close()); - } - - public void disconnectClient(ChannelHandlerContext ctx, String reason) { - ctx.channel().config().setAutoRead(false); - ctx.writeAndFlush(new CloseReasonMessage(reason)) - .addListener(ChannelFutureListener.CLOSE); - } - - @Override - public void close() { - if (closeReason != null) - LOGGER.error(closeReason); - - if (isClosed) return; - isClosed = true; - - LOGGER.info("Shutting down the server."); - workerGroup.shutdownGracefully().syncUninterruptibly(); - bossGroup.shutdownGracefully().syncUninterruptibly(); - LOGGER.info("Server is closed."); - } +public class NetworkServer extends NetworkEventSource implements AutoCloseable +{ + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); + + // TODO move to the config + private final int port; + + private final EventLoopGroup bossGroup = new NioEventLoopGroup(1); + private final EventLoopGroup workerGroup = new NioEventLoopGroup(); + private Channel channel; + private boolean isClosed = false; + + + + public NetworkServer(int port) + { + this.port = port; + + LOGGER.info("Starting server on port "+port); + this.registerHandlers(); + this.bind(); + } + + private void registerHandlers() + { + this.registerHandler(HelloMessage.class, (helloMessage, channelContext) -> + { + LOGGER.info("Client connected: "+channelContext.channel().remoteAddress()); + channelContext.channel().writeAndFlush(new HelloMessage()); + }); + + this.registerHandler(CloseMessage.class, (closeMessage, channelContext) -> + { + LOGGER.info("Client disconnected: "+channelContext.channel().remoteAddress()); + }); + } + + private void bind() + { + ServerBootstrap bootstrap = new ServerBootstrap() + .group(this.bossGroup, this.workerGroup) + .channel(NioServerSocketChannel.class) + .handler(new LoggingHandler(LogLevel.DEBUG)) + .childHandler(new NetworkChannelInitializer(this.messageHandler)); + + ChannelFuture bindFuture = bootstrap.bind(this.port); + bindFuture.addListener((ChannelFuture channelFuture) -> + { + if (!channelFuture.isSuccess()) + { + throw new RuntimeException("Failed to bind: " + channelFuture.cause()); + } + + LOGGER.info("Server is started on port "+this.port); + }); + + this.channel = bindFuture.channel(); + this.channel.closeFuture().addListener(future -> this.close()); + } + + public void disconnectClient(ChannelHandlerContext ctx, String reason) + { + ctx.channel().config().setAutoRead(false); + ctx.writeAndFlush(new CloseReasonMessage(reason)) + .addListener(ChannelFutureListener.CLOSE); + } + + @Override + public void close() + { + if (this.closeReason != null) + { + LOGGER.error(this.closeReason); + } + + if (this.isClosed) + { + return; + } + this.isClosed = true; + + LOGGER.info("Shutting down the network server."); + this.workerGroup.shutdownGracefully().syncUninterruptibly(); + this.bossGroup.shutdownGracefully().syncUninterruptibly(); + LOGGER.info("Network server has been closed."); + } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/AckMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/AckMessage.java index 7c9ed2154..a846352c7 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/AckMessage.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/AckMessage.java @@ -8,21 +8,19 @@ import io.netty.buffer.ByteBuf; * Simple empty response message. * This message is not sent automatically. */ -public class AckMessage implements INetworkMessage { +public class AckMessage implements INetworkMessage +{ public Class messageType; - + + + public AckMessage() { } - public AckMessage(Class messageType) { - this.messageType = messageType; - } - + public AckMessage(Class messageType) { this.messageType = messageType; } + @Override - public void encode(ByteBuf out) { - out.writeInt(MessageRegistry.INSTANCE.getMessageId(messageType)); - } - + public void encode(ByteBuf out) { out.writeInt(MessageRegistry.INSTANCE.getMessageId(this.messageType)); } + @Override - public void decode(ByteBuf in) { - messageType = MessageRegistry.INSTANCE.getClassById(in.readInt()); - } + public void decode(ByteBuf in) { this.messageType = MessageRegistry.INSTANCE.getMessageClassById(in.readInt()); } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/CloseMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/CloseMessage.java index 8d81cae2a..f42aa3515 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/CloseMessage.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/CloseMessage.java @@ -4,18 +4,16 @@ import com.seibel.distanthorizons.core.network.protocol.INetworkMessage; import io.netty.buffer.ByteBuf; /** - * This is not a "real" message, and only used as indication of disconnection. + * This is not a "real" message, and only used to indicate a disconnection. * To send a "disconnect reason" message, use {@link CloseReasonMessage}. */ -public class CloseMessage implements INetworkMessage { +public class CloseMessage implements INetworkMessage +{ @Override - public void encode(ByteBuf out) { - throw new UnsupportedOperationException("CloseMessage is not a real message, and must not be sent."); - } + public void encode(ByteBuf out) { throw new UnsupportedOperationException("CloseMessage is not a real message, and must not be sent."); } @Override - public void decode(ByteBuf in) { - throw new UnsupportedOperationException("CloseMessage is not a real message, and must not be received."); - } + public void decode(ByteBuf in) { throw new UnsupportedOperationException("CloseMessage is not a real message, and must not be received."); } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/CloseReasonMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/CloseReasonMessage.java index 8dcfeb8b9..0671eb3c9 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/CloseReasonMessage.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/CloseReasonMessage.java @@ -4,21 +4,19 @@ import com.seibel.distanthorizons.core.network.protocol.INetworkMessage; import com.seibel.distanthorizons.core.network.protocol.INetworkObject; import io.netty.buffer.ByteBuf; -public class CloseReasonMessage implements INetworkMessage { - public String reason; - - public CloseReasonMessage() { } - public CloseReasonMessage(String reason) { - this.reason = reason; - } - - @Override - public void encode(ByteBuf out) { - INetworkObject.encodeString(reason, out); - } - - @Override - public void decode(ByteBuf in) { - reason = INetworkObject.decodeString(in); - } +public class CloseReasonMessage implements INetworkMessage +{ + public String reason; + + + + public CloseReasonMessage() { } + public CloseReasonMessage(String reason) { this.reason = reason; } + + @Override + public void encode(ByteBuf out) { INetworkObject.encodeString(this.reason, out); } + + @Override + public void decode(ByteBuf in) { this.reason = INetworkObject.decodeString(in); } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/HelloMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/HelloMessage.java index df4092176..155f97dec 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/HelloMessage.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/HelloMessage.java @@ -4,16 +4,16 @@ import com.seibel.distanthorizons.core.network.protocol.INetworkMessage; import com.seibel.distanthorizons.coreapi.ModInfo; import io.netty.buffer.ByteBuf; -public class HelloMessage implements INetworkMessage { +public class HelloMessage implements INetworkMessage +{ public int version = ModInfo.PROTOCOL_VERSION; - + + + @Override - public void encode(ByteBuf out) { - out.writeInt(version); - } - + public void encode(ByteBuf out) { out.writeInt(this.version); } + @Override - public void decode(ByteBuf in) { - version = in.readInt(); - } + public void decode(ByteBuf in) { this.version = in.readInt(); } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/LodConfigMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/LodConfigMessage.java deleted file mode 100644 index 43eb092dc..000000000 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/LodConfigMessage.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.seibel.distanthorizons.core.network.messages; - -import com.seibel.distanthorizons.core.network.protocol.INetworkObject; -import com.seibel.distanthorizons.core.network.protocol.INetworkMessage; -import com.seibel.distanthorizons.core.world.DhRemotePlayer; -import io.netty.buffer.ByteBuf; - -public class LodConfigMessage implements INetworkMessage { - public DhRemotePlayer.Config config; - - public LodConfigMessage() { } - public LodConfigMessage(DhRemotePlayer.Config config) { - this.config = config; - } - - @Override - public void encode(ByteBuf out) { - config.encode(out); - } - - @Override - public void decode(ByteBuf in) { - config = INetworkObject.decode(new DhRemotePlayer.Config(), in); - } -} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/PlayerUUIDMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/PlayerUUIDMessage.java index 64ed53c83..09f15fd2c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/PlayerUUIDMessage.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/PlayerUUIDMessage.java @@ -5,22 +5,23 @@ import io.netty.buffer.ByteBuf; import java.util.UUID; -public class PlayerUUIDMessage implements INetworkMessage { +public class PlayerUUIDMessage implements INetworkMessage +{ public UUID playerUUID; - + + + public PlayerUUIDMessage() { } - public PlayerUUIDMessage(UUID playerUUID) { - this.playerUUID = playerUUID; + public PlayerUUIDMessage(UUID playerUUID) { this.playerUUID = playerUUID; } + + @Override + public void encode(ByteBuf out) + { + out.writeLong(this.playerUUID.getMostSignificantBits()); + out.writeLong(this.playerUUID.getLeastSignificantBits()); } @Override - public void encode(ByteBuf out) { - out.writeLong(playerUUID.getMostSignificantBits()); - out.writeLong(playerUUID.getLeastSignificantBits()); - } - - @Override - public void decode(ByteBuf in) { - playerUUID = new UUID(in.readLong(), in.readLong()); - } + public void decode(ByteBuf in) { this.playerUUID = new UUID(in.readLong(), in.readLong()); } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/RemotePlayerConfigMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/RemotePlayerConfigMessage.java new file mode 100644 index 000000000..8f0910801 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/RemotePlayerConfigMessage.java @@ -0,0 +1,23 @@ +package com.seibel.distanthorizons.core.network.messages; + +import com.seibel.distanthorizons.core.network.protocol.INetworkObject; +import com.seibel.distanthorizons.core.network.protocol.INetworkMessage; +import com.seibel.distanthorizons.core.network.objects.RemotePlayer; +import io.netty.buffer.ByteBuf; + +public class RemotePlayerConfigMessage implements INetworkMessage +{ + public RemotePlayer.Payload payload; + + + + public RemotePlayerConfigMessage() { } + public RemotePlayerConfigMessage(RemotePlayer.Payload payload) { this.payload = payload; } + + @Override + public void encode(ByteBuf out) { this.payload.encode(out); } + + @Override + public void decode(ByteBuf in) { this.payload = INetworkObject.decode(new RemotePlayer.Payload(), in); } + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/RequestChunksMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/RequestChunksMessage.java index 1fbd7f01a..15312601e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/RequestChunksMessage.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/RequestChunksMessage.java @@ -3,15 +3,19 @@ package com.seibel.distanthorizons.core.network.messages; import com.seibel.distanthorizons.core.network.protocol.INetworkMessage; import io.netty.buffer.ByteBuf; -public class RequestChunksMessage implements INetworkMessage { +public class RequestChunksMessage implements INetworkMessage +{ @Override - public void encode(ByteBuf out) { + public void encode(ByteBuf out) + { } @Override - public void decode(ByteBuf in) { + public void decode(ByteBuf in) + { } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/objects/RemotePlayer.java b/core/src/main/java/com/seibel/distanthorizons/core/network/objects/RemotePlayer.java new file mode 100644 index 000000000..30f65397d --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/objects/RemotePlayer.java @@ -0,0 +1,34 @@ +package com.seibel.distanthorizons.core.network.objects; + +import com.seibel.distanthorizons.core.network.protocol.INetworkObject; +import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; + +public class RemotePlayer +{ + public IServerPlayerWrapper serverPlayer; + public Payload payload; + public ChannelHandlerContext channelContext; + + + + public RemotePlayer(IServerPlayerWrapper serverPlayer) { this.serverPlayer = serverPlayer; } + + public static class Payload implements INetworkObject + { + // TODO Replace this example with useful fields, + // this should include any information the server needs to know about the connected client + public int renderDistance; + + + + @Override + public void encode(ByteBuf out) { out.writeInt(this.renderDistance); } + + @Override + public void decode(ByteBuf in) { this.renderDistance = in.readInt(); } + + } + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageHandlerSide.java b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/EMessageHandlerSide.java similarity index 53% rename from core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageHandlerSide.java rename to core/src/main/java/com/seibel/distanthorizons/core/network/protocol/EMessageHandlerSide.java index 3e44e1642..6b8f6d760 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageHandlerSide.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/EMessageHandlerSide.java @@ -1,6 +1,11 @@ package com.seibel.distanthorizons.core.network.protocol; -public enum MessageHandlerSide { +/** + * CLIENT,
+ * SERVER,
+ */ +public enum EMessageHandlerSide +{ CLIENT, SERVER } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/INetworkMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/INetworkMessage.java index c24b290df..270baef88 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/INetworkMessage.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/INetworkMessage.java @@ -1,6 +1,8 @@ package com.seibel.distanthorizons.core.network.protocol; -public interface INetworkMessage extends INetworkObject { - // For now only used for constraining listeners +/** For now this is only used for constraining listeners */ +public interface INetworkMessage extends INetworkObject +{ + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/INetworkObject.java b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/INetworkObject.java index 46f7ae01e..087e05b75 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/INetworkObject.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/INetworkObject.java @@ -4,23 +4,28 @@ import io.netty.buffer.ByteBuf; import java.nio.charset.StandardCharsets; -public interface INetworkObject { - void encode(ByteBuf out); - - void decode(ByteBuf in); - - static T decode(T o, ByteBuf in) { - o.decode(in); - return o; - } - - static void encodeString(String str, ByteBuf out) { - out.writeShort(str.length()); - out.writeBytes(str.getBytes(StandardCharsets.UTF_8)); - } - - static String decodeString(ByteBuf in) { - int length = in.readShort(); - return in.readBytes(length).toString(StandardCharsets.UTF_8); - } +public interface INetworkObject +{ + void encode(ByteBuf out); + + void decode(ByteBuf in); + + static T decode(T obj, ByteBuf inputByteBuf) + { + obj.decode(inputByteBuf); + return obj; + } + + static void encodeString(String inputString, ByteBuf outputByteBuf) + { + outputByteBuf.writeShort(inputString.length()); + outputByteBuf.writeBytes(inputString.getBytes(StandardCharsets.UTF_8)); + } + + static String decodeString(ByteBuf inputByteBuf) + { + int length = inputByteBuf.readShort(); + return inputByteBuf.readBytes(length).toString(StandardCharsets.UTF_8); + } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageDecoder.java b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageDecoder.java index e03afe8cb..19eb98722 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageDecoder.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageDecoder.java @@ -1,17 +1,18 @@ package com.seibel.distanthorizons.core.network.protocol; -import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; -import org.apache.logging.log4j.Logger; import java.util.List; -public class MessageDecoder extends ByteToMessageDecoder { +public class MessageDecoder extends ByteToMessageDecoder +{ @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) { - INetworkMessage message = MessageRegistry.INSTANCE.createMessage(in.readShort()); - out.add(INetworkObject.decode(message, in)); + protected void decode(ChannelHandlerContext channelContext, ByteBuf inputByteBuf, List outputDecodedObjectList) + { + INetworkMessage message = MessageRegistry.INSTANCE.createMessage(inputByteBuf.readShort()); + outputDecodedObjectList.add(INetworkObject.decode(message, inputByteBuf)); } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageEncoder.java b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageEncoder.java index 7e266eef6..ddb7ed5f3 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageEncoder.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageEncoder.java @@ -1,15 +1,16 @@ package com.seibel.distanthorizons.core.network.protocol; -import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; -import org.apache.logging.log4j.Logger; -public class MessageEncoder extends MessageToByteEncoder { - @Override - protected void encode(ChannelHandlerContext ctx, INetworkMessage msg, ByteBuf out) throws IllegalArgumentException { - out.writeShort(MessageRegistry.INSTANCE.getMessageId(msg)); - msg.encode(out); - } +public class MessageEncoder extends MessageToByteEncoder +{ + @Override + protected void encode(ChannelHandlerContext channelContext, INetworkMessage message, ByteBuf outputByteBuf) throws IllegalArgumentException + { + outputByteBuf.writeShort(MessageRegistry.INSTANCE.getMessageId(message)); + message.encode(outputByteBuf); + } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageHandler.java index 0ca377314..9fc9626d2 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageHandler.java @@ -15,32 +15,39 @@ import java.util.Map; import java.util.function.BiConsumer; @ChannelHandler.Sharable -public class MessageHandler extends SimpleChannelInboundHandler { - private static final Logger LOGGER = DhLoggerBuilder.getLogger(); - - private final Map, List>> handlers = new HashMap<>(); - - public void registerHandler(Class clazz, BiConsumer handler) { - handlers.computeIfAbsent(clazz, k -> new LinkedList<>()) - .add((BiConsumer) handler); - } - - @Override - protected void channelRead0(ChannelHandlerContext ctx, INetworkMessage msg) { - LOGGER.trace("Received message: {}", msg.getClass().getSimpleName()); - - List> handlerList = handlers.get(msg.getClass()); - if (handlerList == null) { - LOGGER.warn("Unhandled message type: {}", msg.getClass().getSimpleName()); - return; - } - - for (BiConsumer handler : handlerList) - handler.accept(msg, ctx); - } - - @Override - public void channelInactive(@NotNull ChannelHandlerContext ctx) { - channelRead0(ctx, new CloseMessage()); - } +public class MessageHandler extends SimpleChannelInboundHandler +{ + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); + + private final Map, List>> handlers = new HashMap<>(); + + + + public void registerHandler(Class handlerClass, BiConsumer handlerImplementation) + { + this.handlers.computeIfAbsent(handlerClass, missingHandlerClass -> new LinkedList<>()) + .add((BiConsumer) handlerImplementation); + } + + @Override + protected void channelRead0(ChannelHandlerContext channelContext, INetworkMessage message) + { + LOGGER.trace("Received message: "+message.getClass().getSimpleName()); + + List> handlerList = this.handlers.get(message.getClass()); + if (handlerList == null) + { + LOGGER.warn("Unhandled message type: "+message.getClass().getSimpleName()); + return; + } + + for (BiConsumer handler : handlerList) + { + handler.accept(message, channelContext); + } + } + + @Override + public void channelInactive(@NotNull ChannelHandlerContext channelContext) { this.channelRead0(channelContext, new CloseMessage()); } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageRegistry.java b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageRegistry.java index f1ba66cef..ea952c4ad 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageRegistry.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/MessageRegistry.java @@ -8,49 +8,55 @@ import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; -public class MessageRegistry { - public static final MessageRegistry INSTANCE = new MessageRegistry() {{ - // Note: Messages must have parameterless constructors - - // Keep messages below intact so client/server can disconnect if version does not match - registerMessage(HelloMessage.class, HelloMessage::new); - registerMessage(CloseReasonMessage.class, CloseReasonMessage::new); - - // Define your messages after this line - registerMessage(AckMessage.class, AckMessage::new); - registerMessage(PlayerUUIDMessage.class, PlayerUUIDMessage::new); - registerMessage(LodConfigMessage.class, LodConfigMessage::new); - registerMessage(RequestChunksMessage.class, RequestChunksMessage::new); - }}; - +public class MessageRegistry +{ + public static final MessageRegistry INSTANCE = new MessageRegistry(); + private final Map> idToSupplier = new HashMap<>(); private final BiMap, Integer> classToId = HashBiMap.create(); - - private MessageRegistry() { } - - public void registerMessage(Class clazz, Supplier supplier) { - int id = idToSupplier.size() + 1; - idToSupplier.put(id, supplier); - classToId.put(clazz, id); - } - - public Class getClassById(int id) { - return classToId.inverse().get(id); - } - - public INetworkMessage createMessage(int id) throws IllegalArgumentException { - try { - return idToSupplier.get(id).get(); - } catch (NullPointerException e) { - throw new IllegalArgumentException("Invalid message ID"); - } - } - - public int getMessageId(INetworkMessage message) { - return getMessageId(message.getClass()); - } - - public int getMessageId(Class clazz) { - return classToId.get(clazz); + + + + private MessageRegistry() + { + // Note: Messages must have parameterless constructors + + // Keep messages below intact so client/server can disconnect if version does not match + this.registerMessage(HelloMessage.class, HelloMessage::new); + this.registerMessage(CloseReasonMessage.class, CloseReasonMessage::new); + + // Define your messages after this line + this.registerMessage(AckMessage.class, AckMessage::new); + this.registerMessage(PlayerUUIDMessage.class, PlayerUUIDMessage::new); + this.registerMessage(RemotePlayerConfigMessage.class, RemotePlayerConfigMessage::new); + this.registerMessage(RequestChunksMessage.class, RequestChunksMessage::new); + } + + + + public void registerMessage(Class clazz, Supplier supplier) + { + int id = this.idToSupplier.size() + 1; + this.idToSupplier.put(id, supplier); + this.classToId.put(clazz, id); } + + public Class getMessageClassById(int messageId) { return this.classToId.inverse().get(messageId); } + + public INetworkMessage createMessage(int messageId) throws IllegalArgumentException + { + try + { + return this.idToSupplier.get(messageId).get(); + } + catch (NullPointerException e) + { + throw new IllegalArgumentException("Invalid message ID"); + } + } + + public int getMessageId(INetworkMessage message) { return this.getMessageId(message.getClass()); } + + public int getMessageId(Class messageClass) { return this.classToId.get(messageClass); } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/DhNetworkChannelInitializer.java b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/NetworkChannelInitializer.java similarity index 54% rename from core/src/main/java/com/seibel/distanthorizons/core/network/protocol/DhNetworkChannelInitializer.java rename to core/src/main/java/com/seibel/distanthorizons/core/network/protocol/NetworkChannelInitializer.java index c0283fef5..f021396b6 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/DhNetworkChannelInitializer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/NetworkChannelInitializer.java @@ -1,35 +1,37 @@ package com.seibel.distanthorizons.core.network.protocol; -import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import io.netty.channel.*; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LengthFieldPrepender; -import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; -public class DhNetworkChannelInitializer extends ChannelInitializer { +/** used when creating a network channel */ +public class NetworkChannelInitializer extends ChannelInitializer +{ private final MessageHandler messageHandler; - - public DhNetworkChannelInitializer(MessageHandler messageHandler) { - this.messageHandler = messageHandler; - } - + + + + public NetworkChannelInitializer(MessageHandler messageHandler) { this.messageHandler = messageHandler; } + @Override - public void initChannel(@NotNull SocketChannel ch) { - ChannelPipeline pipeline = ch.pipeline(); - + public void initChannel(@NotNull SocketChannel socketChannel) + { + ChannelPipeline pipeline = socketChannel.pipeline(); + // Encoder pipeline.addLast(new LengthFieldPrepender(Short.BYTES)); pipeline.addLast(new MessageEncoder()); - pipeline.addLast(new OutboundExceptionRouter()); - + pipeline.addLast(new NetworkOutboundExceptionRouter()); + // Decoder pipeline.addLast(new LengthFieldBasedFrameDecoder(Short.MAX_VALUE, 0, Short.BYTES, 0, Short.BYTES)); pipeline.addLast(new MessageDecoder()); - + // Handler - pipeline.addLast(messageHandler); - pipeline.addLast(new ExceptionHandler()); + pipeline.addLast(this.messageHandler); + pipeline.addLast(new NetworkExceptionHandler()); } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/ExceptionHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/NetworkExceptionHandler.java similarity index 55% rename from core/src/main/java/com/seibel/distanthorizons/core/network/protocol/ExceptionHandler.java rename to core/src/main/java/com/seibel/distanthorizons/core/network/protocol/NetworkExceptionHandler.java index d722119b4..365e0e434 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/ExceptionHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/NetworkExceptionHandler.java @@ -5,12 +5,15 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import org.apache.logging.log4j.Logger; -public class ExceptionHandler extends ChannelInboundHandlerAdapter { +public class NetworkExceptionHandler extends ChannelInboundHandlerAdapter +{ private static final Logger LOGGER = DhLoggerBuilder.getLogger(); - + @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - LOGGER.error("Exception caught on channel", cause); - ctx.close(); - } + public void exceptionCaught(ChannelHandlerContext channelContext, Throwable cause) + { + LOGGER.error("Exception caught in channel: ["+channelContext.name()+"].", cause); + channelContext.close(); + } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/NetworkOutboundExceptionRouter.java b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/NetworkOutboundExceptionRouter.java new file mode 100644 index 000000000..dee8614e8 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/NetworkOutboundExceptionRouter.java @@ -0,0 +1,17 @@ +package com.seibel.distanthorizons.core.network.protocol; + +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOutboundHandlerAdapter; +import io.netty.channel.ChannelPromise; + +public class NetworkOutboundExceptionRouter extends ChannelOutboundHandlerAdapter +{ + @Override + public void write(ChannelHandlerContext channelContext, Object messageObj, ChannelPromise promise) throws Exception + { + promise.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); + super.write(channelContext, messageObj, promise); + } + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/OutboundExceptionRouter.java b/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/OutboundExceptionRouter.java deleted file mode 100644 index e222aeb10..000000000 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/protocol/OutboundExceptionRouter.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.seibel.distanthorizons.core.network.protocol; - -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelOutboundHandlerAdapter; -import io.netty.channel.ChannelPromise; - -public class OutboundExceptionRouter extends ChannelOutboundHandlerAdapter { - @Override - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { - promise.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); - super.write(ctx, msg, promise); - } -} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/world/DhClientWorld.java b/core/src/main/java/com/seibel/distanthorizons/core/world/DhClientWorld.java index 56efb821d..8e29caec1 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/world/DhClientWorld.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/world/DhClientWorld.java @@ -5,10 +5,10 @@ import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure; import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.level.DhClientLevel; import com.seibel.distanthorizons.core.network.NetworkClient; -import com.seibel.distanthorizons.core.network.messages.HelloMessage; -import com.seibel.distanthorizons.core.network.messages.LodConfigMessage; +import com.seibel.distanthorizons.core.network.messages.*; import com.seibel.distanthorizons.core.network.messages.PlayerUUIDMessage; -import com.seibel.distanthorizons.core.network.messages.RequestChunksMessage; +import com.seibel.distanthorizons.core.network.messages.RemotePlayerConfigMessage; +import com.seibel.distanthorizons.core.network.objects.RemotePlayer; import com.seibel.distanthorizons.core.util.ThreadUtil; import com.seibel.distanthorizons.core.util.objects.EventLoop; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; @@ -54,15 +54,15 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld ctx.writeAndFlush(new PlayerUUIDMessage(MC_CLIENT.getPlayerUUID())); }); - // TODO Proper config handling + // TODO Proper payload handling networkClient.registerAckHandler(PlayerUUIDMessage.class, ctx -> { - ctx.writeAndFlush(new LodConfigMessage(new DhRemotePlayer.Config())); + ctx.writeAndFlush(new RemotePlayerConfigMessage(new RemotePlayer.Payload())); }); - networkClient.registerHandler(LodConfigMessage.class, (msg, ctx) -> { + networkClient.registerHandler(RemotePlayerConfigMessage.class, (msg, ctx) -> { }); - networkClient.registerAckHandler(LodConfigMessage.class, ctx -> { + networkClient.registerAckHandler(RemotePlayerConfigMessage.class, ctx -> { // TODO Actually request chunks ctx.writeAndFlush(new RequestChunksMessage()); }); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/world/DhRemotePlayer.java b/core/src/main/java/com/seibel/distanthorizons/core/world/DhRemotePlayer.java deleted file mode 100644 index ec74b8aed..000000000 --- a/core/src/main/java/com/seibel/distanthorizons/core/world/DhRemotePlayer.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.seibel.distanthorizons.core.world; - -import com.seibel.distanthorizons.core.network.protocol.INetworkObject; -import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; - -public class DhRemotePlayer { - public IServerPlayerWrapper serverPlayer; - public Config config; - public ChannelHandlerContext ctx; - - public DhRemotePlayer(IServerPlayerWrapper serverPlayer) { - this.serverPlayer = serverPlayer; - } - - public static class Config implements INetworkObject { - // TODO Replace this example with actually useful fields - public int renderDistance; - - @Override - public void encode(ByteBuf out) { - out.writeInt(renderDistance); - } - - @Override - public void decode(ByteBuf in) { - renderDistance = in.readInt(); - } - } -} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/world/DhServerWorld.java b/core/src/main/java/com/seibel/distanthorizons/core/world/DhServerWorld.java index e76a53c1b..dbbea1b33 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/world/DhServerWorld.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/world/DhServerWorld.java @@ -8,6 +8,7 @@ import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.network.NetworkServer; import com.seibel.distanthorizons.core.network.messages.*; import com.seibel.distanthorizons.core.network.messages.RequestChunksMessage; +import com.seibel.distanthorizons.core.network.objects.RemotePlayer; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; @@ -23,11 +24,12 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld { private final HashMap levels; public final LocalSaveStructure saveStructure; - + private final NetworkServer networkServer; - private final HashMap playersByUUID; - private final BiMap playersByConnection; - + private final HashMap playersByUUID; + private final BiMap playersByConnection; + + public DhServerWorld() { @@ -35,63 +37,75 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld this.saveStructure = new LocalSaveStructure(); this.levels = new HashMap<>(); - - // TODO move to global config once server specific configs are implemented + + // TODO move to global payload once server specific configs are implemented this.networkServer = new NetworkServer(25049); this.playersByUUID = new HashMap<>(); this.playersByConnection = HashBiMap.create(); - registerNetworkHandlers(); + this.registerNetworkHandlers(); LOGGER.info("Started "+DhServerWorld.class.getSimpleName()+" of type "+this.environment); } - private void registerNetworkHandlers() { - networkServer.registerHandler(CloseMessage.class, (msg, ctx) -> { - DhRemotePlayer dhPlayer = playersByConnection.remove(ctx); + private void registerNetworkHandlers() + { + this.networkServer.registerHandler(CloseMessage.class, (closeMessage, channelContext) -> + { + RemotePlayer dhPlayer = this.playersByConnection.remove(channelContext); if (dhPlayer != null) - dhPlayer.ctx = null; + { + dhPlayer.channelContext = null; + } }); - - networkServer.registerHandler(PlayerUUIDMessage.class, (msg, ctx) -> { - DhRemotePlayer dhPlayer = playersByUUID.get(msg.playerUUID); - - if (dhPlayer == null) { - networkServer.disconnectClient(ctx, "Player is not logged in."); + + this.networkServer.registerHandler(PlayerUUIDMessage.class, (playerUUIDMessage, channelContext) -> + { + RemotePlayer dhPlayer = this.playersByUUID.get(playerUUIDMessage.playerUUID); + + if (dhPlayer == null) + { + this.networkServer.disconnectClient(channelContext, "Player is not logged in."); return; } - - if (dhPlayer.ctx != null) { - networkServer.disconnectClient(ctx, "Another connection is already in use."); + + if (dhPlayer.channelContext != null) + { + this.networkServer.disconnectClient(channelContext, "Another connection is already in use."); return; } - - dhPlayer.ctx = ctx; - playersByConnection.put(ctx, dhPlayer); - - ctx.writeAndFlush(new AckMessage(PlayerUUIDMessage.class)); + + dhPlayer.channelContext = channelContext; + this.playersByConnection.put(channelContext, dhPlayer); + + channelContext.writeAndFlush(new AckMessage(PlayerUUIDMessage.class)); }); - - networkServer.registerHandler(LodConfigMessage.class, (msg, ctx) -> { - // TODO Take notice of received config and possibly echo back a constrained version - ctx.writeAndFlush(new AckMessage(LodConfigMessage.class)); + + this.networkServer.registerHandler(RemotePlayerConfigMessage.class, (dhRemotePlayerConfigMessage, channelContext) -> + { + // TODO Take notice of received payload and possibly echo back a constrained version + channelContext.writeAndFlush(new AckMessage(RemotePlayerConfigMessage.class)); }); - - networkServer.registerHandler(RequestChunksMessage.class, (msg, ctx) -> { + + this.networkServer.registerHandler(RequestChunksMessage.class, (msg, ctx) -> + { LOGGER.info("RequestChunksMessage"); // hasReceivedChunkRequest should be false somewhere ??? // to avoid sending updates until client says at least something about its state }); } - public void addPlayer(IServerPlayerWrapper serverPlayer) { - playersByUUID.put(serverPlayer.getUUID(), new DhRemotePlayer(serverPlayer)); + public void addPlayer(IServerPlayerWrapper serverPlayer) + { + this.playersByUUID.put(serverPlayer.getUUID(), new RemotePlayer(serverPlayer)); } - - public void removePlayer(IServerPlayerWrapper serverPlayer) { - DhRemotePlayer dhPlayer = playersByUUID.remove(serverPlayer.getUUID()); - ChannelHandlerContext ctx = playersByConnection.inverse().remove(dhPlayer); - if (ctx != null) - networkServer.disconnectClient(ctx, "You are being disconnected."); + public void removePlayer(IServerPlayerWrapper serverPlayer) + { + RemotePlayer dhPlayer = this.playersByUUID.remove(serverPlayer.getUUID()); + ChannelHandlerContext channelContext = this.playersByConnection.inverse().remove(dhPlayer); + if (channelContext != null) + { + this.networkServer.disconnectClient(channelContext, "You are being disconnected."); + } } @Override @@ -102,11 +116,11 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld return null; } - return this.levels.computeIfAbsent((IServerLevelWrapper) wrapper, (w) -> + return this.levels.computeIfAbsent((IServerLevelWrapper) wrapper, (serverLevelWrapper) -> { File levelFile = this.saveStructure.getLevelFolder(wrapper); LodUtil.assertTrue(levelFile != null); - return new DhServerLevel(this.saveStructure, w); + return new DhServerLevel(this.saveStructure, serverLevelWrapper); }); } @@ -164,6 +178,4 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld LOGGER.info("Closed DhWorld of type "+this.environment); } - - } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/misc/IServerPlayerWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/misc/IServerPlayerWrapper.java index 7ac391ecd..329ca7c54 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/misc/IServerPlayerWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/misc/IServerPlayerWrapper.java @@ -4,6 +4,7 @@ import com.seibel.distanthorizons.api.interfaces.IDhApiUnsafeWrapper; import java.util.UUID; -public interface IServerPlayerWrapper extends IDhApiUnsafeWrapper { +public interface IServerPlayerWrapper extends IDhApiUnsafeWrapper +{ UUID getUUID(); }