Ensure exceptions thrown in chunk load events are not dropped
This commit is contained in:
parent
bee4536c1a
commit
ac8d93d5b9
|
|
@ -4,6 +4,8 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import com.mojang.datafixers.util.Either;
|
import com.mojang.datafixers.util.Either;
|
||||||
|
import net.minecraft.CrashReport;
|
||||||
|
import net.minecraft.ReportedException;
|
||||||
import net.minecraft.server.level.ChunkHolder;
|
import net.minecraft.server.level.ChunkHolder;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.util.thread.BlockableEventLoop;
|
import net.minecraft.util.thread.BlockableEventLoop;
|
||||||
|
|
@ -19,10 +21,12 @@ import org.spongepowered.asm.mixin.Unique;
|
||||||
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.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
|
@ -39,6 +43,9 @@ public abstract class ChunkMapLoadMixin {
|
||||||
@Unique
|
@Unique
|
||||||
private static final ThreadLocal<CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>> MFIX_SURROGATE_FUTURE = new ThreadLocal<>();
|
private static final ThreadLocal<CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>> MFIX_SURROGATE_FUTURE = new ThreadLocal<>();
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private final ConcurrentLinkedQueue<Throwable> mfix$promotionExceptions = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author embeddedt
|
* @author embeddedt
|
||||||
* @reason This redirect makes several changes to how full chunk promotion works. First of all, promotion runs
|
* @reason This redirect makes several changes to how full chunk promotion works. First of all, promotion runs
|
||||||
|
|
@ -72,7 +79,14 @@ public abstract class ChunkMapLoadMixin {
|
||||||
}
|
}
|
||||||
}, this.mainThreadExecutor).whenComplete((either, throwable) -> {
|
}, this.mainThreadExecutor).whenComplete((either, throwable) -> {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
surrogate.completeExceptionally(throwable);
|
if (!surrogate.isDone()) {
|
||||||
|
surrogate.completeExceptionally(throwable);
|
||||||
|
} else {
|
||||||
|
// The chunk has already become visible at FULL status, so we
|
||||||
|
// track the exception ourselves and manually rethrow it at the right point
|
||||||
|
// to trigger a server crash
|
||||||
|
this.mfix$promotionExceptions.add(throwable);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
surrogate.complete(either);
|
surrogate.complete(either);
|
||||||
}
|
}
|
||||||
|
|
@ -95,6 +109,19 @@ public abstract class ChunkMapLoadMixin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject(method = "tick()V", at = @At("HEAD"))
|
||||||
|
private void reportDeferredPromotionException(CallbackInfo ci) {
|
||||||
|
var throwable = this.mfix$promotionExceptions.poll();
|
||||||
|
if (throwable == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (throwable instanceof ReportedException e) {
|
||||||
|
throw e;
|
||||||
|
} else {
|
||||||
|
throw new ReportedException(CrashReport.forThrowable(throwable, "Exception during promotion of chunk to FULL status"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// we also preserve the legacy currentlyLoading field to keep Forge parity
|
// we also preserve the legacy currentlyLoading field to keep Forge parity
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user