diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/RemoteFullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/RemoteFullDataFileHandler.java index 656108692..1daaa6962 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/RemoteFullDataFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/RemoteFullDataFileHandler.java @@ -10,6 +10,7 @@ import com.seibel.distanthorizons.core.network.messages.ChunkRequestMessage; import com.seibel.distanthorizons.core.network.messages.ChunkResponseMessage; import com.seibel.distanthorizons.core.pos.DhSectionPos; +import java.nio.file.FileAlreadyExistsException; import java.util.concurrent.CompletableFuture; public class RemoteFullDataFileHandler extends FullDataFileHandler @@ -25,14 +26,11 @@ public class RemoteFullDataFileHandler extends FullDataFileHandler @Override public CompletableFuture read(DhSectionPos pos) { - // TODO read and force update somehow instead ???? + // TODO: LOD data file updating is probably incomplete return super.read(pos).thenCompose((fullDataSource) -> { - if (fullDataSource != null) { - return CompletableFuture.completedFuture(fullDataSource); - } - - CompletableFuture responseFuture = chunkRequestTracker.sendRequest(networkClient.getChannel(), new ChunkRequestMessage()); - + FullDataMetaFile metaFile = this.getLoadOrMakeFile(pos, true); + CompletableFuture responseFuture = chunkRequestTracker.sendRequest(networkClient.getChannel(), new ChunkRequestMessage(pos)); + return onDataFileUpdate(fullDataSource, metaFile, iFullDataSource -> {}, iFullDataSource -> true); }); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/ChunkRequestMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/ChunkRequestMessage.java index 0c9a4d7c5..72eb85870 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/ChunkRequestMessage.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/ChunkRequestMessage.java @@ -7,17 +7,23 @@ import io.netty.buffer.ByteBuf; public class ChunkRequestMessage implements IFutureTrackableNetworkMessage { public DhSectionPos dhSectionPos; - + + public ChunkRequestMessage() {} + + public ChunkRequestMessage(DhSectionPos dhSectionPos) { + this.dhSectionPos = dhSectionPos; + } + @Override public DhSectionPos getRequestKey() { return dhSectionPos; } - + @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/messages/ChunkResponseMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/ChunkResponseMessage.java index cc2fa1a0b..d2abba9b7 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/ChunkResponseMessage.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/ChunkResponseMessage.java @@ -7,12 +7,18 @@ import io.netty.buffer.ByteBuf; public class ChunkResponseMessage implements IFutureTrackableNetworkMessage { public DhSectionPos dhSectionPos; + + public ChunkResponseMessage() {} + + public ChunkResponseMessage(DhSectionPos dhSectionPos) { + this.dhSectionPos = dhSectionPos; + } @Override public DhSectionPos getRequestKey() { return dhSectionPos; } @Override public void encode(ByteBuf out) { - + } @Override public void decode(ByteBuf in) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java index 87d87b9bd..129d4deff 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java @@ -1,8 +1,10 @@ package com.seibel.distanthorizons.core.pos; import com.seibel.distanthorizons.core.enums.ELodDirection; +import com.seibel.distanthorizons.core.network.protocol.INetworkObject; import com.seibel.distanthorizons.coreapi.util.BitShiftUtil; import com.seibel.distanthorizons.core.util.LodUtil; +import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -19,7 +21,7 @@ import java.util.function.Consumer; * @author Leetom * @version 2022-11-6 */ -public class DhSectionPos implements Comparable +public class DhSectionPos implements Comparable, INetworkObject { /** * The lowest detail level a Section position can hold. @@ -32,12 +34,12 @@ public class DhSectionPos implements Comparable public final static byte SECTION_REGION_DETAIL_LEVEL = SECTION_MINIMUM_DETAIL_LEVEL + LodUtil.REGION_DETAIL_LEVEL; - public final byte sectionDetailLevel; + public byte sectionDetailLevel; /** in a sectionDetailLevel grid */ - public final int sectionX; + public int sectionX; /** in a sectionDetailLevel grid */ - public final int sectionZ; + public int sectionZ; @@ -258,4 +260,18 @@ public class DhSectionPos implements Comparable Integer.hashCode(this.sectionX) ^ // XOR Integer.hashCode(this.sectionZ); } + + @Override + public void encode(ByteBuf out) { + out.writeByte(this.sectionDetailLevel); + out.writeInt(this.sectionX); + out.writeInt(this.sectionZ); + } + + @Override + public void decode(ByteBuf in) { + this.sectionDetailLevel = in.readByte(); + this.sectionX = in.readInt(); + this.sectionZ = in.readInt(); + } } 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 e2fa70bdf..b36702b75 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 @@ -9,6 +9,8 @@ import com.seibel.distanthorizons.core.network.messages.*; import com.seibel.distanthorizons.core.network.messages.PlayerUUIDMessage; import com.seibel.distanthorizons.core.network.messages.RemotePlayerConfigMessage; import com.seibel.distanthorizons.core.network.objects.RemotePlayer; +import com.seibel.distanthorizons.core.pos.DhBlockPos2D; +import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.util.ThreadUtil; import com.seibel.distanthorizons.core.util.objects.EventLoop; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; @@ -64,7 +66,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld networkClient.registerAckHandler(RemotePlayerConfigMessage.class, ctx -> { // TODO Actually request chunks - ctx.writeAndFlush(new ChunkRequestMessage()); + ctx.writeAndFlush(new ChunkRequestMessage(new DhSectionPos(new DhBlockPos2D(0, 0)))); }); } 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 ab76ee2e3..fac91db65 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 @@ -2,6 +2,8 @@ package com.seibel.distanthorizons.core.world; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; +import com.seibel.distanthorizons.core.file.fullDatafile.FullDataMetaFile; +import com.seibel.distanthorizons.core.file.fullDatafile.IFullDataSourceProvider; import com.seibel.distanthorizons.core.file.structure.LocalSaveStructure; import com.seibel.distanthorizons.core.level.DhServerLevel; import com.seibel.distanthorizons.core.level.IDhLevel; @@ -9,6 +11,7 @@ import com.seibel.distanthorizons.core.network.NetworkServer; import com.seibel.distanthorizons.core.network.messages.*; import com.seibel.distanthorizons.core.network.messages.ChunkRequestMessage; import com.seibel.distanthorizons.core.network.objects.RemotePlayer; +import com.seibel.distanthorizons.core.pos.DhBlockPos2D; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; @@ -16,6 +19,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import io.netty.channel.ChannelHandlerContext; import java.io.File; +import java.nio.file.FileAlreadyExistsException; import java.util.HashMap; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -24,32 +28,32 @@ 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; - - - + + + public DhServerWorld() { super(EWorldEnvironment.Server_Only); - + this.saveStructure = new LocalSaveStructure(); this.levels = new HashMap<>(); - + // TODO move to global payload once server specific configs are implemented this.networkServer = new NetworkServer(25049); this.playersByUUID = new HashMap<>(); this.playersByConnection = HashBiMap.create(); this.registerNetworkHandlers(); - + LOGGER.info("Started "+DhServerWorld.class.getSimpleName()+" of type "+this.environment); } private void registerNetworkHandlers() { - this.networkServer.registerHandler(CloseMessage.class, (closeMessage, channelContext) -> + this.networkServer.registerHandler(CloseMessage.class, (closeMessage, channelContext) -> { RemotePlayer dhPlayer = this.playersByConnection.remove(channelContext); if (dhPlayer != null) @@ -57,43 +61,57 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld dhPlayer.channelContext = null; } }); - - this.networkServer.registerHandler(PlayerUUIDMessage.class, (playerUUIDMessage, channelContext) -> + + 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.channelContext != null) { this.networkServer.disconnectClient(channelContext, "Another connection is already in use."); return; } - + dhPlayer.channelContext = channelContext; this.playersByConnection.put(channelContext, dhPlayer); - + channelContext.writeAndFlush(new AckMessage(PlayerUUIDMessage.class)); }); - - this.networkServer.registerHandler(RemotePlayerConfigMessage.class, (dhRemotePlayerConfigMessage, channelContext) -> + + 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)); }); - + this.networkServer.registerHandler(ChunkRequestMessage.class, (msg, ctx) -> { - LOGGER.info("RequestChunksMessage"); + if (msg.dhSectionPos == null) { + LOGGER.warn("RequestChunksMessage received with null msg.dhSectionPos"); + return; + } + + LOGGER.info("RequestChunksMessage received at pos ({}, {}) with detail level {}", msg.dhSectionPos.sectionX, msg.dhSectionPos.sectionZ, msg.dhSectionPos.sectionDetailLevel); // hasReceivedChunkRequest should be false somewhere ??? // to avoid sending updates until client says at least something about its state + + // TODO: Get level from the player that sent the packet + DhServerLevel level = this.getLevel(playersByConnection.get(ctx).serverPlayer.getLevel()); + + // TODO: Add level to packet + level.serverside.worldGenTick(new DhBlockPos2D(msg.dhSectionPos.sectionX, msg.dhSectionPos.sectionZ)); + + // Send chunk response message back + ctx.writeAndFlush(new ChunkResponseMessage(msg.dhSectionPos)); }); } - + public void addPlayer(IServerPlayerWrapper serverPlayer) { this.playersByUUID.put(serverPlayer.getUUID(), new RemotePlayer(serverPlayer)); @@ -107,7 +125,7 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld this.networkServer.disconnectClient(channelContext, "You are being disconnected."); } } - + @Override public DhServerLevel getOrLoadLevel(ILevelWrapper wrapper) { @@ -115,7 +133,7 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld { return null; } - + return this.levels.computeIfAbsent((IServerLevelWrapper) wrapper, (serverLevelWrapper) -> { File levelFile = this.saveStructure.getLevelFolder(wrapper); @@ -123,7 +141,7 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld return new DhServerLevel(this.saveStructure, serverLevelWrapper); }); } - + @Override public DhServerLevel getLevel(ILevelWrapper wrapper) { @@ -131,13 +149,13 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld { return null; } - + return this.levels.get(wrapper); } - + @Override public Iterable getAllLoadedLevels() { return this.levels.values(); } - + @Override public void unloadLevel(ILevelWrapper wrapper) { @@ -145,24 +163,24 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld { return; } - + if (this.levels.containsKey(wrapper)) { LOGGER.info("Unloading level {} ", this.levels.get(wrapper)); this.levels.remove(wrapper).close(); } } - + public void serverTick() { this.levels.values().forEach(DhServerLevel::serverTick); } - + public void doWorldGen() { this.levels.values().forEach(DhServerLevel::doWorldGen); } - + @Override public CompletableFuture saveAndFlush() { return CompletableFuture.allOf(this.levels.values().stream().map(DhServerLevel::saveAsync).toArray(CompletableFuture[]::new)); } - + @Override public void close() { @@ -173,9 +191,9 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld LOGGER.info("Unloading level " + level.getLevelWrapper().getDimensionType().getDimensionName()); level.close(); } - + this.levels.clear(); 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 329ca7c54..6b08113e4 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 @@ -1,10 +1,13 @@ package com.seibel.distanthorizons.core.wrapperInterfaces.misc; import com.seibel.distanthorizons.api.interfaces.IDhApiUnsafeWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; import java.util.UUID; -public interface IServerPlayerWrapper extends IDhApiUnsafeWrapper +public interface IServerPlayerWrapper extends IDhApiUnsafeWrapper { UUID getUUID(); + + IServerLevelWrapper getLevel(); }