diff --git a/build.gradle b/build.gradle index 03e379fcf..8c8e47f19 100644 --- a/build.gradle +++ b/build.gradle @@ -203,7 +203,9 @@ subprojects { p -> // SVG shadowMe("com.formdev:svgSalamander:${rootProject.svgSalamander_version}") shadowMe("com.formdev:flatlaf-extras:${rootProject.flatlaf_version}") - + + // Netty + shadowMe("io.netty:netty-all:4.1.94.Final") // Remember, for lwjgl dependancies that arent included in Minecraft, you need to also need to add it to the ShadowJar thing shadowMe("org.lwjgl:lwjgl-jawt:3.2.2") { diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java index ec01f988b..a3d513e41 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java @@ -20,7 +20,9 @@ package com.seibel.distanthorizons.common.wrappers; import com.seibel.distanthorizons.common.wrappers.gui.LangWrapper; +import com.seibel.distanthorizons.common.wrappers.level.KeyedClientLevelManager; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftDedicatedServerWrapper; +import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager; import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper; @@ -49,6 +51,7 @@ public class DependencySetup { SingletonInjector.INSTANCE.bind(ILangWrapper.class, LangWrapper.INSTANCE); SingletonInjector.INSTANCE.bind(IVersionConstants.class, VersionConstants.INSTANCE); SingletonInjector.INSTANCE.bind(IWrapperFactory.class, WrapperFactory.INSTANCE); + SingletonInjector.INSTANCE.bind(IKeyedClientLevelManager.class, KeyedClientLevelManager.INSTANCE); DependencySetupDoneCheck.isDone = true; } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/level/KeyedClientLevelManager.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/level/KeyedClientLevelManager.java new file mode 100644 index 000000000..b0de02033 --- /dev/null +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/level/KeyedClientLevelManager.java @@ -0,0 +1,54 @@ +package com.seibel.distanthorizons.common.wrappers.level; + +import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; +import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel; +import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; +import net.minecraft.client.multiplayer.ClientLevel; + +import java.util.Objects; + +public class KeyedClientLevelManager implements IKeyedClientLevelManager +{ + public static final KeyedClientLevelManager INSTANCE = new KeyedClientLevelManager(); + + /** This is set and managed by the ClientApi for servers with support for DH. */ + private IServerKeyedClientLevel overrideWrapper = null; + private boolean useOverrideWrapper = false; + + + //=============// + // constructor // + //=============// + + private KeyedClientLevelManager() { } + + + + //======================// + // level override logic // + //======================// + + @Override + public void setServerKeyedLevel(IServerKeyedClientLevel clientLevel) { this.overrideWrapper = clientLevel; } + @Override + public IServerKeyedClientLevel getOverrideWrapper() { return this.overrideWrapper; } + + @Override + public IServerKeyedClientLevel getServerKeyedLevel(ILevelWrapper level, String serverLevelKey) + { + Objects.requireNonNull(level); + Objects.requireNonNull(serverLevelKey); + return new ServerKeyedClientLevel((ClientLevel) level.getWrappedMcObject(), serverLevelKey); + } + + + @Override + public void setUseOverrideWrapper(boolean useOverrideWrapper) { this.useOverrideWrapper = useOverrideWrapper; } + @Override + public boolean getUseOverrideWrapper() { return this.useOverrideWrapper; } + + + +} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/level/ServerKeyedClientLevel.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/level/ServerKeyedClientLevel.java new file mode 100644 index 000000000..86048c145 --- /dev/null +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/level/ServerKeyedClientLevel.java @@ -0,0 +1,21 @@ +package com.seibel.distanthorizons.common.wrappers.level; + +import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; +import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel; +import net.minecraft.client.multiplayer.ClientLevel; + +public class ServerKeyedClientLevel extends ClientLevelWrapper implements IServerKeyedClientLevel +{ + /** A unique identifier (generally the level's name) for differentiating multiverse levels */ + private final String serverLevelKey; + + public ServerKeyedClientLevel(ClientLevel level, String serverLevelKey) + { + super(level); + this.serverLevelKey = serverLevelKey; + } + + @Override + public String getServerLevelKey() { return this.serverLevelKey; } + +} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftClientWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftClientWrapper.java index 402b10ac5..bc9aa7930 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftClientWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftClientWrapper.java @@ -180,7 +180,7 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra return null; } - return ClientLevelWrapper.getWrapper(mc.level); + return ClientLevelWrapper.getWrapperIgnoringOverride(this.mc.level); } /** Please move over to getInstallationDirectory() */ @@ -261,4 +261,8 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra public File getInstallationDirectory() { return mc.gameDirectory; } + + @Override + public void executeOnRenderThread(Runnable runnable) { this.mc.execute(runnable); } + } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java index 89d05d57c..53158f0cd 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java @@ -8,6 +8,8 @@ import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; import com.seibel.distanthorizons.common.wrappers.block.cache.ClientBlockDetailMap; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhBlockPos; import com.seibel.distanthorizons.core.pos.DhChunkPos; @@ -28,30 +30,48 @@ import org.jetbrains.annotations.Nullable; import java.util.concurrent.ConcurrentHashMap; -/** - * - * @version 2023-6-3 - */ public class ClientLevelWrapper implements IClientLevelWrapper { private static final Logger LOGGER = DhLoggerBuilder.getLogger(ClientLevelWrapper.class.getSimpleName()); - private static final ConcurrentHashMap - levelWrapperMap = new ConcurrentHashMap<>(); - - public static ClientLevelWrapper getWrapper(ClientLevel level) { - return levelWrapperMap.computeIfAbsent(level, ClientLevelWrapper::new); - } - public static void closeWrapper(ClientLevel level) - { - levelWrapperMap.remove(level); - } - - private ClientLevelWrapper(ClientLevel level) { - this.level = level; - } - final ClientLevel level; - ClientBlockDetailMap blockMap = new ClientBlockDetailMap(this); - @Nullable + private static final ConcurrentHashMap LEVEL_WRAPPER_BY_CLIENT_LEVEL = new ConcurrentHashMap<>(); + private static final IKeyedClientLevelManager KEYED_CLIENT_LEVEL_MANAGER = SingletonInjector.INSTANCE.get(IKeyedClientLevelManager.class); + + private final ClientLevel level; + private final ClientBlockDetailMap blockMap = new ClientBlockDetailMap(this); + + + + //=============// + // constructor // + //=============// + + protected ClientLevelWrapper(ClientLevel level) { this.level = level; } + + + + //===============// + // wrapper logic // + //===============// + + public static IClientLevelWrapper getWrapper(ClientLevel level) + { + // used if the client is connected to a server that defines the currently loaded level + if (KEYED_CLIENT_LEVEL_MANAGER.getUseOverrideWrapper()) + { + return KEYED_CLIENT_LEVEL_MANAGER.getOverrideWrapper(); + } + + return getWrapperIgnoringOverride(level); + } + public static IClientLevelWrapper getWrapperIgnoringOverride(ClientLevel level) + { + return LEVEL_WRAPPER_BY_CLIENT_LEVEL.computeIfAbsent(level, ClientLevelWrapper::new); + } + + public static void closeLevel(ClientLevel level) { LEVEL_WRAPPER_BY_CLIENT_LEVEL.remove(level); } + + + @Nullable @Override public IServerLevelWrapper tryGetServerSideWrapper() { @@ -89,12 +109,18 @@ public class ClientLevelWrapper implements IClientLevelWrapper } } public static void cleanCheck() { - if (!levelWrapperMap.isEmpty()) { - LOGGER.warn("{} client levels havn't been freed!", levelWrapperMap.size()); - levelWrapperMap.clear(); + if (!LEVEL_WRAPPER_BY_CLIENT_LEVEL.isEmpty()) { + LOGGER.warn("{} client levels havn't been freed!", LEVEL_WRAPPER_BY_CLIENT_LEVEL.size()); + LEVEL_WRAPPER_BY_CLIENT_LEVEL.clear(); } } - + + + + //====================// + // base level methods // + //====================// + @Override public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper blockState) { return blockMap.getColor(((BlockStateWrapper)blockState).blockState, @@ -183,8 +209,14 @@ public class ClientLevelWrapper implements IClientLevelWrapper } @Override - public String toString() { - return "Wrapped{" + level.toString() + "@" + getDimensionType().getDimensionName() + "}"; - } + public String toString() + { + if (this.level == null) + { + return "Wrapped{null}"; + } + + return "Wrapped{" + this.level.toString() + "@" + this.getDimensionType().getDimensionName() + "}"; + } } diff --git a/coreSubProjects b/coreSubProjects index b50c2cf9a..2fc74914b 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit b50c2cf9a9220db25f4864481ad33c8ed6244840 +Subproject commit 2fc74914b4707ce4f9d9a509ac8d43671f0fb123 diff --git a/fabric/build.gradle b/fabric/build.gradle index ae5cb6a04..c3fc3acef 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -60,6 +60,7 @@ dependencies { addModJar(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version)) addModJar(fabricApi.module("fabric-rendering-v1", rootProject.fabric_api_version)) // TODO: Remove this as it is only needed in 1 line (FabricClientProxy) addModJar(fabricApi.module("fabric-api-base", rootProject.fabric_api_version)) + addModJar(fabricApi.module("fabric-networking-api-v1", rootProject.fabric_api_version)) // Mod Menu modImplementation("com.terraformersmc:modmenu:${rootProject.modmenu_version}") diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java index 4e67240bb..b987a5b20 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java @@ -31,6 +31,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IImmersivePortalsAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.fabric.wrappers.modAccessor.ImmersivePortalsAccessor; import com.seibel.distanthorizons.fabric.wrappers.modAccessor.SodiumAccessor; import net.fabricmc.api.EnvType; @@ -100,7 +101,7 @@ public class FabricClientProxy //#if PRE_MC_1_18_2 // in 1.18+, we use mixin hook in setClientLightReady(true) ClientChunkEvents.CHUNK_LOAD.register((level, chunk) -> { - ClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level); + IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level); ClientApi.INSTANCE.clientChunkLoadEvent( new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel @@ -119,7 +120,7 @@ public class FabricClientProxy { // LOGGER.info("attack block at blockpos: " + blockPos); - ClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level); + IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level); ClientApi.INSTANCE.clientChunkLoadEvent( new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel @@ -146,7 +147,7 @@ public class FabricClientProxy { // LOGGER.info("use block at blockpos: " + hitResult.getBlockPos()); - ClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level); + IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) level); ClientApi.INSTANCE.clientChunkLoadEvent( new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel @@ -163,7 +164,7 @@ public class FabricClientProxy // ClientChunkSaveEvent ClientChunkEvents.CHUNK_UNLOAD.register((level, chunk) -> { - ClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level); + IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level); ClientApi.INSTANCE.clientChunkSaveEvent( new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricServerProxy.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricServerProxy.java index 71e006f31..3bf1cd435 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricServerProxy.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricServerProxy.java @@ -5,17 +5,23 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; +import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.api.internal.ServerApi; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents; +import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.TitleScreen; import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; @@ -35,50 +41,50 @@ public class FabricServerProxy { private static final ServerApi SERVER_API = ServerApi.INSTANCE; private static final Logger LOGGER = DhLoggerBuilder.getLogger(); - + private final boolean isDedicated; public static Supplier isGenerationThreadChecker = null; - - - + + + public FabricServerProxy(boolean isDedicated) { this.isDedicated = isDedicated; } - - - + + + private boolean isValidTime() { if (isDedicated) { return true; } - + //FIXME: This may cause init issue... return !(Minecraft.getInstance().screen instanceof TitleScreen); } - - private ClientLevelWrapper getClientLevelWrapper(ClientLevel level) { return ClientLevelWrapper.getWrapper(level); } + + private IClientLevelWrapper getClientLevelWrapper(ClientLevel level) { return ClientLevelWrapper.getWrapper(level); } private ServerLevelWrapper getServerLevelWrapper(ServerLevel level) { return ServerLevelWrapper.getWrapper(level); } - + /** Registers Fabric Events */ public void registerEvents() { LOGGER.info("Registering Fabric Server Events"); isGenerationThreadChecker = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread; - + /* Register the mod needed event callbacks */ - + // TEST EVENT //ServerTickEvents.END_SERVER_TICK.register(this::tester); - + // ServerTickEvent ServerTickEvents.END_SERVER_TICK.register((server) -> SERVER_API.serverTickEvent()); - + // ServerWorldLoadEvent //TODO: Check if both of these use the correct timed events. (i.e. is it 'ed' or 'ing' one?) - ServerLifecycleEvents.SERVER_STARTING.register((server) -> + ServerLifecycleEvents.SERVER_STARTING.register((server) -> { if (isValidTime()) { @@ -86,16 +92,16 @@ public class FabricServerProxy } }); // ServerWorldUnloadEvent - ServerLifecycleEvents.SERVER_STOPPED.register((server) -> + ServerLifecycleEvents.SERVER_STOPPED.register((server) -> { if (isValidTime()) { ServerApi.INSTANCE.serverUnloadEvent(); } }); - + // ServerLevelLoadEvent - ServerWorldEvents.LOAD.register((server, level) -> + ServerWorldEvents.LOAD.register((server, level) -> { if (isValidTime()) { @@ -103,16 +109,16 @@ public class FabricServerProxy } }); // ServerLevelUnloadEvent - ServerWorldEvents.UNLOAD.register((server, level) -> + ServerWorldEvents.UNLOAD.register((server, level) -> { if (isValidTime()) { ServerApi.INSTANCE.serverLevelUnloadEvent(getServerLevelWrapper(level)); } }); - + // ServerChunkLoadEvent - ServerChunkEvents.CHUNK_LOAD.register((server, chunk) -> + ServerChunkEvents.CHUNK_LOAD.register((server, chunk) -> { ILevelWrapper level = getServerLevelWrapper((ServerLevel) chunk.getLevel()); if (isValidTime()) @@ -123,8 +129,14 @@ public class FabricServerProxy } }); // ServerChunkSaveEvent - Done in MixinChunkMap + + ClientPlayNetworking.registerGlobalReceiver(new ResourceLocation("distant_horizons", "world_control"), // TODO move these strings into a constant somewhere + (Minecraft client, ClientPacketListener handler, FriendlyByteBuf byteBuffer, PacketSender responseSender) -> + { + ClientApi.INSTANCE.serverMessageReceived(byteBuffer); + }); } - + // This just exists here for testing purposes, it'll be removed in the future public void tester(MinecraftServer server) { // I disabled the Networking functions for now so this will not work atm - coolGi @@ -136,5 +148,5 @@ public class FabricServerProxy Networking.send(player, payload); } } - + } diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java index d1e184feb..be557912a 100644 --- a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java +++ b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java @@ -24,6 +24,7 @@ import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import net.minecraft.world.level.LevelAccessor; import net.minecraft.client.multiplayer.ClientLevel; @@ -95,7 +96,7 @@ public class ForgeClientProxy { if (GetLevel(event) instanceof ClientLevel) { - ClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) GetLevel(event)); + IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) GetLevel(event)); IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetLevel(event), wrappedLevel); ClientApi.INSTANCE.clientChunkLoadEvent(chunk, ClientLevelWrapper.getWrapper((ClientLevel) GetLevel(event))); } @@ -105,7 +106,7 @@ public class ForgeClientProxy { if (GetLevel(event) instanceof ClientLevel) { - ClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) GetLevel(event)); + IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper((ClientLevel) GetLevel(event)); IChunkWrapper chunk = new ChunkWrapper(event.getChunk() , GetLevel(event), wrappedLevel); ClientApi.INSTANCE.clientChunkSaveEvent(chunk, ClientLevelWrapper.getWrapper((ClientLevel) GetLevel(event))); }