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.GuiReplaySettings;
|
||||
import com.replaymod.core.gui.RestoreReplayGui;
|
||||
import com.replaymod.core.mixin.MinecraftAccessor;
|
||||
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.extras.ReplayModExtras;
|
||||
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.us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
import com.replaymod.replaystudio.util.I18n;
|
||||
import com.replaymod.replaystudio.viaversion.ViaVersionPacketConverter;
|
||||
import com.replaymod.simplepathing.ReplayModSimplePathing;
|
||||
import de.johni0702.minecraft.gui.container.GuiScreen;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
@@ -28,63 +28,13 @@ import net.minecraft.text.Style;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.crash.CrashException;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
//#if MC>=11400
|
||||
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
|
||||
//$$ import com.google.common.util.concurrent.ListenableFutureTask;
|
||||
//$$ 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
|
||||
//$$ import net.minecraft.client.settings.GameSettings;
|
||||
//#endif
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -102,43 +52,9 @@ import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
//#if FABRIC<=0
|
||||
//#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 class ReplayMod implements Module, Scheduler {
|
||||
|
||||
public static final String MOD_ID = "replaymod";
|
||||
|
||||
@@ -148,23 +64,15 @@ public class ReplayMod implements
|
||||
|
||||
private static final MinecraftClient mc = MCVer.getMinecraft();
|
||||
|
||||
//#if MC<11400
|
||||
//$$ @Deprecated
|
||||
//$$ public static Configuration config;
|
||||
//#endif
|
||||
|
||||
private final ReplayModBackend backend;
|
||||
private final SchedulerImpl scheduler = new SchedulerImpl();
|
||||
private final KeyBindingRegistry keyBindingRegistry = new KeyBindingRegistry();
|
||||
private final SettingsRegistry settingsRegistry = new SettingsRegistry();
|
||||
{
|
||||
settingsRegistry.register(Setting.class);
|
||||
}
|
||||
|
||||
// The instance of your mod that Forge uses.
|
||||
//#if MC>=11400
|
||||
{ instance = this; }
|
||||
//#else
|
||||
//$$ @Instance(MOD_ID)
|
||||
//#endif
|
||||
public static ReplayMod instance;
|
||||
|
||||
private final List<Module> modules = new ArrayList<>();
|
||||
@@ -181,15 +89,15 @@ public class ReplayMod implements
|
||||
*/
|
||||
private boolean minimalMode;
|
||||
|
||||
public ReplayMod() {
|
||||
public ReplayMod(ReplayModBackend backend) {
|
||||
this.backend = backend;
|
||||
|
||||
I18n.setI18n(net.minecraft.client.resource.language.I18n::translate);
|
||||
|
||||
//#if MC>=11400
|
||||
// Check Minecraft protocol version for compatibility
|
||||
if (!ProtocolVersion.isRegistered(MCVer.getProtocolVersion()) && !Boolean.parseBoolean(System.getProperty("replaymod.skipversioncheck", "false"))) {
|
||||
minimalMode = true;
|
||||
}
|
||||
//#endif
|
||||
|
||||
// Register all RM modules
|
||||
modules.add(this);
|
||||
@@ -205,16 +113,6 @@ public class ReplayMod implements
|
||||
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() {
|
||||
return keyBindingRegistry;
|
||||
}
|
||||
@@ -273,19 +171,14 @@ public class ReplayMod implements
|
||||
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";
|
||||
static { // Note: even preInit is too late and we'd have to issue another resource reload
|
||||
jGuiResourcePack = initJGuiResourcePack();
|
||||
}
|
||||
|
||||
private static DirectoryResourcePack initJGuiResourcePack() {
|
||||
private static DirectoryResourcePack createJGuiResourcePack() {
|
||||
File folder = new File("../jGui/src/main/resources");
|
||||
if (!folder.exists()) {
|
||||
return null;
|
||||
}
|
||||
//noinspection UnnecessaryLocalVariable
|
||||
DirectoryResourcePack jGuiResourcePack = new DirectoryResourcePack(folder) {
|
||||
return new DirectoryResourcePack(folder) {
|
||||
@Override
|
||||
//#if MC>=11400
|
||||
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
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
void initModules() {
|
||||
modules.forEach(Module::initCommon);
|
||||
modules.forEach(Module::initClient);
|
||||
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
|
||||
public void registerKeyBindings(KeyBindingRegistry registry) {
|
||||
@@ -373,10 +223,6 @@ public class ReplayMod implements
|
||||
|
||||
@Override
|
||||
public void initClient() {
|
||||
//#if MC<=10710
|
||||
//$$ FML_BUS.register(this); // For runLater(Runnable)
|
||||
//#endif
|
||||
|
||||
backgroundProcesses.register();
|
||||
keyBindingRegistry.register();
|
||||
|
||||
@@ -391,8 +237,6 @@ public class ReplayMod implements
|
||||
}
|
||||
//#endif
|
||||
|
||||
testIfMoeshAndExitMinecraft();
|
||||
|
||||
runPostStartup(() -> {
|
||||
final long DAYS = 24 * 60 * 60 * 1000;
|
||||
|
||||
@@ -491,231 +335,33 @@ public class ReplayMod implements
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given runnable on the main client thread, returning only after it has been run (or after 30 seconds).
|
||||
*/
|
||||
@Override
|
||||
public void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
//#if MC>=11400
|
||||
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
|
||||
scheduler.runSync(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)}.
|
||||
*/
|
||||
@Override
|
||||
public void runPostStartup(Runnable runnable) {
|
||||
runLater(new 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();
|
||||
}
|
||||
});
|
||||
scheduler.runPostStartup(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;
|
||||
//#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).
|
||||
@Override
|
||||
public void runLaterWithoutLock(Runnable runnable) {
|
||||
//#if MC>=11400
|
||||
// MC 1.14+ no longer synchronizes on the queue while running its tasks
|
||||
runLater(runnable);
|
||||
//#else
|
||||
//$$ runLater(() -> runLaterWithoutLock(runnable), runnable);
|
||||
//#endif
|
||||
scheduler.runLaterWithoutLock(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runLater(Runnable runnable) {
|
||||
runLater(runnable, () -> runLater(runnable));
|
||||
scheduler.runLater(runnable);
|
||||
}
|
||||
|
||||
private void runLater(Runnable runnable, Runnable defer) {
|
||||
//#if MC>=11400
|
||||
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;
|
||||
}
|
||||
});
|
||||
}
|
||||
//#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
|
||||
@Override
|
||||
public void runTasks() {
|
||||
scheduler.runTasks();
|
||||
}
|
||||
|
||||
//#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() {
|
||||
//#if FABRIC>=1
|
||||
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);
|
||||
}
|
||||
return backend.getVersion();
|
||||
}
|
||||
|
||||
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) {
|
||||
//#if MC>=10904
|
||||
//#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;
|
||||
|
||||
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;
|
||||
|
||||
@@ -86,7 +86,7 @@ public class OpenEyeExtra implements Extra {
|
||||
GuiPopup popup = new GuiPopup(OfferGui.this);
|
||||
new Thread(() -> {
|
||||
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());
|
||||
|
||||
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.utils.ModCompat;
|
||||
import com.replaymod.core.utils.Utils;
|
||||
import com.replaymod.core.versions.MCVer;
|
||||
import com.replaymod.editor.gui.MarkerProcessor;
|
||||
import com.replaymod.recording.ServerInfoExt;
|
||||
import com.replaymod.recording.Setting;
|
||||
@@ -137,7 +138,7 @@ public class ConnectionEventHandler {
|
||||
metaData.setCustomServerName(serverName);
|
||||
metaData.setGenerator("ReplayMod v" + ReplayMod.instance.getVersion());
|
||||
metaData.setDate(System.currentTimeMillis());
|
||||
metaData.setMcVersion(ReplayMod.getMinecraftVersion());
|
||||
metaData.setMcVersion(MCVer.getMinecraftVersion());
|
||||
packetListener = new PacketListener(core, outputPath, replayFile, metaData);
|
||||
Channel channel = ((NetworkManagerAccessor) networkManager).getChannel();
|
||||
channel.pipeline().addBefore(packetHandlerKey, "replay_recorder", packetListener);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.replaymod.replay;
|
||||
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.core.utils.WrappedTimer;
|
||||
import com.replaymod.core.versions.MCVer;
|
||||
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.render.RenderTickCounter;
|
||||
|
||||
//#if MC>=11400
|
||||
import com.replaymod.core.ReplayMod;
|
||||
//#endif
|
||||
|
||||
//#if MC>=11400
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
//#else
|
||||
@@ -22,10 +19,7 @@ import org.lwjgl.glfw.GLFW;
|
||||
//$$ import java.io.IOException;
|
||||
//#else
|
||||
//$$ import com.replaymod.replay.gui.screen.GuiOpeningReplay;
|
||||
//$$ import cpw.mods.fml.common.eventhandler.Event;
|
||||
//$$ import net.minecraft.client.renderer.entity.RenderManager;
|
||||
//$$
|
||||
//$$ import static com.replaymod.core.versions.MCVer.FML_BUS;
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
@@ -65,10 +59,9 @@ public class InputReplayTimer extends WrappedTimer {
|
||||
//#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
|
||||
//$$ 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
|
||||
//$$ // the GuiOpeningReplay screen resulting in a livelock.
|
||||
//$$ // 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
|
||||
|
||||
//#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
|
||||
// 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) {
|
||||
@@ -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",
|
||||
"entrypoints": {
|
||||
"client": [
|
||||
"com.replaymod.core.ReplayMod"
|
||||
"com.replaymod.core.ReplayModBackend"
|
||||
],
|
||||
"modmenu": [
|
||||
"com.replaymod.core.gui.ModMenuApiImpl"
|
||||
|
||||
Reference in New Issue
Block a user