Snapshot Curios sync stacks and refine Turbo LODs when idle

This commit is contained in:
ms2k 2026-11-12 03:20:23 +09:00
commit 3ff084d278
16 changed files with 459 additions and 31 deletions

View file

@ -2,6 +2,12 @@ version = '0.42.1'
base.archivesName = 'saltatory' base.archivesName = 'saltatory'
repositories { repositories {
ivy {
url = 'https://github.com/Pocky-l/dhturbo/releases/download'
patternLayout { artifact 'v[revision]/[artifact]-[revision].[ext]' }
metadataSources { artifact() }
content { includeModule 'com.pockyl', 'dhturbo-neoforge-1.21.1' }
}
ivy { ivy {
url = 'https://github.com/tlaplus/tlaplus/releases/download' url = 'https://github.com/tlaplus/tlaplus/releases/download'
patternLayout { artifact '[revision]/[artifact].[ext]' } patternLayout { artifact '[revision]/[artifact].[ext]' }
@ -48,6 +54,7 @@ dependencies {
compileOnly('curse.maven:functional-storage-556861:8459097') { transitive = false } compileOnly('curse.maven:functional-storage-556861:8459097') { transitive = false }
compileOnly('maven.modrinth:refined-storage:lHHiI26k') { transitive = false } compileOnly('maven.modrinth:refined-storage:lHHiI26k') { transitive = false }
compileOnly('maven.modrinth:distanthorizons:9w34y8ai') { transitive = false } compileOnly('maven.modrinth:distanthorizons:9w34y8ai') { transitive = false }
compileOnly('com.pockyl:dhturbo-neoforge-1.21.1:1.5.0') { transitive = false }
compileOnly 'org.jetbrains:annotations:24.1.0' compileOnly 'org.jetbrains:annotations:24.1.0'
compileOnly 'org.apiguardian:apiguardian-api:1.1.2' compileOnly 'org.apiguardian:apiguardian-api:1.1.2'
compileOnly 'io.github.llamalad7:mixinextras-neoforge:0.5.3' compileOnly 'io.github.llamalad7:mixinextras-neoforge:0.5.3'

View file

@ -0,0 +1,56 @@
package dev.quorate.tune;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import java.util.function.LongPredicate;
public final class LodWork {
public interface Generator {
boolean saltatory$active();
boolean saltatory$ready();
}
public interface Queue {
Generator saltatory$refiner();
}
private static final Set<Object> LOADED = Collections.newSetFromMap(new WeakHashMap<>());
private LodWork() {}
public static synchronized void loaded(Object level) {
LOADED.add(level);
}
public static synchronized boolean isLoaded(Object level) {
return LOADED.contains(level);
}
public static boolean ready(int cores, double load, double tickMillis) {
return load >= 0 && (1 - load) * cores >= 1 && tickMillis < 50;
}
public static <T, R> R pick(
ConcurrentHashMap<Long, T> tasks,
long threshold,
Function<Map.Entry<Long, T>, R> mapper,
BiFunction<R, R, R> reducer,
LongPredicate pending,
BooleanSupplier ready) {
R first =
tasks.reduceEntries(
threshold,
entry -> pending.test(entry.getKey()) ? null : mapper.apply(entry),
reducer);
return first != null || !ready.getAsBoolean()
? first
: tasks.reduceEntries(threshold, mapper, reducer);
}
}

View file

@ -0,0 +1,10 @@
package dev.quorate.tune.mixin;
public final class CurioPlugin extends ModPlugin {
static final String CURIOS = "[9.5.1,10)";
@Override
public boolean shouldApplyMixin(String target, String mixin) {
return ModRanges.loaded("curios", CURIOS);
}
}

View file

@ -0,0 +1,19 @@
package dev.quorate.tune.mixin;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
@Pseudo
@Mixin(
targets = "top.theillusivec4.curios.common.network.server.sync.SPacketSyncStack",
remap = false)
public abstract class CurioStack {
@ModifyVariable(method = "<init>", at = @At("HEAD"), argsOnly = true)
private static ItemStack saltatory$snapshot(ItemStack stack) {
return stack.copy();
}
}

View file

@ -1,37 +1,14 @@
package dev.quorate.tune.mixin; package dev.quorate.tune.mixin;
import org.objectweb.asm.tree.ClassNode; public final class LodPlugin extends ModPlugin {
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; static final String TURBO = "[1.5,1.6)";
import org.spongepowered.asm.mixin.extensibility.IMixinInfo; static final String DH = "[3.3.3,3.4)";
import java.util.List;
import java.util.Set;
public final class LodPlugin implements IMixinConfigPlugin {
@Override
public void onLoad(String name) {}
@Override
public String getRefMapperConfig() {
return null;
}
@Override @Override
public boolean shouldApplyMixin(String target, String mixin) { public boolean shouldApplyMixin(String target, String mixin) {
return ModRanges.loaded("distanthorizons", "[3.3.3,)"); if (mixin.endsWith(".LodMap") || mixin.endsWith(".LodQueueMixin")) {
return ModRanges.loaded("distanthorizons", "[3.3.3,)");
}
return ModRanges.loaded("dhturbo", TURBO) && ModRanges.loaded("distanthorizons", DH);
} }
@Override
public void acceptTargets(Set<String> own, Set<String> other) {}
@Override
public List<String> getMixins() {
return null;
}
@Override
public void preApply(String target, ClassNode node, String mixin, IMixinInfo info) {}
@Override
public void postApply(String target, ClassNode node, String mixin, IMixinInfo info) {}
} }

View file

@ -0,0 +1,67 @@
package dev.quorate.tune.mixin;
import com.google.common.collect.ImmutableMap;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
import net.minecraft.world.level.chunk.status.ChunkPyramid;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(
targets =
"com.seibel.distanthorizons.common.wrappers.worldGeneration.DhChunkGenerator_neoforge",
remap = false)
public abstract class RefineBorder {
@Shadow @Final @Mutable
public static ImmutableMap<EDhApiWorldGenerationStep, Integer>
WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP;
@Shadow @Final @Mutable public static int MAX_WORLD_GEN_CHUNK_BORDER_NEEDED;
@ModifyArg(
method = "generateChunks",
at =
@At(
value = "INVOKE",
target =
"Lcom/seibel/distanthorizons/common/wrappers/worldGeneration/ChunkPosGenStream_neoforge;getIterator(IIII)Ljava/util/Iterator;"),
index = 3)
private int saltatory$halo(int margin) {
return margin == 0 ? 0 : MAX_WORLD_GEN_CHUNK_BORDER_NEEDED;
}
@Inject(method = "<clinit>", at = @At("RETURN"))
private static void saltatory$border(CallbackInfo ci) {
var target = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.FEATURES);
int radius = target.getAccumulatedRadiusOf(ChunkStatus.EMPTY);
var borders = ImmutableMap.<EDhApiWorldGenerationStep, Integer>builder();
for (var step : WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP.keySet()) {
ChunkStatus status =
switch (step) {
case EMPTY -> ChunkStatus.EMPTY;
case STRUCTURE_START -> ChunkStatus.STRUCTURE_STARTS;
case STRUCTURE_REFERENCE -> ChunkStatus.STRUCTURE_REFERENCES;
case BIOMES -> ChunkStatus.BIOMES;
case NOISE -> ChunkStatus.NOISE;
case SURFACE -> ChunkStatus.SURFACE;
case CARVERS, LIQUID_CARVERS -> ChunkStatus.CARVERS;
default -> ChunkStatus.FEATURES;
};
int reach =
status.isBefore(ChunkStatus.FEATURES)
? target.getAccumulatedRadiusOf(status)
: 0;
borders.put(step, radius - reach);
}
WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP = borders.build();
MAX_WORLD_GEN_CHUNK_BORDER_NEEDED = radius;
}
}

View file

@ -0,0 +1,36 @@
package dev.quorate.tune.mixin;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
import com.seibel.distanthorizons.core.generation.queues.IFullDataSourceRetrievalQueue;
import dev.quorate.tune.LodWork;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import java.util.concurrent.atomic.AtomicReference;
@Mixin(
targets =
"com.seibel.distanthorizons.core.file.fullDatafile.GeneratedFullDataSourceProvider",
remap = false)
public abstract class RefineData {
@Shadow @Final public AtomicReference<IFullDataSourceRetrievalQueue> worldGenQueueRef;
@ModifyExpressionValue(
method = "getPositionsToRetrieve",
at =
@At(
value = "FIELD",
target =
"Lcom/seibel/distanthorizons/api/enums/worldGeneration/EDhApiWorldGenerationStep;FEATURES:Lcom/seibel/distanthorizons/api/enums/worldGeneration/EDhApiWorldGenerationStep;"))
private EDhApiWorldGenerationStep saltatory$step(EDhApiWorldGenerationStep step) {
return worldGenQueueRef.get() instanceof LodWork.Queue queue
&& queue.saltatory$refiner() != null
? EDhApiWorldGenerationStep.LIGHT
: step;
}
}

View file

@ -0,0 +1,29 @@
package dev.quorate.tune.mixin;
import com.seibel.distanthorizons.core.file.fullDatafile.GeneratedFullDataSourceProvider;
import com.seibel.distanthorizons.core.generation.queues.AbstractLodRequestState;
import com.seibel.distanthorizons.core.level.IDhLevel;
import dev.quorate.tune.LodWork;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(
targets = "com.seibel.distanthorizons.core.generation.queues.LodRequestModule",
remap = false)
public abstract class RefineInit {
@Shadow @Final private IDhLevel level;
@Inject(method = "startWorldGen", at = @At("HEAD"), cancellable = true)
private void saltatory$start(
GeneratedFullDataSourceProvider provider,
AbstractLodRequestState state,
CallbackInfo ci) {
if (!LodWork.isLoaded(level.getLevelWrapper().getWrappedMcObject())) ci.cancel();
}
}

View file

@ -0,0 +1,58 @@
package dev.quorate.tune.mixin;
import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiWorldGenerator;
import com.seibel.distanthorizons.core.generation.tasks.DataSourceRetrievalTask;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import dev.quorate.tune.LodWork;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.function.Function;
@Mixin(
targets = "com.seibel.distanthorizons.core.generation.queues.WorldGenerationQueue",
remap = false)
public abstract class RefineQueue implements LodWork.Queue {
@Shadow @Final private IDhApiWorldGenerator generator;
@Shadow @Final
private ConcurrentHashMap<Long, DataSourceRetrievalTask> inProgressGenTasksByLodPos;
@Override
public LodWork.Generator saltatory$refiner() {
return generator instanceof LodWork.Generator refine && refine.saltatory$active()
? refine
: null;
}
@Redirect(
method = "tryStartNextWorldGenTask",
at =
@At(
value = "INVOKE",
target =
"Ljava/util/concurrent/ConcurrentHashMap;reduceEntries(JLjava/util/function/Function;Ljava/util/function/BiFunction;)Ljava/lang/Object;"))
private <T, R> R saltatory$pick(
ConcurrentHashMap<Long, T> tasks,
long threshold,
Function<Map.Entry<Long, T>, R> mapper,
BiFunction<R, R, R> reducer) {
var refine = saltatory$refiner();
if (refine == null) return tasks.reduceEntries(threshold, mapper, reducer);
return LodWork.pick(
tasks,
threshold,
mapper,
reducer,
pos -> DhSectionPos.getDetailLevel(pos) == 6,
() -> inProgressGenTasksByLodPos.isEmpty() && refine.saltatory$ready());
}
}

View file

@ -0,0 +1,20 @@
package dev.quorate.tune.mixin;
import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
import dev.quorate.tune.LodWork;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Pseudo
@Mixin(targets = "com.pockyl.dhturbo.dh.DhIntegration", remap = false)
public abstract class TurboInit {
@Inject(method = "levelLoaded", at = @At("RETURN"))
private static void saltatory$loaded(IDhApiLevelWrapper wrapper, CallbackInfo ci) {
LodWork.loaded(wrapper.getWrappedMcObject());
}
}

View file

@ -0,0 +1,65 @@
package dev.quorate.tune.mixin;
import com.pockyl.dhturbo.Config;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiGeneratorPlan;
import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.world.DhServerWorld;
import dev.quorate.tune.LodWork;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.lang.management.ManagementFactory;
@Pseudo
@Mixin(targets = "com.pockyl.dhturbo.dh.TurboWorldGenerator", remap = false)
public abstract class TurboMixin implements LodWork.Generator {
@Shadow @Final private IDhApiLevelWrapper levelWrapper;
@Shadow @Final private ResourceKey<Level> dimension;
@Shadow
private EDhApiGeneratorPlan plan() {
throw new AssertionError();
}
@Inject(method = "wantsRealChunks", at = @At("HEAD"), cancellable = true)
private void saltatory$native(int x, int z, byte detail, CallbackInfoReturnable<Boolean> cir) {
if (detail == 0 && saltatory$hybrid()) cir.setReturnValue(saltatory$active());
}
@Override
public boolean saltatory$active() {
return saltatory$hybrid()
&& (!(SharedApi.getAbstractDhWorld() instanceof DhServerWorld world)
|| world.getPregenManager().getRunningPregen() == null);
}
private boolean saltatory$hybrid() {
return Config.generates(dimension)
&& Config.REAL_CHUNKS_NEARBY.get()
&& plan() == EDhApiGeneratorPlan.SURFACE_THEN_CHUNKS;
}
@Override
public boolean saltatory$ready() {
var cpu =
(com.sun.management.OperatingSystemMXBean)
ManagementFactory.getOperatingSystemMXBean();
var level = (ServerLevel) levelWrapper.getWrappedMcObject();
return LodWork.ready(
Runtime.getRuntime().availableProcessors(),
cpu.getCpuLoad(),
level.getServer().getCurrentSmoothedTickTime());
}
}

View file

@ -85,3 +85,6 @@ config="tune.terrain.mixins.json"
[[mixins]] [[mixins]]
config="tune.biome.mixins.json" config="tune.biome.mixins.json"
[[mixins]]
config="tune.curio.mixins.json"

View file

@ -0,0 +1,9 @@
{
"required": true,
"minVersion": "0.8.7",
"package": "dev.quorate.tune.mixin",
"plugin": "dev.quorate.tune.mixin.CurioPlugin",
"compatibilityLevel": "JAVA_21",
"server": ["CurioStack"],
"injectors": {"defaultRequire": 1}
}

View file

@ -6,7 +6,13 @@
"plugin": "dev.quorate.tune.mixin.LodPlugin", "plugin": "dev.quorate.tune.mixin.LodPlugin",
"mixins": [ "mixins": [
"LodMap", "LodMap",
"LodQueueMixin" "LodQueueMixin",
"TurboInit",
"RefineInit",
"TurboMixin",
"RefineQueue",
"RefineData",
"RefineBorder"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1

View file

@ -0,0 +1,43 @@
package dev.quorate.tune;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
final class LodWorkTest {
@Test
void foregroundWinsEvenWhenRefinementIsNearer() {
var tasks = new ConcurrentHashMap<>(Map.of(1L, 1, 100L, 100));
assertEquals(
100,
LodWork.<Integer, Integer>pick(
tasks, 1024, Map.Entry::getValue, Math::min, pos -> pos == 1, () -> true));
}
@Test
void refinementWaitsWithoutConsumingTheRequest() {
var tasks = new ConcurrentHashMap<>(Map.of(1L, 1));
assertNull(
LodWork.pick(
tasks, 1024, Map.Entry::getValue, Math::min, pos -> true, () -> false));
assertEquals(Map.of(1L, 1), tasks);
assertEquals(
1,
LodWork.<Integer, Integer>pick(
tasks, 1024, Map.Entry::getValue, Math::min, pos -> true, () -> true));
}
@Test
void cpuAdmissionFitsOneNativeBatch() {
assertTrue(LodWork.ready(2, .4, 5));
assertFalse(LodWork.ready(16, .95, 5));
assertFalse(LodWork.ready(16, .5, 50));
assertFalse(LodWork.ready(16, -1, 5));
}
}

View file

@ -7,6 +7,29 @@ import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
final class ModRangesTest { final class ModRangesTest {
@Test
void turboRefinementAllowsCompatiblePatches() {
assertFalse(ModRanges.contains(new DefaultArtifactVersion("1.4.0"), LodPlugin.TURBO));
assertTrue(ModRanges.contains(new DefaultArtifactVersion("1.5.0"), LodPlugin.TURBO));
assertTrue(ModRanges.contains(new DefaultArtifactVersion("1.5.1"), LodPlugin.TURBO));
assertFalse(ModRanges.contains(new DefaultArtifactVersion("1.6.0"), LodPlugin.TURBO));
assertFalse(ModRanges.contains(new DefaultArtifactVersion("3.3.2"), LodPlugin.DH));
assertTrue(ModRanges.contains(new DefaultArtifactVersion("3.3.3"), LodPlugin.DH));
assertTrue(ModRanges.contains(new DefaultArtifactVersion("3.3.4"), LodPlugin.DH));
assertFalse(ModRanges.contains(new DefaultArtifactVersion("3.4.0"), LodPlugin.DH));
}
@Test
void curioSnapshotsAllowCompatibleUpdates() {
assertFalse(
ModRanges.contains(new DefaultArtifactVersion("9.5.0+1.21.1"), CurioPlugin.CURIOS));
assertTrue(
ModRanges.contains(new DefaultArtifactVersion("9.5.1+1.21.1"), CurioPlugin.CURIOS));
assertTrue(
ModRanges.contains(new DefaultArtifactVersion("9.6.0+1.21.1"), CurioPlugin.CURIOS));
assertFalse(ModRanges.contains(new DefaultArtifactVersion("10.0.0"), CurioPlugin.CURIOS));
}
@Test @Test
void chunkSnapshotsAllowLaterCompatibleReleases() { void chunkSnapshotsAllowLaterCompatibleReleases() {
assertFalse( assertFalse(