feat: Implement syncing of DhSectionPos for chunk requests/responses
This commit is contained in:
+5
-7
@@ -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<IFullDataSource> 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<ChunkResponseMessage> responseFuture = chunkRequestTracker.sendRequest(networkClient.getChannel(), new ChunkRequestMessage());
|
||||
|
||||
FullDataMetaFile metaFile = this.getLoadOrMakeFile(pos, true);
|
||||
CompletableFuture<ChunkResponseMessage> responseFuture = chunkRequestTracker.sendRequest(networkClient.getChannel(), new ChunkRequestMessage(pos));
|
||||
return onDataFileUpdate(fullDataSource, metaFile, iFullDataSource -> {}, iFullDataSource -> true);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+10
-4
@@ -7,17 +7,23 @@ import io.netty.buffer.ByteBuf;
|
||||
public class ChunkRequestMessage implements IFutureTrackableNetworkMessage<DhSectionPos>
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
+7
-1
@@ -7,12 +7,18 @@ import io.netty.buffer.ByteBuf;
|
||||
public class ChunkResponseMessage implements IFutureTrackableNetworkMessage<DhSectionPos>
|
||||
{
|
||||
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)
|
||||
|
||||
@@ -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<DhSectionPos>
|
||||
public class DhSectionPos implements Comparable<DhSectionPos>, INetworkObject
|
||||
{
|
||||
/**
|
||||
* The lowest detail level a Section position can hold.
|
||||
@@ -32,12 +34,12 @@ public class DhSectionPos implements Comparable<DhSectionPos>
|
||||
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<DhSectionPos>
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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<IServerLevelWrapper, DhServerLevel> levels;
|
||||
public final LocalSaveStructure saveStructure;
|
||||
|
||||
|
||||
private final NetworkServer networkServer;
|
||||
private final HashMap<UUID, RemotePlayer> playersByUUID;
|
||||
private final BiMap<ChannelHandlerContext, RemotePlayer> 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<? extends IDhLevel> 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<Void> 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+4
-1
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user