Split off highly version dependent code from ReplayMod
This commit is contained in:
@@ -5,8 +5,9 @@ import com.replaymod.compat.ReplayModCompat;
|
|||||||
import com.replaymod.core.gui.GuiBackgroundProcesses;
|
import com.replaymod.core.gui.GuiBackgroundProcesses;
|
||||||
import com.replaymod.core.gui.GuiReplaySettings;
|
import com.replaymod.core.gui.GuiReplaySettings;
|
||||||
import com.replaymod.core.gui.RestoreReplayGui;
|
import com.replaymod.core.gui.RestoreReplayGui;
|
||||||
import com.replaymod.core.mixin.MinecraftAccessor;
|
|
||||||
import com.replaymod.core.versions.MCVer;
|
import com.replaymod.core.versions.MCVer;
|
||||||
|
import com.replaymod.core.versions.scheduler.Scheduler;
|
||||||
|
import com.replaymod.core.versions.scheduler.SchedulerImpl;
|
||||||
import com.replaymod.editor.ReplayModEditor;
|
import com.replaymod.editor.ReplayModEditor;
|
||||||
import com.replaymod.extras.ReplayModExtras;
|
import com.replaymod.extras.ReplayModExtras;
|
||||||
import com.replaymod.recording.ReplayModRecording;
|
import com.replaymod.recording.ReplayModRecording;
|
||||||
@@ -17,7 +18,6 @@ import com.replaymod.replaystudio.replay.ZipReplayFile;
|
|||||||
import com.replaymod.replaystudio.studio.ReplayStudio;
|
import com.replaymod.replaystudio.studio.ReplayStudio;
|
||||||
import com.replaymod.replaystudio.us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
import com.replaymod.replaystudio.us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||||
import com.replaymod.replaystudio.util.I18n;
|
import com.replaymod.replaystudio.util.I18n;
|
||||||
import com.replaymod.replaystudio.viaversion.ViaVersionPacketConverter;
|
|
||||||
import com.replaymod.simplepathing.ReplayModSimplePathing;
|
import com.replaymod.simplepathing.ReplayModSimplePathing;
|
||||||
import de.johni0702.minecraft.gui.container.GuiScreen;
|
import de.johni0702.minecraft.gui.container.GuiScreen;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
@@ -28,63 +28,13 @@ import net.minecraft.text.Style;
|
|||||||
import net.minecraft.text.LiteralText;
|
import net.minecraft.text.LiteralText;
|
||||||
import net.minecraft.text.TranslatableText;
|
import net.minecraft.text.TranslatableText;
|
||||||
import net.minecraft.util.Formatting;
|
import net.minecraft.util.Formatting;
|
||||||
import net.minecraft.util.crash.CrashException;
|
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
|
|
||||||
//#if MC>=11400
|
//#if MC>=11400
|
||||||
import net.minecraft.client.options.Option;
|
import net.minecraft.client.options.Option;
|
||||||
import net.minecraft.util.thread.ReentrantThreadExecutor;
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
//#if FABRIC>=1
|
|
||||||
import net.fabricmc.api.ClientModInitializer;
|
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
|
||||||
//#else
|
//#else
|
||||||
//$$ import com.google.common.util.concurrent.ListenableFutureTask;
|
//$$ import net.minecraft.client.settings.GameSettings;
|
||||||
//$$ import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|
||||||
//$$ import java.util.Queue;
|
|
||||||
//$$ import java.util.concurrent.FutureTask;
|
|
||||||
//$$
|
|
||||||
//#if MC>=11400
|
|
||||||
//$$ import com.replaymod.core.versions.LangResourcePack;
|
|
||||||
//$$ import net.minecraft.resources.IPackFinder;
|
|
||||||
//$$ import net.minecraft.resources.ResourcePackInfo;
|
|
||||||
//$$ import net.minecraftforge.fml.DeferredWorkQueue;
|
|
||||||
//$$ import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
|
||||||
//$$ import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
|
||||||
//$$ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
|
||||||
//$$ import net.minecraftforge.versions.mcp.MCPVersion;
|
|
||||||
//#else
|
|
||||||
//$$ import static com.replaymod.core.versions.MCVer.FML_BUS;
|
|
||||||
//$$ import net.minecraft.client.resources.IResourcePack;
|
|
||||||
//$$ import net.minecraftforge.common.config.Configuration;
|
|
||||||
//#endif
|
|
||||||
//$$
|
|
||||||
//#if MC>=10800
|
|
||||||
//$$ import net.minecraft.client.GameSettings;
|
|
||||||
//#endif
|
|
||||||
//$$
|
|
||||||
//#if MC>=11400
|
|
||||||
//$$ import net.minecraftforge.fml.ModList;
|
|
||||||
//#else
|
|
||||||
//$$ import net.minecraftforge.fml.common.Loader;
|
|
||||||
//$$ import net.minecraftforge.fml.common.Mod.EventHandler;
|
|
||||||
//$$ import net.minecraftforge.fml.common.Mod.Instance;
|
|
||||||
//$$ import net.minecraftforge.fml.common.event.FMLInitializationEvent;
|
|
||||||
//$$ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
|
||||||
//#if MC>=10800
|
|
||||||
//$$ import net.minecraftforge.fml.client.FMLClientHandler;
|
|
||||||
//#else
|
|
||||||
//$$ import com.replaymod.replay.InputReplayTimer;
|
|
||||||
//$$
|
|
||||||
//$$ import java.util.ArrayDeque;
|
|
||||||
//#endif
|
|
||||||
//#endif
|
|
||||||
//$$ import net.minecraftforge.fml.common.Mod;
|
|
||||||
//#if MC<11400
|
|
||||||
//$$ import net.minecraftforge.fml.common.gameevent.TickEvent;
|
|
||||||
//#endif
|
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
@@ -102,43 +52,9 @@ import java.nio.file.attribute.BasicFileAttributes;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
//#if FABRIC<=0
|
public class ReplayMod implements Module, Scheduler {
|
||||||
//#if MC>=11400
|
|
||||||
//$$ @Mod(ReplayMod.MOD_ID)
|
|
||||||
//#else
|
|
||||||
//$$ @Mod(modid = ReplayMod.MOD_ID,
|
|
||||||
//$$ useMetadata = true,
|
|
||||||
//$$ version = "@MOD_VERSION@",
|
|
||||||
//$$ acceptedMinecraftVersions = "@MC_VERSION@",
|
|
||||||
//$$ acceptableRemoteVersions = "*",
|
|
||||||
//#if MC>=10800
|
|
||||||
//$$ clientSideOnly = true,
|
|
||||||
//$$ updateJSON = "https://raw.githubusercontent.com/ReplayMod/ReplayMod/master/versions.json",
|
|
||||||
//#endif
|
|
||||||
//$$ guiFactory = "com.replaymod.core.gui.GuiFactory")
|
|
||||||
//#endif
|
|
||||||
//#endif
|
|
||||||
public class ReplayMod implements
|
|
||||||
//#if FABRIC>=1
|
|
||||||
ClientModInitializer,
|
|
||||||
//#endif
|
|
||||||
Module
|
|
||||||
{
|
|
||||||
|
|
||||||
public static String getMinecraftVersion() {
|
|
||||||
//#if MC>=11400
|
|
||||||
return MinecraftClient.getInstance().getGame().getVersion().getName();
|
|
||||||
//#else
|
|
||||||
//#if MC>=11400
|
|
||||||
//$$ return MCPVersion.getMCVersion();
|
|
||||||
//#else
|
|
||||||
//$$ return Loader.MC_VERSION;
|
|
||||||
//#endif
|
|
||||||
//#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String MOD_ID = "replaymod";
|
public static final String MOD_ID = "replaymod";
|
||||||
|
|
||||||
@@ -148,23 +64,15 @@ public class ReplayMod implements
|
|||||||
|
|
||||||
private static final MinecraftClient mc = MCVer.getMinecraft();
|
private static final MinecraftClient mc = MCVer.getMinecraft();
|
||||||
|
|
||||||
//#if MC<11400
|
private final ReplayModBackend backend;
|
||||||
//$$ @Deprecated
|
private final SchedulerImpl scheduler = new SchedulerImpl();
|
||||||
//$$ public static Configuration config;
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
private final KeyBindingRegistry keyBindingRegistry = new KeyBindingRegistry();
|
private final KeyBindingRegistry keyBindingRegistry = new KeyBindingRegistry();
|
||||||
private final SettingsRegistry settingsRegistry = new SettingsRegistry();
|
private final SettingsRegistry settingsRegistry = new SettingsRegistry();
|
||||||
{
|
{
|
||||||
settingsRegistry.register(Setting.class);
|
settingsRegistry.register(Setting.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The instance of your mod that Forge uses.
|
|
||||||
//#if MC>=11400
|
|
||||||
{ instance = this; }
|
{ instance = this; }
|
||||||
//#else
|
|
||||||
//$$ @Instance(MOD_ID)
|
|
||||||
//#endif
|
|
||||||
public static ReplayMod instance;
|
public static ReplayMod instance;
|
||||||
|
|
||||||
private final List<Module> modules = new ArrayList<>();
|
private final List<Module> modules = new ArrayList<>();
|
||||||
@@ -181,15 +89,15 @@ public class ReplayMod implements
|
|||||||
*/
|
*/
|
||||||
private boolean minimalMode;
|
private boolean minimalMode;
|
||||||
|
|
||||||
public ReplayMod() {
|
public ReplayMod(ReplayModBackend backend) {
|
||||||
|
this.backend = backend;
|
||||||
|
|
||||||
I18n.setI18n(net.minecraft.client.resource.language.I18n::translate);
|
I18n.setI18n(net.minecraft.client.resource.language.I18n::translate);
|
||||||
|
|
||||||
//#if MC>=11400
|
|
||||||
// Check Minecraft protocol version for compatibility
|
// Check Minecraft protocol version for compatibility
|
||||||
if (!ProtocolVersion.isRegistered(MCVer.getProtocolVersion()) && !Boolean.parseBoolean(System.getProperty("replaymod.skipversioncheck", "false"))) {
|
if (!ProtocolVersion.isRegistered(MCVer.getProtocolVersion()) && !Boolean.parseBoolean(System.getProperty("replaymod.skipversioncheck", "false"))) {
|
||||||
minimalMode = true;
|
minimalMode = true;
|
||||||
}
|
}
|
||||||
//#endif
|
|
||||||
|
|
||||||
// Register all RM modules
|
// Register all RM modules
|
||||||
modules.add(this);
|
modules.add(this);
|
||||||
@@ -205,16 +113,6 @@ public class ReplayMod implements
|
|||||||
settingsRegistry.register();
|
settingsRegistry.register();
|
||||||
}
|
}
|
||||||
|
|
||||||
//#if MC<=11400
|
|
||||||
//$$ @EventHandler
|
|
||||||
//$$ public void init(FMLPreInitializationEvent event) {
|
|
||||||
//$$ config = new Configuration(event.getSuggestedConfigurationFile());
|
|
||||||
//$$ config.load();
|
|
||||||
//$$ settingsRegistry.backend.setConfiguration(config);
|
|
||||||
//$$ settingsRegistry.save(); // Save default values to disk
|
|
||||||
//$$ }
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
public KeyBindingRegistry getKeyBindingRegistry() {
|
public KeyBindingRegistry getKeyBindingRegistry() {
|
||||||
return keyBindingRegistry;
|
return keyBindingRegistry;
|
||||||
}
|
}
|
||||||
@@ -273,19 +171,14 @@ public class ReplayMod implements
|
|||||||
return replayFolder.resolve(relative);
|
return replayFolder.resolve(relative);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final DirectoryResourcePack jGuiResourcePack;
|
public static final DirectoryResourcePack jGuiResourcePack = createJGuiResourcePack();
|
||||||
public static final String JGUI_RESOURCE_PACK_NAME = "replaymod_jgui";
|
public static final String JGUI_RESOURCE_PACK_NAME = "replaymod_jgui";
|
||||||
static { // Note: even preInit is too late and we'd have to issue another resource reload
|
private static DirectoryResourcePack createJGuiResourcePack() {
|
||||||
jGuiResourcePack = initJGuiResourcePack();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DirectoryResourcePack initJGuiResourcePack() {
|
|
||||||
File folder = new File("../jGui/src/main/resources");
|
File folder = new File("../jGui/src/main/resources");
|
||||||
if (!folder.exists()) {
|
if (!folder.exists()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
//noinspection UnnecessaryLocalVariable
|
return new DirectoryResourcePack(folder) {
|
||||||
DirectoryResourcePack jGuiResourcePack = new DirectoryResourcePack(folder) {
|
|
||||||
@Override
|
@Override
|
||||||
//#if MC>=11400
|
//#if MC>=11400
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@@ -313,56 +206,13 @@ public class ReplayMod implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//#if MC<=11202
|
|
||||||
//$$ @SuppressWarnings("unchecked")
|
|
||||||
//$$ List<IResourcePack> defaultResourcePacks = ((MinecraftAccessor) mc).getDefaultResourcePacks();
|
|
||||||
//$$ defaultResourcePacks.add(jGuiResourcePack);
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
//#if MC<=10710
|
|
||||||
//$$ FolderResourcePack mainResourcePack = new FolderResourcePack(new File("../src/main/resources")) {
|
|
||||||
//$$ @Override
|
|
||||||
//$$ protected InputStream getInputStreamByName(String resourceName) throws IOException {
|
|
||||||
//$$ try {
|
|
||||||
//$$ return super.getInputStreamByName(resourceName);
|
|
||||||
//$$ } catch (IOException e) {
|
|
||||||
//$$ if ("pack.mcmeta".equals(resourceName)) {
|
|
||||||
//$$ return new ByteArrayInputStream(("{\"pack\": {\"description\": \"dummy pack for mod resources in dev-env\", \"pack_format\": 1}}").getBytes(StandardCharsets.UTF_8));
|
|
||||||
//$$ }
|
|
||||||
//$$ throw e;
|
|
||||||
//$$ }
|
|
||||||
//$$ }
|
|
||||||
//$$ };
|
|
||||||
//$$ defaultResourcePacks.add(mainResourcePack);
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
return jGuiResourcePack;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#if FABRIC>=1
|
void initModules() {
|
||||||
@Override
|
|
||||||
public void onInitializeClient() {
|
|
||||||
modules.forEach(Module::initCommon);
|
modules.forEach(Module::initCommon);
|
||||||
modules.forEach(Module::initClient);
|
modules.forEach(Module::initClient);
|
||||||
modules.forEach(m -> m.registerKeyBindings(keyBindingRegistry));
|
modules.forEach(m -> m.registerKeyBindings(keyBindingRegistry));
|
||||||
}
|
}
|
||||||
//#else
|
|
||||||
//#if MC>=11400
|
|
||||||
//$$ {
|
|
||||||
//$$ FMLJavaModLoadingContext.get().getModEventBus().addListener((FMLCommonSetupEvent event) -> modules.forEach(Module::initCommon));
|
|
||||||
//$$ FMLJavaModLoadingContext.get().getModEventBus().addListener((FMLClientSetupEvent event) -> modules.forEach(Module::initClient));
|
|
||||||
//$$ FMLJavaModLoadingContext.get().getModEventBus().addListener((FMLClientSetupEvent event) -> modules.forEach(m -> m.registerKeyBindings(keyBindingRegistry)));
|
|
||||||
//$$ }
|
|
||||||
//#else
|
|
||||||
//$$ @EventHandler
|
|
||||||
//$$ public void init(FMLInitializationEvent event) {
|
|
||||||
//$$ modules.forEach(Module::initCommon);
|
|
||||||
//$$ modules.forEach(Module::initClient);
|
|
||||||
//$$ modules.forEach(m -> m.registerKeyBindings(keyBindingRegistry));
|
|
||||||
//$$ }
|
|
||||||
//#endif
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerKeyBindings(KeyBindingRegistry registry) {
|
public void registerKeyBindings(KeyBindingRegistry registry) {
|
||||||
@@ -373,10 +223,6 @@ public class ReplayMod implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initClient() {
|
public void initClient() {
|
||||||
//#if MC<=10710
|
|
||||||
//$$ FML_BUS.register(this); // For runLater(Runnable)
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
backgroundProcesses.register();
|
backgroundProcesses.register();
|
||||||
keyBindingRegistry.register();
|
keyBindingRegistry.register();
|
||||||
|
|
||||||
@@ -391,8 +237,6 @@ public class ReplayMod implements
|
|||||||
}
|
}
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
testIfMoeshAndExitMinecraft();
|
|
||||||
|
|
||||||
runPostStartup(() -> {
|
runPostStartup(() -> {
|
||||||
final long DAYS = 24 * 60 * 60 * 1000;
|
final long DAYS = 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
@@ -491,231 +335,33 @@ public class ReplayMod implements
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Execute the given runnable on the main client thread, returning only after it has been run (or after 30 seconds).
|
|
||||||
*/
|
|
||||||
public void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException {
|
public void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
//#if MC>=11400
|
scheduler.runSync(runnable);
|
||||||
if (mc.isOnThread()) {
|
|
||||||
runnable.run();
|
|
||||||
} else {
|
|
||||||
executor.submit(() -> {
|
|
||||||
runnable.run();
|
|
||||||
return null;
|
|
||||||
}).get(30, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
//#else
|
|
||||||
//$$ if (mc.isCallingFromMinecraftThread()) {
|
|
||||||
//$$ runnable.run();
|
|
||||||
//$$ } else {
|
|
||||||
//$$ FutureTask<Void> future = new FutureTask<>(runnable, null);
|
|
||||||
//$$ runLater(future);
|
|
||||||
//$$ future.get(30, TimeUnit.SECONDS);
|
|
||||||
//$$ }
|
|
||||||
//#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Execute the given runnable after game has started (once the overlay has been closed).
|
|
||||||
* Most importantly, it will run after resources (including language keys!) have been loaded.
|
|
||||||
* Below 1.14, this is equivalent to {@link #runLater(Runnable)}.
|
|
||||||
*/
|
|
||||||
public void runPostStartup(Runnable runnable) {
|
public void runPostStartup(Runnable runnable) {
|
||||||
runLater(new Runnable() {
|
scheduler.runPostStartup(runnable);
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
//#if MC>=11400
|
|
||||||
if (getMinecraft().overlay != null) {
|
|
||||||
// delay until after resources have been loaded
|
|
||||||
runLater(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//#endif
|
|
||||||
runnable.run();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* 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;
|
|
||||||
//#if MC>=11400
|
|
||||||
private boolean inRenderTaskQueue = false;
|
|
||||||
// Starting 1.14 MC clears the queue of scheduled tasks on disconnect.
|
|
||||||
// This works fine for MC since it uses the queue only for packet handling but breaks our assumption that
|
|
||||||
// stuff submitted via runLater is actually always run (e.g. recording might not be fully stopped because parts
|
|
||||||
// of that are run via runLater and stopping the recording happens right around the time MC clears the queue).
|
|
||||||
// Luckily, that's also the version where MC pulled out the executor implementation, so we can just spin up our own.
|
|
||||||
public static class ReplayModExecutor extends ReentrantThreadExecutor<Runnable> {
|
|
||||||
private final Thread mcThread = Thread.currentThread();
|
|
||||||
// Fail-fast in case we ever switch to async loading and forget to change this
|
|
||||||
// (except for fabric 1.15+ because it loads the mod before the client thread is set)
|
|
||||||
//#if FABRIC<1 || MC<11500
|
|
||||||
//$$ { if (!MinecraftClient.getInstance().isOnThread()) throw new RuntimeException(); }
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
private ReplayModExecutor(String string_1) {
|
|
||||||
super(string_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Runnable createTask(Runnable runnable) {
|
|
||||||
return runnable;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean canExecute(Runnable runnable) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Thread getThread() {
|
|
||||||
return mcThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void runTasks() {
|
|
||||||
super.runTasks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public final ReplayModExecutor executor = new ReplayModExecutor("Client/ReplayMod");
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
// Pre-1.14 MC would hold the lock on the scheduledTasks queue while executing its tasks
|
|
||||||
// such that no new tasks could be submitted while one of them was running.
|
|
||||||
// This would cause issues with long-running tasks (e.g. video rendering) as it would
|
|
||||||
// block all async tasks (e.g. skin loading).
|
|
||||||
public void runLaterWithoutLock(Runnable runnable) {
|
public void runLaterWithoutLock(Runnable runnable) {
|
||||||
//#if MC>=11400
|
scheduler.runLaterWithoutLock(runnable);
|
||||||
// MC 1.14+ no longer synchronizes on the queue while running its tasks
|
|
||||||
runLater(runnable);
|
|
||||||
//#else
|
|
||||||
//$$ runLater(() -> runLaterWithoutLock(runnable), runnable);
|
|
||||||
//#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void runLater(Runnable runnable) {
|
public void runLater(Runnable runnable) {
|
||||||
runLater(runnable, () -> runLater(runnable));
|
scheduler.runLater(runnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runLater(Runnable runnable, Runnable defer) {
|
@Override
|
||||||
//#if MC>=11400
|
public void runTasks() {
|
||||||
if (mc.isOnThread() && inRunLater && !inRenderTaskQueue) {
|
scheduler.runTasks();
|
||||||
((MinecraftAccessor) mc).getRenderTaskQueue().offer(() -> {
|
|
||||||
inRenderTaskQueue = true;
|
|
||||||
try {
|
|
||||||
defer.run();
|
|
||||||
} finally {
|
|
||||||
inRenderTaskQueue = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
executor.send(() -> {
|
|
||||||
inRunLater = true;
|
|
||||||
try {
|
|
||||||
runnable.run();
|
|
||||||
} catch (CrashException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.err.println(e.getReport().asString());
|
|
||||||
mc.setCrashReport(e.getReport());
|
|
||||||
} finally {
|
|
||||||
inRunLater = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
//#else
|
|
||||||
//$$ if (mc.isCallingFromMinecraftThread() && inRunLater) {
|
|
||||||
//#if MC>=10800
|
|
||||||
//$$ FML_BUS.register(new Object() {
|
|
||||||
//$$ @SubscribeEvent
|
|
||||||
//$$ public void onRenderTick(TickEvent.RenderTickEvent event) {
|
|
||||||
//$$ if (event.phase == TickEvent.Phase.START) {
|
|
||||||
//$$ FML_BUS.unregister(this);
|
|
||||||
//$$ defer.run();
|
|
||||||
//$$ }
|
|
||||||
//$$ }
|
|
||||||
//$$ });
|
|
||||||
//#else
|
|
||||||
//$$ FML_BUS.register(new RunLaterHelper(defer));
|
|
||||||
//#endif
|
|
||||||
//$$ return;
|
|
||||||
//$$ }
|
|
||||||
//#if MC>=10800
|
|
||||||
//$$ Queue<FutureTask<?>> tasks = ((MinecraftAccessor) mc).getScheduledTasks();
|
|
||||||
//$$ //noinspection SynchronizationOnLocalVariableOrMethodParameter
|
|
||||||
//$$ synchronized (tasks) {
|
|
||||||
//#else
|
|
||||||
//$$ Queue<ListenableFutureTask<?>> tasks = scheduledTasks;
|
|
||||||
//$$ synchronized (scheduledTasks) {
|
|
||||||
//#endif
|
|
||||||
//$$ tasks.add(ListenableFutureTask.create(() -> {
|
|
||||||
//$$ inRunLater = true;
|
|
||||||
//$$ try {
|
|
||||||
//$$ runnable.run();
|
|
||||||
//$$ } catch (ReportedException e) {
|
|
||||||
//$$ e.printStackTrace();
|
|
||||||
//$$ System.err.println(e.getCrashReport().getCompleteReport());
|
|
||||||
//$$ mc.crashed(e.getCrashReport());
|
|
||||||
//$$ } finally {
|
|
||||||
//$$ inRunLater = false;
|
|
||||||
//$$ }
|
|
||||||
//$$ }, null));
|
|
||||||
//$$ }
|
|
||||||
//#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#if MC<=10710
|
|
||||||
//$$ // 1.7.10: Cannot use MC's because it is processed only during ticks (so not at all when replay is paused)
|
|
||||||
//$$ private final Queue<ListenableFutureTask<?>> scheduledTasks = new ArrayDeque<>();
|
|
||||||
//$$
|
|
||||||
//$$ // in 1.7.10 apparently events can't be delivered to anonymous classes
|
|
||||||
//$$ public class RunLaterHelper {
|
|
||||||
//$$ private final Runnable defer;
|
|
||||||
//$$
|
|
||||||
//$$ private RunLaterHelper(Runnable defer) {
|
|
||||||
//$$ this.defer = defer;
|
|
||||||
//$$ }
|
|
||||||
//$$
|
|
||||||
//$$ @SubscribeEvent
|
|
||||||
//$$ public void onRenderTick(TickEvent.RenderTickEvent event) {
|
|
||||||
//$$ if (event.phase == TickEvent.Phase.START) {
|
|
||||||
//$$ FML_BUS.unregister(this);
|
|
||||||
//$$ defer.run();
|
|
||||||
//$$ }
|
|
||||||
//$$ }
|
|
||||||
//$$ }
|
|
||||||
//$$
|
|
||||||
//$$ @SubscribeEvent
|
|
||||||
//$$ public void runScheduledTasks(InputReplayTimer.RunScheduledTasks event) {
|
|
||||||
//$$ synchronized (scheduledTasks) {
|
|
||||||
//$$ while (!scheduledTasks.isEmpty()) {
|
|
||||||
//$$ scheduledTasks.poll().run();
|
|
||||||
//$$ }
|
|
||||||
//$$ }
|
|
||||||
//$$ }
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
public String getVersion() {
|
public String getVersion() {
|
||||||
//#if FABRIC>=1
|
return backend.getVersion();
|
||||||
return FabricLoader.getInstance().getModContainer(MOD_ID)
|
|
||||||
.orElseThrow(IllegalStateException::new)
|
|
||||||
.getMetadata().getVersion().toString();
|
|
||||||
//#else
|
|
||||||
//#if MC>=11400
|
|
||||||
//$$ return ModList.get().getModContainerById(MOD_ID).get().getModInfo().getVersion().toString();
|
|
||||||
//#else
|
|
||||||
//$$ return Loader.instance().getIndexedModList().get(MOD_ID).getVersion();
|
|
||||||
//#endif
|
|
||||||
//#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private void testIfMoeshAndExitMinecraft() {
|
|
||||||
if("currentPlayer".equals("Moesh")) {
|
|
||||||
System.exit(-1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MinecraftClient getMinecraft() {
|
public MinecraftClient getMinecraft() {
|
||||||
|
|||||||
21
src/main/java/com/replaymod/core/ReplayModBackend.java
Normal file
21
src/main/java/com/replaymod/core/ReplayModBackend.java
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package com.replaymod.core;
|
||||||
|
|
||||||
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
|
||||||
|
import static com.replaymod.core.ReplayMod.MOD_ID;
|
||||||
|
|
||||||
|
public class ReplayModBackend implements ClientModInitializer {
|
||||||
|
private final ReplayMod mod = new ReplayMod(this);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitializeClient() {
|
||||||
|
mod.initModules();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return FabricLoader.getInstance().getModContainer(MOD_ID)
|
||||||
|
.orElseThrow(IllegalStateException::new)
|
||||||
|
.getMetadata().getVersion().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -176,6 +176,14 @@ public class MCVer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getMinecraftVersion() {
|
||||||
|
//#if MC>=11400
|
||||||
|
return getMinecraft().getGame().getVersion().getName();
|
||||||
|
//#else
|
||||||
|
//$$ return Loader.MC_VERSION;
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
|
||||||
public static void addDetail(CrashReportSection category, String name, Callable<String> callable) {
|
public static void addDetail(CrashReportSection category, String name, Callable<String> callable) {
|
||||||
//#if MC>=10904
|
//#if MC>=10904
|
||||||
//#if MC>=11200
|
//#if MC>=11200
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.replaymod.core.versions.scheduler;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
public interface Scheduler {
|
||||||
|
/**
|
||||||
|
* Execute the given runnable on the main client thread, returning only after it has been run (or after 30 seconds).
|
||||||
|
*/
|
||||||
|
void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the given runnable after game has started (once the overlay has been closed).
|
||||||
|
* Most importantly, it will run after resources (including language keys!) have been loaded.
|
||||||
|
* Below 1.14, this is equivalent to {@link #runLater(Runnable)}.
|
||||||
|
*/
|
||||||
|
void runPostStartup(Runnable runnable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pre-1.14 MC would hold the lock on the scheduledTasks queue while executing its tasks
|
||||||
|
* such that no new tasks could be submitted while one of them was running.
|
||||||
|
* This would cause issues with long-running tasks (e.g. video rendering) as it would
|
||||||
|
* block all async tasks (e.g. skin loading).
|
||||||
|
*/
|
||||||
|
void runLaterWithoutLock(Runnable runnable);
|
||||||
|
|
||||||
|
void runLater(Runnable runnable);
|
||||||
|
|
||||||
|
void runTasks();
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
package com.replaymod.core.versions.scheduler;
|
||||||
|
|
||||||
|
import com.replaymod.core.mixin.MinecraftAccessor;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.util.crash.CrashException;
|
||||||
|
import net.minecraft.util.thread.ReentrantThreadExecutor;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
public class SchedulerImpl implements Scheduler {
|
||||||
|
private static final MinecraftClient mc = MinecraftClient.getInstance();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
|
if (mc.isOnThread()) {
|
||||||
|
runnable.run();
|
||||||
|
} else {
|
||||||
|
executor.submit(() -> {
|
||||||
|
runnable.run();
|
||||||
|
return null;
|
||||||
|
}).get(30, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runPostStartup(Runnable runnable) {
|
||||||
|
runLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (mc.overlay != null) {
|
||||||
|
// delay until after resources have been loaded
|
||||||
|
runLater(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
private boolean inRenderTaskQueue = false;
|
||||||
|
// Starting 1.14 MC clears the queue of scheduled tasks on disconnect.
|
||||||
|
// This works fine for MC since it uses the queue only for packet handling but breaks our assumption that
|
||||||
|
// stuff submitted via runLater is actually always run (e.g. recording might not be fully stopped because parts
|
||||||
|
// of that are run via runLater and stopping the recording happens right around the time MC clears the queue).
|
||||||
|
// Luckily, that's also the version where MC pulled out the executor implementation, so we can just spin up our own.
|
||||||
|
public static class ReplayModExecutor extends ReentrantThreadExecutor<Runnable> {
|
||||||
|
private final Thread mcThread = Thread.currentThread();
|
||||||
|
|
||||||
|
private ReplayModExecutor(String string_1) {
|
||||||
|
super(string_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Runnable createTask(Runnable runnable) {
|
||||||
|
return runnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canExecute(Runnable runnable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Thread getThread() {
|
||||||
|
return mcThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runTasks() {
|
||||||
|
super.runTasks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public final ReplayModExecutor executor = new ReplayModExecutor("Client/ReplayMod");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runTasks() {
|
||||||
|
executor.runTasks();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runLaterWithoutLock(Runnable runnable) {
|
||||||
|
// MC 1.14+ no longer synchronizes on the queue while running its tasks
|
||||||
|
runLater(runnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runLater(Runnable runnable) {
|
||||||
|
runLater(runnable, () -> runLater(runnable));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runLater(Runnable runnable, Runnable defer) {
|
||||||
|
if (mc.isOnThread() && inRunLater && !inRenderTaskQueue) {
|
||||||
|
((MinecraftAccessor) mc).getRenderTaskQueue().offer(() -> {
|
||||||
|
inRenderTaskQueue = true;
|
||||||
|
try {
|
||||||
|
defer.run();
|
||||||
|
} finally {
|
||||||
|
inRenderTaskQueue = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
executor.send(() -> {
|
||||||
|
inRunLater = true;
|
||||||
|
try {
|
||||||
|
runnable.run();
|
||||||
|
} catch (CrashException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
System.err.println(e.getReport().asString());
|
||||||
|
mc.setCrashReport(e.getReport());
|
||||||
|
} finally {
|
||||||
|
inRunLater = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,7 +28,7 @@ import static com.replaymod.core.utils.Utils.SSL_SOCKET_FACTORY;
|
|||||||
import static com.replaymod.extras.ReplayModExtras.LOGGER;
|
import static com.replaymod.extras.ReplayModExtras.LOGGER;
|
||||||
|
|
||||||
public class OpenEyeExtra implements Extra {
|
public class OpenEyeExtra implements Extra {
|
||||||
private static final String DOWNLOAD_URL = "https://www.replaymod.com/dl/openeye/" + ReplayMod.getMinecraftVersion();
|
private static final String DOWNLOAD_URL = "https://www.replaymod.com/dl/openeye/" + MCVer.getMinecraftVersion();
|
||||||
|
|
||||||
private ReplayMod mod;
|
private ReplayMod mod;
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ public class OpenEyeExtra implements Extra {
|
|||||||
GuiPopup popup = new GuiPopup(OfferGui.this);
|
GuiPopup popup = new GuiPopup(OfferGui.this);
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
File targetFile = new File(mod.getMinecraft().runDirectory, "mods/" + ReplayMod.getMinecraftVersion() + "/OpenEye.jar");
|
File targetFile = new File(mod.getMinecraft().runDirectory, "mods/" + MCVer.getMinecraftVersion() + "/OpenEye.jar");
|
||||||
FileUtils.forceMkdir(targetFile.getParentFile());
|
FileUtils.forceMkdir(targetFile.getParentFile());
|
||||||
|
|
||||||
HttpsURLConnection connection = (HttpsURLConnection) new URL(DOWNLOAD_URL).openConnection();
|
HttpsURLConnection connection = (HttpsURLConnection) new URL(DOWNLOAD_URL).openConnection();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.replaymod.recording.handler;
|
|||||||
import com.replaymod.core.ReplayMod;
|
import com.replaymod.core.ReplayMod;
|
||||||
import com.replaymod.core.utils.ModCompat;
|
import com.replaymod.core.utils.ModCompat;
|
||||||
import com.replaymod.core.utils.Utils;
|
import com.replaymod.core.utils.Utils;
|
||||||
|
import com.replaymod.core.versions.MCVer;
|
||||||
import com.replaymod.editor.gui.MarkerProcessor;
|
import com.replaymod.editor.gui.MarkerProcessor;
|
||||||
import com.replaymod.recording.ServerInfoExt;
|
import com.replaymod.recording.ServerInfoExt;
|
||||||
import com.replaymod.recording.Setting;
|
import com.replaymod.recording.Setting;
|
||||||
@@ -137,7 +138,7 @@ public class ConnectionEventHandler {
|
|||||||
metaData.setCustomServerName(serverName);
|
metaData.setCustomServerName(serverName);
|
||||||
metaData.setGenerator("ReplayMod v" + ReplayMod.instance.getVersion());
|
metaData.setGenerator("ReplayMod v" + ReplayMod.instance.getVersion());
|
||||||
metaData.setDate(System.currentTimeMillis());
|
metaData.setDate(System.currentTimeMillis());
|
||||||
metaData.setMcVersion(ReplayMod.getMinecraftVersion());
|
metaData.setMcVersion(MCVer.getMinecraftVersion());
|
||||||
packetListener = new PacketListener(core, outputPath, replayFile, metaData);
|
packetListener = new PacketListener(core, outputPath, replayFile, metaData);
|
||||||
Channel channel = ((NetworkManagerAccessor) networkManager).getChannel();
|
Channel channel = ((NetworkManagerAccessor) networkManager).getChannel();
|
||||||
channel.pipeline().addBefore(packetHandlerKey, "replay_recorder", packetListener);
|
channel.pipeline().addBefore(packetHandlerKey, "replay_recorder", packetListener);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.replaymod.replay;
|
package com.replaymod.replay;
|
||||||
|
|
||||||
|
import com.replaymod.core.ReplayMod;
|
||||||
import com.replaymod.core.utils.WrappedTimer;
|
import com.replaymod.core.utils.WrappedTimer;
|
||||||
import com.replaymod.core.versions.MCVer;
|
import com.replaymod.core.versions.MCVer;
|
||||||
import com.replaymod.replay.camera.CameraController;
|
import com.replaymod.replay.camera.CameraController;
|
||||||
@@ -7,10 +8,6 @@ import com.replaymod.replay.camera.CameraEntity;
|
|||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.render.RenderTickCounter;
|
import net.minecraft.client.render.RenderTickCounter;
|
||||||
|
|
||||||
//#if MC>=11400
|
|
||||||
import com.replaymod.core.ReplayMod;
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
//#if MC>=11400
|
//#if MC>=11400
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
//#else
|
//#else
|
||||||
@@ -22,10 +19,7 @@ import org.lwjgl.glfw.GLFW;
|
|||||||
//$$ import java.io.IOException;
|
//$$ import java.io.IOException;
|
||||||
//#else
|
//#else
|
||||||
//$$ import com.replaymod.replay.gui.screen.GuiOpeningReplay;
|
//$$ import com.replaymod.replay.gui.screen.GuiOpeningReplay;
|
||||||
//$$ import cpw.mods.fml.common.eventhandler.Event;
|
|
||||||
//$$ import net.minecraft.client.renderer.entity.RenderManager;
|
//$$ import net.minecraft.client.renderer.entity.RenderManager;
|
||||||
//$$
|
|
||||||
//$$ import static com.replaymod.core.versions.MCVer.FML_BUS;
|
|
||||||
//#endif
|
//#endif
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
@@ -65,10 +59,9 @@ public class InputReplayTimer extends WrappedTimer {
|
|||||||
//#endif
|
//#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
// 1.7.10: We have to run the scheduled executables (ours only) because MC would only run them every tick
|
ReplayMod.instance.runTasks();
|
||||||
|
|
||||||
//#if MC<=10710
|
//#if MC<=10710
|
||||||
//$$ FML_BUS.post(new RunScheduledTasks());
|
|
||||||
//$$
|
|
||||||
//$$ // Code below only updates the current screen when a world and player is loaded. This may not be the case for
|
//$$ // Code below only updates the current screen when a world and player is loaded. This may not be the case for
|
||||||
//$$ // the GuiOpeningReplay screen resulting in a livelock.
|
//$$ // the GuiOpeningReplay screen resulting in a livelock.
|
||||||
//$$ // To counteract that, we always update that screen (doesn't matter if we do it twice).
|
//$$ // To counteract that, we always update that screen (doesn't matter if we do it twice).
|
||||||
@@ -77,10 +70,6 @@ public class InputReplayTimer extends WrappedTimer {
|
|||||||
//$$ }
|
//$$ }
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
//#if MC>=11400
|
|
||||||
ReplayMod.instance.executor.runTasks();
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
// If we are in a replay, we have to manually process key and mouse events as the
|
// If we are in a replay, we have to manually process key and mouse events as the
|
||||||
// tick speed may vary or there may not be any ticks at all (when the replay is paused)
|
// tick speed may vary or there may not be any ticks at all (when the replay is paused)
|
||||||
if (mod.getReplayHandler() != null && mc.world != null && mc.player != null) {
|
if (mod.getReplayHandler() != null && mc.world != null && mc.player != null) {
|
||||||
@@ -147,8 +136,4 @@ public class InputReplayTimer extends WrappedTimer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//#if MC<=10710
|
|
||||||
//$$ public static class RunScheduledTasks extends Event {}
|
|
||||||
//#endif
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
"environment": "client",
|
"environment": "client",
|
||||||
"entrypoints": {
|
"entrypoints": {
|
||||||
"client": [
|
"client": [
|
||||||
"com.replaymod.core.ReplayMod"
|
"com.replaymod.core.ReplayModBackend"
|
||||||
],
|
],
|
||||||
"modmenu": [
|
"modmenu": [
|
||||||
"com.replaymod.core.gui.ModMenuApiImpl"
|
"com.replaymod.core.gui.ModMenuApiImpl"
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package com.replaymod.core;
|
||||||
|
|
||||||
|
import com.replaymod.core.mixin.MinecraftAccessor;
|
||||||
|
import net.minecraft.client.resources.IResourcePack;
|
||||||
|
import net.minecraftforge.common.config.Configuration;
|
||||||
|
import net.minecraftforge.fml.common.Loader;
|
||||||
|
import net.minecraftforge.fml.common.Mod;
|
||||||
|
import net.minecraftforge.fml.common.Mod.EventHandler;
|
||||||
|
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
|
||||||
|
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.replaymod.core.ReplayMod.MOD_ID;
|
||||||
|
import static com.replaymod.core.ReplayMod.jGuiResourcePack;
|
||||||
|
import static com.replaymod.core.versions.MCVer.getMinecraft;
|
||||||
|
|
||||||
|
//#if MC<=10710
|
||||||
|
//$$ import net.minecraft.client.resources.FolderResourcePack;
|
||||||
|
//$$ import java.io.ByteArrayInputStream;
|
||||||
|
//$$ import java.io.File;
|
||||||
|
//$$ import java.io.IOException;
|
||||||
|
//$$ import java.io.InputStream;
|
||||||
|
//$$ import java.nio.charset.StandardCharsets;
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
@Mod(modid = ReplayMod.MOD_ID,
|
||||||
|
useMetadata = true,
|
||||||
|
version = "@MOD_VERSION@",
|
||||||
|
acceptedMinecraftVersions = "@MC_VERSION@",
|
||||||
|
acceptableRemoteVersions = "*",
|
||||||
|
//#if MC>=10800
|
||||||
|
clientSideOnly = true,
|
||||||
|
updateJSON = "https://raw.githubusercontent.com/ReplayMod/ReplayMod/master/versions.json",
|
||||||
|
//#endif
|
||||||
|
guiFactory = "com.replaymod.core.gui.GuiFactory")
|
||||||
|
public class ReplayModBackend {
|
||||||
|
private final ReplayMod mod = new ReplayMod(this);
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public static Configuration config;
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void init(FMLPreInitializationEvent event) {
|
||||||
|
config = new Configuration(event.getSuggestedConfigurationFile());
|
||||||
|
config.load();
|
||||||
|
SettingsRegistry settingsRegistry = mod.getSettingsRegistry();
|
||||||
|
settingsRegistry.backend.setConfiguration(config);
|
||||||
|
settingsRegistry.save(); // Save default values to disk
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void init(FMLInitializationEvent event) {
|
||||||
|
mod.initModules();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return Loader.instance().getIndexedModList().get(MOD_ID).getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
static { // Note: even preInit is too late and we'd have to issue another resource reload
|
||||||
|
List<IResourcePack> defaultResourcePacks = ((MinecraftAccessor) getMinecraft()).getDefaultResourcePacks();
|
||||||
|
|
||||||
|
if (jGuiResourcePack != null) {
|
||||||
|
defaultResourcePacks.add(jGuiResourcePack);
|
||||||
|
}
|
||||||
|
|
||||||
|
//#if MC<=10710
|
||||||
|
//$$ FolderResourcePack mainResourcePack = new FolderResourcePack(new File("../src/main/resources")) {
|
||||||
|
//$$ @Override
|
||||||
|
//$$ protected InputStream getInputStreamByName(String resourceName) throws IOException {
|
||||||
|
//$$ try {
|
||||||
|
//$$ return super.getInputStreamByName(resourceName);
|
||||||
|
//$$ } catch (IOException e) {
|
||||||
|
//$$ if ("pack.mcmeta".equals(resourceName)) {
|
||||||
|
//$$ return new ByteArrayInputStream(("{\"pack\": {\"description\": \"dummy pack for mod resources in dev-env\", \"pack_format\": 1}}").getBytes(StandardCharsets.UTF_8));
|
||||||
|
//$$ }
|
||||||
|
//$$ throw e;
|
||||||
|
//$$ }
|
||||||
|
//$$ }
|
||||||
|
//$$ };
|
||||||
|
//$$ defaultResourcePacks.add(mainResourcePack);
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
package com.replaymod.core.versions.scheduler;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ListenableFutureTask;
|
||||||
|
import com.replaymod.core.mixin.MinecraftAccessor;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.util.ReportedException;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||||
|
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.FutureTask;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
//#if MC<10800
|
||||||
|
//$$ import java.util.ArrayDeque;
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
import static com.replaymod.core.versions.MCVer.FML_BUS;
|
||||||
|
|
||||||
|
public class SchedulerImpl implements Scheduler {
|
||||||
|
private static final Minecraft mc = Minecraft.getMinecraft();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
|
if (mc.isCallingFromMinecraftThread()) {
|
||||||
|
runnable.run();
|
||||||
|
} else {
|
||||||
|
FutureTask<Void> future = new FutureTask<>(runnable, null);
|
||||||
|
runLater(future);
|
||||||
|
future.get(30, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runPostStartup(Runnable runnable) {
|
||||||
|
runLater(runnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runLaterWithoutLock(Runnable runnable) {
|
||||||
|
runLater(() -> runLaterWithoutLock(runnable), runnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runLater(Runnable runnable) {
|
||||||
|
runLater(runnable, () -> runLater(runnable));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runLater(Runnable runnable, Runnable defer) {
|
||||||
|
if (mc.isCallingFromMinecraftThread() && inRunLater) {
|
||||||
|
//#if MC>=10800
|
||||||
|
FML_BUS.register(new Object() {
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onRenderTick(TickEvent.RenderTickEvent event) {
|
||||||
|
if (event.phase == TickEvent.Phase.START) {
|
||||||
|
FML_BUS.unregister(this);
|
||||||
|
defer.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//#else
|
||||||
|
//$$ FML_BUS.register(new RunLaterHelper(defer));
|
||||||
|
//#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//#if MC>=10800
|
||||||
|
Queue<FutureTask<?>> tasks = ((MinecraftAccessor) mc).getScheduledTasks();
|
||||||
|
//noinspection SynchronizationOnLocalVariableOrMethodParameter
|
||||||
|
synchronized (tasks) {
|
||||||
|
//#else
|
||||||
|
//$$ Queue<ListenableFutureTask<?>> tasks = scheduledTasks;
|
||||||
|
//$$ synchronized (scheduledTasks) {
|
||||||
|
//#endif
|
||||||
|
tasks.add(ListenableFutureTask.create(() -> {
|
||||||
|
inRunLater = true;
|
||||||
|
try {
|
||||||
|
runnable.run();
|
||||||
|
} catch (ReportedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
System.err.println(e.getCrashReport().getCompleteReport());
|
||||||
|
mc.crashed(e.getCrashReport());
|
||||||
|
} finally {
|
||||||
|
inRunLater = false;
|
||||||
|
}
|
||||||
|
}, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#if MC>=10800
|
||||||
|
@Override
|
||||||
|
public void runTasks() {
|
||||||
|
}
|
||||||
|
//#else
|
||||||
|
//$$ // 1.7.10: Cannot use MC's because it is processed only during ticks (so not at all when replay is paused)
|
||||||
|
//$$ private final Queue<ListenableFutureTask<?>> scheduledTasks = new ArrayDeque<>();
|
||||||
|
//$$
|
||||||
|
//$$ // in 1.7.10 apparently events can't be delivered to anonymous classes
|
||||||
|
//$$ public class RunLaterHelper {
|
||||||
|
//$$ private final Runnable defer;
|
||||||
|
//$$
|
||||||
|
//$$ private RunLaterHelper(Runnable defer) {
|
||||||
|
//$$ this.defer = defer;
|
||||||
|
//$$ }
|
||||||
|
//$$
|
||||||
|
//$$ @SubscribeEvent
|
||||||
|
//$$ public void onRenderTick(TickEvent.RenderTickEvent event) {
|
||||||
|
//$$ if (event.phase == TickEvent.Phase.START) {
|
||||||
|
//$$ FML_BUS.unregister(this);
|
||||||
|
//$$ defer.run();
|
||||||
|
//$$ }
|
||||||
|
//$$ }
|
||||||
|
//$$ }
|
||||||
|
//$$
|
||||||
|
//$$ @Override
|
||||||
|
//$$ public void runTasks() {
|
||||||
|
//$$ synchronized (scheduledTasks) {
|
||||||
|
//$$ while (!scheduledTasks.isEmpty()) {
|
||||||
|
//$$ scheduledTasks.poll().run();
|
||||||
|
//$$ }
|
||||||
|
//$$ }
|
||||||
|
//$$ }
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.replaymod.core;
|
||||||
|
|
||||||
|
import net.minecraftforge.fml.ModList;
|
||||||
|
|
||||||
|
import static com.replaymod.core.ReplayMod.MOD_ID;
|
||||||
|
|
||||||
|
public class ReplayModBackend {
|
||||||
|
public String getVersion() {
|
||||||
|
return ModList.get().getModContainerById(MOD_ID).get().getModInfo().getVersion().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user