Merge branch 'stable' into develop

This commit is contained in:
Jonas Herzig
2020-11-22 17:10:27 +01:00
20 changed files with 192 additions and 40 deletions

View File

@@ -3,7 +3,7 @@ import java.io.ByteArrayOutputStream
plugins { plugins {
id("fabric-loom") version "0.4-SNAPSHOT" apply false id("fabric-loom") version "0.4-SNAPSHOT" apply false
id("com.replaymod.preprocess") version "3c46acb" id("com.replaymod.preprocess") version "24ac087"
id("com.github.hierynomus.license") version "0.15.0" id("com.github.hierynomus.license") version "0.15.0"
} }
@@ -115,10 +115,7 @@ fun generateVersionsJson(): Map<String, Any> {
versions.forEach { versions.forEach {
val (thisMcVersion, modVersion, preVersion) = it.split("-") + listOf(null, null) val (thisMcVersion, modVersion, preVersion) = it.split("-") + listOf(null, null)
if (thisMcVersion == mcVersion) { if (thisMcVersion == mcVersion) {
mcVersionRoot[it] = if (tagVersions.contains(it)) mcVersionRoot[it] = "See https://www.replaymod.com/changelog.txt"
"See https://github.com/ReplayMod/ReplayMod/releases/$it"
else
"See https://www.replaymod.com/forum/thread/100"
if (latest == null) latest = it if (latest == null) latest = it
if (preVersion == null) { if (preVersion == null) {
if (recommended == null) recommended = it if (recommended == null) recommended = it
@@ -147,13 +144,19 @@ val doRelease by tasks.registering {
listOf(version, null) listOf(version, null)
} }
// Create new commit // Merge release branch into stable but do not yet commit (we need to update the version.txt first)
command("git", "checkout", "stable")
command("git", "merge", "--no-ff", "--no-commit", "release-$version")
// Update version.txt
file("version.txt").writeText("$version\n")
command("git", "add", "version.txt")
// Finallize the merge. The message is what is later used to identify releses for building the version.json tree
val commitMessage = if (preVersion != null) val commitMessage = if (preVersion != null)
"Pre-release $preVersion of $modVersion" "Pre-release $preVersion of $modVersion"
else else
"Release $modVersion" "Release $modVersion"
file("version.txt").writeText("$version\n")
command("git", "add", "version.txt")
command("git", "commit", "-m", commitMessage) command("git", "commit", "-m", commitMessage)
// Generate versions.json content // Generate versions.json content

View File

@@ -20,7 +20,7 @@ After installing Forge, simply put the downloaded `ReplayMod.jar` file in the `/
To render your creations with **Replay Mod** you will need to have FFmpeg installed. To render your creations with **Replay Mod** you will need to have FFmpeg installed.
### Windows [windows] ### Windows [windows]
Download the **latest** FFmpeg build from <https://www.gyan.dev/ffmpeg/builds/> (the essentials version is sufficient). Download the latest FFmpeg release from https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip.
Extract the downloaded .zip file into your `.minecraft` folder. Extract the downloaded .zip file into your `.minecraft` folder.
@@ -46,7 +46,7 @@ If in doubt, consult the documentation of your distribution.
## Settings [settings] ## Settings [settings]
To access the **Replay Mod Settings** from the Main Menu click the **"Replay Viewer"** button and click the **Settings** button. To access the **Replay Mod Settings** from the Main Menu click the **"Replay Viewer"** button and click the **Settings** button.
While playing, you can click the 'Mods' button in the Pause screen to reach **Replay Mod Settings** if you use Minecraft 1.12.2 and below, or have the mod [Mod Menu](https://www.curseforge.com/minecraft/mc-mods/modmenu) installed. While playing, you can click the 'Mods' button in the Pause screen to reach **Replay Mod Settings** if you use Minecraft 1.12.2 and below, or have the mod _Mod Menu_ installed.
When in a Replay, you can either bind a hotkey to the **Replay Mod Settings** in Minecraft's Control settings When in a Replay, you can either bind a hotkey to the **Replay Mod Settings** in Minecraft's Control settings
or use the hotkey GUI by clicking on the hamburger button in the lower left corner. or use the hotkey GUI by clicking on the hamburger button in the lower left corner.
@@ -472,6 +472,8 @@ When you first enable **Quick Mode** in a replay, an internal reference of certa
As a side effect, certain features like particles and second skin layers will not be rendered in the preview. As a side effect, certain features like particles and second skin layers will not be rendered in the preview.
By default, **Quick Mode** is toggled with `Q`. By default, **Quick Mode** is toggled with `Q`.
**Quick Mode** is available in ReplayMod for Minecraft 1.9.4 and up.
## Player Overview [overview] ## Player Overview [overview]
![](img/player-overview.jpg) ![](img/player-overview.jpg)
The **Player Overview** Screen The **Player Overview** Screen
@@ -561,11 +563,6 @@ On Windows, this path might look like `C:\ffmpeg\ffmpeg.exe`.
Then, open the **"Command Line Settings" Section** in the Render Settings and paste this path into the **left input field** and retry rendering. Then, open the **"Command Line Settings" Section** in the Render Settings and paste this path into the **left input field** and retry rendering.
## Rendering Failed [libx264]
An error screen is displayed with FFmpeg error: `Unknown encoder 'libx264'`
The FFmpeg version you have installed is compiled without `--enable-_libx264_`. The 4.3 version on [https://ffmpeg.zeranoe.com/](https://ffmpeg.zeranoe.com/) has this issue. To fix it, install another version (e.g. the latest snapshot).
## Crash while rendering [crash] ## Crash while rendering [crash]
If Minecraft crashes after a few frames of rendering, it most likely means the **FFmpeg** didn't like the **Command Line Arguments** you passed. If Minecraft crashes after a few frames of rendering, it most likely means the **FFmpeg** didn't like the **Command Line Arguments** you passed.
If you customized the Command Line Arguments manually, re-check them - it's probably your own fault. If you customized the Command Line Arguments manually, re-check them - it's probably your own fault.
@@ -576,20 +573,20 @@ If you customized the Command Line Arguments manually, re-check them - it's prob
- Make sure the camera doesn't move below Y=0 or above Y=255 - Make sure the camera doesn't move below Y=0 or above Y=255
## Unsupported Launchers [launchers] ## Unsupported Launchers [launchers]
[Lunar Client](https://www.lunarclient.com/) does not support ReplayMod _Future Client_ is not compatible with the Mixin required by ReplayMod.
[Badlion Client](https://www.badlion.net/) offers a different ReplayMod that is not the same as this one. _Lunar Client_ does not support ReplayMod.
_Badlion Client_ offers a different ReplayMod that is not the same as this one.
## Compatibility with other Mods [compatibility] ## Compatibility with other Mods [compatibility]
### General information [general] ### General information [general]
In General, the Replay Mod _should_ be compatible with most Forge and Fabric Mods. In General, the Replay Mod _should_ be compatible with most Forge and Fabric Mods.
### Shaders Mod [shaders] ### Shaders Mod [shaders]
[Karyonix' Shaders Mod](http://www.minecraftforum.net/forums/mapping-and-modding/minecraft-mods/1286604-shaders-mod-updated-by-karyonix) _Karyonix' Shaders Mod_ is no longer compatible with Minecraft Forge starting with 1.9.4. As such it is not compatible with the Replay Mod either.
is no longer compatible with Minecraft Forge starting with 1.9.4. As such it is not compatible with the Replay Mod either. Please use _Optifine_ instead.
Please use [Optifine](https://optifine.net/) instead.
### Custom Main Menu [custom-main-menu] ### Custom Main Menu [custom-main-menu]
The [Custom Main Menu](https://www.curseforge.com/minecraft/mc-mods/custom-main-menu) mod is often used in mod packs to customize their Main Menu with a button layout fitting the background image, links to their website / bug tracker and similar. The _Custom Main Menu_ mod is often used in mod packs to customize their Main Menu with a button layout fitting the background image, links to their website / bug tracker and similar.
If you are familiar with it, the button id for the Replay Mod is: **17890234** (text: `replaymod.gui.replayviewer`). If you are familiar with it, the button id for the Replay Mod is: **17890234** (text: `replaymod.gui.replayviewer`).
Due to the nature of this Custom Main Menu mod, buttons added to the Main Menu by 3rd party mods like the **Replay Mod** will not show up by default. Due to the nature of this Custom Main Menu mod, buttons added to the Main Menu by 3rd party mods like the **Replay Mod** will not show up by default.
@@ -601,22 +598,58 @@ For an explanation of this config file, have a look at Custom Main Menu's page.
You can find a list of already modified config files [here](https://gist.github.com/Johni0702/3f3fab81dbf7ada83d045d9fe8f345aa). You can find a list of already modified config files [here](https://gist.github.com/Johni0702/3f3fab81dbf7ada83d045d9fe8f345aa).
### Tickrate Changer [tickrate-changer] ### Tickrate Changer [tickrate-changer]
The [Tickrate Changer](https://www.curseforge.com/minecraft/mc-mods/tickratechanger) mod may cause minecraft to freeze when you try to use the Replay Viewer UI. The _Tickrate Changer_ mod may cause minecraft to freeze when you try to use the Replay Viewer UI.
### LabyMod [labymod] ### LabyMod [labymod]
The [LabyMod](https://www.curseforge.com/minecraft/mc-mods/labymod) is not compatible with ReplayMod. _LabyMod_ v3.7.x has been reported to be compatible with ReplayMod and other Forge mods.
Lower versions are not compatible.
### OldAnimationsMod [oldanimationsmod] ### OldAnimationsMod [oldanimationsmod]
In case your Minecraft crashes when you are using both ReplayMod and [OldAnimationsMod](https://oldanimationsmod.net/), try removing OldAnimationsMod. In case your Minecraft crashes when you are using both ReplayMod and _OldAnimationsMod_, try removing OldAnimationsMod.
### Orange's 1.7 Animations [17animations]
If you use ReplayMod with shaders and _1.7 Animations_ you may see floating water and glass. Remove 1.7 Animations to resolve this.
### Sk1er Club: Patcher [patcher] ### Sk1er Club: Patcher [patcher]
We have seen reports of crashes that were related to [Patcher](https://sk1er.club/mods/patcher); in case of crashes try removing Patcher. We have seen reports of crashes that were related to _Patcher_; in case of crashes try removing Patcher.
### Baritone [baritone] ### Baritone [baritone]
The [Baritone](https://github.com/cabaletta/baritone/) mod can cause a crash when you're trying to load a replay. If you experience such problems, try running without Baritone. The _Baritone_ mod can cause a crash when you're trying to load a replay. If you experience such problems, try running without Baritone.
### RandomPatches [randompatches] ### RandomPatches [randompatches]
Minecraft may crash if you try to use [RandomPatches](https://www.curseforge.com/minecraft/mc-mods/randompatches) together with ReplayMod. Try removing RandomPatches if Minecraft crashes on startup. Minecraft may crash if you try to use _RandomPatches_ together with ReplayMod. Try removing RandomPatches if Minecraft crashes on startup.
### Sodium [sodium] ### Sodium [sodium]
ReplayMod can record when [Sodium](https://www.curseforge.com/minecraft/mc-mods/sodium) is installed but will crash during render. Disable Sodium before rendering, it can be re-enabled after that. ReplayMod can record when _Sodium_ is installed but will crash during render. Disable Sodium before rendering, it can be re-enabled after that.
### Resource Loader [resourceloader]
The _Resource Loader_ mod is not compatible with ReplayMod.
### LiteLoader [liteloader]
![](img/mutlimc-liteloader.jpg)
The MultiMC interface to place ReplayMod above LiteLoader.
![](img/multimc-addempty.jpg)
The properties for the new *Empty*.
_LiteLoader_ is known to cause issues due to the mixin version it contains.
You can use MultiMC to workaround this problem.
> The MultiMC `Edit` function requires that your computer has a default editor for json files associated.
1: Create your instance then edit the instance
2: Click `Install Forge`
3: Click `Install LiteLoader`
4: Click `Add Empty`; use `ReplayMod` as name and `com.replaymod` as uid
5: Select the new *ReplayMod* and click `Edit`
6: Replace the contents with one of the below snippets
7: Save and close the text editor
8: Move *ReplayMod* up until it is **above** *LiteLoader*
9: Remove the ReplayMod jar from the mods folder if you installed it previously.
** Snippet for 1.8.9 **
`{ "formatVersion": 1, "name": "ReplayMod", "uid": "com.replaymod", "version": "1.8.9-2.4.5", "libraries": [{ "name": "com.replaymod:replaymod:1.8.9-2.4.5", "MMC-absoluteUrl": "https://minio.replaymod.com/replaymod/replaymod-1.8.9-2.4.5.jar" }]}`
** Snippet for 1.12.2 **
`{ "formatVersion": 1, "name": "ReplayMod", "uid": "com.replaymod", "version": "1.12.2-2.4.5", "libraries": [{ "name": "com.replaymod:replaymod:1.12.2-2.4.5", "MMC-absoluteUrl": "https://minio.replaymod.com/replaymod/replaymod-1.12.2-2.4.5.jar" }]}`

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -53,6 +53,10 @@ public class MarkerProcessor {
} }
} }
public static boolean producesAnyOutput(ReplayFile replayFile) throws IOException {
return !getOutputSuffixes(replayFile).isEmpty();
}
private enum OutputState { private enum OutputState {
/** A new output file has begun but not data has been written yet. */ /** A new output file has begun but not data has been written yet. */
NotYetWriting, NotYetWriting,

View File

@@ -50,7 +50,7 @@ public class GuiCreateScreenshot extends GuiRenderSettings implements Loadable {
buttonPanel.removeElement(queueButton); buttonPanel.removeElement(queueButton);
renderButton.setI18nLabel("replaymod.gui.advancedscreenshots.create").onClick(() -> { renderButton.setI18nLabel("replaymod.gui.advancedscreenshots.create").onClick(() -> {
// Closing this GUI ensures that settings are saved // Closing this GUI ensures that settings are saved
getMinecraft().openScreen(null); close();
mod.runLater(() -> { mod.runLater(() -> {
try { try {

View File

@@ -8,6 +8,7 @@ public final class Setting<T> extends SettingsRegistry.SettingKeys<T> {
public static final Setting<Boolean> INDICATOR = make("indicator", "indicator", true); public static final Setting<Boolean> INDICATOR = make("indicator", "indicator", true);
public static final Setting<Boolean> AUTO_START_RECORDING = make("autoStartRecording", "autostartrecording", true); public static final Setting<Boolean> AUTO_START_RECORDING = make("autoStartRecording", "autostartrecording", true);
public static final Setting<Boolean> AUTO_POST_PROCESS = make("autoPostProcess", null, true); public static final Setting<Boolean> AUTO_POST_PROCESS = make("autoPostProcess", null, true);
public static final Setting<Boolean> RENAME_DIALOG = make("renameDialog", "rename_recording_dialog", true);
private static <T> Setting<T> make(String key, String displayName, T defaultValue) { private static <T> Setting<T> make(String key, String displayName, T defaultValue) {
return new Setting<>(key, displayName, defaultValue); return new Setting<>(key, displayName, defaultValue);

View File

@@ -2,6 +2,7 @@ package com.replaymod.recording.gui;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
import com.replaymod.core.utils.Utils; import com.replaymod.core.utils.Utils;
import com.replaymod.recording.Setting;
import com.replaymod.replay.gui.screen.GuiReplayViewer; import com.replaymod.replay.gui.screen.GuiReplayViewer;
import com.replaymod.replaystudio.replay.ReplayMetaData; import com.replaymod.replaystudio.replay.ReplayMetaData;
import com.replaymod.replaystudio.us.myles.ViaVersion.api.Pair; import com.replaymod.replaystudio.us.myles.ViaVersion.api.Pair;
@@ -83,12 +84,13 @@ public class GuiSavingReplay {
GuiButton applyButton = new GuiButton() GuiButton applyButton = new GuiButton()
.setSize(150, 20) .setSize(150, 20)
.setI18nLabel("replaymod.gui.done") .setI18nLabel("replaymod.gui.done")
.onClick(() -> { .onClick(this::apply);
apply.forEach(Runnable::run);
close();
});
panel.addElements(new VerticalLayout.Data(0.5), applyButton); panel.addElements(new VerticalLayout.Data(0.5), applyButton);
if (!core.getSettingsRegistry().get(Setting.RENAME_DIALOG)) {
apply();
}
} }
private GuiTextField addOutput(Path path, ReplayMetaData metaData) { private GuiTextField addOutput(Path path, ReplayMetaData metaData) {
@@ -98,6 +100,7 @@ public class GuiSavingReplay {
.setText(originalName) .setText(originalName)
.setI18nHint("replaymod.gui.delete") .setI18nHint("replaymod.gui.delete")
.setTextColorDisabled(Colors.RED) .setTextColorDisabled(Colors.RED)
.onEnter(this::apply)
.setTooltip(createTooltip(path, metaData)); .setTooltip(createTooltip(path, metaData));
GuiButton clearButton = new GuiButton() GuiButton clearButton = new GuiButton()
.setSize(20, 20) .setSize(20, 20)
@@ -133,6 +136,11 @@ public class GuiSavingReplay {
}).addElements(null, tooltip, entry); }).addElements(null, tooltip, entry);
} }
private void apply() {
apply.forEach(Runnable::run);
close();
}
private void applyOutput(Path path, String newName) { private void applyOutput(Path path, String newName) {
if (newName.isEmpty()) { if (newName.isEmpty()) {
try { try {

View File

@@ -39,6 +39,7 @@ import net.minecraft.network.Packet;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import net.minecraft.util.crash.CrashReport; import net.minecraft.util.crash.CrashReport;
import org.apache.commons.io.FilenameUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@@ -65,6 +66,7 @@ import net.minecraft.network.NetworkSide;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@@ -266,6 +268,23 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
List<Pair<Path, ReplayMetaData>> outputPaths; List<Pair<Path, ReplayMetaData>> outputPaths;
synchronized (replayFile) { synchronized (replayFile) {
try { try {
if (!MarkerProcessor.producesAnyOutput(replayFile)) {
// Immediately close the saving popup, the user doesn't care about it
core.runLater(guiSavingReplay::close);
// We still have the replay, so we just save it (at least for a few weeks) in case they change their mind
String replayName = FilenameUtils.getBaseName(outputPath.getFileName().toString());
Path rawFolder = ReplayMod.instance.getRawReplayFolder();
Path rawPath = rawFolder.resolve(outputPath.getFileName());
for (int i = 1; Files.exists(rawPath); i++) {
rawPath = rawPath.resolveSibling(replayName + "." + i + ".mcpr");
}
Files.createDirectories(rawPath.getParent());
replayFile.saveTo(rawPath.toFile());
replayFile.close();
return;
}
replayFile.save(); replayFile.save();
replayFile.close(); replayFile.close();

View File

@@ -91,7 +91,7 @@ public class CameraPathExporter {
quatYaw.setFromAxisAngle(new Vector4f(0, -1, 0, (float) Math.toRadians(yaw))); quatYaw.setFromAxisAngle(new Vector4f(0, -1, 0, (float) Math.toRadians(yaw)));
quatPitch.setFromAxisAngle(new Vector4f(-1, 0, 0, (float) Math.toRadians(pitch))); quatPitch.setFromAxisAngle(new Vector4f(-1, 0, 0, (float) Math.toRadians(pitch)));
quatRoll.setFromAxisAngle(new Vector4f(0, 0, 1, (float) Math.toRadians(roll))); quatRoll.setFromAxisAngle(new Vector4f(0, 0, -1, (float) Math.toRadians(roll)));
Quaternion quaternion = new Quaternion(0, 0, 0, 1); Quaternion quaternion = new Quaternion(0, 0, 0, 1);
Quaternion.mul(quaternion, quatYaw, quaternion); Quaternion.mul(quaternion, quatYaw, quaternion);
@@ -213,7 +213,7 @@ public class CameraPathExporter {
java.nio.file.Path videoPath = settings.getOutputFile().toPath(); java.nio.file.Path videoPath = settings.getOutputFile().toPath();
java.nio.file.Path glbBasePath = Files.isDirectory(videoPath) java.nio.file.Path glbBasePath = Files.isDirectory(videoPath)
? videoPath.resolve("camera.glb") ? videoPath.resolve("camera.glb")
: videoPath.resolveSibling(videoPath.getFileName() + ".glb"); : videoPath.resolveSibling(FilenameUtils.getBaseName(videoPath.getFileName().toString()) + ".glb");
java.nio.file.Path glbPath = glbBasePath; java.nio.file.Path glbPath = glbBasePath;
for (int i = 0; Files.exists(glbPath); i++) { for (int i = 0; Files.exists(glbPath); i++) {
String baseName = FilenameUtils.getBaseName(glbBasePath.getFileName().toString()); String baseName = FilenameUtils.getBaseName(glbBasePath.getFileName().toString());

View File

@@ -141,7 +141,9 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
for (Channel channel : Channel.values()) { for (Channel channel : Channel.values()) {
CubicOpenGlFrame leftFrame = leftChannels.get(channel); CubicOpenGlFrame leftFrame = leftChannels.get(channel);
CubicOpenGlFrame rightFrame = rightChannels.get(channel); CubicOpenGlFrame rightFrame = rightChannels.get(channel);
result.put(channel, new ODSOpenGlFrame(leftFrame, rightFrame)); if (leftFrame != null && rightFrame != null) {
result.put(channel, new ODSOpenGlFrame(leftFrame, rightFrame));
}
} }
return result; return result;
} }

View File

@@ -237,7 +237,7 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
@Override @Override
public void run() { public void run() {
// Closing this GUI ensures that settings are saved // Closing this GUI ensures that settings are saved
getMinecraft().openScreen(null); close();
try { try {
VideoRenderer videoRenderer = new VideoRenderer(save(false), replayHandler, timeline); VideoRenderer videoRenderer = new VideoRenderer(save(false), replayHandler, timeline);
videoRenderer.renderVideo(); videoRenderer.renderVideo();

View File

@@ -0,0 +1,81 @@
//#if MC>=11400
package com.replaymod.render.mixin;
import org.lwjgl.system.Library;
import org.lwjgl.system.Platform;
import org.lwjgl.util.tinyexr.TinyEXR;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.function.Consumer;
import java.util.regex.Pattern;
/**
* It appears like natives on Windows cannot be loaded if one of their dependencies has already been loaded by a
* different class loader. In our case we cannot load tinyexr (on the knot class loader) because lwjgl has already
* been loaded on the system class loader.
*
* If we force the tinyexr native to load on the system class loader (by calling `Library.loadSystem(absPath)`),
* it'll load but we'll get an error when we call any of the native methods.
*
* We can't really load TinyEXR itself via the system class loader because Java does not provide any methods for
* modifying the system class path at runtime and we'd have to use JVM-specific hacks.
*
* Strangely, if we use System.loadLibrary instead of System.load, then it all just works. This mixin implements
* that workaround by finding MC's natives folder, extracting the dll from our jar into that folder and then replacing
* the context class passed to Library.loadSystem (which it uses to find dlls in jars) with Library (which is on the
* system class loader) so it cannot find the dll in our jar and falls back to using System.loadLibrary.
*/
@Mixin(value = TinyEXR.class, remap = false)
public class Mixin_WindowsWorkaroundForTinyEXRNatives {
private static final String LOAD_SYSTEM_CONSUMERS = "Lorg/lwjgl/system/Library;loadSystem(Ljava/util/function/Consumer;Ljava/util/function/Consumer;Ljava/lang/Class;Ljava/lang/String;)V";
@ModifyArg(method = "<clinit>", at = @At(value = "INVOKE", target = LOAD_SYSTEM_CONSUMERS))
private static Class<?> uglyWindowsHacks(Consumer<String> load, Consumer<String> loadLibrary, Class<?> context, String name) throws IOException {
if (Platform.get() != Platform.WINDOWS) {
return context; // works out of the box on linux
}
name = System.mapLibraryName(name);
URL libURL = context.getClassLoader().getResource(name);
if (libURL == null) {
throw new UnsatisfiedLinkError("Failed to locate library: " + name);
}
String lwjglLibName = Library.JNI_LIBRARY_NAME;
if (!lwjglLibName.endsWith(".dll")) {
lwjglLibName = System.mapLibraryName(lwjglLibName);
}
String paths = System.getProperty("java.library.path");
Path nativesDir = null;
for (String dir : Pattern.compile(File.pathSeparator).split(paths)) {
Path path = Paths.get(dir);
if (Files.isReadable(path.resolve(lwjglLibName))) {
nativesDir = path;
break;
}
}
if (nativesDir == null) {
throw new UnsatisfiedLinkError("Failed to locate natives folder in " + paths);
}
Path libPath = nativesDir.resolve(name);
try (InputStream source = libURL.openStream()) {
Files.copy(source, libPath, StandardCopyOption.REPLACE_EXISTING);
}
return Library.class;
}
}
//#endif

View File

@@ -19,6 +19,7 @@
//#endif //#endif
//#if MC>=11400 //#if MC>=11400
"Mixin_PreserveDepthDuringHandRendering", "Mixin_PreserveDepthDuringHandRendering",
"Mixin_WindowsWorkaroundForTinyEXRNatives",
"MainWindowAccessor", "MainWindowAccessor",
//#endif //#endif
"WorldRendererAccessor", "WorldRendererAccessor",

View File

@@ -1 +1 @@
2.4.5 2.5.1

View File

@@ -309,7 +309,7 @@ dependencies {
shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8' shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8'
shadow "com.github.ReplayMod:ReplayStudio:830678c", shadeExclusions shadow "com.github.ReplayMod:ReplayStudio:dac74cc", shadeExclusions
implementation(jGui){ implementation(jGui){
transitive = false // FG 1.2 puts all MC deps into the compile configuration and we don't want to shade those transitive = false // FG 1.2 puts all MC deps into the compile configuration and we don't want to shade those