From efc2ce84e48ae6f9380fe9c5721d6883bd362a23 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 25 Nov 2023 11:39:39 -0600 Subject: [PATCH] Fix null pointer when joining some multiverse servers --- .../core/api/internal/ClientApi.java | 125 ++++++++++++------ .../core/world/DhClientServerWorld.java | 7 +- .../core/world/DhClientWorld.java | 7 +- .../core/world/DhServerWorld.java | 7 +- .../distanthorizons/core/world/IDhWorld.java | 7 +- 5 files changed, 97 insertions(+), 56 deletions(-) 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 acb18b5f9..31aa4be55 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 @@ -48,6 +48,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapp //import io.netty.buffer.ByteBuf; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; import java.nio.ByteBuffer; @@ -160,46 +161,73 @@ public class ClientApi // level events // //==============// - public void clientLevelUnloadEvent(IClientLevelWrapper level) + public void clientLevelUnloadEvent(@Nullable IClientLevelWrapper level) { - LOGGER.info("Unloading client level [" + level + "]."); - - AbstractDhWorld world = SharedApi.getAbstractDhWorld(); - if (world != null) + try { - world.unloadLevel(level); - ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(level)); + if (level == null) + { + // can happen on certain multiverse servers + return; + } + LOGGER.info("Unloading client level [" + level + "]."); + + AbstractDhWorld world = SharedApi.getAbstractDhWorld(); + if (world != null) + { + world.unloadLevel(level); + ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelUnloadEvent.class, new DhApiLevelUnloadEvent.EventParam(level)); + } + else + { + this.waitingClientLevels.remove(level); + } } - else + catch (Exception e) { - this.waitingClientLevels.remove(level); + // handle errors here to prevent blowing up a mixin or API up stream + LOGGER.error("Unexpected error in ClientApi.clientLevelUnloadEvent(), error: "+e.getMessage(), e); } } - public void clientLevelLoadEvent(IClientLevelWrapper level) { this.clientLevelLoadEvent(level, false); } - public void multiverseClientLevelLoadEvent(IClientLevelWrapper level) { this.clientLevelLoadEvent(level, true); } - private void clientLevelLoadEvent(IClientLevelWrapper level, boolean isServerCommunication) + public void clientLevelLoadEvent(@Nullable IClientLevelWrapper level) { this.clientLevelLoadEvent(level, false); } + public void multiverseClientLevelLoadEvent(@Nullable IClientLevelWrapper level) { this.clientLevelLoadEvent(level, true); } + private void clientLevelLoadEvent(@Nullable IClientLevelWrapper level, boolean isServerCommunication) { - if (this.isServerCommunicationEnabled && !isServerCommunication) + try { - LOGGER.info("Server supports communication, deferring loading."); - return; - } - - - LOGGER.info("Loading " + (isServerCommunication ? "Multiverse" : "") + " client level [" + level + "]."); - - AbstractDhWorld world = SharedApi.getAbstractDhWorld(); - if (world != null) - { - world.getOrLoadLevel(level); - ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(level)); + if (this.isServerCommunicationEnabled && !isServerCommunication) + { + LOGGER.info("Server supports communication, deferring loading."); + return; + } + if (level == null) + { + // can happen on certain multiverse servers + return; + } - this.loadWaitingChunksForLevel(level); + + + LOGGER.info("Loading " + (isServerCommunication ? "Multiverse" : "") + " client level [" + level + "]."); + + AbstractDhWorld world = SharedApi.getAbstractDhWorld(); + if (world != null) + { + world.getOrLoadLevel(level); + ApiEventInjector.INSTANCE.fireAllEvents(DhApiLevelLoadEvent.class, new DhApiLevelLoadEvent.EventParam(level)); + + this.loadWaitingChunksForLevel(level); + } + else + { + this.waitingClientLevels.add(level); + } } - else + catch (Exception e) { - this.waitingClientLevels.add(level); + // handle errors here to prevent blowing up a mixin or API up stream + LOGGER.error("Unexpected error in ClientApi.clientLevelLoadEvent(), error: "+e.getMessage(), e); } } private void loadWaitingChunksForLevel(IClientLevelWrapper level) @@ -257,26 +285,35 @@ public class ClientApi IProfilerWrapper profiler = MC.getProfiler(); profiler.push("DH-ClientTick"); - boolean doFlush = System.nanoTime() - this.lastFlushNanoTime >= SPAM_LOGGER_FLUSH_NS; - if (doFlush) + try { - this.lastFlushNanoTime = System.nanoTime(); - SpamReducedLogger.flushAll(); - } - ConfigBasedLogger.updateAll(); - ConfigBasedSpamLogger.updateAll(doFlush); - - IDhClientWorld clientWorld = SharedApi.getIDhClientWorld(); - if (clientWorld != null) - { - clientWorld.clientTick(); - - // Ignore local world gen, as it's managed by server ticking - if (!(clientWorld instanceof DhClientServerWorld)) + boolean doFlush = System.nanoTime() - this.lastFlushNanoTime >= SPAM_LOGGER_FLUSH_NS; + if (doFlush) { - SharedApi.worldGenTick(clientWorld::doWorldGen); + this.lastFlushNanoTime = System.nanoTime(); + SpamReducedLogger.flushAll(); + } + ConfigBasedLogger.updateAll(); + ConfigBasedSpamLogger.updateAll(doFlush); + + IDhClientWorld clientWorld = SharedApi.getIDhClientWorld(); + if (clientWorld != null) + { + clientWorld.clientTick(); + + // Ignore local world gen, as it's managed by server ticking + if (!(clientWorld instanceof DhClientServerWorld)) + { + SharedApi.worldGenTick(clientWorld::doWorldGen); + } } } + catch (Exception e) + { + // handle errors here to prevent blowing up a mixin or API up stream + LOGGER.error("Unexpected error in ClientApi.clientTickEvent(), error: "+e.getMessage(), e); + } + profiler.pop(); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/world/DhClientServerWorld.java b/core/src/main/java/com/seibel/distanthorizons/core/world/DhClientServerWorld.java index 6d64be5ca..c0584ced3 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/world/DhClientServerWorld.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/world/DhClientServerWorld.java @@ -29,6 +29,7 @@ import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.util.HashMap; @@ -69,7 +70,7 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor //=========// @Override - public DhClientServerLevel getOrLoadLevel(ILevelWrapper wrapper) + public DhClientServerLevel getOrLoadLevel(@NotNull ILevelWrapper wrapper) { if (wrapper instanceof IServerLevelWrapper) { @@ -105,13 +106,13 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor } @Override - public DhClientServerLevel getLevel(ILevelWrapper wrapper) { return this.levelWrapperByDhLevel.get(wrapper); } + public DhClientServerLevel getLevel(@NotNull ILevelWrapper wrapper) { return this.levelWrapperByDhLevel.get(wrapper); } @Override public Iterable getAllLoadedLevels() { return this.dhLevels; } @Override - public void unloadLevel(ILevelWrapper wrapper) + public void unloadLevel(@NotNull ILevelWrapper wrapper) { if (this.levelWrapperByDhLevel.containsKey(wrapper)) { 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 9daa63b94..7aa0e7a64 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 @@ -35,6 +35,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftCli import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.util.concurrent.CompletableFuture; @@ -111,7 +112,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld //=========// @Override - public DhClientLevel getOrLoadLevel(ILevelWrapper wrapper) + public DhClientLevel getOrLoadLevel(@NotNull ILevelWrapper wrapper) { if (!(wrapper instanceof IClientLevelWrapper)) { @@ -132,7 +133,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld } @Override - public DhClientLevel getLevel(ILevelWrapper wrapper) + public DhClientLevel getLevel(@NotNull ILevelWrapper wrapper) { if (!(wrapper instanceof IClientLevelWrapper)) { @@ -146,7 +147,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld public Iterable getAllLoadedLevels() { return this.levels.values(); } @Override - public void unloadLevel(ILevelWrapper wrapper) + public void unloadLevel(@NotNull ILevelWrapper wrapper) { if (!(wrapper instanceof IClientLevelWrapper)) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/world/DhServerWorld.java b/core/src/main/java/com/seibel/distanthorizons/core/world/DhServerWorld.java index 58c5d73fa..4d35d79b8 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/world/DhServerWorld.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/world/DhServerWorld.java @@ -32,6 +32,7 @@ import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; +import org.jetbrains.annotations.NotNull; //import io.netty.channel.ChannelHandlerContext; import java.io.File; @@ -138,7 +139,7 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld } @Override - public DhServerLevel getOrLoadLevel(ILevelWrapper wrapper) + public DhServerLevel getOrLoadLevel(@NotNull ILevelWrapper wrapper) { if (!(wrapper instanceof IServerLevelWrapper)) { @@ -154,7 +155,7 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld } @Override - public DhServerLevel getLevel(ILevelWrapper wrapper) + public DhServerLevel getLevel(@NotNull ILevelWrapper wrapper) { if (!(wrapper instanceof IServerLevelWrapper)) { @@ -168,7 +169,7 @@ public class DhServerWorld extends AbstractDhWorld implements IDhServerWorld public Iterable getAllLoadedLevels() { return this.levels.values(); } @Override - public void unloadLevel(ILevelWrapper wrapper) + public void unloadLevel(@NotNull ILevelWrapper wrapper) { if (!(wrapper instanceof IServerLevelWrapper)) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/world/IDhWorld.java b/core/src/main/java/com/seibel/distanthorizons/core/world/IDhWorld.java index 388929e89..dd631015c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/world/IDhWorld.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/world/IDhWorld.java @@ -21,17 +21,18 @@ package com.seibel.distanthorizons.core.world; import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; +import org.jetbrains.annotations.NotNull; import java.util.concurrent.CompletableFuture; public interface IDhWorld { - IDhLevel getOrLoadLevel(ILevelWrapper levelWrapper); - IDhLevel getLevel(ILevelWrapper wrapper); + IDhLevel getOrLoadLevel(@NotNull ILevelWrapper levelWrapper); + IDhLevel getLevel(@NotNull ILevelWrapper wrapper); Iterable getAllLoadedLevels(); - void unloadLevel(ILevelWrapper levelWrapper); + void unloadLevel(@NotNull ILevelWrapper levelWrapper); CompletableFuture saveAndFlush();