Merge branch '1.12-dev' into 1.12.1-dev

This commit is contained in:
Jonas Herzig
2018-01-17 19:55:23 +01:00
37 changed files with 759 additions and 45 deletions

View File

@@ -12,7 +12,7 @@ to access private fields is a good indication that this has happened).
You can build the mod by running `./gradlew :build`. You can then find the final jar files in `build/libs/`. You can build the mod by running `./gradlew :build`. You can then find the final jar files in `build/libs/`.
### IntelliJ ### IntelliJ
For the initial setup run `./gradlew preshadowJar idea genIntellijRuns`. For the initial setup run `./gradlew idea genIntellijRuns`.
You also need to enable the Mixin annotation processor: You also need to enable the Mixin annotation processor:
1. Go to File -> Settings -> Build, Execution, Deployment -> Compiler -> Annotation Processors 1. Go to File -> Settings -> Build, Execution, Deployment -> Compiler -> Annotation Processors
2. Tick "Enable annotation processing" 2. Tick "Enable annotation processing"
@@ -20,8 +20,8 @@ You also need to enable the Mixin annotation processor:
4. Set the name to "reobfSrgFile" and the value to "$path/build/mcp-srg.srg" where you replace $path with the full 4. Set the name to "reobfSrgFile" and the value to "$path/build/mcp-srg.srg" where you replace $path with the full
path to the folder containing the gradlew file path to the folder containing the gradlew file
Whenever you switch to another branch, you can either just run `./gradlew preshadowJar idea` or instead run Whenever you switch to another branch, you can either just run `./gradlew idea` or instead run
`./gradlew preshadowJar copySrg` and then refresh the gradle project from within IntelliJ. `./gradlew copySrg` and then refresh the gradle project from within IntelliJ.
### Eclipse ### Eclipse

View File

@@ -69,7 +69,7 @@ dependencies {
shade 'org.aspectj:aspectjrt:1.8.2' shade 'org.aspectj:aspectjrt:1.8.2'
shade 'com.github.replaymod:ReplayStudio:77dc1d7' shade 'com.github.replaymod:ReplayStudio:d4b2037'
testCompile 'junit:junit:4.11' testCompile 'junit:junit:4.11'
} }

View File

@@ -16,8 +16,8 @@ f98b3e07c6b6a32dd6f9f70f5cef4ac9be42a9a6c850ceb8f33767da94706635 /com/github/joh
03e3dff7f9b3ac6cd3b87684fd36a2f6996a4b164a2f8fab9c22c01cb7bfb84b /com/github/johni0702/gradle-reproducible-builds-plugin/a524ada/gradle-reproducible-builds-plugin-a524ada.pom 03e3dff7f9b3ac6cd3b87684fd36a2f6996a4b164a2f8fab9c22c01cb7bfb84b /com/github/johni0702/gradle-reproducible-builds-plugin/a524ada/gradle-reproducible-builds-plugin-a524ada.pom
75ccc0e24d37ed5b8916e1bcffad1e067c2b1cfa21b635287f968db5c3c1963a /com/github/jponge/lzma-java/1.3/lzma-java-1.3.jar 75ccc0e24d37ed5b8916e1bcffad1e067c2b1cfa21b635287f968db5c3c1963a /com/github/jponge/lzma-java/1.3/lzma-java-1.3.jar
fbcba81b21a8bc3c0761e4798fa05285444b43d681c03c9af49f9b2e1ecb0184 /com/github/jponge/lzma-java/1.3/lzma-java-1.3.pom fbcba81b21a8bc3c0761e4798fa05285444b43d681c03c9af49f9b2e1ecb0184 /com/github/jponge/lzma-java/1.3/lzma-java-1.3.pom
8b81939c797646572f726cb810d219d6e6d30ffa1d352cdfb17e67f819afcac8 /com/github/replaymod/ReplayStudio/77dc1d7/ReplayStudio-77dc1d7.jar be650f4c822de0128866975e6af3ef7b4574328ecf99afd92ef92af30dddea34 /com/github/replaymod/ReplayStudio/d4b2037/ReplayStudio-d4b2037.jar
277b1b1dc9e04fd9c28c224a43821ba9aa83f0dd866fefd47ee2354f3f15d9a8 /com/github/replaymod/ReplayStudio/77dc1d7/ReplayStudio-77dc1d7.pom b2a36467f1d2ea19d340912ddad589d306baa06b10411458a26bbb3886902400 /com/github/replaymod/ReplayStudio/d4b2037/ReplayStudio-d4b2037.pom
c6ebd74cd6108b8c372c95b842725ee5bd6d3303ba26cb00f18bc92f80b47956 /com/github/tony19/named-regexp/0.2.3/named-regexp-0.2.3.jar c6ebd74cd6108b8c372c95b842725ee5bd6d3303ba26cb00f18bc92f80b47956 /com/github/tony19/named-regexp/0.2.3/named-regexp-0.2.3.jar
7cdd89a892927998beab59398ef073232588f6e83e411cf4f0905833bf300487 /com/github/tony19/named-regexp/0.2.3/named-regexp-0.2.3.pom 7cdd89a892927998beab59398ef073232588f6e83e411cf4f0905833bf300487 /com/github/tony19/named-regexp/0.2.3/named-regexp-0.2.3.pom
47c625c83a8cf97b8bbdff2acde923ff8fd3174e62aabcfc5d1b86692594ffba /com/google/api-client/google-api-client/1.22.0/google-api-client-1.22.0.jar 47c625c83a8cf97b8bbdff2acde923ff8fd3174e62aabcfc5d1b86692594ffba /com/google/api-client/google-api-client/1.22.0/google-api-client-1.22.0.jar
@@ -164,7 +164,7 @@ a096bc9f7579cec07483874151578720eeb3189c546c19cff56a6203df17b50e /lzma/lzma/0.0.
* /mc/game/version_manifest.json * /mc/game/version_manifest.json
19331fb29bf8b8d5ed764677c94cca9d66481e10104f660eb555894a4300cf22 /mc/game/1.12.1/client/83385d346cf7f97d1e447b888750fb88e9928b93/client.jar 19331fb29bf8b8d5ed764677c94cca9d66481e10104f660eb555894a4300cf22 /mc/game/1.12.1/client/83385d346cf7f97d1e447b888750fb88e9928b93/client.jar
848912640bccfa7ea34a2cc1c76cb2b35f8467c4216d9603917c991660f91a8b /mc/game/1.12.1/server/561c7b2d54bae80cc06b05d950633a9ac95da816/server.jar 848912640bccfa7ea34a2cc1c76cb2b35f8467c4216d9603917c991660f91a8b /mc/game/1.12.1/server/561c7b2d54bae80cc06b05d950633a9ac95da816/server.jar
5dcff0a65ed3b43d82328340505118e53dab5273c352e2d56733a0e498ed5655 /mc/game/2ce9731e5bafdf69014e4e6db1cc56149958c5a8/1.12.1.json * /mc/game/2ce9731e5bafdf69014e4e6db1cc56149958c5a8/1.12.1.json
c4dadeeecaa90c8847902082aee5eb107fcf59c5d0e63a17fcaf273c0e2d2bd1 /net/java/dev/jna/jna/4.4.0/jna-4.4.0.jar c4dadeeecaa90c8847902082aee5eb107fcf59c5d0e63a17fcaf273c0e2d2bd1 /net/java/dev/jna/jna/4.4.0/jna-4.4.0.jar
800bb2831dda341336ea69b7beb675f159973f64dad6aaa1ad8c4fa78e5cb19b /net/java/dev/jna/jna/4.4.0/jna-4.4.0.pom 800bb2831dda341336ea69b7beb675f159973f64dad6aaa1ad8c4fa78e5cb19b /net/java/dev/jna/jna/4.4.0/jna-4.4.0.pom
ea89d5090c8303ba4e9a0056e6d8a20429f3e021411e950bfd9eba3b6e6cf15c /net/java/dev/jna/platform/3.4.0/platform-3.4.0.jar ea89d5090c8303ba4e9a0056e6d8a20429f3e021411e950bfd9eba3b6e6cf15c /net/java/dev/jna/platform/3.4.0/platform-3.4.0.jar
@@ -461,6 +461,7 @@ cbfacd5dd812db16dc910994007fe58d9402a25507f81a1c2218e15c2c1bedfa /org/ow2/asm/as
347a7a9400f9964e87c91d3980e48eebdc8d024bc3b36f7f22189c662853a51c /org/ow2/asm/asm-tree/5.0.3/asm-tree-5.0.3.jar 347a7a9400f9964e87c91d3980e48eebdc8d024bc3b36f7f22189c662853a51c /org/ow2/asm/asm-tree/5.0.3/asm-tree-5.0.3.jar
65819ca7c5a218ff49f8ebe72f3b39219c81f137d017acc1aec15b1054cf5236 /org/ow2/asm/asm-tree/5.0.3/asm-tree-5.0.3.pom 65819ca7c5a218ff49f8ebe72f3b39219c81f137d017acc1aec15b1054cf5236 /org/ow2/asm/asm-tree/5.0.3/asm-tree-5.0.3.pom
51215c67d2c068d8b7d2f6f80f51372a098075deccc448d4bdd7b987ba8328fb /org/ow2/ow2/1.3/ow2-1.3.pom 51215c67d2c068d8b7d2f6f80f51372a098075deccc448d4bdd7b987ba8328fb /org/ow2/ow2/1.3/ow2-1.3.pom
3ca225ce3917eac8bf4b7d2186845df4e70dcdede356dca8537b6d78a535c91e /org/projectlombok/lombok/1.16.4/lombok-1.16.4.jar
fcb8d5745f776567f1cce332282750b1653568324621ecef03288c8a25919d0e /org/projectlombok/lombok/1.16.4/lombok-1.16.4.pom fcb8d5745f776567f1cce332282750b1653568324621ecef03288c8a25919d0e /org/projectlombok/lombok/1.16.4/lombok-1.16.4.pom
e0a471be03e1e6b02bf019480cec7a3ac9801702bf7bf62f15d077ad4df8dd5d /org/projectlombok/lombok/1.16.6/lombok-1.16.6.jar e0a471be03e1e6b02bf019480cec7a3ac9801702bf7bf62f15d077ad4df8dd5d /org/projectlombok/lombok/1.16.6/lombok-1.16.6.jar
32ac0a2363ccc0c5086b62cfc05e28a355b74e155efef6b426f5498a0dfc9e4c /org/projectlombok/lombok/1.16.6/lombok-1.16.6.pom 32ac0a2363ccc0c5086b62cfc05e28a355b74e155efef6b426f5498a0dfc9e4c /org/projectlombok/lombok/1.16.6/lombok-1.16.6.pom

