From 1283a39ffac670187db20d78f12b9bd6505e1b69 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Thu, 14 Sep 2017 16:06:49 +0200 Subject: [PATCH] Backport to 1.7.10 --- .gitmodules | 4 - ReplayStudio | 1 - build.gradle | 53 +++-- jGui | 2 +- settings.gradle | 1 - .../java/com/replaymod/core/AbstractTask.java | 73 ++++--- .../core/ReplayModIntegrationTest.java | 6 +- .../com/replaymod/extra/DownloadOpenEye.java | 2 +- .../replaymod/recording/CreateSPWorld.java | 17 +- .../java/com/replaymod/replay/LoadReplay.java | 17 +- .../com/replaymod/replay/SpectatePlayer.java | 6 +- .../com/replaymod/compat/ReplayModCompat.java | 10 +- .../DisableBetterSprinting.java | 34 ++-- .../compat/optifine/DisableFastRender.java | 5 +- .../HideInvisibleEntities.java | 6 +- .../compat/shaders/ShaderBeginRender.java | 39 ---- .../compat/shaders/ShaderReflection.java | 53 ----- .../mixin/MixinShaderEntityRenderer.java | 28 --- .../shaders/mixin/MixinShaderRenderChunk.java | 28 --- .../mixin/MixinShaderRenderGlobal.java | 40 ---- .../compat/shaders/mixin/MixinShaders.java | 50 +++++ .../replaymod/core/GLErrorTransformer.java | 94 +++++++++ .../core/GLStateTrackerTransformer.java | 105 ++++++++++ .../replaymod/core/KeyBindingRegistry.java | 10 +- .../com/replaymod/core/LoadingPlugin.java | 15 +- .../java/com/replaymod/core/ReplayMod.java | 87 +++++--- .../com/replaymod/core/SettingsRegistry.java | 2 +- .../core/events/SettingsChangedEvent.java | 2 +- .../com/replaymod/core/gui/GuiFactory.java | 2 +- .../core/handler/MainMenuHandler.java | 2 +- .../com/replaymod/core/utils/ModCompat.java | 18 +- .../com/replaymod/core/utils/OpenGLUtils.java | 23 +-- .../replaymod/core/utils/Restrictions.java | 7 +- .../java/com/replaymod/core/utils/Utils.java | 16 +- .../com/replaymod/editor/ReplayModEditor.java | 6 +- .../replaymod/editor/handler/GuiHandler.java | 4 +- .../com/replaymod/extras/FullBrightness.java | 6 +- .../com/replaymod/extras/HotkeyButtons.java | 4 +- .../com/replaymod/extras/OpenEyeExtra.java | 2 +- .../com/replaymod/extras/ReplayModExtras.java | 6 +- .../extras/playeroverview/PlayerOverview.java | 33 ++-- .../playeroverview/PlayerOverviewGui.java | 13 +- ...ixinRender.java => MixinRenderPlayer.java} | 37 ++-- .../extras/youtube/YoutubeUpload.java | 2 +- .../com/replaymod/online/ReplayModOnline.java | 12 +- .../replaymod/online/handler/GuiHandler.java | 4 +- .../player/AbstractTimelinePlayer.java | 4 +- .../player/RealtimeTimelinePlayer.java | 2 + .../replaymod/pathing/player/ReplayTimer.java | 4 +- .../pathing/properties/SpectatorProperty.java | 5 +- .../recording/ReplayModRecording.java | 12 +- .../recording/gui/GuiRecordingOverlay.java | 7 +- .../handler/ConnectionEventHandler.java | 13 +- .../recording/handler/FMLHandshakeFilter.java | 4 +- .../handler/RecordingEventHandler.java | 174 ++++------------ .../mixin/MixinNetHandlerLoginClient.java | 8 +- .../mixin/MixinNetHandlerPlayClient.java | 33 +--- .../mixin/MixinNetworkDispatcher.java | 6 +- .../recording/mixin/MixinRenderGlobal.java | 7 +- .../recording/packet/PacketListener.java | 25 ++- .../packet/ResourcePackRecorder.java | 185 ++++++------------ .../com/replaymod/render/ReplayModRender.java | 8 +- .../com/replaymod/render/VideoWriter.java | 2 +- .../render/capturer/ODSFrameCapturer.java | 56 +++--- .../render/capturer/OpenGlFrameCapturer.java | 10 +- .../replaymod/render/capturer/RenderInfo.java | 2 + .../render/events/ReplayRenderEvent.java | 2 +- .../hooks/ChunkLoadingRenderGlobal.java | 105 ---------- .../render/hooks/EntityRendererHandler.java | 19 +- .../render/hooks/GLStateTracker.java | 63 ++++++ .../render/mixin/MixinEffectRenderer.java | 21 +- .../render/mixin/MixinEntityRenderer.java | 67 ++++--- .../replaymod/render/mixin/MixinFrustum.java | 4 +- .../render/mixin/MixinOpenGlHelper.java | 16 ++ .../replaymod/render/mixin/MixinRender.java | 8 +- .../render/mixin/MixinRenderGlobal.java | 63 ------ .../replaymod/render/rendering/Pipelines.java | 18 +- .../render/rendering/VideoRenderer.java | 40 ++-- .../replaymod/replay/InputReplayTimer.java | 42 ++-- .../com/replaymod/replay/NoGuiScreenshot.java | 14 +- .../com/replaymod/replay/ReplayHandler.java | 67 ++++--- .../com/replaymod/replay/ReplayModReplay.java | 8 +- .../com/replaymod/replay/ReplaySender.java | 184 +++++++---------- .../replaymod/replay/camera/CameraEntity.java | 91 ++++----- .../camera/ClassicCameraController.java | 6 +- .../camera/SpectatorCameraController.java | 4 +- .../camera/VanillaCameraController.java | 2 +- .../replay/events/ReplayChatMessageEvent.java | 4 +- .../replay/events/ReplayCloseEvent.java | 2 +- .../replay/events/ReplayOpenEvent.java | 2 +- .../replay/gui/overlay/GuiReplayOverlay.java | 6 +- .../replay/gui/screen/GuiOpeningReplay.java | 17 ++ .../replaymod/replay/handler/GuiHandler.java | 4 +- .../replay/mixin/MixinGuiSpectator.java | 24 --- .../replay/mixin/MixinPlayerControllerMP.java | 24 ++- .../replay/mixin/MixinRenderArrow.java | 22 --- .../replay/mixin/MixinRenderManager.java | 27 --- .../MixinTileEntityEndPortalRenderer.java | 6 +- .../replay/mixin/MixinViewFrustum.java | 70 ------- .../simplepathing/ReplayModSimplePathing.java | 8 +- .../simplepathing/gui/GuiPathing.java | 4 +- .../simplepathing/preview/PathPreview.java | 4 +- .../preview/PathPreviewRenderer.java | 33 ++-- src/main/resources/META-INF/replaymod_at.cfg | 4 +- .../assets/replaymod/shader/ods.frag | 4 - .../mixins.compat.shaders.replaymod.json | 4 +- ...ixins.extras.playeroverview.replaymod.json | 2 +- .../resources/mixins.render.replaymod.json | 2 +- .../resources/mixins.replay.replaymod.json | 4 - 109 files changed, 1170 insertions(+), 1505 deletions(-) delete mode 160000 ReplayStudio delete mode 100644 src/main/java/com/replaymod/compat/shaders/ShaderBeginRender.java delete mode 100644 src/main/java/com/replaymod/compat/shaders/ShaderReflection.java delete mode 100644 src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderEntityRenderer.java delete mode 100644 src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderRenderChunk.java delete mode 100644 src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderRenderGlobal.java create mode 100644 src/main/java/com/replaymod/compat/shaders/mixin/MixinShaders.java create mode 100644 src/main/java/com/replaymod/core/GLErrorTransformer.java create mode 100644 src/main/java/com/replaymod/core/GLStateTrackerTransformer.java rename src/main/java/com/replaymod/extras/playeroverview/mixin/{MixinRender.java => MixinRenderPlayer.java} (50%) delete mode 100644 src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java create mode 100644 src/main/java/com/replaymod/render/hooks/GLStateTracker.java create mode 100644 src/main/java/com/replaymod/render/mixin/MixinOpenGlHelper.java delete mode 100644 src/main/java/com/replaymod/render/mixin/MixinRenderGlobal.java create mode 100644 src/main/java/com/replaymod/replay/gui/screen/GuiOpeningReplay.java delete mode 100644 src/main/java/com/replaymod/replay/mixin/MixinGuiSpectator.java delete mode 100644 src/main/java/com/replaymod/replay/mixin/MixinRenderArrow.java delete mode 100644 src/main/java/com/replaymod/replay/mixin/MixinRenderManager.java delete mode 100644 src/main/java/com/replaymod/replay/mixin/MixinViewFrustum.java diff --git a/.gitmodules b/.gitmodules index ea042fed..0d1b3611 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,10 +2,6 @@ path = jGui url = https://github.com/ReplayMod/jGui -[submodule "ReplayStudio"] - path = ReplayStudio - url = https://github.com/ReplayMod/ReplayStudio - [submodule "src/main/resources/assets/replaymod/lang"] path = src/main/resources/assets/replaymod/lang url = https://github.com/ReplayMod/Translations diff --git a/ReplayStudio b/ReplayStudio deleted file mode 160000 index 44109f11..00000000 --- a/ReplayStudio +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 44109f11b157e29615489e83ee5df742b4fb4305 diff --git a/build.gradle b/build.gradle index 3ff6b6ed..a7e1f689 100755 --- a/build.gradle +++ b/build.gradle @@ -7,23 +7,17 @@ buildscript { name = "forge" url = "http://files.minecraftforge.net/maven" } - maven { - name = "sponge" - url = "https://repo.spongepowered.org/maven" - } maven { name = "sonatype" url = "https://oss.sonatype.org/content/repositories/snapshots/" } } dependencies { - classpath 'net.minecraftforge.gradle:ForgeGradle:2.0-SNAPSHOT' - classpath 'org.spongepowered:mixingradle:0.3-SNAPSHOT' + classpath 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT' } } -apply plugin: 'net.minecraftforge.gradle.forge' -apply plugin: 'org.spongepowered.mixin' +apply plugin: 'forge' sourceCompatibility = 1.8 targetCompatibility = 1.8 @@ -32,11 +26,18 @@ version = gitDescribe() group= "com.replaymod" archivesBaseName = "replaymod" +ext { + mixinConfigs = [ + 'compat.shaders', 'extras.playeroverview', 'recording', 'render', 'replay' + ].collect {"mixins.${it}.replaymod.json"} + mixinSrg = new File(project.buildDir, 'tmp/mixins/mixins.srg') + mixinRefMap = new File(project.buildDir, 'tmp/mixins/mixins.replaymod.refmap.json') +} + minecraft { - coreMod = 'com.replaymod.core.LoadingPlugin' - version = '1.8-11.14.4.1563' + version = '1.7.10-10.13.4.1558-1.7.10' runDir = "eclipse" - mappings = "snapshot_nodoc_20141130" + mappings = "stable_12" replace '@MOD_VERSION@', project.version // Includes intentional whitespace to stop Forge from declaring the mod to be compatible with // a newer srg-compatible MC version (that may be using a different protocol version) @@ -49,7 +50,7 @@ repositories { url = "http://repo.spongepowered.org/maven/" } maven { - url 'https://repo.spacehq.org/content/repositories/snapshots/' + url 'https://jitpack.io' } } @@ -71,24 +72,22 @@ dependencies { shade 'org.aspectj:aspectjrt:1.8.2' - compile project(':ReplayStudio') + shade 'com.github.replaymod:ReplayStudio:181140c' testCompile 'junit:junit:4.11' } -tasks['idea'].dependsOn ':ReplayStudio:preshadowJar' - jar { duplicatesStrategy = DuplicatesStrategy.EXCLUDE dependsOn configurations.compile dependsOn configurations.shade - dependsOn ':ReplayStudio:shadowJar' + + from project.mixinRefMap def shade = {files( configurations.compile.findAll {it.name.startsWith 'mixin-'} + configurations.shade - + getTasks().getByPath(':ReplayStudio:shadowJar').outputs.files )} def noticeDir = file("$buildDir/NOTICE") @@ -117,6 +116,8 @@ jar { manifest { attributes 'TweakClass': 'org.spongepowered.asm.launch.MixinTweaker', 'TweakOrder': '0', + 'MixinConfigs': project.mixinConfigs.join(','), + 'FMLCorePlugin': 'com.replaymod.core.LoadingPlugin', 'FMLAT': 'replaymod_at.cfg' } } @@ -156,6 +157,8 @@ processResources sourceSets { main { + // Required so resources are loaded correctly in dev env + output.resourcesDir = output.classesDir // Directly include jGui into main build // This could also be done by including it as a gradle subproject, however // doing so caused classpath issues on some IntelliJ versions. @@ -165,7 +168,6 @@ sourceSets { resources { srcDir 'jGui/src/main/resources' } - refMap = "mixins.replaymod.refmap.json" } integrationTest { compileClasspath += main.runtimeClasspath + main.output @@ -181,6 +183,21 @@ task copySrg(type: Copy, dependsOn: 'genSrgs') { into 'build' } +reobf.doFirst { + if (project.mixinSrg.exists()) { + addExtraSrgFile project.mixinSrg + } +} + +compileJava.dependsOn copySrg +compileJava { + options.compilerArgs += [ + "-AoutSrgFile=${project.mixinSrg.canonicalPath}", + "-AoutRefMapFile=${project.mixinRefMap.canonicalPath}", + "-AreobfSrgFile=${project.file('build/mcp-srg.srg').canonicalPath}" + ] +} + setupDecompWorkspace.dependsOn copySrg setupDevWorkspace.dependsOn copySrg project.tasks.idea.dependsOn copySrg diff --git a/jGui b/jGui index 9e84e724..042e1c6e 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 9e84e724aaf7de21a06fd534faccdfdc6740fc28 +Subproject commit 042e1c6e5025f85814532f3e653556304f929be1 diff --git a/settings.gradle b/settings.gradle index 28830758..e69de29b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +0,0 @@ -include 'ReplayStudio' \ No newline at end of file diff --git a/src/integration-test/java/com/replaymod/core/AbstractTask.java b/src/integration-test/java/com/replaymod/core/AbstractTask.java index e21d7b52..5fc7ca17 100644 --- a/src/integration-test/java/com/replaymod/core/AbstractTask.java +++ b/src/integration-test/java/com/replaymod/core/AbstractTask.java @@ -3,6 +3,9 @@ package com.replaymod.core; import com.google.common.collect.Iterables; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; import de.johni0702.minecraft.gui.container.AbstractGuiOverlay; import de.johni0702.minecraft.gui.container.AbstractGuiScreen; import de.johni0702.minecraft.gui.container.GuiContainer; @@ -16,9 +19,6 @@ import de.johni0702.minecraft.gui.utils.Consumer; import net.minecraft.client.Minecraft; import net.minecraft.client.settings.KeyBinding; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.TickEvent; import org.lwjgl.input.Keyboard; import java.lang.reflect.Field; @@ -84,10 +84,21 @@ public abstract class AbstractTask implements Task { private void expectGuiClosed0(int timeout, Runnable onClosed) { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - class EventHandler { + FMLCommonHandler.instance().bus().register(new GuiEventHandler(timeout, stackTrace, onClosed)); + } + public class GuiEventHandler { final net.minecraft.client.gui.GuiScreen currentScreen = mc.currentScreen; + private final int timeout; + private final StackTraceElement[] stackTrace; + private final Runnable onClosed; int framesPassed; + public GuiEventHandler(int timeout, StackTraceElement[] stackTrace, Runnable onClosed) { + this.timeout = timeout; + this.stackTrace = stackTrace; + this.onClosed = onClosed; + } + @SubscribeEvent public void onGuiOpen(TickEvent.RenderTickEvent event) { if (event.phase != TickEvent.Phase.START) return; @@ -106,8 +117,6 @@ public abstract class AbstractTask implements Task { } } } - FMLCommonHandler.instance().bus().register(new EventHandler()); - } public void expectPopupClosed(Runnable onClosed) { expectPopupClosed0(10, onClosed); @@ -119,13 +128,25 @@ public abstract class AbstractTask implements Task { private void expectPopupClosed0(int timeout, Runnable onClosed) { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - AbstractGuiPopup popup = getPopup(mc.currentScreen); - if (popup == null) { - throw new IllegalStateException("No popup found."); - } - class EventHandler { + FMLCommonHandler.instance().bus().register(new PopupEventHandler(timeout, stackTrace, onClosed)); + } + public class PopupEventHandler { + private final int timeout; + private final StackTraceElement[] stackTrace; + private final Runnable onClosed; + private final AbstractGuiPopup popup; int framesPassed; + public PopupEventHandler(int timeout, StackTraceElement[] stackTrace, Runnable onClosed) { + this.timeout = timeout; + this.stackTrace = stackTrace; + this.onClosed = onClosed; + this.popup = getPopup(mc.currentScreen); + if (this.popup == null) { + throw new IllegalStateException("No popup found."); + } + } + @SubscribeEvent public void onGuiOpen(TickEvent.RenderTickEvent event) { if (event.phase != TickEvent.Phase.START) return; @@ -143,8 +164,6 @@ public abstract class AbstractTask implements Task { } } } - FMLCommonHandler.instance().bus().register(new EventHandler()); - } private AbstractGuiPopup getPopup(net.minecraft.client.gui.GuiScreen minecraft) { GuiContainer container = GuiOverlay.from(minecraft); @@ -165,10 +184,21 @@ public abstract class AbstractTask implements Task { public void expectGui(Class guiClass, Consumer onOpen) { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - class EventHandler { + FMLCommonHandler.instance().bus().register(new ExpectGuiEventHandler(guiClass, stackTrace, onOpen)); + } + public class ExpectGuiEventHandler { + private final Class guiClass; + private final StackTraceElement[] stackTrace; + private final Consumer onOpen; net.minecraft.client.gui.GuiScreen currentScreen; int framesPassed; + public ExpectGuiEventHandler(Class guiClass, StackTraceElement[] stackTrace, Consumer onOpen) { + this.guiClass = guiClass; + this.stackTrace = stackTrace; + this.onOpen = onOpen; + } + @SubscribeEvent public void onGuiOpen(TickEvent.RenderTickEvent event) { if (event.phase != TickEvent.Phase.START) return; @@ -210,16 +240,15 @@ public abstract class AbstractTask implements Task { return; } } - class UnexpectedGuiException extends Exception { - UnexpectedGuiException(Object foundGui) { - super("Expected instance of " + guiClass + " but found " + foundGui); - setStackTrace(Arrays.copyOfRange(stackTrace, 2, stackTrace.length)); - } - } - future.setException(new UnexpectedGuiException(foundGui == null ? currentScreen : foundGui)); + future.setException(new UnexpectedGuiException(guiClass, stackTrace, + foundGui == null ? currentScreen : foundGui)); } } - FMLCommonHandler.instance().bus().register(new EventHandler()); + class UnexpectedGuiException extends Exception { + UnexpectedGuiException(Class guiClass, StackTraceElement[] stackTrace, Object foundGui) { + super("Expected instance of " + guiClass + " but found " + foundGui); + setStackTrace(Arrays.copyOfRange(stackTrace, 2, stackTrace.length)); + } } private void clickNow(int x, int y) { diff --git a/src/integration-test/java/com/replaymod/core/ReplayModIntegrationTest.java b/src/integration-test/java/com/replaymod/core/ReplayModIntegrationTest.java index 3fc0d00f..d299f729 100644 --- a/src/integration-test/java/com/replaymod/core/ReplayModIntegrationTest.java +++ b/src/integration-test/java/com/replaymod/core/ReplayModIntegrationTest.java @@ -10,10 +10,10 @@ import com.replaymod.recording.ExitSPWorld; import com.replaymod.replay.ExitReplay; import com.replaymod.replay.LoadReplay; import com.replaymod.replay.OpenReplayViewer; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; import net.minecraft.client.Minecraft; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import org.apache.logging.log4j.Logger; import static com.replaymod.core.AbstractTask.mc; diff --git a/src/integration-test/java/com/replaymod/extra/DownloadOpenEye.java b/src/integration-test/java/com/replaymod/extra/DownloadOpenEye.java index 753090c0..f5b8c1e5 100644 --- a/src/integration-test/java/com/replaymod/extra/DownloadOpenEye.java +++ b/src/integration-test/java/com/replaymod/extra/DownloadOpenEye.java @@ -2,7 +2,7 @@ package com.replaymod.extra; import com.replaymod.core.AbstractTask; import com.replaymod.extras.OpenEyeExtra; -import net.minecraftforge.fml.common.Loader; +import cpw.mods.fml.common.Loader; import java.io.File; import java.nio.file.NoSuchFileException; diff --git a/src/integration-test/java/com/replaymod/recording/CreateSPWorld.java b/src/integration-test/java/com/replaymod/recording/CreateSPWorld.java index 95f4cb16..ef27d09a 100644 --- a/src/integration-test/java/com/replaymod/recording/CreateSPWorld.java +++ b/src/integration-test/java/com/replaymod/recording/CreateSPWorld.java @@ -1,12 +1,12 @@ package com.replaymod.recording; import com.replaymod.core.AbstractTask; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import net.minecraft.client.gui.GuiCreateWorld; import net.minecraft.client.gui.GuiMainMenu; import net.minecraft.client.gui.GuiSelectWorld; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; public class CreateSPWorld extends AbstractTask { @Override @@ -17,16 +17,17 @@ public class CreateSPWorld extends AbstractTask { click("Create New World"); expectGui(GuiCreateWorld.class, createWorld -> { click("Create New World"); - class EventHandler { - @SubscribeEvent - public void onRenderIngame(RenderGameOverlayEvent.Pre event) { - MinecraftForge.EVENT_BUS.unregister(this); - runLater(() -> future.set(null)); - } - } MinecraftForge.EVENT_BUS.register(new EventHandler()); }); }); }); } + + public class EventHandler { + @SubscribeEvent + public void onRenderIngame(RenderGameOverlayEvent.Pre event) { + MinecraftForge.EVENT_BUS.unregister(this); + runLater(() -> future.set(null)); + } + } } diff --git a/src/integration-test/java/com/replaymod/replay/LoadReplay.java b/src/integration-test/java/com/replaymod/replay/LoadReplay.java index 2db6383b..615a2c8f 100644 --- a/src/integration-test/java/com/replaymod/replay/LoadReplay.java +++ b/src/integration-test/java/com/replaymod/replay/LoadReplay.java @@ -2,10 +2,10 @@ package com.replaymod.replay; import com.replaymod.core.AbstractTask; import com.replaymod.replay.gui.screen.GuiReplayViewer; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import de.johni0702.minecraft.gui.function.Clickable; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.lwjgl.util.Point; import org.lwjgl.util.ReadableDimension; @@ -19,14 +19,15 @@ public class LoadReplay extends AbstractTask { // Load first replay click(replayViewer.loadButton); - class EventHandler { - @SubscribeEvent - public void onRenderIngame(RenderGameOverlayEvent.Pre event) { - MinecraftForge.EVENT_BUS.unregister(this); - runLater(() -> future.set(null)); - } - } MinecraftForge.EVENT_BUS.register(new EventHandler()); })); } + + public class EventHandler { + @SubscribeEvent + public void onRenderIngame(RenderGameOverlayEvent.Pre event) { + MinecraftForge.EVENT_BUS.unregister(this); + runLater(() -> future.set(null)); + } + } } diff --git a/src/integration-test/java/com/replaymod/replay/SpectatePlayer.java b/src/integration-test/java/com/replaymod/replay/SpectatePlayer.java index e024f347..19fce75a 100644 --- a/src/integration-test/java/com/replaymod/replay/SpectatePlayer.java +++ b/src/integration-test/java/com/replaymod/replay/SpectatePlayer.java @@ -2,8 +2,8 @@ package com.replaymod.replay; import com.replaymod.core.AbstractTask; import com.replaymod.extras.playeroverview.PlayerOverviewGui; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.TickEvent; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; import org.lwjgl.input.Keyboard; import java.util.concurrent.TimeoutException; @@ -34,7 +34,7 @@ public class SpectatePlayer extends AbstractTask { future.setException(new TimeoutException("Camera hasn't stopped spectating.")); return; } - if (mc.getRenderViewEntity() == mc.thePlayer) { + if (mc.renderViewEntity == mc.thePlayer) { future.set(null); } } diff --git a/src/main/java/com/replaymod/compat/ReplayModCompat.java b/src/main/java/com/replaymod/compat/ReplayModCompat.java index 9347cd2f..e40b72db 100644 --- a/src/main/java/com/replaymod/compat/ReplayModCompat.java +++ b/src/main/java/com/replaymod/compat/ReplayModCompat.java @@ -3,11 +3,10 @@ package com.replaymod.compat; import com.replaymod.compat.bettersprinting.DisableBetterSprinting; import com.replaymod.compat.optifine.DisableFastRender; import com.replaymod.compat.oranges17animations.HideInvisibleEntities; -import com.replaymod.compat.shaders.ShaderBeginRender; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.event.FMLInitializationEvent; -import net.minecraftforge.fml.common.eventhandler.EventBus; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.eventhandler.EventBus; @Mod(modid = ReplayModCompat.MOD_ID, version = "@MOD_VERSION@", @@ -20,7 +19,6 @@ public class ReplayModCompat { @Mod.EventHandler public void init(FMLInitializationEvent event) { EventBus bus = FMLCommonHandler.instance().bus(); - bus.register(new ShaderBeginRender()); bus.register(new DisableFastRender()); bus.register(new HideInvisibleEntities()); DisableBetterSprinting.register(); diff --git a/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java b/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java index 57ab557a..865eda53 100644 --- a/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java +++ b/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java @@ -2,21 +2,20 @@ package com.replaymod.compat.bettersprinting; import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.events.ReplayChatMessageEvent; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.ModContainer; +import cpw.mods.fml.common.eventhandler.EventPriority; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.versioning.DefaultArtifactVersion; +import cpw.mods.fml.common.versioning.Restriction; +import cpw.mods.fml.common.versioning.VersionRange; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.PlayerControllerMP; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.util.BlockPos; import net.minecraft.world.IWorldAccess; import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.Loader; -import net.minecraftforge.fml.common.ModContainer; -import net.minecraftforge.fml.common.eventhandler.EventPriority; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion; -import net.minecraftforge.fml.common.versioning.Restriction; -import net.minecraftforge.fml.common.versioning.VersionRange; import java.util.Collections; @@ -74,7 +73,7 @@ public class DisableBetterSprinting { private class BetterSprintingWorldAccess implements IWorldAccess { @Override - public void onEntityRemoved(Entity entityIn) { + public void onEntityDestroy(Entity entityIn) { 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. // This is the right time to destroy their plan. @@ -82,16 +81,17 @@ public class DisableBetterSprinting { } } - @Override public void markBlockForUpdate(BlockPos pos) {} - @Override public void notifyLightSet(BlockPos pos) {} + @Override public void markBlockForUpdate(int x, int y, int z) {} + @Override public void markBlockForRenderUpdate(int p_147588_1_, int p_147588_2_, int p_147588_3_) {} @Override public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) {} @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) {} @Override public void playSoundToNearExcept(EntityPlayer except, String soundName, double x, double y, double z, float volume, float pitch) {} - @Override public void spawnParticle(int p_180442_1_, boolean p_180442_2_, double p_180442_3_, double p_180442_5_, double p_180442_7_, double p_180442_9_, double p_180442_11_, double p_180442_13_, int... p_180442_15_) {} - @Override public void onEntityAdded(Entity entityIn) {} - @Override public void playRecord(String recordName, BlockPos blockPosIn) {} - @Override public void broadcastSound(int p_180440_1_, BlockPos p_180440_2_, int p_180440_3_) {} - @Override public void playAusSFX(EntityPlayer p_180439_1_, int p_180439_2_, BlockPos blockPosIn, int p_180439_4_) {} - @Override public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) {} + @Override public void spawnParticle(String p_180442_1_, double p_180442_2_, double p_180442_3_, double p_180442_5_, double p_180442_7_, double p_180442_9_, double p_180442_11_) {} + @Override public void onEntityCreate(Entity p_72703_1_) {} + @Override public void playRecord(String recordName, int x, int y, int z) {} + @Override public void broadcastSound(int p_180440_1_, int x, int y, int z, int p_180440_3_) {} + @Override public void playAuxSFX(EntityPlayer p_72706_1_, int p_72706_2_, int p_72706_3_, int p_72706_4_, int p_72706_5_, int p_72706_6_) {} + @Override public void destroyBlockPartially(int p_147587_1_, int p_147587_2_, int p_147587_3_, int p_147587_4_, int p_147587_5_) {} + @Override public void onStaticEntitiesChanged() {} } } diff --git a/src/main/java/com/replaymod/compat/optifine/DisableFastRender.java b/src/main/java/com/replaymod/compat/optifine/DisableFastRender.java index 5dec6a94..00ecc5e5 100644 --- a/src/main/java/com/replaymod/compat/optifine/DisableFastRender.java +++ b/src/main/java/com/replaymod/compat/optifine/DisableFastRender.java @@ -1,10 +1,11 @@ package com.replaymod.compat.optifine; import com.replaymod.render.events.ReplayRenderEvent; +import cpw.mods.fml.client.FMLClientHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import net.minecraft.client.Minecraft; -import net.minecraftforge.fml.client.FMLClientHandler; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +// TODO 1.7.10: Is this still necessary (probably, but needs checking)? public class DisableFastRender { private final Minecraft mc = Minecraft.getMinecraft(); diff --git a/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java b/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java index 1600905d..6e27135c 100644 --- a/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java +++ b/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java @@ -1,11 +1,11 @@ package com.replaymod.compat.oranges17animations; import com.replaymod.replay.camera.CameraEntity; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.eventhandler.EventPriority; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import net.minecraft.client.Minecraft; import net.minecraftforge.client.event.RenderLivingEvent; -import net.minecraftforge.fml.common.Loader; -import net.minecraftforge.fml.common.eventhandler.EventPriority; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; /** * Orange seems to have copied vast parts of the RendererLivingEntity into their ArmorAnimation class which cancels the RenderLivingEvent.Pre and calls its own code instead. diff --git a/src/main/java/com/replaymod/compat/shaders/ShaderBeginRender.java b/src/main/java/com/replaymod/compat/shaders/ShaderBeginRender.java deleted file mode 100644 index 8404801b..00000000 --- a/src/main/java/com/replaymod/compat/shaders/ShaderBeginRender.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.replaymod.compat.shaders; - -import com.replaymod.render.hooks.EntityRendererHandler; -import net.minecraft.client.Minecraft; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.TickEvent; - -import java.lang.reflect.InvocationTargetException; - -public class ShaderBeginRender { - - private final Minecraft mc = Minecraft.getMinecraft(); - - /** - * Invokes Shaders#beginRender when rendering a video, - * as this would usually get called by EntityRenderer#renderWorld, - * which we're not calling during rendering. - */ - @SubscribeEvent - public void onRenderTickStart(TickEvent.RenderTickEvent event) { - if (event.phase != TickEvent.Phase.START) return; - if (ShaderReflection.shaders_beginRender == null) return; - if (ShaderReflection.config_isShaders == null) return; - - try { - // check if video is being rendered - if (((EntityRendererHandler.IEntityRenderer) mc.entityRenderer).replayModRender_getHandler() == null) - return; - - // check if Shaders are enabled - if (!(boolean) (ShaderReflection.config_isShaders.invoke(null))) return; - - ShaderReflection.shaders_beginRender.invoke(null, mc, mc.timer.elapsedPartialTicks, 0); - } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } - } - -} diff --git a/src/main/java/com/replaymod/compat/shaders/ShaderReflection.java b/src/main/java/com/replaymod/compat/shaders/ShaderReflection.java deleted file mode 100644 index 63b07ebf..00000000 --- a/src/main/java/com/replaymod/compat/shaders/ShaderReflection.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.replaymod.compat.shaders; - -import net.minecraft.client.Minecraft; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -public class ShaderReflection { - - // Shaders.frameTimeCounter - public static Field shaders_frameTimeCounter; - - // Shaders.isShadowPass - public static Field shaders_isShadowPass; - - // Shaders.beginRender() - public static Method shaders_beginRender; - - // RenderGlobal.chunksToUpdateForced (Optifine only) - public static Field renderGlobal_chunksToUpdateForced; - - // Config.isShaders() (Optifine only) - public static Method config_isShaders; - - static { - try { - shaders_frameTimeCounter = Class.forName("shadersmod.client.Shaders") - .getDeclaredField("frameTimeCounter"); - shaders_frameTimeCounter.setAccessible(true); - - shaders_isShadowPass = Class.forName("shadersmod.client.Shaders") - .getDeclaredField("isShadowPass"); - shaders_isShadowPass.setAccessible(true); - - shaders_beginRender = Class.forName("shadersmod.client.Shaders") - .getDeclaredMethod("beginRender", Minecraft.class, float.class, long.class); - shaders_beginRender.setAccessible(true); - - renderGlobal_chunksToUpdateForced = Class.forName("net.minecraft.client.renderer.RenderGlobal") - .getDeclaredField("chunksToUpdateForced"); - renderGlobal_chunksToUpdateForced.setAccessible(true); - - config_isShaders = Class.forName("Config") - .getDeclaredMethod("isShaders"); - config_isShaders.setAccessible(true); - } catch (ClassNotFoundException ignore) { - // no shaders mod installed - } catch (NoSuchMethodException | NoSuchFieldException e) { - // the method wasn't found. Has it been renamed? - e.printStackTrace(); - } - } -} diff --git a/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderEntityRenderer.java b/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderEntityRenderer.java deleted file mode 100644 index 358ff118..00000000 --- a/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderEntityRenderer.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.replaymod.compat.shaders.mixin; - -import com.replaymod.compat.shaders.ShaderReflection; -import com.replaymod.replay.ReplayHandler; -import com.replaymod.replay.ReplayModReplay; -import net.minecraft.client.renderer.EntityRenderer; -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; - -@Mixin(EntityRenderer.class) -public abstract class MixinShaderEntityRenderer { - - @Inject(method = "renderWorldPass", at = @At("HEAD")) - private void replayModCompat_updateShaderFrameTimeCounter(CallbackInfo ignore) { - if (ReplayModReplay.instance.getReplayHandler() == null) return; - if (ShaderReflection.shaders_frameTimeCounter == null) return; - - ReplayHandler replayHandler = ReplayModReplay.instance.getReplayHandler(); - float timestamp = replayHandler.getReplaySender().currentTimeStamp() / 1000f % 3600f; - try { - ShaderReflection.shaders_frameTimeCounter.set(null, timestamp); - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderRenderChunk.java b/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderRenderChunk.java deleted file mode 100644 index 3b4e9bc2..00000000 --- a/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderRenderChunk.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.replaymod.compat.shaders.mixin; - -import com.replaymod.render.hooks.EntityRendererHandler; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.chunk.RenderChunk; -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.CallbackInfoReturnable; - -@Mixin(RenderChunk.class) -public abstract class MixinShaderRenderChunk { - - private final Minecraft mc = Minecraft.getMinecraft(); - - /** - * Changes the RenderChunk#isPlayerUpdate method that Optifine adds - * to always return true while rendering so no chunks are being added - * to a separate rendering queue - */ - @Inject(method = "isPlayerUpdate", at = @At("HEAD"), cancellable = true) - private void replayModCompat_disableIsPlayerUpdate(CallbackInfoReturnable ci) { - if (((EntityRendererHandler.IEntityRenderer) mc.entityRenderer).replayModRender_getHandler() == null) return; - ci.setReturnValue(true); - } - - -} diff --git a/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderRenderGlobal.java b/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderRenderGlobal.java deleted file mode 100644 index be69cf00..00000000 --- a/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderRenderGlobal.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.replaymod.compat.shaders.mixin; - -import com.replaymod.compat.shaders.ShaderReflection; -import com.replaymod.render.hooks.EntityRendererHandler; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.RenderGlobal; -import net.minecraft.client.renderer.culling.ICamera; -import net.minecraft.entity.Entity; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(RenderGlobal.class) -public abstract class MixinShaderRenderGlobal { - - private final Minecraft mc = Minecraft.getMinecraft(); - - @Shadow - public boolean displayListEntitiesDirty; - - @Inject(method = "setupTerrain", at = @At("HEAD"), cancellable = true) - public void replayModCompat_setupTerrain(Entity viewEntity, double partialTicks, ICamera camera, - int frameCount, boolean playerSpectator, CallbackInfo ci) { - if (((EntityRendererHandler.IEntityRenderer) mc.entityRenderer).replayModRender_getHandler() == null) return; - if (ShaderReflection.shaders_isShadowPass == null) return; - - // when called by the shadow pass, displayListEntitiesDirty can't be set to false, as no chunk updates - // are being processed. As it's being set to true by ChunkLoadingRenderGlobal#updateChunks, we have to - // set it to false manually to exit the loop imposed by MixinRenderGlobal#replayModRender_setupTerrain. - try { - if ((boolean) ShaderReflection.shaders_isShadowPass.get(null) == true) { - displayListEntitiesDirty = false; - } - } catch (IllegalAccessException ignore) {} - - } - -} diff --git a/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaders.java b/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaders.java new file mode 100644 index 00000000..a6f3d475 --- /dev/null +++ b/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaders.java @@ -0,0 +1,50 @@ +package com.replaymod.compat.shaders.mixin; + +import com.replaymod.render.hooks.EntityRendererHandler; +import com.replaymod.replay.ReplayHandler; +import com.replaymod.replay.ReplayModReplay; +import net.minecraft.client.Minecraft; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Pseudo +@Mixin(targets = "shadersmod/client/Shaders", remap = false) +public abstract class MixinShaders { + + @Shadow static Minecraft mc; + @Shadow static long systemTime; + @Shadow static long lastSystemTime; + @Shadow static long diffSystemTime; + @Shadow static int frameCounter; + @Shadow static float frameTime; + @Shadow static float frameTimeCounter; + + @Redirect(method = "beginRender", at = @At(value = "INVOKE", target = "Ljava/lang/System;currentTimeMillis()J")) + private static long replayModCompat_currentTimeMillis() { + ReplayHandler replayHandler = ReplayModReplay.instance.getReplayHandler(); + if (replayHandler != null) { + systemTime = replayHandler.getReplaySender().currentTimeStamp(); + + // We need to manipulate all the other previous-frame-time-based variables too + + lastSystemTime = 0; // Draw all frames as if they were the first ones + // diffSystemTime will be set to 0 by Shaders + // frameTime will be set to 0 by Shaders + frameTimeCounter = systemTime / 1000f; // will be %= 3600f by Shaders + + // Set frameCounter only if rendering is in progress + EntityRendererHandler entityRendererHandler = + ((EntityRendererHandler.IEntityRenderer) mc.entityRenderer).replayModRender_getHandler(); + if (entityRendererHandler != null) { + frameCounter = entityRendererHandler.getRenderInfo().getFramesDone(); + } + + return systemTime; + } + return System.currentTimeMillis(); + } + +} diff --git a/src/main/java/com/replaymod/core/GLErrorTransformer.java b/src/main/java/com/replaymod/core/GLErrorTransformer.java new file mode 100644 index 00000000..07c04ef5 --- /dev/null +++ b/src/main/java/com/replaymod/core/GLErrorTransformer.java @@ -0,0 +1,94 @@ +package com.replaymod.core; + +import net.minecraft.launchwrapper.IClassTransformer; +import org.lwjgl.opengl.GL11; +import org.lwjgl.util.glu.GLU; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * Insert glGetError checks after all calls to any method in any GL*, ARB* and EXT* classes + */ +public class GLErrorTransformer implements IClassTransformer { + private static final String GL_CLASS = "org.lwjgl.opengl.GL"; + private static final String GL = GL_CLASS.replace('.', '/'); + private static final String ARB_CLASS = "org.lwjgl.opengl.ARB"; + private static final String ARB = ARB_CLASS.replace('.', '/'); + private static final String EXT_CLASS = "org.lwjgl.opengl.EXT"; + private static final String EXT = EXT_CLASS.replace('.', '/'); + private static final String GLErrorTransformer_CLASS = GLErrorTransformer.class.getName(); + private static final String GLErrorTransformer = GLErrorTransformer_CLASS.replace('.', '/'); + + @Override + public byte[] transform(String name, String transformedName, byte[] basicClass) { + // Ignore (anonymous) inner classes of this transformer + if (name.startsWith(GLErrorTransformer_CLASS)) return basicClass; + + ClassReader reader = new ClassReader(basicClass); + ClassWriter writer = new ClassWriter(reader, 0); + reader.accept(new ClassVisitor(Opcodes.ASM5, writer) { + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); + return new MethodVisitor(Opcodes.ASM5, mv) { + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + if (owner.startsWith(GL) || owner.startsWith(ARB) || owner.startsWith(EXT)) { + visitLdcInsn(owner.replace('/', '.')); + visitLdcInsn(name); + super.visitMethodInsn(Opcodes.INVOKESTATIC, GLErrorTransformer, "glErrorCheck", "(Ljava/lang/String;Ljava/lang/String;)V", false); + } + } + + @Override + public void visitMaxs(int maxStack, int maxLocals) { + super.visitMaxs(maxStack + 2, maxLocals); + } + }; + } + }, 0); + return writer.toByteArray(); + } + + private static boolean inGlBegin; + + @SuppressWarnings("unused") // Called via ASM + public static void glErrorCheck(String cls, String method) { + if (method.equals("glBegin") && cls.equals(GL_CLASS + "11")) { + if (inGlBegin) { + // glBegin within glBegin + throw new GLError(GL11.GL_INVALID_OPERATION, cls, method); + } + inGlBegin = true; + return; + } + if (inGlBegin && method.equals("glEnd") && cls.equals(GL_CLASS + "11")) { + inGlBegin = false; + } + if (inGlBegin) { + return; // Cannot call glGetError in between of glBegin and glEnd + } + int err = GL11.glGetError(); + if (err != 0) { + GLError e = new GLError(err, cls, method); + if ("true".equals(System.getProperty("replaymod.glerrors.throw", "true"))) { + throw e; + } else { + e.printStackTrace(); + } + } + } + + public static class GLError extends RuntimeException { + private GLError(int err, String cls, String method) { + super(GLU.gluErrorString(err) + " (" + err + ")"); + StackTraceElement[] stack = getStackTrace(); + stack[0] = new StackTraceElement(cls, method, stack[0].getFileName(), stack[0].getLineNumber()); + setStackTrace(stack); + } + } +} diff --git a/src/main/java/com/replaymod/core/GLStateTrackerTransformer.java b/src/main/java/com/replaymod/core/GLStateTrackerTransformer.java new file mode 100644 index 00000000..da620019 --- /dev/null +++ b/src/main/java/com/replaymod/core/GLStateTrackerTransformer.java @@ -0,0 +1,105 @@ +package com.replaymod.core; + +import net.minecraft.launchwrapper.IClassTransformer; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import java.util.HashSet; +import java.util.Set; + +/** + * Redirect all calls to GL11.glEnable and GL11.glDisable to the GLStateTracker (excluding that class itself). + */ +public class GLStateTrackerTransformer implements IClassTransformer { + private static final String GL11_CLASS = "org.lwjgl.opengl.GL11"; + private static final String GL11 = GL11_CLASS.replace('.', '/'); + private static final String glEnable = "glEnable"; + private static final String glDisable = "glDisable"; + private static final String GLStateTracker_CLASS = "com.replaymod.render.hooks.GLStateTracker"; + private static final String GLStateTracker = GLStateTracker_CLASS.replace('.', '/'); + private static final String hook_glEnable = "hook_glEnable"; + private static final String hook_glDisable = "hook_glDisable"; + + @Override + public byte[] transform(String name, String transformedName, byte[] basicClass) { + // Ignore (anonymous) inner classes of this transformer + if (name.startsWith(GLStateTrackerTransformer.class.getName())) return basicClass; + // Ignore the state tracker itself + if (name.equals(GLStateTracker_CLASS)) return basicClass; + + ClassReader reader = new ClassReader(basicClass); + Set eligibleMethods = findEligibleMethods(reader); + if (eligibleMethods.isEmpty()) { + return basicClass; + } + + ClassWriter writer = new ClassWriter(reader, 0); + reader.accept(new ClassVisitor(Opcodes.ASM5, writer) { + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); + if (!eligibleMethods.contains(new Method(name, desc))) { + return mv; + } + return new MethodVisitor(Opcodes.ASM5, mv) { + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (owner.equals(GL11)) { + if (name.equals(glEnable)) { + owner = GLStateTracker; + name = hook_glEnable; + } else if (name.equals(glDisable)) { + owner = GLStateTracker; + name = hook_glDisable; + } + } + super.visitMethodInsn(opcode, owner, name, desc, itf); + } + }; + } + }, 0); + return writer.toByteArray(); + } + + private Set findEligibleMethods(ClassReader reader) { + Set eligibleMethods = new HashSet<>(); + reader.accept(new ClassVisitor(Opcodes.ASM5) { + @Override + public MethodVisitor visitMethod(int access, String methodName, String methodDesc, String signature, String[] exceptions) { + return new MethodVisitor(Opcodes.ASM5) { + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (owner.equals(GL11) && (name.equals(glEnable) || name.equals(glDisable))) { + eligibleMethods.add(new Method(methodName, methodDesc)); + } + } + }; + } + }, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + return eligibleMethods; + } + + private static class Method { + private final String name, desc; + + private Method(String name, String desc) { + this.name = name; + this.desc = desc; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + Method method = (Method) o; + return name.equals(method.name) && desc.equals(method.desc); + } + + @Override + public int hashCode() { + return name.hashCode() ^ desc.hashCode(); + } + } +} diff --git a/src/main/java/com/replaymod/core/KeyBindingRegistry.java b/src/main/java/com/replaymod/core/KeyBindingRegistry.java index 8231700c..f86a00e6 100644 --- a/src/main/java/com/replaymod/core/KeyBindingRegistry.java +++ b/src/main/java/com/replaymod/core/KeyBindingRegistry.java @@ -2,14 +2,14 @@ package com.replaymod.core; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; +import cpw.mods.fml.client.registry.ClientRegistry; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.InputEvent; +import cpw.mods.fml.common.gameevent.TickEvent; import net.minecraft.client.settings.KeyBinding; import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; import net.minecraft.util.ReportedException; -import net.minecraftforge.fml.client.registry.ClientRegistry; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.InputEvent; -import net.minecraftforge.fml.common.gameevent.TickEvent; import org.lwjgl.input.Keyboard; import java.util.Collection; @@ -64,7 +64,7 @@ public class KeyBindingRegistry { public void handleRepeatedKeyBindings() { for (Map.Entry> entry : repeatedKeyBindingHandlers.asMap().entrySet()) { - if (entry.getKey().isKeyDown()) { + if (entry.getKey().getIsKeyPressed()) { invokeKeyBindingHandlers(entry.getKey(), entry.getValue()); } } diff --git a/src/main/java/com/replaymod/core/LoadingPlugin.java b/src/main/java/com/replaymod/core/LoadingPlugin.java index 9a251ed9..fbf4a4b2 100755 --- a/src/main/java/com/replaymod/core/LoadingPlugin.java +++ b/src/main/java/com/replaymod/core/LoadingPlugin.java @@ -1,7 +1,7 @@ package com.replaymod.core; -import net.minecraftforge.fml.relauncher.CoreModManager; -import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; +import cpw.mods.fml.relauncher.CoreModManager; +import cpw.mods.fml.relauncher.IFMLLoadingPlugin; import org.apache.logging.log4j.LogManager; import org.spongepowered.asm.launch.MixinBootstrap; import org.spongepowered.asm.mixin.Mixins; @@ -10,6 +10,8 @@ import java.io.File; import java.net.URISyntaxException; import java.net.URL; import java.security.CodeSource; +import java.util.ArrayList; +import java.util.List; import java.util.Map; public class LoadingPlugin implements IFMLLoadingPlugin { @@ -31,6 +33,7 @@ public class LoadingPlugin implements IFMLLoadingPlugin { // This forces forge to reexamine the jar file for FML mods // Should eventually be handled by Mixin itself, maybe? CoreModManager.getLoadedCoremods().remove(file.getName()); + CoreModManager.getReparseableCoremods().add(file.getName()); } } catch (URISyntaxException e) { e.printStackTrace(); @@ -43,8 +46,12 @@ public class LoadingPlugin implements IFMLLoadingPlugin { @Override public String[] getASMTransformerClass() { - return new String[]{ - }; + List transformers = new ArrayList<>(); + if ("true".equals(System.getProperty("replaymod.glerrors", "false"))) { + transformers.add(GLErrorTransformer.class.getName()); + } + transformers.add(GLStateTrackerTransformer.class.getName()); + return transformers.stream().toArray(String[]::new); } @Override diff --git a/src/main/java/com/replaymod/core/ReplayMod.java b/src/main/java/com/replaymod/core/ReplayMod.java index 86cf4877..8f194ae7 100755 --- a/src/main/java/com/replaymod/core/ReplayMod.java +++ b/src/main/java/com/replaymod/core/ReplayMod.java @@ -7,32 +7,38 @@ import com.replaymod.core.gui.RestoreReplayGui; import com.replaymod.core.handler.MainMenuHandler; import com.replaymod.core.utils.OpenGLUtils; import com.replaymod.render.utils.SoundHandler; +import com.replaymod.replay.InputReplayTimer; import com.replaymod.replaystudio.util.I18n; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.Mod.EventHandler; +import cpw.mods.fml.common.Mod.Instance; +import cpw.mods.fml.common.ModContainer; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.eventhandler.EventBus; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; import de.johni0702.minecraft.gui.container.GuiScreen; import lombok.Getter; +import lombok.RequiredArgsConstructor; import net.minecraft.client.Minecraft; -import net.minecraft.client.settings.GameSettings; import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; -import net.minecraft.util.*; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.ChatStyle; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.IChatComponent; +import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.config.Configuration; -import net.minecraftforge.fml.client.FMLClientHandler; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.Loader; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.Mod.EventHandler; -import net.minecraftforge.fml.common.Mod.Instance; -import net.minecraftforge.fml.common.ModContainer; -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.TickEvent; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; +import java.util.ArrayDeque; import java.util.List; import java.util.Queue; @@ -41,7 +47,6 @@ import java.util.Queue; version = "@MOD_VERSION@", acceptedMinecraftVersions = "@MC_VERSION@", acceptableRemoteVersions = "*", - updateJSON = "https://raw.githubusercontent.com/ReplayMod/ReplayMod/master/versions.json", guiFactory = "com.replaymod.core.gui.GuiFactory") public class ReplayMod { @@ -54,10 +59,10 @@ public class ReplayMod { private static String parseMinecraftVersion() { CrashReport crashReport = new CrashReport("", new Throwable()); @SuppressWarnings("unchecked") - List list = crashReport.getCategory().children; + List list = crashReport.getCategory().field_85077_c; for (CrashReportCategory.Entry entry : list) { - if ("Minecraft Version".equals(entry.getKey())) { - return entry.getValue(); + if ("Minecraft Version".equals(entry.func_85089_a())) { + return entry.func_85090_b(); } } return "Unknown"; @@ -116,6 +121,7 @@ public class ReplayMod { new MainMenuHandler().register(); + FMLCommonHandler.instance().bus().register(this); FMLCommonHandler.instance().bus().register(keyBindingRegistry); getKeyBindingRegistry().registerKeyBinding("replaymod.input.settings", 0, () -> { @@ -127,8 +133,10 @@ public class ReplayMod { public void postInit(FMLPostInitializationEvent event) throws IOException { settingsRegistry.save(); // Save default values to disk + /* TODO 1.7.10: MC crashes when setting render distance to > 16 if(!FMLClientHandler.instance().hasOptifine()) GameSettings.Options.RENDER_DISTANCE.setValueMax(64f); + */ if (System.getProperty("replaymod.render.file") != null) { final File file = new File(System.getProperty("replaymod.render.file")); @@ -316,24 +324,17 @@ public class ReplayMod { */ private boolean inRunLater = false; + // 1.7.10: Cannot use MC's because it is processed only during ticks (so not at all when replay is paused) + private final Queue> scheduledTasks = new ArrayDeque<>(); + public void runLater(Runnable runnable) { if (mc.isCallingFromMinecraftThread() && inRunLater) { EventBus bus = FMLCommonHandler.instance().bus(); - bus.register(new Object() { - @SubscribeEvent - public void onRenderTick(TickEvent.RenderTickEvent event) { - if (event.phase == TickEvent.Phase.START) { - runLater(runnable); - bus.unregister(this); - } - } - }); + bus.register(new RunLaterHelper(runnable)); return; } - @SuppressWarnings("unchecked") - Queue tasks = mc.scheduledTasks; - synchronized (mc.scheduledTasks) { - tasks.add(ListenableFutureTask.create(() -> { + synchronized (scheduledTasks) { + scheduledTasks.add(ListenableFutureTask.create(() -> { inRunLater = true; try { runnable.run(); @@ -344,6 +345,28 @@ public class ReplayMod { } } + // in 1.7.10 apparently events can't be delivered to anonymous classes + @RequiredArgsConstructor + public class RunLaterHelper { + private final Runnable runnable; + @SubscribeEvent + public void onRenderTick(TickEvent.RenderTickEvent event) { + if (event.phase == TickEvent.Phase.START) { + runLater(runnable); + FMLCommonHandler.instance().bus().unregister(this); + } + } + } + + @SubscribeEvent + public void runScheduledTasks(InputReplayTimer.RunScheduledTasks event) { + synchronized (scheduledTasks) { + while (!scheduledTasks.isEmpty()) { + scheduledTasks.poll().run(); + } + } + } + public String getVersion() { return getContainer().getVersion(); } diff --git a/src/main/java/com/replaymod/core/SettingsRegistry.java b/src/main/java/com/replaymod/core/SettingsRegistry.java index 8d4636d8..bc226d1c 100644 --- a/src/main/java/com/replaymod/core/SettingsRegistry.java +++ b/src/main/java/com/replaymod/core/SettingsRegistry.java @@ -1,9 +1,9 @@ package com.replaymod.core; import com.replaymod.core.events.SettingsChangedEvent; +import cpw.mods.fml.common.FMLCommonHandler; import net.minecraft.client.resources.I18n; import net.minecraftforge.common.config.Configuration; -import net.minecraftforge.fml.common.FMLCommonHandler; import java.lang.reflect.Field; import java.lang.reflect.Modifier; diff --git a/src/main/java/com/replaymod/core/events/SettingsChangedEvent.java b/src/main/java/com/replaymod/core/events/SettingsChangedEvent.java index 6bc8d2f7..5f2cfd3b 100644 --- a/src/main/java/com/replaymod/core/events/SettingsChangedEvent.java +++ b/src/main/java/com/replaymod/core/events/SettingsChangedEvent.java @@ -1,9 +1,9 @@ package com.replaymod.core.events; import com.replaymod.core.SettingsRegistry; +import cpw.mods.fml.common.eventhandler.Event; import lombok.Getter; import lombok.RequiredArgsConstructor; -import net.minecraftforge.fml.common.eventhandler.Event; @RequiredArgsConstructor public class SettingsChangedEvent extends Event { diff --git a/src/main/java/com/replaymod/core/gui/GuiFactory.java b/src/main/java/com/replaymod/core/gui/GuiFactory.java index ca770c82..9db2f0c3 100644 --- a/src/main/java/com/replaymod/core/gui/GuiFactory.java +++ b/src/main/java/com/replaymod/core/gui/GuiFactory.java @@ -1,9 +1,9 @@ package com.replaymod.core.gui; import com.replaymod.core.ReplayMod; +import cpw.mods.fml.client.IModGuiFactory; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; -import net.minecraftforge.fml.client.IModGuiFactory; import java.util.Set; diff --git a/src/main/java/com/replaymod/core/handler/MainMenuHandler.java b/src/main/java/com/replaymod/core/handler/MainMenuHandler.java index d12bbeaa..d5bc6f47 100644 --- a/src/main/java/com/replaymod/core/handler/MainMenuHandler.java +++ b/src/main/java/com/replaymod/core/handler/MainMenuHandler.java @@ -1,10 +1,10 @@ package com.replaymod.core.handler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiMainMenu; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import java.util.List; diff --git a/src/main/java/com/replaymod/core/utils/ModCompat.java b/src/main/java/com/replaymod/core/utils/ModCompat.java index 876c05fe..2770c0b0 100644 --- a/src/main/java/com/replaymod/core/utils/ModCompat.java +++ b/src/main/java/com/replaymod/core/utils/ModCompat.java @@ -1,10 +1,9 @@ package com.replaymod.core.utils; import com.replaymod.replaystudio.data.ModInfo; -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.common.Loader; -import net.minecraftforge.fml.common.ModContainer; -import net.minecraftforge.fml.common.registry.GameData; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.ModContainer; +import cpw.mods.fml.common.registry.GameData; import java.util.*; import java.util.function.Function; @@ -17,14 +16,19 @@ public class ModCompat { Map ignoreCaseMap = Loader.instance().getModList().stream() .collect(Collectors.toMap(m -> m.getModId().toLowerCase(), Function.identity())); return Stream.concat( - ((Set) GameData.getBlockRegistry().getKeys()).stream(), - ((Set) GameData.getItemRegistry().getKeys()).stream() - ).map(ResourceLocation::getResourceDomain).filter(s -> !s.equals("minecraft")).distinct() + ((Set) GameData.getBlockRegistry().getKeys()).stream(), + ((Set) GameData.getItemRegistry().getKeys()).stream() + ).map(ModCompat::getResourceDomain).filter(s -> !s.equals("minecraft")).distinct() .map(String::toLowerCase).map(ignoreCaseMap::get).filter(mod -> mod != null) .map(mod -> new ModInfo(mod.getModId(), mod.getName(), mod.getVersion())) .collect(Collectors.toList()); } + private static String getResourceDomain(String name) { + if (!name.contains(":")) return null; // Still using old names without namespace, can't do anything, ignore + return name.split(":", 2)[0]; + } + public static final class ModInfoDifference { private final Set missing = new HashSet<>(); private final Map differing = new HashMap<>(); diff --git a/src/main/java/com/replaymod/core/utils/OpenGLUtils.java b/src/main/java/com/replaymod/core/utils/OpenGLUtils.java index 6ee4886b..ddb465e8 100644 --- a/src/main/java/com/replaymod/core/utils/OpenGLUtils.java +++ b/src/main/java/com/replaymod/core/utils/OpenGLUtils.java @@ -1,8 +1,6 @@ package com.replaymod.core.utils; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.WorldRenderer; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; @@ -28,22 +26,21 @@ public class OpenGLUtils { } public static void drawRotatedRectWithCustomSizedTexture(int x, int y, float rotation, float u, float v, int width, int height, float textureWidth, float textureHeight) { - GlStateManager.pushMatrix(); + GL11.glPushMatrix(); float f4 = 1.0F / textureWidth; float f5 = 1.0F / textureHeight; - Tessellator tessellator = Tessellator.getInstance(); - WorldRenderer worldrenderer = tessellator.getWorldRenderer(); - GlStateManager.translate(x+(width/2), y+(width/2), 0); - GlStateManager.rotate(rotation, 0, 0, 1); - worldrenderer.startDrawingQuads(); - worldrenderer.addVertexWithUV(-width / 2, height / 2, 0.0D, (double) (u * f4), (double) ((v + (float) height) * f5)); - worldrenderer.addVertexWithUV(width/2, height/2, 0.0D, (double)((u + (float)width) * f4), (double)((v + (float)height) * f5)); - worldrenderer.addVertexWithUV(width/2, -height/2, 0.0D, (double)((u + (float)width) * f4), (double)(v * f5)); - worldrenderer.addVertexWithUV(-width/2, -height/2, 0.0D, (double)(u * f4), (double)(v * f5)); + Tessellator tessellator = Tessellator.instance; + GL11.glTranslatef(x+(width/2), y+(width/2), 0); + GL11.glRotatef(rotation, 0, 0, 1); + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV(-width / 2, height / 2, 0.0D, (double) (u * f4), (double) ((v + (float) height) * f5)); + tessellator.addVertexWithUV(width/2, height/2, 0.0D, (double)((u + (float)width) * f4), (double)((v + (float)height) * f5)); + tessellator.addVertexWithUV(width/2, -height/2, 0.0D, (double)((u + (float)width) * f4), (double)(v * f5)); + tessellator.addVertexWithUV(-width/2, -height/2, 0.0D, (double)(u * f4), (double)(v * f5)); tessellator.draw(); - GlStateManager.popMatrix(); + GL11.glPopMatrix(); } } diff --git a/src/main/java/com/replaymod/core/utils/Restrictions.java b/src/main/java/com/replaymod/core/utils/Restrictions.java index 06248597..23d5a568 100644 --- a/src/main/java/com/replaymod/core/utils/Restrictions.java +++ b/src/main/java/com/replaymod/core/utils/Restrictions.java @@ -1,8 +1,11 @@ package com.replaymod.core.utils; +import io.netty.buffer.Unpooled; import net.minecraft.network.PacketBuffer; import net.minecraft.network.play.server.S3FPacketCustomPayload; +import java.io.IOException; + /** * Restrictions set by the server, * @see Replay Restrictions Gist @@ -14,8 +17,8 @@ public class Restrictions { private boolean onlyFirstPerson; private boolean onlyRecordingPlayer; - public String handle(S3FPacketCustomPayload packet) { - PacketBuffer buffer = packet.getBufferData(); + public String handle(S3FPacketCustomPayload packet) throws IOException { + PacketBuffer buffer = new PacketBuffer(Unpooled.wrappedBuffer(packet.func_149168_d())); while (buffer.isReadable()) { String name = buffer.readStringFromBuffer(64); boolean active = buffer.readBoolean(); diff --git a/src/main/java/com/replaymod/core/utils/Utils.java b/src/main/java/com/replaymod/core/utils/Utils.java index fb32c44c..809fcc8f 100644 --- a/src/main/java/com/replaymod/core/utils/Utils.java +++ b/src/main/java/com/replaymod/core/utils/Utils.java @@ -18,10 +18,11 @@ import de.johni0702.minecraft.gui.layout.VerticalLayout; import de.johni0702.minecraft.gui.popup.GuiInfoPopup; import de.johni0702.minecraft.gui.utils.Colors; import lombok.SneakyThrows; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.network.NetworkPlayerInfo; -import net.minecraft.client.resources.DefaultPlayerSkin; import net.minecraft.crash.CrashReport; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.ResourceLocation; import org.apache.commons.io.Charsets; import org.apache.commons.io.FilenameUtils; @@ -160,14 +161,11 @@ public class Utils { } public static ResourceLocation getResourceLocationForPlayerUUID(UUID uuid) { - NetworkPlayerInfo info = getMinecraft().getNetHandler().getPlayerInfo(uuid); - ResourceLocation skinLocation; - if (info != null && info.hasLocationSkin()) { - skinLocation = info.getLocationSkin(); - } else { - skinLocation = DefaultPlayerSkin.getDefaultSkin(uuid); + EntityPlayer player = Minecraft.getMinecraft().theWorld.getPlayerEntityByUUID(uuid); + if (player == null || !(player instanceof AbstractClientPlayer)) { + return AbstractClientPlayer.locationStevePng; } - return skinLocation; + return ((AbstractClientPlayer) player).getLocationSkin(); } public static boolean isCtrlDown() { diff --git a/src/main/java/com/replaymod/editor/ReplayModEditor.java b/src/main/java/com/replaymod/editor/ReplayModEditor.java index 7749f5c0..b2286767 100644 --- a/src/main/java/com/replaymod/editor/ReplayModEditor.java +++ b/src/main/java/com/replaymod/editor/ReplayModEditor.java @@ -3,9 +3,9 @@ package com.replaymod.editor; import com.replaymod.core.ReplayMod; import com.replaymod.editor.handler.GuiHandler; import com.replaymod.online.Setting; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.event.FMLInitializationEvent; -import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; import org.apache.logging.log4j.Logger; @Mod(modid = ReplayModEditor.MOD_ID, diff --git a/src/main/java/com/replaymod/editor/handler/GuiHandler.java b/src/main/java/com/replaymod/editor/handler/GuiHandler.java index 7fdb59e1..7717ac4e 100644 --- a/src/main/java/com/replaymod/editor/handler/GuiHandler.java +++ b/src/main/java/com/replaymod/editor/handler/GuiHandler.java @@ -2,14 +2,14 @@ package com.replaymod.editor.handler; import com.replaymod.editor.ReplayModEditor; import com.replaymod.editor.gui.GuiReplayEditor; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import de.johni0702.minecraft.gui.container.GuiScreen; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiMainMenu; import net.minecraft.client.resources.I18n; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import java.util.List; diff --git a/src/main/java/com/replaymod/extras/FullBrightness.java b/src/main/java/com/replaymod/extras/FullBrightness.java index 754bdf8e..6a65fad4 100644 --- a/src/main/java/com/replaymod/extras/FullBrightness.java +++ b/src/main/java/com/replaymod/extras/FullBrightness.java @@ -5,13 +5,13 @@ import com.replaymod.replay.ReplayHandler; import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.events.ReplayOpenEvent; import com.replaymod.replay.gui.overlay.GuiReplayOverlay; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; import de.johni0702.minecraft.gui.element.GuiImage; import de.johni0702.minecraft.gui.element.IGuiImage; import de.johni0702.minecraft.gui.layout.HorizontalLayout; import net.minecraft.client.settings.GameSettings; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.TickEvent; import org.lwjgl.input.Keyboard; public class FullBrightness implements Extra { diff --git a/src/main/java/com/replaymod/extras/HotkeyButtons.java b/src/main/java/com/replaymod/extras/HotkeyButtons.java index c660e37e..17b1adca 100644 --- a/src/main/java/com/replaymod/extras/HotkeyButtons.java +++ b/src/main/java/com/replaymod/extras/HotkeyButtons.java @@ -4,6 +4,8 @@ import com.replaymod.core.KeyBindingRegistry; import com.replaymod.core.ReplayMod; import com.replaymod.replay.events.ReplayOpenEvent; import com.replaymod.replay.gui.overlay.GuiReplayOverlay; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import de.johni0702.minecraft.gui.GuiRenderer; import de.johni0702.minecraft.gui.RenderInfo; import de.johni0702.minecraft.gui.container.GuiContainer; @@ -17,8 +19,6 @@ import de.johni0702.minecraft.gui.layout.GridLayout; import de.johni0702.minecraft.gui.layout.HorizontalLayout; import de.johni0702.minecraft.gui.layout.LayoutData; import net.minecraft.client.resources.I18n; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.lwjgl.input.Keyboard; import org.lwjgl.util.Dimension; import org.lwjgl.util.ReadableDimension; diff --git a/src/main/java/com/replaymod/extras/OpenEyeExtra.java b/src/main/java/com/replaymod/extras/OpenEyeExtra.java index ba0575fb..a6a736f8 100644 --- a/src/main/java/com/replaymod/extras/OpenEyeExtra.java +++ b/src/main/java/com/replaymod/extras/OpenEyeExtra.java @@ -2,6 +2,7 @@ package com.replaymod.extras; import com.replaymod.core.ReplayMod; import com.replaymod.core.Setting; +import cpw.mods.fml.common.Loader; import de.johni0702.minecraft.gui.container.AbstractGuiScreen; import de.johni0702.minecraft.gui.container.GuiContainer; import de.johni0702.minecraft.gui.container.GuiPanel; @@ -14,7 +15,6 @@ import de.johni0702.minecraft.gui.layout.HorizontalLayout; import de.johni0702.minecraft.gui.layout.VerticalLayout; import de.johni0702.minecraft.gui.popup.AbstractGuiPopup; import de.johni0702.minecraft.gui.utils.Colors; -import net.minecraftforge.fml.common.Loader; import org.apache.commons.io.FileUtils; import javax.net.ssl.HttpsURLConnection; diff --git a/src/main/java/com/replaymod/extras/ReplayModExtras.java b/src/main/java/com/replaymod/extras/ReplayModExtras.java index 93ed038a..6694b397 100644 --- a/src/main/java/com/replaymod/extras/ReplayModExtras.java +++ b/src/main/java/com/replaymod/extras/ReplayModExtras.java @@ -4,9 +4,9 @@ import com.replaymod.core.ReplayMod; import com.replaymod.extras.playeroverview.PlayerOverview; import com.replaymod.extras.urischeme.UriSchemeExtra; import com.replaymod.extras.youtube.YoutubeUpload; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.event.FMLInitializationEvent; -import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; import org.apache.logging.log4j.Logger; import java.util.Arrays; diff --git a/src/main/java/com/replaymod/extras/playeroverview/PlayerOverview.java b/src/main/java/com/replaymod/extras/playeroverview/PlayerOverview.java index 67619f84..97298777 100644 --- a/src/main/java/com/replaymod/extras/playeroverview/PlayerOverview.java +++ b/src/main/java/com/replaymod/extras/playeroverview/PlayerOverview.java @@ -1,7 +1,6 @@ package com.replaymod.extras.playeroverview; import com.google.common.base.Optional; -import com.google.common.base.Predicate; import com.replaymod.core.ReplayMod; import com.replaymod.core.utils.Utils; import com.replaymod.extras.Extra; @@ -9,16 +8,23 @@ import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.camera.CameraEntity; import com.replaymod.replay.events.ReplayCloseEvent; import com.replaymod.replay.events.ReplayOpenEvent; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.EventPriority; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.client.event.RenderHandEvent; +import net.minecraftforge.client.event.RenderPlayerEvent; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.lwjgl.input.Keyboard; import java.io.IOException; -import java.util.*; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; public class PlayerOverview implements Extra { private ReplayModReplay module; @@ -35,12 +41,10 @@ public class PlayerOverview implements Extra { public void run() { if (module.getReplayHandler() != null) { @SuppressWarnings("unchecked") - List players = mod.getMinecraft().theWorld.getPlayers(EntityPlayer.class, new Predicate() { - @Override - public boolean apply(Object input) { - return !(input instanceof CameraEntity); // Exclude the camera entity - } - }); + List players = mod.getMinecraft().theWorld.playerEntities; + players = players.stream() + .filter(it -> !(it instanceof CameraEntity)) // Exclude the camera entity + .collect(Collectors.toList()); if (!Utils.isCtrlDown()) { // Hide all players that have an UUID v2 (commonly used for NPCs) Iterator iter = players.iterator(); @@ -90,12 +94,19 @@ public class PlayerOverview implements Extra { @SubscribeEvent public void oRenderHand(RenderHandEvent event) { - Entity view = module.getCore().getMinecraft().getRenderViewEntity(); + Entity view = module.getCore().getMinecraft().renderViewEntity; if (view != null && isHidden(view.getUniqueID())) { event.setCanceled(true); } } + @SubscribeEvent(priority = EventPriority.HIGHEST) + public void preRenderPlayer(RenderPlayerEvent.Pre event) { + if (isHidden(event.entityPlayer.getUniqueID())) { + event.setCanceled(true); + } + } + public boolean isSavingEnabled() { return savingEnabled; } diff --git a/src/main/java/com/replaymod/extras/playeroverview/PlayerOverviewGui.java b/src/main/java/com/replaymod/extras/playeroverview/PlayerOverviewGui.java index 9dcce774..27952468 100644 --- a/src/main/java/com/replaymod/extras/playeroverview/PlayerOverviewGui.java +++ b/src/main/java/com/replaymod/extras/playeroverview/PlayerOverviewGui.java @@ -20,7 +20,6 @@ import de.johni0702.minecraft.gui.layout.HorizontalLayout; import de.johni0702.minecraft.gui.utils.Colors; import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.EnumPlayerModelParts; import net.minecraft.potion.Potion; import net.minecraft.util.ResourceLocation; import org.lwjgl.util.Dimension; @@ -46,14 +45,14 @@ public class PlayerOverviewGui extends GuiScreen implements Closeable { public final GuiCheckbox checkAll = new GuiCheckbox(contentPanel){ @Override public void onClick() { - getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.create(BUTTON_SOUND, 1.0F)); + getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.createPositionedSoundRecord(BUTTON_SOUND, 1.0F)); playersScrollable.forEach(IGuiCheckbox.class).setChecked(true); } }.setLabel("").setChecked(true).setTooltip(new GuiTooltip().setI18nText("replaymod.gui.playeroverview.showall")); public final GuiCheckbox uncheckAll = new GuiCheckbox(contentPanel){ @Override public void onClick() { - getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.create(BUTTON_SOUND, 1.0F)); + getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.createPositionedSoundRecord(BUTTON_SOUND, 1.0F)); playersScrollable.forEach(IGuiCheckbox.class).setChecked(false); } }.setLabel("").setChecked(false).setTooltip(new GuiTooltip().setI18nText("replaymod.gui.playeroverview.hideall")); @@ -96,12 +95,10 @@ public class PlayerOverviewGui extends GuiScreen implements Closeable { public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) { renderer.bindTexture(texture); renderer.drawTexturedRect(0, 0, 8, 8, 16, 16, 8, 8, 64, 64); - if (p.func_175148_a(EnumPlayerModelParts.HAT)) { - renderer.drawTexturedRect(0, 0, 40, 8, size.getWidth(), size.getHeight(), 8, 8, 64, 64); - } + renderer.drawTexturedRect(0, 0, 40, 8, size.getWidth(), size.getHeight(), 8, 8, 64, 64); } }.setSize(16, 16), - new GuiLabel().setText(p.getName()).setColor(isSpectator(p) ? Colors.DKGREY : Colors.WHITE) + new GuiLabel().setText(p.getDisplayName()).setColor(isSpectator(p) ? Colors.DKGREY : Colors.WHITE) ).onClick(new Runnable() { @Override public void run() { @@ -153,7 +150,7 @@ public class PlayerOverviewGui extends GuiScreen implements Closeable { public int compare(EntityPlayer o1, EntityPlayer o2) { if (isSpectator(o1) && !isSpectator(o2)) return 1; if (isSpectator(o2) && !isSpectator(o1)) return -1; - return o1.getName().compareToIgnoreCase(o2.getName()); + return o1.getDisplayName().compareToIgnoreCase(o2.getDisplayName()); } } } diff --git a/src/main/java/com/replaymod/extras/playeroverview/mixin/MixinRender.java b/src/main/java/com/replaymod/extras/playeroverview/mixin/MixinRenderPlayer.java similarity index 50% rename from src/main/java/com/replaymod/extras/playeroverview/mixin/MixinRender.java rename to src/main/java/com/replaymod/extras/playeroverview/mixin/MixinRenderPlayer.java index fd750943..f18e62bb 100644 --- a/src/main/java/com/replaymod/extras/playeroverview/mixin/MixinRender.java +++ b/src/main/java/com/replaymod/extras/playeroverview/mixin/MixinRenderPlayer.java @@ -2,14 +2,13 @@ package com.replaymod.extras.playeroverview.mixin; import com.replaymod.extras.ReplayModExtras; import com.replaymod.extras.playeroverview.PlayerOverview; -import net.minecraft.client.renderer.culling.ICamera; -import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.renderer.entity.RenderPlayer; +import net.minecraft.client.renderer.entity.RendererLivingEntity; import net.minecraft.entity.Entity; -import net.minecraft.entity.player.EntityPlayer; 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.CallbackInfoReturnable; + +import java.util.UUID; /** * This mixin prevents players that are hidden in the PlayerOverview from being rendered. @@ -19,22 +18,22 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; * * The previous solution was to overwrite the RenderPlayer instances which has been dropped in favor of this one * because it is less compatible with other mods whereas this one should be fine as long as no other mod completely - * overwrites the shouldRender method. + * overwrites the methods we modify in this mixin. * One example of the previous solution breaking is when used with VanillaEnhancements because it replaces the * RenderManager with a new custom one which in turn will reset our registered RenderPlayer instances because * it does so after we have already registered with the old RenderManager. */ -@Mixin(value = Render.class, priority = 1200) -public abstract class MixinRender { - @Inject(method = "shouldRender", at=@At("HEAD"), cancellable = true) - public void replayModExtras_isPlayerHidden(Entity entity, ICamera camera, double camX, double camY, double camZ, CallbackInfoReturnable ci) { - ReplayModExtras.instance.get(PlayerOverview.class).ifPresent(playerOverview -> { - if (entity instanceof EntityPlayer) { - EntityPlayer player = (EntityPlayer) entity; - if (playerOverview.isHidden(player.getUniqueID())) { - ci.setReturnValue(false); - } - } - }); +@Mixin(value = RenderPlayer.class, priority = 1200) +public abstract class MixinRenderPlayer extends RendererLivingEntity { + public MixinRenderPlayer(ModelBase p_i1261_1_, float p_i1261_2_) { + super(p_i1261_1_, p_i1261_2_); + } + + @Override + public void doRenderShadowAndFire(Entity entity, double d1, double d2, double d3, float f1, float f2) { + UUID uuid = entity.getUniqueID(); + if (!ReplayModExtras.instance.get(PlayerOverview.class).map(po -> po.isHidden(uuid)).orElse(false)) { + super.doRenderShadowAndFire(entity, d1, d2, d3, f1, f2); + } } } diff --git a/src/main/java/com/replaymod/extras/youtube/YoutubeUpload.java b/src/main/java/com/replaymod/extras/youtube/YoutubeUpload.java index bd740632..6e1a237e 100644 --- a/src/main/java/com/replaymod/extras/youtube/YoutubeUpload.java +++ b/src/main/java/com/replaymod/extras/youtube/YoutubeUpload.java @@ -3,11 +3,11 @@ package com.replaymod.extras.youtube; import com.replaymod.core.ReplayMod; import com.replaymod.extras.Extra; import com.replaymod.render.gui.GuiRenderingDone; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import de.johni0702.minecraft.gui.container.GuiScreen; import de.johni0702.minecraft.gui.element.GuiButton; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; public class YoutubeUpload implements Extra { @Override diff --git a/src/main/java/com/replaymod/online/ReplayModOnline.java b/src/main/java/com/replaymod/online/ReplayModOnline.java index 44092066..9e455fb7 100644 --- a/src/main/java/com/replaymod/online/ReplayModOnline.java +++ b/src/main/java/com/replaymod/online/ReplayModOnline.java @@ -11,14 +11,14 @@ import com.replaymod.replay.events.ReplayCloseEvent; import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ZipReplayFile; import com.replaymod.replaystudio.studio.ReplayStudio; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import de.johni0702.minecraft.gui.container.GuiScreen; 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.SubscribeEvent; import org.apache.logging.log4j.Logger; import java.io.File; diff --git a/src/main/java/com/replaymod/online/handler/GuiHandler.java b/src/main/java/com/replaymod/online/handler/GuiHandler.java index bf631767..a193e943 100644 --- a/src/main/java/com/replaymod/online/handler/GuiHandler.java +++ b/src/main/java/com/replaymod/online/handler/GuiHandler.java @@ -5,6 +5,8 @@ import com.replaymod.online.gui.GuiLoginPrompt; import com.replaymod.online.gui.GuiReplayCenter; import com.replaymod.online.gui.GuiUploadReplay; import com.replaymod.replay.gui.screen.GuiReplayViewer; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import de.johni0702.minecraft.gui.container.AbstractGuiScreen; import de.johni0702.minecraft.gui.container.GuiPanel; import de.johni0702.minecraft.gui.container.GuiScreen; @@ -14,8 +16,6 @@ import net.minecraft.client.gui.GuiMainMenu; import net.minecraft.client.resources.I18n; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import java.io.File; import java.util.List; diff --git a/src/main/java/com/replaymod/pathing/player/AbstractTimelinePlayer.java b/src/main/java/com/replaymod/pathing/player/AbstractTimelinePlayer.java index 04104787..d099eeb1 100644 --- a/src/main/java/com/replaymod/pathing/player/AbstractTimelinePlayer.java +++ b/src/main/java/com/replaymod/pathing/player/AbstractTimelinePlayer.java @@ -10,9 +10,9 @@ import com.replaymod.replay.ReplayHandler; import com.replaymod.replaystudio.pathing.path.Keyframe; import com.replaymod.replaystudio.pathing.path.Path; import com.replaymod.replaystudio.pathing.path.Timeline; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import net.minecraft.client.Minecraft; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import javax.annotation.Nullable; import java.util.Iterator; diff --git a/src/main/java/com/replaymod/pathing/player/RealtimeTimelinePlayer.java b/src/main/java/com/replaymod/pathing/player/RealtimeTimelinePlayer.java index 4271ddbf..c231c67f 100644 --- a/src/main/java/com/replaymod/pathing/player/RealtimeTimelinePlayer.java +++ b/src/main/java/com/replaymod/pathing/player/RealtimeTimelinePlayer.java @@ -3,6 +3,7 @@ package com.replaymod.pathing.player; import com.google.common.util.concurrent.ListenableFuture; import com.replaymod.replay.ReplayHandler; import com.replaymod.replaystudio.pathing.path.Timeline; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; /** * Timeline player using the system time. @@ -32,6 +33,7 @@ public class RealtimeTimelinePlayer extends AbstractTimelinePlayer { } @Override + @SubscribeEvent // 1.7.10 doesn't yet deal properly with inherited, overridden event handlers public void onTick(ReplayTimer.UpdatedEvent event) { if (secondFrame) { secondFrame = false; diff --git a/src/main/java/com/replaymod/pathing/player/ReplayTimer.java b/src/main/java/com/replaymod/pathing/player/ReplayTimer.java index ca5858ed..62093736 100644 --- a/src/main/java/com/replaymod/pathing/player/ReplayTimer.java +++ b/src/main/java/com/replaymod/pathing/player/ReplayTimer.java @@ -1,9 +1,9 @@ package com.replaymod.pathing.player; import com.replaymod.core.utils.WrappedTimer; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.Event; import net.minecraft.util.Timer; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.eventhandler.Event; /** * Wrapper around the current timer that prevents the timer from advancing by itself. diff --git a/src/main/java/com/replaymod/pathing/properties/SpectatorProperty.java b/src/main/java/com/replaymod/pathing/properties/SpectatorProperty.java index 8bd6ee2e..0af9d093 100644 --- a/src/main/java/com/replaymod/pathing/properties/SpectatorProperty.java +++ b/src/main/java/com/replaymod/pathing/properties/SpectatorProperty.java @@ -8,6 +8,7 @@ import com.replaymod.replaystudio.pathing.property.PropertyPart; import com.replaymod.replaystudio.pathing.property.PropertyParts; import lombok.NonNull; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.world.World; import java.io.IOException; @@ -36,7 +37,9 @@ public class SpectatorProperty extends AbstractProperty { // Lookup entity by id, returns null if an entity with the id does not exists Entity target = world.getEntityByID(value); // Spectate entity, when called with null, returns to camera - handler.spectateEntity(target); + if (target instanceof EntityLivingBase) { + handler.spectateEntity((EntityLivingBase) target); + } } @Override diff --git a/src/main/java/com/replaymod/recording/ReplayModRecording.java b/src/main/java/com/replaymod/recording/ReplayModRecording.java index b2458985..20f872e0 100644 --- a/src/main/java/com/replaymod/recording/ReplayModRecording.java +++ b/src/main/java/com/replaymod/recording/ReplayModRecording.java @@ -4,15 +4,15 @@ import com.replaymod.core.ReplayMod; import com.replaymod.core.utils.Restrictions; import com.replaymod.recording.handler.ConnectionEventHandler; import com.replaymod.recording.packet.PacketListener; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.eventhandler.EventBus; +import cpw.mods.fml.common.network.NetworkRegistry; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandler; import net.minecraft.network.NetworkManager; -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.FMLPreInitializationEvent; -import net.minecraftforge.fml.common.eventhandler.EventBus; -import net.minecraftforge.fml.common.network.NetworkRegistry; import org.apache.logging.log4j.Logger; import org.lwjgl.input.Keyboard; diff --git a/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java b/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java index 775276f8..253f0a28 100644 --- a/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java +++ b/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java @@ -2,14 +2,14 @@ package com.replaymod.recording.gui; import com.replaymod.core.SettingsRegistry; import com.replaymod.recording.Setting; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.Gui; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.resources.I18n; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.lwjgl.opengl.GL11; import static com.replaymod.core.ReplayMod.TEXTURE; import static com.replaymod.core.ReplayMod.TEXTURE_SIZE; @@ -45,8 +45,7 @@ public class GuiRecordingOverlay { FontRenderer fontRenderer = mc.fontRendererObj; fontRenderer.drawString(I18n.format("replaymod.gui.recording").toUpperCase(), 30, 18 - (fontRenderer.FONT_HEIGHT / 2), 0xffffffff); mc.renderEngine.bindTexture(TEXTURE); - GlStateManager.resetColor(); - GlStateManager.enableAlpha(); + GL11.glEnable(GL11.GL_ALPHA_TEST); Gui.drawModalRectWithCustomSizedTexture(10, 10, 58, 20, 16, 16, TEXTURE_SIZE, TEXTURE_SIZE); } } diff --git a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java index ae01e5b7..29602dd6 100755 --- a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java @@ -10,11 +10,10 @@ import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayMetaData; import com.replaymod.replaystudio.replay.ZipReplayFile; import com.replaymod.replaystudio.studio.ReplayStudio; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.network.FMLNetworkEvent; import net.minecraft.client.Minecraft; import net.minecraft.network.NetworkManager; -import net.minecraft.world.WorldType; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientDisconnectionFromServerEvent; import org.apache.logging.log4j.Logger; import java.io.File; @@ -47,10 +46,6 @@ public class ConnectionEventHandler { try { boolean local = networkManager.isLocalChannel(); if (local) { - if (mc.getIntegratedServer().getEntityWorld().getWorldType() == WorldType.DEBUG_WORLD) { - logger.info("Debug World recording is not supported."); - return; - } if(!core.getSettingsRegistry().get(Setting.RECORD_SINGLEPLAYER)) { logger.info("Singleplayer Recording is disabled"); return; @@ -96,14 +91,14 @@ public class ConnectionEventHandler { guiOverlay.register(); core.printInfoToChat("replaymod.chat.recordingstarted"); - } catch(Exception e) { + } catch(Throwable e) { e.printStackTrace(); core.printWarningToChat("replaymod.chat.recordingfailed"); } } @SubscribeEvent - public void onDisconnectedFromServerEvent(ClientDisconnectionFromServerEvent event) { + public void onDisconnectedFromServerEvent(FMLNetworkEvent.ClientDisconnectionFromServerEvent event) { if (packetListener != null) { guiOverlay.unregister(); guiOverlay = null; diff --git a/src/main/java/com/replaymod/recording/handler/FMLHandshakeFilter.java b/src/main/java/com/replaymod/recording/handler/FMLHandshakeFilter.java index 79553b3b..fefc1d68 100644 --- a/src/main/java/com/replaymod/recording/handler/FMLHandshakeFilter.java +++ b/src/main/java/com/replaymod/recording/handler/FMLHandshakeFilter.java @@ -1,8 +1,8 @@ package com.replaymod.recording.handler; +import cpw.mods.fml.common.network.handshake.FMLHandshakeMessage; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; -import net.minecraftforge.fml.common.network.handshake.FMLHandshakeMessage; /** * Filters out all handshake packets that were sent for recording but must @@ -17,7 +17,7 @@ import net.minecraftforge.fml.common.network.handshake.FMLHandshakeMessage; public class FMLHandshakeFilter extends SimpleChannelInboundHandler { @Override protected void channelRead0(ChannelHandlerContext ctx, FMLHandshakeMessage msg) throws Exception { - if (!(msg instanceof FMLHandshakeMessage.RegistryData)) { + if (!(msg instanceof FMLHandshakeMessage.ModIdData)) { // Pass on everything but RegistryData messages ctx.fireChannelRead(msg); } diff --git a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java index 9dfb6f55..c2900f79 100755 --- a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java @@ -1,28 +1,34 @@ package com.replaymod.recording.handler; import com.replaymod.recording.packet.PacketListener; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.PlayerEvent; +import cpw.mods.fml.common.gameevent.TickEvent; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.network.Packet; import net.minecraft.network.PacketBuffer; -import net.minecraft.network.play.server.*; +import net.minecraft.network.play.server.S04PacketEntityEquipment; +import net.minecraft.network.play.server.S0APacketUseBed; +import net.minecraft.network.play.server.S0BPacketAnimation; +import net.minecraft.network.play.server.S0CPacketSpawnPlayer; +import net.minecraft.network.play.server.S0DPacketCollectItem; +import net.minecraft.network.play.server.S12PacketEntityVelocity; import net.minecraft.network.play.server.S14PacketEntity.S17PacketEntityLookMove; +import net.minecraft.network.play.server.S18PacketEntityTeleport; +import net.minecraft.network.play.server.S19PacketEntityHeadLook; +import net.minecraft.network.play.server.S1BPacketEntityAttach; +import net.minecraft.network.play.server.S25PacketBlockBreakAnim; import net.minecraft.server.integrated.IntegratedServer; -import net.minecraft.util.BlockPos; import net.minecraft.util.MathHelper; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.minecart.MinecartInteractEvent; import net.minecraftforge.event.entity.player.PlayerSleepInBedEvent; import net.minecraftforge.event.entity.player.PlayerUseItemEvent; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.PlayerEvent.ItemPickupEvent; -import net.minecraftforge.fml.common.gameevent.TickEvent; -import net.minecraftforge.fml.common.gameevent.TickEvent.PlayerTickEvent; import java.util.Objects; @@ -74,37 +80,11 @@ public class RecordingEventHandler { } private S0CPacketSpawnPlayer spawnPlayer(EntityPlayer player) { - try { - S0CPacketSpawnPlayer packet = new S0CPacketSpawnPlayer(); - - ByteBuf bb = Unpooled.buffer(); - PacketBuffer pb = new PacketBuffer(bb); - - pb.writeVarIntToBuffer(player.getEntityId()); - pb.writeUuid(EntityPlayer.getUUID(player.getGameProfile())); - - pb.writeInt(MathHelper.floor_double(player.posX * 32.0D)); - pb.writeInt(MathHelper.floor_double(player.posY * 32.0D)); - pb.writeInt(MathHelper.floor_double(player.posZ * 32.0D)); - pb.writeByte((byte) ((int) (player.rotationYaw * 256.0F / 360.0F))); - pb.writeByte((byte) ((int) (player.rotationPitch * 256.0F / 360.0F))); - - ItemStack itemstack = player.inventory.getCurrentItem(); - pb.writeShort(itemstack == null ? 0 : Item.getIdFromItem(itemstack.getItem())); - - player.getDataWatcher().writeTo(pb); - - packet.readPacketData(pb); - - return packet; - } catch(Exception e) { - e.printStackTrace(); - return null; - } + return new S0CPacketSpawnPlayer(player); } @SubscribeEvent - public void onPlayerTick(PlayerTickEvent e) { + public void onPlayerTick(TickEvent.PlayerTickEvent e) { try { if(e.player != mc.thePlayer) return; @@ -112,7 +92,7 @@ public class RecordingEventHandler { if(lastX == null || lastY == null || lastZ == null) { force = true; lastX = e.player.posX; - lastY = e.player.posY; + lastY = e.player.boundingBox.minY; lastZ = e.player.posZ; } @@ -123,28 +103,28 @@ public class RecordingEventHandler { } double dx = e.player.posX - lastX; - double dy = e.player.posY - lastY; + double dy = e.player.boundingBox.minY - lastY; double dz = e.player.posZ - lastZ; lastX = e.player.posX; - lastY = e.player.posY; + lastY = e.player.boundingBox.minY; lastZ = e.player.posZ; Packet packet; if(force || Math.abs(dx) > 4.0 || Math.abs(dy) > 4.0 || Math.abs(dz) > 4.0) { int x = MathHelper.floor_double(e.player.posX * 32.0D); - int y = MathHelper.floor_double(e.player.posY * 32.0D); + int y = MathHelper.floor_double(e.player.boundingBox.minY * 32.0D); int z = MathHelper.floor_double(e.player.posZ * 32.0D); byte yaw = (byte) ((int) (e.player.rotationYaw * 256.0F / 360.0F)); byte pitch = (byte) ((int) (e.player.rotationPitch * 256.0F / 360.0F)); - packet = new S18PacketEntityTeleport(e.player.getEntityId(), x, y, z, yaw, pitch, e.player.onGround); + packet = new S18PacketEntityTeleport(e.player.getEntityId(), x, y, z, yaw, pitch); } else { byte newYaw = (byte) ((int) (e.player.rotationYaw * 256.0F / 360.0F)); byte newPitch = (byte) ((int) (e.player.rotationPitch * 256.0F / 360.0F)); packet = new S17PacketEntityLookMove(e.player.getEntityId(), (byte) Math.round(dx * 32), (byte) Math.round(dy * 32), (byte) Math.round(dz * 32), - newYaw, newPitch, e.player.onGround); + newYaw, newPitch); } packetListener.save(packet); @@ -153,16 +133,7 @@ public class RecordingEventHandler { int rotationYawHead = ((int)(e.player.rotationYawHead * 256.0F / 360.0F)); if(!Objects.equals(rotationYawHead, rotationYawHeadBefore)) { - S19PacketEntityHeadLook head = new S19PacketEntityHeadLook(); - ByteBuf bb1 = Unpooled.buffer(); - PacketBuffer pb1 = new PacketBuffer(bb1); - - pb1.writeVarIntToBuffer(e.player.getEntityId()); - pb1.writeByte(rotationYawHead); - - head.readPacketData(pb1); - - packetListener.save(head); + packetListener.save(new S19PacketEntityHeadLook(e.player, (byte) rotationYawHead)); rotationYawHeadBefore = rotationYawHead; } @@ -173,17 +144,7 @@ public class RecordingEventHandler { //Animation Packets //Swing Animation if(e.player.swingProgressInt == 1) { - S0BPacketAnimation pac = new S0BPacketAnimation(); - - ByteBuf bb = Unpooled.buffer(); - PacketBuffer pb = new PacketBuffer(bb); - - pb.writeVarIntToBuffer(e.player.getEntityId()); - pb.writeByte(0); - - pac.readPacketData(pb); - - packetListener.save(pac); + packetListener.save(new S0BPacketAnimation(e.player, 0)); } /* @@ -263,17 +224,7 @@ public class RecordingEventHandler { //Sleeping if(!mc.thePlayer.isPlayerSleeping() && wasSleeping) { - S0BPacketAnimation pac = new S0BPacketAnimation(); - - ByteBuf bb = Unpooled.buffer(); - PacketBuffer pb = new PacketBuffer(bb); - - pb.writeVarIntToBuffer(e.player.getEntityId()); - pb.writeByte(2); - - pac.readPacketData(pb); - - packetListener.save(pac); + packetListener.save(new S0BPacketAnimation(e.player, 2)); wasSleeping = false; } @@ -284,7 +235,7 @@ public class RecordingEventHandler { } @SubscribeEvent - public void onPickupItem(ItemPickupEvent event) { + public void onPickupItem(PlayerEvent.ItemPickupEvent event) { try { packetListener.save(new S0DPacketCollectItem(event.pickedUp.getEntityId(), event.player.getEntityId())); } catch(Exception e) { @@ -294,80 +245,33 @@ public class RecordingEventHandler { @SubscribeEvent public void onStartEating(PlayerUseItemEvent.Start event) { - try { - if(!event.entityPlayer.isEating()) return; - S0BPacketAnimation packet = new S0BPacketAnimation(); - - ByteBuf bb = Unpooled.buffer(); - PacketBuffer pb = new PacketBuffer(bb); - - pb.writeVarIntToBuffer(event.entityPlayer.getEntityId()); - pb.writeByte(3); - - packet.readPacketData(pb); - - packetListener.save(packet); - } catch(Exception e) { - e.printStackTrace(); - } + if(!event.entityPlayer.isEating()) return; + packetListener.save(new S0BPacketAnimation(event.entityPlayer, 3)); } @SubscribeEvent public void onSleep(PlayerSleepInBedEvent event) { - try { - if(event.entityPlayer != mc.thePlayer) { - return; - } - - S0APacketUseBed pub = new S0APacketUseBed(); - - ByteBuf buf = Unpooled.buffer(); - PacketBuffer pbuf = new PacketBuffer(buf); - - pbuf.writeVarIntToBuffer(event.entityPlayer.getEntityId()); - pbuf.writeBlockPos(event.pos); - - pub.readPacketData(pbuf); - - packetListener.save(pub); - - wasSleeping = true; - - } catch(Exception e) { - e.printStackTrace(); + if(event.entityPlayer != mc.thePlayer) { + return; } + + packetListener.save(new S0APacketUseBed(event.entityPlayer, event.x, event.y, event.z)); + wasSleeping = true; } @SubscribeEvent public void enterMinecart(MinecartInteractEvent event) { - try { - if(event.player != mc.thePlayer) { - return; - } - - S1BPacketEntityAttach pea = new S1BPacketEntityAttach(); - - ByteBuf buf = Unpooled.buffer(); - PacketBuffer pbuf = new PacketBuffer(buf); - - pbuf.writeInt(event.player.getEntityId()); - pbuf.writeInt(event.minecart.getEntityId()); - pbuf.writeBoolean(false); - - pea.readPacketData(pbuf); - - packetListener.save(pea); - - lastRiding = event.minecart.getEntityId(); - } catch(Exception e) { - e.printStackTrace(); + if(event.player != mc.thePlayer) { + return; } + packetListener.save(new S1BPacketEntityAttach(0, event.player, event.minecart)); + lastRiding = event.minecart.getEntityId(); } - public void onBlockBreakAnim(int breakerId, BlockPos pos, int progress) { + public void onBlockBreakAnim(int breakerId, int x, int y, int z, int progress) { EntityPlayer thePlayer = mc.thePlayer; if (thePlayer != null && breakerId == thePlayer.getEntityId()) { - packetListener.save(new S25PacketBlockBreakAnim(breakerId, pos, progress)); + packetListener.save(new S25PacketBlockBreakAnim(breakerId, x, y, z, progress)); } } diff --git a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java index 5cbe64bc..55f4e02a 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java @@ -1,8 +1,10 @@ package com.replaymod.recording.mixin; import com.replaymod.recording.ReplayModRecording; +import cpw.mods.fml.common.network.FMLNetworkEvent; import net.minecraft.client.network.NetHandlerLoginClient; import net.minecraft.network.NetworkManager; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -13,15 +15,15 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; public abstract class MixinNetHandlerLoginClient { @Shadow - private NetworkManager networkManager; + private @Final NetworkManager field_147393_d; /** * Starts the recording right before switching into PLAY state. - * We cannot use the {@link net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientConnectedToServerEvent} + * We cannot use the {@link FMLNetworkEvent.ClientConnectedToServerEvent} * as it only fires after the forge handshake. */ @Inject(method = "handleLoginSuccess", at=@At("HEAD")) public void replayModRecording_initiateRecording(CallbackInfo cb) { - ReplayModRecording.instance.initiateRecording(networkManager); + ReplayModRecording.instance.initiateRecording(field_147393_d); } } diff --git a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java index bd5d4a99..a3611573 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java @@ -3,28 +3,20 @@ package com.replaymod.recording.mixin; import com.replaymod.recording.handler.RecordingEventHandler; import net.minecraft.client.Minecraft; import net.minecraft.client.network.NetHandlerPlayClient; -import net.minecraft.client.network.NetworkPlayerInfo; +import net.minecraft.network.play.server.S01PacketJoinGame; import net.minecraft.network.play.server.S07PacketRespawn; -import net.minecraft.network.play.server.S38PacketPlayerListItem; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; 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.List; -import java.util.Map; -import java.util.UUID; - @Mixin(NetHandlerPlayClient.class) public abstract class MixinNetHandlerPlayClient { @Shadow private Minecraft gameController; - @Shadow - private Map playerInfoMap; - public RecordingEventHandler getRecordingEventHandler() { return ((RecordingEventHandler.RecordingEventSender) gameController.renderGlobal).getRecordingEventHandler(); } @@ -32,33 +24,22 @@ public abstract class MixinNetHandlerPlayClient { /** * Record the own player entity joining the world. * We cannot use the {@link net.minecraftforge.event.entity.EntityJoinWorldEvent} because the entity id - * of the player is set afterwards and the tablist entry might not yet be sent. + * of the player is set afterwards * @param packet The packet * @param ci Callback info */ - @Inject(method = "handlePlayerListItem", at=@At("HEAD")) - public void recordOwnJoin(S38PacketPlayerListItem packet, CallbackInfo ci) { - if (gameController.thePlayer == null) return; - + @Inject(method = "handleJoinGame", at=@At("RETURN")) + public void recordOwnJoin(S01PacketJoinGame packet, CallbackInfo ci) { RecordingEventHandler handler = getRecordingEventHandler(); - if (handler != null && packet.func_179768_b() == S38PacketPlayerListItem.Action.ADD_PLAYER) { - @SuppressWarnings("unchecked") - List dataList = packet.func_179767_a(); - for (S38PacketPlayerListItem.AddPlayerData data : dataList) { - if (data.func_179962_a() == null || data.func_179962_a().getId() == null) continue; - // Only add spawn packet for our own player and only if he isn't known yet - if (data.func_179962_a().getId().equals(Minecraft.getMinecraft().thePlayer.getGameProfile().getId()) - && !playerInfoMap.containsKey(data.func_179962_a().getId())) { - handler.onPlayerJoin(); - } - } + if (handler != null) { + handler.onPlayerJoin(); } } /** * Record the own player entity respawning. * We cannot use the {@link net.minecraftforge.event.entity.EntityJoinWorldEvent} because that would also include - * the first spawn which is already handled by {@link #recordOwnJoin(S38PacketPlayerListItem, CallbackInfo)}. + * the first spawn which is already handled by {@link #recordOwnJoin(S01PacketJoinGame, CallbackInfo)}. * @param packet The packet * @param ci Callback info */ diff --git a/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java b/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java index c6e2e4d5..46f87bbf 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java @@ -1,11 +1,11 @@ package com.replaymod.recording.mixin; import com.replaymod.recording.handler.FMLHandshakeFilter; +import cpw.mods.fml.common.network.handshake.FMLHandshakeCodec; +import cpw.mods.fml.common.network.handshake.NetworkDispatcher; +import cpw.mods.fml.relauncher.Side; import io.netty.channel.ChannelPipeline; import io.netty.channel.embedded.EmbeddedChannel; -import net.minecraftforge.fml.common.network.handshake.FMLHandshakeCodec; -import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher; -import net.minecraftforge.fml.relauncher.Side; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/com/replaymod/recording/mixin/MixinRenderGlobal.java b/src/main/java/com/replaymod/recording/mixin/MixinRenderGlobal.java index d9e11de1..07c0eda1 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinRenderGlobal.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinRenderGlobal.java @@ -2,7 +2,6 @@ package com.replaymod.recording.mixin; import com.replaymod.recording.handler.RecordingEventHandler; import net.minecraft.client.renderer.RenderGlobal; -import net.minecraft.util.BlockPos; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -23,10 +22,10 @@ public abstract class MixinRenderGlobal implements RecordingEventHandler.Recordi return recordingEventHandler; } - @Inject(method = "sendBlockBreakProgress", at = @At("HEAD")) - public void saveBlockBreakProgressPacket(int breakerId, BlockPos pos, int progress, CallbackInfo info) { + @Inject(method = "destroyBlockPartially", at = @At("HEAD")) + public void saveBlockBreakProgressPacket(int breakerId, int x, int y, int z, int progress, CallbackInfo info) { if (recordingEventHandler != null) { - recordingEventHandler.onBlockBreakAnim(breakerId, pos, progress); + recordingEventHandler.onBlockBreakAnim(breakerId, x, y, z, progress); } } } diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index 2d051c56..f0a5d216 100755 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -4,6 +4,7 @@ import com.replaymod.core.utils.Restrictions; import com.replaymod.replaystudio.data.Marker; import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayMetaData; +import cpw.mods.fml.common.network.internal.FMLProxyPacket; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; @@ -12,12 +13,10 @@ import net.minecraft.client.Minecraft; import net.minecraft.entity.DataWatcher; import net.minecraft.entity.Entity; import net.minecraft.network.EnumConnectionState; -import net.minecraft.network.EnumPacketDirection; import net.minecraft.network.Packet; import net.minecraft.network.PacketBuffer; import net.minecraft.network.play.server.*; import net.minecraft.util.ChatComponentText; -import net.minecraftforge.fml.common.network.internal.FMLProxyPacket; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -85,15 +84,12 @@ public class PacketListener extends ChannelInboundHandlerAdapter { public void save(Packet packet) { try { if(packet instanceof S0CPacketSpawnPlayer) { - UUID uuid = ((S0CPacketSpawnPlayer) packet).func_179819_c(); + UUID uuid = ((S0CPacketSpawnPlayer) packet).field_148955_b.getId(); Set uuids = new HashSet<>(Arrays.asList(metaData.getPlayers())); uuids.add(uuid.toString()); metaData.setPlayers(uuids.toArray(new String[uuids.size()])); saveMetaData(); } - if (packet instanceof S46PacketSetCompressionLevel) { - return; // Replay data is never compressed on the packet level - } byte[] bytes = getPacketData(packet); long now = System.currentTimeMillis(); @@ -162,14 +158,17 @@ public class PacketListener extends ChannelInboundHandlerAdapter { } } - if (packet instanceof S48PacketResourcePackSend) { - save(resourcePackRecorder.handleResourcePack((S48PacketResourcePackSend) packet)); - return; + if (packet instanceof S3FPacketCustomPayload) { + S3FPacketCustomPayload p = (S3FPacketCustomPayload) packet; + if ("MC|RPack".equals(p.func_149169_c())) { + save(resourcePackRecorder.handleResourcePack(p)); + return; + } } if (packet instanceof FMLProxyPacket) { // This packet requires special handling - ((FMLProxyPacket) packet).toS3FPackets().forEach(this::save); + save(((FMLProxyPacket) packet).toS3FPacket()); super.channelRead(ctx, msg); return; } @@ -178,7 +177,7 @@ public class PacketListener extends ChannelInboundHandlerAdapter { if (packet instanceof S3FPacketCustomPayload) { S3FPacketCustomPayload p = (S3FPacketCustomPayload) packet; - if (Restrictions.PLUGIN_CHANNEL.equals(p.getChannelName())) { + if (Restrictions.PLUGIN_CHANNEL.equals(p.func_149169_c())) { packet = new S40PacketDisconnect(new ChatComponentText("Please update to view this replay.")); save(packet); } @@ -218,7 +217,7 @@ public class PacketListener extends ChannelInboundHandlerAdapter { } } - Integer packetId = EnumConnectionState.PLAY.getPacketId(EnumPacketDirection.CLIENTBOUND, packet); + Integer packetId = (Integer) EnumConnectionState.PLAY.func_150755_b().inverse().get(packet.getClass()); if (packetId == null) { throw new IOException("Unknown packet type:" + packet.getClass()); } @@ -236,7 +235,7 @@ public class PacketListener extends ChannelInboundHandlerAdapter { } public void addMarker() { - Entity view = Minecraft.getMinecraft().getRenderViewEntity(); + Entity view = Minecraft.getMinecraft().renderViewEntity; int timestamp = (int) (System.currentTimeMillis() - startTime); Marker marker = new Marker(); diff --git a/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java b/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java index ed5cfc7f..08f06f4a 100644 --- a/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java +++ b/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java @@ -2,28 +2,23 @@ package com.replaymod.recording.packet; import com.google.common.hash.Hashing; import com.google.common.io.Files; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; import com.replaymod.replaystudio.replay.ReplayFile; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreenWorking; import net.minecraft.client.gui.GuiYesNo; import net.minecraft.client.gui.GuiYesNoCallback; import net.minecraft.client.multiplayer.ServerData; +import net.minecraft.client.multiplayer.ServerData.ServerResourceMode; import net.minecraft.client.multiplayer.ServerList; -import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.client.resources.FileResourcePack; import net.minecraft.client.resources.I18n; import net.minecraft.client.resources.ResourcePackRepository; -import net.minecraft.network.NetworkManager; -import net.minecraft.network.play.client.C19PacketResourcePackStatus; -import net.minecraft.network.play.server.S48PacketResourcePackSend; +import net.minecraft.network.play.server.S3FPacketCustomPayload; import net.minecraft.util.HttpUtil; -import org.apache.commons.io.FileUtils; +import org.apache.commons.io.Charsets; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; import java.io.OutputStream; @@ -75,145 +70,75 @@ public class ResourcePackRecorder { } } - public synchronized S48PacketResourcePackSend handleResourcePack(S48PacketResourcePackSend packet) { + public synchronized S3FPacketCustomPayload handleResourcePack(S3FPacketCustomPayload packet) { final int requestId = nextRequestId++; - final NetHandlerPlayClient netHandler = mc.getNetHandler(); - final NetworkManager netManager = netHandler.getNetworkManager(); - final String url = packet.func_179783_a(); - final String hash = packet.func_179784_b(); - - if (url.startsWith("level://")) { - String levelName = url.substring("level://".length()); - File savesDir = new File(mc.mcDataDir, "saves"); - final File levelDir = new File(savesDir, levelName); - - if (levelDir.isFile()) { - netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.ACCEPTED)); - Futures.addCallback(mc.getResourcePackRepository().func_177319_a(levelDir), new FutureCallback() { - @Override - public void onSuccess(Object result) { - recordResourcePack(levelDir, requestId); - netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.SUCCESSFULLY_LOADED)); - } - - @Override - public void onFailure(@Nonnull Throwable throwable) { - netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.FAILED_DOWNLOAD)); - } - }); - } else { - netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.FAILED_DOWNLOAD)); - } - } else { - final ServerData serverData = mc.getCurrentServerData(); - if (serverData != null && serverData.getResourceMode() == ServerData.ServerResourceMode.ENABLED) { - netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.ACCEPTED)); - downloadResourcePackFuture(requestId, url, hash); - } else if (serverData != null && serverData.getResourceMode() != ServerData.ServerResourceMode.PROMPT) { - netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.DECLINED)); - } else { - // Lambdas MUST NOT be used with methods that need re-obfuscation in FG prior to 2.2 (will result in AbstractMethodError) - //noinspection Convert2Lambda - mc.addScheduledTask(() -> mc.displayGuiScreen(new GuiYesNo(new GuiYesNoCallback() { - @Override - public void confirmClicked(boolean result, int id) { - if (serverData != null) { - serverData.setResourceMode(result ? ServerData.ServerResourceMode.ENABLED : ServerData.ServerResourceMode.DISABLED); - } - if (result) { - netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.ACCEPTED)); - ResourcePackRecorder.this.downloadResourcePackFuture(requestId, url, hash); - } else { - netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.DECLINED)); - } + final String url = new String(packet.func_149168_d(), Charsets.UTF_8); + ServerData serverData = mc.getCurrentServerData(); + ServerResourceMode resourceMode = serverData == null ? ServerResourceMode.PROMPT : serverData.getResourceMode(); + if (resourceMode == ServerResourceMode.ENABLED) { + downloadResourcePack(requestId, url); + mc.getResourcePackRepository().obtainResourcePack(url); + } else if (resourceMode == ServerResourceMode.PROMPT) { + // Lambdas MUST NOT be used with methods that need re-obfuscation in FG prior to 2.2 (will result in AbstractMethodError) + //noinspection Convert2Lambda + mc.displayGuiScreen(new GuiYesNo(new GuiYesNoCallback() { + @Override + public void confirmClicked(boolean result, int id) { + if (serverData != null) { + serverData.setResourceMode(ServerResourceMode.ENABLED); ServerList.func_147414_b(serverData); - mc.displayGuiScreen(null); } - }, I18n.format("multiplayer.texturePrompt.line1"), I18n.format("multiplayer.texturePrompt.line2"), 0))); - } + + mc.displayGuiScreen(null); + + if (result) { + downloadResourcePack(requestId, url); + } + } + }, I18n.format("multiplayer.texturePrompt.line1"), I18n.format("multiplayer.texturePrompt.line2"), 0)); } - return new S48PacketResourcePackSend("replay://" + requestId, ""); + return new S3FPacketCustomPayload(packet.func_149169_c(), ("replay://" + requestId).getBytes(Charsets.UTF_8)); } - private void downloadResourcePackFuture(int requestId, String url, final String hash) { - Futures.addCallback(downloadResourcePack(requestId, url, hash), new FutureCallback() { - @Override - public void onSuccess(Object result) { - mc.getNetHandler().addToSendQueue(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.SUCCESSFULLY_LOADED)); - } - - @Override - public void onFailure(@Nonnull Throwable throwable) { - mc.getNetHandler().addToSendQueue(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.FAILED_DOWNLOAD)); - } - }); - } - - private ListenableFuture downloadResourcePack(final int requestId, String url, String hash) { + private void downloadResourcePack(final int requestId, String url) { final ResourcePackRepository repo = mc.mcResourcePackRepository; - String fileName; - if (hash.matches("^[a-f0-9]{40}$")) { - fileName = hash; - } else { - fileName = url.substring(url.lastIndexOf("/") + 1); - if (fileName.contains("?")) { - fileName = fileName.substring(0, fileName.indexOf("?")); - } + String fileName = url.substring(url.lastIndexOf("/") + 1); - if (!fileName.endsWith(".zip")) { - return Futures.immediateFailedFuture(new IllegalArgumentException("Invalid filename; must end in .zip")); - } - - fileName = "legacy_" + fileName.replaceAll("\\W", ""); + if (fileName.contains("?")) { + fileName = fileName.substring(0, fileName.indexOf("?")); } - final File file = new File(repo.dirServerResourcepacks, fileName); - repo.field_177321_h.lock(); - try { - repo.func_148529_f(); + if (!fileName.endsWith(".zip")) { + return; + } - if (file.exists() && hash.length() == 40) { - try { - String fileHash = Hashing.sha1().hashBytes(Files.toByteArray(file)).toString(); - if (fileHash.equals(hash)) { - recordResourcePack(file, requestId); - return repo.func_177319_a(file); - } + fileName = fileName.replaceAll("\\W", ""); - logger.warn("File " + file + " had wrong hash (expected " + hash + ", found " + fileHash + "). Deleting it."); - FileUtils.deleteQuietly(file); - } catch (IOException ioexception) { - logger.warn("File " + file + " couldn\'t be hashed. Deleting it.", ioexception); - FileUtils.deleteQuietly(file); - } - } + File file = new File(repo.field_148534_e, fileName); - final GuiScreenWorking guiScreen = new GuiScreenWorking(); - final Minecraft mc = Minecraft.getMinecraft(); + HashMap hashmap = new HashMap<>(); + hashmap.put("X-Minecraft-Username", mc.getSession().getUsername()); + hashmap.put("X-Minecraft-UUID", mc.getSession().getPlayerID()); + hashmap.put("X-Minecraft-Version", "1.7.10"); - Futures.getUnchecked(mc.addScheduledTask(() -> mc.displayGuiScreen(guiScreen))); - - Map sessionInfo = Minecraft.getSessionInfo(); - repo.field_177322_i = HttpUtil.func_180192_a(file, url, sessionInfo, 50 * 1024 * 1024, guiScreen, mc.getProxy()); - Futures.addCallback(repo.field_177322_i, new FutureCallback() { - @Override - public void onSuccess(Object value) { + GuiScreenWorking guiScreen = new GuiScreenWorking(); + Minecraft.getMinecraft().displayGuiScreen(guiScreen); + repo.func_148529_f(); + repo.field_148533_g = true; + // Lambdas MUST NOT be used with methods that need re-obfuscation in FG prior to 2.2 (will result in AbstractMethodError) + //noinspection Convert2Lambda + HttpUtil.downloadResourcePack(file, url, new HttpUtil.DownloadListener() { + public void onDownloadComplete(File file) { + if (repo.field_148533_g) { + repo.field_148533_g = false; + repo.field_148532_f = new FileResourcePack(file); + Minecraft.getMinecraft().scheduleResourcesRefresh(); recordResourcePack(file, requestId); - repo.func_177319_a(file); } - - @Override - public void onFailure(@Nonnull Throwable throwable) { - throwable.printStackTrace(); - } - }); - return repo.field_177322_i; - } finally { - repo.field_177321_h.unlock(); - } + } + }, hashmap, 50*1024*1024, guiScreen, Minecraft.getMinecraft().getProxy()); } - } diff --git a/src/main/java/com/replaymod/render/ReplayModRender.java b/src/main/java/com/replaymod/render/ReplayModRender.java index 6b7f3668..92646e0d 100644 --- a/src/main/java/com/replaymod/render/ReplayModRender.java +++ b/src/main/java/com/replaymod/render/ReplayModRender.java @@ -3,13 +3,13 @@ package com.replaymod.render; import com.replaymod.core.ReplayMod; import com.replaymod.render.utils.RenderJob; import com.replaymod.replay.events.ReplayCloseEvent; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import net.minecraft.crash.CrashReport; import net.minecraft.util.ReportedException; import net.minecraftforge.common.config.Configuration; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.apache.commons.io.FileUtils; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/com/replaymod/render/VideoWriter.java b/src/main/java/com/replaymod/render/VideoWriter.java index 08ddb9e4..5a4b6094 100755 --- a/src/main/java/com/replaymod/render/VideoWriter.java +++ b/src/main/java/com/replaymod/render/VideoWriter.java @@ -5,11 +5,11 @@ import com.replaymod.render.rendering.FrameConsumer; import com.replaymod.render.rendering.VideoRenderer; import com.replaymod.render.utils.ByteBufferPool; import com.replaymod.render.utils.StreamPipe; +import cpw.mods.fml.common.versioning.ComparableVersion; import net.minecraft.client.Minecraft; import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; import net.minecraft.util.Util; -import net.minecraftforge.fml.common.versioning.ComparableVersion; import org.apache.commons.exec.CommandLine; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; diff --git a/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java b/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java index 01a480f0..80cf39c9 100644 --- a/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java +++ b/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java @@ -4,10 +4,10 @@ import com.replaymod.render.RenderSettings; import com.replaymod.render.frame.CubicOpenGlFrame; import com.replaymod.render.frame.ODSOpenGlFrame; import com.replaymod.render.frame.OpenGlFrame; +import com.replaymod.render.hooks.GLStateTracker; import com.replaymod.render.rendering.FrameCapturer; import com.replaymod.render.shader.Program; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.crash.CrashReport; import net.minecraft.util.ReportedException; import net.minecraft.util.ResourceLocation; @@ -15,9 +15,13 @@ import org.lwjgl.util.ReadableDimension; import java.io.IOException; -import static net.minecraft.client.renderer.GlStateManager.*; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; +import static org.lwjgl.opengl.GL11.glClear; +import static org.lwjgl.opengl.GL11.glEnable; +import static org.lwjgl.opengl.GL11.glPopMatrix; +import static org.lwjgl.opengl.GL11.glPushMatrix; public class ODSFrameCapturer implements FrameCapturer { private static final ResourceLocation vertexResource = new ResourceLocation("replaymod", "shader/ods.vert"); @@ -28,8 +32,8 @@ public class ODSFrameCapturer implements FrameCapturer { private final Program.Uniform directionVariable; private final Program.Uniform leftEyeVariable; - private final BooleanState[] previousStates = new BooleanState[3]; - private final BooleanState previousFogState; + private final GLStateTracker.EnabledState[] previousStates = new GLStateTracker.EnabledState[2]; + private final GLStateTracker.EnabledState previousFogState; private final Minecraft mc = Minecraft.getMinecraft(); @@ -42,6 +46,11 @@ public class ODSFrameCapturer implements FrameCapturer { return renderInfo.getFrameSize(); } + @Override + public int getFramesDone() { + return renderInfo.getFramesDone(); + } + @Override public int getTotalFrames() { return renderInfo.getTotalFrames(); @@ -73,15 +82,14 @@ public class ODSFrameCapturer implements FrameCapturer { setTexture("lightMap", 1); linkState(0, "textureEnabled"); linkState(1, "lightMapEnabled"); - linkState(2, "hurtTextureEnabled"); final Program.Uniform uniform = shaderProgram.getUniformVariable("fogEnabled"); - previousFogState = GlStateManager.fogState.field_179049_a; - uniform.set(previousFogState.currentState); - GlStateManager.fogState.field_179049_a = new BooleanState(previousFogState.capability) { + previousFogState = GLStateTracker.getInstance().fog; + uniform.set(previousFogState.isEnabled()); + GLStateTracker.getInstance().fog = new GLStateTracker.EnabledState() { @Override - public void setState(boolean state) { - super.setState(state); - uniform.set(state); + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + uniform.set(enabled); } }; shaderProgram.stopUsing(); @@ -96,13 +104,13 @@ public class ODSFrameCapturer implements FrameCapturer { private void linkState(int id, String var) { final Program.Uniform uniform = shaderProgram.getUniformVariable(var); - previousStates[id] = GlStateManager.textureState[id].texture2DState; - uniform.set(previousStates[id].currentState); - GlStateManager.textureState[id].texture2DState = new BooleanState(previousStates[id].capability) { + previousStates[id] = GLStateTracker.getInstance().texture[id]; + uniform.set(previousStates[id].isEnabled()); + GLStateTracker.getInstance().texture[id] = new GLStateTracker.EnabledState() { @Override - public void setState(boolean state) { - super.setState(state); - uniform.set(state); + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + uniform.set(enabled); } }; } @@ -132,10 +140,10 @@ public class ODSFrameCapturer implements FrameCapturer { left.close(); right.close(); shaderProgram.delete(); - for (int i = 0; i < 3; i++) { - GlStateManager.textureState[i].texture2DState = previousStates[i]; + for (int i = 0; i < previousStates.length; i++) { + GLStateTracker.getInstance().texture[i] = previousStates[i]; } - GlStateManager.fogState.field_179049_a = previousFogState; + GLStateTracker.getInstance().fog = previousFogState; } private class CubicStereoFrameCapturer extends CubicPboOpenGlFrameCapturer { @@ -147,17 +155,17 @@ public class ODSFrameCapturer implements FrameCapturer { protected OpenGlFrame renderFrame(int frameId, float partialTicks, CubicOpenGlFrameCapturer.Data captureData) { resize(getFrameWidth(), getFrameHeight()); - pushMatrix(); + glPushMatrix(); frameBuffer().bindFramebuffer(true); - clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - enableTexture2D(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_TEXTURE_2D); directionVariable.set(captureData.ordinal()); worldRenderer.renderWorld(partialTicks, null); frameBuffer().unbindFramebuffer(); - popMatrix(); + glPopMatrix(); return captureFrame(frameId, captureData); } diff --git a/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java b/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java index d0968582..c682e919 100644 --- a/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java +++ b/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java @@ -15,9 +15,9 @@ import org.lwjgl.util.WritableDimension; import java.io.IOException; import java.nio.ByteBuffer; -import static net.minecraft.client.renderer.GlStateManager.*; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; public abstract class OpenGlFrameCapturer implements FrameCapturer { protected final WorldRenderer worldRenderer; @@ -76,16 +76,16 @@ public abstract class OpenGlFrameCapturer workerJailingQueue; - private final CustomChunkRenderWorker renderWorker; - private int frame; - - @SuppressWarnings("unchecked") - public ChunkLoadingRenderGlobal(RenderGlobal renderGlobal) { - this.hooked = renderGlobal; - this.renderDispatcher = renderGlobal.renderDispatcher; - this.renderWorker = new CustomChunkRenderWorker(renderDispatcher, new RegionRenderCacheBuilder()); - - int workerThreads = renderDispatcher.listThreadedWorkers.size(); - BlockingQueue queueChunkUpdates = renderDispatcher.queueChunkUpdates; - workerJailingQueue = new JailingQueue<>(queueChunkUpdates); - renderDispatcher.queueChunkUpdates = workerJailingQueue; - ChunkCompileTaskGenerator element = new ChunkCompileTaskGenerator(null, null); - element.finish(); - for (int i = 0; i < workerThreads; i++) { - queueChunkUpdates.add(element); - } - - // Temporary workaround for dead lock, will be replaced by a new (ShaderMod compatible) mechanism later - //noinspection StatementWithEmptyBody - while (renderDispatcher.runChunkUploads(0)) {} - - workerJailingQueue.jail(workerThreads); - renderDispatcher.queueChunkUpdates = queueChunkUpdates; - - try { - Field hookField = RenderGlobal.class.getField("replayModRender_hook"); - hookField.set(hooked, this); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new Error(e); - } - } - - @SuppressWarnings("unchecked") - public void updateChunks() { - while (renderDispatcher.runChunkUploads(0)) { - hooked.displayListEntitiesDirty = true; - } - - while (!renderDispatcher.queueChunkUpdates.isEmpty()) { - try { - renderWorker.processTask((ChunkCompileTaskGenerator) renderDispatcher.queueChunkUpdates.poll()); - } catch (InterruptedException ignored) { } - } - - Iterator iterator = hooked.chunksToUpdate.iterator(); - while (iterator.hasNext()) { - RenderChunk renderchunk = iterator.next(); - - renderDispatcher.updateChunkNow(renderchunk); - - renderchunk.setNeedsUpdate(false); - iterator.remove(); - } - } - - public void uninstall() { - workerJailingQueue.freeAll(); - - try { - Field hookField = RenderGlobal.class.getField("replayModRender_hook"); - hookField.set(hooked, null); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new Error(e); - } - } - - public int nextFrameId() { - return frame++; - } - - /** - * Custom ChunkRenderWorker class providing access to the protected processTask method - */ - private static class CustomChunkRenderWorker extends ChunkRenderWorker { - public CustomChunkRenderWorker(ChunkRenderDispatcher p_i46202_1_, RegionRenderCacheBuilder p_i46202_2_) { - super(p_i46202_1_, p_i46202_2_); - } - - @Override - protected void processTask(ChunkCompileTaskGenerator p_178474_1_) throws InterruptedException { - super.processTask(p_178474_1_); - } - } -} diff --git a/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java b/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java index f27ada50..42ecaa5c 100644 --- a/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java +++ b/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java @@ -2,11 +2,12 @@ package com.replaymod.render.hooks; import com.replaymod.render.RenderSettings; import com.replaymod.render.capturer.CaptureData; +import com.replaymod.render.capturer.RenderInfo; import com.replaymod.render.capturer.WorldRenderer; +import cpw.mods.fml.common.FMLCommonHandler; import lombok.Getter; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraftforge.fml.common.FMLCommonHandler; +import org.lwjgl.opengl.GL11; import java.io.IOException; @@ -16,12 +17,16 @@ public class EntityRendererHandler implements WorldRenderer { @Getter protected final RenderSettings settings; + @Getter + private final RenderInfo renderInfo; + public CaptureData data; public boolean omnidirectional; - public EntityRendererHandler(RenderSettings settings) { + public EntityRendererHandler(RenderSettings settings, RenderInfo renderInfo) { this.settings = settings; + this.renderInfo = renderInfo; ((IEntityRenderer) mc.entityRenderer).replayModRender_setHandler(this); } @@ -37,11 +42,11 @@ public class EntityRendererHandler implements WorldRenderer { mc.entityRenderer.updateLightmap(partialTicks); - GlStateManager.enableDepth(); - GlStateManager.enableAlpha(); - GlStateManager.alphaFunc(516, 0.5F); + GL11.glEnable(GL11.GL_DEPTH_TEST); + GL11.glEnable(GL11.GL_ALPHA_TEST); + GL11.glAlphaFunc(516, 0.5F); - mc.entityRenderer.renderWorldPass(2, partialTicks, finishTimeNano); + mc.entityRenderer.renderWorld(partialTicks, finishTimeNano); FMLCommonHandler.instance().onRenderTickEnd(partialTicks); } diff --git a/src/main/java/com/replaymod/render/hooks/GLStateTracker.java b/src/main/java/com/replaymod/render/hooks/GLStateTracker.java new file mode 100644 index 00000000..3b6795d2 --- /dev/null +++ b/src/main/java/com/replaymod/render/hooks/GLStateTracker.java @@ -0,0 +1,63 @@ +package com.replaymod.render.hooks; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; + +/** + * Tracks OpenGL state for use in the ODS shader. + * All methods should be called from the GL mixins only. + */ +public class GLStateTracker { + private static ThreadLocal stateTracker = ThreadLocal.withInitial(GLStateTracker::new); + public static GLStateTracker getInstance() { + return stateTracker.get(); + } + + public int activeTexture; + public EnabledState fog = new EnabledState(); + public EnabledState[] texture = new EnabledState[32]; + { + for (int i = 0; i < texture.length; i++) { + texture[i] = new EnabledState(); + } + } + + public void updateActiveTexture(int magic) { + this.activeTexture = magic - GL13.GL_TEXTURE0; + } + + public void updateEnabledState(int magic, boolean enabled) { + switch (magic) { + case GL11.GL_FOG: fog.setEnabled(enabled); break; + case GL11.GL_TEXTURE_2D: texture[activeTexture].setEnabled(enabled); break; + } + } + + public static class EnabledState { + private boolean enabled; + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isEnabled() { + return enabled; + } + } + + // Called via ASM (see GLStateTrackerTransformer) + @Deprecated + @SuppressWarnings("unused") + public static void hook_glEnable(int magic) { + GL11.glEnable(magic); + getInstance().updateEnabledState(magic, true); + } + + // Called via ASM (see GLStateTrackerTransformer) + @Deprecated + @SuppressWarnings("unused") + public static void hook_glDisable(int magic) { + GL11.glDisable(magic); + getInstance().updateEnabledState(magic, false); + } +} diff --git a/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java b/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java index eb9deb08..15839203 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java +++ b/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java @@ -4,7 +4,7 @@ import com.replaymod.render.hooks.EntityRendererHandler; import net.minecraft.client.Minecraft; import net.minecraft.client.particle.EffectRenderer; import net.minecraft.client.particle.EntityFX; -import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.Tessellator; import net.minecraft.entity.Entity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -12,22 +12,23 @@ import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(EffectRenderer.class) public abstract class MixinEffectRenderer { - @Redirect(method = "renderParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;func_180434_a(Lnet/minecraft/client/renderer/WorldRenderer;Lnet/minecraft/entity/Entity;FFFFFF)V")) - private void renderNormalParticle(EntityFX fx, WorldRenderer worldRenderer, Entity view, float partialTicks, + @Redirect(method = "renderParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;renderParticle(Lnet/minecraft/client/renderer/Tesselator;FFFFFF)V")) + private void renderNormalParticle(EntityFX fx, Tessellator tesselator, float partialTicks, float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) { - renderParticle(fx, worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); + renderParticle(fx, tesselator, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); } - @Redirect(method = "renderLitParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;func_180434_a(Lnet/minecraft/client/renderer/WorldRenderer;Lnet/minecraft/entity/Entity;FFFFFF)V")) - private void renderLitParticle(EntityFX fx, WorldRenderer worldRenderer, Entity view, float partialTicks, + @Redirect(method = "renderLitParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;renderParticle(Lnet/minecraft/client/renderer/Tesselator;FFFFFF)V")) + private void renderLitParticle(EntityFX fx, Tessellator tesselator, float partialTicks, float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) { - renderParticle(fx, worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); + renderParticle(fx, tesselator, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); } - private void renderParticle(EntityFX fx, WorldRenderer worldRenderer, Entity view, float partialTicks, - float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) { + private void renderParticle(EntityFX fx, Tessellator tessellator, float partialTicks, + float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) { EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) Minecraft.getMinecraft().entityRenderer).replayModRender_getHandler(); if (handler != null && handler.omnidirectional) { + Entity view = Minecraft.getMinecraft().renderViewEntity; // Align all particles towards the camera double dx = fx.prevPosX + (fx.posX - fx.prevPosX) * partialTicks - view.posX; double dy = fx.prevPosY + (fx.posY - fx.prevPosY) * partialTicks - view.posY; @@ -42,6 +43,6 @@ public abstract class MixinEffectRenderer { rotYZ = (float) (-rotZ * Math.sin(pitch)); rotXY = (float) (rotX * Math.sin(pitch)); } - fx.func_180434_a(worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); + fx.renderParticle(tessellator, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); } } diff --git a/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java b/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java index f3711094..7ed76096 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java +++ b/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java @@ -7,10 +7,10 @@ import com.replaymod.render.hooks.EntityRendererHandler; import com.replaymod.replay.camera.CameraEntity; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.EntityRenderer; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.settings.GameSettings; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.MovingObjectPosition; import org.lwjgl.opengl.GL11; @@ -40,6 +40,15 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti return replayModRender_handler; } + @Redirect(method = "renderWorld", at = @At(value = "INVOKE",target = + "Lnet/minecraft/client/renderer/RenderGlobal;updateRenderers(Lnet/minecraft/entity/EntityLivingBase;Z)Z")) + private boolean replayModRender_updateAllChunks(RenderGlobal self, EntityLivingBase view, boolean renderAllChunks) { + if (replayModRender_handler != null) { + renderAllChunks = true; + } + return self.updateRenderers(view, renderAllChunks); + } + @Inject(method = "setupFog", at = @At("HEAD"), cancellable = true) private void replayModRender_onSetupFog(int fogDistanceFlag, float partialTicks, CallbackInfo ci) { if (replayModRender_handler == null) return; @@ -51,7 +60,7 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti @Inject(method = "orientCamera", at = @At("HEAD")) private void replayModRender_resetRotationIfNeeded(float partialTicks, CallbackInfo ci) { if (replayModRender_handler != null) { - Entity entity = Minecraft.getMinecraft().getRenderViewEntity(); + Entity entity = Minecraft.getMinecraft().renderViewEntity; RenderSettings settings = replayModRender_handler.getSettings(); if (settings.isStabilizeYaw()) { entity.prevRotationYaw = entity.rotationYaw = 0; @@ -74,7 +83,7 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti @Inject(method = "setupCameraTransform", at = @At("HEAD")) private void replayModRender_beforeSetupCameraTransform(float partialTicks, int renderPass, CallbackInfo ci) { if (replayModRender_handler != null) { - Entity entity = Minecraft.getMinecraft().getRenderViewEntity(); + Entity entity = Minecraft.getMinecraft().renderViewEntity; orgYaw = entity.rotationYaw; orgPitch = entity.rotationPitch; orgPrevYaw = entity.prevRotationYaw; @@ -86,7 +95,7 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti @Inject(method = "setupCameraTransform", at = @At("RETURN")) private void replayModRender_afterSetupCameraTransform(float partialTicks, int renderPass, CallbackInfo ci) { if (replayModRender_handler != null) { - Entity entity = Minecraft.getMinecraft().getRenderViewEntity(); + Entity entity = Minecraft.getMinecraft().renderViewEntity; entity.rotationYaw = orgYaw; entity.rotationPitch = orgPitch; entity.prevRotationYaw = orgPrevYaw; @@ -104,7 +113,7 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti ci.cancel(); return; // No spectator hands during 360° view, we wouldn't even know where to put it } - Entity currentEntity = Minecraft.getMinecraft().getRenderViewEntity(); + Entity currentEntity = Minecraft.getMinecraft().renderViewEntity; if (currentEntity instanceof EntityPlayer && !(currentEntity instanceof CameraEntity)) { if (renderPass == 2) { // Need to update render pass renderPass = replayModRender_handler.data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE ? 1 : 0; @@ -118,7 +127,7 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti @Shadow public abstract void renderHand(float partialTicks, int renderPass); - @Redirect(method = "renderWorldPass", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;drawSelectionBox(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MovingObjectPosition;IF)V")) + @Redirect(method = "renderWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;drawSelectionBox(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MovingObjectPosition;IF)V")) private void replayModRender_drawSelectionBox(RenderGlobal instance, EntityPlayer player, MovingObjectPosition mop, int alwaysZero, float partialTicks) { if (replayModRender_handler == null) { instance.drawSelectionBox(player, mop, alwaysZero, partialTicks); @@ -127,7 +136,8 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti private int orgRenderDistanceChunks; - @Inject(method = "renderWorldPass", at = @At(value = "JUMP", ordinal = 0)) + @Inject(method = "renderWorld", at = @At(value = "INVOKE", ordinal = 0, shift = At.Shift.AFTER, + target = "Lnet/minecraft/client/renderer/culling/ClippingHelperImpl;getInstance()Lnet/minecraft/client/renderer/culling/ClippingHelper;")) private void replayModRender_beforeRenderSky(CallbackInfo ci) { if (replayModRender_handler != null && replayModRender_handler.getSettings().getChromaKeyingColor() != null) { GameSettings settings = Minecraft.getMinecraft().gameSettings; @@ -136,15 +146,15 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti } } - @Redirect(method = "renderWorldPass", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;renderSky(FI)V")) - private void replayModRender_renderSky(RenderGlobal instance, float partialTicks, int renderPass) { + @Redirect(method = "renderWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;renderSky(F)V")) + private void replayModRender_renderSky(RenderGlobal instance, float partialTicks) { if (replayModRender_handler != null && replayModRender_handler.getSettings().getChromaKeyingColor() != null) { Minecraft.getMinecraft().gameSettings.renderDistanceChunks = orgRenderDistanceChunks; ReadableColor color = replayModRender_handler.getSettings().getChromaKeyingColor(); - GlStateManager.clearColor(color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, 1); - GlStateManager.clear(GL11.GL_COLOR_BUFFER_BIT); + GL11.glClearColor(color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, 1); + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); } else { - instance.renderSky(partialTicks, renderPass); + instance.renderSky(partialTicks); } } @@ -152,24 +162,24 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti * Stereoscopic Renderer */ - @Inject(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;loadIdentity()V", shift = At.Shift.AFTER, ordinal = 0)) + @Inject(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glLoadIdentity()V", shift = At.Shift.AFTER, ordinal = 0, remap = false)) private void replayModRender_setupStereoscopicProjection(float partialTicks, int renderPass, CallbackInfo ci) { if (replayModRender_getHandler() != null) { if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE) { - GlStateManager.translate(0.07, 0, 0); + GL11.glTranslatef(0.07f, 0, 0); } else if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.RIGHT_EYE) { - GlStateManager.translate(-0.07, 0, 0); + GL11.glTranslatef(-0.07f, 0, 0); } } } - @Inject(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;loadIdentity()V", shift = At.Shift.AFTER, ordinal = 1)) + @Inject(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glLoadIdentity()V", shift = At.Shift.AFTER, ordinal = 1, remap = false)) private void replayModRender_setupStereoscopicModelView(float partialTicks, int renderPass, CallbackInfo ci) { if (replayModRender_getHandler() != null) { if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE) { - GlStateManager.translate(0.1, 0, 0); + GL11.glTranslatef(0.1f, 0, 0); } else if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.RIGHT_EYE) { - GlStateManager.translate(-0.1, 0, 0); + GL11.glTranslatef(-0.1f, 0, 0); } } } @@ -183,16 +193,11 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti replayModRender_gluPerspective(fovY, aspect, zNear, zFar); } - @Redirect(method = "renderWorldPass", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false)) + @Redirect(method = "renderHand", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false)) private void replayModRender_gluPerspective$1(float fovY, float aspect, float zNear, float zFar) { replayModRender_gluPerspective(fovY, aspect, zNear, zFar); } - @Redirect(method = "renderCloudsCheck", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false)) - private void replayModRender_gluPerspective$2(float fovY, float aspect, float zNear, float zFar) { - replayModRender_gluPerspective(fovY, aspect, zNear, zFar); - } - @Override public void replayModRender_gluPerspective(float fovY, float aspect, float zNear, float zFar) { if (replayModRender_getHandler() != null && replayModRender_getHandler().omnidirectional) { @@ -207,28 +212,28 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti if (replayModRender_getHandler() != null && replayModRender_getHandler().data instanceof CubicOpenGlFrameCapturer.Data) { switch ((CubicOpenGlFrameCapturer.Data) replayModRender_getHandler().data) { case FRONT: - GlStateManager.rotate(0, 0.0F, 1.0F, 0.0F); + GL11.glRotatef(0, 0.0F, 1.0F, 0.0F); break; case RIGHT: - GlStateManager.rotate(90, 0.0F, 1.0F, 0.0F); + GL11.glRotatef(90, 0.0F, 1.0F, 0.0F); break; case BACK: - GlStateManager.rotate(180, 0.0F, 1.0F, 0.0F); + GL11.glRotatef(180, 0.0F, 1.0F, 0.0F); break; case LEFT: - GlStateManager.rotate(-90, 0.0F, 1.0F, 0.0F); + GL11.glRotatef(-90, 0.0F, 1.0F, 0.0F); break; case BOTTOM: - GlStateManager.rotate(90, 1.0F, 0.0F, 0.0F); + GL11.glRotatef(90, 1.0F, 0.0F, 0.0F); break; case TOP: - GlStateManager.rotate(-90, 1.0F, 0.0F, 0.0F); + GL11.glRotatef(-90, 1.0F, 0.0F, 0.0F); break; } } if (replayModRender_getHandler() != null && replayModRender_getHandler().omnidirectional) { // Minecraft goes back a little so we have to revert that - GlStateManager.translate(0.0F, 0.0F, 0.1F); + GL11.glTranslatef(0.0F, 0.0F, 0.1F); } } } diff --git a/src/main/java/com/replaymod/render/mixin/MixinFrustum.java b/src/main/java/com/replaymod/render/mixin/MixinFrustum.java index ed22976e..b3065cea 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinFrustum.java +++ b/src/main/java/com/replaymod/render/mixin/MixinFrustum.java @@ -2,13 +2,13 @@ package com.replaymod.render.mixin; import com.replaymod.render.hooks.EntityRendererHandler; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.client.renderer.culling.Frustrum; 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.CallbackInfoReturnable; -@Mixin(Frustum.class) +@Mixin(Frustrum.class) public abstract class MixinFrustum { @Inject(method = "isBoxInFrustum", at = @At("HEAD"), cancellable = true) public void isBoxInFrustum(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, CallbackInfoReturnable ci) { diff --git a/src/main/java/com/replaymod/render/mixin/MixinOpenGlHelper.java b/src/main/java/com/replaymod/render/mixin/MixinOpenGlHelper.java new file mode 100644 index 00000000..8a20ca74 --- /dev/null +++ b/src/main/java/com/replaymod/render/mixin/MixinOpenGlHelper.java @@ -0,0 +1,16 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.hooks.GLStateTracker; +import net.minecraft.client.renderer.OpenGlHelper; +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; + +@Mixin(OpenGlHelper.class) +public abstract class MixinOpenGlHelper { + @Inject(method = "setActiveTexture", at = @At("RETURN")) + private static void replayModRender_trackActiveTexture(int magic, CallbackInfo ci) { + GLStateTracker.getInstance().updateActiveTexture(magic); + } +} diff --git a/src/main/java/com/replaymod/render/mixin/MixinRender.java b/src/main/java/com/replaymod/render/mixin/MixinRender.java index f29678b8..8bd61a18 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinRender.java +++ b/src/main/java/com/replaymod/render/mixin/MixinRender.java @@ -2,17 +2,17 @@ package com.replaymod.render.mixin; import com.replaymod.render.hooks.EntityRendererHandler; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.entity.Render; -import net.minecraft.entity.Entity; +import net.minecraft.client.renderer.entity.RendererLivingEntity; +import net.minecraft.entity.EntityLivingBase; 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.CallbackInfoReturnable; -@Mixin(Render.class) +@Mixin(RendererLivingEntity.class) public abstract class MixinRender { @Inject(method = "canRenderName", at = @At("HEAD"), cancellable = true) - private void replayModRender_areAllNamesHidden(Entity entity, CallbackInfoReturnable ci) { + private void replayModRender_areAllNamesHidden(EntityLivingBase entity, CallbackInfoReturnable ci) { EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) Minecraft.getMinecraft().entityRenderer).replayModRender_getHandler(); if (handler != null && !handler.getSettings().isRenderNameTags()) { ci.setReturnValue(false); diff --git a/src/main/java/com/replaymod/render/mixin/MixinRenderGlobal.java b/src/main/java/com/replaymod/render/mixin/MixinRenderGlobal.java deleted file mode 100644 index 7f5cae0a..00000000 --- a/src/main/java/com/replaymod/render/mixin/MixinRenderGlobal.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.replaymod.render.mixin; - -import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; -import net.minecraft.client.renderer.RenderGlobal; -import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher; -import net.minecraft.client.renderer.chunk.RenderChunk; -import net.minecraft.client.renderer.culling.ICamera; -import net.minecraft.entity.Entity; -import net.minecraft.util.BlockPos; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(RenderGlobal.class) -public abstract class MixinRenderGlobal { - public ChunkLoadingRenderGlobal replayModRender_hook; - private boolean replayModRender_passThroughSetupTerrain; - - @Shadow - public boolean displayListEntitiesDirty; - - @Shadow - public ChunkRenderDispatcher renderDispatcher; - - @Shadow - public abstract void setupTerrain(Entity viewEntity, double partialTicks, ICamera camera, - int frameCount, boolean playerSpectator); - - @Inject(method = "setupTerrain", at = @At("HEAD"), cancellable = true) - public void replayModRender_setupTerrain(Entity viewEntity, double partialTicks, ICamera camera, - int frameCount, boolean playerSpectator, CallbackInfo ci) { - if (replayModRender_hook != null && !replayModRender_passThroughSetupTerrain) { - replayModRender_passThroughSetupTerrain = true; - - do { - setupTerrain(viewEntity, partialTicks, camera, replayModRender_hook.nextFrameId(), playerSpectator); - } while (displayListEntitiesDirty); - - displayListEntitiesDirty = true; - - replayModRender_passThroughSetupTerrain = false; - ci.cancel(); - } - } - - @Inject(method = "isPositionInRenderChunk", at = @At("HEAD"), cancellable = true) - public void replayModRender_isPositionInRenderChunk(BlockPos pos, RenderChunk chunk, CallbackInfoReturnable ci) { - if (replayModRender_hook != null) { - ci.setReturnValue(true); - } - } - - @Inject(method = "updateChunks", at = @At("HEAD"), cancellable = true) - public void replayModRender_updateChunks(long finishTimeNano, CallbackInfo ci) { - if (replayModRender_hook != null) { - replayModRender_hook.updateChunks(); - ci.cancel(); - } - } -} diff --git a/src/main/java/com/replaymod/render/rendering/Pipelines.java b/src/main/java/com/replaymod/render/rendering/Pipelines.java index f16ba7df..720c6317 100644 --- a/src/main/java/com/replaymod/render/rendering/Pipelines.java +++ b/src/main/java/com/replaymod/render/rendering/Pipelines.java @@ -30,9 +30,9 @@ public class Pipelines { RenderSettings settings = renderInfo.getRenderSettings(); FrameCapturer capturer; if (PixelBufferObject.SUPPORTED) { - capturer = new SimplePboOpenGlFrameCapturer(new EntityRendererHandler(settings), renderInfo); + capturer = new SimplePboOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo); } else { - capturer = new SimpleOpenGlFrameCapturer(new EntityRendererHandler(settings), renderInfo); + capturer = new SimpleOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo); } return new Pipeline<>(capturer, new OpenGlToRGBProcessor(), consumer); } @@ -41,9 +41,9 @@ public class Pipelines { RenderSettings settings = renderInfo.getRenderSettings(); FrameCapturer capturer; if (PixelBufferObject.SUPPORTED) { - capturer = new StereoscopicPboOpenGlFrameCapturer(new EntityRendererHandler(settings), renderInfo); + capturer = new StereoscopicPboOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo); } else { - capturer = new StereoscopicOpenGlFrameCapturer(new EntityRendererHandler(settings), renderInfo); + capturer = new StereoscopicOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo); } return new Pipeline<>(capturer, new StereoscopicToRGBProcessor(), consumer); } @@ -52,9 +52,9 @@ public class Pipelines { RenderSettings settings = renderInfo.getRenderSettings(); FrameCapturer capturer; if (PixelBufferObject.SUPPORTED) { - capturer = new CubicPboOpenGlFrameCapturer(new EntityRendererHandler(settings), renderInfo, settings.getVideoWidth() / 4); + capturer = new CubicPboOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, settings.getVideoWidth() / 4); } else { - capturer = new CubicOpenGlFrameCapturer(new EntityRendererHandler(settings), renderInfo, settings.getVideoWidth() / 4); + capturer = new CubicOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, settings.getVideoWidth() / 4); } return new Pipeline<>(capturer, new CubicToRGBProcessor(), consumer); } @@ -63,9 +63,9 @@ public class Pipelines { RenderSettings settings = renderInfo.getRenderSettings(); FrameCapturer capturer; if (PixelBufferObject.SUPPORTED) { - capturer = new CubicPboOpenGlFrameCapturer(new EntityRendererHandler(settings), renderInfo, settings.getVideoWidth() / 4); + capturer = new CubicPboOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, settings.getVideoWidth() / 4); } else { - capturer = new CubicOpenGlFrameCapturer(new EntityRendererHandler(settings), renderInfo, settings.getVideoWidth() / 4); + capturer = new CubicOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, settings.getVideoWidth() / 4); } return new Pipeline<>(capturer, new EquirectangularToRGBProcessor(settings.getVideoWidth() / 4), consumer); } @@ -73,7 +73,7 @@ public class Pipelines { public static Pipeline newODSPipeline(RenderInfo renderInfo, FrameConsumer consumer) { RenderSettings settings = renderInfo.getRenderSettings(); FrameCapturer capturer = - new ODSFrameCapturer(new EntityRendererHandler(settings), renderInfo, settings.getVideoWidth() / 4); + new ODSFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, settings.getVideoWidth() / 4); return new Pipeline<>(capturer, new ODSToRGBProcessor(settings.getVideoWidth() / 4), consumer); } } diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index 9b36c0ad..e176633c 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -12,21 +12,21 @@ import com.replaymod.render.events.ReplayRenderEvent; import com.replaymod.render.frame.RGBFrame; import com.replaymod.render.gui.GuiRenderingDone; import com.replaymod.render.gui.GuiVideoRenderer; -import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; import com.replaymod.render.metadata.MetadataInjector; import com.replaymod.replay.ReplayHandler; import com.replaymod.replaystudio.pathing.path.Keyframe; import com.replaymod.replaystudio.pathing.path.Path; import com.replaymod.replaystudio.pathing.path.Timeline; +import cpw.mods.fml.common.FMLCommonHandler; import net.minecraft.client.Minecraft; import net.minecraft.client.audio.SoundCategory; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.shader.Framebuffer; import net.minecraft.util.Timer; -import net.minecraftforge.fml.common.FMLCommonHandler; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.Display; +import org.lwjgl.opengl.GL11; import org.lwjgl.util.Dimension; import org.lwjgl.util.ReadableDimension; @@ -40,9 +40,9 @@ import java.util.concurrent.FutureTask; import static com.google.common.collect.Iterables.getLast; import static com.replaymod.render.ReplayModRender.LOGGER; -import static net.minecraft.client.renderer.GlStateManager.*; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; public class VideoRenderer implements RenderInfo { private final Minecraft mc = Minecraft.getMinecraft(); @@ -59,7 +59,6 @@ public class VideoRenderer implements RenderInfo { private TimelinePlayer timelinePlayer; private Future timelinePlayerFuture; - private ChunkLoadingRenderGlobal chunkLoadingRenderGlobal; private int framesDone; private int totalFrames; @@ -228,8 +227,6 @@ public class VideoRenderer implements RenderInfo { ScaledResolution scaled = new ScaledResolution(mc, displayWidth, displayHeight); gui.toMinecraft().setWorldAndResolution(mc, scaled.getScaledWidth(), scaled.getScaledHeight()); - chunkLoadingRenderGlobal = new ChunkLoadingRenderGlobal(mc.renderGlobal); - // Set up our own framebuffer to render the GUI to guiFramebuffer = new Framebuffer(displayWidth, displayHeight, true); } @@ -250,9 +247,6 @@ public class VideoRenderer implements RenderInfo { } mc.gameSettings.mapSoundLevels = originalSoundLevels; mc.displayGuiScreen(null); - if (chunkLoadingRenderGlobal != null) { - chunkLoadingRenderGlobal.uninstall(); - } ReplayMod.soundHandler.playRenderSuccessSound(); @@ -276,11 +270,7 @@ public class VideoRenderer implements RenderInfo { } mc.currentScreen = gui.toMinecraft(); - try { - mc.runTick(); - } catch (IOException e) { - throw new RuntimeException(e); - } + mc.runTick(); } public void drawGui() { @@ -291,9 +281,9 @@ public class VideoRenderer implements RenderInfo { guiFramebuffer.createBindFramebuffer(mc.displayWidth, mc.displayHeight); } - pushMatrix(); - clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - enableTexture2D(); + GL11.glPushMatrix(); + GL11.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + GL11.glEnable(GL_TEXTURE_2D); guiFramebuffer.bindFramebuffer(true); mc.entityRenderer.setupOverlayRendering(); @@ -301,13 +291,7 @@ public class VideoRenderer implements RenderInfo { ScaledResolution scaled = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight); gui.toMinecraft().setWorldAndResolution(mc, scaled.getScaledWidth(), scaled.getScaledHeight()); - try { - gui.toMinecraft().handleInput(); - } catch (IOException e) { - // That's a strange exception from this kind of method O_o - // It isn't actually thrown here, so we'll deal with it the easy way - throw new RuntimeException(e); - } + gui.toMinecraft().handleInput(); int mouseX = Mouse.getX() * scaled.getScaledWidth() / mc.displayWidth; int mouseY = scaled.getScaledHeight() - Mouse.getY() * scaled.getScaledHeight() / mc.displayHeight - 1; @@ -315,17 +299,17 @@ public class VideoRenderer implements RenderInfo { gui.toMinecraft().drawScreen(mouseX, mouseY, 0); guiFramebuffer.unbindFramebuffer(); - popMatrix(); - pushMatrix(); + GL11.glPopMatrix(); + GL11.glPushMatrix(); guiFramebuffer.framebufferRender(displayWidth, displayHeight); - popMatrix(); + GL11.glPopMatrix(); // if not in high performance mode, update the gui size if screen size changed // otherwise just swap the progress gui to screen if (settings.isHighPerformance()) { Display.update(); } else { - mc.updateDisplay(); + mc.resetSize(); } if (Mouse.isGrabbed()) { Mouse.setGrabbed(false); diff --git a/src/main/java/com/replaymod/replay/InputReplayTimer.java b/src/main/java/com/replaymod/replay/InputReplayTimer.java index da1bd5fb..9b8b5eb3 100644 --- a/src/main/java/com/replaymod/replay/InputReplayTimer.java +++ b/src/main/java/com/replaymod/replay/InputReplayTimer.java @@ -3,20 +3,20 @@ package com.replaymod.replay; import com.replaymod.core.utils.WrappedTimer; import com.replaymod.replay.camera.CameraController; import com.replaymod.replay.camera.CameraEntity; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.Event; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.settings.GameSettings; import net.minecraft.client.settings.KeyBinding; import net.minecraft.crash.CrashReport; import net.minecraft.util.ReportedException; import net.minecraft.util.Timer; import net.minecraftforge.client.ForgeHooksClient; -import net.minecraftforge.fml.common.FMLCommonHandler; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; -import java.io.IOException; - public class InputReplayTimer extends WrappedTimer { private final ReplayModReplay mod; private final Minecraft mc; @@ -31,6 +31,9 @@ public class InputReplayTimer extends WrappedTimer { public void updateTimer() { super.updateTimer(); + // 1.7.10: We have to run the scheduled executables (ours only) because MC would only run them every tick + FMLCommonHandler.instance().bus().post(new RunScheduledTasks()); + // If we are in a replay, we have to manually process key and mouse events as the // tick speed may vary or there may not be any ticks at all (when the replay is paused) if (mod.getReplayHandler() != null) { @@ -43,11 +46,7 @@ public class InputReplayTimer extends WrappedTimer { handleKeyEvent(); } } else { - try { - mc.currentScreen.handleInput(); - } catch (IOException e) { // *SIGH* - e.printStackTrace(); - } + mc.currentScreen.handleInput(); } } } @@ -89,17 +88,14 @@ public class InputReplayTimer extends WrappedTimer { mc.setIngameFocus(); } } else { - try { - mc.currentScreen.handleMouseInput(); - } catch (IOException e) { // WHO IS RESPONSIBLE FOR THIS MESS?!? - e.printStackTrace(); - } + mc.currentScreen.handleMouseInput(); } FMLCommonHandler.instance().fireMouseInput(); } protected void handleKeyEvent() { + // TODO 1.7.10: This might be missing some 1.7.10-only key bindings or implement some of them incorrectly int key = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey(); boolean pressed = Keyboard.getEventKeyState(); @@ -127,15 +123,11 @@ public class InputReplayTimer extends WrappedTimer { if (pressed) { // This might be subject to change as vanilla shaders are still kinda unused in 1.8 if (key == Keyboard.KEY_F4 && mc.entityRenderer != null) { - mc.entityRenderer.switchUseShader(); + mc.entityRenderer.activateNextShader(); } if (mc.currentScreen != null) { - try { - mc.currentScreen.handleKeyboardInput(); - } catch (IOException e) { // AND WHO THOUGHT THIS WAS A GREAT IDEA? - e.printStackTrace(); - } + mc.currentScreen.handleKeyboardInput(); } else { if (key == Keyboard.KEY_ESCAPE) { mc.displayInGameMenu(); @@ -167,7 +159,7 @@ public class InputReplayTimer extends WrappedTimer { } if (key == 48 && Keyboard.isKeyDown(61)) { - mc.getRenderManager().setDebugBoundingBox(!mc.getRenderManager().isDebugBoundingBox()); + RenderManager.debugBoundingBox = !RenderManager.debugBoundingBox; } if (key == 25 && Keyboard.isKeyDown(61)) { @@ -186,14 +178,6 @@ public class InputReplayTimer extends WrappedTimer { if (mc.gameSettings.keyBindTogglePerspective.isPressed()) { mc.gameSettings.thirdPersonView = (mc.gameSettings.thirdPersonView + 1) % 3; - - if (mc.entityRenderer != null) { // Extra check, not in vanilla code - if (mc.gameSettings.thirdPersonView == 0) { - mc.entityRenderer.loadEntityShader(mc.getRenderViewEntity()); - } else if (mc.gameSettings.thirdPersonView == 1) { - mc.entityRenderer.loadEntityShader(null); - } - } } } @@ -213,4 +197,6 @@ public class InputReplayTimer extends WrappedTimer { FMLCommonHandler.instance().fireKeyInput(); } + + public static class RunScheduledTasks extends Event {} } diff --git a/src/main/java/com/replaymod/replay/NoGuiScreenshot.java b/src/main/java/com/replaymod/replay/NoGuiScreenshot.java index f3626baa..1a6bc917 100644 --- a/src/main/java/com/replaymod/replay/NoGuiScreenshot.java +++ b/src/main/java/com/replaymod/replay/NoGuiScreenshot.java @@ -8,9 +8,9 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.ScreenShotHelper; import org.apache.commons.io.FileUtils; +import org.lwjgl.opengl.GL11; import javax.imageio.ImageIO; import java.awt.*; @@ -40,18 +40,18 @@ public class NoGuiScreenshot { mc.gameSettings.hideGUI = true; // Render frame without GUI - GlStateManager.pushMatrix(); - GlStateManager.clear(16640); + GL11.glPushMatrix(); + GL11.glClear(16640); mc.getFramebuffer().bindFramebuffer(true); - GlStateManager.enableTexture2D(); + GL11.glEnable(GL11.GL_TEXTURE_2D); mc.entityRenderer.updateCameraAndRender(mc.timer.renderPartialTicks); mc.getFramebuffer().unbindFramebuffer(); - GlStateManager.popMatrix(); - GlStateManager.pushMatrix(); + GL11.glPopMatrix(); + GL11.glPushMatrix(); mc.getFramebuffer().framebufferRender(mc.displayWidth, mc.displayHeight); - GlStateManager.popMatrix(); + GL11.glPopMatrix(); } catch (Throwable t) { future.setException(t); return; diff --git a/src/main/java/com/replaymod/replay/ReplayHandler.java b/src/main/java/com/replaymod/replay/ReplayHandler.java index caca9969..d2546cde 100755 --- a/src/main/java/com/replaymod/replay/ReplayHandler.java +++ b/src/main/java/com/replaymod/replay/ReplayHandler.java @@ -1,39 +1,41 @@ package com.replaymod.replay; import com.google.common.base.Preconditions; -import com.mojang.authlib.GameProfile; import com.replaymod.core.utils.Restrictions; import com.replaymod.replay.camera.CameraEntity; import com.replaymod.replay.camera.SpectatorCameraController; import com.replaymod.replay.events.ReplayCloseEvent; import com.replaymod.replay.events.ReplayOpenEvent; import com.replaymod.replay.gui.overlay.GuiReplayOverlay; +import com.replaymod.replay.gui.screen.GuiOpeningReplay; import com.replaymod.replaystudio.data.Marker; import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.util.Location; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.network.internal.FMLNetworkHandler; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOutboundHandlerAdapter; import io.netty.channel.embedded.EmbeddedChannel; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityOtherPlayerMP; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; -import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.client.network.NetHandlerLoginClient; import net.minecraft.client.resources.I18n; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.network.EnumPacketDirection; +import net.minecraft.network.EnumConnectionState; import net.minecraft.network.NetworkManager; -import net.minecraftforge.fml.client.FMLClientHandler; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher; import org.lwjgl.opengl.Display; +import org.lwjgl.opengl.GL11; import java.io.IOException; import java.util.*; -import static net.minecraft.client.renderer.GlStateManager.*; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; public class ReplayHandler { @@ -132,24 +134,29 @@ public class ReplayHandler { private void setup() { mc.ingameGUI.getChatGUI().clearChatMessages(); - NetworkManager networkManager = new NetworkManager(EnumPacketDirection.CLIENTBOUND) { + NetworkManager networkManager = new NetworkManager(true) { @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) { t.printStackTrace(); } }; - NetHandlerPlayClient netHandlerPlayClient = - new NetHandlerPlayClient(mc, null, networkManager, new GameProfile(UUID.randomUUID(), "Player")); - networkManager.setNetHandler(netHandlerPlayClient); - FMLClientHandler.instance().setPlayClient(netHandlerPlayClient); + networkManager.setNetHandler(new NetHandlerLoginClient(networkManager, mc, null)); - channel = new EmbeddedChannel(networkManager); - NetworkDispatcher networkDispatcher = new NetworkDispatcher(networkManager); - channel.attr(NetworkDispatcher.FML_DISPATCHER).set(networkDispatcher); + mc.displayGuiScreen(new GuiOpeningReplay(networkManager)); + ChannelOutboundHandlerAdapter dummyHandler = new ChannelOutboundHandlerAdapter(); + channel = new EmbeddedChannel(dummyHandler); + channel.pipeline().remove(dummyHandler); channel.pipeline().addFirst("ReplayModReplay_replaySender", replaySender); - channel.pipeline().addAfter("ReplayModReplay_replaySender", "fml:packet_handler", networkDispatcher); + channel.pipeline().addAfter("ReplayModReplay_replaySender", "packet_handler", networkManager); channel.pipeline().fireChannelActive(); + + // Call twice to force-overwrite the NetworkManager's internal state + networkManager.setConnectionState(EnumConnectionState.PLAY); + networkManager.getNetHandler().onConnectionStateTransition(EnumConnectionState.LOGIN, EnumConnectionState.PLAY); + networkManager.setConnectionState(EnumConnectionState.PLAY); + + FMLNetworkHandler.fmlClientHandshake(networkManager); } public ReplayFile getReplayFile() { @@ -209,7 +216,7 @@ public class ReplayHandler { * When the entity is {@code null} or the camera entity, the camera becomes the view entity. * @param e The entity to spectate */ - public void spectateEntity(Entity e) { + public void spectateEntity(EntityLivingBase e) { CameraEntity cameraEntity = getCameraEntity(); if (cameraEntity == null) { return; // Cannot spectate if we have no camera @@ -227,15 +234,15 @@ public class ReplayHandler { cameraEntity.setCameraController(new SpectatorCameraController(cameraEntity)); } - if (mc.getRenderViewEntity() != e) { - mc.setRenderViewEntity(e); + if (mc.renderViewEntity != e) { + mc.renderViewEntity = e; cameraEntity.setCameraPosRot(e); } } /** * Set the camera as the view entity. - * This is equivalent to {@link #spectateEntity(Entity) spectateEntity(null)}. + * This is equivalent to {@link #spectateEntity(EntityLivingBase) spectateEntity(null)}. */ public void spectateCamera() { spectateEntity(null); @@ -246,7 +253,7 @@ public class ReplayHandler { * @return {@code true} if the camera is the view entity, {@code false} otherwise */ public boolean isCameraView() { - return mc.thePlayer instanceof CameraEntity && mc.thePlayer == mc.getRenderViewEntity(); + return mc.thePlayer instanceof CameraEntity && mc.thePlayer == mc.renderViewEntity; } /** @@ -310,9 +317,9 @@ public class ReplayHandler { replaySender.setSyncModeAndWait(); // Perform the rendering using OpenGL - pushMatrix(); - clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - enableTexture2D(); + GL11.glPushMatrix(); + GL11.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + GL11.glEnable(GL_TEXTURE_2D); mc.getFramebuffer().bindFramebuffer(true); mc.entityRenderer.setupOverlayRendering(); @@ -321,10 +328,10 @@ public class ReplayHandler { guiScreen.drawScreen(0, 0, 0); mc.getFramebuffer().unbindFramebuffer(); - popMatrix(); - pushMatrix(); + GL11.glPopMatrix(); + GL11.glPushMatrix(); mc.getFramebuffer().framebufferRender(mc.displayWidth, mc.displayHeight); - popMatrix(); + GL11.glPopMatrix(); Display.update(); @@ -349,11 +356,7 @@ public class ReplayHandler { entity.prevRotationYaw = entity.rotationYaw; entity.prevRotationPitch = entity.rotationPitch; } - try { - mc.runTick(); - } catch (IOException e) { - e.printStackTrace(); // This should never be thrown but whatever - } + mc.runTick(); //finally, updating the camera's position (which is not done by the sync jumping) moveCameraToTargetPosition(); diff --git a/src/main/java/com/replaymod/replay/ReplayModReplay.java b/src/main/java/com/replaymod/replay/ReplayModReplay.java index d6ef677d..68d8ce65 100644 --- a/src/main/java/com/replaymod/replay/ReplayModReplay.java +++ b/src/main/java/com/replaymod/replay/ReplayModReplay.java @@ -18,11 +18,11 @@ import com.replaymod.replaystudio.data.Marker; import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ZipReplayFile; import com.replaymod.replaystudio.studio.ReplayStudio; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; import net.minecraft.client.Minecraft; -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 org.apache.logging.log4j.Logger; import org.lwjgl.input.Keyboard; diff --git a/src/main/java/com/replaymod/replay/ReplaySender.java b/src/main/java/com/replaymod/replay/ReplaySender.java index 9e000d3a..b14eee0f 100755 --- a/src/main/java/com/replaymod/replay/ReplaySender.java +++ b/src/main/java/com/replaymod/replay/ReplaySender.java @@ -15,11 +15,38 @@ import io.netty.channel.ChannelPromise; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiDownloadTerrain; import net.minecraft.client.gui.GuiErrorScreen; +import net.minecraft.client.resources.FileResourcePack; import net.minecraft.client.resources.I18n; +import net.minecraft.client.resources.ResourcePackRepository; import net.minecraft.entity.Entity; -import net.minecraft.network.*; -import net.minecraft.network.play.server.*; -import net.minecraft.util.ClassInheritanceMultiMap; +import net.minecraft.network.EnumConnectionState; +import net.minecraft.network.Packet; +import net.minecraft.network.PacketBuffer; +import net.minecraft.network.play.server.S01PacketJoinGame; +import net.minecraft.network.play.server.S02PacketChat; +import net.minecraft.network.play.server.S06PacketUpdateHealth; +import net.minecraft.network.play.server.S07PacketRespawn; +import net.minecraft.network.play.server.S08PacketPlayerPosLook; +import net.minecraft.network.play.server.S0CPacketSpawnPlayer; +import net.minecraft.network.play.server.S0EPacketSpawnObject; +import net.minecraft.network.play.server.S0FPacketSpawnMob; +import net.minecraft.network.play.server.S10PacketSpawnPainting; +import net.minecraft.network.play.server.S11PacketSpawnExperienceOrb; +import net.minecraft.network.play.server.S13PacketDestroyEntities; +import net.minecraft.network.play.server.S1FPacketSetExperience; +import net.minecraft.network.play.server.S21PacketChunkData; +import net.minecraft.network.play.server.S2APacketParticles; +import net.minecraft.network.play.server.S2BPacketChangeGameState; +import net.minecraft.network.play.server.S2CPacketSpawnGlobalEntity; +import net.minecraft.network.play.server.S2DPacketOpenWindow; +import net.minecraft.network.play.server.S2EPacketCloseWindow; +import net.minecraft.network.play.server.S2FPacketSetSlot; +import net.minecraft.network.play.server.S30PacketWindowItems; +import net.minecraft.network.play.server.S36PacketSignEditorOpen; +import net.minecraft.network.play.server.S37PacketStatistics; +import net.minecraft.network.play.server.S39PacketPlayerAbilities; +import net.minecraft.network.play.server.S3FPacketCustomPayload; +import net.minecraft.network.play.server.S40PacketDisconnect; import net.minecraft.util.IChatComponent; import net.minecraft.util.MathHelper; import net.minecraft.world.EnumDifficulty; @@ -28,10 +55,15 @@ import net.minecraft.world.WorldSettings.GameType; import net.minecraft.world.WorldType; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.IChunkProvider; +import org.apache.commons.io.Charsets; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -import java.io.*; +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -46,14 +78,6 @@ import java.util.Map; @Sharable public class ReplaySender extends ChannelDuplexHandler { - /** - * Previously packets for the client player were inserted using one fixed entity id (this one). - * This is no longer the case however to provide backwards compatibility, we have to convert - * these old packets to use the normal entity id. - * Need to punch someone? -> CrushedPixel - */ - public static final int LEGACY_ENTITY_ID = Integer.MIN_VALUE + 9001; - /** * These packets are ignored completely during replay. */ @@ -66,9 +90,7 @@ public class ReplaySender extends ChannelDuplexHandler { S36PacketSignEditorOpen.class, S37PacketStatistics.class, S1FPacketSetExperience.class, - S43PacketCamera.class, - S39PacketPlayerAbilities.class, - S45PacketTitle.class); + S39PacketPlayerAbilities.class); private static int TP_DISTANCE_LIMIT = 128; @@ -123,7 +145,7 @@ public class ReplaySender extends ChannelDuplexHandler { /** * Whether we need to restart the current replay. E.g. when jumping backwards in time */ - protected boolean startFromBeginning = true; + protected boolean startFromBeginning; /** * Whether to terminate the replay. This only has an effect on the async mode and is {@code true} during sync mode. @@ -321,7 +343,7 @@ public class ReplaySender extends ChannelDuplexHandler { int i = pb.readVarIntFromBuffer(); - Packet p = EnumConnectionState.PLAY.getPacket(EnumPacketDirection.CLIENTBOUND, i); + Packet p = Packet.generatePacket(EnumConnectionState.PLAY.func_150755_b(), i); p.readPacketData(pb); return p; @@ -335,7 +357,7 @@ public class ReplaySender extends ChannelDuplexHandler { protected Packet processPacket(Packet p) throws Exception { if (p instanceof S3FPacketCustomPayload) { S3FPacketCustomPayload packet = (S3FPacketCustomPayload) p; - if (Restrictions.PLUGIN_CHANNEL.equals(packet.getChannelName())) { + if (Restrictions.PLUGIN_CHANNEL.equals(packet.func_149169_c())) { final String unknown = replayHandler.getRestrictions().handle(packet); if (unknown == null) { return null; @@ -373,52 +395,51 @@ public class ReplaySender extends ChannelDuplexHandler { if (p instanceof S3FPacketCustomPayload) { S3FPacketCustomPayload packet = (S3FPacketCustomPayload) p; - if ("MC|BOpen".equals(packet.getChannelName())) { + if ("MC|BOpen".equals(packet.func_149169_c())) { return null; } - } - - convertLegacyEntityIds(p); - - if(p instanceof S48PacketResourcePackSend) { - S48PacketResourcePackSend packet = (S48PacketResourcePackSend) p; - String url = packet.func_179783_a(); - if (url.startsWith("replay://")) { - int id = Integer.parseInt(url.substring("replay://".length())); - Map index = replayFile.getResourcePackIndex(); - if (index != null) { - String hash = index.get(id); - if (hash != null) { - File file = new File(tempResourcePackFolder, hash + ".zip"); - if (!file.exists()) { - IOUtils.copy(replayFile.getResourcePack(hash).get(), new FileOutputStream(file)); + if ("MC|RPack".equals(packet.func_149169_c())) { + String url = new String(packet.func_149168_d(), Charsets.UTF_8); + if (url.startsWith("replay://")) { + int id = Integer.parseInt(url.substring("replay://".length())); + Map index = replayFile.getResourcePackIndex(); + if (index != null) { + String hash = index.get(id); + if (hash != null) { + File file = new File(tempResourcePackFolder, hash + ".zip"); + if (!file.exists()) { + IOUtils.copy(replayFile.getResourcePack(hash).get(), new FileOutputStream(file)); + } + ResourcePackRepository repo = mc.getResourcePackRepository(); + repo.field_148533_g = false; + repo.field_148532_f = new FileResourcePack(file); + Minecraft.getMinecraft().scheduleResourcesRefresh(); } - mc.getResourcePackRepository().func_177319_a(file); } + return null; } - return null; } } if(p instanceof S01PacketJoinGame) { S01PacketJoinGame packet = (S01PacketJoinGame) p; allowMovement = true; - int entId = packet.getEntityId(); + int entId = packet.func_149197_c(); actualID = entId; entId = -1789435; // Camera entity id should be negative which is an invalid id and can't be used by servers - int dimension = packet.getDimension(); - EnumDifficulty difficulty = packet.getDifficulty(); - int maxPlayers = packet.getMaxPlayers(); - WorldType worldType = packet.getWorldType(); + int dimension = packet.func_149194_f(); + EnumDifficulty difficulty = packet.func_149192_g(); + int maxPlayers = packet.func_149193_h(); + WorldType worldType = packet.func_149196_i(); - p = new S01PacketJoinGame(entId, GameType.SPECTATOR, false, dimension, - difficulty, maxPlayers, worldType, false); + p = new S01PacketJoinGame(entId, GameType.ADVENTURE, false, dimension, + difficulty, maxPlayers, worldType); } if(p instanceof S07PacketRespawn) { S07PacketRespawn respawn = (S07PacketRespawn) p; p = new S07PacketRespawn(respawn.func_149082_c(), - respawn.func_149081_d(), respawn.func_149080_f(), GameType.SPECTATOR); + respawn.func_149081_d(), respawn.func_149080_f(), GameType.ADVENTURE); allowMovement = true; } @@ -436,14 +457,6 @@ public class ReplaySender extends ChannelDuplexHandler { CameraEntity cent = replayHandler.getCameraEntity(); - for (Object relative : ppl.func_179834_f()) { - if (relative == S08PacketPlayerPosLook.EnumFlags.X - || relative == S08PacketPlayerPosLook.EnumFlags.Y - || relative == S08PacketPlayerPosLook.EnumFlags.Z) { - return null; // At least one of the coordinates is relative, so we don't care - } - } - if(cent != null) { if(!allowMovement && !((Math.abs(cent.posX - ppl.func_148932_c()) > TP_DISTANCE_LIMIT) || (Math.abs(cent.posZ - ppl.func_148933_e()) > TP_DISTANCE_LIMIT))) { @@ -497,7 +510,6 @@ public class ReplaySender extends ChannelDuplexHandler { @SuppressWarnings("unchecked") public void channelActive(ChannelHandlerContext ctx) throws Exception { this.ctx = ctx; - ctx.attr(NetworkManager.attrKeyConnectionState).set(EnumConnectionState.PLAY); super.channelActive(ctx); } @@ -821,7 +833,7 @@ public class ReplaySender extends ChannelDuplexHandler { if (!chunk.isEmpty()) { List entitiesInChunk = new ArrayList<>(); // Gather all entities in that chunk - for (ClassInheritanceMultiMap entityList : chunk.getEntityLists()) { + for (List entityList : chunk.entityLists) { @SuppressWarnings("unchecked") Collection typedEntityList = entityList; entitiesInChunk.addAll(typedEntityList); @@ -851,68 +863,6 @@ public class ReplaySender extends ChannelDuplexHandler { return p; // During synchronous playback everything is sent normally } - /** - * This is necessary to convert packets from old replays to new replays. - * @param packet The packet to be transformed. - * @see #LEGACY_ENTITY_ID - */ - private void convertLegacyEntityIds(Packet packet) { - if (packet instanceof S0CPacketSpawnPlayer) { - S0CPacketSpawnPlayer p = (S0CPacketSpawnPlayer) packet; - if (p.field_148957_a == LEGACY_ENTITY_ID) { - p.field_148957_a = actualID; - } - } else if (packet instanceof S18PacketEntityTeleport) { - S18PacketEntityTeleport p = (S18PacketEntityTeleport) packet; - if (p.field_149458_a == LEGACY_ENTITY_ID) { - p.field_149458_a = actualID; - } - } else if (packet instanceof S14PacketEntity.S17PacketEntityLookMove) { - S14PacketEntity.S17PacketEntityLookMove p = (S14PacketEntity.S17PacketEntityLookMove) packet; - if (p.field_149074_a == LEGACY_ENTITY_ID) { - p.field_149074_a = actualID; - } - } else if (packet instanceof S19PacketEntityHeadLook) { - S19PacketEntityHeadLook p = (S19PacketEntityHeadLook) packet; - if (p.field_149384_a == LEGACY_ENTITY_ID) { - p.field_149384_a = actualID; - } - } else if (packet instanceof S12PacketEntityVelocity) { - S12PacketEntityVelocity p = (S12PacketEntityVelocity) packet; - if (p.field_149417_a == LEGACY_ENTITY_ID) { - p.field_149417_a = actualID; - } - } else if (packet instanceof S0BPacketAnimation) { - S0BPacketAnimation p = (S0BPacketAnimation) packet; - if (p.entityId == LEGACY_ENTITY_ID) { - p.entityId = actualID; - } - } else if (packet instanceof S04PacketEntityEquipment) { - S04PacketEntityEquipment p = (S04PacketEntityEquipment) packet; - if (p.field_149394_a == LEGACY_ENTITY_ID) { - p.field_149394_a = actualID; - } - } else if (packet instanceof S1BPacketEntityAttach) { - S1BPacketEntityAttach p = (S1BPacketEntityAttach) packet; - if (p.field_149408_a == LEGACY_ENTITY_ID) { - p.field_149408_a = actualID; - } - if (p.field_149406_b == LEGACY_ENTITY_ID) { - p.field_149406_b = actualID; - } - } else if (packet instanceof S0DPacketCollectItem) { - S0DPacketCollectItem p = (S0DPacketCollectItem) packet; - if (p.field_149356_b == LEGACY_ENTITY_ID) { - p.field_149356_b = actualID; - } - } else if (packet instanceof S13PacketDestroyEntities) { - S13PacketDestroyEntities p = (S13PacketDestroyEntities) packet; - if (p.field_149100_a.length == 1 && p.field_149100_a[0] == LEGACY_ENTITY_ID) { - p.field_149100_a[0] = actualID; - } - } - } - private static final class PacketData { private final int timestamp; private final byte[] bytes; diff --git a/src/main/java/com/replaymod/replay/camera/CameraEntity.java b/src/main/java/com/replaymod/replay/camera/CameraEntity.java index 9935baf5..200ba7d6 100755 --- a/src/main/java/com/replaymod/replay/camera/CameraEntity.java +++ b/src/main/java/com/replaymod/replay/camera/CameraEntity.java @@ -7,32 +7,29 @@ import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.Setting; import com.replaymod.replay.events.ReplayChatMessageEvent; import com.replaymod.replaystudio.util.Location; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.EventPriority; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; import lombok.Getter; import lombok.Setter; import net.minecraft.block.material.Material; import net.minecraft.client.Minecraft; -import net.minecraft.client.entity.AbstractClientPlayer; -import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.entity.EntityClientPlayerMP; import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.client.settings.KeyBinding; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.item.EntityItemFrame; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.stats.StatFileWriter; -import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.IChatComponent; import net.minecraft.util.MovingObjectPosition; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.Session; import net.minecraft.world.World; -import net.minecraftforge.client.event.EntityViewRenderEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.RenderHandEvent; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.eventhandler.EventPriority; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.TickEvent; import java.util.Map; import java.util.UUID; @@ -43,7 +40,7 @@ import java.util.function.Function; * During a replay {@link Minecraft#thePlayer} should be an instance of this class. * Camera movement is controlled by a separate {@link CameraController}. */ -public class CameraEntity extends EntityPlayerSP { +public class CameraEntity extends EntityClientPlayerMP { /** * Roll of this camera in degrees. */ @@ -67,8 +64,9 @@ public class CameraEntity extends EntityPlayerSP { */ private final EventHandler eventHandler = new EventHandler(); - public CameraEntity(Minecraft mcIn, World worldIn, NetHandlerPlayClient netHandlerPlayClient, StatFileWriter statFileWriter) { - super(mcIn, worldIn, netHandlerPlayClient, statFileWriter); + public CameraEntity(Minecraft mcIn, World worldIn, Session session, NetHandlerPlayClient netHandlerPlayClient, StatFileWriter statFileWriter) { + super(mcIn, worldIn, session, netHandlerPlayClient, statFileWriter); + entityUniqueID = UUID.randomUUID(); // Need to not have the same UUID as the player who recorded the replay FMLCommonHandler.instance().bus().register(eventHandler); MinecraftForge.EVENT_BUS.register(eventHandler); if (ReplayModReplay.instance.getReplayHandler().getSpectatedUUID() == null) { @@ -127,31 +125,33 @@ public class CameraEntity extends EntityPlayerSP { * @param to The entity whose position to copy */ public void setCameraPosRot(Entity to) { + if (to == this) return; + float yOffset = 1.62f; // Magic value (eye height) from EntityRenderer#orientCamera prevPosX = to.prevPosX; - prevPosY = to.prevPosY; + prevPosY = to.prevPosY + yOffset; prevPosZ = to.prevPosZ; prevRotationYaw = to.prevRotationYaw; prevRotationPitch = to.prevRotationPitch; posX = to.posX; - posY = to.posY; + posY = to.posY + yOffset; posZ = to.posZ; rotationYaw = to.rotationYaw; rotationPitch = to.rotationPitch; lastTickPosX = to.lastTickPosX; - lastTickPosY = to.lastTickPosY; + lastTickPosY = to.lastTickPosY + yOffset; lastTickPosZ = to.lastTickPosZ; updateBoundingBox(); } private void updateBoundingBox() { - setEntityBoundingBox(new AxisAlignedBB( + this.boundingBox.setBounds( posX - width / 2, posY, posZ - width / 2, - posX + width / 2, posY + height, posZ + width / 2)); + posX + width / 2, posY + height, posZ + width / 2); } @Override public void onUpdate() { - Entity view = mc.getRenderViewEntity(); + EntityLivingBase view = mc.renderViewEntity; if (view != null) { // Make sure we're always spectating the right entity // This is important if the spectated player respawns as their @@ -167,9 +167,9 @@ public class CameraEntity extends EntityPlayerSP { } view = worldObj.getPlayerEntityByUUID(spectating); if (view != null) { - mc.setRenderViewEntity(view); + mc.renderViewEntity = view; } else { - mc.setRenderViewEntity(this); + mc.renderViewEntity = this; return; } } @@ -192,7 +192,7 @@ public class CameraEntity extends EntityPlayerSP { @Override public void setAngles(float yaw, float pitch) { - if (mc.getRenderViewEntity() == this) { + if (mc.renderViewEntity == this) { // Only update camera rotation when the camera is the view super.setAngles(yaw, pitch); } @@ -209,8 +209,8 @@ public class CameraEntity extends EntityPlayerSP { } @Override - public boolean isInLava() { - return falseUnlessSpectating(Entity::isInLava); // Make sure no lava overlay is rendered + public boolean handleLavaMovement() { + return falseUnlessSpectating(Entity::handleLavaMovement); // Make sure no lava overlay is rendered } @Override @@ -224,7 +224,7 @@ public class CameraEntity extends EntityPlayerSP { } private boolean falseUnlessSpectating(Function property) { - Entity view = mc.getRenderViewEntity(); + Entity view = mc.renderViewEntity; if (view != null && view != this) { return property.apply(view); } @@ -236,20 +236,17 @@ public class CameraEntity extends EntityPlayerSP { return false; // We are in full control of ourselves } - @Override - protected void createRunningParticles() { - // We do not produce any particles, we are a camera - } - @Override public boolean canBeCollidedWith() { return false; // We are a camera, we cannot collide } + /* TODO 1.7.10: isSpectator has been added in 1.8, this is probably going to require lots of manual changes @Override public boolean isSpectator() { return ReplayModReplay.instance.getReplayHandler().isCameraView(); // Make sure we're treated as spectator } + */ @Override public boolean shouldRenderInPass(int pass) { @@ -261,7 +258,7 @@ public class CameraEntity extends EntityPlayerSP { @Override public boolean isInvisible() { - Entity view = mc.getRenderViewEntity(); + Entity view = mc.renderViewEntity; if (view != this) { return view.isInvisible(); } @@ -270,25 +267,16 @@ public class CameraEntity extends EntityPlayerSP { @Override public ResourceLocation getLocationSkin() { - Entity view = mc.getRenderViewEntity(); + Entity view = mc.renderViewEntity; if (view != this && view instanceof EntityPlayer) { return Utils.getResourceLocationForPlayerUUID(view.getUniqueID()); } return super.getLocationSkin(); } - @Override - public String getSkinType() { - Entity view = mc.getRenderViewEntity(); - if (view != this && view instanceof AbstractClientPlayer) { - return ((AbstractClientPlayer) view).getSkinType(); - } - return super.getSkinType(); - } - @Override public float getSwingProgress(float renderPartialTicks) { - Entity view = mc.getRenderViewEntity(); + Entity view = mc.renderViewEntity; if (view != this && view instanceof EntityPlayer) { return ((EntityPlayer) view).getSwingProgress(renderPartialTicks); } @@ -328,17 +316,17 @@ public class CameraEntity extends EntityPlayerSP { if (mc.gameSettings.keyBindAttack.isPressed() || mc.gameSettings.keyBindUseItem.isPressed()) { if (canSpectate(mc.pointedEntity)) { - ReplayModReplay.instance.getReplayHandler().spectateEntity(mc.pointedEntity); + ReplayModReplay.instance.getReplayHandler().spectateEntity((EntityLivingBase) mc.pointedEntity); // Make sure we don't exit right away mc.gameSettings.keyBindSneak.pressTime = 0; } } Map keyBindings = ReplayMod.instance.getKeyBindingRegistry().getKeyBindings(); - if (keyBindings.get("replaymod.input.rollclockwise").isKeyDown()) { + if (keyBindings.get("replaymod.input.rollclockwise").getIsKeyPressed()) { roll += Utils.isCtrlDown() ? 0.2 : 1; } - if (keyBindings.get("replaymod.input.rollcounterclockwise").isKeyDown()) { + if (keyBindings.get("replaymod.input.rollcounterclockwise").getIsKeyPressed()) { roll -= Utils.isCtrlDown() ? 0.2 : 1; } } @@ -352,7 +340,7 @@ public class CameraEntity extends EntityPlayerSP { public boolean canSpectate(Entity e) { return e != null && !e.isInvisible() - && (e instanceof EntityPlayer || e instanceof EntityLiving || e instanceof EntityItemFrame); + && e instanceof EntityPlayer; // 1.7.10 has no general concept of eye height } @Override @@ -361,7 +349,10 @@ public class CameraEntity extends EntityPlayerSP { super.addChatMessage(message); } - private class EventHandler { + // All event handlers need to be public in 1.7.10 + public class EventHandler { + private EventHandler() {} + @SubscribeEvent public void onPreClientTick(TickEvent.ClientTickEvent event) { if (event.phase == TickEvent.Phase.START) { @@ -399,14 +390,14 @@ public class CameraEntity extends EntityPlayerSP { @SubscribeEvent public void onRenderHand(RenderHandEvent event) { // Unless we are spectating another player, don't render our hand - if (mc.getRenderViewEntity() == CameraEntity.this || !(mc.getRenderViewEntity() instanceof EntityPlayer)) { + if (mc.renderViewEntity == CameraEntity.this || !(mc.renderViewEntity instanceof EntityPlayer)) { event.setCanceled(true); } } @SubscribeEvent(priority = EventPriority.LOWEST) public void onRenderHandMonitor(RenderHandEvent event) { - Entity view = mc.getRenderViewEntity(); + Entity view = mc.renderViewEntity; if (view instanceof EntityPlayer) { EntityPlayer player = (EntityPlayer) view; // When the spectated player has changed, force equip their items to prevent the equip animation @@ -424,12 +415,14 @@ public class CameraEntity extends EntityPlayerSP { } } + /* TODO 1.7.10: This event has been added in 1.8, has to be replaced with mixin @SubscribeEvent public void onEntityViewRenderEvent(EntityViewRenderEvent.CameraSetup event) { if (mc.getRenderViewEntity() == CameraEntity.this) { event.roll = roll; } } + */ private boolean heldItemTooltipsWasTrue; diff --git a/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java b/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java index 797776ee..0a0ea820 100644 --- a/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java +++ b/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java @@ -34,7 +34,7 @@ public class ClassicCameraController implements CameraController { boolean forward = false, backward = false, left = false, right = false, up = false, down = false; speedup = false; for(KeyBinding kb : Minecraft.getMinecraft().gameSettings.keyBindings) { - if(!kb.isKeyDown()) continue; + if(!kb.getIsKeyPressed()) continue; if(kb.getKeyDescription().equals("key.forward")) { forward = true; speedup = true; @@ -161,7 +161,7 @@ public class ClassicCameraController implements CameraController { Vec3 dbf = direction; if(dirBefore != null) { - direction = dirBefore.normalize().add(direction); + direction = dirBefore.normalize().addVector(direction.xCoord, direction.yCoord, direction.zCoord); } dirBefore = dbf; @@ -174,7 +174,7 @@ public class ClassicCameraController implements CameraController { float f3 = MathHelper.sin(-yaw * 0.017453292F - (float)Math.PI); float f4 = -MathHelper.cos(-pitch * 0.017453292F); float f5 = MathHelper.sin(-pitch * 0.017453292F); - return new Vec3((double)(f3 * f4), (double)f5, (double)(f2 * f4)); + return Vec3.createVectorHelper((double)(f3 * f4), (double)f5, (double)(f2 * f4)); } public enum MoveDirection { diff --git a/src/main/java/com/replaymod/replay/camera/SpectatorCameraController.java b/src/main/java/com/replaymod/replay/camera/SpectatorCameraController.java index 3bab138f..d4b30261 100644 --- a/src/main/java/com/replaymod/replay/camera/SpectatorCameraController.java +++ b/src/main/java/com/replaymod/replay/camera/SpectatorCameraController.java @@ -34,9 +34,9 @@ public class SpectatorCameraController implements CameraController { // Always make sure the camera is in the exact same spot as the spectated entity // This is necessary as some rendering code for the hand doesn't respect the view entity // and always uses mc.thePlayer - Entity view = mc.getRenderViewEntity(); + Entity view = mc.renderViewEntity; if (view != null && view != camera) { - camera.setCameraPosRot(mc.getRenderViewEntity()); + camera.setCameraPosRot(mc.renderViewEntity); // If it's a player, also 'steal' its inventory so the rendering code knows what item to render if (view instanceof EntityPlayer) { EntityPlayer viewPlayer = (EntityPlayer) view; diff --git a/src/main/java/com/replaymod/replay/camera/VanillaCameraController.java b/src/main/java/com/replaymod/replay/camera/VanillaCameraController.java index 5a9c3427..66722fa4 100644 --- a/src/main/java/com/replaymod/replay/camera/VanillaCameraController.java +++ b/src/main/java/com/replaymod/replay/camera/VanillaCameraController.java @@ -39,7 +39,7 @@ public class VanillaCameraController implements CameraController { if (partialTicksPassed == 0) return; Vector3f direction = new Vector3f(0, 0, 0); for (int i = 0; i < 6; i++) { // First, get movement direction depending on keys pressed - if (bindings[i].isKeyDown()) { + if (bindings[i].getIsKeyPressed()) { Vector3f.add(direction, DIRECTIONS[i], direction); } } diff --git a/src/main/java/com/replaymod/replay/events/ReplayChatMessageEvent.java b/src/main/java/com/replaymod/replay/events/ReplayChatMessageEvent.java index c29c594e..54a1d64b 100644 --- a/src/main/java/com/replaymod/replay/events/ReplayChatMessageEvent.java +++ b/src/main/java/com/replaymod/replay/events/ReplayChatMessageEvent.java @@ -1,10 +1,10 @@ package com.replaymod.replay.events; import com.replaymod.replay.camera.CameraEntity; +import cpw.mods.fml.common.eventhandler.Cancelable; +import cpw.mods.fml.common.eventhandler.Event; import lombok.Getter; import lombok.RequiredArgsConstructor; -import net.minecraftforge.fml.common.eventhandler.Cancelable; -import net.minecraftforge.fml.common.eventhandler.Event; @Cancelable @RequiredArgsConstructor diff --git a/src/main/java/com/replaymod/replay/events/ReplayCloseEvent.java b/src/main/java/com/replaymod/replay/events/ReplayCloseEvent.java index f01720e6..8d3789d0 100644 --- a/src/main/java/com/replaymod/replay/events/ReplayCloseEvent.java +++ b/src/main/java/com/replaymod/replay/events/ReplayCloseEvent.java @@ -1,9 +1,9 @@ package com.replaymod.replay.events; import com.replaymod.replay.ReplayHandler; +import cpw.mods.fml.common.eventhandler.Event; import lombok.Getter; import lombok.RequiredArgsConstructor; -import net.minecraftforge.fml.common.eventhandler.Event; @RequiredArgsConstructor public abstract class ReplayCloseEvent extends Event { diff --git a/src/main/java/com/replaymod/replay/events/ReplayOpenEvent.java b/src/main/java/com/replaymod/replay/events/ReplayOpenEvent.java index ad970a37..89d5c233 100644 --- a/src/main/java/com/replaymod/replay/events/ReplayOpenEvent.java +++ b/src/main/java/com/replaymod/replay/events/ReplayOpenEvent.java @@ -1,9 +1,9 @@ package com.replaymod.replay.events; import com.replaymod.replay.ReplayHandler; +import cpw.mods.fml.common.eventhandler.Event; import lombok.Getter; import lombok.RequiredArgsConstructor; -import net.minecraftforge.fml.common.eventhandler.Event; @RequiredArgsConstructor public abstract class ReplayOpenEvent extends Event { diff --git a/src/main/java/com/replaymod/replay/gui/overlay/GuiReplayOverlay.java b/src/main/java/com/replaymod/replay/gui/overlay/GuiReplayOverlay.java index 63c4326d..16288154 100644 --- a/src/main/java/com/replaymod/replay/gui/overlay/GuiReplayOverlay.java +++ b/src/main/java/com/replaymod/replay/gui/overlay/GuiReplayOverlay.java @@ -3,6 +3,9 @@ package com.replaymod.replay.gui.overlay; import com.replaymod.core.ReplayMod; import com.replaymod.replay.ReplayHandler; import com.replaymod.replay.ReplaySender; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.InputEvent; import de.johni0702.minecraft.gui.GuiRenderer; import de.johni0702.minecraft.gui.RenderInfo; import de.johni0702.minecraft.gui.container.AbstractGuiOverlay; @@ -16,9 +19,6 @@ import de.johni0702.minecraft.gui.layout.CustomLayout; import de.johni0702.minecraft.gui.layout.HorizontalLayout; import net.minecraft.client.resources.I18n; import net.minecraft.client.settings.GameSettings; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.InputEvent; import org.lwjgl.input.Keyboard; import org.lwjgl.util.ReadableDimension; import org.lwjgl.util.ReadablePoint; diff --git a/src/main/java/com/replaymod/replay/gui/screen/GuiOpeningReplay.java b/src/main/java/com/replaymod/replay/gui/screen/GuiOpeningReplay.java new file mode 100644 index 00000000..5fc69a32 --- /dev/null +++ b/src/main/java/com/replaymod/replay/gui/screen/GuiOpeningReplay.java @@ -0,0 +1,17 @@ +package com.replaymod.replay.gui.screen; + +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.network.NetworkManager; + +public class GuiOpeningReplay extends GuiScreen { + private final NetworkManager networkManager; + + public GuiOpeningReplay(NetworkManager networkManager) { + this.networkManager = networkManager; + } + + @Override + public void handleInput() { + networkManager.processReceivedPackets(); + } +} diff --git a/src/main/java/com/replaymod/replay/handler/GuiHandler.java b/src/main/java/com/replaymod/replay/handler/GuiHandler.java index f05d2971..6cbb03b4 100644 --- a/src/main/java/com/replaymod/replay/handler/GuiHandler.java +++ b/src/main/java/com/replaymod/replay/handler/GuiHandler.java @@ -2,6 +2,8 @@ package com.replaymod.replay.handler; import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.gui.screen.GuiReplayViewer; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiIngameMenu; @@ -9,8 +11,6 @@ import net.minecraft.client.gui.GuiMainMenu; import net.minecraft.client.resources.I18n; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import java.io.IOException; import java.util.ArrayList; diff --git a/src/main/java/com/replaymod/replay/mixin/MixinGuiSpectator.java b/src/main/java/com/replaymod/replay/mixin/MixinGuiSpectator.java deleted file mode 100644 index 081c702c..00000000 --- a/src/main/java/com/replaymod/replay/mixin/MixinGuiSpectator.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.replaymod.replay.mixin; - -import com.replaymod.replay.camera.CameraEntity; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiSpectator; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(GuiSpectator.class) -public abstract class MixinGuiSpectator { - @Shadow - private Minecraft field_175268_g; - - @Inject(method = "func_175260_a", at = @At("HEAD"), cancellable = true) - public void isInReplay(int i, CallbackInfo ci) { - // Prevent spectator gui from opening while in a replay - if (field_175268_g.thePlayer instanceof CameraEntity) { - ci.cancel(); - } - } -} diff --git a/src/main/java/com/replaymod/replay/mixin/MixinPlayerControllerMP.java b/src/main/java/com/replaymod/replay/mixin/MixinPlayerControllerMP.java index 2998fec5..24a74777 100644 --- a/src/main/java/com/replaymod/replay/mixin/MixinPlayerControllerMP.java +++ b/src/main/java/com/replaymod/replay/mixin/MixinPlayerControllerMP.java @@ -1,9 +1,9 @@ package com.replaymod.replay.mixin; -import com.replaymod.replay.camera.CameraEntity; import com.replaymod.replay.ReplayModReplay; +import com.replaymod.replay.camera.CameraEntity; import net.minecraft.client.Minecraft; -import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.entity.EntityClientPlayerMP; import net.minecraft.client.multiplayer.PlayerControllerMP; import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.stats.StatFileWriter; @@ -12,6 +12,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(PlayerControllerMP.class) @@ -23,18 +24,23 @@ public abstract class MixinPlayerControllerMP { @Shadow private NetHandlerPlayClient netClientHandler; - @Inject(method = "func_178892_a", at=@At("HEAD"), cancellable = true) - private void replayModReplay_createReplayCamera(World worldIn, StatFileWriter statFileWriter, CallbackInfoReturnable ci) { + @Inject(method = "createPlayer", at=@At("HEAD"), cancellable = true) + private void replayModReplay_createReplayCamera(World worldIn, StatFileWriter statFileWriter, CallbackInfoReturnable ci) { if (ReplayModReplay.instance.getReplayHandler() != null) { - ci.setReturnValue(new CameraEntity(mc, worldIn, netClientHandler, statFileWriter)); + ci.setReturnValue(new CameraEntity(mc, worldIn, mc.getSession(), netClientHandler, statFileWriter)); ci.cancel(); } } - @Inject(method = "isSpectator", at=@At("HEAD"), cancellable = true) - private void replayModReplay_isSpectator(CallbackInfoReturnable ci) { - if (mc.thePlayer instanceof CameraEntity) { // this check should in theory not be required - ci.setReturnValue(mc.thePlayer.isSpectator()); + // Prevent the disconnect GUI from being opened during the short time when the replay is restarted + // at which the old network manager is closed but still getting ticked (hence the disconnect GUI opening). + @Inject(method = "updateController", at = @At("HEAD"), cancellable = true) + private void replayModReplay_onlyTickNeverDisconnect(CallbackInfo ci) { + if (ReplayModReplay.instance.getReplayHandler() != null) { + if (netClientHandler.getNetworkManager().isChannelOpen()) { + netClientHandler.getNetworkManager().processReceivedPackets(); + } + ci.cancel(); } } } diff --git a/src/main/java/com/replaymod/replay/mixin/MixinRenderArrow.java b/src/main/java/com/replaymod/replay/mixin/MixinRenderArrow.java deleted file mode 100644 index 03787d5d..00000000 --- a/src/main/java/com/replaymod/replay/mixin/MixinRenderArrow.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.replaymod.replay.mixin; - -import com.replaymod.replay.ReplayModReplay; -import net.minecraft.client.renderer.culling.ICamera; -import net.minecraft.client.renderer.entity.Render; -import net.minecraft.client.renderer.entity.RenderArrow; -import net.minecraft.client.renderer.entity.RenderManager; -import net.minecraft.entity.Entity; -import org.spongepowered.asm.mixin.Mixin; - -@Mixin(RenderArrow.class) -public abstract class MixinRenderArrow extends Render { - protected MixinRenderArrow(RenderManager renderManager) { - super(renderManager); - } - - @Override - public boolean shouldRender(Entity entity, ICamera camera, double camX, double camY, double camZ) { - // Force arrows to always render, otherwise they stop rendering when you get close to them - return ReplayModReplay.instance.getReplayHandler() != null || super.shouldRender(entity, camera, camX, camY, camZ); - } -} diff --git a/src/main/java/com/replaymod/replay/mixin/MixinRenderManager.java b/src/main/java/com/replaymod/replay/mixin/MixinRenderManager.java deleted file mode 100644 index 5c738d72..00000000 --- a/src/main/java/com/replaymod/replay/mixin/MixinRenderManager.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.replaymod.replay.mixin; - -import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.renderer.entity.RenderManager; -import net.minecraft.client.settings.GameSettings; -import net.minecraft.entity.Entity; -import net.minecraft.entity.passive.EntityAnimal; -import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(RenderManager.class) -public class MixinRenderManager { - @Shadow - private float playerViewY; - - @Inject(method = "cacheActiveRenderInfo", at = @At("RETURN")) - public void fixHeadRotationForAnimals(World world, FontRenderer font, Entity view, Entity target, GameSettings settings, float partialRenderTick, CallbackInfo ci) { - if (view instanceof EntityAnimal && !((EntityAnimal) view).isPlayerSleeping()) { - EntityAnimal e = (EntityAnimal) view; - this.playerViewY = e.prevRotationYawHead + (e.rotationYawHead - e.prevRotationYawHead) * partialRenderTick; - } - } -} diff --git a/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java b/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java index f6cca14a..88fa500d 100644 --- a/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java +++ b/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java @@ -3,14 +3,14 @@ package com.replaymod.replay.mixin; import com.replaymod.replay.ReplayHandler; import com.replaymod.replay.ReplayModReplay; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.tileentity.TileEntityEndPortalRenderer; +import net.minecraft.client.renderer.tileentity.RenderEndPortal; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -@Mixin(TileEntityEndPortalRenderer.class) +@Mixin(RenderEndPortal.class) public class MixinTileEntityEndPortalRenderer { - @Redirect(method = "func_180544_a", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;getSystemTime()J")) + @Redirect(method = "renderTileEntityAt", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;getSystemTime()J")) private long replayModReplay_getEnchantmentTime() { ReplayHandler replayHandler = ReplayModReplay.instance.getReplayHandler(); if (replayHandler != null) { diff --git a/src/main/java/com/replaymod/replay/mixin/MixinViewFrustum.java b/src/main/java/com/replaymod/replay/mixin/MixinViewFrustum.java deleted file mode 100644 index 94e44a58..00000000 --- a/src/main/java/com/replaymod/replay/mixin/MixinViewFrustum.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.replaymod.replay.mixin; - -import com.replaymod.replay.ReplayModReplay; -import net.minecraft.client.renderer.RenderGlobal; -import net.minecraft.client.renderer.ViewFrustum; -import net.minecraft.client.renderer.chunk.IRenderChunkFactory; -import net.minecraft.client.renderer.chunk.RenderChunk; -import net.minecraft.util.BlockPos; -import net.minecraft.util.MathHelper; -import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(ViewFrustum.class) -public abstract class MixinViewFrustum { - private IRenderChunkFactory renderChunkFactory; - - @Shadow protected RenderGlobal renderGlobal; - @Shadow protected World world; - @Shadow protected int countChunksY; - @Shadow protected int countChunksX; - @Shadow protected int countChunksZ; - @Shadow public RenderChunk[] renderChunks; - - @Inject(method = "", at = @At("RETURN")) - private void setRenderChunkFactory(World a1, int a2, RenderGlobal a3, IRenderChunkFactory rcf, CallbackInfo ci) { - this.renderChunkFactory = rcf; - } - - /** - * Instead of calling {@link RenderChunk#setPosition(BlockPos)} we recreate the render chunk - * which seems to solve the problem that chunks are invisible when you leave an area and return - * to it. - * Any better fixes are welcome. - * Note: Most of this code is copied from {@link ViewFrustum#updateChunkPositions(double, double)} - */ - @Inject(method = "updateChunkPositions", at = @At("HEAD"), cancellable = true) - public void fixedUpdateChunkPositions(double viewEntityX, double viewEntityZ, CallbackInfo ci) { - if (ReplayModReplay.instance.getReplayHandler() == null) { - return; - } - - int i = MathHelper.floor_double(viewEntityX) - 8; - int j = MathHelper.floor_double(viewEntityZ) - 8; - int k = this.countChunksX * 16; - - for (int l = 0; l < this.countChunksX; ++l) { - int i1 = this.func_178157_a(i, k, l); - for (int j1 = 0; j1 < this.countChunksZ; ++j1) { - int k1 = this.func_178157_a(j, k, j1); - for (int l1 = 0; l1 < this.countChunksY; ++l1) { - int i2 = l1 * 16; - RenderChunk renderchunk = this.renderChunks[(j1 * this.countChunksY + l1) * this.countChunksX + l]; - BlockPos blockpos = new BlockPos(i1, i2, k1); - if (!blockpos.equals(renderchunk.getPosition())) { - // Recreate render chunk instead of setting its position - renderChunks[(j1 * this.countChunksY + l1) * this.countChunksX + l] = - renderChunkFactory.makeRenderChunk(world, renderGlobal, blockpos, 0); - } - } - } - } - ci.cancel(); - } - - @Shadow abstract int func_178157_a(int p_178157_1_, int p_178157_2_, int p_178157_3_); -} diff --git a/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java b/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java index ecb1e436..050fa668 100644 --- a/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java +++ b/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java @@ -8,11 +8,11 @@ import com.replaymod.replaystudio.pathing.path.Keyframe; import com.replaymod.simplepathing.SPTimeline.SPPath; import com.replaymod.simplepathing.gui.GuiPathing; import com.replaymod.simplepathing.preview.PathPreview; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import lombok.Getter; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.apache.logging.log4j.Logger; import org.lwjgl.input.Keyboard; diff --git a/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java b/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java index 77854930..f0d97b9a 100644 --- a/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java +++ b/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java @@ -24,6 +24,7 @@ import com.replaymod.replaystudio.util.EntityPositionTracker; import com.replaymod.simplepathing.ReplayModSimplePathing; import com.replaymod.simplepathing.SPTimeline; import com.replaymod.simplepathing.SPTimeline.SPPath; +import cpw.mods.fml.common.Loader; import de.johni0702.minecraft.gui.GuiRenderer; import de.johni0702.minecraft.gui.RenderInfo; import de.johni0702.minecraft.gui.container.GuiContainer; @@ -46,7 +47,6 @@ import de.johni0702.minecraft.gui.popup.GuiInfoPopup; import de.johni0702.minecraft.gui.popup.GuiYesNoPopup; import de.johni0702.minecraft.gui.utils.Colors; import net.minecraft.crash.CrashReport; -import net.minecraftforge.fml.common.Loader; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.input.Keyboard; @@ -618,7 +618,7 @@ public class GuiPathing { CameraEntity camera = replayHandler.getCameraEntity(); int spectatedId = -1; if (!replayHandler.isCameraView()) { - spectatedId = replayHandler.getOverlay().getMinecraft().getRenderViewEntity().getEntityId(); + spectatedId = replayHandler.getOverlay().getMinecraft().renderViewEntity.getEntityId(); } timeline.addPositionKeyframe(time, camera.posX, camera.posY, camera.posZ, camera.rotationYaw, camera.rotationPitch, camera.roll, spectatedId); diff --git a/src/main/java/com/replaymod/simplepathing/preview/PathPreview.java b/src/main/java/com/replaymod/simplepathing/preview/PathPreview.java index 30a60336..b8152495 100644 --- a/src/main/java/com/replaymod/simplepathing/preview/PathPreview.java +++ b/src/main/java/com/replaymod/simplepathing/preview/PathPreview.java @@ -8,8 +8,8 @@ import com.replaymod.replay.events.ReplayCloseEvent; import com.replaymod.replay.events.ReplayOpenEvent; import com.replaymod.simplepathing.ReplayModSimplePathing; import com.replaymod.simplepathing.Setting; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import org.lwjgl.input.Keyboard; public class PathPreview { diff --git a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java index 070c8d30..ba01f779 100644 --- a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java +++ b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java @@ -14,15 +14,14 @@ import com.replaymod.replaystudio.util.Location; import com.replaymod.simplepathing.ReplayModSimplePathing; import com.replaymod.simplepathing.SPTimeline; import com.replaymod.simplepathing.gui.GuiPathing; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.Entity; import net.minecraft.util.ResourceLocation; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; import org.lwjgl.opengl.GL11; @@ -60,7 +59,7 @@ public class PathPreviewRenderer { public void renderCameraPath(RenderWorldLastEvent event) { if (!replayHandler.getReplaySender().isAsyncMode() || mc.gameSettings.hideGUI) return; - Entity view = mc.getRenderViewEntity(); + Entity view = mc.renderViewEntity; if (view == null) return; GuiPathing guiPathing = mod.getGuiPathing(); @@ -79,7 +78,8 @@ public class PathPreviewRenderer { int renderDistanceSquared = renderDistance * renderDistance; // Eye height is subtracted to make path appear higher (at eye height) than it actually is (at foot height) - Triple viewPos = Triple.of(view.posX, view.posY - view.getEyeHeight(), view.posZ); + // ^ Not for 1.7.10 (posY is the eye height of the camera) + Triple viewPos = Triple.of(view.posX, view.posY, view.posZ); GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); try { @@ -174,7 +174,7 @@ public class PathPreviewRenderer { } } } finally { - GlStateManager.popAttrib(); + GL11.glPopAttrib(); } } @@ -202,8 +202,7 @@ public class PathPreviewRenderer { if (distanceSquared(view, pos1) > renderDistanceSquared) return; if (distanceSquared(view, pos2) > renderDistanceSquared) return; - Tessellator tessellator = Tessellator.getInstance(); - WorldRenderer renderer = tessellator.getWorldRenderer(); + Tessellator renderer = Tessellator.instance; renderer.setTranslation(-view.getLeft(), -view.getMiddle(), -view.getRight()); renderer.startDrawing(GL11.GL_LINES); @@ -213,15 +212,14 @@ public class PathPreviewRenderer { renderer.addVertex(pos2.getLeft(), pos2.getMiddle(), pos2.getRight()); GL11.glLineWidth(3); - tessellator.draw(); + renderer.draw(); renderer.setTranslation(0, 0, 0); } private void drawPoint(Triple view, Triple pos, Keyframe keyframe) { - Tessellator tessellator = Tessellator.getInstance(); - WorldRenderer renderer = tessellator.getWorldRenderer(); + Tessellator renderer = Tessellator.instance; renderer.setTranslation(0, 0, 0); mc.renderEngine.bindTexture(TEXTURE); @@ -258,10 +256,10 @@ public class PathPreviewRenderer { pos.getRight() - view.getRight() ); GL11.glNormal3f(0, 1, 0); - GL11.glRotatef(-mc.getRenderManager().playerViewY, 0, 1, 0); - GL11.glRotatef(mc.getRenderManager().playerViewX, 1, 0, 0); + GL11.glRotatef(-RenderManager.instance.playerViewY, 0, 1, 0); + GL11.glRotatef(RenderManager.instance.playerViewX, 1, 0, 0); - tessellator.draw(); + renderer.draw(); GL11.glPopMatrix(); } @@ -269,8 +267,7 @@ public class PathPreviewRenderer { private void drawCamera(Triple view, Triple pos, Triple rot) { - Tessellator tessellator = Tessellator.getInstance(); - WorldRenderer renderer = tessellator.getWorldRenderer(); + Tessellator renderer = Tessellator.instance; renderer.setTranslation(0, 0, 0); mc.renderEngine.bindTexture(CAMERA_HEAD); @@ -296,7 +293,7 @@ public class PathPreviewRenderer { renderer.addVertex(0, 0, 0); renderer.addVertex(0, 0, 2); - tessellator.draw(); + renderer.draw(); // draw camera cube GL11.glEnable(GL11.GL_TEXTURE_2D); @@ -345,7 +342,7 @@ public class PathPreviewRenderer { renderer.addVertexWithUV(r + cubeSize, r + cubeSize, r + cubeSize, 2*8/64f, 8/64f); renderer.addVertexWithUV(r + cubeSize, r + cubeSize, r, 2 * 8 / 64f, 0); - tessellator.draw(); + renderer.draw(); GL11.glPopMatrix(); } diff --git a/src/main/resources/META-INF/replaymod_at.cfg b/src/main/resources/META-INF/replaymod_at.cfg index 59d3b95e..87be2711 100644 --- a/src/main/resources/META-INF/replaymod_at.cfg +++ b/src/main/resources/META-INF/replaymod_at.cfg @@ -47,8 +47,8 @@ public net.minecraft.entity.Entity field_70180_af # dataWatcher # ResourcePackRepository public net.minecraft.client.resources.ResourcePackRepository field_148534_e # dirServerResourcepacks -public net.minecraft.client.resources.ResourcePackRepository field_177321_h # lock -public net.minecraft.client.resources.ResourcePackRepository field_177322_i # httpRequest +public net.minecraft.client.resources.ResourcePackRepository field_148532_f # resourcePack +public net.minecraft.client.resources.ResourcePackRepository field_148533_g # currentlyDownloading # EntityRenderer public net.minecraft.client.renderer.EntityRenderer * diff --git a/src/main/resources/assets/replaymod/shader/ods.frag b/src/main/resources/assets/replaymod/shader/ods.frag index ef46047b..9886edb9 100644 --- a/src/main/resources/assets/replaymod/shader/ods.frag +++ b/src/main/resources/assets/replaymod/shader/ods.frag @@ -10,7 +10,6 @@ uniform sampler2D lightMap; uniform bool textureEnabled; uniform bool lightMapEnabled; -uniform bool hurtTextureEnabled; uniform bool fogEnabled; void main() { @@ -21,9 +20,6 @@ void main() { if (lightMapEnabled) { color *= texture2D(lightMap, lightMapCoord.st); } - if (hurtTextureEnabled) { - color = vec4(mix(color.rgb, vec3(1, 0, 0), 0.3), color.a); - } if (fogEnabled) { color.rgb = mix(color.rgb, gl_Fog.color.rgb, clamp((gl_FogFragCoord - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0)); } diff --git a/src/main/resources/mixins.compat.shaders.replaymod.json b/src/main/resources/mixins.compat.shaders.replaymod.json index 792af576..9eb7f2b6 100644 --- a/src/main/resources/mixins.compat.shaders.replaymod.json +++ b/src/main/resources/mixins.compat.shaders.replaymod.json @@ -4,9 +4,7 @@ "mixins": [], "server": [], "client": [ - "MixinShaderEntityRenderer", - "MixinShaderRenderChunk", - "MixinShaderRenderGlobal", + "MixinShaders", "MixinShadersRender" ], "compatibilityLevel": "JAVA_8", diff --git a/src/main/resources/mixins.extras.playeroverview.replaymod.json b/src/main/resources/mixins.extras.playeroverview.replaymod.json index 7c9a0a1f..a1da3fc4 100644 --- a/src/main/resources/mixins.extras.playeroverview.replaymod.json +++ b/src/main/resources/mixins.extras.playeroverview.replaymod.json @@ -4,7 +4,7 @@ "mixins": [], "server": [], "client": [ - "MixinRender" + "MixinRenderPlayer" ], "compatibilityLevel": "JAVA_8", "refmap": "mixins.replaymod.refmap.json" diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index a2e940c8..6f6a8eb3 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -5,9 +5,9 @@ "MixinEffectRenderer", "MixinEntityRenderer", "MixinFrustum", + "MixinOpenGlHelper", "MixinRender", "MixinRendererLivingEntity", - "MixinRenderGlobal", "MixinRenderManager" ], "server": [], diff --git a/src/main/resources/mixins.replay.replaymod.json b/src/main/resources/mixins.replay.replaymod.json index 8d02ed09..37ae38fd 100644 --- a/src/main/resources/mixins.replay.replaymod.json +++ b/src/main/resources/mixins.replay.replaymod.json @@ -2,14 +2,10 @@ "required": true, "package": "com.replaymod.replay.mixin", "mixins": [ - "MixinGuiSpectator", "MixinPlayerControllerMP", - "MixinRenderArrow", "MixinRendererLivingEntity", "MixinRenderItem", - "MixinRenderManager", "MixinTileEntityEndPortalRenderer", - "MixinViewFrustum", "MixinWorldClient" ], "server": [],