Release 2.6.1

This commit is contained in:
Jonas Herzig
2021-08-21 15:32:42 +02:00
26 changed files with 297 additions and 162 deletions

View File

@@ -332,7 +332,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:a67fb11", shadeExclusions shadow "com.github.ReplayMod:ReplayStudio:c9de2f5", 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

2
jGui

Submodule jGui updated: 71d361746e...31bcfabe67

View File

@@ -68,6 +68,12 @@ fun command(vararg cmd: Any): List<String> {
} }
fun generateVersionsJson(): Map<String, Any> { fun generateVersionsJson(): Map<String, Any> {
val versionComparator = compareBy<String>(
{ (it.split(".").getOrNull(0) ?: "0").toInt() },
{ (it.split(".").getOrNull(1) ?: "0").toInt() },
{ (it.split(".").getOrNull(2) ?: "0").toInt() }
)
// Find all tag-style releases by listing all tags // Find all tag-style releases by listing all tags
val tagVersions = command("git", "for-each-ref", "--sort=taggerdate", "--format=%(refname:short)", "refs/tags") val tagVersions = command("git", "for-each-ref", "--sort=taggerdate", "--format=%(refname:short)", "refs/tags")
@@ -85,6 +91,9 @@ fun generateVersionsJson(): Map<String, Any> {
.filter { it != "core" } .filter { it != "core" }
// Internal project used to automatically remap from Forge 1.12.2 to Fabric 1.14.4 // Internal project used to automatically remap from Forge 1.12.2 to Fabric 1.14.4
.filter { it != "1.14.4-forge" } .filter { it != "1.14.4-forge" }
// We dropped 1.7.10 with the Gradle 7 update but still kept its source in case someone
// volunteers to update FG 1.2 to Gradle 7.
.filterNot { it == "1.7.10" && versionComparator.compare(version, "2.6.0") >= 0 }
mcVersions.map { "$it-$version" } mcVersions.map { "$it-$version" }
}.flatten() }.flatten()
@@ -92,11 +101,7 @@ fun generateVersionsJson(): Map<String, Any> {
val mcVersions = versions val mcVersions = versions
.map {it.substring(0, it.indexOf("-"))} .map {it.substring(0, it.indexOf("-"))}
.distinct() .distinct()
.sortedWith(compareBy( .sortedWith(versionComparator)
{ (it.split(".").getOrNull(0) ?: "0").toInt() },
{ (it.split(".").getOrNull(1) ?: "0").toInt() },
{ (it.split(".").getOrNull(2) ?: "0").toInt() }
))
val promos = mutableMapOf<String, String>() val promos = mutableMapOf<String, String>()
val root = mutableMapOf<String, Any>( val root = mutableMapOf<String, Any>(
@@ -126,6 +131,14 @@ fun generateVersionsJson(): Map<String, Any> {
return root return root
} }
val writeVersionsJson by tasks.registering {
doLast {
val versionsRoot = generateVersionsJson()
val versionsJson = JsonOutput.prettyPrint(JsonOutput.toJson(versionsRoot))
File("versions.json").writeText(versionsJson)
}
}
val doRelease by tasks.registering { val doRelease by tasks.registering {
doLast { doLast {
// Parse version // Parse version

View File

@@ -325,6 +325,18 @@ public class ReplayMod implements Module, Scheduler {
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
// Cleanup leftover no_recover files
try (DirectoryStream<Path> paths = Files.newDirectoryStream(getReplayFolder())) {
for (Path path : paths) {
String name = path.getFileName().toString();
if (name.endsWith(".no_recover")) {
Files.delete(path);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}); });
} }

View File

@@ -18,12 +18,25 @@ import static com.replaymod.core.versions.MCVer.getMinecraft;
public class GuiBackgroundProcesses extends EventRegistrations { public class GuiBackgroundProcesses extends EventRegistrations {
private GuiPanel panel = new GuiPanel().setLayout(new VerticalLayout().setSpacing(10)); private GuiPanel panel = new GuiPanel().setLayout(new VerticalLayout().setSpacing(10));
private boolean reentrant;
{ on(InitScreenCallback.EVENT, (screen, buttons) -> onGuiInit(screen)); } { on(InitScreenCallback.EVENT, (screen, buttons) -> onGuiInit(screen)); }
private void onGuiInit(net.minecraft.client.gui.screen.Screen guiScreen) { private void onGuiInit(net.minecraft.client.gui.screen.Screen guiScreen) {
if (guiScreen != getMinecraft().currentScreen) return; // people tend to construct GuiScreens without opening them if (guiScreen != getMinecraft().currentScreen) return; // people tend to construct GuiScreens without opening them
VanillaGuiScreen vanillaGui = VanillaGuiScreen.wrap(guiScreen); VanillaGuiScreen vanillaGui;
// TODO Workaround for #473 and #501 where another mod opens a new gui in response to the MCGuiScreen.init we
// call from VanillaGuiScreen.register.
// Ideally, we don't have an hidden inner MCGuiScreen and instead have a common parent class for
// AbstractGuiScreen, AbstractGuiOverlay and VanillaGuiScreen which deals with the common things. That's
// quite a bit of changes though, so I'll keep that for 2.7 and have this workaround until then.
if (reentrant) return;
try {
reentrant = true;
vanillaGui = VanillaGuiScreen.wrap(guiScreen);
} finally {
reentrant = false;
}
vanillaGui.setLayout(new CustomLayout<GuiScreen>(vanillaGui.getLayout()) { vanillaGui.setLayout(new CustomLayout<GuiScreen>(vanillaGui.getLayout()) {
@Override @Override
protected void layout(GuiScreen container, int width, int height) { protected void layout(GuiScreen container, int width, int height) {

View File

@@ -1,37 +0,0 @@
//#if FABRIC>=1
package com.replaymod.core.mixin;
import net.minecraft.client.gui.screen.pack.PackListWidget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//#if MC>=11600
import net.minecraft.client.gui.screen.pack.PackScreen;
import net.minecraft.client.gui.screen.pack.ResourcePackOrganizer;
//#else
//$$ import net.minecraft.client.resource.ClientResourcePackProfile;
//#endif
//#if MC>=11600
@Mixin(PackScreen.class)
//#else
//$$ @Mixin(ResourcePackListWidget.class)
//#endif
public abstract class Mixin_HideDynamicResourcePacks {
//#if MC>=11600
@Inject(method = "method_29672", at = @At("HEAD"), cancellable = true)
private void hideInternalPacks(PackListWidget packListWidget, ResourcePackOrganizer.Pack pack, CallbackInfo info) {
//#else
//$$ @Inject(method = "add", at = @At("HEAD"), cancellable = true)
//$$ private void hideInternalPacks(ResourcePackListWidget.ResourcePackEntry entry, CallbackInfo info) {
//$$ ClientResourcePackProfile pack = entry.getPack();
//#endif
String name = pack.getDisplayName().asString();
if (name.equals("replaymod_lang") || name.equals("replaymod_jgui")) {
info.cancel();
}
}
}
//#endif

View File

@@ -0,0 +1,52 @@
//#if FABRIC>=1
package com.replaymod.core.mixin;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.versions.LangResourcePack;
import net.minecraft.resource.ResourcePack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import java.util.function.BiConsumer;
import java.util.stream.Collector;
//#if MC>=11600
@Mixin(net.minecraft.resource.ResourcePackManager.class)
//#else
//$$ @Mixin(net.minecraft.client.MinecraftClient.class)
//#endif
public class Mixin_InjectDynamicResourcePacks {
@ModifyArg(
//#if MC>=11600
method = "createResourcePacks",
//#elseif MC>=11500
//$$ method = { "<init>", "reloadResources" },
//#else
//$$ method = { "init", "reloadResources" },
//#endif
at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;collect(Ljava/util/stream/Collector;)Ljava/lang/Object;")
)
private Collector<ResourcePack, ?, ?> injectReplayModPacks(Collector<ResourcePack, ?, ?> collector) {
collector = append(collector, new LangResourcePack());
if (ReplayMod.jGuiResourcePack != null) {
collector = append(collector, ReplayMod.jGuiResourcePack);
}
return collector;
}
private static <T, A, R> Collector<T, A, R> append(Collector<T, A, R> collector, T value) {
BiConsumer<A, T> accumulator = collector.accumulator();
return Collector.of(
collector.supplier(),
accumulator,
collector.combiner(),
result -> {
accumulator.accept(result, value);
return collector.finisher().apply(result);
}
);
}
}
//#endif

View File

@@ -1,56 +0,0 @@
//#if FABRIC>=1
package com.replaymod.core.mixin;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.versions.LangResourcePack;
import net.minecraft.client.resource.ClientBuiltinResourcePackProvider;
import net.minecraft.resource.ResourcePackProfile;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.function.Consumer;
//#if MC>=11600
import net.minecraft.resource.ResourcePackSource;
//#else
//$$ import java.util.Map;
//#endif
@Mixin(ClientBuiltinResourcePackProvider.class)
public class Mixin_RegisterDynamicResourcePacks {
@Inject(method = "register", at = @At("RETURN"))
//#if MC>=11600
private void registerReplayMod(Consumer<ResourcePackProfile> consumer, ResourcePackProfile.Factory factory, CallbackInfo ci) {
//#else
//$$ private <T extends ResourcePackProfile> void registerReplayMod(Map<String, T> map, ResourcePackProfile.Factory<T> factory, CallbackInfo ci) {
//$$ Consumer<T> consumer = (pack) -> map.put(pack.getName(), pack);
//#endif
consumer.accept(ResourcePackProfile.of(
LangResourcePack.NAME,
true,
LangResourcePack::new,
factory,
ResourcePackProfile.InsertionPosition.BOTTOM
//#if MC>=11600
, ResourcePackSource.PACK_SOURCE_BUILTIN
//#endif
));
if (ReplayMod.jGuiResourcePack != null) {
consumer.accept(ResourcePackProfile.of(
ReplayMod.JGUI_RESOURCE_PACK_NAME,
true,
() -> ReplayMod.jGuiResourcePack,
factory,
ResourcePackProfile.InsertionPosition.BOTTOM
//#if MC>=11600
, ResourcePackSource.PACK_SOURCE_BUILTIN
//#endif
));
}
}
}
//#endif

View File

@@ -9,6 +9,7 @@ import net.minecraft.client.world.ClientWorld;
import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.entity.EntityRenderDispatcher; import net.minecraft.client.render.entity.EntityRenderDispatcher;
import net.minecraft.client.sound.PositionedSoundInstance; import net.minecraft.client.sound.PositionedSoundInstance;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.crash.CrashReportSection; import net.minecraft.util.crash.CrashReportSection;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
@@ -215,6 +216,15 @@ class Patterns {
//#endif //#endif
} }
@Pattern
private static PlayerInventory getInventory(PlayerEntity entity) {
//#if MC>=11700
//$$ return entity.getInventory();
//#else
return entity.inventory;
//#endif
}
@Pattern @Pattern
private static Iterable<Entity> loadedEntityList(ClientWorld world) { private static Iterable<Entity> loadedEntityList(ClientWorld world) {
//#if MC>=11400 //#if MC>=11400

View File

@@ -31,8 +31,6 @@ public class ScreenshotRenderer implements RenderInfo {
Window window = mc.getWindow(); Window window = mc.getWindow();
int widthBefore = window.getFramebufferWidth(); int widthBefore = window.getFramebufferWidth();
int heightBefore = window.getFramebufferHeight(); int heightBefore = window.getFramebufferHeight();
boolean hideGUIBefore = mc.options.hudHidden;
mc.options.hudHidden = true;
ForceChunkLoadingHook clrg = new ForceChunkLoadingHook(mc.worldRenderer); ForceChunkLoadingHook clrg = new ForceChunkLoadingHook(mc.worldRenderer);
@@ -46,7 +44,6 @@ public class ScreenshotRenderer implements RenderInfo {
clrg.uninstall(); clrg.uninstall();
mc.options.hudHidden = hideGUIBefore;
resizeMainWindow(mc, widthBefore, heightBefore); resizeMainWindow(mc, widthBefore, heightBefore);
return true; return true;
} catch (OutOfMemoryError e) { } catch (OutOfMemoryError e) {

View File

@@ -3,6 +3,7 @@ package com.replaymod.pathing.player;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.replaymod.replay.ReplayHandler; import com.replaymod.replay.ReplayHandler;
import com.replaymod.replaystudio.pathing.path.Timeline; import com.replaymod.replaystudio.pathing.path.Timeline;
import net.minecraft.client.MinecraftClient;
/** /**
* Timeline player using the system time. * Timeline player using the system time.
@@ -21,6 +22,9 @@ public class RealtimeTimelinePlayer extends AbstractTimelinePlayer {
*/ */
private long startTime; private long startTime;
private boolean loadingResources;
private long timeBeforeResourceLoading;
public RealtimeTimelinePlayer(ReplayHandler replayHandler) { public RealtimeTimelinePlayer(ReplayHandler replayHandler) {
super(replayHandler); super(replayHandler);
} }
@@ -28,6 +32,7 @@ public class RealtimeTimelinePlayer extends AbstractTimelinePlayer {
@Override @Override
public ListenableFuture<Void> start(Timeline timeline) { public ListenableFuture<Void> start(Timeline timeline) {
firstFrame = true; firstFrame = true;
loadingResources = false;
return super.start(timeline); return super.start(timeline);
} }
@@ -35,9 +40,25 @@ public class RealtimeTimelinePlayer extends AbstractTimelinePlayer {
public void onTick() { public void onTick() {
if (secondFrame) { if (secondFrame) {
secondFrame = false; secondFrame = false;
startTime = System.currentTimeMillis(); startTime = System.currentTimeMillis() - startOffset;
}
//#if MC>=11400
if (MinecraftClient.getInstance().getOverlay() != null) {
if (!loadingResources) {
timeBeforeResourceLoading = getTimePassed();
loadingResources = true;
} }
super.onTick(); super.onTick();
return;
} else if (loadingResources && !firstFrame) {
startTime = System.currentTimeMillis() - timeBeforeResourceLoading;
loadingResources = false;
}
//#endif
super.onTick();
if (firstFrame) { if (firstFrame) {
firstFrame = false; firstFrame = false;
secondFrame = true; secondFrame = true;
@@ -46,6 +67,8 @@ public class RealtimeTimelinePlayer extends AbstractTimelinePlayer {
@Override @Override
public long getTimePassed() { public long getTimePassed() {
return startOffset + (firstFrame ? 0 : System.currentTimeMillis() - startTime); if (firstFrame) return 0;
if (loadingResources) return timeBeforeResourceLoading;
return System.currentTimeMillis() - startTime;
} }
} }

View File

@@ -166,8 +166,14 @@ public class RecordingEventHandler extends EventRegistrations {
lastY = player.getY(); lastY = player.getY();
lastZ = player.getZ(); lastZ = player.getZ();
//#if MC>=10904
final double maxRelDist = 8.0;
//#else
//$$ final double maxRelDist = 4.0;
//#endif
Packet packet; Packet packet;
if (force || Math.abs(dx) > 8.0 || Math.abs(dy) > 8.0 || Math.abs(dz) > 8.0) { if (force || Math.abs(dx) > maxRelDist || Math.abs(dy) > maxRelDist || Math.abs(dz) > maxRelDist) {
//#if MC>=10800 //#if MC>=10800
packet = new EntityPositionS2CPacket(player); packet = new EntityPositionS2CPacket(player);
//#else //#else

View File

@@ -275,7 +275,8 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
// If we crash right here, on the next start we'll prompt the user for recovery // If we crash right here, on the next start we'll prompt the user for recovery
// but we don't really want that, so drop a marker file to skip recovery for this replay. // but we don't really want that, so drop a marker file to skip recovery for this replay.
Files.createFile(outputPath.resolveSibling(outputPath.getFileName() + ".no_recover")); Path noRecoverMarker = outputPath.resolveSibling(outputPath.getFileName() + ".no_recover");
Files.createFile(noRecoverMarker);
// We still have the replay, so we just save it (at least for a few weeks) in case they change their mind // 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()); String replayName = FilenameUtils.getBaseName(outputPath.getFileName().toString());
@@ -287,6 +288,9 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
Files.createDirectories(rawPath.getParent()); Files.createDirectories(rawPath.getParent());
replayFile.saveTo(rawPath.toFile()); replayFile.saveTo(rawPath.toFile());
replayFile.close(); replayFile.close();
// Done, clean up the marker
Files.delete(noRecoverMarker);
return; return;
} }

View File

@@ -4,6 +4,7 @@ import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import com.replaymod.core.utils.FileTypeAdapter; import com.replaymod.core.utils.FileTypeAdapter;
import com.replaymod.core.versions.MCVer; import com.replaymod.core.versions.MCVer;
import de.johni0702.minecraft.gui.utils.lwjgl.Color;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableColor; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableColor;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
import net.minecraft.util.Util; import net.minecraft.util.Util;
@@ -153,7 +154,7 @@ public class RenderSettings {
private final boolean stabilizeYaw; private final boolean stabilizeYaw;
private final boolean stabilizePitch; private final boolean stabilizePitch;
private final boolean stabilizeRoll; private final boolean stabilizeRoll;
private final ReadableColor chromaKeyingColor; private final Color chromaKeyingColor;
private final int sphericalFovX; private final int sphericalFovX;
private final int sphericalFovY; private final int sphericalFovY;
private final boolean injectSphericalMetadata; private final boolean injectSphericalMetadata;
@@ -173,6 +174,32 @@ public class RenderSettings {
private final boolean highPerformance; private final boolean highPerformance;
public RenderSettings() {
this(
RenderSettings.RenderMethod.DEFAULT,
RenderSettings.EncodingPreset.MP4_CUSTOM,
1920,
1080,
60,
20 << 20,
null,
true,
false,
false,
false,
null,
360,
180,
false,
false,
false,
RenderSettings.AntiAliasing.NONE,
"",
RenderSettings.EncodingPreset.MP4_CUSTOM.getValue(),
false
);
}
public RenderSettings( public RenderSettings(
RenderMethod renderMethod, RenderMethod renderMethod,
EncodingPreset encodingPreset, EncodingPreset encodingPreset,
@@ -207,7 +234,7 @@ public class RenderSettings {
this.stabilizeYaw = stabilizeYaw; this.stabilizeYaw = stabilizeYaw;
this.stabilizePitch = stabilizePitch; this.stabilizePitch = stabilizePitch;
this.stabilizeRoll = stabilizeRoll; this.stabilizeRoll = stabilizeRoll;
this.chromaKeyingColor = chromaKeyingColor; this.chromaKeyingColor = chromaKeyingColor == null ? null : new Color(chromaKeyingColor);
this.sphericalFovX = sphericalFovX; this.sphericalFovX = sphericalFovX;
this.sphericalFovY = sphericalFovY; this.sphericalFovY = sphericalFovY;
this.injectSphericalMetadata = injectSphericalMetadata; this.injectSphericalMetadata = injectSphericalMetadata;

View File

@@ -2,8 +2,6 @@ package com.replaymod.render.gui;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.InstanceCreator;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
import com.replaymod.render.RenderSettings; import com.replaymod.render.RenderSettings;
@@ -31,7 +29,6 @@ import de.johni0702.minecraft.gui.utils.Consumer;
import de.johni0702.minecraft.gui.utils.Utils; import de.johni0702.minecraft.gui.utils.Utils;
import de.johni0702.minecraft.gui.utils.lwjgl.Color; import de.johni0702.minecraft.gui.utils.lwjgl.Color;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableColor;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.client.gui.screen.NoticeScreen; import net.minecraft.client.gui.screen.NoticeScreen;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
@@ -331,16 +328,13 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
} }
RenderSettings settings = null; RenderSettings settings = null;
try { try {
settings = new GsonBuilder() settings = new Gson().fromJson(json, RenderSettings.class);
.registerTypeAdapter(RenderSettings.class, (InstanceCreator<RenderSettings>) type -> getDefaultRenderSettings())
.registerTypeAdapter(ReadableColor.class, new Gson().getAdapter(Color.class))
.create().fromJson(json, RenderSettings.class);
} catch (JsonSyntaxException e) { } catch (JsonSyntaxException e) {
LOGGER.error("Parsing render settings:", e); LOGGER.error("Parsing render settings:", e);
LOGGER.error("Raw JSON: {}", json); LOGGER.error("Raw JSON: {}", json);
} }
if (settings == null) { if (settings == null) {
settings = getDefaultRenderSettings(); settings = new RenderSettings();
} }
load(settings); load(settings);
} }
@@ -508,7 +502,7 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
/* encodingPreset can be null from a previously supported and later removed preset */ /* encodingPreset can be null from a previously supported and later removed preset */
boolean invalidEncodingPreset = encodingPreset == null || !encodingPreset.isSupported(); boolean invalidEncodingPreset = encodingPreset == null || !encodingPreset.isSupported();
if (invalidEncodingPreset) { if (invalidEncodingPreset) {
encodingPreset = getDefaultRenderSettings().getEncodingPreset(); encodingPreset = new RenderSettings().getEncodingPreset();
} }
encodingPresetDropdown.setSelected(encodingPreset); encodingPresetDropdown.setSelected(encodingPreset);
videoWidth.setValue(settings.getTargetVideoWidth()); videoWidth.setValue(settings.getTargetVideoWidth());
@@ -628,11 +622,6 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
return ReplayModRender.instance.getRenderSettingsPath(); return ReplayModRender.instance.getRenderSettingsPath();
} }
private RenderSettings getDefaultRenderSettings() {
return new RenderSettings(RenderSettings.RenderMethod.DEFAULT, RenderSettings.EncodingPreset.MP4_CUSTOM, 1920, 1080, 60, 20 << 20, null,
true, false, false, false, null, 360, 180, false, false, false, RenderSettings.AntiAliasing.NONE, "", RenderSettings.EncodingPreset.MP4_CUSTOM.getValue(), false);
}
@Override @Override
public void open() { public void open() {
super.open(); super.open();

View File

@@ -10,6 +10,7 @@ import com.replaymod.core.events.SettingsChangedCallback;
import com.replaymod.replay.ReplayHandler; import com.replaymod.replay.ReplayHandler;
import com.replaymod.replay.events.RenderHotbarCallback; import com.replaymod.replay.events.RenderHotbarCallback;
import com.replaymod.replay.events.RenderSpectatorCrosshairCallback; import com.replaymod.replay.events.RenderSpectatorCrosshairCallback;
import com.replaymod.replay.mixin.EntityPlayerAccessor;
import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.utils.EventRegistrations;
import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback;
import com.replaymod.core.utils.Utils; import com.replaymod.core.utils.Utils;
@@ -21,9 +22,11 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.decoration.ItemFrameEntity; import net.minecraft.entity.decoration.ItemFrameEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.stat.StatHandler; import net.minecraft.stat.StatHandler;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
@@ -246,9 +249,37 @@ public class CameraEntity
this.lastRenderX = to.lastRenderX; this.lastRenderX = to.lastRenderX;
this.lastRenderY = to.lastRenderY + yOffset; this.lastRenderY = to.lastRenderY + yOffset;
this.lastRenderZ = to.lastRenderZ; this.lastRenderZ = to.lastRenderZ;
if (to instanceof LivingEntity) {
LivingEntity toLiving = (LivingEntity) to;
this.headYaw = toLiving.headYaw;
this.prevHeadYaw = toLiving.prevHeadYaw;
} else {
this.headYaw = to.yaw;
this.prevHeadYaw = to.prevYaw;
}
updateBoundingBox(); updateBoundingBox();
} }
//#if MC>=11400
@Override
public float getYaw(float tickDelta) {
Entity view = this.client.getCameraEntity();
if (view != null && view != this) {
return this.prevHeadYaw + (this.headYaw - this.prevHeadYaw) * tickDelta;
}
return super.getYaw(tickDelta);
}
@Override
public float getPitch(float tickDelta) {
Entity view = this.client.getCameraEntity();
if (view != null && view != this) {
return this.prevPitch + (this.pitch - this.prevPitch) * tickDelta;
}
return super.getPitch(tickDelta);
}
//#endif
private void updateBoundingBox() { private void updateBoundingBox() {
//#if MC>=11400 //#if MC>=11400
float width = getWidth(); float width = getWidth();
@@ -618,6 +649,43 @@ public class CameraEntity
//#if MC>=10800 //#if MC>=10800
this.noClip = this.isSpectator(); this.noClip = this.isSpectator();
//#endif //#endif
syncInventory();
}
private final PlayerInventory originalInventory = this.inventory;
// If we are spectating a player, "steal" its inventory so the rendering code knows what item(s) to render
// and if we aren't, then reset ours.
private void syncInventory() {
Entity view = this.client.getCameraEntity();
PlayerEntity viewPlayer = view != this && view instanceof PlayerEntity ? (PlayerEntity) view : null;
EntityPlayerAccessor cameraA = (EntityPlayerAccessor) this;
EntityPlayerAccessor viewPlayerA = (EntityPlayerAccessor) viewPlayer;
//#if MC>=11100
ItemStack empty = ItemStack.EMPTY;
//#else
//$$ ItemStack empty = null;
//#endif
// TODO switch to replacing the entire inventory for 1.14+ as well, should be easier and faster
//#if MC>=11400
this.equipStack(EquipmentSlot.HEAD, viewPlayer != null ? viewPlayer.getEquippedStack(EquipmentSlot.HEAD) : empty);
this.equipStack(EquipmentSlot.MAINHAND, viewPlayer != null ? viewPlayer.getEquippedStack(EquipmentSlot.MAINHAND) : empty);
this.equipStack(EquipmentSlot.OFFHAND, viewPlayer != null ? viewPlayer.getEquippedStack(EquipmentSlot.OFFHAND) : empty);
//#else
//$$ this.inventory = viewPlayer != null ? viewPlayer.inventory : originalInventory;
//#endif
//#if MC>=10904
cameraA.setItemStackMainHand(viewPlayerA != null ? viewPlayerA.getItemStackMainHand() : empty);
this.preferredHand = viewPlayer != null ? viewPlayer.preferredHand : Hand.MAIN_HAND;
cameraA.setActiveItemStackUseCount(viewPlayerA != null ? viewPlayerA.getActiveItemStackUseCount() : 0);
//#else
//$$ cameraA.setItemInUse(viewPlayerA != null ? viewPlayerA.getItemInUse() : empty);
//$$ cameraA.setItemInUseCount(viewPlayerA != null ? viewPlayerA.getItemInUseCount() : 0);
//#endif
} }
private void handleInputEvents() { private void handleInputEvents() {
@@ -639,7 +707,7 @@ public class CameraEntity
this.lastRenderYaw = this.renderYaw; this.lastRenderYaw = this.renderYaw;
this.lastRenderPitch = this.renderPitch; this.lastRenderPitch = this.renderPitch;
this.renderPitch = this.renderPitch + (this.pitch - this.renderPitch) * 0.5f; this.renderPitch = this.renderPitch + (this.pitch - this.renderPitch) * 0.5f;
this.renderYaw = this.renderYaw + (this.yaw - this.renderYaw) * 0.5f; this.renderYaw = this.renderYaw + (this.headYaw - this.renderYaw) * 0.5f;
} }
public boolean canSpectate(Entity e) { public boolean canSpectate(Entity e) {

View File

@@ -1,15 +1,9 @@
package com.replaymod.replay.camera; package com.replaymod.replay.camera;
import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.ReplayModReplay;
import com.replaymod.replay.mixin.EntityPlayerAccessor;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.options.KeyBinding; import net.minecraft.client.options.KeyBinding;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
//#if MC>=11400
import net.minecraft.entity.EquipmentSlot;
//#endif
//#if MC>=11400 //#if MC>=11400
//#else //#else
@@ -55,27 +49,6 @@ public class SpectatorCameraController implements CameraController {
Entity view = mc.getCameraEntity(); Entity view = mc.getCameraEntity();
if (view != null && view != camera) { if (view != null && view != camera) {
camera.setCameraPosRot(mc.getCameraEntity()); camera.setCameraPosRot(mc.getCameraEntity());
// If it's a player, also 'steal' its inventory so the rendering code knows what item to render
if (view instanceof PlayerEntity) {
PlayerEntity viewPlayer = (PlayerEntity) view;
//#if MC>=11400
camera.equipStack(EquipmentSlot.HEAD, viewPlayer.getEquippedStack(EquipmentSlot.HEAD));
camera.equipStack(EquipmentSlot.MAINHAND, viewPlayer.getEquippedStack(EquipmentSlot.MAINHAND));
camera.equipStack(EquipmentSlot.OFFHAND, viewPlayer.getEquippedStack(EquipmentSlot.OFFHAND));
//#else
//$$ camera.inventory = viewPlayer.inventory;
//#endif
EntityPlayerAccessor cameraA = (EntityPlayerAccessor) camera;
EntityPlayerAccessor viewPlayerA = (EntityPlayerAccessor) viewPlayer;
//#if MC>=10904
cameraA.setItemStackMainHand(viewPlayerA.getItemStackMainHand());
camera.preferredHand = viewPlayer.preferredHand;
cameraA.setActiveItemStackUseCount(viewPlayerA.getActiveItemStackUseCount());
//#else
//$$ cameraA.setItemInUse(viewPlayerA.getItemInUse());
//$$ cameraA.setItemInUseCount(viewPlayerA.getItemInUseCount());
//#endif
}
} }
} }

View File

@@ -27,7 +27,9 @@ public abstract class MixinKeyboardListener {
//#endif //#endif
at = @At( at = @At(
value = "INVOKE", value = "INVOKE",
//#if MC>=11400 //#if MC>=11701
//$$ target = "Lnet/minecraft/client/util/ScreenshotRecorder;saveScreenshot(Ljava/io/File;Lnet/minecraft/client/gl/Framebuffer;Ljava/util/function/Consumer;)V"
//#elseif MC>=11400
target = "Lnet/minecraft/client/util/ScreenshotUtils;saveScreenshot(Ljava/io/File;IILnet/minecraft/client/gl/Framebuffer;Ljava/util/function/Consumer;)V" target = "Lnet/minecraft/client/util/ScreenshotUtils;saveScreenshot(Ljava/io/File;IILnet/minecraft/client/gl/Framebuffer;Ljava/util/function/Consumer;)V"
//#else //#else
//#if MC>=11400 //#if MC>=11400

View File

@@ -2,6 +2,7 @@ package com.replaymod.replay.mixin;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.network.OtherClientPlayerEntity;
import net.minecraft.client.network.PlayerListEntry; import net.minecraft.client.network.PlayerListEntry;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@@ -24,8 +25,19 @@ public abstract class Mixin_FixNPCSkinCaching {
// intended ones. To fix that, we make this caching-glitch which servers have come to rely on an actual feature // intended ones. To fix that, we make this caching-glitch which servers have come to rely on an actual feature
// by just fetching the cache in the constructor which arguably is what MC should have done to begin with, // by just fetching the cache in the constructor which arguably is what MC should have done to begin with,
// especially because the spawn packet handling code already requires the entry to be present). // especially because the spawn packet handling code already requires the entry to be present).
if (MinecraftClient.getInstance().getNetworkHandler() != null) { // will be null if this is the client player
// To reduce the chance of incompatibility with custom player entities, we only do this for the vanilla MP one.
//noinspection ConstantConditions
if (!(((Object) this) instanceof OtherClientPlayerEntity)) return;
// To get the player list entry, we need to be connected (we usually are, but better be safe than sorry)
if (MinecraftClient.getInstance().getNetworkHandler() == null) return;
// And we catch any exceptions, so if there is still something, it's hopefully not fatal
try {
this.getPlayerListEntry(); this.getPlayerListEntry();
} catch (Exception e) {
e.printStackTrace();
} }
} }
} }

View File

@@ -150,9 +150,9 @@ public class ReplayModSimplePathing extends EventRegistrations implements Module
synchronized (replayFile) { synchronized (replayFile) {
Timeline timeline = replayFile.getTimelines(new SPTimeline()).get(""); Timeline timeline = replayFile.getTimelines(new SPTimeline()).get("");
if (timeline != null) { if (timeline != null) {
setCurrentTimeline(new SPTimeline(timeline)); setCurrentTimeline(new SPTimeline(timeline), false);
} else { } else {
setCurrentTimeline(new SPTimeline()); setCurrentTimeline(new SPTimeline(), false);
} }
} }
} catch (IOException e) { } catch (IOException e) {
@@ -225,8 +225,16 @@ public class ReplayModSimplePathing extends EventRegistrations implements Module
} }
public void setCurrentTimeline(SPTimeline newTimeline) { public void setCurrentTimeline(SPTimeline newTimeline) {
setCurrentTimeline(newTimeline, true);
}
private void setCurrentTimeline(SPTimeline newTimeline, boolean save) {
selectedPath = null; selectedPath = null;
currentTimeline = newTimeline; currentTimeline = newTimeline;
if (!save) {
lastTimeline = newTimeline;
lastChange = newTimeline.getTimeline().peekUndoStack();
}
updateDefaultInterpolatorType(); updateDefaultInterpolatorType();
} }
@@ -254,18 +262,21 @@ public class ReplayModSimplePathing extends EventRegistrations implements Module
private final AtomicInteger lastSaveId = new AtomicInteger(); private final AtomicInteger lastSaveId = new AtomicInteger();
private ExecutorService saveService; private ExecutorService saveService;
private SPTimeline lastTimeline;
private Change lastChange; private Change lastChange;
private void maybeSaveTimeline(ReplayFile replayFile) { private void maybeSaveTimeline(ReplayFile replayFile) {
SPTimeline spTimeline = currentTimeline; SPTimeline spTimeline = currentTimeline;
if (spTimeline == null || saveService == null) { if (spTimeline == null || saveService == null) {
lastTimeline = null;
lastChange = null; lastChange = null;
return; return;
} }
Change latestChange = spTimeline.getTimeline().peekUndoStack(); Change latestChange = spTimeline.getTimeline().peekUndoStack();
if (latestChange == null || latestChange == lastChange) { if (spTimeline == lastTimeline && latestChange == lastChange) {
return; return;
} }
lastTimeline = spTimeline;
lastChange = latestChange; lastChange = latestChange;
// Clone the timeline for async saving // Clone the timeline for async saving

View File

@@ -34,7 +34,7 @@ import java.util.Optional;
import static com.replaymod.core.versions.MCVer.emitLine; import static com.replaymod.core.versions.MCVer.emitLine;
import static de.johni0702.minecraft.gui.versions.MCVer.popScissorState; import static de.johni0702.minecraft.gui.versions.MCVer.popScissorState;
import static de.johni0702.minecraft.gui.versions.MCVer.pushScissorState; import static de.johni0702.minecraft.gui.versions.MCVer.pushScissorState;
import static de.johni0702.minecraft.gui.versions.MCVer.setScissorState; import static de.johni0702.minecraft.gui.versions.MCVer.setScissorDisabled;
//#if MC>=11700 //#if MC>=11700
//$$ import com.mojang.blaze3d.systems.RenderSystem; //$$ import com.mojang.blaze3d.systems.RenderSystem;
@@ -176,7 +176,7 @@ public class GuiKeyframeTimeline extends AbstractGuiTimeline<GuiKeyframeTimeline
GL11.glDisable(GL11.GL_TEXTURE_2D); GL11.glDisable(GL11.GL_TEXTURE_2D);
//#endif //#endif
pushScissorState(); pushScissorState();
setScissorState(false); setScissorDisabled();
GL11.glLineWidth(2); GL11.glLineWidth(2);
tessellator.draw(); tessellator.draw();
popScissorState(); popScissorState();

View File

@@ -102,6 +102,7 @@ public class GuiPathing {
public final GuiButton renderButton = new GuiButton().onClick(new Runnable() { public final GuiButton renderButton = new GuiButton().onClick(new Runnable() {
@Override @Override
public void run() { public void run() {
abortPathPlayback();
GuiScreen screen = GuiRenderSettings.createBaseScreen(); GuiScreen screen = GuiRenderSettings.createBaseScreen();
new GuiRenderQueue(screen, replayHandler, () -> preparePathsForPlayback(false)) { new GuiRenderQueue(screen, replayHandler, () -> preparePathsForPlayback(false)) {
@Override @Override
@@ -378,7 +379,21 @@ public class GuiPathing {
startLoadingEntityTracker(); startLoadingEntityTracker();
} }
private void abortPathPlayback() {
if (!player.isActive()) {
return;
}
ListenableFuture<Void> future = player.getFuture();
if (!future.isDone() && !future.isCancelled()) {
future.cancel(false);
}
// Tear down of the player might only happen the next tick after it was cancelled
player.onTick();
}
public void keyframeRepoButtonPressed() { public void keyframeRepoButtonPressed() {
abortPathPlayback();
try { try {
GuiKeyframeRepository gui = new GuiKeyframeRepository( GuiKeyframeRepository gui = new GuiKeyframeRepository(
mod.getCurrentTimeline(), replayHandler.getReplayFile(), mod.getCurrentTimeline().getTimeline()); mod.getCurrentTimeline(), replayHandler.getReplayFile(), mod.getCurrentTimeline().getTimeline());

View File

@@ -8,8 +8,7 @@
//#if MC>=11400 //#if MC>=11400
"AbstractButtonWidgetAccessor", "AbstractButtonWidgetAccessor",
"MixinGameRenderer", "MixinGameRenderer",
"Mixin_HideDynamicResourcePacks", "Mixin_InjectDynamicResourcePacks",
"Mixin_RegisterDynamicResourcePacks",
//#endif //#endif
//#if MC>=11400 //#if MC>=11400
"MixinMouse", "MixinMouse",

View File

@@ -1 +1 @@
2.6.0 2.6.1

View File

@@ -0,0 +1 @@
net.minecraft.item.ItemStack EMPTY field_190927_a

View File

@@ -1,3 +1,4 @@
net.minecraft.entity.player.PlayerInventory net.minecraft.entity.player.InventoryPlayer
net.minecraft.potion.EffectInstance net.minecraft.potion.PotionEffect net.minecraft.potion.EffectInstance net.minecraft.potion.PotionEffect
net.minecraft.client.gui.screen.AddServerScreen net.minecraft.client.gui.GuiScreenAddServer net.minecraft.client.gui.screen.AddServerScreen net.minecraft.client.gui.GuiScreenAddServer
net.minecraft.resources.AbstractResourcePack net.minecraft.client.resources.AbstractResourcePack net.minecraft.resources.AbstractResourcePack net.minecraft.client.resources.AbstractResourcePack