From 649cd5bbe85d8b5a513eb13bd65a61e75bbb20e6 Mon Sep 17 00:00:00 2001 From: Cailin Smith Date: Sun, 2 Jul 2023 21:41:14 +0200 Subject: [PATCH 1/4] Add ability for servers to communicate with the client to set the world. This prevents the client from accidentally selected the wrong world folder to load LODs from, since levels of the same dimension can't naturally be distinguished from each other. With level similarity detection, this can sometimes work, but in general is not reliable. This mechanism instead allows servers to send a packet to the client on load, enabling the override system, and then a second packet on world change, which specifically sets the world key, based on knowledge that only the server has, leading to a reliable way of detecting the correct world. --- .../core/api/internal/ClientApi.java | 204 ++++++++++++------ .../core/api/internal/SharedApi.java | 2 + .../structure/ClientOnlySaveStructure.java | 9 + .../core/level/DhClientLevel.java | 1 + .../level/IServerEnhancedClientLevel.java | 15 ++ .../core/level/IServerEnhancedManager.java | 26 +++ .../core/world/DhClientWorld.java | 1 + .../minecraft/IFriendlyByteBuf.java | 13 ++ .../minecraft/IMinecraftClientWrapper.java | 6 + 9 files changed, 216 insertions(+), 61 deletions(-) create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/level/IServerEnhancedClientLevel.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/level/IServerEnhancedManager.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IFriendlyByteBuf.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 cef0c1e8f..a0695cbb3 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 @@ -21,6 +21,11 @@ package com.seibel.distanthorizons.core.api.internal; import com.seibel.distanthorizons.api.methods.events.abstractEvents.*; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam; +import com.seibel.distanthorizons.core.level.IServerEnhancedClientLevel; +import com.seibel.distanthorizons.core.level.IServerEnhancedManager; +import com.seibel.distanthorizons.core.world.*; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IFriendlyByteBuf; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; import com.seibel.distanthorizons.core.level.IDhClientLevel; import com.seibel.distanthorizons.core.config.Config; @@ -36,10 +41,6 @@ import com.seibel.distanthorizons.coreapi.util.math.Mat4f; import com.seibel.distanthorizons.core.render.glObject.GLProxy; import com.seibel.distanthorizons.core.render.renderer.TestRenderer; import com.seibel.distanthorizons.core.util.RenderUtil; -import com.seibel.distanthorizons.core.world.DhClientWorld; -import com.seibel.distanthorizons.core.world.AbstractDhWorld; -import com.seibel.distanthorizons.core.world.IDhClientWorld; -import com.seibel.distanthorizons.core.world.EWorldEnvironment; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; @@ -49,13 +50,14 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.glfw.GLFW; +import java.nio.charset.Charset; import java.util.concurrent.TimeUnit; /** * This holds the methods that should be called * by the host mod loader (Fabric, Forge, etc.). * Specifically for the client. - * + * * @author James Seibel * @version 2022-9-16 */ @@ -64,36 +66,41 @@ public class ClientApi private static final Logger LOGGER = LogManager.getLogger(); public static final boolean ENABLE_EVENT_LOGGING = true; public static boolean prefLoggerEnabled = false; - + public static final ClientApi INSTANCE = new ClientApi(); public static TestRenderer testRenderer = new TestRenderer(); private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); - + private static final IServerEnhancedManager SERVER_ENHANCED_MANAGER + = SingletonInjector.INSTANCE.get(IServerEnhancedManager.class); + public static final long SPAM_LOGGER_FLUSH_NS = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS); - + private boolean configOverrideReminderPrinted = false; public boolean rendererDisabledBecauseOfExceptions = false; - + private long lastFlushNanoTime = 0; - - - + + private boolean isServerCommunicationEnabled = true; + + private boolean serverIsMalformed = false; + + //==============// // constructors // //==============// - + private ClientApi() { - + } - - - + + + //========// // events // //========// - + public void onClientOnlyConnected() { // only continue if the client is connected to a different server @@ -103,11 +110,11 @@ public class ClientApi { LOGGER.info("Client on ClientOnly mode connecting."); } - + SharedApi.setDhWorld(new DhClientWorld()); } } - + public void onClientOnlyDisconnected() { if (MC.clientConnectedToDedicatedServer()) @@ -119,13 +126,17 @@ public class ClientApi { LOGGER.info("Client on ClientOnly mode disconnecting."); } - + world.close(); SharedApi.setDhWorld(null); } + this.isServerCommunicationEnabled = false; + this.serverIsMalformed = false; + SERVER_ENHANCED_MANAGER.setUseOverrideWrapper(false); + SERVER_ENHANCED_MANAGER.registerServerEnhancedLevel(null); } } - + public void clientChunkLoadEvent(IChunkWrapper chunk, IClientLevelWrapper level) { if (SharedApi.getEnvironment() == EWorldEnvironment.Client_Only) @@ -137,7 +148,7 @@ public class ClientApi } } } - + public void clientChunkSaveEvent(IChunkWrapper chunk, IClientLevelWrapper level) { if (SharedApi.getEnvironment() == EWorldEnvironment.Client_Only) @@ -149,14 +160,14 @@ public class ClientApi } } } - + public void clientLevelUnloadEvent(IClientLevelWrapper level) { if (ENABLE_EVENT_LOGGING) { LOGGER.info("Client level "+level+" unloading."); } - + AbstractDhWorld world = SharedApi.getAbstractDhWorld(); if (world != null) { @@ -164,14 +175,18 @@ public class ClientApi ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(level)); } } - + public void clientLevelLoadEvent(IClientLevelWrapper level) { - if (ENABLE_EVENT_LOGGING) - { - LOGGER.info("Client level "+level+" loading."); + if (ENABLE_EVENT_LOGGING) { + if (this.isServerCommunicationEnabled) { + LOGGER.info("Server supports communication, deferring loading."); + return; + } + + LOGGER.info("Client level " + level + " loading."); } - + AbstractDhWorld world = SharedApi.getAbstractDhWorld(); if (world != null) { @@ -179,40 +194,55 @@ public class ClientApi ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(level)); } } - + + public void serverLevelLoadEvent(IServerEnhancedClientLevel level) + { + if (ENABLE_EVENT_LOGGING) + { + LOGGER.info("Server level " + level + " (" + level.getServerWorldKey() + ") loading."); + } + + AbstractDhWorld world = SharedApi.getAbstractDhWorld(); + if (world != null) + { + world.getOrLoadLevel(level); + ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(level)); + } + } + public void rendererShutdownEvent() { if (ENABLE_EVENT_LOGGING) { LOGGER.info("Renderer shutting down."); } - + IProfilerWrapper profiler = MC.getProfiler(); profiler.push("DH-RendererShutdown"); - + profiler.pop(); } - + public void rendererStartupEvent() { if (ENABLE_EVENT_LOGGING) { LOGGER.info("Renderer starting up."); } - + IProfilerWrapper profiler = MC.getProfiler(); profiler.push("DH-RendererStartup"); - + // make sure the GLProxy is created before the LodBufferBuilder needs it GLProxy.getInstance(); profiler.pop(); } - + public void clientTickEvent() { IProfilerWrapper profiler = MC.getProfiler(); profiler.push("DH-ClientTick"); - + boolean doFlush = System.nanoTime() - this.lastFlushNanoTime >= SPAM_LOGGER_FLUSH_NS; if (doFlush) { @@ -221,7 +251,7 @@ public class ClientApi } ConfigBasedLogger.updateAll(); ConfigBasedSpamLogger.updateAll(doFlush); - + IDhClientWorld clientWorld = SharedApi.getIDhClientWorld(); if (clientWorld != null) { @@ -229,13 +259,65 @@ public class ClientApi } profiler.pop(); } - - - + + public void serverMessageReceived(IFriendlyByteBuf buf) + { + // It is important to ensure malicious server input is ignored. + if(this.serverIsMalformed) { + return; + } + short commandLength = buf.readShort(); + if(commandLength > 32) { + LOGGER.error("Server sent command > 32"); + ClientApi.INSTANCE.serverIsMalformed = true; + return; + } + String eventType = buf.readCharSequence(commandLength, Charset.forName("UTF-8")).toString(); + switch(eventType) { + case "ServerCommsEnabled": + LOGGER.info("Server supports DH protocol."); + ClientApi.INSTANCE.isServerCommunicationEnabled = true; + SERVER_ENHANCED_MANAGER.setUseOverrideWrapper(true); + MC.execute(() -> { + // Go ahead and unload the current world, because it may be wrong. We expect + // a followup WorldChanged event from the server soon anyways. + clientLevelUnloadEvent((IClientLevelWrapper) MC.getWrappedClientWorld()); + }); + break; + case "WorldChanged": + short worldKeyLength = buf.readShort(); + if(worldKeyLength > 128) { + LOGGER.error("Server sent worldKey > 128"); + this.serverIsMalformed = true; + return; + } + String worldKey = buf.readCharSequence(worldKeyLength, Charset.forName("UTF-8")).toString(); + if(!worldKey.matches("[a-zA-Z0-9_]+")) { + LOGGER.error("Server sent invalid world key name, and is being ignored."); + this.isServerCommunicationEnabled = false; + this.serverIsMalformed = true; + return; + } + LOGGER.info("Server sent world change event: " + worldKey); + MC.execute(() -> { + if(MC.getWrappedClientWorld() != null) { + clientLevelUnloadEvent((IClientLevelWrapper) MC.getWrappedClientWorld()); + } + IServerEnhancedClientLevel clientLevel + = SERVER_ENHANCED_MANAGER.getServerEnhancedLevel(MC.getWrappedClientWorld(), worldKey); + SERVER_ENHANCED_MANAGER.registerServerEnhancedLevel(clientLevel); + serverLevelLoadEvent(clientLevel); + }); + break; + } + } + + + //===========// // rendering // //===========// - + public void renderLods(IClientLevelWrapper levelWrapper, Mat4f mcModelViewMatrix, Mat4f mcProjectionMatrix, float partialTicks) { if (ModInfo.IS_DEV_BUILD && !this.configOverrideReminderPrinted && MC.playerExists()) @@ -246,8 +328,8 @@ public class ClientApi MC.sendChatMessage("Here be dragons!"); this.configOverrideReminderPrinted = true; } - - + + IProfilerWrapper profiler = MC.getProfiler(); profiler.pop(); // get out of "terrain" profiler.push("DH-RenderLevel"); @@ -257,20 +339,20 @@ public class ClientApi { return; } - - + + //FIXME: Improve class hierarchy of DhWorld, IClientWorld, IServerWorld to fix all this hard casting // (also in RenderUtil) IDhClientWorld dhClientWorld = SharedApi.getIDhClientWorld(); IDhClientLevel level = dhClientWorld.getOrLoadClientLevel(levelWrapper); - + if (prefLoggerEnabled) { level.dumpRamUsage(); } - - - + + + profiler.push("Render" + (Config.Client.Advanced.Debugging.rendererMode.get() == ERendererMode.DEFAULT ? "-lods" : "-debug")); try { @@ -280,7 +362,7 @@ public class ClientApi new DhApiRenderParam(mcProjectionMatrix, mcModelViewMatrix, RenderUtil.createLodProjectionMatrix(mcProjectionMatrix, partialTicks), RenderUtil.createLodModelViewMatrix(mcModelViewMatrix), partialTicks); - + boolean renderingCanceled = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderEvent.class, new DhApiBeforeRenderEvent.EventParam(renderEventParam)); if (!this.rendererDisabledBecauseOfExceptions && !renderingCanceled) { @@ -298,7 +380,7 @@ public class ClientApi { this.rendererDisabledBecauseOfExceptions = true; LOGGER.error("Renderer thrown an uncaught exception: ", e); - + MC.sendChatMessage("\u00A74\u00A7l\u00A7uERROR: Distant Horizons" + " renderer has encountered an exception!"); MC.sendChatMessage("\u00A74Renderer is now disabled to prevent further issues."); @@ -316,13 +398,13 @@ public class ClientApi profiler.push("terrain"); // go back into "terrain" } } - - - + + + //=================// // DEBUG USE // //=================// - + /** Trigger once on key press, with CLIENT PLAYER. */ public void keyPressedEvent(int glfwKey) { @@ -331,8 +413,8 @@ public class ClientApi // keybindings are disabled return; } - - + + if (glfwKey == GLFW.GLFW_KEY_F8) { Config.Client.Advanced.Debugging.debugRendering.set(EDebugRendering.next(Config.Client.Advanced.Debugging.debugRendering.get())); @@ -349,6 +431,6 @@ public class ClientApi MC.sendChatMessage("P: Debug Pref Logger is " + (prefLoggerEnabled ? "enabled" : "disabled")); } } - - + + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java index c6a063850..a16764ae9 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java @@ -5,6 +5,7 @@ import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.ColumnR import com.seibel.distanthorizons.core.dataObjects.transformers.DataRenderTransformer; import com.seibel.distanthorizons.core.file.fullDatafile.FullDataFileHandler; import com.seibel.distanthorizons.core.generation.WorldGenerationQueue; +import com.seibel.distanthorizons.core.level.IDhClientLevel; import com.seibel.distanthorizons.core.world.*; import com.seibel.distanthorizons.core.world.*; @@ -12,6 +13,7 @@ import com.seibel.distanthorizons.core.world.*; public class SharedApi { private static AbstractDhWorld currentWorld; + diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/structure/ClientOnlySaveStructure.java b/core/src/main/java/com/seibel/distanthorizons/core/file/structure/ClientOnlySaveStructure.java index 3ad53c5ca..285009d32 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/structure/ClientOnlySaveStructure.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/structure/ClientOnlySaveStructure.java @@ -5,6 +5,7 @@ import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.file.subDimMatching.SubDimensionLevelMatcher; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.api.enums.config.EServerFolderNameMode; +import com.seibel.distanthorizons.core.level.IServerEnhancedClientLevel; import com.seibel.distanthorizons.core.util.objects.ParsedIp; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; @@ -58,6 +59,14 @@ public class ClientOnlySaveStructure extends AbstractSaveStructure { return this.levelToFileMap.computeIfAbsent(level, (newLevel) -> { + if (newLevel instanceof IServerEnhancedClientLevel) { + IServerEnhancedClientLevel secl = (IServerEnhancedClientLevel) newLevel; + // This world was identified by the server directly, so we can know for sure which folder to use. + File seclFolder = new File(this.folder.getParent(), MC_CLIENT.getCurrentServerIp().toString()); + seclFolder = new File(seclFolder, secl.getServerWorldKey()); + return seclFolder; + } + if (Config.Client.Advanced.Multiplayer.multiverseSimilarityRequiredPercent.get() == 0) { if (this.fileMatcher != null) 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 9e63773a9..06fb790cc 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 @@ -4,6 +4,7 @@ import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedF import com.seibel.distanthorizons.core.file.fullDatafile.IFullDataSourceProvider; import com.seibel.distanthorizons.core.file.fullDatafile.RemoteFullDataFileHandler; import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure; +import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhBlockPos; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/IServerEnhancedClientLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/IServerEnhancedClientLevel.java new file mode 100644 index 000000000..7f50aad1d --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/IServerEnhancedClientLevel.java @@ -0,0 +1,15 @@ +package com.seibel.distanthorizons.core.level; + +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; + +/** + * Enhances an IClientLevelWrapper with server provided world information. + */ +public interface IServerEnhancedClientLevel extends IClientLevelWrapper +{ + /** + * Returns the world key, which is used to select the correct folder on the client. + * @return + */ + String getServerWorldKey(); +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/IServerEnhancedManager.java b/core/src/main/java/com/seibel/distanthorizons/core/level/IServerEnhancedManager.java new file mode 100644 index 000000000..bd252e959 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/IServerEnhancedManager.java @@ -0,0 +1,26 @@ +package com.seibel.distanthorizons.core.level; + +import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; +import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable; + +public interface IServerEnhancedManager extends IBindable { + /** + * Called when a client level is wrapped by a ServerEnhancedClientLevel, for integration into mod internals. + * @param clientLevel + */ + void registerServerEnhancedLevel(IServerEnhancedClientLevel clientLevel); + + /** + * Returns a new instance of a ServerEnhancedClientLevel. + * @param level + * @param worldKey + * @return + */ + IServerEnhancedClientLevel getServerEnhancedLevel(ILevelWrapper level, String worldKey); + + /** + * Sets the LOD engine to use the override wrapper, if the server has communication enabled. + * @param useOverrideWrapper + */ + void setUseOverrideWrapper(boolean useOverrideWrapper); +} 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 1c9126f19..553731fe8 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 @@ -45,6 +45,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld return this.levels.computeIfAbsent((IClientLevelWrapper) wrapper, (clientLevelWrapper) -> { File file = this.saveStructure.getLevelFolder(wrapper); + if (file == null) { return null; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IFriendlyByteBuf.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IFriendlyByteBuf.java new file mode 100644 index 000000000..fac5fac2b --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IFriendlyByteBuf.java @@ -0,0 +1,13 @@ +package com.seibel.distanthorizons.core.wrapperInterfaces.minecraft; + +import java.nio.charset.Charset; + +/** + * Interface that wraps the net.minecraft.network.FriendlyByteBuffer. + */ +public interface IFriendlyByteBuf { + + short readShort(); + + CharSequence readCharSequence(int length, Charset charset); +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java index 252a2bea6..57f8b573a 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java @@ -138,5 +138,11 @@ public interface IMinecraftClientWrapper extends IBindable void crashMinecraft(String errorMessage, Throwable exception); //FIXME: Move to IMinecraftSharedWrapper Object getOptionsObject(); + + /** + * Executes a task on the Minecraft render thread. + * @param runnable + */ + void execute(Runnable runnable); } From 44a66a3d93b1716984ae674d07f921aa909ff770 Mon Sep 17 00:00:00 2001 From: Cailin Smith Date: Sun, 2 Jul 2023 21:44:54 +0200 Subject: [PATCH 2/4] Add ability for servers to communicate with the client to set the world. This prevents the client from accidentally selected the wrong world folder to load LODs from, since levels of the same dimension can't naturally be distinguished from each other. With level similarity detection, this can sometimes work, but in general is not reliable. This mechanism instead allows servers to send a packet to the client on load, enabling the override system, and then a second packet on world change, which specifically sets the world key, based on knowledge that only the server has, leading to a reliable way of detecting the correct world. --- .../interfaces/IDhServerMessageRecieved.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 api/src/main/java/com/seibel/distanthorizons/api/methods/events/interfaces/IDhServerMessageRecieved.java diff --git a/api/src/main/java/com/seibel/distanthorizons/api/methods/events/interfaces/IDhServerMessageRecieved.java b/api/src/main/java/com/seibel/distanthorizons/api/methods/events/interfaces/IDhServerMessageRecieved.java new file mode 100644 index 000000000..dd31f79b7 --- /dev/null +++ b/api/src/main/java/com/seibel/distanthorizons/api/methods/events/interfaces/IDhServerMessageRecieved.java @@ -0,0 +1,15 @@ +package com.seibel.distanthorizons.api.methods.events.interfaces; + +/** + * + * @author Cailin + */ +public interface IDhServerMessageRecieved extends IDhApiEvent +{ + /** + * Triggered when a plugin message is received from the server. + * @param channel The name of the channel this was received on. + * @param message The message sent from the server. + */ + void serverMessageRecieved(String channel, byte[] message); +} From 55f39996cbd2f0aa4e4b30166e445acff00c77ee Mon Sep 17 00:00:00 2001 From: Cailin Smith Date: Sun, 2 Jul 2023 22:34:47 +0200 Subject: [PATCH 3/4] Rename class --- .../core/api/internal/ClientApi.java | 17 ++++++++--------- ...Manager.java => IEnhancedServerManager.java} | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) rename core/src/main/java/com/seibel/distanthorizons/core/level/{IServerEnhancedManager.java => IEnhancedServerManager.java} (93%) 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 a0695cbb3..aeabb36c8 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 @@ -22,10 +22,9 @@ package com.seibel.distanthorizons.core.api.internal; import com.seibel.distanthorizons.api.methods.events.abstractEvents.*; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam; import com.seibel.distanthorizons.core.level.IServerEnhancedClientLevel; -import com.seibel.distanthorizons.core.level.IServerEnhancedManager; +import com.seibel.distanthorizons.core.level.IEnhancedServerManager; import com.seibel.distanthorizons.core.world.*; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IFriendlyByteBuf; -import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; import com.seibel.distanthorizons.core.level.IDhClientLevel; import com.seibel.distanthorizons.core.config.Config; @@ -71,8 +70,8 @@ public class ClientApi public static TestRenderer testRenderer = new TestRenderer(); private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); - private static final IServerEnhancedManager SERVER_ENHANCED_MANAGER - = SingletonInjector.INSTANCE.get(IServerEnhancedManager.class); + private static final IEnhancedServerManager ENHANCED_SERVER_MANAGER + = SingletonInjector.INSTANCE.get(IEnhancedServerManager.class); public static final long SPAM_LOGGER_FLUSH_NS = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS); @@ -132,8 +131,8 @@ public class ClientApi } this.isServerCommunicationEnabled = false; this.serverIsMalformed = false; - SERVER_ENHANCED_MANAGER.setUseOverrideWrapper(false); - SERVER_ENHANCED_MANAGER.registerServerEnhancedLevel(null); + ENHANCED_SERVER_MANAGER.setUseOverrideWrapper(false); + ENHANCED_SERVER_MANAGER.registerServerEnhancedLevel(null); } } @@ -277,7 +276,7 @@ public class ClientApi case "ServerCommsEnabled": LOGGER.info("Server supports DH protocol."); ClientApi.INSTANCE.isServerCommunicationEnabled = true; - SERVER_ENHANCED_MANAGER.setUseOverrideWrapper(true); + ENHANCED_SERVER_MANAGER.setUseOverrideWrapper(true); MC.execute(() -> { // Go ahead and unload the current world, because it may be wrong. We expect // a followup WorldChanged event from the server soon anyways. @@ -304,8 +303,8 @@ public class ClientApi clientLevelUnloadEvent((IClientLevelWrapper) MC.getWrappedClientWorld()); } IServerEnhancedClientLevel clientLevel - = SERVER_ENHANCED_MANAGER.getServerEnhancedLevel(MC.getWrappedClientWorld(), worldKey); - SERVER_ENHANCED_MANAGER.registerServerEnhancedLevel(clientLevel); + = ENHANCED_SERVER_MANAGER.getServerEnhancedLevel(MC.getWrappedClientWorld(), worldKey); + ENHANCED_SERVER_MANAGER.registerServerEnhancedLevel(clientLevel); serverLevelLoadEvent(clientLevel); }); break; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/IServerEnhancedManager.java b/core/src/main/java/com/seibel/distanthorizons/core/level/IEnhancedServerManager.java similarity index 93% rename from core/src/main/java/com/seibel/distanthorizons/core/level/IServerEnhancedManager.java rename to core/src/main/java/com/seibel/distanthorizons/core/level/IEnhancedServerManager.java index bd252e959..b24cdaf5b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/IServerEnhancedManager.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/IEnhancedServerManager.java @@ -3,7 +3,7 @@ package com.seibel.distanthorizons.core.level; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable; -public interface IServerEnhancedManager extends IBindable { +public interface IEnhancedServerManager extends IBindable { /** * Called when a client level is wrapped by a ServerEnhancedClientLevel, for integration into mod internals. * @param clientLevel From 2b0ee29a8cc0aaa763eb9f8a2c68bc928271502c Mon Sep 17 00:00:00 2001 From: James Seibel Date: Tue, 4 Jul 2023 10:29:32 -0500 Subject: [PATCH 4/4] refactor and rename --- ...ved.java => IDhServerMessageReceived.java} | 6 +- .../core/api/internal/ClientApi.java | 92 ++++++++++-------- .../structure/ClientOnlySaveStructure.java | 95 +++++++++++-------- .../core/level/IEnhancedServerManager.java | 26 ----- .../core/level/IKeyedClientLevelManager.java | 24 +++++ .../level/IServerEnhancedClientLevel.java | 15 --- .../core/level/IServerKeyedClientLevel.java | 11 +++ .../minecraft/IFriendlyByteBuf.java | 13 --- .../minecraft/IMinecraftClientWrapper.java | 7 +- 9 files changed, 150 insertions(+), 139 deletions(-) rename api/src/main/java/com/seibel/distanthorizons/api/methods/events/interfaces/{IDhServerMessageRecieved.java => IDhServerMessageReceived.java} (69%) delete mode 100644 core/src/main/java/com/seibel/distanthorizons/core/level/IEnhancedServerManager.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/level/IKeyedClientLevelManager.java delete mode 100644 core/src/main/java/com/seibel/distanthorizons/core/level/IServerEnhancedClientLevel.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/level/IServerKeyedClientLevel.java delete mode 100644 core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IFriendlyByteBuf.java diff --git a/api/src/main/java/com/seibel/distanthorizons/api/methods/events/interfaces/IDhServerMessageRecieved.java b/api/src/main/java/com/seibel/distanthorizons/api/methods/events/interfaces/IDhServerMessageReceived.java similarity index 69% rename from api/src/main/java/com/seibel/distanthorizons/api/methods/events/interfaces/IDhServerMessageRecieved.java rename to api/src/main/java/com/seibel/distanthorizons/api/methods/events/interfaces/IDhServerMessageReceived.java index dd31f79b7..378f8fe3d 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/methods/events/interfaces/IDhServerMessageRecieved.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/methods/events/interfaces/IDhServerMessageReceived.java @@ -1,15 +1,15 @@ package com.seibel.distanthorizons.api.methods.events.interfaces; /** - * * @author Cailin */ -public interface IDhServerMessageRecieved extends IDhApiEvent +public interface IDhServerMessageReceived extends IDhApiEvent { /** * Triggered when a plugin message is received from the server. * @param channel The name of the channel this was received on. * @param message The message sent from the server. */ - void serverMessageRecieved(String channel, byte[] message); + void serverMessageReceived(String channel, byte[] message); + } 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 aeabb36c8..d2fd8fb9f 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 @@ -21,10 +21,9 @@ package com.seibel.distanthorizons.core.api.internal; import com.seibel.distanthorizons.api.methods.events.abstractEvents.*; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam; -import com.seibel.distanthorizons.core.level.IServerEnhancedClientLevel; -import com.seibel.distanthorizons.core.level.IEnhancedServerManager; +import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel; +import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager; import com.seibel.distanthorizons.core.world.*; -import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IFriendlyByteBuf; import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; import com.seibel.distanthorizons.core.level.IDhClientLevel; import com.seibel.distanthorizons.core.config.Config; @@ -45,20 +44,19 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftCli import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; +import io.netty.buffer.ByteBuf; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.glfw.GLFW; -import java.nio.charset.Charset; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeUnit; /** * This holds the methods that should be called * by the host mod loader (Fabric, Forge, etc.). * Specifically for the client. - * - * @author James Seibel - * @version 2022-9-16 */ public class ClientApi { @@ -70,8 +68,7 @@ public class ClientApi public static TestRenderer testRenderer = new TestRenderer(); private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); - private static final IEnhancedServerManager ENHANCED_SERVER_MANAGER - = SingletonInjector.INSTANCE.get(IEnhancedServerManager.class); + private static final IKeyedClientLevelManager KEYED_CLIENT_LEVEL_MANAGER = SingletonInjector.INSTANCE.get(IKeyedClientLevelManager.class); public static final long SPAM_LOGGER_FLUSH_NS = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS); @@ -131,8 +128,8 @@ public class ClientApi } this.isServerCommunicationEnabled = false; this.serverIsMalformed = false; - ENHANCED_SERVER_MANAGER.setUseOverrideWrapper(false); - ENHANCED_SERVER_MANAGER.registerServerEnhancedLevel(null); + KEYED_CLIENT_LEVEL_MANAGER.setUseOverrideWrapper(false); + KEYED_CLIENT_LEVEL_MANAGER.setServerKeyedLevel(null); } } @@ -177,15 +174,21 @@ public class ClientApi public void clientLevelLoadEvent(IClientLevelWrapper level) { - if (ENABLE_EVENT_LOGGING) { - if (this.isServerCommunicationEnabled) { + if (this.isServerCommunicationEnabled) + { + if (ENABLE_EVENT_LOGGING) + { LOGGER.info("Server supports communication, deferring loading."); - return; } - + return; + } + + + if (ENABLE_EVENT_LOGGING) + { LOGGER.info("Client level " + level + " loading."); } - + AbstractDhWorld world = SharedApi.getAbstractDhWorld(); if (world != null) { @@ -194,11 +197,11 @@ public class ClientApi } } - public void serverLevelLoadEvent(IServerEnhancedClientLevel level) + public void serverLevelLoadEvent(IServerKeyedClientLevel level) { if (ENABLE_EVENT_LOGGING) { - LOGGER.info("Server level " + level + " (" + level.getServerWorldKey() + ") loading."); + LOGGER.info("Server level " + level + " (" + level.getServerLevelKey() + ") loading."); } AbstractDhWorld world = SharedApi.getAbstractDhWorld(); @@ -258,54 +261,65 @@ public class ClientApi } profiler.pop(); } - - public void serverMessageReceived(IFriendlyByteBuf buf) + + /** @param byteBuf is Netty's {@link ByteBuffer} wrapper. */ + public void serverMessageReceived(ByteBuf byteBuf) { // It is important to ensure malicious server input is ignored. - if(this.serverIsMalformed) { + if (this.serverIsMalformed) + { return; } - short commandLength = buf.readShort(); - if(commandLength > 32) { + + short commandLength = byteBuf.readShort(); + if (commandLength > 32) + { LOGGER.error("Server sent command > 32"); ClientApi.INSTANCE.serverIsMalformed = true; return; } - String eventType = buf.readCharSequence(commandLength, Charset.forName("UTF-8")).toString(); - switch(eventType) { + + String eventType = byteBuf.readCharSequence(commandLength, StandardCharsets.UTF_8).toString(); + switch (eventType) + { case "ServerCommsEnabled": LOGGER.info("Server supports DH protocol."); ClientApi.INSTANCE.isServerCommunicationEnabled = true; - ENHANCED_SERVER_MANAGER.setUseOverrideWrapper(true); - MC.execute(() -> { + KEYED_CLIENT_LEVEL_MANAGER.setUseOverrideWrapper(true); + MC.executeOnRenderThread(() -> { // Go ahead and unload the current world, because it may be wrong. We expect // a followup WorldChanged event from the server soon anyways. - clientLevelUnloadEvent((IClientLevelWrapper) MC.getWrappedClientWorld()); + this.clientLevelUnloadEvent((IClientLevelWrapper) MC.getWrappedClientWorld()); }); break; + case "WorldChanged": - short worldKeyLength = buf.readShort(); - if(worldKeyLength > 128) { + short worldKeyLength = byteBuf.readShort(); + if (worldKeyLength > 128) + { LOGGER.error("Server sent worldKey > 128"); this.serverIsMalformed = true; return; } - String worldKey = buf.readCharSequence(worldKeyLength, Charset.forName("UTF-8")).toString(); - if(!worldKey.matches("[a-zA-Z0-9_]+")) { + + String worldKey = byteBuf.readCharSequence(worldKeyLength, StandardCharsets.UTF_8).toString(); + if (!worldKey.matches("[a-zA-Z0-9_]+")) + { LOGGER.error("Server sent invalid world key name, and is being ignored."); this.isServerCommunicationEnabled = false; this.serverIsMalformed = true; return; } + LOGGER.info("Server sent world change event: " + worldKey); - MC.execute(() -> { - if(MC.getWrappedClientWorld() != null) { - clientLevelUnloadEvent((IClientLevelWrapper) MC.getWrappedClientWorld()); + MC.executeOnRenderThread(() -> { + if (MC.getWrappedClientWorld() != null) + { + this.clientLevelUnloadEvent((IClientLevelWrapper) MC.getWrappedClientWorld()); } - IServerEnhancedClientLevel clientLevel - = ENHANCED_SERVER_MANAGER.getServerEnhancedLevel(MC.getWrappedClientWorld(), worldKey); - ENHANCED_SERVER_MANAGER.registerServerEnhancedLevel(clientLevel); - serverLevelLoadEvent(clientLevel); + IServerKeyedClientLevel clientLevel = KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel(MC.getWrappedClientWorld(), worldKey); + KEYED_CLIENT_LEVEL_MANAGER.setServerKeyedLevel(clientLevel); + this.serverLevelLoadEvent(clientLevel); }); break; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/structure/ClientOnlySaveStructure.java b/core/src/main/java/com/seibel/distanthorizons/core/file/structure/ClientOnlySaveStructure.java index 285009d32..a7ec08d8d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/structure/ClientOnlySaveStructure.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/structure/ClientOnlySaveStructure.java @@ -5,10 +5,11 @@ import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.file.subDimMatching.SubDimensionLevelMatcher; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.api.enums.config.EServerFolderNameMode; -import com.seibel.distanthorizons.core.level.IServerEnhancedClientLevel; +import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel; import com.seibel.distanthorizons.core.util.objects.ParsedIp; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import javax.annotation.Nullable; @@ -26,17 +27,17 @@ public class ClientOnlySaveStructure extends AbstractSaveStructure { final File folder; private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); + private static final IMinecraftSharedWrapper MC_SHARED = SingletonInjector.INSTANCE.get(IMinecraftSharedWrapper.class); public static final String INVALID_FILE_CHARACTERS_REGEX = "[\\\\/:*?\"<>|]"; - SubDimensionLevelMatcher fileMatcher = null; - final HashMap levelToFileMap = new HashMap<>(); + SubDimensionLevelMatcher subDimMatcher = null; + final HashMap levelWrapperToFileMap = new HashMap<>(); public ClientOnlySaveStructure() { - this.folder = new File(MC_CLIENT.getGameDirectory().getPath() + - File.separatorChar + "Distant_Horizons_server_data" + File.separatorChar + getServerFolderName()); + this.folder = new File(getSaveStructureFolderPath()); if (!this.folder.exists()) { @@ -55,42 +56,51 @@ public class ClientOnlySaveStructure extends AbstractSaveStructure //================// @Override - public File getLevelFolder(ILevelWrapper level) + public File getLevelFolder(ILevelWrapper levelWrapper) { - return this.levelToFileMap.computeIfAbsent(level, (newLevel) -> + return this.levelWrapperToFileMap.computeIfAbsent(levelWrapper, (newLevelWrapper) -> { - if (newLevel instanceof IServerEnhancedClientLevel) { - IServerEnhancedClientLevel secl = (IServerEnhancedClientLevel) newLevel; + // Use the server provided key if one was provided + if (newLevelWrapper instanceof IServerKeyedClientLevel) + { + IServerKeyedClientLevel keyedClientLevel = (IServerKeyedClientLevel) newLevelWrapper; + LOGGER.info("Loading level "+newLevelWrapper.getDimensionType().getDimensionName()+" with key: "+keyedClientLevel.getServerLevelKey()); // This world was identified by the server directly, so we can know for sure which folder to use. - File seclFolder = new File(this.folder.getParent(), MC_CLIENT.getCurrentServerIp().toString()); - seclFolder = new File(seclFolder, secl.getServerWorldKey()); - return seclFolder; + return new File(getSaveStructureFolderPath() + File.separatorChar + keyedClientLevel.getServerLevelKey()); } - - if (Config.Client.Advanced.Multiplayer.multiverseSimilarityRequiredPercent.get() == 0) + + + // use multiverse matching if enabled + if (Config.Client.Advanced.Multiplayer.multiverseSimilarityRequiredPercent.get() != 0) { - if (this.fileMatcher != null) + // create the matcher if one doesn't exist + if (this.subDimMatcher == null || !this.subDimMatcher.isFindingLevel(newLevelWrapper)) { - this.fileMatcher.close(); - this.fileMatcher = null; + LOGGER.info("Loading level " + newLevelWrapper.getDimensionType().getDimensionName()); + this.subDimMatcher = new SubDimensionLevelMatcher(newLevelWrapper, this.folder, + this.getMatchingLevelFolders(newLevelWrapper).toArray(new File[0] /* surprisingly we don't need to create an array of any specific size for this to work */)); } - return this.getLevelFolderWithoutSimilarityMatching(newLevel); + + File levelFile = this.subDimMatcher.tryGetLevel(); + if (levelFile != null) + { + this.subDimMatcher.close(); + this.subDimMatcher = null; + } + return levelFile; } - - if (this.fileMatcher == null || !this.fileMatcher.isFindingLevel(newLevel)) + + // we aren't using multiverse matching, shut down the matcher + // TODO this additional call may not be needed + if (this.subDimMatcher != null) { - LOGGER.info("Loading level for world " + newLevel.getDimensionType().getDimensionName()); - this.fileMatcher = new SubDimensionLevelMatcher(newLevel, this.folder, - this.getMatchingLevelFolders(newLevel).toArray(new File[0] /* surprisingly we don't need to create an array of any specific size for this to work */)); + this.subDimMatcher.close(); + this.subDimMatcher = null; } - - File levelFile = this.fileMatcher.tryGetLevel(); - if (levelFile != null) - { - this.fileMatcher.close(); - this.fileMatcher = null; - } - return levelFile; + + + // get the default folder + return this.getLevelFolderWithoutSimilarityMatching(newLevelWrapper); }); } @@ -138,7 +148,7 @@ public class ClientOnlySaveStructure extends AbstractSaveStructure @Override public File getRenderCacheFolder(ILevelWrapper level) { - File levelFolder = this.levelToFileMap.get(level); + File levelFolder = this.levelWrapperToFileMap.get(level); if (levelFolder == null) { return null; @@ -150,7 +160,7 @@ public class ClientOnlySaveStructure extends AbstractSaveStructure @Override public File getFullDataFolder(ILevelWrapper level) { - File levelFolder = this.levelToFileMap.get(level); + File levelFolder = this.levelWrapperToFileMap.get(level); if (levelFolder == null) { return null; @@ -182,7 +192,16 @@ public class ClientOnlySaveStructure extends AbstractSaveStructure // a valid level folder needs to have DH specific folders in it return files != null && files.length != 0; } - + + + private static String getSaveStructureFolderPath() + { + String path = MC_SHARED.getInstallationDirectory().getPath() + File.separatorChar + + "Distant_Horizons_server_data" + File.separatorChar + + getServerFolderName(); + return path; + } + /** Generated from the server the client is currently connected to. */ private static String getServerFolderName() { @@ -222,15 +241,15 @@ public class ClientOnlySaveStructure extends AbstractSaveStructure // This fixes some issues when the server is named something in other languages return new PercentEscaper("", true).escape(folderName); } - - - + + + //==================// // override methods // //==================// @Override - public void close() { this.fileMatcher.close(); } + public void close() { this.subDimMatcher.close(); } @Override public String toString() { return "[" + this.getClass().getSimpleName() + "@" + this.folder.getName() + "]"; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/IEnhancedServerManager.java b/core/src/main/java/com/seibel/distanthorizons/core/level/IEnhancedServerManager.java deleted file mode 100644 index b24cdaf5b..000000000 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/IEnhancedServerManager.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.seibel.distanthorizons.core.level; - -import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; -import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable; - -public interface IEnhancedServerManager extends IBindable { - /** - * Called when a client level is wrapped by a ServerEnhancedClientLevel, for integration into mod internals. - * @param clientLevel - */ - void registerServerEnhancedLevel(IServerEnhancedClientLevel clientLevel); - - /** - * Returns a new instance of a ServerEnhancedClientLevel. - * @param level - * @param worldKey - * @return - */ - IServerEnhancedClientLevel getServerEnhancedLevel(ILevelWrapper level, String worldKey); - - /** - * Sets the LOD engine to use the override wrapper, if the server has communication enabled. - * @param useOverrideWrapper - */ - void setUseOverrideWrapper(boolean useOverrideWrapper); -} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/IKeyedClientLevelManager.java b/core/src/main/java/com/seibel/distanthorizons/core/level/IKeyedClientLevelManager.java new file mode 100644 index 000000000..b8e6a324e --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/IKeyedClientLevelManager.java @@ -0,0 +1,24 @@ +package com.seibel.distanthorizons.core.level; + +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; +import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable; + +/** + * Handles level overrides initiated by servers that + * support differentiating between different levels. + */ +public interface IKeyedClientLevelManager extends IBindable +{ + /** Called when a client level is wrapped by a ServerEnhancedClientLevel, for integration into mod internals. */ + void setServerKeyedLevel(IServerKeyedClientLevel clientLevel); + IServerKeyedClientLevel getOverrideWrapper(); + + /** Returns a new instance of a ServerEnhancedClientLevel. */ + IServerKeyedClientLevel getServerKeyedLevel(ILevelWrapper level, String serverLevelKey); + + /** Sets the LOD engine to use the override wrapper, if the server has communication enabled. */ + void setUseOverrideWrapper(boolean useOverrideWrapper); + boolean getUseOverrideWrapper(); + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/IServerEnhancedClientLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/IServerEnhancedClientLevel.java deleted file mode 100644 index 7f50aad1d..000000000 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/IServerEnhancedClientLevel.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.seibel.distanthorizons.core.level; - -import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; - -/** - * Enhances an IClientLevelWrapper with server provided world information. - */ -public interface IServerEnhancedClientLevel extends IClientLevelWrapper -{ - /** - * Returns the world key, which is used to select the correct folder on the client. - * @return - */ - String getServerWorldKey(); -} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/IServerKeyedClientLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/IServerKeyedClientLevel.java new file mode 100644 index 000000000..24577e59e --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/IServerKeyedClientLevel.java @@ -0,0 +1,11 @@ +package com.seibel.distanthorizons.core.level; + +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; + +/** Enhances a {@link IClientLevelWrapper} with server provided level information. */ +public interface IServerKeyedClientLevel extends IClientLevelWrapper +{ + /** Returns the level key, which is used to select the correct folder on the client. */ + String getServerLevelKey(); + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IFriendlyByteBuf.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IFriendlyByteBuf.java deleted file mode 100644 index fac5fac2b..000000000 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IFriendlyByteBuf.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.seibel.distanthorizons.core.wrapperInterfaces.minecraft; - -import java.nio.charset.Charset; - -/** - * Interface that wraps the net.minecraft.network.FriendlyByteBuffer. - */ -public interface IFriendlyByteBuf { - - short readShort(); - - CharSequence readCharSequence(int length, Charset charset); -} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java index 57f8b573a..05f4e8979 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java @@ -139,10 +139,7 @@ public interface IMinecraftClientWrapper extends IBindable Object getOptionsObject(); - /** - * Executes a task on the Minecraft render thread. - * @param runnable - */ - void execute(Runnable runnable); + /** Executes the given task on Minecraft's render thread. */ + void executeOnRenderThread(Runnable runnable); }