Skip to content

Commit 8e140e8

Browse files
committed
Release 2.6.4
2 parents 39ccea9 + c010a43 commit 8e140e8

File tree

66 files changed

+711
-339
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+711
-339
lines changed

build.gradle

+14-5
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ dependencies {
245245
11701: '1.17.1',
246246
11800: '1.18',
247247
11801: '1.18.1',
248+
11802: '1.18.2',
248249
][mcVersion]
249250
mappings 'net.fabricmc:yarn:' + [
250251
11404: '1.14.4+build.16',
@@ -256,6 +257,7 @@ dependencies {
256257
11701: '1.17.1+build.29:v2',
257258
11800: '1.18+build.1:v2',
258259
11801: '1.18.1+build.1:v2',
260+
11802: '1.18.2+build.1:v2',
259261
][mcVersion]
260262
modImplementation 'net.fabricmc:fabric-loader:0.12.5'
261263
def fabricApiVersion = [
@@ -268,6 +270,7 @@ dependencies {
268270
11701: '0.37.1+1.17',
269271
11800: '0.43.1+1.18',
270272
11801: '0.43.1+1.18',
273+
11802: '0.47.9+1.18.2',
271274
][mcVersion]
272275
def fabricApiModules = [
273276
"api-base",
@@ -338,29 +341,35 @@ dependencies {
338341

339342
shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8'
340343

341-
shadow "com.github.ReplayMod:ReplayStudio:70f59ef", shadeExclusions
344+
shadow "com.github.ReplayMod:ReplayStudio:b5539d1", shadeExclusions
342345

343346
implementation(FABRIC ? dependencies.project(path: jGui.path, configuration: "namedElements") : jGui) {
344347
transitive = false // FG 1.2 puts all MC deps into the compile configuration and we don't want to shade those
345348
}
346349
shadow 'com.github.ReplayMod:lwjgl-utils:27dcd66'
347350

348351
if (FABRIC) {
349-
if (mcVersion >= 11800) {
352+
if (mcVersion >= 11802) {
353+
modImplementation 'com.terraformersmc:modmenu:3.1.0'
354+
} else if (mcVersion >= 11800) {
350355
modImplementation 'com.terraformersmc:modmenu:3.0.0'
351356
} else if (mcVersion >= 11700) {
352357
modImplementation 'com.terraformersmc:modmenu:2.0.0-beta.7'
353358
} else if (mcVersion >= 11602) {
354359
modImplementation 'com.terraformersmc:modmenu:1.16.8'
355360
} else if (mcVersion >= 11600) {
356-
modImplementation 'io.github.prospector:modmenu:1.14.0+build.24'
361+
modImplementation('com.terraformersmc:modmenu:1.14.15') {
362+
exclude module: 'fabric-resource-loader-v0' // inappropriate version for 1.16.1
363+
}
357364
} else {
358-
modImplementation 'io.github.prospector.modmenu:ModMenu:1.6.2-92'
365+
modImplementation 'com.terraformersmc:modmenu:1.10.6'
359366
}
360367
}
361368

362369
if (mcVersion >= 11600) {
363-
modCompileOnly 'com.github.IrisShaders:Iris:1.0.0'
370+
modCompileOnly("com.github.IrisShaders:Iris:1.18.x~v1.2.0") {
371+
transitive = false // we do not want to upgrade our libs, we only need this to compile our mixins
372+
}
364373
}
365374

366375
testImplementation 'junit:junit:4.11'

docs/content.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -465,16 +465,14 @@ If you have a Replay in a dark setting (for example at nighttime, or in a cave)
465465

466466
This works as a replacement for the **Night Vision Potion Effect**, without the side effect of a weird sky color.
467467

468-
## Quick Mode [quickmode] (Minecraft 1.9 and up)
468+
## Quick Mode [quickmode]
469469
![](img/quickmode-icon.jpg)
470470
In **Quick Mode**, this clock symbol is displayed in the lower right corner of the screen.
471471

472472
When you first enable **Quick Mode** in a replay, an internal reference of certain entity and block properties is stored for quick access, allowing for faster navigation in the **Replay Timeline**.
473473
As a side effect, certain features like particles and second skin layers will not be rendered in the preview.
474474
By default, **Quick Mode** is toggled with `Q`.
475475

476-
**Quick Mode** is available in ReplayMod for Minecraft 1.9.4 and up.
477-
478476
## Player Overview [overview]
479477
![](img/player-overview.jpg)
480478
The **Player Overview** Screen

root.gradle.kts

+2
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ val doRelease by tasks.registering {
189189
defaultTasks("bundleJar")
190190

191191
preprocess {
192+
val mc11802 = createNode("1.18.2", 11802, "yarn")
192193
val mc11801 = createNode("1.18.1", 11801, "yarn")
193194
val mc11701 = createNode("1.17.1", 11701, "yarn")
194195
val mc11700 = createNode("1.17", 11700, "yarn")
@@ -208,6 +209,7 @@ preprocess {
208209
val mc10800 = createNode("1.8", 10800, "srg")
209210
val mc10710 = createNode("1.7.10", 10710, "srg")
210211

212+
mc11802.link(mc11801)
211213
mc11801.link(mc11701, file("versions/mapping-fabric-1.18.1-1.17.1.txt"))
212214
mc11701.link(mc11700)
213215
mc11700.link(mc11604, file("versions/mapping-fabric-1.17-1.16.4.txt"))

settings.gradle.kts

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ val jGuiVersions = listOf(
3232
"1.17",
3333
"1.17.1",
3434
"1.18.1",
35+
"1.18.2",
3536
)
3637
val replayModVersions = listOf(
3738
// "1.7.10",
@@ -52,6 +53,7 @@ val replayModVersions = listOf(
5253
"1.17",
5354
"1.17.1",
5455
"1.18.1",
56+
"1.18.2",
5557
)
5658

5759
rootProject.buildFileName = "root.gradle.kts"

src/main/java/com/replaymod/core/ReplayModMixinConfigPlugin.java

+10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
import java.util.List;
1010
import java.util.Set;
1111

12+
//#if FABRIC
13+
import net.fabricmc.loader.api.FabricLoader;
14+
//#endif
15+
1216
//#if MC>=11400
1317
import java.io.InputStream;
1418
//#else
@@ -34,6 +38,9 @@ static boolean hasClass(String name) throws IOException {
3438

3539
private final Logger logger = LogManager.getLogger("replaymod/mixin");
3640
private final boolean hasOF = hasClass("optifine.OptiFineForgeTweaker") || hasClass("me.modmuss50.optifabric.mod.Optifabric");
41+
//#if FABRIC
42+
private final boolean hasIris = FabricLoader.getInstance().isModLoaded("iris");
43+
//#endif
3744

3845
{
3946
logger.debug("hasOF: " + hasOF);
@@ -49,6 +56,9 @@ public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
4956
}
5057
if (mixinClassName.endsWith("_OF")) return hasOF;
5158
if (mixinClassName.endsWith("_NoOF")) return !hasOF;
59+
//#if FABRIC
60+
if (mixinClassName.endsWith("_Iris")) return hasIris;
61+
//#endif
5262
return true;
5363
}
5464

src/main/java/com/replaymod/core/SettingsRegistryBackend.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.List;
2323
import java.util.Map;
2424

25+
import static com.replaymod.core.utils.Utils.ensureDirectoryExists;
2526
import static com.replaymod.core.versions.MCVer.getMinecraft;
2627

2728
class SettingsRegistryBackend {
@@ -179,7 +180,7 @@ public void save() {
179180
Gson gson = new GsonBuilder().setPrettyPrinting().create();
180181
String config = gson.toJson(root);
181182
try {
182-
Files.createDirectories(configFile.getParent());
183+
ensureDirectoryExists(configFile.getParent());
183184
Files.write(configFile, config.getBytes(StandardCharsets.UTF_8));
184185
} catch (IOException e) {
185186
e.printStackTrace();

src/main/java/com/replaymod/core/files/ReplayFoldersService.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import java.nio.file.Files;
1111
import java.nio.file.Path;
1212

13+
import static com.replaymod.core.utils.Utils.ensureDirectoryExists;
14+
1315
public class ReplayFoldersService {
1416
private final Path mcDir = MinecraftClient.getInstance().runDirectory.toPath();
1517
private final SettingsRegistry settings;
@@ -19,30 +21,30 @@ public ReplayFoldersService(SettingsRegistry settings) {
1921
}
2022

2123
public Path getReplayFolder() throws IOException {
22-
return Files.createDirectories(mcDir.resolve(settings.get(Setting.RECORDING_PATH)));
24+
return ensureDirectoryExists(mcDir.resolve(settings.get(Setting.RECORDING_PATH)));
2325
}
2426

2527
/**
2628
* Folder into which replay backups are saved before the MarkerProcessor is unleashed.
2729
*/
2830
public Path getRawReplayFolder() throws IOException {
29-
return Files.createDirectories(getReplayFolder().resolve("raw"));
31+
return ensureDirectoryExists(getReplayFolder().resolve("raw"));
3032
}
3133

3234
/**
3335
* Folder into which replays are recorded.
3436
* Distinct from the main folder, so they cannot be opened while they are still saving.
3537
*/
3638
public Path getRecordingFolder() throws IOException {
37-
return Files.createDirectories(getReplayFolder().resolve("recording"));
39+
return ensureDirectoryExists(getReplayFolder().resolve("recording"));
3840
}
3941

4042
/**
4143
* Folder in which replay cache files are stored.
4244
* Distinct from the recording folder cause people kept confusing them with recordings.
4345
*/
4446
public Path getCacheFolder() throws IOException {
45-
Path path = Files.createDirectories(mcDir.resolve(settings.get(Setting.CACHE_PATH)));
47+
Path path = ensureDirectoryExists(mcDir.resolve(settings.get(Setting.CACHE_PATH)));
4648
try {
4749
Files.setAttribute(path, "dos:hidden", true);
4850
} catch (UnsupportedOperationException ignored) {

src/main/java/com/replaymod/core/gui/RestoreReplayGui.java

+5
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,16 @@ public RestoreReplayGui(ReplayMod core, GuiScreen parent, File file) {
5656
new GuiLabel().setI18nText("replaymod.gui.restorereplay1"),
5757
new GuiLabel().setI18nText("replaymod.gui.restorereplay2", Files.getNameWithoutExtension(file.getName())),
5858
new GuiLabel().setI18nText("replaymod.gui.restorereplay3"));
59+
60+
LOGGER.info("Found partially saved replay, offering recovery: " + file);
61+
5962
yesButton.onClick(() -> {
63+
LOGGER.info("Attempting recovery: " + file);
6064
recoverInBackground();
6165
parent.display();
6266
});
6367
noButton.onClick(() -> {
68+
LOGGER.info("Recovery rejected, marking for deletion: " + file);
6469
try {
6570
File tmp = new File(file.getParentFile(), file.getName() + ".tmp");
6671
File deleted = new File(file.getParentFile(), file.getName() + ".del");

src/main/java/com/replaymod/core/mixin/MixinMinecraft.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ private void postRender(boolean unused, CallbackInfo ci) {
6363
PostRenderCallback.EVENT.invoker().postRender();
6464
}
6565
//#else
66+
//$$ @Shadow long systemTime;
6667
//#if MC>=10904
6768
//$$ @Shadow protected abstract void runTickKeyboard() throws IOException;
6869
//$$ @Shadow protected abstract void runTickMouse() throws IOException;
@@ -80,6 +81,8 @@ private void postRender(boolean unused, CallbackInfo ci) {
8081
//$$ public void replayModRunTickMouse() {
8182
//$$ try {
8283
//$$ runTickMouse();
84+
//$$ // Update last tick time (MC ignores inputs when there hasn't been a tick in 200ms)
85+
//$$ systemTime = Minecraft.getSystemTime();
8386
//$$ } catch (IOException e) {
8487
//$$ e.printStackTrace();
8588
//$$ }
@@ -94,7 +97,12 @@ private void postRender(boolean unused, CallbackInfo ci) {
9497
//$$
9598
//$$ @Inject(method = "runTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;sendClickBlockToController(Z)V"), cancellable = true)
9699
//$$ private void doEarlyReturnFromRunTick(CallbackInfo ci) {
97-
//$$ if (earlyReturn) ci.cancel();
100+
//$$ if (earlyReturn) {
101+
//$$ ci.cancel();
102+
//$$
103+
//$$ // Update last tick time (MC ignores inputs when there hasn't been a tick in 200ms)
104+
//$$ systemTime = Minecraft.getSystemTime();
105+
//$$ }
98106
//$$ }
99107
//#endif
100108
//$$ @Redirect(

src/main/java/com/replaymod/core/utils/Utils.java

+54-2
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,13 @@
5555
import java.io.File;
5656
import java.io.IOException;
5757
import java.io.InputStream;
58+
import java.io.OutputStream;
5859
import java.io.UnsupportedEncodingException;
5960
import java.net.URLDecoder;
61+
import java.nio.file.Files;
62+
import java.nio.file.Path;
63+
import java.nio.file.StandardOpenOption;
64+
import java.nio.file.attribute.FileAttribute;
6065
import java.security.KeyManagementException;
6166
import java.security.KeyStore;
6267
import java.security.KeyStoreException;
@@ -166,8 +171,45 @@ public static boolean isValidEmailAddress(String mail) {
166171

167172
private static final PercentEscaper REPLAY_NAME_ENCODER = new PercentEscaper(".-_ ", false);
168173

169-
public static String replayNameToFileName(String replayName) {
170-
return REPLAY_NAME_ENCODER.escape(replayName) + ".mcpr";
174+
public static Path replayNameToPath(Path folder, String replayName) {
175+
// If we can, prefer directly using the replay name as the file name
176+
if (isUsable(folder, replayName + ".mcpr")) {
177+
return folder.resolve(replayName + ".mcpr");
178+
} else {
179+
// otherwise, fall back to percent encoding
180+
return folder.resolve(REPLAY_NAME_ENCODER.escape(replayName) + ".mcpr");
181+
}
182+
}
183+
184+
/**
185+
* Checks whether a given file name is actually usable with the file system / operating system at the given folder.
186+
*/
187+
private static boolean isUsable(Path folder, String fileName) {
188+
Path path = folder.resolve(fileName);
189+
if (Files.exists(path)) {
190+
return true; // if it already exits, it's definitely usable
191+
}
192+
193+
// Otherwise, there's no sure way to know, so we just gotta try
194+
try (OutputStream outputStream = Files.newOutputStream(path, StandardOpenOption.CREATE_NEW)) {
195+
outputStream.flush();
196+
} catch (IOException e) {
197+
return false;
198+
}
199+
200+
// Looking good, but now we gotta clean up that mess (and Anti-Virus / Cloud Sync are know to lock them)
201+
int attempts = 0;
202+
while (true) {
203+
try {
204+
Files.delete(path);
205+
return true;
206+
} catch (IOException e) {
207+
if (attempts++ > 100) {
208+
LOGGER.warn("Repeatedly failed to clean up temporary test file at " + path + ": ", e);
209+
return false; // while we were able to use it, it's taken now and we can't get it back
210+
}
211+
}
212+
}
171213
}
172214

173215
public static String fileNameToReplayName(String fileName) {
@@ -356,4 +398,14 @@ public static <T> T configure(T instance, Consumer<T> configure) {
356398
configure.accept(instance);
357399
return instance;
358400
}
401+
402+
/**
403+
* Like {@link Files#createDirectories(Path, FileAttribute[])} but doesn't explode if it's a symlink.
404+
*/
405+
public static Path ensureDirectoryExists(Path path) throws IOException {
406+
// Who in their right mind thought the default behavior of throwing when the target is a link to a directory
407+
// was the preferred behavior?! Everyone has to fall for this at least once to learn it...
408+
// https://bugs.openjdk.java.net/browse/JDK-8130464
409+
return Files.createDirectories(Files.exists(path) ? path.toRealPath() : path);
410+
}
359411
}

src/main/java/com/replaymod/core/versions/MCVer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ public static Vec3d getPosition(Particle particle, float partialTicks) {
304304

305305
//#if MC<=11601
306306
//$$ public static Vec3d getTrackedPosition(Entity entity) {
307-
//$$ return new Vec3d(entity.trackedX, entity.trackedY, entity.trackedZ);
307+
//$$ return new Vec3d(entity.trackedX / 4096.0, entity.trackedY / 4096.0, entity.trackedZ / 4096.0);
308308
//$$ }
309309
//#endif
310310

src/main/java/com/replaymod/editor/gui/GuiEditReplay.java

+6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import de.johni0702.minecraft.gui.utils.lwjgl.Color;
2222
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
2323
import net.minecraft.util.crash.CrashReport;
24+
import org.apache.logging.log4j.LogManager;
25+
import org.apache.logging.log4j.Logger;
2426

2527
import java.io.IOException;
2628
import java.nio.file.Path;
@@ -31,6 +33,8 @@
3133
import java.util.stream.Collectors;
3234

3335
public class GuiEditReplay extends AbstractGuiPopup<GuiEditReplay> {
36+
private static final Logger LOGGER = LogManager.getLogger();
37+
3438
private final Path inputPath;
3539

3640
private final EditTimeline timeline;
@@ -60,6 +64,8 @@ protected GuiEditReplay(GuiContainer container, Path inputPath) throws IOExcepti
6064
super(container);
6165
this.inputPath = inputPath;
6266

67+
LOGGER.info("Opening replay in editor: " + inputPath);
68+
6369
try (ReplayFile replayFile = ReplayMod.instance.files.open(inputPath)) {
6470
markers = replayFile.getMarkers().or(HashSet::new);
6571
timeline = new EditTimeline(new HashSet<>(markers), markers -> this.markers = markers);

src/main/java/com/replaymod/editor/gui/MarkerProcessor.java

-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ public static List<Pair<Path, ReplayMetaData>> apply(Path path, Consumer<Float>
133133
for (int i = 1; Files.exists(inputPath); i++) {
134134
inputPath = inputPath.resolveSibling(replayName + "." + i + ".mcpr");
135135
}
136-
Files.createDirectories(inputPath.getParent());
137136
Files.move(path, inputPath);
138137

139138
try (ReplayFile inputReplayFile = mod.files.open(inputPath)) {

src/main/java/com/replaymod/extras/QuickMode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public void register(final ReplayMod mod) {
2525
return;
2626
}
2727
replayHandler.getReplaySender().setSyncModeAndWait();
28-
mod.runLater(() -> {
28+
mod.runLaterWithoutLock(() -> {
2929
replayHandler.ensureQuickModeInitialized(() -> {
3030
boolean enabled = !replayHandler.isQuickMode();
3131
updateIndicator(replayHandler.getOverlay(), enabled);

src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public GuiCreateScreenshot(ReplayMod mod) {
4040
new GuiLabel().setI18nText("replaymod.gui.advancedscreenshots.resolution"), videoResolutionPanel,
4141
new GuiLabel().setI18nText("replaymod.gui.rendersettings.outputfile"), outputFileButton);
4242

43-
resetChildren(advancedPanel).addElements(null, nametagCheckbox, new GuiPanel().setLayout(
43+
resetChildren(advancedPanel).addElements(null, nametagCheckbox, alphaCheckbox , new GuiPanel().setLayout(
4444
new GridLayout().setCellsEqualSize(false).setColumns(2).setSpacingX(5).setSpacingY(15))
4545
.addElements(new GridLayout.Data(0, 0.5),
4646
new GuiLabel().setI18nText("replaymod.gui.rendersettings.stabilizecamera"), stabilizePanel,

0 commit comments

Comments
 (0)