diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientPluginChannelApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientPluginChannelApi.java index 57e0fc12c..9bc607734 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientPluginChannelApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientPluginChannelApi.java @@ -6,7 +6,7 @@ import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager; import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel; import com.seibel.distanthorizons.core.logging.ConfigBasedLogger; import com.seibel.distanthorizons.core.network.event.internal.CloseInternalEvent; -import com.seibel.distanthorizons.core.network.messages.base.CurrentLevelKeyMessage; +import com.seibel.distanthorizons.core.network.messages.base.LevelInitMessage; import com.seibel.distanthorizons.core.network.session.NetworkSession; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; @@ -69,13 +69,13 @@ public class ClientPluginChannelApi { Objects.requireNonNull(networkSession); this.networkSession = networkSession; - this.networkSession.registerHandler(CurrentLevelKeyMessage.class, this::onCurrentLevelKeyMessage); + this.networkSession.registerHandler(LevelInitMessage.class, this::onLevelInitMessage); this.networkSession.registerHandler(CloseInternalEvent.class, this::onClose); } - private void onCurrentLevelKeyMessage(CurrentLevelKeyMessage msg) + private void onLevelInitMessage(LevelInitMessage msg) { - if (!msg.levelKey.matches(CurrentLevelKeyMessage.VALIDATION_REGEX)) + if (!msg.levelKey.matches(LevelInitMessage.VALIDATION_REGEX)) { throw new IllegalArgumentException("Server sent invalid level key."); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java index 944b8a52d..6c762a0ab 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java @@ -31,10 +31,8 @@ import javax.annotation.CheckForNull; import javax.annotation.Nullable; import java.awt.*; import java.io.IOException; +import java.util.*; import java.util.List; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -161,7 +159,7 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende { Map.Entry mapEntry = this.waitingTasksBySectionPos.entrySet().stream() .filter(task -> task.getValue().networkDataSourceFuture == null) - .min((x, y) -> posDistanceSquared(targetPos, x.getKey()) - posDistanceSquared(targetPos, y.getKey())) + .min(Comparator.comparingInt(x -> posDistanceSquared(targetPos, x.getKey()))) .orElse(null); if (mapEntry == null) @@ -173,8 +171,12 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende long sectionPos = mapEntry.getKey(); RequestQueueEntry entry = mapEntry.getValue(); + Long offsetEntryTimestamp = entry.updateTimestamp != null + ? entry.updateTimestamp + this.networkState.getServerTimeOffset() + : null; + CompletableFuture dataSourceFuture = this.networkState.getSession().sendRequest( - new FullDataSourceRequestMessage(this.level.getLevelWrapper(), sectionPos, entry.updateTimestamp), + new FullDataSourceRequestMessage(this.level.getLevelWrapper(), sectionPos, offsetEntryTimestamp), FullDataSourceResponseMessage.class ); entry.networkDataSourceFuture = dataSourceFuture; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/ClientNetworkState.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/ClientNetworkState.java index 358d15a31..3246fa015 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/ClientNetworkState.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/ClientNetworkState.java @@ -8,7 +8,7 @@ import com.seibel.distanthorizons.core.multiplayer.fullData.FullDataPayloadRecei import com.seibel.distanthorizons.core.network.event.ScopedNetworkEventSource; import com.seibel.distanthorizons.core.network.event.internal.CloseInternalEvent; import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageInternalEvent; -import com.seibel.distanthorizons.core.network.messages.base.CurrentLevelKeyMessage; +import com.seibel.distanthorizons.core.network.messages.base.LevelInitMessage; import com.seibel.distanthorizons.core.network.messages.base.SessionConfigMessage; import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSourceResponseMessage; import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSplitMessage; @@ -53,6 +53,9 @@ public class ClientNetworkState implements Closeable @Nullable private Integer closestProtocolVersion; + private long serverTimeOffset = 0; + public long getServerTimeOffset() { return this.serverTimeOffset; } + //=============// @@ -70,13 +73,16 @@ public class ClientNetworkState implements Closeable } }); - this.networkSession.registerHandler(CurrentLevelKeyMessage.class, message -> + this.networkSession.registerHandler(LevelInitMessage.class, message -> { // we will also receive this message when we have full support if (this.serverSupportStatus == EServerSupportStatus.NONE) { this.serverSupportStatus = EServerSupportStatus.LEVELS_ONLY; } + + this.serverTimeOffset = message.serverTime - System.currentTimeMillis(); + LOGGER.info("Server time offset: [${this.serverTimeOffset}] ms"); }); this.networkSession.registerHandler(CloseInternalEvent.class, message -> diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ServerPlayerState.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ServerPlayerState.java index 3a0826715..ab41b4acc 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ServerPlayerState.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/server/ServerPlayerState.java @@ -5,7 +5,7 @@ import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener; import com.seibel.distanthorizons.core.level.AbstractDhServerLevel; import com.seibel.distanthorizons.core.multiplayer.config.SessionConfig; import com.seibel.distanthorizons.core.multiplayer.fullData.FullDataPayloadSender; -import com.seibel.distanthorizons.core.network.messages.base.CurrentLevelKeyMessage; +import com.seibel.distanthorizons.core.network.messages.base.LevelInitMessage; import com.seibel.distanthorizons.core.network.messages.base.SessionConfigMessage; import com.seibel.distanthorizons.core.network.event.internal.CloseInternalEvent; import com.seibel.distanthorizons.core.network.exceptions.RateLimitedException; @@ -79,7 +79,7 @@ public class ServerPlayerState implements Closeable if (!levelKey.equals(this.lastLevelKey)) { this.lastLevelKey = levelKey; - this.networkSession.sendMessage(new CurrentLevelKeyMessage(levelKey)); + this.networkSession.sendMessage(new LevelInitMessage(levelKey)); } } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/MessageRegistry.java b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/MessageRegistry.java index 241f77807..189295085 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/MessageRegistry.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/MessageRegistry.java @@ -22,7 +22,7 @@ package com.seibel.distanthorizons.core.network.messages; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.seibel.distanthorizons.core.network.messages.base.CodecCrashMessage; -import com.seibel.distanthorizons.core.network.messages.base.CurrentLevelKeyMessage; +import com.seibel.distanthorizons.core.network.messages.base.LevelInitMessage; import com.seibel.distanthorizons.core.network.messages.base.SessionConfigMessage; import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSplitMessage; import com.seibel.distanthorizons.core.network.messages.requests.CancelMessage; @@ -59,7 +59,7 @@ public class MessageRegistry this.registerMessage(CloseReasonMessage.class, CloseReasonMessage::new); // Level keys - this.registerMessage(CurrentLevelKeyMessage.class, CurrentLevelKeyMessage::new); + this.registerMessage(LevelInitMessage.class, LevelInitMessage::new); // Config (for full DH support) this.registerMessage(SessionConfigMessage.class, SessionConfigMessage::new); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/base/CurrentLevelKeyMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/base/LevelInitMessage.java similarity index 64% rename from core/src/main/java/com/seibel/distanthorizons/core/network/messages/base/CurrentLevelKeyMessage.java rename to core/src/main/java/com/seibel/distanthorizons/core/network/messages/base/LevelInitMessage.java index 68539bfc9..7f8d13a96 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/base/CurrentLevelKeyMessage.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/base/LevelInitMessage.java @@ -4,7 +4,7 @@ import com.google.common.base.MoreObjects; import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage; import io.netty.buffer.ByteBuf; -public class CurrentLevelKeyMessage extends AbstractNetworkMessage +public class LevelInitMessage extends AbstractNetworkMessage { public static final int MAX_LENGTH = 150; @@ -16,6 +16,7 @@ public class CurrentLevelKeyMessage extends AbstractNetworkMessage public String levelKey; + public long serverTime; @@ -23,8 +24,12 @@ public class CurrentLevelKeyMessage extends AbstractNetworkMessage // constructors // //==============// - public CurrentLevelKeyMessage() { } - public CurrentLevelKeyMessage(String levelKey) { this.levelKey = levelKey; } + public LevelInitMessage() { } + public LevelInitMessage(String levelKey) + { + this.levelKey = levelKey; + this.serverTime = System.currentTimeMillis(); + } @@ -33,10 +38,18 @@ public class CurrentLevelKeyMessage extends AbstractNetworkMessage //===============// @Override - public void encode(ByteBuf out) { this.writeString(this.levelKey, out); } + public void encode(ByteBuf out) + { + this.writeString(this.levelKey, out); + out.writeLong(this.serverTime); + } @Override - public void decode(ByteBuf in) { this.levelKey = this.readString(in); } + public void decode(ByteBuf in) + { + this.levelKey = this.readString(in); + this.serverTime = in.readLong(); + } @@ -48,7 +61,8 @@ public class CurrentLevelKeyMessage extends AbstractNetworkMessage public MoreObjects.ToStringHelper toStringHelper() { return super.toStringHelper() - .add("levelKey", this.levelKey); + .add("levelKey", this.levelKey) + .add("serverTime", this.serverTime); } } \ No newline at end of file diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IServerLevelWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IServerLevelWrapper.java index ca6b687a8..dd8c95c8c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IServerLevelWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IServerLevelWrapper.java @@ -21,7 +21,7 @@ package com.seibel.distanthorizons.core.wrapperInterfaces.world; import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.config.Config; -import com.seibel.distanthorizons.core.network.messages.base.CurrentLevelKeyMessage; +import com.seibel.distanthorizons.core.network.messages.base.LevelInitMessage; import com.seibel.distanthorizons.core.world.EWorldEnvironment; import java.io.File; @@ -41,7 +41,7 @@ public interface IServerLevelWrapper extends ILevelWrapper if (SharedApi.getEnvironment() == EWorldEnvironment.CLIENT_SERVER) { String cleanWorldFolderName = this.getMcSaveFolder().getParentFile().getName() - .replaceAll("[^" + CurrentLevelKeyMessage.PART_ALLOWED_CHARS_REGEX + " ]", "") + .replaceAll("[^" + LevelInitMessage.PART_ALLOWED_CHARS_REGEX + " ]", "") .replaceAll(" ", "_"); levelKeyPrefix += (!levelKeyPrefix.isEmpty() ? "_" : "") + cleanWorldFolderName; } @@ -51,7 +51,7 @@ public interface IServerLevelWrapper extends ILevelWrapper String mainPart = "@" + dimensionName; return levelKeyPrefix.substring(0, Math.min( - CurrentLevelKeyMessage.MAX_LENGTH - mainPart.length(), + LevelInitMessage.MAX_LENGTH - mainPart.length(), levelKeyPrefix.length() )) + mainPart; }