diff --git a/src/main/java/me/cortex/voxy/client/core/VoxelCore.java b/src/main/java/me/cortex/voxy/client/core/VoxelCore.java index 84bc3402..0bc27889 100644 --- a/src/main/java/me/cortex/voxy/client/core/VoxelCore.java +++ b/src/main/java/me/cortex/voxy/client/core/VoxelCore.java @@ -113,7 +113,7 @@ public class VoxelCore { //this.world.getMapper().forceResaveStates(); this.importer.shutdown(); Logger.info("Shutting down world engine"); - try {this.world.shutdown();} catch (Exception e) {Logger.error("Error shutting down world engine", e);} + try {this.world.free();} catch (Exception e) {Logger.error("Error shutting down world engine", e);} Logger.info("Shutting down service thread pool"); this.serviceThreadPool.shutdown(); Logger.info("Voxel core shut down"); diff --git a/src/main/java/me/cortex/voxy/common/util/TrackedObject.java b/src/main/java/me/cortex/voxy/common/util/TrackedObject.java index 7b52e1b1..31efae42 100644 --- a/src/main/java/me/cortex/voxy/common/util/TrackedObject.java +++ b/src/main/java/me/cortex/voxy/common/util/TrackedObject.java @@ -18,6 +18,10 @@ public abstract class TrackedObject { this.ref = register(shouldTrack, this); } + protected TrackedObject(Object forObj, boolean shouldTrack) { + this.ref = register(shouldTrack, forObj); + } + protected void free0() { if (this.isFreed()) { throw new IllegalStateException("Object " + this + " was double freed."); @@ -78,4 +82,20 @@ public abstract class TrackedObject { } return new Ref(cleanable, freed); } + + public static final class TrackedObjectObject extends TrackedObject { + private TrackedObjectObject(Object forObj) { + super(forObj, true); + } + + @Override + public void free() { + this.free0(); + } + } + + public static TrackedObject createTrackedObject(Object forObj) { + return new TrackedObjectObject(forObj); + } + } diff --git a/src/main/java/me/cortex/voxy/common/world/WorldEngine.java b/src/main/java/me/cortex/voxy/common/world/WorldEngine.java index 1416d53c..9c47ccd3 100644 --- a/src/main/java/me/cortex/voxy/common/world/WorldEngine.java +++ b/src/main/java/me/cortex/voxy/common/world/WorldEngine.java @@ -2,6 +2,7 @@ package me.cortex.voxy.common.world; import me.cortex.voxy.common.Logger; import me.cortex.voxy.common.config.section.SectionStorage; +import me.cortex.voxy.common.util.TrackedObject; import me.cortex.voxy.common.voxelization.VoxelizedSection; import me.cortex.voxy.common.world.other.Mapper; @@ -16,6 +17,7 @@ public class WorldEngine { public interface ISectionChangeCallback {void accept(WorldSection section, int updateFlags);} public interface ISectionSaveCallback {void save(WorldEngine engine, WorldSection section);} + private final TrackedObject thisTracker = TrackedObject.createTrackedObject(this); public final SectionStorage storage; private final Mapper mapper; @@ -207,7 +209,8 @@ public class WorldEngine { debug.add("ACC/SCC: " + this.sectionTracker.getLoadedCacheCount()+"/"+this.sectionTracker.getSecondaryCacheSize());//Active cache count, Secondary cache counts } - public void shutdown() { + public void free() { + this.thisTracker.free(); this.isLive = false; try {this.mapper.close();} catch (Exception e) {Logger.error(e);} try {this.storage.flush();} catch (Exception e) {Logger.error(e);} diff --git a/src/main/java/me/cortex/voxy/commonImpl/VoxyCommon.java b/src/main/java/me/cortex/voxy/commonImpl/VoxyCommon.java index 36e9ce44..99beb40a 100644 --- a/src/main/java/me/cortex/voxy/commonImpl/VoxyCommon.java +++ b/src/main/java/me/cortex/voxy/commonImpl/VoxyCommon.java @@ -7,8 +7,6 @@ import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; public class VoxyCommon implements ModInitializer { - private static VoxyInstance INSTANCE; - public static final String MOD_VERSION; public static final boolean IS_DEDICATED_SERVER; @@ -27,21 +25,24 @@ public class VoxyCommon implements ModInitializer { } } - @Override - public void onInitialize() { + //This is hardcoded like this because people do not understand what they are doing + private static final boolean GlobalVerificationDisableOverride = false;//System.getProperty("voxy.verificationDisableOverride", "false").equals("true"); + public static boolean isVerificationFlagOn(String name) { + return (!GlobalVerificationDisableOverride) && System.getProperty("voxy."+name, "true").equals("true"); } public static void breakpoint() { int breakpoint = 0; } - - //This is hardcoded like this because people do not understand what they are doing - private static final boolean GlobalVerificationDisableOverride = false;//System.getProperty("voxy.verificationDisableOverride", "false").equals("true"); - public static boolean isVerificationFlagOn(String name) { - return (!GlobalVerificationDisableOverride) && System.getProperty("voxy."+name, "true").equals("true"); + @Override + public void onInitialize() { } + public interface IInstanceFactory {VoxyInstance create();} + private static VoxyInstance INSTANCE; + private static IInstanceFactory FACTORY; + public static VoxyInstance getInstance() { return INSTANCE; } @@ -57,6 +58,9 @@ public class VoxyCommon implements ModInitializer { if (INSTANCE != null) { throw new IllegalStateException("Cannot create multiple instances"); } - INSTANCE = new VoxyInstance(12); + if (FACTORY == null) { + throw new IllegalStateException("Instance factory null"); + } + INSTANCE = FACTORY.create(); } } diff --git a/src/main/java/me/cortex/voxy/commonImpl/VoxyInstance.java b/src/main/java/me/cortex/voxy/commonImpl/VoxyInstance.java index 94acf9e1..44a3c99e 100644 --- a/src/main/java/me/cortex/voxy/commonImpl/VoxyInstance.java +++ b/src/main/java/me/cortex/voxy/commonImpl/VoxyInstance.java @@ -17,10 +17,10 @@ import java.util.Set; //TODO: add thread access verification (I.E. only accessible on a single thread) public class VoxyInstance { - private final ServiceThreadPool threadPool; - private final SectionSavingService savingService; - private final VoxelIngestService ingestService; - private final Set activeWorlds = new HashSet<>(); + protected final ServiceThreadPool threadPool; + protected final SectionSavingService savingService; + protected final VoxelIngestService ingestService; + protected final Set activeWorlds = new HashSet<>(); public VoxyInstance(int threadCount) { this.threadPool = new ServiceThreadPool(threadCount); @@ -66,7 +66,7 @@ public class VoxyInstance { } } - private WorldEngine createWorld(SectionStorage storage) { + protected WorldEngine createWorld(SectionStorage storage) { var world = new WorldEngine(storage, 1024); world.setSaveCallback(this.savingService::enqueueSave); this.activeWorlds.add(world); @@ -83,6 +83,30 @@ public class VoxyInstance { // so if make into singleplayer as host, would need to reload the system into that mode // so that the world renderer uses the WorldEngine of the server + public void stopWorld(WorldEngine world) { + if (!this.activeWorlds.contains(world)) { + if (world.isLive()) { + throw new IllegalStateException("World cannot be live and not in world set"); + } + throw new IllegalStateException("Cannot close world which is not part of instance"); + } + if (!world.isLive()) { + throw new IllegalStateException("World cannot be in world set and not alive"); + } + + + if (this.importWrapper != null) { + this.importWrapper.stopImporter(); + this.importWrapper = null; + } + + this.flush(); + + + world.free(); + this.activeWorlds.remove(world); + } + private static final ContextSelectionSystem SELECTOR = new ContextSelectionSystem(); public WorldImportWrapper importWrapper; public WorldEngine getOrMakeWorld(ClientWorld world) { @@ -95,25 +119,4 @@ public class VoxyInstance { return vworld; } - - - public void stopWorld(WorldEngine world) { - if (!this.activeWorlds.contains(world)) { - if (world.isLive()) { - throw new IllegalStateException("World cannot be live and not in world set"); - } - throw new IllegalStateException("Cannot close world which is not part of instance"); - } - if (!world.isLive()) { - throw new IllegalStateException("World cannot be in world set and not alive"); - } - - if (this.importWrapper != null) { - this.importWrapper.stopImporter(); - } - this.flush(); - - world.shutdown(); - this.activeWorlds.remove(world); - } } \ No newline at end of file