From 213887340a0aeb7a6f6a371755a1848b76be2f24 Mon Sep 17 00:00:00 2001 From: Xytronix <32957125+Xytronix@users.noreply.github.com> Date: Tue, 24 Feb 2026 13:51:50 +0100 Subject: [PATCH 1/3] ft Proper Management of Mixins, all can now be disabled properly using iConfigManager --- .../cc/irori/refixes/early/EarlyOptions.java | 15 -- .../refixes/early/RefixesMixinPlugin.java | 226 ++++++++++++++++++ .../refixes/early/mixin/MixinBlockModule.java | 8 +- .../early/mixin/MixinCollectVisible.java | 10 +- .../early/mixin/MixinEntityTickingSystem.java | 7 +- .../refixes/early/mixin/MixinFluidPlugin.java | 8 +- .../early/mixin/MixinHytaleServerConfig.java | 5 +- .../early/mixin/MixinInstancesPlugin.java | 4 - .../refixes/early/mixin/MixinKDTree.java | 4 +- .../mixin/MixinMarkerAddRemoveSystem.java | 6 +- .../irori/refixes/early/mixin/MixinStore.java | 5 +- .../early/mixin/MixinTickingThread.java | 6 - early/src/main/resources/refixes.mixins.json | 1 + .../main/java/cc/irori/refixes/Refixes.java | 21 -- .../config/impl/ExperimentalConfig.java | 21 -- .../refixes/config/impl/RefixesConfig.java | 11 +- .../refixes/service/ActiveChunkUnloader.java | 18 +- .../refixes/service/IdlePlayerService.java | 3 +- 18 files changed, 250 insertions(+), 129 deletions(-) create mode 100644 early/src/main/java/cc/irori/refixes/early/RefixesMixinPlugin.java delete mode 100644 plugin/src/main/java/cc/irori/refixes/config/impl/ExperimentalConfig.java diff --git a/early/src/main/java/cc/irori/refixes/early/EarlyOptions.java b/early/src/main/java/cc/irori/refixes/early/EarlyOptions.java index 08fe3ee..6a8da7e 100644 --- a/early/src/main/java/cc/irori/refixes/early/EarlyOptions.java +++ b/early/src/main/java/cc/irori/refixes/early/EarlyOptions.java @@ -6,32 +6,17 @@ public final class EarlyOptions { private static boolean available = false; - /* Force Skip Mod Validation */ - public static final Value FORCE_SKIP_MOD_VALIDATION = new Value<>(); - - /* Fluid Pre-processing */ - public static final Value DISABLE_FLUID_PRE_PROCESS = new Value<>(); - - /* Block Pre-processing */ - public static final Value ASYNC_BLOCK_PRE_PROCESS = new Value<>(); - /* Cylinder Visibility */ - public static final Value CYLINDER_VISIBILITY_ENABLED = new Value<>(); public static final Value CYLINDER_VISIBILITY_HEIGHT_MULTIPLIER = new Value<>(); - /* Parallel Entity Ticking */ - public static final Value PARALLEL_ENTITY_TICKING = new Value<>(); - /* ChunkTracker Rate Limits */ public static final Value MAX_CHUNKS_PER_SECOND = new Value<>(); public static final Value MAX_CHUNKS_PER_TICK = new Value<>(); /* KDTree Optimization */ - public static final Value KDTREE_OPTIMIZATION_OPTIMIZE_SORT = new Value<>(); public static final Value KDTREE_OPTIMIZATION_THRESHOLD = new Value<>(); /* Shared Instances */ - public static final Value SHARED_INSTANCES_ENABLED = new Value<>(); public static final Value SHARED_INSTANCES_EXCLUDED_PREFIXES = new Value<>(); // Private constructor to prevent instantiation diff --git a/early/src/main/java/cc/irori/refixes/early/RefixesMixinPlugin.java b/early/src/main/java/cc/irori/refixes/early/RefixesMixinPlugin.java new file mode 100644 index 0000000..fc52c63 --- /dev/null +++ b/early/src/main/java/cc/irori/refixes/early/RefixesMixinPlugin.java @@ -0,0 +1,226 @@ +package cc.irori.refixes.early; + +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class RefixesMixinPlugin implements IMixinConfigPlugin { + + private static final Path CONFIG_PATH = Paths.get("mods", "IroriPowered_Refixes", "Refixes.json"); + + private record MixinToggle(String[] jsonPath, boolean enabledWhen, boolean defaultEnabled, List mixins) { + MixinToggle(String[] jsonPath, boolean enabledWhen, List mixins) { + this(jsonPath, enabledWhen, true, mixins); + } + } + + private static final List TOGGLES = List.of( + // Fluid processing + new MixinToggle(new String[] {"Mixins", "MixinFluidPlugin"}, true, List.of("MixinFluidPlugin")), + new MixinToggle( + new String[] {"Mixins", "MixinFluidReplicateChanges"}, + true, + false, + List.of("MixinFluidReplicateChanges")), + + // Block processing + new MixinToggle(new String[] {"Mixins", "MixinBlockModule"}, true, List.of("MixinBlockModule")), + new MixinToggle( + new String[] {"Mixins", "MixinBlockComponentChunk"}, true, List.of("MixinBlockComponentChunk")), + new MixinToggle(new String[] {"Mixins", "MixinBlockHealthSystem"}, true, List.of("MixinBlockHealthSystem")), + + // Chunk systems + new MixinToggle( + new String[] {"Mixins", "MixinChunkReplicateChanges"}, + true, + false, + List.of("MixinChunkReplicateChanges")), + new MixinToggle( + new String[] {"Mixins", "MixinChunkSavingSystems"}, true, List.of("MixinChunkSavingSystems")), + + // Entity systems + new MixinToggle(new String[] {"Mixins", "MixinArchetypeChunk"}, true, List.of("MixinArchetypeChunk")), + new MixinToggle( + new String[] {"Mixins", "MixinEntityTickingSystem"}, + true, + false, + List.of("MixinEntityTickingSystem")), + new MixinToggle(new String[] {"Mixins", "MixinStore"}, true, false, List.of("MixinStore")), + new MixinToggle(new String[] {"Mixins", "MixinCommandBuffer"}, true, List.of("MixinCommandBuffer")), + new MixinToggle(new String[] {"Mixins", "MixinRemovalSystem"}, true, List.of("MixinRemovalSystem")), + new MixinToggle(new String[] {"Mixins", "MixinUUIDSystem"}, true, List.of("MixinUUIDSystem")), + new MixinToggle(new String[] {"Mixins", "MixinCollectVisible"}, true, List.of("MixinCollectVisible")), + new MixinToggle(new String[] {"Mixins", "MixinKDTree"}, true, List.of("MixinKDTree")), + + // Ticking + new MixinToggle(new String[] {"Mixins", "MixinTickingThread"}, true, List.of("MixinTickingThread")), + new MixinToggle( + new String[] {"Mixins", "MixinTickingThreadAssert"}, true, List.of("MixinTickingThreadAssert")), + new MixinToggle( + new String[] {"Mixins", "MixinTickingSpawnMarkerSystem"}, + true, + List.of("MixinTickingSpawnMarkerSystem")), + + // Player & network + new MixinToggle( + new String[] {"Mixins", "MixinPlayerChunkTrackerSystems"}, + true, + List.of("MixinPlayerChunkTrackerSystems")), + new MixinToggle(new String[] {"Mixins", "MixinGamePacketHandler"}, true, List.of("MixinGamePacketHandler")), + + // Interactions + new MixinToggle(new String[] {"Mixins", "MixinInteractionChain"}, true, List.of("MixinInteractionChain")), + new MixinToggle( + new String[] {"Mixins", "MixinInteractionManager"}, true, List.of("MixinInteractionManager")), + new MixinToggle( + new String[] {"Mixins", "MixinSetMemoriesCapacityInteraction"}, + true, + List.of("MixinSetMemoriesCapacityInteraction")), + new MixinToggle( + new String[] {"Mixins", "MixinCraftingManagerAccessor"}, + true, + List.of("MixinCraftingManagerAccessor")), + + // World & universe + new MixinToggle(new String[] {"Mixins", "MixinWorld"}, true, List.of("MixinWorld")), + new MixinToggle(new String[] {"Mixins", "MixinWorldConfig"}, true, List.of("MixinWorldConfig")), + new MixinToggle(new String[] {"Mixins", "MixinWorldMapTracker"}, true, List.of("MixinWorldMapTracker")), + new MixinToggle( + new String[] {"Mixins", "MixinWorldSpawningSystem"}, true, List.of("MixinWorldSpawningSystem")), + new MixinToggle(new String[] {"Mixins", "MixinUniverse"}, true, List.of("MixinUniverse")), + new MixinToggle(new String[] {"Mixins", "MixinPrefabLoader"}, true, List.of("MixinPrefabLoader")), + new MixinToggle(new String[] {"Mixins", "MixinInstancesPlugin"}, true, List.of("MixinInstancesPlugin")), + + // Portals + new MixinToggle( + new String[] {"Mixins", "MixinPortalDeviceSummonPage"}, + true, + List.of("MixinPortalDeviceSummonPage")), + new MixinToggle( + new String[] {"Mixins", "MixinPortalWorldAccessor"}, true, List.of("MixinPortalWorldAccessor")), + + // Placement & markers + new MixinToggle( + new String[] {"Mixins", "MixinTrackedPlacementAccessor"}, + true, + List.of("MixinTrackedPlacementAccessor")), + new MixinToggle( + new String[] {"Mixins", "MixinTrackedPlacementOnAddRemove"}, + true, + List.of("MixinTrackedPlacementOnAddRemove")), + new MixinToggle( + new String[] {"Mixins", "MixinBeaconAddRemoveSystem"}, true, List.of("MixinBeaconAddRemoveSystem")), + new MixinToggle( + new String[] {"Mixins", "MixinMarkerAddRemoveSystem"}, true, List.of("MixinMarkerAddRemoveSystem")), + + // Server + new MixinToggle(new String[] {"Mixins", "MixinHytaleServer"}, true, List.of("MixinHytaleServer")), + new MixinToggle( + new String[] {"Mixins", "MixinHytaleServerConfig"}, + true, + false, + List.of("MixinHytaleServerConfig"))); + + private String mixinPackage; + private Set disabledMixins = Collections.emptySet(); + + @Override + public void onLoad(String mixinPackage) { + this.mixinPackage = mixinPackage; + + JsonObject config = readConfig(); + if (config == null) { + return; + } + + Set disabled = new HashSet<>(); + for (MixinToggle toggle : TOGGLES) { + Boolean value = getBoolean(config, toggle.jsonPath); + boolean enabled; + if (value == null) { + enabled = toggle.defaultEnabled; + } else { + enabled = (value == toggle.enabledWhen); + } + if (!enabled) { + disabled.addAll(toggle.mixins); + } + } + + if (!disabled.isEmpty()) { + disabledMixins = disabled; + System.out.println("[Refixes] Disabled mixins: " + disabled); + } + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + String simpleName = mixinClassName; + if (mixinPackage != null && mixinClassName.startsWith(mixinPackage + ".")) { + simpleName = mixinClassName.substring(mixinPackage.length() + 1); + } + return !disabledMixins.contains(simpleName); + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) {} + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {} + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {} + + private static JsonObject readConfig() { + if (!Files.isRegularFile(CONFIG_PATH)) { + return null; + } + try (Reader reader = Files.newBufferedReader(CONFIG_PATH, StandardCharsets.UTF_8)) { + JsonElement el = JsonParser.parseReader(reader); + return el.isJsonObject() ? el.getAsJsonObject() : null; + } catch (Exception e) { + System.err.println("[Refixes] Failed to read config: " + e.getMessage()); + return null; + } + } + + private static Boolean getBoolean(JsonObject root, String[] path) { + JsonObject current = root; + for (int i = 0; i < path.length - 1; i++) { + JsonElement el = current.get(path[i]); + if (el == null || !el.isJsonObject()) { + return null; + } + current = el.getAsJsonObject(); + } + JsonElement leaf = current.get(path[path.length - 1]); + if (leaf != null && leaf.isJsonPrimitive() && leaf.getAsJsonPrimitive().isBoolean()) { + return leaf.getAsBoolean(); + } + return null; + } +} diff --git a/early/src/main/java/cc/irori/refixes/early/mixin/MixinBlockModule.java b/early/src/main/java/cc/irori/refixes/early/mixin/MixinBlockModule.java index b60b4d2..5d12c06 100644 --- a/early/src/main/java/cc/irori/refixes/early/mixin/MixinBlockModule.java +++ b/early/src/main/java/cc/irori/refixes/early/mixin/MixinBlockModule.java @@ -1,6 +1,5 @@ package cc.irori.refixes.early.mixin; -import cc.irori.refixes.early.EarlyOptions; import com.hypixel.hytale.server.core.modules.block.BlockModule; import com.hypixel.hytale.server.core.universe.world.events.ChunkPreLoadProcessEvent; import java.util.function.Consumer; @@ -23,11 +22,6 @@ public class MixinBlockModule { index = 2) private Consumer refixes$asyncBlockChunkPreProcess( Consumer consumer) { - return event -> { - if (EarlyOptions.isAvailable() && EarlyOptions.ASYNC_BLOCK_PRE_PROCESS.get()) { - return; - } - consumer.accept(event); - }; + return event -> {}; } } diff --git a/early/src/main/java/cc/irori/refixes/early/mixin/MixinCollectVisible.java b/early/src/main/java/cc/irori/refixes/early/mixin/MixinCollectVisible.java index 669ca2c..af60e33 100644 --- a/early/src/main/java/cc/irori/refixes/early/mixin/MixinCollectVisible.java +++ b/early/src/main/java/cc/irori/refixes/early/mixin/MixinCollectVisible.java @@ -48,13 +48,9 @@ public void tick( ObjectList> results = SpatialResource.getThreadLocalReferenceList(); - if (EarlyOptions.isAvailable() && EarlyOptions.CYLINDER_VISIBILITY_ENABLED.get()) { - double radius = entityViewerComponent.viewRadiusBlocks; - double height = radius * EarlyOptions.CYLINDER_VISIBILITY_HEIGHT_MULTIPLIER.get(); - spatialStructure.collectCylinder(position, radius, height, results); - } else { - spatialStructure.collect(position, entityViewerComponent.viewRadiusBlocks, results); - } + double radius = entityViewerComponent.viewRadiusBlocks; + double height = radius * EarlyOptions.CYLINDER_VISIBILITY_HEIGHT_MULTIPLIER.get(); + spatialStructure.collectCylinder(position, radius, height, results); entityViewerComponent.visible.addAll(results); } diff --git a/early/src/main/java/cc/irori/refixes/early/mixin/MixinEntityTickingSystem.java b/early/src/main/java/cc/irori/refixes/early/mixin/MixinEntityTickingSystem.java index 91523e9..75b56f7 100644 --- a/early/src/main/java/cc/irori/refixes/early/mixin/MixinEntityTickingSystem.java +++ b/early/src/main/java/cc/irori/refixes/early/mixin/MixinEntityTickingSystem.java @@ -1,6 +1,5 @@ package cc.irori.refixes.early.mixin; -import cc.irori.refixes.early.EarlyOptions; import com.hypixel.hytale.component.system.tick.EntityTickingSystem; import com.hypixel.hytale.component.task.ParallelRangeTask; import org.spongepowered.asm.mixin.Mixin; @@ -18,9 +17,7 @@ public class MixinEntityTickingSystem { // Enable parallel entity ticking when chunk size is large enough @Inject(method = "maybeUseParallel", at = @At("HEAD"), cancellable = true) private static void maybeUseParallel(int archetypeChunkSize, int taskCount, CallbackInfoReturnable cir) { - if (EarlyOptions.isAvailable() && EarlyOptions.PARALLEL_ENTITY_TICKING.get()) { - cir.cancel(); - cir.setReturnValue(taskCount > 0 || archetypeChunkSize > ParallelRangeTask.PARALLELISM); - } + cir.cancel(); + cir.setReturnValue(taskCount > 0 || archetypeChunkSize > ParallelRangeTask.PARALLELISM); } } diff --git a/early/src/main/java/cc/irori/refixes/early/mixin/MixinFluidPlugin.java b/early/src/main/java/cc/irori/refixes/early/mixin/MixinFluidPlugin.java index f65f337..9840bb9 100644 --- a/early/src/main/java/cc/irori/refixes/early/mixin/MixinFluidPlugin.java +++ b/early/src/main/java/cc/irori/refixes/early/mixin/MixinFluidPlugin.java @@ -1,6 +1,5 @@ package cc.irori.refixes.early.mixin; -import cc.irori.refixes.early.EarlyOptions; import com.hypixel.hytale.builtin.fluid.FluidPlugin; import com.hypixel.hytale.server.core.universe.world.events.ChunkPreLoadProcessEvent; import java.util.function.Consumer; @@ -21,11 +20,6 @@ public class MixinFluidPlugin { index = 2) private Consumer refixes$disableFluidChunkPreProcess( Consumer consumer) { - return event -> { - if (EarlyOptions.isAvailable() && EarlyOptions.DISABLE_FLUID_PRE_PROCESS.get()) { - return; - } - consumer.accept(event); - }; + return event -> {}; } } diff --git a/early/src/main/java/cc/irori/refixes/early/mixin/MixinHytaleServerConfig.java b/early/src/main/java/cc/irori/refixes/early/mixin/MixinHytaleServerConfig.java index 9d20985..e06186a 100644 --- a/early/src/main/java/cc/irori/refixes/early/mixin/MixinHytaleServerConfig.java +++ b/early/src/main/java/cc/irori/refixes/early/mixin/MixinHytaleServerConfig.java @@ -1,6 +1,5 @@ package cc.irori.refixes.early.mixin; -import cc.irori.refixes.early.EarlyOptions; import com.hypixel.hytale.server.core.HytaleServerConfig; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -12,8 +11,6 @@ public class MixinHytaleServerConfig { @Inject(method = "shouldSkipModValidation", at = @At("HEAD"), cancellable = true) private void refixes$forceSkipModValidation(CallbackInfoReturnable cir) { - if (EarlyOptions.isAvailable() && EarlyOptions.FORCE_SKIP_MOD_VALIDATION.get()) { - cir.setReturnValue(true); - } + cir.setReturnValue(true); } } diff --git a/early/src/main/java/cc/irori/refixes/early/mixin/MixinInstancesPlugin.java b/early/src/main/java/cc/irori/refixes/early/mixin/MixinInstancesPlugin.java index fe9e0d9..478dd72 100644 --- a/early/src/main/java/cc/irori/refixes/early/mixin/MixinInstancesPlugin.java +++ b/early/src/main/java/cc/irori/refixes/early/mixin/MixinInstancesPlugin.java @@ -31,10 +31,6 @@ public abstract CompletableFuture spawnInstance( @Overwrite public CompletableFuture spawnInstance( @Nonnull String name, @Nonnull World forWorld, @Nonnull Transform returnPoint) { - if (!EarlyOptions.isAvailable() || !EarlyOptions.SHARED_INSTANCES_ENABLED.get()) { - return spawnInstance(name, null, forWorld, returnPoint); - } - String[] excludedPrefixes = EarlyOptions.SHARED_INSTANCES_EXCLUDED_PREFIXES.get(); for (String prefix : excludedPrefixes) { if (name.startsWith(prefix)) { diff --git a/early/src/main/java/cc/irori/refixes/early/mixin/MixinKDTree.java b/early/src/main/java/cc/irori/refixes/early/mixin/MixinKDTree.java index 679a64a..847a63d 100644 --- a/early/src/main/java/cc/irori/refixes/early/mixin/MixinKDTree.java +++ b/early/src/main/java/cc/irori/refixes/early/mixin/MixinKDTree.java @@ -19,9 +19,7 @@ public class MixinKDTree { method = "rebuild", at = @At(value = "INVOKE", target = "Lcom/hypixel/hytale/component/spatial/SpatialData;sortMorton()V")) private void refixes$fastSort(SpatialData spatialData) { - if (EarlyOptions.isAvailable() - && EarlyOptions.KDTREE_OPTIMIZATION_OPTIMIZE_SORT.get() - && spatialData.size() < EarlyOptions.KDTREE_OPTIMIZATION_THRESHOLD.get()) { + if (spatialData.size() < EarlyOptions.KDTREE_OPTIMIZATION_THRESHOLD.get()) { spatialData.sort(); } else { spatialData.sortMorton(); diff --git a/early/src/main/java/cc/irori/refixes/early/mixin/MixinMarkerAddRemoveSystem.java b/early/src/main/java/cc/irori/refixes/early/mixin/MixinMarkerAddRemoveSystem.java index 73da880..4adfacd 100644 --- a/early/src/main/java/cc/irori/refixes/early/mixin/MixinMarkerAddRemoveSystem.java +++ b/early/src/main/java/cc/irori/refixes/early/mixin/MixinMarkerAddRemoveSystem.java @@ -53,10 +53,8 @@ public abstract void onEntityRemove( try { onEntityRemove(ref, reason, store, commandBuffer); } catch (ArrayIndexOutOfBoundsException e) { - refixes$LOGGER - .atWarning() - .withCause(e) - .log("MarkerAddRemoveSystem#onEntityRemove(): Array index out of bounds while removing NPC references"); + refixes$LOGGER.atWarning().withCause(e).log( + "MarkerAddRemoveSystem#onEntityRemove(): Array index out of bounds while removing NPC references"); } finally { refixes$WRAPPING.set(false); } diff --git a/early/src/main/java/cc/irori/refixes/early/mixin/MixinStore.java b/early/src/main/java/cc/irori/refixes/early/mixin/MixinStore.java index 5099ae2..5d44afd 100644 --- a/early/src/main/java/cc/irori/refixes/early/mixin/MixinStore.java +++ b/early/src/main/java/cc/irori/refixes/early/mixin/MixinStore.java @@ -1,6 +1,5 @@ package cc.irori.refixes.early.mixin; -import cc.irori.refixes.early.EarlyOptions; import cc.irori.refixes.early.util.Logs; import com.hypixel.hytale.component.CommandBuffer; import com.hypixel.hytale.component.Component; @@ -86,9 +85,7 @@ public void assertThread() { ci.cancel(); return; } - if (EarlyOptions.isAvailable() && EarlyOptions.PARALLEL_ENTITY_TICKING.get()) { - ci.cancel(); - } + ci.cancel(); } // synchronize the isEmpty + pop sequence diff --git a/early/src/main/java/cc/irori/refixes/early/mixin/MixinTickingThread.java b/early/src/main/java/cc/irori/refixes/early/mixin/MixinTickingThread.java index 8fda4f6..f1d6178 100644 --- a/early/src/main/java/cc/irori/refixes/early/mixin/MixinTickingThread.java +++ b/early/src/main/java/cc/irori/refixes/early/mixin/MixinTickingThread.java @@ -1,7 +1,6 @@ package cc.irori.refixes.early.mixin; import cc.irori.refixes.early.util.Logs; -import cc.irori.refixes.early.util.TickSleepOptimization; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.server.core.util.thread.TickingThread; import java.util.concurrent.locks.LockSupport; @@ -32,11 +31,6 @@ public class MixinTickingThread { // Replaces the pure spin-wait in the tick loop with a hybrid spin approach @Redirect(method = "run", at = @At(value = "INVOKE", target = "Ljava/lang/Thread;onSpinWait()V")) private void refixes$hybridWait() { - if (!TickSleepOptimization.enabled) { - Thread.onSpinWait(); - return; - } - Thread.onSpinWait(); // Park for 100ns, loop will re-check and spin-wait naturally as it approaches the deadline LockSupport.parkNanos(100_000L); diff --git a/early/src/main/resources/refixes.mixins.json b/early/src/main/resources/refixes.mixins.json index 2109ce7..d27a22d 100644 --- a/early/src/main/resources/refixes.mixins.json +++ b/early/src/main/resources/refixes.mixins.json @@ -2,6 +2,7 @@ "required": true, "minVersion": "0.8", "package": "cc.irori.refixes.early.mixin", + "plugin": "cc.irori.refixes.early.RefixesMixinPlugin", "mixins": [ "MixinArchetypeChunk", "MixinBeaconAddRemoveSystem", diff --git a/plugin/src/main/java/cc/irori/refixes/Refixes.java b/plugin/src/main/java/cc/irori/refixes/Refixes.java index 54a7e41..c21c563 100644 --- a/plugin/src/main/java/cc/irori/refixes/Refixes.java +++ b/plugin/src/main/java/cc/irori/refixes/Refixes.java @@ -4,7 +4,6 @@ import cc.irori.refixes.config.impl.ChunkUnloaderConfig; import cc.irori.refixes.config.impl.CylinderVisibilityConfig; import cc.irori.refixes.config.impl.EarlyConfig; -import cc.irori.refixes.config.impl.ExperimentalConfig; import cc.irori.refixes.config.impl.IdlePlayerHandlerConfig; import cc.irori.refixes.config.impl.KDTreeOptimizationConfig; import cc.irori.refixes.config.impl.ListenerConfig; @@ -123,39 +122,19 @@ private void registerEarlyOptions() { CylinderVisibilityConfig cylinderVisibilityConfig = CylinderVisibilityConfig.get(); KDTreeOptimizationConfig kdTreeOptimizationConfig = KDTreeOptimizationConfig.get(); SharedInstanceConfig sharedInstanceConfig = SharedInstanceConfig.get(); - ExperimentalConfig experimentalConfig = ExperimentalConfig.get(); - if (config.getValue(EarlyConfig.FORCE_SKIP_MOD_VALIDATION)) { - LOGGER.atSevere().log( - "Force Skip Mod Validation is enabled! ALWAYS remember to check your mods are working correctly after server updates."); - } - - EarlyOptions.FORCE_SKIP_MOD_VALIDATION.setSupplier( - () -> config.getValue(EarlyConfig.FORCE_SKIP_MOD_VALIDATION)); - EarlyOptions.DISABLE_FLUID_PRE_PROCESS.setSupplier( - () -> config.getValue(EarlyConfig.DISABLE_FLUID_PRE_PROCESS)); - EarlyOptions.ASYNC_BLOCK_PRE_PROCESS.setSupplier(() -> config.getValue(EarlyConfig.ASYNC_BLOCK_PRE_PROCESS)); EarlyOptions.MAX_CHUNKS_PER_SECOND.setSupplier(() -> config.getValue(EarlyConfig.MAX_CHUNKS_PER_SECOND)); EarlyOptions.MAX_CHUNKS_PER_TICK.setSupplier(() -> config.getValue(EarlyConfig.MAX_CHUNKS_PER_TICK)); - EarlyOptions.CYLINDER_VISIBILITY_ENABLED.setSupplier( - () -> cylinderVisibilityConfig.getValue(CylinderVisibilityConfig.ENABLED)); EarlyOptions.CYLINDER_VISIBILITY_HEIGHT_MULTIPLIER.setSupplier( () -> cylinderVisibilityConfig.getValue(CylinderVisibilityConfig.HEIGHT_MULTIPLIER)); - EarlyOptions.KDTREE_OPTIMIZATION_OPTIMIZE_SORT.setSupplier( - () -> kdTreeOptimizationConfig.getValue(KDTreeOptimizationConfig.OPTIMIZE_KDTREE_SORT)); EarlyOptions.KDTREE_OPTIMIZATION_THRESHOLD.setSupplier( () -> kdTreeOptimizationConfig.getValue(KDTreeOptimizationConfig.SPATIAL_FAST_SORT_THRESHOLD)); - EarlyOptions.SHARED_INSTANCES_ENABLED.setSupplier( - () -> sharedInstanceConfig.getValue(SharedInstanceConfig.ENABLED)); EarlyOptions.SHARED_INSTANCES_EXCLUDED_PREFIXES.setSupplier( () -> sharedInstanceConfig.getValue(SharedInstanceConfig.EXCLUDED_PREFIXES)); - EarlyOptions.PARALLEL_ENTITY_TICKING.setSupplier( - () -> experimentalConfig.getValue(ExperimentalConfig.PARALLEL_ENTITY_TICKING)); - EarlyOptions.setAvailable(true); /* Tick Sleep Optimization */ diff --git a/plugin/src/main/java/cc/irori/refixes/config/impl/ExperimentalConfig.java b/plugin/src/main/java/cc/irori/refixes/config/impl/ExperimentalConfig.java deleted file mode 100644 index c494bb7..0000000 --- a/plugin/src/main/java/cc/irori/refixes/config/impl/ExperimentalConfig.java +++ /dev/null @@ -1,21 +0,0 @@ -package cc.irori.refixes.config.impl; - -import cc.irori.refixes.config.Configuration; -import cc.irori.refixes.config.ConfigurationKey; -import cc.irori.refixes.config.field.ConfigField; - -public class ExperimentalConfig extends Configuration { - - public static final ConfigurationKey PARALLEL_ENTITY_TICKING = - new ConfigurationKey<>("ParallelEntityTicking", ConfigField.BOOLEAN, false); - - private static final ExperimentalConfig INSTANCE = new ExperimentalConfig(); - - public ExperimentalConfig() { - register(PARALLEL_ENTITY_TICKING); - } - - public static ExperimentalConfig get() { - return INSTANCE; - } -} diff --git a/plugin/src/main/java/cc/irori/refixes/config/impl/RefixesConfig.java b/plugin/src/main/java/cc/irori/refixes/config/impl/RefixesConfig.java index d293f2a..1b32fe8 100644 --- a/plugin/src/main/java/cc/irori/refixes/config/impl/RefixesConfig.java +++ b/plugin/src/main/java/cc/irori/refixes/config/impl/RefixesConfig.java @@ -17,20 +17,11 @@ public class RefixesConfig extends Configuration { ConfigurationKey.subConfig("SharedInstanceWorlds", SharedInstanceConfig.get()); private static final ConfigurationKey WATCHDOG_CONFIG = ConfigurationKey.subConfig("Watchdog", WatchdogConfig.get()); - private static final ConfigurationKey EXPERIMENTAL_CONFIG = - ConfigurationKey.subConfig("Experimental", ExperimentalConfig.get()); private static final RefixesConfig INSTANCE = new RefixesConfig(); public RefixesConfig() { - register( - EARLY_CONFIG, - LISTENER_CONFIG, - SYSTEM_CONFIG, - SERVICE_CONFIG, - SHARED_INSTANCE_CONFIG, - WATCHDOG_CONFIG, - EXPERIMENTAL_CONFIG); + register(EARLY_CONFIG, LISTENER_CONFIG, SYSTEM_CONFIG, SERVICE_CONFIG, SHARED_INSTANCE_CONFIG, WATCHDOG_CONFIG); } public static RefixesConfig get() { diff --git a/plugin/src/main/java/cc/irori/refixes/service/ActiveChunkUnloader.java b/plugin/src/main/java/cc/irori/refixes/service/ActiveChunkUnloader.java index 3d59d21..851d3e8 100644 --- a/plugin/src/main/java/cc/irori/refixes/service/ActiveChunkUnloader.java +++ b/plugin/src/main/java/cc/irori/refixes/service/ActiveChunkUnloader.java @@ -1,12 +1,7 @@ package cc.irori.refixes.service; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - +import cc.irori.refixes.config.impl.ChunkUnloaderConfig; +import cc.irori.refixes.util.Logs; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.RemoveReason; import com.hypixel.hytale.logger.HytaleLogger; @@ -23,12 +18,15 @@ import com.hypixel.hytale.server.core.universe.world.events.ecs.ChunkUnloadEvent; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; - -import cc.irori.refixes.config.impl.ChunkUnloaderConfig; -import cc.irori.refixes.util.Logs; import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap; import it.unimi.dsi.fastutil.longs.LongIterator; import it.unimi.dsi.fastutil.longs.LongSet; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; // Actively unloads chunks that are outside all players' view range public class ActiveChunkUnloader { diff --git a/plugin/src/main/java/cc/irori/refixes/service/IdlePlayerService.java b/plugin/src/main/java/cc/irori/refixes/service/IdlePlayerService.java index 26d588f..d6011b6 100644 --- a/plugin/src/main/java/cc/irori/refixes/service/IdlePlayerService.java +++ b/plugin/src/main/java/cc/irori/refixes/service/IdlePlayerService.java @@ -146,7 +146,8 @@ private void applyIdleSettings(PlayerRef playerRef, PlayerIdleState state, IdleP if (cfg.getValue(IdlePlayerHandlerConfig.REDUCE_MIN_LOADED_RADIUS)) { int currentMinLoaded = tracker.getMinLoadedChunksRadius(); - int idleMinLoaded = Math.max(2, cfg.getValue(IdlePlayerHandlerConfig.IDLE_MIN_LOADED_RADIUS)); + int idleMinLoaded = + Math.max(2, cfg.getValue(IdlePlayerHandlerConfig.IDLE_MIN_LOADED_RADIUS)); if (currentMinLoaded > idleMinLoaded) { state.savedMinLoadedRadius = currentMinLoaded; tracker.setMinLoadedChunksRadius(idleMinLoaded); From 063a93aa7edf9ac9e605fe54a44f0312b48636c9 Mon Sep 17 00:00:00 2001 From: Xytronix <32957125+Xytronix@users.noreply.github.com> Date: Tue, 24 Feb 2026 14:06:47 +0100 Subject: [PATCH 2/3] Add write and logging logic --- .../refixes/early/RefixesMixinPlugin.java | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/early/src/main/java/cc/irori/refixes/early/RefixesMixinPlugin.java b/early/src/main/java/cc/irori/refixes/early/RefixesMixinPlugin.java index fc52c63..a28ad41 100644 --- a/early/src/main/java/cc/irori/refixes/early/RefixesMixinPlugin.java +++ b/early/src/main/java/cc/irori/refixes/early/RefixesMixinPlugin.java @@ -1,6 +1,7 @@ package cc.irori.refixes.early; import java.io.Reader; +import java.io.Writer; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -14,6 +15,8 @@ import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinInfo; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -144,10 +147,11 @@ public void onLoad(String mixinPackage) { JsonObject config = readConfig(); if (config == null) { - return; + config = new JsonObject(); } Set disabled = new HashSet<>(); + JsonObject mixinsSection = new JsonObject(); for (MixinToggle toggle : TOGGLES) { Boolean value = getBoolean(config, toggle.jsonPath); boolean enabled; @@ -159,11 +163,22 @@ public void onLoad(String mixinPackage) { if (!enabled) { disabled.addAll(toggle.mixins); } + String leafKey = toggle.jsonPath[toggle.jsonPath.length - 1]; + mixinsSection.addProperty(leafKey, enabled == toggle.enabledWhen); } - if (!disabled.isEmpty()) { - disabledMixins = disabled; - System.out.println("[Refixes] Disabled mixins: " + disabled); + disabledMixins = disabled; + + // Write resolved mixin toggles back to config + config.add("Mixins", mixinsSection); + writeConfig(config); + + System.out.println("[Refixes] === Early mixin patches ==="); + for (MixinToggle toggle : TOGGLES) { + for (String mixin : toggle.mixins) { + String marker = disabled.contains(mixin) ? "[ ]" : "[x]"; + System.out.println("[Refixes] - " + marker + " " + mixin); + } } } @@ -208,6 +223,18 @@ private static JsonObject readConfig() { } } + private static void writeConfig(JsonObject config) { + try { + Files.createDirectories(CONFIG_PATH.getParent()); + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + try (Writer writer = Files.newBufferedWriter(CONFIG_PATH, StandardCharsets.UTF_8)) { + gson.toJson(config, writer); + } + } catch (Exception e) { + System.err.println("[Refixes] Failed to write config: " + e.getMessage()); + } + } + private static Boolean getBoolean(JsonObject root, String[] path) { JsonObject current = root; for (int i = 0; i < path.length - 1; i++) { From 4eb5b46071cc89632f74249ce563ca073eed6361 Mon Sep 17 00:00:00 2001 From: Xytronix <32957125+Xytronix@users.noreply.github.com> Date: Tue, 24 Feb 2026 14:22:31 +0100 Subject: [PATCH 3/3] switch to system.out --- .../main/java/cc/irori/refixes/early/RefixesMixinPlugin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/early/src/main/java/cc/irori/refixes/early/RefixesMixinPlugin.java b/early/src/main/java/cc/irori/refixes/early/RefixesMixinPlugin.java index a28ad41..d139ad4 100644 --- a/early/src/main/java/cc/irori/refixes/early/RefixesMixinPlugin.java +++ b/early/src/main/java/cc/irori/refixes/early/RefixesMixinPlugin.java @@ -218,7 +218,7 @@ private static JsonObject readConfig() { JsonElement el = JsonParser.parseReader(reader); return el.isJsonObject() ? el.getAsJsonObject() : null; } catch (Exception e) { - System.err.println("[Refixes] Failed to read config: " + e.getMessage()); + System.out.println("[Refixes] Failed to read config: " + e.getMessage()); return null; } } @@ -231,7 +231,7 @@ private static void writeConfig(JsonObject config) { gson.toJson(config, writer); } } catch (Exception e) { - System.err.println("[Refixes] Failed to write config: " + e.getMessage()); + System.out.println("[Refixes] Failed to write config: " + e.getMessage()); } }