Implement chunk forcing during rendering for 1.15
This commit is contained in:
@@ -16,7 +16,7 @@ import com.replaymod.render.mixin.MainWindowAccessor;
|
||||
import static com.replaymod.core.versions.MCVer.getWindow;
|
||||
//#endif
|
||||
|
||||
//#if MC>=10800 && MC<11500
|
||||
//#if MC>=10800
|
||||
import com.replaymod.render.hooks.ChunkLoadingRenderGlobal;
|
||||
//#endif
|
||||
|
||||
@@ -44,7 +44,7 @@ public class ScreenshotRenderer implements RenderInfo {
|
||||
boolean hideGUIBefore = mc.options.hudHidden;
|
||||
mc.options.hudHidden = true;
|
||||
|
||||
//#if MC>=10800 && MC<11500
|
||||
//#if MC>=10800
|
||||
ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.worldRenderer);
|
||||
//#endif
|
||||
|
||||
@@ -56,7 +56,7 @@ public class ScreenshotRenderer implements RenderInfo {
|
||||
new ScreenshotWriter(settings.getOutputFile())).run();
|
||||
}
|
||||
|
||||
//#if MC>=10800 && MC<11500
|
||||
//#if MC>=10800
|
||||
clrg.uninstall();
|
||||
//#endif
|
||||
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
// FIXME 1.15 chunk rendering has changed significantly, ignoring this feature for now
|
||||
//#if MC>=10800 && MC<11500
|
||||
//#if MC>=10800
|
||||
package com.replaymod.render.hooks;
|
||||
|
||||
import net.minecraft.client.render.WorldRenderer;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
//#if MC>=11500
|
||||
//#else
|
||||
import com.replaymod.render.mixin.ChunkRenderDispatcherAccessor;
|
||||
import com.replaymod.render.mixin.WorldRendererAccessor;
|
||||
import com.replaymod.render.utils.JailingQueue;
|
||||
import net.minecraft.client.render.chunk.BlockBufferBuilderStorage;
|
||||
import net.minecraft.client.render.WorldRenderer;
|
||||
import net.minecraft.client.render.chunk.ChunkBuilder;
|
||||
import net.minecraft.client.render.chunk.ChunkRenderTask;
|
||||
import net.minecraft.client.render.chunk.ChunkRenderWorker;
|
||||
import net.minecraft.client.render.chunk.ChunkRenderer;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Iterator;
|
||||
import static com.replaymod.core.versions.MCVer.*;
|
||||
//#endif
|
||||
|
||||
//#if MC>=10904
|
||||
import java.util.concurrent.PriorityBlockingQueue;
|
||||
@@ -21,8 +25,6 @@ import java.util.concurrent.PriorityBlockingQueue;
|
||||
//$$ import java.util.concurrent.BlockingQueue;
|
||||
//#endif
|
||||
|
||||
import static com.replaymod.core.versions.MCVer.*;
|
||||
|
||||
public class ChunkLoadingRenderGlobal {
|
||||
|
||||
//#if MC>=11400
|
||||
@@ -30,6 +32,9 @@ public class ChunkLoadingRenderGlobal {
|
||||
//#else
|
||||
//$$ private final RenderGlobal hooked;
|
||||
//#endif
|
||||
|
||||
//#if MC>=11500
|
||||
//#else
|
||||
private ChunkBuilder renderDispatcher;
|
||||
//#if MC>=11400
|
||||
private JailingQueue<ChunkRenderTask> workerJailingQueue;
|
||||
@@ -38,8 +43,8 @@ public class ChunkLoadingRenderGlobal {
|
||||
//#endif
|
||||
private ChunkRenderWorkerAccessor renderWorker;
|
||||
private int frame;
|
||||
//#endif
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChunkLoadingRenderGlobal(
|
||||
//#if MC>=11400
|
||||
WorldRenderer renderGlobal
|
||||
@@ -49,9 +54,29 @@ public class ChunkLoadingRenderGlobal {
|
||||
) {
|
||||
this.hooked = renderGlobal;
|
||||
|
||||
//#if MC>=11500
|
||||
//$$ install();
|
||||
//#else
|
||||
setup(((WorldRendererAccessor) renderGlobal).getRenderDispatcher());
|
||||
install();
|
||||
//#endif
|
||||
}
|
||||
|
||||
private void install() {
|
||||
try {
|
||||
//#if MC>=11400
|
||||
Field hookField = WorldRenderer.class.getField("replayModRender_hook");
|
||||
//#else
|
||||
//$$ Field hookField = RenderGlobal.class.getField("replayModRender_hook");
|
||||
//#endif
|
||||
hookField.set(hooked, this);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
//#if MC>=11500
|
||||
//#else
|
||||
public void updateRenderDispatcher(ChunkBuilder renderDispatcher) {
|
||||
if (this.renderDispatcher != null) {
|
||||
workerJailingQueue.freeAll();
|
||||
@@ -98,17 +123,6 @@ public class ChunkLoadingRenderGlobal {
|
||||
|
||||
workerJailingQueue.jail(workerThreads);
|
||||
renderDispatcherAcc.setQueueChunkUpdates(queueChunkUpdates);
|
||||
|
||||
try {
|
||||
//#if MC>=11400
|
||||
Field hookField = WorldRenderer.class.getField("replayModRender_hook");
|
||||
//#else
|
||||
//$$ Field hookField = RenderGlobal.class.getField("replayModRender_hook");
|
||||
//#endif
|
||||
hookField.set(hooked, this);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateChunks() {
|
||||
@@ -143,8 +157,15 @@ public class ChunkLoadingRenderGlobal {
|
||||
}
|
||||
}
|
||||
|
||||
public int nextFrameId() {
|
||||
return frame++;
|
||||
}
|
||||
//#endif
|
||||
|
||||
public void uninstall() {
|
||||
//#if MC<11500
|
||||
workerJailingQueue.freeAll();
|
||||
//#endif
|
||||
|
||||
try {
|
||||
//#if MC>=11400
|
||||
@@ -158,8 +179,10 @@ public class ChunkLoadingRenderGlobal {
|
||||
}
|
||||
}
|
||||
|
||||
public int nextFrameId() {
|
||||
return frame++;
|
||||
}
|
||||
//#if MC>=11500
|
||||
//$$ public interface IBlockOnChunkRebuilds {
|
||||
//$$ boolean uploadEverythingBlocking();
|
||||
//$$ }
|
||||
//#endif
|
||||
}
|
||||
//#endif
|
||||
|
||||
@@ -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
|
||||
@@ -49,9 +49,7 @@ import org.lwjgl.glfw.GLFW;
|
||||
//#endif
|
||||
|
||||
//#if MC>=10800
|
||||
//#if MC<11500
|
||||
import com.replaymod.render.hooks.ChunkLoadingRenderGlobal;
|
||||
//#endif
|
||||
import static com.mojang.blaze3d.platform.GlStateManager.*;
|
||||
//#else
|
||||
//$$ import com.replaymod.replay.gui.screen.GuiOpeningReplay;
|
||||
@@ -88,7 +86,7 @@ public class VideoRenderer implements RenderInfo {
|
||||
|
||||
private TimelinePlayer timelinePlayer;
|
||||
private Future<Void> timelinePlayerFuture;
|
||||
//#if MC>=10800 && MC<11500
|
||||
//#if MC>=10800
|
||||
private ChunkLoadingRenderGlobal chunkLoadingRenderGlobal;
|
||||
//#endif
|
||||
//#if MC<10800
|
||||
@@ -314,7 +312,7 @@ public class VideoRenderer implements RenderInfo {
|
||||
//$$ gui.toMinecraft().setWorldAndResolution(mc, scaled.getScaledWidth(), scaled.getScaledHeight());
|
||||
//#endif
|
||||
|
||||
//#if MC>=10800 && MC<11500
|
||||
//#if MC>=10800
|
||||
chunkLoadingRenderGlobal = new ChunkLoadingRenderGlobal(mc.worldRenderer);
|
||||
//#endif
|
||||
|
||||
@@ -351,7 +349,7 @@ public class VideoRenderer implements RenderInfo {
|
||||
mc.options.setSoundVolume(entry.getKey(), entry.getValue());
|
||||
}
|
||||
mc.openScreen(null);
|
||||
//#if MC>=10800 && MC<11500
|
||||
//#if MC>=10800
|
||||
if (chunkLoadingRenderGlobal != null) {
|
||||
chunkLoadingRenderGlobal.uninstall();
|
||||
}
|
||||
|
||||
@@ -8,9 +8,13 @@
|
||||
"Mixin_ChromaKeyForceSky",
|
||||
"Mixin_CubicRotation",
|
||||
"Mixin_SkipBlockOutlinesDuringRender",
|
||||
//#if MC>=10800 && MC<11500
|
||||
//#if MC>=10800
|
||||
//#if MC>=11500
|
||||
//$$ "Mixin_BlockOnChunkRebuilds",
|
||||
//#else
|
||||
"ChunkRenderDispatcherAccessor",
|
||||
"MixinChunkRenderWorker",
|
||||
//#endif
|
||||
"Mixin_ForceChunkLoading",
|
||||
//#endif
|
||||
//#if MC>=11400
|
||||
"MainWindowAccessor",
|
||||
|
||||
Reference in New Issue
Block a user