2
jGui

Submodule jGui updated: e5fcc65032...46c3086257

View File

@@ -7,16 +7,26 @@ import com.replaymod.compat.shaders.ShaderBeginRender;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.EventBus; import net.minecraftforge.fml.common.eventhandler.EventBus;
import org.apache.logging.log4j.Logger;
@Mod(modid = ReplayModCompat.MOD_ID, @Mod(modid = ReplayModCompat.MOD_ID,
version = "@MOD_VERSION@", version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*", acceptableRemoteVersions = "*",
clientSideOnly = true,
useMetadata = true) useMetadata = true)
public class ReplayModCompat { public class ReplayModCompat {
public static final String MOD_ID = "replaymod-compat"; public static final String MOD_ID = "replaymod-compat";
public static Logger LOGGER;
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
LOGGER = event.getModLog();
}
@Mod.EventHandler @Mod.EventHandler
public void init(FMLInitializationEvent event) { public void init(FMLInitializationEvent event) {
EventBus bus = MinecraftForge.EVENT_BUS; EventBus bus = MinecraftForge.EVENT_BUS;

View File

@@ -25,6 +25,8 @@ import net.minecraftforge.fml.common.versioning.VersionRange;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collections; import java.util.Collections;
import static com.replaymod.compat.ReplayModCompat.LOGGER;
/** /**
* Old Better Sprinting versions replace the vanilla player with their own, overridden instance (replacing the camera entity). * Old Better Sprinting versions replace the vanilla player with their own, overridden instance (replacing the camera entity).
* *
@@ -34,7 +36,7 @@ public class DisableBetterSprinting {
private static final VersionRange OLD_VERSION = VersionRange.newRange(null, private static final VersionRange OLD_VERSION = VersionRange.newRange(null,
Collections.singletonList(new Restriction(null, false, new DefaultArtifactVersion("2.0.0"), false))); Collections.singletonList(new Restriction(null, false, new DefaultArtifactVersion("2.0.0"), false)));
private static final String LOGIC_CLASS_NAME = "chylex.bettersprinting.client.player.impl.LogicImplOverride"; private static final String LOGIC_CLASS_NAME = "chylex.bettersprinting.client.player.impl.LogicImplOverride";
private static final String CONTROLLER_OVERRIDE_CLASS_NAME = LOGIC_CLASS_NAME + ".PlayerControllerMPOverride"; private static final String CONTROLLER_OVERRIDE_CLASS_NAME = LOGIC_CLASS_NAME + "$PlayerControllerMPOverride";
public static void register() { public static void register() {
Loader.instance().getModList().stream() Loader.instance().getModList().stream()
@@ -44,7 +46,9 @@ public class DisableBetterSprinting {
.ifPresent($_ -> MinecraftForge.EVENT_BUS.register(new DisableBetterSprinting())); .ifPresent($_ -> MinecraftForge.EVENT_BUS.register(new DisableBetterSprinting()));
} }
private DisableBetterSprinting() {} private DisableBetterSprinting() {
LOGGER.info("BetterSprinting workaround enabled");
}
private final Minecraft mc = Minecraft.getMinecraft(); private final Minecraft mc = Minecraft.getMinecraft();
private PlayerControllerMP originalController; private PlayerControllerMP originalController;
@@ -71,6 +75,7 @@ public class DisableBetterSprinting {
// Suppress this message if it's the Better Sprinting warning message // Suppress this message if it's the Better Sprinting warning message
for (StackTraceElement elem : Thread.currentThread().getStackTrace()) { for (StackTraceElement elem : Thread.currentThread().getStackTrace()) {
if (LOGIC_CLASS_NAME.equals(elem.getClassName())) { if (LOGIC_CLASS_NAME.equals(elem.getClassName())) {
LOGGER.info("BetterSprinting warning message suppressed.");
event.setCanceled(true); event.setCanceled(true);
return; return;
} }
@@ -83,6 +88,7 @@ public class DisableBetterSprinting {
if (mc.playerController != null && mc.playerController.getClass().getName().equals(CONTROLLER_OVERRIDE_CLASS_NAME)) { if (mc.playerController != null && mc.playerController.getClass().getName().equals(CONTROLLER_OVERRIDE_CLASS_NAME)) {
// Someone has secretly swapped out the player controller and is about to substitute their own player entity. // Someone has secretly swapped out the player controller and is about to substitute their own player entity.
// This is the right time to destroy their plan. // This is the right time to destroy their plan.
LOGGER.info("Preventing player controller {} from being replaced by BetterSprinting with {}.", originalController, mc.playerController);
mc.playerController = originalController; mc.playerController = originalController;
} }
} }

View File

@@ -40,6 +40,7 @@ import java.util.List;
version = "@MOD_VERSION@", version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*", acceptableRemoteVersions = "*",
clientSideOnly = true,
updateJSON = "https://raw.githubusercontent.com/ReplayMod/ReplayMod/master/versions.json", updateJSON = "https://raw.githubusercontent.com/ReplayMod/ReplayMod/master/versions.json",
guiFactory = "com.replaymod.core.gui.GuiFactory") guiFactory = "com.replaymod.core.gui.GuiFactory")
public class ReplayMod { public class ReplayMod {

View File

@@ -12,6 +12,7 @@ import org.apache.logging.log4j.Logger;
version = "@MOD_VERSION@", version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*", acceptableRemoteVersions = "*",
clientSideOnly = true,
useMetadata = true) useMetadata = true)
public class ReplayModEditor { public class ReplayModEditor {
public static final String MOD_ID = "replaymod-editor"; public static final String MOD_ID = "replaymod-editor";

View File

@@ -1,6 +1,7 @@
package com.replaymod.extras; package com.replaymod.extras;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
import com.replaymod.extras.advancedscreenshots.AdvancedScreenshots;
import com.replaymod.extras.playeroverview.PlayerOverview; import com.replaymod.extras.playeroverview.PlayerOverview;
import com.replaymod.extras.urischeme.UriSchemeExtra; import com.replaymod.extras.urischeme.UriSchemeExtra;
import com.replaymod.extras.youtube.YoutubeUpload; import com.replaymod.extras.youtube.YoutubeUpload;
@@ -19,6 +20,7 @@ import java.util.Optional;
version = "@MOD_VERSION@", version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*", acceptableRemoteVersions = "*",
clientSideOnly = true,
useMetadata = true) useMetadata = true)
public class ReplayModExtras { public class ReplayModExtras {
public static final String MOD_ID = "replaymod-extras"; public static final String MOD_ID = "replaymod-extras";
@@ -27,6 +29,7 @@ public class ReplayModExtras {
public static ReplayModExtras instance; public static ReplayModExtras instance;
private static final List<Class<? extends Extra>> builtin = Arrays.asList( private static final List<Class<? extends Extra>> builtin = Arrays.asList(
AdvancedScreenshots.class,
PlayerOverview.class, PlayerOverview.class,
UriSchemeExtra.class, UriSchemeExtra.class,
YoutubeUpload.class, YoutubeUpload.class,
@@ -43,6 +46,7 @@ public class ReplayModExtras {
@Mod.EventHandler @Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) { public void preInit(FMLPreInitializationEvent event) {
LOGGER = event.getModLog(); LOGGER = event.getModLog();
ReplayMod.instance.getSettingsRegistry().register(Setting.class);
} }
@Mod.EventHandler @Mod.EventHandler

View File

@@ -0,0 +1,8 @@
package com.replaymod.extras;
import com.replaymod.core.SettingsRegistry;
public final class Setting<T> {
public static final SettingsRegistry.SettingKey<Boolean> SKIP_POST_SCREENSHOT_GUI =
new SettingsRegistry.SettingKeys<>("advanced", "skipPostScreenshotGui", null, false);
}

View File

@@ -0,0 +1,41 @@
package com.replaymod.extras.advancedscreenshots;
import com.replaymod.core.ReplayMod;
import com.replaymod.extras.Extra;
import com.replaymod.replay.events.ReplayDispatchKeypressesEvent;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiControls;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.lwjgl.input.Keyboard;
public class AdvancedScreenshots implements Extra {
private ReplayMod mod;
private final Minecraft mc = Minecraft.getMinecraft();
@Override
public void register(ReplayMod mod) throws Exception {
this.mod = mod;
MinecraftForge.EVENT_BUS.register(this);
}
@SubscribeEvent
public void onDispatchKeypresses(ReplayDispatchKeypressesEvent.Pre event) {
int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() : Keyboard.getEventKey();
// all the conditions required to trigger a screenshot condensed in a single if statement
if (keyCode != 0 && !Keyboard.isRepeatEvent()
&& (!(mc.currentScreen instanceof GuiControls) || ((GuiControls) mc.currentScreen).time <= mc.getSystemTime() - 20L)
&& Keyboard.getEventKeyState()
&& keyCode == mc.gameSettings.keyBindScreenshot.getKeyCode()) {
ReplayMod.instance.runLater(() -> {
new GuiCreateScreenshot(mod).display();
});
event.setCanceled(true);
}
}
}

View File

@@ -0,0 +1,94 @@
package com.replaymod.extras.advancedscreenshots;
import com.replaymod.core.ReplayMod;
import com.replaymod.render.RenderSettings;
import com.replaymod.render.gui.GuiRenderSettings;
import com.replaymod.replay.ReplayModReplay;
import de.johni0702.minecraft.gui.container.GuiContainer;
import de.johni0702.minecraft.gui.container.GuiPanel;
import de.johni0702.minecraft.gui.element.GuiLabel;
import de.johni0702.minecraft.gui.function.Loadable;
import de.johni0702.minecraft.gui.layout.GridLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout;
import net.minecraft.crash.CrashReport;
import net.minecraft.util.ScreenShotHelper;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
import java.io.File;
import java.util.ArrayList;
import static com.replaymod.core.utils.Utils.error;
import static com.replaymod.render.ReplayModRender.LOGGER;
public class GuiCreateScreenshot extends GuiRenderSettings implements Loadable {
private final ReplayMod mod;
public GuiCreateScreenshot(ReplayMod mod) {
super(null, null);
this.mod = mod;
resetChildren(settingsList.getListPanel()).addElements(new VerticalLayout.Data(0.5),
new GuiLabel().setI18nText("replaymod.gui.advancedscreenshots.title"), mainPanel, new GuiPanel(),
new GuiLabel().setI18nText("replaymod.gui.rendersettings.advanced"), advancedPanel, new GuiPanel());
resetChildren(mainPanel).addElements(new GridLayout.Data(1, 0.5),
new GuiLabel().setI18nText("replaymod.gui.rendersettings.renderer"), renderMethodDropdown,
new GuiLabel().setI18nText("replaymod.gui.advancedscreenshots.resolution"), videoResolutionPanel,
new GuiLabel().setI18nText("replaymod.gui.rendersettings.outputfile"), outputFileButton);
resetChildren(advancedPanel).addElements(null, nametagCheckbox, new GuiPanel().setLayout(
new GridLayout().setCellsEqualSize(false).setColumns(2).setSpacingX(5).setSpacingY(15))
.addElements(new GridLayout.Data(0, 0.5),
new GuiLabel().setI18nText("replaymod.gui.rendersettings.stabilizecamera"), stabilizePanel,
chromaKeyingCheckbox, chromaKeyingColor));
exportArguments.setText(""); // To disable any preset-based checks
buttonPanel.removeElement(queueButton);
renderButton.setI18nLabel("replaymod.gui.advancedscreenshots.create").onClick(() -> {
// Closing this GUI ensures that settings are saved
getMinecraft().displayGuiScreen(null);
mod.runLater(() -> {
try {
RenderSettings settings = save(false);
boolean success = new ScreenshotRenderer(settings).renderScreenshot();
if (success) {
new GuiUploadScreenshot(ReplayModReplay.instance.getReplayHandler().getOverlay(), mod,
settings).open();
}
} catch (Throwable t) {
error(LOGGER, GuiCreateScreenshot.this, CrashReport.makeCrashReport(t, "Rendering video"), () -> {});
display(); // Re-show the render settings gui and the new error popup
}
});
});
}
private <T extends GuiContainer<?>> T resetChildren(T container) {
new ArrayList<>(container.getChildren()).forEach(container::removeElement);
return container;
}
@Override
public void load() {
// pause replay when opening this gui
ReplayModReplay.instance.getReplayHandler().getReplaySender().setReplaySpeed(0);
}
@Override
protected File generateOutputFile(RenderSettings.EncodingPreset encodingPreset) {
File screenshotFolder = new File(getMinecraft().mcDataDir, "screenshots");
return ScreenShotHelper.getTimestampedPNGFileForDirectory(screenshotFolder);
}
@Override
protected Property getConfigProperty(Configuration configuration) {
return configuration.get("screenshotsettings", "settings", "{}",
"Last state of the screenshot settings GUI. Internal use only.");
}
}

View File

@@ -0,0 +1,128 @@
package com.replaymod.extras.advancedscreenshots;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.SettingsRegistry;
import com.replaymod.extras.Setting;
import com.replaymod.render.RenderSettings;
import de.johni0702.minecraft.gui.container.GuiContainer;
import de.johni0702.minecraft.gui.container.GuiPanel;
import de.johni0702.minecraft.gui.element.GuiButton;
import de.johni0702.minecraft.gui.element.GuiCheckbox;
import de.johni0702.minecraft.gui.element.GuiLabel;
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.popup.AbstractGuiPopup;
import org.lwjgl.util.ReadableColor;
import java.awt.*;
import java.io.IOException;
import java.net.URI;
public class GuiUploadScreenshot extends AbstractGuiPopup<GuiUploadScreenshot> {
public final ReplayMod mod;
public final RenderSettings renderSettings;
public final GuiLabel successLabel = new GuiLabel()
.setI18nText("replaymod.gui.advancedscreenshots.finished.description")
.setColor(ReadableColor.BLACK);
public final GuiLabel veerLabel = new GuiLabel()
.setI18nText("replaymod.gui.advancedscreenshots.finished.description.veer")
.setColor(ReadableColor.BLACK);
public final GuiButton veerUploadButton = new GuiButton()
.setSize(150, 20)
.setI18nLabel("replaymod.gui.advancedscreenshots.finished.upload.veer");
public final GuiButton showOnDiskButton = new GuiButton()
.setSize(150, 20)
.setI18nLabel("replaymod.gui.advancedscreenshots.finished.showfile");
public final GuiButton closeButton = new GuiButton()
.setSize(150, 20)
.setI18nLabel("replaymod.gui.close");
public final GuiCheckbox neverOpenCheckbox = new GuiCheckbox();
public final GuiLabel neverOpenLabel = new GuiLabel()
.setI18nText("replaymod.gui.notagain")
.setColor(ReadableColor.BLACK);
public final GuiPanel checkboxPanel = GuiPanel.builder()
.layout(new HorizontalLayout(HorizontalLayout.Alignment.RIGHT).setSpacing(5))
.with(neverOpenCheckbox, new HorizontalLayout.Data(0.5))
.with(neverOpenLabel, new HorizontalLayout.Data(0.5))
.build();
public GuiUploadScreenshot(GuiContainer container, ReplayMod mod, RenderSettings renderSettings) {
super(container);
this.mod = mod;
this.renderSettings = renderSettings;
boolean veer = renderSettings.getRenderMethod() == RenderSettings.RenderMethod.EQUIRECTANGULAR;
if (renderSettings.getRenderMethod() == RenderSettings.RenderMethod.EQUIRECTANGULAR) {
successLabel.setI18nText("replaymod.gui.advancedscreenshots.finished.description.360");
}
if (veer) {
veerUploadButton.onClick(() -> {
try {
Desktop.getDesktop().browse(URI.create("https://veer.tv/upload"));
} catch (IOException e) {
e.printStackTrace();
}
});
}
showOnDiskButton.onClick(() -> {
try {
Desktop.getDesktop().browse(renderSettings.getOutputFile().toURI());
} catch (IOException e) {
e.printStackTrace();
}
});
closeButton.onClick(() -> {
if (neverOpenCheckbox.isChecked()) {
SettingsRegistry settingsRegistry = mod.getSettingsRegistry();
settingsRegistry.set(Setting.SKIP_POST_SCREENSHOT_GUI, true);
settingsRegistry.save();
}
close();
});
popup.addElements(new VerticalLayout.Data(0.5), successLabel);
if (veer) {
popup.addElements(new VerticalLayout.Data(0.5),
veerLabel,
veerUploadButton);
}
popup.addElements(new VerticalLayout.Data(0.5),
successLabel,
showOnDiskButton,
closeButton);
popup.addElements(new VerticalLayout.Data(1),
checkboxPanel);
popup.setLayout(new VerticalLayout().setSpacing(5));
}
@Override
protected void open() {
if (mod.getSettingsRegistry().get(Setting.SKIP_POST_SCREENSHOT_GUI)) {
return;
}
super.open();
}
@Override
protected GuiUploadScreenshot getThis() {
return this;
}
}

View File

@@ -0,0 +1,66 @@
package com.replaymod.extras.advancedscreenshots;
import com.replaymod.render.RenderSettings;
import com.replaymod.render.capturer.RenderInfo;
import com.replaymod.render.hooks.ChunkLoadingRenderGlobal;
import com.replaymod.render.rendering.Pipelines;
import lombok.RequiredArgsConstructor;
import net.minecraft.client.Minecraft;
import net.minecraft.crash.CrashReport;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
@RequiredArgsConstructor
public class ScreenshotRenderer implements RenderInfo {
private final Minecraft mc = Minecraft.getMinecraft();
private final RenderSettings settings;
public boolean renderScreenshot() throws Throwable {
try {
int displayWidthBefore = mc.displayWidth;
int displayHeightBefore = mc.displayHeight;
boolean hideGUIBefore = mc.gameSettings.hideGUI;
mc.gameSettings.hideGUI = true;
ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.renderGlobal);
Pipelines.newPipeline(settings.getRenderMethod(),this,
new ScreenshotWriter(settings.getOutputFile())).run();
clrg.uninstall();
mc.gameSettings.hideGUI = hideGUIBefore;
mc.resize(displayWidthBefore, displayHeightBefore);
return true;
} catch (OutOfMemoryError e) {
e.printStackTrace();
CrashReport report = CrashReport.makeCrashReport(e, "Creating Equirectangular Screenshot");
Minecraft.getMinecraft().crashed(report);
}
return false;
}
@Override
public ReadableDimension getFrameSize() {
return new Dimension(settings.getVideoWidth(), settings.getVideoHeight());
}
@Override
public int getTotalFrames() {
// render 2 frames, because only the second contains all frames fully loaded
return 2;
}
@Override
public float updateForNextFrame() {
return mc.timer.renderPartialTicks;
}
@Override
public RenderSettings getRenderSettings() {
return settings;
}
}

View File

@@ -0,0 +1,65 @@
package com.replaymod.extras.advancedscreenshots;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.utils.Utils;
import com.replaymod.extras.ReplayModExtras;
import com.replaymod.render.frame.RGBFrame;
import com.replaymod.render.rendering.FrameConsumer;
import com.replaymod.replay.ReplayModReplay;
import net.minecraft.client.Minecraft;
import net.minecraft.crash.CrashReport;
import org.lwjgl.util.ReadableDimension;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class ScreenshotWriter implements FrameConsumer<RGBFrame> {
private final File outputFile;
public ScreenshotWriter(File outputFile) {
this.outputFile = outputFile;
}
@Override
public void consume(RGBFrame frame) {
// skip the first frame, in which not all chunks are properly loaded
if (frame.getFrameId() == 0) return;
try {
final ReadableDimension frameSize = frame.getSize();
BufferedImage img = new BufferedImage(frameSize.getWidth(), frameSize.getHeight(), BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < frameSize.getHeight(); y++) {
for (int x = 0; x < frameSize.getWidth(); x++) {
byte r = frame.getByteBuffer().get();
byte g = frame.getByteBuffer().get();
byte b = frame.getByteBuffer().get();
int color = ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff);
img.setRGB(x, y, color);
}
}
outputFile.getParentFile().mkdirs();
ImageIO.write(img, "PNG", outputFile);
} catch (OutOfMemoryError e) {
e.printStackTrace();
CrashReport report = CrashReport.makeCrashReport(e, "Exporting frame");
Minecraft.getMinecraft().crashed(report);
} catch (Throwable t) {
CrashReport report = CrashReport.makeCrashReport(t, "Exporting frame");
ReplayMod.instance.runLater(() -> Utils.error(ReplayModExtras.LOGGER,
ReplayModReplay.instance.getReplayHandler().getOverlay(),
report, null));
}
}
@Override
public void close() throws IOException {
}
}

View File

@@ -30,6 +30,7 @@ import static net.minecraft.client.Minecraft.getMinecraft;
version = "@MOD_VERSION@", version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*", acceptableRemoteVersions = "*",
clientSideOnly = true,
useMetadata = true) useMetadata = true)
public class ReplayModOnline { public class ReplayModOnline {
public static final String MOD_ID = "replaymod-online"; public static final String MOD_ID = "replaymod-online";

View File

@@ -110,7 +110,7 @@ public class GuiRegister extends AbstractGuiScreen<GuiRegister> {
@Override @Override
public void run() { public void run() {
String status = null; String status = null;
if (usernameInput.getText().length() < 5) { if (usernameInput.getText().length() < 1) {
status = "replaymod.gui.register.error.shortusername"; status = "replaymod.gui.register.error.shortusername";
} else if(!Patterns.ALPHANUMERIC_UNDERSCORE.matcher(usernameInput.getText().trim()).matches()) { } else if(!Patterns.ALPHANUMERIC_UNDERSCORE.matcher(usernameInput.getText().trim()).matches()) {
status = "replaymod.gui.register.error.invalidname"; status = "replaymod.gui.register.error.invalidname";

View File

@@ -3,6 +3,7 @@ package com.replaymod.recording;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
import com.replaymod.core.utils.Restrictions; import com.replaymod.core.utils.Restrictions;
import com.replaymod.recording.handler.ConnectionEventHandler; import com.replaymod.recording.handler.ConnectionEventHandler;
import com.replaymod.recording.handler.GuiHandler;
import com.replaymod.recording.packet.PacketListener; import com.replaymod.recording.packet.PacketListener;
import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler;
@@ -20,6 +21,7 @@ import org.lwjgl.input.Keyboard;
version = "@MOD_VERSION@", version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*", acceptableRemoteVersions = "*",
clientSideOnly = true,
useMetadata = true) useMetadata = true)
public class ReplayModRecording { public class ReplayModRecording {
public static final String MOD_ID = "replaymod-recording"; public static final String MOD_ID = "replaymod-recording";
@@ -57,6 +59,8 @@ public class ReplayModRecording {
EventBus bus = MinecraftForge.EVENT_BUS; EventBus bus = MinecraftForge.EVENT_BUS;
bus.register(connectionEventHandler = new ConnectionEventHandler(logger, core)); bus.register(connectionEventHandler = new ConnectionEventHandler(logger, core));
new GuiHandler(core).register();
NetworkRegistry.INSTANCE.newChannel(Restrictions.PLUGIN_CHANNEL, new RestrictionsChannelHandler()); NetworkRegistry.INSTANCE.newChannel(Restrictions.PLUGIN_CHANNEL, new RestrictionsChannelHandler());
} }

View File

@@ -0,0 +1,52 @@
package com.replaymod.recording.handler;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.SettingsRegistry;
import com.replaymod.recording.Setting;
import de.johni0702.minecraft.gui.container.GuiScreen;
import de.johni0702.minecraft.gui.container.VanillaGuiScreen;
import de.johni0702.minecraft.gui.element.GuiCheckbox;
import de.johni0702.minecraft.gui.layout.CustomLayout;
import net.minecraft.client.gui.GuiMultiplayer;
import net.minecraft.client.gui.GuiWorldSelection;
import net.minecraftforge.client.event.GuiScreenEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
public class GuiHandler {
private final ReplayMod mod;
public GuiHandler(ReplayMod mod) {
this.mod = mod;
}
public void register() {
MinecraftForge.EVENT_BUS.register(this);
}
@SubscribeEvent
public void onGuiInit(GuiScreenEvent.InitGuiEvent.Post event) {
if (event.getGui() instanceof GuiWorldSelection || event.getGui() instanceof GuiMultiplayer) {
SettingsRegistry settingsRegistry = mod.getSettingsRegistry();
boolean sp = event.getGui() instanceof GuiWorldSelection;
Setting<Boolean> setting = sp ? Setting.RECORD_SINGLEPLAYER : Setting.RECORD_SERVER;
GuiCheckbox recordingCheckbox = new GuiCheckbox()
.setI18nLabel("replaymod.gui.settings.record" + (sp ? "singleplayer" : "server"))
.setChecked(settingsRegistry.get(setting));
recordingCheckbox.onClick(() -> {
settingsRegistry.set(setting, recordingCheckbox.isChecked());
settingsRegistry.save();
});
VanillaGuiScreen.setup(event.getGui()).setLayout(new CustomLayout<GuiScreen>() {
@Override
protected void layout(GuiScreen container, int width, int height) {
//size(recordingCheckbox, 200, 20);
pos(recordingCheckbox, width - width(recordingCheckbox) - 5, 5);
}
}).addElements(null, recordingCheckbox);
}
}
}

View File

@@ -22,6 +22,7 @@ import java.util.List;
version = "@MOD_VERSION@", version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*", acceptableRemoteVersions = "*",
clientSideOnly = true,
useMetadata = true) useMetadata = true)
public class ReplayModRender { public class ReplayModRender {
public static final String MOD_ID = "replaymod-render"; public static final String MOD_ID = "replaymod-render";

View File

@@ -427,7 +427,7 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
); );
} }
private File generateOutputFile(RenderSettings.EncodingPreset encodingPreset) { protected File generateOutputFile(RenderSettings.EncodingPreset encodingPreset) {
String fileName = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss").format(new Date()); String fileName = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss").format(new Date());
File folder = ReplayModRender.instance.getVideoFolder(); File folder = ReplayModRender.instance.getVideoFolder();
return new File(folder, fileName + "." + encodingPreset.getFileExtension()); return new File(folder, fileName + "." + encodingPreset.getFileExtension());
@@ -447,7 +447,7 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
config.save(); config.save();
} }
private Property getConfigProperty(Configuration configuration) { protected Property getConfigProperty(Configuration configuration) {
return configuration.get("rendersettings", "settings", "{}", return configuration.get("rendersettings", "settings", "{}",
"Last state of the render settings GUI. Internal use only."); "Last state of the render settings GUI. Internal use only.");
} }

View File

@@ -34,7 +34,6 @@ public abstract class MixinRenderGlobal {
do { do {
setupTerrain(viewEntity, partialTicks, camera, replayModRender_hook.nextFrameId(), playerSpectator); setupTerrain(viewEntity, partialTicks, camera, replayModRender_hook.nextFrameId(), playerSpectator);
replayModRender_hook.updateChunks(); replayModRender_hook.updateChunks();
} while (displayListEntitiesDirty); } while (displayListEntitiesDirty);

View File

@@ -3,6 +3,7 @@ package com.replaymod.replay;
import com.replaymod.core.utils.WrappedTimer; import com.replaymod.core.utils.WrappedTimer;
import com.replaymod.replay.camera.CameraController; import com.replaymod.replay.camera.CameraController;
import com.replaymod.replay.camera.CameraEntity; import com.replaymod.replay.camera.CameraEntity;
import com.replaymod.replay.events.ReplayDispatchKeypressesEvent;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.settings.GameSettings; import net.minecraft.client.settings.GameSettings;
@@ -11,6 +12,7 @@ import net.minecraft.crash.CrashReport;
import net.minecraft.util.ReportedException; import net.minecraft.util.ReportedException;
import net.minecraft.util.Timer; import net.minecraft.util.Timer;
import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.FMLCommonHandler;
import org.lwjgl.input.Keyboard; import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse; import org.lwjgl.input.Mouse;
@@ -122,7 +124,9 @@ public class InputReplayTimer extends WrappedTimer {
} }
// Twitch, screenshot, fullscreen, etc. (stuff that works everywhere) // Twitch, screenshot, fullscreen, etc. (stuff that works everywhere)
mc.dispatchKeypresses(); if (!MinecraftForge.EVENT_BUS.post(new ReplayDispatchKeypressesEvent.Pre())) {
mc.dispatchKeypresses();
}
if (pressed) { if (pressed) {
// This might be subject to change as vanilla shaders are still kinda unused in 1.8 // This might be subject to change as vanilla shaders are still kinda unused in 1.8

View File

@@ -36,6 +36,7 @@ import java.util.Optional;
version = "@MOD_VERSION@", version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*", acceptableRemoteVersions = "*",
clientSideOnly = true,
useMetadata = true) useMetadata = true)
public class ReplayModReplay { public class ReplayModReplay {
public static final String MOD_ID = "replaymod-replay"; public static final String MOD_ID = "replaymod-replay";
@@ -194,6 +195,10 @@ public class ReplayModReplay {
replayHandler = new ReplayHandler(replayFile, true); replayHandler = new ReplayHandler(replayFile, true);
} }
public void forcefullyStopReplay() {
replayHandler = null;
}
public ReplayMod getCore() { public ReplayMod getCore() {
return core; return core;
} }

View File

@@ -6,8 +6,12 @@ import com.replaymod.core.ReplayMod;
import com.replaymod.core.utils.Restrictions; import com.replaymod.core.utils.Restrictions;
import com.replaymod.core.utils.WrappedTimer; import com.replaymod.core.utils.WrappedTimer;
import com.replaymod.replay.camera.CameraEntity; import com.replaymod.replay.camera.CameraEntity;
import com.replaymod.replaystudio.io.ReplayInputStream;
import com.replaymod.replaystudio.io.ReplayOutputStream;
import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.studio.ReplayStudio;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandler.Sharable;
@@ -109,10 +113,10 @@ public class ReplaySender extends ChannelDuplexHandler {
protected ChannelHandlerContext ctx; protected ChannelHandlerContext ctx;
/** /**
* The data input stream from which new packets are read. * The replay input stream from which new packets are read.
* When accessing this stream make sure to synchronize on {@code this} as it's used from multiple threads. * When accessing this stream make sure to synchronize on {@code this} as it's used from multiple threads.
*/ */
protected DataInputStream dis; protected ReplayInputStream replayIn;
/** /**
* The next packet that should be sent. * The next packet that should be sent.
@@ -595,8 +599,8 @@ public class ReplaySender extends ChannelDuplexHandler {
REPLAY_LOOP: REPLAY_LOOP:
while (!terminate) { while (!terminate) {
synchronized (ReplaySender.this) { synchronized (ReplaySender.this) {
if (dis == null) { if (replayIn == null) {
dis = new DataInputStream(replayFile.getPacketData()); replayIn = replayFile.getPacketData();
} }
// Packet loop // Packet loop
while (true) { while (true) {
@@ -623,7 +627,7 @@ public class ReplaySender extends ChannelDuplexHandler {
// Read the next packet if we don't already have one // Read the next packet if we don't already have one
if (nextPacket == null) { if (nextPacket == null) {
nextPacket = new PacketData(dis); nextPacket = new PacketData(replayIn);
} }
int nextTimeStamp = nextPacket.timestamp; int nextTimeStamp = nextPacket.timestamp;
@@ -680,9 +684,9 @@ public class ReplaySender extends ChannelDuplexHandler {
nextPacket = null; nextPacket = null;
lastPacketSent = System.currentTimeMillis(); lastPacketSent = System.currentTimeMillis();
replayHandler.restartedReplay(); replayHandler.restartedReplay();
if (dis != null) { if (replayIn != null) {
dis.close(); replayIn.close();
dis = null; replayIn = null;
} }
} }
} }
@@ -771,17 +775,17 @@ public class ReplaySender extends ChannelDuplexHandler {
if (timestamp < lastTimeStamp) { // Restart the replay if we need to go backwards in time if (timestamp < lastTimeStamp) { // Restart the replay if we need to go backwards in time
hasWorldLoaded = false; hasWorldLoaded = false;
lastTimeStamp = 0; lastTimeStamp = 0;
if (dis != null) { if (replayIn != null) {
dis.close(); replayIn.close();
dis = null; replayIn = null;
} }
startFromBeginning = false; startFromBeginning = false;
nextPacket = null; nextPacket = null;
replayHandler.restartedReplay(); replayHandler.restartedReplay();
} }
if (dis == null) { if (replayIn == null) {
dis = new DataInputStream(replayFile.getPacketData()); replayIn = replayFile.getPacketData();
} }
while (true) { // Send packets while (true) { // Send packets
@@ -793,7 +797,7 @@ public class ReplaySender extends ChannelDuplexHandler {
nextPacket = null; nextPacket = null;
} else { } else {
// Otherwise read one from the input stream // Otherwise read one from the input stream
pd = new PacketData(dis); pd = new PacketData(replayIn);
} }
int nextTimeStamp = pd.timestamp; int nextTimeStamp = pd.timestamp;
@@ -808,7 +812,7 @@ public class ReplaySender extends ChannelDuplexHandler {
} catch (EOFException eof) { } catch (EOFException eof) {
// Shit! We hit the end before finishing our job! What shall we do now? // Shit! We hit the end before finishing our job! What shall we do now?
// well, let's just pretend we're done... // well, let's just pretend we're done...
dis = null; replayIn = null;
break; break;
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@@ -873,13 +877,32 @@ public class ReplaySender extends ChannelDuplexHandler {
} }
private static final class PacketData { private static final class PacketData {
private static final ByteBuf byteBuf = Unpooled.buffer();
private static final ByteBufOutputStream byteBufOut = new ByteBufOutputStream(byteBuf);
private static final ReplayOutputStream encoder = new ReplayOutputStream(new ReplayStudio(), byteBufOut);
private final int timestamp; private final int timestamp;
private final byte[] bytes; private final byte[] bytes;
public PacketData(DataInputStream in) throws IOException { public PacketData(ReplayInputStream in) throws IOException {
timestamp = in.readInt(); com.replaymod.replaystudio.PacketData data = in.readPacket();
bytes = new byte[in.readInt()]; timestamp = (int) data.getTime();
in.readFully(bytes); // We need to re-encode MCProtocolLib packets, so we can later decode them as NMS packets
// The main reason we aren't reading them as NMS packets is that we want ReplayStudio to be able
// to apply ViaVersion (and potentially other magic) to it.
synchronized (encoder) {
byteBuf.markReaderIndex(); // Mark the current reader and writer index (should be at start)
byteBuf.markWriterIndex();
encoder.write(data); // Re-encode packet, data will end up in byteBuf
encoder.flush();
byteBuf.skipBytes(8); // Skip packet length & timestamp
bytes = new byte[byteBuf.readableBytes()]; // Create bytes array of sufficient size
byteBuf.readBytes(bytes); // Read all data into bytes
byteBuf.resetReaderIndex(); // Reset reader & writer index for next use
byteBuf.resetWriterIndex();
}
} }
} }
} }

View File

@@ -4,6 +4,7 @@ import com.replaymod.core.SettingsRegistry;
public final class Setting<T> extends SettingsRegistry.SettingKeys<T> { public final class Setting<T> extends SettingsRegistry.SettingKeys<T> {
public static final Setting<Boolean> SHOW_CHAT = make("showChat", "showchat", true); public static final Setting<Boolean> SHOW_CHAT = make("showChat", "showchat", true);
public static final Setting<Boolean> SHOW_SERVER_IPS = new Setting<>("showServerIPs", true);
public static final SettingsRegistry.MultipleChoiceSettingKeys<String> CAMERA = public static final SettingsRegistry.MultipleChoiceSettingKeys<String> CAMERA =
new SettingsRegistry.MultipleChoiceSettingKeys<>( new SettingsRegistry.MultipleChoiceSettingKeys<>(
"replay", "camera", "replaymod.gui.settings.camera", "replaymod.camera.classic"); "replay", "camera", "replaymod.gui.settings.camera", "replaymod.camera.classic");
@@ -15,4 +16,8 @@ public final class Setting<T> extends SettingsRegistry.SettingKeys<T> {
public Setting(String key, String displayString, T defaultValue) { public Setting(String key, String displayString, T defaultValue) {
super("replay", key, "replaymod.gui.settings." + displayString, defaultValue); super("replay", key, "replaymod.gui.settings." + displayString, defaultValue);
} }
public Setting(String key, T defaultValue) {
super("replay", key, null, defaultValue);
}
} }

View File

@@ -0,0 +1,10 @@
package com.replaymod.replay.events;
import net.minecraftforge.fml.common.eventhandler.Cancelable;
import net.minecraftforge.fml.common.eventhandler.Event;
public abstract class ReplayDispatchKeypressesEvent extends Event {
@Cancelable
public static class Pre extends ReplayDispatchKeypressesEvent {}
}

View File

@@ -5,9 +5,12 @@ import com.google.common.base.Supplier;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.mojang.realmsclient.gui.ChatFormatting; import com.mojang.realmsclient.gui.ChatFormatting;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.SettingsRegistry;
import com.replaymod.core.gui.GuiReplaySettings; import com.replaymod.core.gui.GuiReplaySettings;
import com.replaymod.core.utils.Utils; import com.replaymod.core.utils.Utils;
import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.ReplayModReplay;
import com.replaymod.replay.Setting;
import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ReplayMetaData; import com.replaymod.replaystudio.replay.ReplayMetaData;
import com.replaymod.replaystudio.replay.ZipReplayFile; import com.replaymod.replaystudio.replay.ZipReplayFile;
@@ -18,6 +21,7 @@ import de.johni0702.minecraft.gui.container.GuiPanel;
import de.johni0702.minecraft.gui.container.GuiScreen; import de.johni0702.minecraft.gui.container.GuiScreen;
import de.johni0702.minecraft.gui.element.*; import de.johni0702.minecraft.gui.element.*;
import de.johni0702.minecraft.gui.element.advanced.GuiResourceLoadingList; import de.johni0702.minecraft.gui.element.advanced.GuiResourceLoadingList;
import de.johni0702.minecraft.gui.function.Typeable;
import de.johni0702.minecraft.gui.layout.CustomLayout; import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.GridLayout; import de.johni0702.minecraft.gui.layout.GridLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout; import de.johni0702.minecraft.gui.layout.HorizontalLayout;
@@ -34,8 +38,10 @@ import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.util.Strings; import org.apache.logging.log4j.util.Strings;
import org.lwjgl.Sys; import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.util.Dimension; import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension; import org.lwjgl.util.ReadableDimension;
import org.lwjgl.util.ReadablePoint;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@@ -47,7 +53,7 @@ import java.util.Date;
import static com.replaymod.replay.ReplayModReplay.LOGGER; import static com.replaymod.replay.ReplayModReplay.LOGGER;
public class GuiReplayViewer extends GuiScreen { public class GuiReplayViewer extends GuiScreen implements Typeable {
private final ReplayModReplay mod; private final ReplayModReplay mod;
public final GuiResourceLoadingList<GuiReplayEntry> list = new GuiResourceLoadingList<GuiReplayEntry>(this).onSelectionChanged(new Runnable() { public final GuiResourceLoadingList<GuiReplayEntry> list = new GuiResourceLoadingList<GuiReplayEntry>(this).onSelectionChanged(new Runnable() {
@@ -272,6 +278,18 @@ public class GuiReplayViewer extends GuiScreen {
} }
private final GuiImage defaultThumbnail = new GuiImage().setTexture(Utils.DEFAULT_THUMBNAIL); private final GuiImage defaultThumbnail = new GuiImage().setTexture(Utils.DEFAULT_THUMBNAIL);
@Override
public boolean typeKey(ReadablePoint mousePosition, int keyCode, char keyChar, boolean ctrlDown, boolean shiftDown) {
if (keyCode == Keyboard.KEY_F1) {
SettingsRegistry reg = ReplayMod.instance.getSettingsRegistry();
reg.set(Setting.SHOW_SERVER_IPS, !reg.get(Setting.SHOW_SERVER_IPS));
reg.save();
list.load();
}
return false;
}
public class GuiReplayEntry extends AbstractGuiContainer<GuiReplayEntry> implements Comparable<GuiReplayEntry> { public class GuiReplayEntry extends AbstractGuiContainer<GuiReplayEntry> implements Comparable<GuiReplayEntry> {
public final File file; public final File file;
public final GuiLabel name = new GuiLabel(); public final GuiLabel name = new GuiLabel();
@@ -303,7 +321,8 @@ public class GuiReplayViewer extends GuiScreen {
this.file = file; this.file = file;
name.setText(ChatFormatting.UNDERLINE + Utils.fileNameToReplayName(file.getName())); name.setText(ChatFormatting.UNDERLINE + Utils.fileNameToReplayName(file.getName()));
if (Strings.isEmpty(metaData.getServerName())) { if (Strings.isEmpty(metaData.getServerName())
|| !ReplayMod.instance.getSettingsRegistry().get(Setting.SHOW_SERVER_IPS)) {
server.setI18nText("replaymod.gui.iphidden").setColor(Colors.DARK_RED); server.setI18nText("replaymod.gui.iphidden").setColor(Colors.DARK_RED);
} else { } else {
server.setText(metaData.getServerName()); server.setText(metaData.getServerName());

View File

@@ -15,6 +15,8 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static com.replaymod.replay.ReplayModReplay.LOGGER;
public class GuiHandler { public class GuiHandler {
private static final int BUTTON_EXIT_SERVER = 1; private static final int BUTTON_EXIT_SERVER = 1;
private static final int BUTTON_ADVANCEMENTS = 5; private static final int BUTTON_ADVANCEMENTS = 5;
@@ -99,6 +101,20 @@ public class GuiHandler {
return; return;
} }
if (mod.getReplayHandler() != null) {
// Something went terribly wrong and we ended up in the main menu with the replay still active.
// To prevent players from joining live servers and using the CameraEntity, try to stop the replay now.
try {
mod.getReplayHandler().endReplay();
} catch (IOException e) {
LOGGER.error("Trying to stop broken replay: ", e);
} finally {
if (mod.getReplayHandler() != null) {
mod.forcefullyStopReplay();
}
}
}
GuiButton button = new GuiButton(BUTTON_REPLAY_VIEWER, event.getGui().width / 2 - 100, GuiButton button = new GuiButton(BUTTON_REPLAY_VIEWER, event.getGui().width / 2 - 100,
event.getGui().height / 4 + 10 + 3 * 24, I18n.format("replaymod.gui.replayviewer")); event.getGui().height / 4 + 10 + 3 * 24, I18n.format("replaymod.gui.replayviewer"));
button.width = button.width / 2 - 2; button.width = button.width / 2 - 2;

View File

@@ -0,0 +1,95 @@
package com.replaymod.restrictions;
import com.replaymod.core.SettingsRegistry;
import com.replaymod.core.utils.Restrictions;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.EventBus;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
import net.minecraftforge.fml.common.network.FMLEmbeddedChannel;
import net.minecraftforge.fml.common.network.FMLOutboundHandler;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;
import net.minecraftforge.fml.relauncher.Side;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Mod(modid = ReplayModRestrictions.MOD_ID,
version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*",
serverSideOnly = true,
useMetadata = true)
public class ReplayModRestrictions {
public static final String MOD_ID = "replaymod-restrictions";
public static Logger LOGGER;
private final SettingsRegistry settingsRegistry = new SettingsRegistry();
private FMLEmbeddedChannel channel;
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
LOGGER = event.getModLog();
Configuration config = new Configuration(event.getSuggestedConfigurationFile());
config.load();
settingsRegistry.setConfiguration(config);
settingsRegistry.register(Setting.class);
}
@Mod.EventHandler
public void init(FMLInitializationEvent event) {
EventBus bus = FMLCommonHandler.instance().bus();
bus.register(this);
channel = NetworkRegistry.INSTANCE.newChannel(Restrictions.PLUGIN_CHANNEL, new RestrictionsChannelHandler()).get(Side.SERVER);
}
@Mod.EventHandler
public void postInit(FMLPostInitializationEvent event) throws IOException {
settingsRegistry.save(); // Save default values to disk
}
@ChannelHandler.Sharable
private static class RestrictionsChannelHandler extends ChannelDuplexHandler {}
@SubscribeEvent
public void onUserJoin(PlayerEvent.PlayerLoggedInEvent event) {
Map<String, byte[]> restrictions = new HashMap<>();
if (settingsRegistry.get(Setting.NO_XRAY)) restrictions.put("no_xray", new byte[0]);
if (settingsRegistry.get(Setting.NO_NOCLIP)) restrictions.put("no_noclip", new byte[0]);
if (settingsRegistry.get(Setting.ONLY_FIRST_PERSON)) restrictions.put("only_first_person", new byte[0]);
if (settingsRegistry.get(Setting.ONLY_RECORDING_PLAYER)) restrictions.put("only_recording_player", new byte[0]);
if (settingsRegistry.get(Setting.HIDE_COORDINATES)) restrictions.put("hide_coordinates", new byte[0]);
PacketBuffer buf = new PacketBuffer(Unpooled.buffer());
for (Map.Entry<String, byte[]> e : restrictions.entrySet()) {
byte[] bytes = e.getKey().getBytes();
buf.writeByte(bytes.length);
buf.writeBytes(bytes);
buf.writeByte(1);
buf.writeBytes(e.getValue());
}
FMLProxyPacket packet = new FMLProxyPacket(buf, Restrictions.PLUGIN_CHANNEL);
channel.attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.PLAYER);
channel.attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(event.player);
channel.writeAndFlush(packet).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
}
}

View File

@@ -0,0 +1,19 @@
package com.replaymod.restrictions;
import com.replaymod.core.SettingsRegistry;
public final class Setting<T> extends SettingsRegistry.SettingKeys<T> {
public static final Setting<Boolean> NO_XRAY = make("no_xray", false);
public static final Setting<Boolean> NO_NOCLIP = make("no_noclip", false);
public static final Setting<Boolean> ONLY_FIRST_PERSON = make("only_first_person", false);
public static final Setting<Boolean> ONLY_RECORDING_PLAYER = make("only_recording_player", false);
public static final Setting<Boolean> HIDE_COORDINATES = make("hide_coordinates", false);
private static <T> Setting<T> make(String key, T defaultValue) {
return new Setting<>("restrictions", key, defaultValue);
}
public Setting(String category, String key, T defaultValue) {
super(category, key, null, defaultValue);
}
}

View File

@@ -2,8 +2,10 @@ package com.replaymod.simplepathing;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
import com.replaymod.core.events.SettingsChangedEvent; import com.replaymod.core.events.SettingsChangedEvent;
import com.replaymod.replay.ReplayModReplay;
import com.replaymod.replay.events.ReplayCloseEvent; import com.replaymod.replay.events.ReplayCloseEvent;
import com.replaymod.replay.events.ReplayOpenEvent; import com.replaymod.replay.events.ReplayOpenEvent;
import com.replaymod.replay.gui.overlay.GuiReplayOverlay;
import com.replaymod.replaystudio.pathing.path.Keyframe; import com.replaymod.replaystudio.pathing.path.Keyframe;
import com.replaymod.simplepathing.SPTimeline.SPPath; import com.replaymod.simplepathing.SPTimeline.SPPath;
import com.replaymod.simplepathing.gui.GuiPathing; import com.replaymod.simplepathing.gui.GuiPathing;
@@ -20,6 +22,7 @@ import org.lwjgl.input.Keyboard;
version = "@MOD_VERSION@", version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*", acceptableRemoteVersions = "*",
clientSideOnly = true,
useMetadata = true) useMetadata = true)
public class ReplayModSimplePathing { public class ReplayModSimplePathing {
public static final String MOD_ID = "replaymod-simplepathing"; public static final String MOD_ID = "replaymod-simplepathing";
@@ -81,20 +84,34 @@ public class ReplayModSimplePathing {
} }
} }
private GuiReplayOverlay getReplayOverlay() {
return ReplayModReplay.instance.getReplayHandler().getOverlay();
}
private SPTimeline currentTimeline; private SPTimeline currentTimeline;
@Getter
private SPPath selectedPath; private SPPath selectedPath;
@Getter @Getter
private long selectedTime; private long selectedTime;
public SPPath getSelectedPath() {
if (getReplayOverlay().timeline.getSelectedMarker() != null) {
selectedPath = null;
selectedTime = 0;
}
return selectedPath;
}
public boolean isSelected(Keyframe keyframe) { public boolean isSelected(Keyframe keyframe) {
return selectedPath != null && currentTimeline.getKeyframe(selectedPath, selectedTime) == keyframe; return getSelectedPath() != null && currentTimeline.getKeyframe(selectedPath, selectedTime) == keyframe;
} }
public void setSelected(SPPath path, long time) { public void setSelected(SPPath path, long time) {
selectedPath = path; selectedPath = path;
selectedTime = time; selectedTime = time;
if (selectedPath != null) {
getReplayOverlay().timeline.setSelectedMarker(null);
}
} }
public void setCurrentTimeline(SPTimeline newTimeline) { public void setCurrentTimeline(SPTimeline newTimeline) {

View File

@@ -124,5 +124,8 @@ public net.minecraft.entity.EntityLivingBase field_184628_bn # activeItemStackUs
# EntityLivingBase # EntityLivingBase
public net.minecraft.client.particle.Particle * public net.minecraft.client.particle.Particle *
# ScreenShotHelper
public net.minecraft.util.ScreenShotHelper func_74290_a(Ljava/io/File;)Ljava/io/File; # getTimestampedPNGFileForDirectory
# Example # Example
# public net.minecraft.package.ClassName func_some_id(Ljava/lang/Class;IZS)V # methodName # public net.minecraft.package.ClassName func_some_id(Ljava/lang/Class;IZS)V # methodName

View File

@@ -134,6 +134,22 @@
"screenshots": [], "screenshots": [],
"dependencies": [] "dependencies": []
}, },
{
"modid": "replaymod-restrictions",
"name": "Replay Mod - Restrictions",
"description": "Server-side Restrictions Module of the ReplayMod - Restrict what clients can do in replays",
"version": "${version}",
"mcversion": "${mcversion}",
"url": "https://replaymod.com",
"updateUrl": "https://replaymod.com/download",
"authorList": [
"CrushedPixel",
"johni0702"
],
"logoFile": "replaymod_logo.png",
"screenshots": [],
"dependencies": []
},
{ {
"modid": "replaymod-compat", "modid": "replaymod-compat",
"name": "Replay Mod - Compatibility", "name": "Replay Mod - Compatibility",

View File

@@ -1,7 +1,9 @@
{ {
"required": true, "required": true,
"package": "com.replaymod.render.mixin", "package": "com.replaymod.render.mixin",
"mixins": [ "mixins": [],
"server": [],
"client": [
"MixinEntityRenderer", "MixinEntityRenderer",
"MixinFrustum", "MixinFrustum",
"MixinParticleManager", "MixinParticleManager",
@@ -9,8 +11,6 @@
"MixinRenderGlobal", "MixinRenderGlobal",
"MixinRenderManager" "MixinRenderManager"
], ],
"server": [],
"client": [],
"compatibilityLevel": "JAVA_8", "compatibilityLevel": "JAVA_8",
"minVersion": "0.6.11", "minVersion": "0.6.11",
"refmap": "mixins.replaymod.refmap.json" "refmap": "mixins.replaymod.refmap.json"

View File

@@ -1,7 +1,9 @@
{ {
"required": true, "required": true,
"package": "com.replaymod.replay.mixin", "package": "com.replaymod.replay.mixin",
"mixins": [ "mixins": [],
"server": [],
"client": [
"MixinGuiSpectator", "MixinGuiSpectator",
"MixinParticleManager", "MixinParticleManager",
"MixinPlayerControllerMP", "MixinPlayerControllerMP",
@@ -13,8 +15,6 @@
"MixinViewFrustum", "MixinViewFrustum",
"MixinWorldClient" "MixinWorldClient"
], ],
"server": [],
"client": [],
"compatibilityLevel": "JAVA_8", "compatibilityLevel": "JAVA_8",
"minVersion": "0.6.11", "minVersion": "0.6.11",
"refmap": "mixins.replaymod.refmap.json" "refmap": "mixins.replaymod.refmap.json"