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.
This commit is contained in:
@@ -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.ServerEnhancedManager;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftDedicatedServerWrapper;
|
||||
import com.seibel.distanthorizons.core.level.IServerEnhancedManager;
|
||||
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(IServerEnhancedManager.class, ServerEnhancedManager.INSTANCE);
|
||||
DependencySetupDoneCheck.isDone = true;
|
||||
}
|
||||
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.level;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.level.IServerEnhancedClientLevel;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
|
||||
public class ServerEnhancedClientLevel extends ClientLevelWrapper implements IServerEnhancedClientLevel {
|
||||
|
||||
private final String serverKey;
|
||||
|
||||
public ServerEnhancedClientLevel(ClientLevel level, String serverKey) {
|
||||
super(level);
|
||||
this.serverKey = serverKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerWorldKey() {
|
||||
return this.serverKey;
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.level;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.level.IServerEnhancedClientLevel;
|
||||
import com.seibel.distanthorizons.core.level.IServerEnhancedManager;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import org.apache.logging.log4j.core.jmx.Server;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class ServerEnhancedManager implements IServerEnhancedManager {
|
||||
|
||||
public static ServerEnhancedManager INSTANCE = new ServerEnhancedManager();
|
||||
|
||||
@Override
|
||||
public void registerServerEnhancedLevel(IServerEnhancedClientLevel clientLevel) {
|
||||
ClientLevelWrapper.setWrappedLevel(clientLevel);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public IServerEnhancedClientLevel getServerEnhancedLevel(ILevelWrapper level, String worldKey) {
|
||||
Objects.requireNonNull(level);
|
||||
Objects.requireNonNull(worldKey);
|
||||
return new ServerEnhancedClientLevel((ClientLevel) level.getWrappedMcObject(), worldKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUseOverrideWrapper(boolean useOverrideWrapper) {
|
||||
ClientLevelWrapper.setUseOverrideWrapper(useOverrideWrapper);
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.minecraft;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IFriendlyByteBuf;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class FriendlyByteBufWrapper implements IFriendlyByteBuf
|
||||
{
|
||||
private final FriendlyByteBuf buf;
|
||||
|
||||
public FriendlyByteBufWrapper(FriendlyByteBuf buf) {
|
||||
this.buf = buf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readShort()
|
||||
{
|
||||
return buf.readShort();
|
||||
}
|
||||
|
||||
public CharSequence readCharSequence(int length, Charset charset)
|
||||
{
|
||||
return buf.readCharSequence(length, charset);
|
||||
}
|
||||
}
|
||||
+6
-1
@@ -180,7 +180,7 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
||||
return null;
|
||||
}
|
||||
|
||||
return ClientLevelWrapper.getWrapper(mc.level);
|
||||
return ClientLevelWrapper.getOriginalWrapper(mc.level);
|
||||
}
|
||||
|
||||
/** Please move over to getInstallationDirectory() */
|
||||
@@ -261,4 +261,9 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
||||
public File getInstallationDirectory() {
|
||||
return mc.gameDirectory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable runnable) {
|
||||
mc.execute(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
+34
-2
@@ -38,7 +38,34 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
||||
private static final ConcurrentHashMap<ClientLevel, ClientLevelWrapper>
|
||||
levelWrapperMap = new ConcurrentHashMap<>();
|
||||
|
||||
public static ClientLevelWrapper getWrapper(ClientLevel level) {
|
||||
/**
|
||||
* This is set and managed by the ClientApi for servers with support for DH.
|
||||
*/
|
||||
private static IClientLevelWrapper overrideWrapper = null;
|
||||
private static boolean useOverrideWrapper = false;
|
||||
|
||||
public static void setWrappedLevel(IClientLevelWrapper wrapper) {
|
||||
overrideWrapper = wrapper;
|
||||
}
|
||||
|
||||
public static void setUseOverrideWrapper(boolean useOverrideWrapper) {
|
||||
ClientLevelWrapper.useOverrideWrapper = useOverrideWrapper;
|
||||
}
|
||||
|
||||
public static IClientLevelWrapper getWrapper(ClientLevel level) {
|
||||
if(useOverrideWrapper) {
|
||||
return overrideWrapper;
|
||||
}
|
||||
return getOriginalWrapper(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original level wrapper, regardless of whether or not the server is overriding the
|
||||
* level wrapper.
|
||||
* @param level
|
||||
* @return
|
||||
*/
|
||||
public static IClientLevelWrapper getOriginalWrapper(ClientLevel level) {
|
||||
return levelWrapperMap.computeIfAbsent(level, ClientLevelWrapper::new);
|
||||
}
|
||||
public static void closeWrapper(ClientLevel level)
|
||||
@@ -46,9 +73,11 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
||||
levelWrapperMap.remove(level);
|
||||
}
|
||||
|
||||
private ClientLevelWrapper(ClientLevel level) {
|
||||
protected ClientLevelWrapper(ClientLevel level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
|
||||
final ClientLevel level;
|
||||
ClientBlockDetailMap blockMap = new ClientBlockDetailMap(this);
|
||||
@Nullable
|
||||
@@ -184,6 +213,9 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if(level == null) {
|
||||
return "Wrapped{null}";
|
||||
}
|
||||
return "Wrapped{" + level.toString() + "@" + getDimensionType().getDimensionName() + "}";
|
||||
}
|
||||
|
||||
|
||||
+1
-1
Submodule coreSubProjects updated: d04b4c0d55...368541b09c
@@ -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}")
|
||||
|
||||
@@ -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_1 // 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
|
||||
|
||||
@@ -2,20 +2,29 @@ package com.seibel.distanthorizons.fabric;
|
||||
|
||||
import com.seibel.distanthorizons.common.networking.Networking;
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.FriendlyByteBufWrapper;
|
||||
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.level.IServerEnhancedManager;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.level.ServerEnhancedClientLevel;
|
||||
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 +44,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<Boolean> 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 +95,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 +112,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 +132,14 @@ public class FabricServerProxy
|
||||
}
|
||||
});
|
||||
// ServerChunkSaveEvent - Done in MixinChunkMap
|
||||
|
||||
ClientPlayNetworking.registerGlobalReceiver(new ResourceLocation("distant_horizons", "world_control"),
|
||||
(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf, PacketSender responseSender) ->
|
||||
{
|
||||
ClientApi.INSTANCE.serverMessageReceived(new FriendlyByteBufWrapper(buf));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 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 +151,5 @@ public class FabricServerProxy
|
||||
Networking.send(player, payload);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user