Implement chunk forcing during rendering for 1.15
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
package com.replaymod.render.mixin;
|
||||
|
||||
//#if MC>=11500
|
||||
//$$ import com.replaymod.render.hooks.ChunkLoadingRenderGlobal;
|
||||
//$$ import net.minecraft.client.render.chunk.BlockBufferBuilderStorage;
|
||||
//$$ import net.minecraft.client.render.chunk.ChunkBuilder;
|
||||
//$$ import net.minecraft.util.thread.TaskExecutor;
|
||||
//$$ 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;
|
||||
//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
//$$
|
||||
//$$ import java.util.Queue;
|
||||
//$$ import java.util.concurrent.CompletableFuture;
|
||||
//$$ import java.util.concurrent.locks.Condition;
|
||||
//$$ import java.util.concurrent.locks.Lock;
|
||||
//$$ import java.util.concurrent.locks.ReentrantLock;
|
||||
//$$
|
||||
//$$ @Mixin(ChunkBuilder.class)
|
||||
//$$ public abstract class Mixin_BlockOnChunkRebuilds implements ChunkLoadingRenderGlobal.IBlockOnChunkRebuilds {
|
||||
//$$ @Shadow @Final private Queue<BlockBufferBuilderStorage> threadBuffers;
|
||||
//$$
|
||||
//$$ @Shadow public abstract boolean upload();
|
||||
//$$
|
||||
//$$ @Shadow @Final private TaskExecutor<Runnable> mailbox;
|
||||
//$$
|
||||
//$$ @Shadow protected abstract void scheduleRunTasks();
|
||||
//$$
|
||||
//$$ @Shadow @Final private Queue<Runnable> uploadQueue;
|
||||
//$$ private final Lock waitingForWorkLock = new ReentrantLock();
|
||||
//$$ private final Condition newWork = waitingForWorkLock.newCondition();
|
||||
//$$ private volatile boolean allDone;
|
||||
//$$
|
||||
//$$ private int totalBufferCount;
|
||||
//$$
|
||||
//$$ @Inject(method = "<init>", at = @At("RETURN"))
|
||||
//$$ private void rememberTotalThreads(CallbackInfo ci) {
|
||||
//$$ this.totalBufferCount = this.threadBuffers.size();
|
||||
//$$ }
|
||||
//$$
|
||||
//$$ @Inject(method = "scheduleRunTasks", at = @At("RETURN"))
|
||||
//$$ private void notifyMainThreadIfEverythingIsDone(CallbackInfo ci) {
|
||||
//$$ if (this.threadBuffers.size() == this.totalBufferCount) {
|
||||
//$$ // Looks like we're done, better notify the main thread in case the previous task didn't generate an upload
|
||||
//$$ this.waitingForWorkLock.lock();
|
||||
//$$ try {
|
||||
//$$ this.allDone = true;
|
||||
//$$ this.newWork.signalAll();
|
||||
//$$ } finally {
|
||||
//$$ this.waitingForWorkLock.unlock();
|
||||
//$$ }
|
||||
//$$ } else {
|
||||
//$$ this.allDone = false;
|
||||
//$$ }
|
||||
//$$ }
|
||||
//$$
|
||||
//$$ @Inject(method = "scheduleUpload", at = @At("RETURN"))
|
||||
//$$ private void notifyMainThreadOfNewUpload(CallbackInfoReturnable<CompletableFuture<Void>> ci) {
|
||||
//$$ this.waitingForWorkLock.lock();
|
||||
//$$ try {
|
||||
//$$ this.newWork.signal();
|
||||
//$$ } finally {
|
||||
//$$ this.waitingForWorkLock.unlock();
|
||||
//$$ }
|
||||
//$$ }
|
||||
//$$
|
||||
//$$ private boolean waitForMainThreadWork() {
|
||||
//$$ boolean allDone = this.mailbox.<Boolean>ask(reply -> () -> {
|
||||
//$$ scheduleRunTasks();
|
||||
//$$ reply.send(this.threadBuffers.size() == this.totalBufferCount);
|
||||
//$$ }).join();
|
||||
//$$
|
||||
//$$ if (allDone) {
|
||||
//$$ return true;
|
||||
//$$ } else {
|
||||
//$$ this.waitingForWorkLock.lock();
|
||||
//$$ try {
|
||||
//$$ while (true) {
|
||||
//$$ if (this.allDone) {
|
||||
//$$ return true;
|
||||
//$$ } else if (!this.uploadQueue.isEmpty()) {
|
||||
//$$ return false;
|
||||
//$$ } else {
|
||||
//$$ this.newWork.awaitUninterruptibly();
|
||||
//$$ }
|
||||
//$$ }
|
||||
//$$ } finally {
|
||||
//$$ this.waitingForWorkLock.unlock();
|
||||
//$$ }
|
||||
//$$ }
|
||||
//$$ }
|
||||
//$$
|
||||
//$$ @Override
|
||||
//$$ public boolean uploadEverythingBlocking() {
|
||||
//$$ boolean anything = false;
|
||||
//$$
|
||||
//$$ boolean allChunksBuilt;
|
||||
//$$ do {
|
||||
//$$ allChunksBuilt = waitForMainThreadWork();
|
||||
//$$ while (upload()) {
|
||||
//$$ anything = true;
|
||||
//$$ }
|
||||
//$$ } while (!allChunksBuilt);
|
||||
//$$
|
||||
//$$ return anything;
|
||||
//$$ }
|
||||
//$$ }
|
||||
//#endif
|
||||
@@ -1,17 +1,24 @@
|
||||
//#if MC>=10800 && MC<11500
|
||||
package com.replaymod.render.mixin;
|
||||
|
||||
//#if MC>=10800
|
||||
import com.replaymod.render.hooks.ChunkLoadingRenderGlobal;
|
||||
import net.minecraft.client.render.Camera;
|
||||
import net.minecraft.client.render.Frustum;
|
||||
import net.minecraft.client.render.chunk.ChunkBuilder;
|
||||
import net.minecraft.client.render.VisibleRegion;
|
||||
import net.minecraft.entity.Entity;
|
||||
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;
|
||||
|
||||
//#if MC>=11400
|
||||
//#if MC>=11500
|
||||
//$$ import java.util.Set;
|
||||
//#else
|
||||
import net.minecraft.client.render.VisibleRegion;
|
||||
import net.minecraft.entity.Entity;
|
||||
//#endif
|
||||
|
||||
//#if MC>=11400 && MC<11500
|
||||
import net.minecraft.client.render.Camera;
|
||||
//#endif
|
||||
|
||||
@@ -32,8 +39,57 @@ import net.minecraft.client.render.WorldRenderer;
|
||||
//#else
|
||||
//$$ @Mixin(RenderGlobal.class)
|
||||
//#endif
|
||||
public abstract class MixinRenderGlobal {
|
||||
public abstract class Mixin_ForceChunkLoading {
|
||||
public ChunkLoadingRenderGlobal replayModRender_hook;
|
||||
|
||||
//#if MC>=11500
|
||||
//$$ @Shadow private Set<ChunkBuilder.BuiltChunk> chunksToRebuild;
|
||||
//$$
|
||||
//$$ @Shadow private ChunkBuilder chunkBuilder;
|
||||
//$$
|
||||
//$$ @Shadow private boolean needsTerrainUpdate;
|
||||
//$$
|
||||
//$$ @Shadow public abstract void scheduleTerrainUpdate();
|
||||
//$$
|
||||
//$$ @Shadow protected abstract void setupTerrain(Camera camera_1, Frustum frustum_1, boolean boolean_1, int int_1, boolean boolean_2);
|
||||
//$$
|
||||
//$$ @Shadow private int frame;
|
||||
//$$
|
||||
//$$ private boolean passThrough;
|
||||
//$$ @Inject(method = "setupTerrain", at = @At("HEAD"), cancellable = true)
|
||||
//$$ private void forceAllChunks(Camera camera_1, Frustum frustum_1, boolean boolean_1, int int_1, boolean boolean_2, CallbackInfo ci) {
|
||||
//$$ if (replayModRender_hook == null) {
|
||||
//$$ return;
|
||||
//$$ }
|
||||
//$$ if (passThrough) {
|
||||
//$$ return;
|
||||
//$$ }
|
||||
//$$ ci.cancel();
|
||||
//$$
|
||||
//$$ passThrough = true;
|
||||
//$$ try {
|
||||
//$$ do {
|
||||
//$$ // Determine which chunks shall be visible
|
||||
//$$ setupTerrain(camera_1, frustum_1, boolean_1, frame++, boolean_2);
|
||||
//$$
|
||||
//$$ // Schedule all chunks which need rebuilding (we schedule even important rebuilds because we wait for
|
||||
//$$ // all of them anyway and this way we can take advantage of threading)
|
||||
//$$ for (ChunkBuilder.BuiltChunk builtChunk : this.chunksToRebuild) {
|
||||
//$$ builtChunk.scheduleRebuild(this.chunkBuilder);
|
||||
//$$ builtChunk.cancelRebuild();
|
||||
//$$ }
|
||||
//$$ this.chunksToRebuild.clear();
|
||||
//$$
|
||||
//$$ // Upload all chunks
|
||||
//$$ this.needsTerrainUpdate |= ((ChunkLoadingRenderGlobal.IBlockOnChunkRebuilds) this.chunkBuilder).uploadEverythingBlocking();
|
||||
//$$
|
||||
//$$ // Repeat until no more updates are needed
|
||||
//$$ } while (this.needsTerrainUpdate);
|
||||
//$$ } finally {
|
||||
//$$ passThrough = false;
|
||||
//$$ }
|
||||
//$$ }
|
||||
//#else
|
||||
private boolean replayModRender_passThroughSetupTerrain;
|
||||
|
||||
@Shadow
|
||||
@@ -132,5 +188,6 @@ public abstract class MixinRenderGlobal {
|
||||
replayModRender_hook.updateRenderDispatcher(this.chunkBuilder);
|
||||
}
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
//#endif
|
||||
Reference in New Issue
Block a user