Improved chunk deadlock detection system + patch Valhelsia Structures
when installed
This commit is contained in:
parent
10149e9f87
commit
e977fcdfce
|
|
@ -98,6 +98,7 @@ dependencies {
|
||||||
modRuntimeOnly("curse.maven:ferritecore-429235:4074330")
|
modRuntimeOnly("curse.maven:ferritecore-429235:4074330")
|
||||||
modCompileOnly("team.chisel.ctm:CTM:${ctm_version}")
|
modCompileOnly("team.chisel.ctm:CTM:${ctm_version}")
|
||||||
modCompileOnly("curse.maven:supermartijncore-454372:4455378")
|
modCompileOnly("curse.maven:supermartijncore-454372:4455378")
|
||||||
|
modCompileOnly("curse.maven:valhesiastructures-347488:3476252")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,14 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if(mixinClassName.equals("org.embeddedt.modernfix.mixin.bugfix.chunk_deadlock.valhesia.BlockStateBaseMixin")) {
|
||||||
|
// We need to destroy Valhelsia's callback so it can never run getBlockState
|
||||||
|
for(MethodNode m : targetClass.methods) {
|
||||||
|
if(m.name.contains("valhelsia_placeDousedTorch")) {
|
||||||
|
m.instructions.clear();
|
||||||
|
m.instructions.add(new InsnNode(Opcodes.RETURN));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -50,6 +50,7 @@ public class ModernFixEarlyConfig {
|
||||||
this.addMixinRule("bugfix.structure_manager_crash", true);
|
this.addMixinRule("bugfix.structure_manager_crash", true);
|
||||||
this.addMixinRule("bugfix.mc218112", true);
|
this.addMixinRule("bugfix.mc218112", true);
|
||||||
this.addMixinRule("bugfix.chunk_deadlock", true);
|
this.addMixinRule("bugfix.chunk_deadlock", true);
|
||||||
|
this.addMixinRule("bugfix.chunk_deadlock.valhesia", modPresent("valhelsia_structures"));
|
||||||
this.addMixinRule("bugfix.tf_cme_on_load", modPresent("twilightforest"));
|
this.addMixinRule("bugfix.tf_cme_on_load", modPresent("twilightforest"));
|
||||||
this.addMixinRule("bugfix.refinedstorage", modPresent("refinedstorage"));
|
this.addMixinRule("bugfix.refinedstorage", modPresent("refinedstorage"));
|
||||||
this.addMixinRule("perf.async_jei", modPresent("jei"));
|
this.addMixinRule("perf.async_jei", modPresent("jei"));
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package org.embeddedt.modernfix.mixin.bugfix.chunk_deadlock;
|
package org.embeddedt.modernfix.mixin.bugfix.chunk_deadlock;
|
||||||
|
|
||||||
|
import com.mojang.datafixers.util.Either;
|
||||||
|
import net.minecraft.server.level.ChunkHolder;
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
import net.minecraft.server.level.ServerChunkCache;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
|
@ -13,12 +15,18 @@ import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
@Mixin(value = ServerChunkCache.class, priority = 1100)
|
@Mixin(value = ServerChunkCache.class, priority = 1100)
|
||||||
public abstract class ServerChunkCacheMixin {
|
public abstract class ServerChunkCacheMixin {
|
||||||
@Shadow @Final private Thread mainThread;
|
@Shadow @Final private Thread mainThread;
|
||||||
@Shadow @Final public ServerLevel level;
|
@Shadow @Final public ServerLevel level;
|
||||||
|
|
||||||
|
@Shadow protected abstract CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> getChunkFutureMainThread(int k, int l, ChunkStatus arg, boolean bl);
|
||||||
|
|
||||||
|
@Shadow @Final private ServerChunkCache.MainThreadExecutor mainThreadProcessor;
|
||||||
private final boolean debugDeadServerAccess = Boolean.getBoolean("modernfix.debugBadChunkloading");
|
private final boolean debugDeadServerAccess = Boolean.getBoolean("modernfix.debugBadChunkloading");
|
||||||
|
|
||||||
@Inject(method = "getChunk", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "getChunk", at = @At("HEAD"), cancellable = true)
|
||||||
private void bailIfServerDead(int chunkX, int chunkZ, ChunkStatus requiredStatus, boolean load, CallbackInfoReturnable<ChunkAccess> cir) {
|
private void bailIfServerDead(int chunkX, int chunkZ, ChunkStatus requiredStatus, boolean load, CallbackInfoReturnable<ChunkAccess> cir) {
|
||||||
if(!this.mainThread.isAlive()) {
|
if(!this.mainThread.isAlive()) {
|
||||||
|
|
@ -27,6 +35,34 @@ public abstract class ServerChunkCacheMixin {
|
||||||
new Exception().printStackTrace();
|
new Exception().printStackTrace();
|
||||||
}
|
}
|
||||||
cir.setReturnValue(new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ)));
|
cir.setReturnValue(new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ)));
|
||||||
|
} else if(Thread.currentThread() != this.mainThread) {
|
||||||
|
CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> future = CompletableFuture.supplyAsync(() -> this.getChunkFutureMainThread(chunkX, chunkZ, requiredStatus, false), this.mainThreadProcessor).join();
|
||||||
|
if(!future.isDone()) {
|
||||||
|
// Wait at least 500 milliseconds before printing anything
|
||||||
|
Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> resultingChunk = null;
|
||||||
|
try {
|
||||||
|
resultingChunk = future.get(500, TimeUnit.MILLISECONDS);
|
||||||
|
} catch(InterruptedException | ExecutionException | TimeoutException ignored) {
|
||||||
|
}
|
||||||
|
if(resultingChunk != null && resultingChunk.left().isPresent()) {
|
||||||
|
cir.setReturnValue(resultingChunk.left().get());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(debugDeadServerAccess)
|
||||||
|
ModernFix.LOGGER.warn("Async loading of a chunk was requested, this might not be desirable", new Exception());
|
||||||
|
else
|
||||||
|
ModernFix.LOGGER.warn("Suspicious async chunkload, pass -Dmodernfix.debugBadChunkloading=true for more details");
|
||||||
|
try {
|
||||||
|
resultingChunk = future.get(10, TimeUnit.SECONDS);
|
||||||
|
if(resultingChunk.left().isPresent()) {
|
||||||
|
cir.setReturnValue(resultingChunk.left().get());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch(InterruptedException | ExecutionException | TimeoutException e) {
|
||||||
|
ModernFix.LOGGER.error("Async chunk load took way too long, this needs to be reported to the appropriate mod.", e);
|
||||||
|
}
|
||||||
|
//cir.setReturnValue(new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package org.embeddedt.modernfix.mixin.bugfix.chunk_deadlock.valhesia;
|
||||||
|
|
||||||
|
import com.stal111.valhelsia_structures.init.ModBlocks;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
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.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(value = BlockBehaviour.BlockStateBase.class, priority = 900)
|
||||||
|
public abstract class BlockStateBaseMixin {
|
||||||
|
@Shadow public abstract Block getBlock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do not call getBlockState here; this can cause deadlocks during world gen/lighting.
|
||||||
|
*/
|
||||||
|
@Inject(method = "getOffset", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void useThisBlock(BlockGetter getter, BlockPos pos, CallbackInfoReturnable<Vec3> cir) {
|
||||||
|
if(this.getBlock() == ModBlocks.BONE_PILE.get())
|
||||||
|
cir.setReturnValue(new Vec3(0.0, -0.46875, 0.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -29,8 +29,9 @@ public class IntegratedWatchdog extends Thread {
|
||||||
while(server.isRunning()) {
|
while(server.isRunning()) {
|
||||||
long nextTick = this.server.getNextTickTime();
|
long nextTick = this.server.getNextTickTime();
|
||||||
long curTime = Util.getMillis();
|
long curTime = Util.getMillis();
|
||||||
if((curTime - nextTick) > MAX_TICK_DELTA) {
|
long delta = curTime - nextTick;
|
||||||
LOGGER.error("A single server tick has taken {}, more than {} milliseconds", (nextTick - curTime), MAX_TICK_DELTA);
|
if(delta > MAX_TICK_DELTA) {
|
||||||
|
LOGGER.error("A single server tick has taken {}, more than {} milliseconds", delta, MAX_TICK_DELTA);
|
||||||
ThreadMXBean threadmxbean = ManagementFactory.getThreadMXBean();
|
ThreadMXBean threadmxbean = ManagementFactory.getThreadMXBean();
|
||||||
ThreadInfo[] athreadinfo = threadmxbean.dumpAllThreads(true, true);
|
ThreadInfo[] athreadinfo = threadmxbean.dumpAllThreads(true, true);
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,4 @@ public net.minecraft.block.AbstractBlock$Properties field_235818_t_ # hasPostPro
|
||||||
public net.minecraft.block.AbstractBlock$Properties field_235819_u_ # emissiveRendering
|
public net.minecraft.block.AbstractBlock$Properties field_235819_u_ # emissiveRendering
|
||||||
public net.minecraft.block.AbstractBlock$Properties field_235806_h_ # requiresCorrectToolForDrops
|
public net.minecraft.block.AbstractBlock$Properties field_235806_h_ # requiresCorrectToolForDrops
|
||||||
public net.minecraft.block.AbstractBlock$Properties field_200959_g # destroyTime
|
public net.minecraft.block.AbstractBlock$Properties field_200959_g # destroyTime
|
||||||
|
public net.minecraft.world.server.ServerChunkProvider$ChunkExecutor
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
"bugfix.refinedstorage.te_bug.ItemExternalStorageCacheMixin",
|
"bugfix.refinedstorage.te_bug.ItemExternalStorageCacheMixin",
|
||||||
"bugfix.refinedstorage.te_bug.ItemExternalStorageMixin",
|
"bugfix.refinedstorage.te_bug.ItemExternalStorageMixin",
|
||||||
"bugfix.chunk_deadlock.ServerChunkCacheMixin",
|
"bugfix.chunk_deadlock.ServerChunkCacheMixin",
|
||||||
|
"bugfix.chunk_deadlock.valhesia.BlockStateBaseMixin",
|
||||||
"perf.remove_biome_temperature_cache.BiomeMixin",
|
"perf.remove_biome_temperature_cache.BiomeMixin",
|
||||||
"perf.resourcepacks.ModFileResourcePackMixin",
|
"perf.resourcepacks.ModFileResourcePackMixin",
|
||||||
"perf.resourcepacks.VanillaPackMixin",
|
"perf.resourcepacks.VanillaPackMixin",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user