Fix infinite loop in mc.scheduledTasks (fixes #86)
This commit is contained in:
@@ -26,6 +26,9 @@ import net.minecraftforge.fml.common.ModContainer;
|
||||
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
import net.minecraftforge.fml.common.eventhandler.EventBus;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
@@ -306,11 +309,38 @@ public class ReplayMod {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set when the currently running code has been scheduled by runLater.
|
||||
* If this is the case, subsequent calls to runLater have to be delayed until all scheduled tasks have been
|
||||
* processed, otherwise a livelock may occur.
|
||||
*/
|
||||
private boolean inRunLater = false;
|
||||
|
||||
public void runLater(Runnable runnable) {
|
||||
if (mc.isCallingFromMinecraftThread() && inRunLater) {
|
||||
EventBus bus = FMLCommonHandler.instance().bus();
|
||||
bus.register(new Object() {
|
||||
@SubscribeEvent
|
||||
public void onRenderTick(TickEvent.RenderTickEvent event) {
|
||||
if (event.phase == TickEvent.Phase.START) {
|
||||
runLater(runnable);
|
||||
bus.unregister(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
Queue<ListenableFutureTask> tasks = mc.scheduledTasks;
|
||||
synchronized (mc.scheduledTasks) {
|
||||
tasks.add(ListenableFutureTask.create(runnable, null));
|
||||
tasks.add(ListenableFutureTask.create(() -> {
|
||||
inRunLater = true;
|
||||
try {
|
||||
runnable.run();
|
||||
} finally {
|
||||
inRunLater = false;
|
||||
}
|
||||
}, null));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.replaymod.replay;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.common.util.concurrent.ListenableFutureTask;
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.core.utils.Restrictions;
|
||||
import com.replaymod.replay.camera.CameraEntity;
|
||||
import com.replaymod.replaystudio.replay.ReplayFile;
|
||||
@@ -30,7 +30,6 @@ import java.io.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* Sends replay packets to netty channels.
|
||||
@@ -440,22 +439,19 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
new Callable<Void>() {
|
||||
new Runnable() {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Void call() {
|
||||
public void run() {
|
||||
if (mc.theWorld == null || !mc.isCallingFromMinecraftThread()) {
|
||||
synchronized(mc.scheduledTasks) {
|
||||
mc.scheduledTasks.add(ListenableFutureTask.create(this));
|
||||
}
|
||||
return null;
|
||||
ReplayMod.instance.runLater(this);
|
||||
return;
|
||||
}
|
||||
|
||||
CameraEntity cent = replayHandler.getCameraEntity();
|
||||
cent.setCameraPosition(ppl.func_148932_c(), ppl.func_148928_d(), ppl.func_148933_e());
|
||||
return null;
|
||||
}
|
||||
}.call();
|
||||
}.run();
|
||||
}
|
||||
|
||||
if(p instanceof S2BPacketChangeGameState) {
|
||||
|
||||
Reference in New Issue
Block a user