From 7149baf0f6c6d2c06c871dade76f9ba7ad93bdfc Mon Sep 17 00:00:00 2001 From: Acuadragon100 <8165958-acuadragon100@users.noreply.gitlab.com> Date: Sat, 25 Apr 2026 20:16:20 +0200 Subject: [PATCH] Fix server loading. --- .../core/api/internal/ClientApi.java | 31 ++++++++- .../core/api/internal/ServerApi.java | 23 +++++++ .../core/level/AbstractDhServerLevel.java | 4 +- .../core/level/DhClientLevel.java | 4 +- .../client/ClientNetworkState.java | 5 +- .../multiplayer/server/ServerPlayerState.java | 26 +++++++- .../network/messages/MessageRegistry.java | 6 +- .../base/RequestLevelInitMessage.java | 65 +++++++++++++++++++ .../core/world/AbstractDhServerWorld.java | 3 + .../core/world/DhClientServerWorld.java | 1 + .../core/world/DhClientWorld.java | 5 ++ .../minecraft/IMinecraftSharedWrapper.java | 3 +- 12 files changed, 162 insertions(+), 14 deletions(-) create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/network/messages/base/RequestLevelInitMessage.java diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java index ef4289643..6507192ce 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java @@ -68,6 +68,7 @@ import org.lwjgl.glfw.GLFW; import java.io.File; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ThreadPoolExecutor; @@ -128,7 +129,7 @@ public class ClientApi /** Holds any levels that were loaded before the {@link ClientApi#onClientOnlyConnected} was fired. */ public final HashSet waitingClientLevels = new HashSet<>(); /** Holds any chunks that were loaded before the {@link ClientApi#clientLevelLoadEvent(IClientLevelWrapper)} was fired. */ - public final HashMap, IChunkWrapper> waitingChunkByClientLevelAndPos = new HashMap<>(); + public final Map, IChunkWrapper> waitingChunkByClientLevelAndPos = new ConcurrentHashMap<>(); /** publicly available so {@link F3Screen} can display the error */ @Nullable @@ -235,6 +236,34 @@ public class ClientApi //endregion + public boolean canLoadAlready(IClientLevelWrapper wrapper) { + // wait a moment before loading the level to give the server a chance to handle the client's login request + if (MC_CLIENT.clientConnectedToDedicatedServer()) + { + if (this.firstLevelLoadTimer == null) + { + this.firstLevelLoadTimer = TimerUtil.CreateTimer("FirstLevelLoadTimer"); + this.firstLevelLoadTimer.schedule(new TimerTask() + { + @Override + public void run() { canLoadAlready(wrapper); } + }, FIRST_LEVEL_LOAD_DELAY_IN_MS); + return false; + } + this.firstLevelLoadTimer.cancel(); + } + if (!this.pluginChannelApi.allowLevelLoading(wrapper)) + { + LOGGER.debug("Levels in this connection are managed by the server, skipping auto-load of " + wrapper); + AbstractDhWorld world = SharedApi.getAbstractDhWorld(); + if (world == null) return false; + // Instead of attempting to load themselves, send the config and wait for a server provided level key. + ((DhClientWorld) world).networkState.sendLevelInitRequest(wrapper.getDimensionName()); + return false; + } + return true; + } + //==============// // level events // 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 06dd5b302..01645cd92 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 @@ -77,7 +77,30 @@ public class ServerApi } + //==============// + // level events // + //==============// + public void serverLevelLoadEvent(IServerLevelWrapper levelWrapper) + { + LOGGER.debug("Server Level " + levelWrapper + " loading"); + + AbstractDhWorld serverWorld = SharedApi.getAbstractDhWorld(); + if (serverWorld != null) + { + serverWorld.getOrLoadLevel(levelWrapper); + } + } + public void serverLevelUnloadEvent(IServerLevelWrapper level) + { + LOGGER.debug("Server Level " + level + " unloading"); + + AbstractDhWorld serverWorld = SharedApi.getAbstractDhWorld(); + if (serverWorld != null) + { + serverWorld.unloadLevel(level); + } + } //=======================// diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhServerLevel.java index 2077ee056..401cb87ec 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhServerLevel.java @@ -202,7 +202,7 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I // Check if the player is in this dimension, // since handling multiple dimensions isn't allowed - if (message.getSession().serverPlayer.getLevel() != this.getLevelWrapper()) + /*if (message.getSession().serverPlayer.getLevel() != this.getLevelWrapper()) { // If the message can be replied to - reply with an error, otherwise just ignore if (message instanceof AbstractTrackableMessage) @@ -218,7 +218,7 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I } return false; - } + }*/ return true; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java index 4246b86dd..80929ce19 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java @@ -237,16 +237,14 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel { ClientNetworkState networkState = this.networkState; - boolean isClientUsable = false, isAllowedDimension = false; + boolean isClientUsable = false; if (networkState != null) { isClientUsable = networkState.isReady(); - isAllowedDimension = MC_CLIENT.getWrappedClientLevel() == this.levelWrapper; } return isClientUsable && networkState.sessionConfig.isDistantGenerationEnabled() - && isAllowedDimension && this.clientside.isRendering(); } 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 0a922fa9e..10aa6e1a6 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 @@ -13,6 +13,7 @@ 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.LevelInitMessage; +import com.seibel.distanthorizons.core.network.messages.base.RequestLevelInitMessage; 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; @@ -164,7 +165,9 @@ public class ClientNetworkState implements Closeable // send message // //==============// - + public void sendLevelInitRequest(String clientLevelKey) { + this.getSession().sendMessage(new RequestLevelInitMessage(clientLevelKey)); + } public void sendConfigMessage() { this.sendConfigMessage(true); } public void sendConfigMessage(boolean blocking) 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 b5b86050a..fd18defd3 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 @@ -2,6 +2,7 @@ package com.seibel.distanthorizons.core.multiplayer.server; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.level.AbstractDhServerLevel; import com.seibel.distanthorizons.core.multiplayer.config.SessionConfig; import com.seibel.distanthorizons.core.multiplayer.fullData.FullDataPayloadSender; @@ -9,17 +10,20 @@ import com.seibel.distanthorizons.core.multiplayer.fullData.SharedBandwidthLimit import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageInternalEvent; import com.seibel.distanthorizons.core.network.messages.base.CloseReasonMessage; import com.seibel.distanthorizons.core.network.messages.base.LevelInitMessage; +import com.seibel.distanthorizons.core.network.messages.base.RequestLevelInitMessage; 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; import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSourceRequestMessage; import com.seibel.distanthorizons.core.network.session.NetworkSession; import com.seibel.distanthorizons.core.util.ratelimiting.SupplierBasedRateAndConcurrencyLimiter; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; import org.jetbrains.annotations.NotNull; import java.io.Closeable; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; public class ServerPlayerState implements Closeable { @@ -66,6 +70,12 @@ public class ServerPlayerState implements Closeable this.sendConfigMessage(); }); + this.networkSession.registerHandler(RequestLevelInitMessage.class, (requestLevelKeyMessage) -> + { + sendLevelKey(requestLevelKeyMessage.clientLevelKey); + }); + + this.networkSession.registerHandler(CloseInternalEvent.class, event -> { // No-op. prevents "Unhandled message" log entries }); @@ -85,12 +95,13 @@ public class ServerPlayerState implements Closeable //=================// private void onLevelKeyPrefixConfigChanged(String newLevelKey) { this.sendLevelKey(); } - private void sendLevelKey() + + private void sendLevelKey(Supplier levelKeySupplier) { if (Config.Server.sendLevelKeys.get()) { + String levelKey = levelKeySupplier.get(); // let the client's know about the change - String levelKey = this.getServerPlayer().getLevel().getKeyedLevelDimensionName(); if (!levelKey.equals(this.lastLevelKey)) { this.lastLevelKey = levelKey; @@ -99,6 +110,17 @@ public class ServerPlayerState implements Closeable } } + private void sendLevelKey(String clientLevelKey) + { + sendLevelKey(() -> SingletonInjector.INSTANCE.get(IMinecraftSharedWrapper.class) + .getWrappedServerLevel(clientLevelKey).getKeyedLevelDimensionName()); + } + + private void sendLevelKey() + { + sendLevelKey(() -> this.getServerPlayer().getLevel().getKeyedLevelDimensionName()); + } + private void sendConfigMessage() { double coordinateScale = this.getServerPlayer().getLevel().getDimensionType().getCoordinateScale(); 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 8e3748e8e..3eb230ed1 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 @@ -21,12 +21,9 @@ 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.LevelInitMessage; -import com.seibel.distanthorizons.core.network.messages.base.SessionConfigMessage; +import com.seibel.distanthorizons.core.network.messages.base.*; import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSplitMessage; import com.seibel.distanthorizons.core.network.messages.requests.CancelMessage; -import com.seibel.distanthorizons.core.network.messages.base.CloseReasonMessage; import com.seibel.distanthorizons.core.network.messages.requests.ExceptionMessage; import com.seibel.distanthorizons.core.network.messages.fullData.FullDataPartialUpdateMessage; import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSourceRequestMessage; @@ -60,6 +57,7 @@ public class MessageRegistry // Level keys this.registerMessage(LevelInitMessage.class, LevelInitMessage::new); + this.registerMessage(RequestLevelInitMessage.class, RequestLevelInitMessage::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/RequestLevelInitMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/base/RequestLevelInitMessage.java new file mode 100644 index 000000000..5f80e2cc3 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/base/RequestLevelInitMessage.java @@ -0,0 +1,65 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.core.network.messages.base; + +import com.google.common.base.MoreObjects; +import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage; +import io.netty.buffer.ByteBuf; + +/** used for full DH support */ +public class RequestLevelInitMessage extends AbstractNetworkMessage +{ + public String clientLevelKey; + + + + //=============// + // constructor // + //=============// + + public RequestLevelInitMessage() { } + public RequestLevelInitMessage(String clientLevelKey) { this.clientLevelKey = clientLevelKey; } + + + + //===============// + // serialization // + //===============// + + @Override + public void encode(ByteBuf out) { this.writeString(this.clientLevelKey, out); } + + @Override + public void decode(ByteBuf in) { this.clientLevelKey = this.readString(in); } + + + + //================// + // base overrides // + //================// + + @Override + public MoreObjects.ToStringHelper toStringHelper() + { + return super.toStringHelper() + .add("levelKey", this.clientLevelKey); + } + +} \ No newline at end of file diff --git a/core/src/main/java/com/seibel/distanthorizons/core/world/AbstractDhServerWorld.java b/core/src/main/java/com/seibel/distanthorizons/core/world/AbstractDhServerWorld.java index adeb7dbcd..a774eacb9 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/world/AbstractDhServerWorld.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/world/AbstractDhServerWorld.java @@ -1,5 +1,6 @@ package com.seibel.distanthorizons.core.world; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelUnloadEvent; import com.seibel.distanthorizons.core.file.structure.LocalSaveStructure; import com.seibel.distanthorizons.core.level.AbstractDhServerLevel; import com.seibel.distanthorizons.core.level.IDhLevel; @@ -8,6 +9,7 @@ import com.seibel.distanthorizons.core.multiplayer.server.ServerPlayerStateManag import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; +import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -138,6 +140,7 @@ public abstract class AbstractDhServerWorld