From ad49a69f379c0f7776bdefcc00250ee082c20be4 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 29 May 2022 18:08:42 +0200 Subject: [PATCH 01/28] Switch from FG to archloom + essential-gradle-toolkit - Upgrade Gradle to 8.7 - Increase build daemon max memory to 8GB because archloom can compile a lot more projects at the same time. - Disable Minecraft 1.8 (not 1.8.9) because archloom fails to set up for that --- .gitignore | Bin 2605 -> 2614 bytes build.gradle | 735 ------------------ build.gradle.kts | 337 ++++++++ gradle.properties | 5 +- gradle/wrapper/gradle-wrapper.properties | 2 +- jGui | 2 +- root.gradle.kts | 16 +- settings.gradle.kts | 24 +- .../java/com/replaymod/render/EXRWriter.java | 6 +- .../replaymod/replay/FullReplaySender.java | 5 + src/main/resources/mcmod.info | 16 +- .../com/replaymod/core/ReplayModBackend.java | 2 - versions/1.14.4-forge/gradle.properties | 1 + versions/1.18.1/gradle.properties | 1 + versions/1.18.2/gradle.properties | 1 + versions/1.19.2/gradle.properties | 1 + versions/1.19.3/gradle.properties | 2 + versions/1.20.2/logs/latest.log | 0 versions/1.8.9/gradle.properties | 1 + 19 files changed, 390 insertions(+), 767 deletions(-) delete mode 100644 build.gradle create mode 100644 build.gradle.kts create mode 100644 versions/1.14.4-forge/gradle.properties create mode 100644 versions/1.18.1/gradle.properties create mode 100644 versions/1.18.2/gradle.properties create mode 100644 versions/1.19.2/gradle.properties create mode 100644 versions/1.19.3/gradle.properties delete mode 100644 versions/1.20.2/logs/latest.log create mode 100644 versions/1.8.9/gradle.properties diff --git a/.gitignore b/.gitignore index 37399e16c7aac5fd9c47c4cd6b9f1b1f90b5b957..0b48d75f58d335cd68d2bbca975ca0ab164215fe 100644 GIT binary patch delta 17 YcmZ20vQ1=zE*Ga>S#ffHN~%5=05p3AX8-^I delta 7 OcmdlcvQ}h+E*Ag`o&s|K diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 12d0c9db..00000000 --- a/build.gradle +++ /dev/null @@ -1,735 +0,0 @@ -import com.replaymod.gradle.preprocess.PreprocessTask -import static gg.essential.gradle.util.PrebundleKt.prebundle - -buildscript { - def mcVersion - def (major, minor, patch) = project.name.tokenize('-')[0].tokenize('.') - mcVersion = "${major}${minor.padLeft(2, '0')}${(patch ?: '').padLeft(2, '0')}" as int - def fabric = mcVersion >= 11400 && !project.name.endsWith("-forge") - project.ext.mcVersion = mcVersion - project.ext.fabric = fabric - - repositories { - mavenLocal() - maven { - url = "https://plugins.gradle.org/m2/" - } - mavenCentral() - maven { - name = "fabric" - url = "https://maven.fabricmc.net/" - } - maven { - name = "forge" - url = "https://maven.minecraftforge.net" - } - maven { - name = "sonatype" - url = "https://oss.sonatype.org/content/repositories/snapshots/" - } - maven { url 'https://jitpack.io' } - maven { url "https://maven.architectury.dev" } - maven { url "https://repo.essential.gg/repository/maven-public" } - } - - dependencies { - classpath 'gradle.plugin.com.github.jengelman.gradle.plugins:shadow:7.0.0' - if (fabric) { - classpath 'fabric-loom:fabric-loom.gradle.plugin:0.11-SNAPSHOT' - } else if (mcVersion >= 11400) { - classpath('net.minecraftforge.gradle:ForgeGradle:5.0.5') { // the FG people still haven't learned to not do breaking changes - exclude group: 'trove', module: 'trove' // preprocessor/idea requires more recent one - } - } else if (mcVersion >= 10800) { - classpath('com.github.ReplayMod:ForgeGradle:' + ( - mcVersion >= 11200 ? '34ab703' : // FG 2.3 - mcVersion >= 10904 ? '5d1e8d8' : // FG 2.2 - 'ceb83c0' // FG 2.1 - ) + ':all') - } else { - classpath 'com.github.ReplayMod:ForgeGradle:a8a9e0ca:all' // FG 1.2 - } - classpath 'gg.essential:essential-gradle-toolkit:0.1.10' - } -} - -def FG3 = !fabric && mcVersion >= 11400 -def FABRIC = fabric - -def jGuiVersion = project.name -if (['1.10.2', '1.11', '1.11.2'].contains(jGuiVersion)) jGuiVersion = '1.9.4' -if (['1.12.1', '1.12.2'].contains(jGuiVersion)) jGuiVersion = '1.12' -def jGui = project.evaluationDependsOn(":jGui:$jGuiVersion") - -apply plugin: 'com.github.johnrengelman.shadow' - -if (mcVersion >= 10800) { - if (FABRIC) { - apply plugin: 'fabric-loom' - } else if (FG3) { - apply plugin: 'net.minecraftforge.gradle' - } else { - apply plugin: 'net.minecraftforge.gradle.forge' - } -} else { - apply plugin: 'forge' -} - -if (!FABRIC) { - ext { - mixinSrg = new File(project.buildDir, 'tmp/mixins/mixins.srg') - mixinRefMap = new File(project.buildDir, 'tmp/mixins/mixins.replaymod.refmap.json') - } - - compileJava { - options.compilerArgs += [ - "-AoutSrgFile=${project.mixinSrg.canonicalPath}", - "-AoutRefMapFile=${project.mixinRefMap.canonicalPath}", - "-AreobfSrgFile=${project.file('build/mcp-srg.srg').canonicalPath}" - ] - } -} - -apply plugin: 'com.replaymod.preprocess' - -preprocess { - vars.put("MC", project.mcVersion) - vars.put("FABRIC", project.fabric ? 1 : 0) - - keywords.set([ - ".java": PreprocessTask.DEFAULT_KEYWORDS, - ".json": PreprocessTask.DEFAULT_KEYWORDS, - ".mcmeta": PreprocessTask.DEFAULT_KEYWORDS, - ".cfg": PreprocessTask.CFG_KEYWORDS, - ".vert": PreprocessTask.DEFAULT_KEYWORDS, - ".frag": PreprocessTask.DEFAULT_KEYWORDS, - ]) - - patternAnnotation.set("com.replaymod.gradle.remap.Pattern") -} - -def mcVersionStr = "${(int)(mcVersion/10000)}.${(int)(mcVersion/100)%100}" + (mcVersion%100==0 ? '' : ".${mcVersion%100}") - -sourceCompatibility = targetCompatibility = mcVersion >= 11800 ? 17 : mcVersion >= 11700 ? 16 : 1.8 -tasks.withType(JavaCompile).configureEach { - options.release = mcVersion >= 11800 ? 17 : mcVersion >= 11700 ? 16 : 8 -} - -if (mcVersion >= 11400) { - sourceSets { - api - } -} - -version = project.name + '-' + rootProject.version -group= "com.replaymod" -archivesBaseName = "replaymod" - -if (FABRIC) { - loom { - mixin.defaultRefmapName.set('mixins.replaymod.refmap.json') - runConfigs.all { - ideConfigGenerated = true - } - } -} else { - minecraft { - if (FG3) { - runs { - client { - workingDirectory rootProject.file('run') - property 'forge.logging.console.level', 'info' - mods { - replaymod { - source sourceSets.main - } - } - } - } - } else { - if (mcVersion >= 10800) { - coreMod = 'com.replaymod.core.LoadingPlugin' - } - runDir = "../../run" - } - - if (!FG3) { - version = [ - 11202: '1.12.2-14.23.0.2486', - 11201: '1.12.1-14.22.0.2444', - 11200: '1.12-14.21.1.2387', - 11102: '1.11.2-13.20.0.2216', - 11100: '1.11-13.19.1.2188', - 11002: '1.10.2-12.18.2.2099', - 10904: '1.9.4-12.17.0.1976', - 10809: '1.8.9-11.15.1.1722', - 10800: '1.8-11.14.4.1563', - 10710: '1.7.10-10.13.4.1558-1.7.10', - ][mcVersion] - } - mappings = [ - 11404: "snapshot_20190719-1.14.3", - 11202: "snapshot_20170615", - 11201: "snapshot_20170615", - 11200: "snapshot_20170615", - 11102: "snapshot_20161220", - 11100: "snapshot_20161111", - 11002: "snapshot_20160518", - 10904: "snapshot_20160518", - 10809: "stable_22", - 10800: "snapshot_nodoc_20141130", - 10710: "stable_12", - ][mcVersion] - } -} - -afterEvaluate { - if (mcVersion >= 11400) { - // No longer required in 1.13+ because all version info is in the toml file - } else { - // Note cannot use minecraft.replace because that has already been forwarded to the task by FG by now - tasks.sourceMainJava.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) - tasks.sourceMainJava.replace '@MC_VERSION@', "[ $mcVersionStr ]" - } -} - -repositories { - mavenLocal() - maven { - name = "SpongePowered Repo" - url = "https://repo.spongepowered.org/maven/" - } - maven { - name = "fabric" - url = "https://maven.fabricmc.net/" - } - maven { - url 'https://maven.terraformersmc.com/releases/' - content { - includeGroup 'com.terraformersmc' - } - } - maven { - url 'https://jitpack.io' - content { - includeGroupByRegex 'com\\.github\\..*' - } - } - exclusiveContent { - forRepository { - maven { - name = "Modrinth" - url = "https://api.modrinth.com/maven" - } - } - filter { - includeGroup "maven.modrinth" - } - } -} - -configurations { - // Include dep in fat jar without relocation and, when forge supports it, without exploding (TODO) - shade - implementation.extendsFrom shade - // Include dep in fat jar with relocation and minimization - shadow - implementation.extendsFrom shadow -} - -def shadeExclusions = { - // Cannot just add these to the shade configuration because they'd be inherited by the compile configuration then - exclude group: 'com.google.guava', module: 'guava-jdk5' - exclude group: 'com.google.guava', module: 'guava' // provided by MC - exclude group: 'com.google.code.gson', module: 'gson' // provided by MC (or manually bundled for 1.11.2 and below) -} - -dependencies { - if (FABRIC) { - minecraft 'com.mojang:minecraft:' + [ - 11404: '1.14.4', - 11502: '1.15.2', - 11601: '1.16.1', - 11603: '1.16.3', - 11604: '1.16.4', - 11701: '1.17.1', - 11800: '1.18', - 11801: '1.18.1', - 11802: '1.18.2', - 11900: '1.19', - 11901: '1.19.1', - 11902: '1.19.2', - 11903: '1.19.3-rc3', - 11904: '1.19.4', - 12001: '1.20.1', - 12002: '1.20.2', - 12004: '1.20.4', - ][mcVersion] - mappings 'net.fabricmc:yarn:' + [ - 11404: '1.14.4+build.16', - 11502: '1.15.2+build.14', - 11601: '1.16.1+build.17:v2', - 11603: '1.16.3+build.1:v2', - 11604: '1.16.4+build.6:v2', - 11701: '1.17.1+build.29:v2', - 11800: '1.18+build.1:v2', - 11801: '1.18.1+build.1:v2', - 11802: '1.18.2+build.1:v2', - 11900: '1.19+build.2:v2', - 11901: '1.19.1+build.5:v2', - 11902: '1.19.2+build.28:v2', - 11903: '1.19.3-rc3+build.1:v2', - 11904: '1.19.4+build.1:v2', - 12001: '1.20.1+build.2:v2', - 12002: '1.20.2+build.4:v2', - 12004: '1.20.4+build.1:v2', - ][mcVersion] - modImplementation 'net.fabricmc:fabric-loader:0.15.1' - def fabricApiVersion = [ - 11404: '0.4.3+build.247-1.14', - 11502: '0.5.1+build.294-1.15', - 11601: '0.14.0+build.371-1.16', - 11603: '0.17.1+build.394-1.16', - 11604: '0.42.0+1.16', - 11701: '0.46.1+1.17', - 11800: '0.43.1+1.18', - 11801: '0.43.1+1.18', - 11802: '0.47.9+1.18.2', - 11900: '0.55.3+1.19', - 11901: '0.58.5+1.19.1', - 11902: '0.68.0+1.19.2', - 11903: '0.68.1+1.19.3', - 11904: '0.76.0+1.19.4', - 12001: '0.83.1+1.20.1', - 12002: '0.91.2+1.20.2', - 12004: '0.91.2+1.20.4', - ][mcVersion] - def fabricApiModules = [ - "api-base", - "networking-v0", - "keybindings-v0", - "resource-loader-v0", - ] - if (mcVersion >= 11600) { - fabricApiModules.remove("keybindings-v0") - fabricApiModules.add("key-binding-api-v1") - } - if (mcVersion >= 11604) { - fabricApiModules.add("screen-api-v1") - fabricApiModules.add("networking-api-v1") - } - if (mcVersion >= 11700) { - fabricApiModules.remove("networking-v0") - } - fabricApiModules.each { module -> - modImplementation fabricApi.module("fabric-$module", fabricApiVersion) - include fabricApi.module("fabric-$module", fabricApiVersion) - } - } - - if (FG3) { - minecraft 'net.minecraftforge:forge:' + [ - 11404: '1.14.4-28.1.113', - ][mcVersion] - } - - if (!FABRIC) { - // Mixin 0.8 is no longer compatible with MC 1.11.2 or older - def mixinVersion = mcVersion >= 11200 ? '0.8.2' : '0.7.11-SNAPSHOT' - annotationProcessor "org.spongepowered:mixin:$mixinVersion" - compileOnly "org.spongepowered:mixin:$mixinVersion" - shade("org.spongepowered:mixin:$mixinVersion") { - transitive = false // deps should all be bundled with MC - } - - // Mixin needs these (and depends on them but for some reason that's not enough. FG, did you do that?) - annotationProcessor 'com.google.code.gson:gson:2.2.4' - annotationProcessor 'com.google.guava:guava:21.0' - annotationProcessor 'org.ow2.asm:asm-tree:6.2' - annotationProcessor 'org.apache.logging.log4j:log4j-core:2.0-beta9' - } - - if (mcVersion >= 11604) { - shadow(annotationProcessor('com.github.LlamaLad7:MixinExtras:0.1.1')) - } - - shadow 'com.googlecode.mp4parser:isoparser:1.1.7' - shadow 'org.apache.commons:commons-exec:1.3' - shadow 'com.google.apis:google-api-services-youtube:v3-rev178-1.22.0', shadeExclusions - shadow 'com.google.api-client:google-api-client-gson:1.20.0', shadeExclusions - shadow 'com.google.api-client:google-api-client-java6:1.20.0', shadeExclusions - shadow 'com.google.oauth-client:google-oauth-client-jetty:1.20.0' - - def lwjgl = configurations.create("lwjgl") - for (suffix in ['', ':natives-linux', ':natives-windows', ':natives-macos', ':natives-macos-arm64']) { - add(lwjgl.name, 'org.lwjgl:lwjgl:3.3.1' + suffix) - add(lwjgl.name, 'org.lwjgl:lwjgl-tinyexr:3.3.1' + suffix) - } - compileOnly('org.lwjgl:lwjgl-tinyexr:3.3.1') - shadow(prebundle(project, lwjgl, "com/replaymod/render/utils/lwjgl.jar", {})) - - if (mcVersion < 11200) { - // The version which MC ships is too old, we'll need to ship our own - shadow 'com.google.code.gson:gson:2.8.7' - } - - shadow 'com.github.javagl.JglTF:jgltf-model:3af6de4' - - if (FABRIC) { - shadow 'org.apache.maven:maven-artifact:3.6.1' - } - - shadow 'org.aspectj:aspectjrt:1.8.2' - - shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8' - - shadow "com.github.ReplayMod:ReplayStudio:d9f7c11", shadeExclusions - - // FIXME this should be pulled in by ReplayStudio, and IntelliJ sees it, but javac for some reason does not - implementation 'com.github.viaversion:opennbt:0a02214' // 2.0-SNAPSHOT (ViaVersion Edition) - - implementation(FABRIC ? dependencies.project(path: jGui.path, configuration: "namedElements") : jGui) { - transitive = false // FG 1.2 puts all MC deps into the compile configuration and we don't want to shade those - } - shadow 'com.github.ReplayMod:lwjgl-utils:27dcd66' - - if (FABRIC) { - if (mcVersion >= 12003) { - modImplementation 'com.terraformersmc:modmenu:9.0.0-pre.1' - } else if (mcVersion >= 12002) { - modImplementation 'com.terraformersmc:modmenu:8.0.0' - } else if (mcVersion >= 12000) { - modImplementation 'com.terraformersmc:modmenu:7.0.1' - } else if (mcVersion >= 11904) { - modImplementation 'com.terraformersmc:modmenu:6.1.0-rc.4' - } else if (mcVersion >= 11903) { - modImplementation 'com.terraformersmc:modmenu:5.0.0-alpha.4' - } else if (mcVersion >= 11901) { - modImplementation 'com.terraformersmc:modmenu:4.0.5' - } else if (mcVersion >= 11900) { - modImplementation 'com.terraformersmc:modmenu:4.0.4' - } else if (mcVersion >= 11802) { - modImplementation 'com.terraformersmc:modmenu:3.1.0' - } else if (mcVersion >= 11800) { - modImplementation 'com.terraformersmc:modmenu:3.0.0' - } else if (mcVersion >= 11700) { - modImplementation 'com.terraformersmc:modmenu:2.0.0-beta.7' - } else if (mcVersion >= 11602) { - modImplementation 'com.terraformersmc:modmenu:1.16.8' - } else if (mcVersion >= 11600) { - modImplementation('com.terraformersmc:modmenu:1.14.15') { - exclude module: 'fabric-resource-loader-v0' // inappropriate version for 1.16.1 - } - } else if (mcVersion >= 11500) { - modImplementation 'com.terraformersmc:modmenu:1.10.6' - } else { - modCompileOnly 'com.terraformersmc:modmenu:1.10.6' - } - } - - if (mcVersion >= 11600) { - modCompileOnly("maven.modrinth:iris:1.18.x-v1.2.0") { - transitive = false // we do not want to upgrade our libs, we only need this to compile our mixins - } - } - - testImplementation 'junit:junit:4.11' -} - -if (mcVersion <= 10710) { - // FG 1.2 adds all MC deps to the compile configuration which we don't want - afterEvaluate { - // Remove them from the compile and runtime configurations - configurations.compile.extendsFrom -= [configurations.minecraft, configurations.minecraftDeps] - configurations.runtime.extendsFrom -= [configurations.forgeGradleStartClass] - // And add them to the source sets instead - sourceSets.main.with { - compileClasspath += configurations.minecraft + configurations.minecraftDeps - runtimeClasspath += configurations.minecraft + configurations.minecraftDeps + configurations.forgeGradleStartClass - } - // Also need to reconfigure the reobf task, so it can properly re-obfuscates inherited members - tasks.reobf.obfOutput.all { artifact -> - artifact.getFile() // force resolve - artifact.classpath += configurations.minecraft + configurations.minecraftDeps - } - } - - // Test sources aren't preprocessed and I can't be bothered to fix that - tasks.compileTestJava.onlyIf { false } -} - -if (FABRIC) { - tasks.remapJar { - addNestedDependencies.set(true) - afterEvaluate { // FIXME why does loom overwrite this if we set it immediately? - archiveClassifier.set('obf') - } - } -} - -File configureRelocationOutput = new File(project.buildDir, 'configureRelocation') -task configureRelocation() { - dependsOn tasks.jar - dependsOn configurations.shadow - outputs.file(configureRelocationOutput) - doLast { - def pkgs = files(configurations.shadow).filter { it.exists() }.collect { - def tree = it.isDirectory() ? fileTree(it) : zipTree(it) - def pkgs = [].toSet() - tree.visit { file -> - if (!file.directory && file.name.endsWith('.class') && file.path.contains('/')) { - def pkg = file.path.substring(0, file.path.lastIndexOf('/')) + '/' - if (pkg.startsWith('com/')) { - if (pkg.startsWith('com/google/')) { - if (!pkg.startsWith('com/google/common')) { - pkgs << pkg.substring(0, pkg.indexOf('/', 'com/google/'.length())) - } - } else if (!pkg.startsWith('com/replaymod')) { - pkgs << pkg.substring(0, pkg.indexOf('/', 4)) - } - } else if (pkg.startsWith('net/')) { - if (!pkg.startsWith('net/minecraft') - && !pkg.startsWith('net/fabric')) { - pkgs << pkg.substring(0, pkg.indexOf('/', 'net/'.length())) - } - } else if (pkg.startsWith('org/')) { - if (pkg.startsWith('org/apache/')) { - if (pkg.startsWith('org/apache/commons/')) { - if (!pkg.startsWith('org/apache/commons/io')) { - pkgs << pkg.substring(0, pkg.indexOf('/', 'org/apache/commons/'.length())) - } - } else if (!pkg.startsWith('org/apache/logging')) { - pkgs << pkg.substring(0, pkg.indexOf('/', 'org/apache/'.length())) - } - } else if (pkg.startsWith('org/lwjgl')) { - return // either bundled with MC or uses natives which we can't relocate - } else if (!pkg.startsWith('org/spongepowered')) { - pkgs << pkg.substring(0, pkg.indexOf('/', 4)) - } - } else if (pkg.startsWith('it/unimi/dsi/fastutil') && mcVersion >= 11400) { - return // MC uses this as well - } else if (!pkg.startsWith('javax/')) { - // Note: we cannot just use top level packages as those will be too generic and we'll run - // into this long standing bug: https://github.com/johnrengelman/shadow/issues/232 - def i = pkg.indexOf('/') - def i2 = pkg.indexOf('/', i + 1) - if (i2 > 0) { - pkgs << pkg.substring(0, i2) - } - } - } - } - pkgs - }.flatten().unique() - configureRelocationOutput.write(pkgs.join('\n')) - } -} - -// we want to base our shadowed jar on the reobfJar output, not the sourceSet output -// Tried tasks.replace but that does not actually seem to replace everything. -tasks.shadowJar.doFirst { - throw new GradleException("Wrong task! You want to run 'bundleJar' instead.") -} -tasks.register('bundleJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar).configure { - from { (FABRIC ? tasks.remapJar : tasks.jar).archiveFile.get() } - dependsOn { FABRIC ? tasks.remapJar : (mcVersion >= 10800 ? tasks.reobfJar : tasks.reobf) } - - from({ zipTree((FABRIC ? jGui.tasks.remapJar : jGui.tasks.jar).archiveFile.get()) }) { - filesMatching('mixins.jgui.json') { - filter { it.replace('de.johni0702', 'com.replaymod.lib.de.johni0702') } - } - filesMatching('mixins.jgui.refmap.json') { - filter { it.replace('de/johni0702', 'com/replaymod/lib/de/johni0702') } - } - } - dependsOn { FABRIC ? jGui.tasks.remapJar : (mcVersion >= 10800 ? jGui.tasks.reobfJar : jGui.tasks.reobf) } - relocate 'de.johni0702', 'com.replaymod.lib.de.johni0702' - - manifest.inheritFrom tasks.jar.manifest - - from project.configurations.shade - configurations = [project.configurations.shadow] - exclude 'META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'module-info.class' - - dependsOn tasks.configureRelocation - inputs.file(configureRelocationOutput) - doFirst { - configureRelocationOutput.readLines().each { pkg -> - def pkgName = pkg.replace('/', '.') - relocate pkgName, 'com.replaymod.lib.' + pkgName - } - } - - // No need to shadow netty, MC provides it - // (actually, pre-1.12 ships a netty which is too old, so we need to shade it there anyway) - if (mcVersion >= 11200) { - relocate 'com.github.steveice10.netty', 'io.netty' - exclude 'com/github/steveice10/netty/**' - } - - if (mcVersion >= 11400) { - // MC ships this - exclude 'it/unimi/dsi/fastutil/**' - } - - minimize { - exclude(dependency('.*spongepowered:mixin:.*')) - } -} -tasks.assemble.dependsOn tasks.bundleJar - -jar { - classifier = 'raw' - - if (!FABRIC) { - from files(project.mixinRefMap.canonicalPath) - manifest { - attributes 'TweakClass': 'com.replaymod.core.tweaker.ReplayModTweaker', - 'TweakOrder': '0', - 'FMLCorePluginContainsFMLMod': 'true', - 'FMLCorePlugin': 'com.replaymod.core.LoadingPlugin', - 'FMLAT': 'replaymod_at.cfg' - } - } - - if (mcVersion >= 11700) { - // Workaround a mixin bug which generates invalid refmaps for the `addDrawableChild` invoker - filesMatching("mixins.replaymod.refmap.json") { - it.filter { - it.replace("addDrawableChild(L/;)L/;", "method_37063(Lnet/minecraft/class_364;)Lnet/minecraft/class_364;") - } - } - } -} - -processResources { - // this will ensure that this task is redone when the versions change. - inputs.property 'version', { project.version } - inputs.property 'mcversion', { mcVersionStr } - - // replace stuff in mcmod.info (forge) and fabric.mod.json, nothing else - filesMatching(['mcmod.info', 'fabric.mod.json']) { - // replace version and mcversion - expand 'version': project.version, 'mcversion': mcVersionStr - } - - // strip comments from (strict) JSON files - filesMatching('pack.mcmeta') { - filter { line -> line.trim().startsWith('//') ? '' : line} - } - - // exclude mod meta for non-applicable loader - if (FABRIC) { - exclude 'mcmod.info' - } else { - exclude 'fabric.mod.json' - } -} - -sourceSets { - integrationTest { - compileClasspath += main.runtimeClasspath + main.output - java { - srcDir file('src/integration-test/java') - } - resources.srcDir file('src/integration-test/resources') - } -} - -if (FABRIC) { - // not required, fabric manages those by itself just fine -} else if (FG3) { - task copySrg(dependsOn: 'createMcpToSrg') { - doLast { - def tsrg = file(project.tasks.createMcpToSrg.output).readLines() - def srg = [] - def cls = '' - for (def line : tsrg) { - if (line[0] != '\t') { - srg.add('CL: ' + line) - cls = line.split(' ')[0] - } else { - def parts = line.substring(1).split(' ') - if (line.contains('(')) { - srg.add('MD: ' + cls + '/' + parts[0] + ' ' + parts[1] + ' ' + cls + '/' + parts[2] + ' ' + parts[1]) - } else { - srg.add('FD: ' + cls + '/' + parts[0] + ' ' + cls + '/' + parts[1]) - } - } - } - new File(project.buildDir, 'mcp-srg.srg').write(srg.join('\n')) - } - } - compileJava.dependsOn copySrg -} else { - task copySrg(type: Copy, dependsOn: 'genSrgs') { - from {project.tasks.genSrgs.mcpToSrg} - into 'build' - } - compileJava.dependsOn copySrg -} - -if (!FABRIC && !FG3) { - if (mcVersion <= 10710) { - reobf.addExtraSrgFile project.mixinSrg - } else { - reobfJar.addSecondarySrgFile project.mixinSrg - } -} - -/* FIXME -// Mixin uses multiple HashMaps to generate the refmap. -// HashMaps are unordered collections and as such do not produce deterministic output. -// To fix that, we simply sort the refmap json file. -import groovy.json.JsonSlurper -import groovy.json.JsonOutput -compileJava.doLast { - File refmapFile = mcVersion >= 10800 ? compileJava.ext.refMapFile : project.mixinRefMap - if (refmapFile.exists()) { - def ordered - ordered = { - if (it instanceof Map) { - def sorted = new TreeMap(it) - sorted.replaceAll { k, v -> ordered(v) } - sorted - } else if (it instanceof List) { - it.replaceAll { v -> ordered(v) } - } else { - it - } - } - def json = JsonOutput.toJson(ordered(new JsonSlurper().parse(refmapFile))) - refmapFile.withWriter { it.write json } - } -} -*/ - -if (!FG3 && !FABRIC) { // FIXME -task runIntegrationTest(type: JavaExec, dependsOn: ["makeStart", "jar"]) { - main = 'GradleStart' - standardOutput = System.out - errorOutput = System.err - workingDir file(minecraft.runDir) - - def testDir = new File(minecraft.runDir, "integration-test") - doFirst { - testDir.deleteDir() - testDir.mkdirs() - } - - doLast { - testDir.deleteDir() - } - - afterEvaluate { - def runClient = tasks.getByName("runClient") - runIntegrationTest.jvmArgs = runClient.jvmArgs + "-Dfml.noGrab=true" - runIntegrationTest.args = runClient.args + "--gameDir" + testDir.canonicalPath - runIntegrationTest.classpath runClient.classpath + sourceSets.integrationTest.output - } -} -} - -defaultTasks 'build' diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..39e0b76a --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,337 @@ +import com.replaymod.gradle.preprocess.PreprocessTask +import gg.essential.gradle.util.* + +plugins { + java + id("com.github.johnrengelman.shadow") apply false + id("gg.essential.multi-version") + id("gg.essential.defaults.repo") + id("gg.essential.defaults.java") + id("gg.essential.defaults.loom") +} + +val mcVersion = platform.mcVersion + +var jGuiVersion = project.name +if (jGuiVersion in listOf("1.10.2", "1.11", "1.11.2")) jGuiVersion = "1.9.4" +if (jGuiVersion in listOf("1.12.1", "1.12.2")) jGuiVersion = "1.12" +val jGui = project.evaluationDependsOn(":jGui:$jGuiVersion") + +version = "${project.name}-${rootProject.version}" +base.archivesName.set("replaymod") +java.withSourcesJar() + +loom { + mixin.defaultRefmapName.set("mixins.replaymod.refmap.json") + noServerRunConfigs() +} + +if (platform.isLegacyForge) { + loom.runs.named("client") { + property("fml.coreMods.load", "com.replaymod.core.LoadingPlugin") + } +} + +repositories { + mavenLocal() + maven("https://repo.spongepowered.org/maven/") + maven("https://maven.terraformersmc.com/releases/") { + content { + includeGroup("com.terraformersmc") + } + } + maven("https://jitpack.io") { + content { + includeGroupByRegex("com\\.github\\..*") + } + } + exclusiveContent { + forRepository { + maven("https://api.modrinth.com/maven") + } + filter { + includeGroup("maven.modrinth") + } + } +} + +// Include dep in fat jar without relocation and, when forge supports it, without exploding (TODO) +val shade by configurations.creating +// Include dep in fat jar with relocation and minimization +val shadow by configurations.creating { + exclude(group = "net.fabricmc", module = "fabric-loader") + exclude(group = "com.google.guava", module = "guava-jdk5") + exclude(group = "com.google.guava", module = "guava") // provided by MC + exclude(group = "com.google.code.gson", module = "gson") // provided by MC (or manually bundled for 1.11.2 and below) +} + +dependencies { + if (platform.isFabric) { + val fabricApiVersion = when (mcVersion) { + 11404 -> "0.4.3+build.247-1.14" + 11502 -> "0.5.1+build.294-1.15" + 11601 -> "0.14.0+build.371-1.16" + 11603 -> "0.17.1+build.394-1.16" + 11604 -> "0.42.0+1.16" + 11701 -> "0.46.1+1.17" + 11800 -> "0.43.1+1.18" + 11801 -> "0.43.1+1.18" + 11802 -> "0.47.9+1.18.2" + 11900 -> "0.55.3+1.19" + 11901 -> "0.58.5+1.19.1" + 11902 -> "0.68.0+1.19.2" + 11903 -> "0.68.1+1.19.3" + 11904 -> "0.76.0+1.19.4" + 12001 -> "0.83.1+1.20.1" + 12002 -> "0.91.2+1.20.2" + 12004 -> "0.91.2+1.20.4" + else -> throw UnsupportedOperationException() + } + val fabricApiModules = mutableListOf( + "api-base", + "networking-v0", + "keybindings-v0", + "resource-loader-v0", + ) + if (mcVersion >= 11600) { + fabricApiModules.remove("keybindings-v0") + fabricApiModules.add("key-binding-api-v1") + } + if (mcVersion >= 11604) { + fabricApiModules.add("screen-api-v1") + fabricApiModules.add("networking-api-v1") + } + if (mcVersion >= 11700) { + fabricApiModules.remove("networking-v0") + } + for (module in fabricApiModules) { + val dep = fabricApi.module("fabric-$module", fabricApiVersion) + modImplementation(dep) + "include"(dep) + } + } + + if (!platform.isFabric) { + // Mixin 0.8 is no longer compatible with MC 1.11.2 or older + val mixinVersion = if (mcVersion >= 11200) "0.8.2" else "0.7.11-SNAPSHOT" + compileOnly("org.spongepowered:mixin:$mixinVersion") + implementation(shade("org.spongepowered:mixin:$mixinVersion") { + isTransitive = false // deps should all be bundled with MC + }) + } + + if (mcVersion >= 11604) { + implementation(shadow(annotationProcessor("com.github.LlamaLad7:MixinExtras:0.1.1")!!)!!) + } + + implementation(shadow("com.googlecode.mp4parser:isoparser:1.1.7")!!) + implementation(shadow("org.apache.commons:commons-exec:1.3")!!) + implementation(shadow("com.google.apis:google-api-services-youtube:v3-rev178-1.22.0")!!) + implementation(shadow("com.google.api-client:google-api-client-gson:1.20.0")!!) + implementation(shadow("com.google.api-client:google-api-client-java6:1.20.0")!!) + implementation(shadow("com.google.oauth-client:google-oauth-client-jetty:1.20.0")!!) + + val lwjgl by configurations.creating + for (suffix in listOf("", ":natives-linux", ":natives-windows", ":natives-macos", ":natives-macos-arm64")) { + lwjgl("org.lwjgl:lwjgl:3.3.1$suffix") + lwjgl("org.lwjgl:lwjgl-tinyexr:3.3.1$suffix") + } + compileOnly("org.lwjgl:lwjgl-tinyexr:3.3.1") + shadow(prebundle(lwjgl, "com/replaymod/render/utils/lwjgl.jar")) + + if (mcVersion < 11200) { + // The version which MC ships is too old, we'll need to ship our own + implementation(shadow("com.google.code.gson:gson:2.8.7")!!) + } + + implementation(shadow("com.github.javagl.JglTF:jgltf-model:3af6de4")!!) + + if (platform.isFabric) { + implementation(shadow("org.apache.maven:maven-artifact:3.6.1")!!) + } + + implementation(shadow("org.aspectj:aspectjrt:1.8.2")!!) + + implementation(shadow("com.github.ReplayMod.JavaBlend:2.79.0:a0696f8")!!) + + implementation(shadow("com.github.ReplayMod:ReplayStudio:d9f7c11")!!) + // FIXME this should be pulled in by ReplayStudio, and IntelliJ sees it, but javac for some reason does not + implementation("com.github.viaversion:opennbt:0a02214") // 2.0-SNAPSHOT (ViaVersion Edition) + + implementation(project(path = jGui.path, configuration = "namedElements")) + implementation(shadow("com.github.ReplayMod:lwjgl-utils:27dcd66")!!) + + if (platform.isFabric) { + val modMenuVersion = when { + mcVersion >= 12003 -> "9.0.0-pre.1" + mcVersion >= 12002 -> "8.0.0" + mcVersion >= 12000 -> "7.0.1" + mcVersion >= 11904 -> "6.1.0-rc.4" + mcVersion >= 11903 -> "5.0.0-alpha.4" + mcVersion >= 11901 -> "4.0.5" + mcVersion >= 11900 -> "4.0.4" + mcVersion >= 11802 -> "3.1.0" + mcVersion >= 11800 -> "3.0.0" + mcVersion >= 11700 -> "2.0.0-beta.7" + mcVersion >= 11602 -> "1.16.8" + mcVersion >= 11600 -> null // maven doesn't have one for this version (only 1.16.5) + mcVersion >= 11500 -> "1.10.6" + else -> null + } + if (modMenuVersion != null) { + modImplementation("com.terraformersmc:modmenu:$modMenuVersion") + } else { + // Oldest modmenu on their maven is 1.10.5 for MC 1.15.2; for older versions we won't run it in dev + modCompileOnly("com.terraformersmc:modmenu:1.10.6") + } + } + + if (mcVersion >= 11600) { + modCompileOnly("maven.modrinth:iris:1.18.x-v1.2.0") { + isTransitive = false // we do not want to upgrade our libs, we only need this to compile our mixins + } + } + + testImplementation("junit:junit:4.11") +} + +preprocess { + keywords.set(mapOf( + ".java" to PreprocessTask.DEFAULT_KEYWORDS, + ".kt" to PreprocessTask.DEFAULT_KEYWORDS, + ".json" to PreprocessTask.DEFAULT_KEYWORDS, + ".mcmeta" to PreprocessTask.DEFAULT_KEYWORDS, + ".cfg" to PreprocessTask.CFG_KEYWORDS, + ".vert" to PreprocessTask.DEFAULT_KEYWORDS, + ".frag" to PreprocessTask.DEFAULT_KEYWORDS, + )) + + patternAnnotation.set("com.replaymod.gradle.remap.Pattern") +} + +tasks.jar { + archiveClassifier.set("raw") + + if (!platform.isFabric) { + manifest { + attributes( + "TweakClass" to "com.replaymod.core.tweaker.ReplayModTweaker", + "TweakOrder" to "0", + "FMLCorePluginContainsFMLMod" to "true", + "FMLCorePlugin" to "com.replaymod.core.LoadingPlugin", + "FMLAT" to "replaymod_at.cfg", + ) + } + } +} + +tasks.remapJar { + if (platform.isFabric) { + addNestedDependencies.set(true) + } + archiveClassifier.set("obf") +} + +val configureRelocationOutput = project.layout.buildDirectory.file("configureRelocation") +val configureRelocation by tasks.registering { + dependsOn(tasks.jar) + dependsOn(shadow) + outputs.file(configureRelocationOutput) + doLast { + val pkgs = files(shadow).filter { it.exists() }.map { + val tree = if (it.isDirectory) fileTree(it) else zipTree(it) + val pkgs = mutableSetOf() + tree.visit { + val file = this + if (!file.isDirectory && file.name.endsWith(".class") && file.path.contains("/")) { + val pkg = file.path.substring(0, file.path.lastIndexOf("/")) + "/" + if (pkg.startsWith("com/")) { + if (pkg.startsWith("com/google/")) { + if (!pkg.startsWith("com/google/common")) { + pkgs += pkg.substring(0, pkg.indexOf("/", "com/google/".length)) + } + } else if (!pkg.startsWith("com/replaymod")) { + pkgs += pkg.substring(0, pkg.indexOf("/", 4)) + } + } else if (pkg.startsWith("net/")) { + if (!pkg.startsWith("net/minecraft") + && !pkg.startsWith("net/fabric")) { + pkgs += pkg.substring(0, pkg.indexOf("/", "net/".length)) + } + } else if (pkg.startsWith("org/")) { + if (pkg.startsWith("org/apache/")) { + if (pkg.startsWith("org/apache/commons/")) { + if (!pkg.startsWith("org/apache/commons/io")) { + pkgs += pkg.substring(0, pkg.indexOf("/", "org/apache/commons/".length)) + } + } else if (!pkg.startsWith("org/apache/logging")) { + pkgs += pkg.substring(0, pkg.indexOf("/", "org/apache/".length)) + } + } else if (pkg.startsWith("org/lwjgl")) { + return@visit // either bundled with MC or uses natives which we can't relocate + } else if (!pkg.startsWith("org/spongepowered")) { + pkgs += pkg.substring(0, pkg.indexOf("/", 4)) + } + } else if (pkg.startsWith("it/unimi/dsi/fastutil") && mcVersion >= 11400) { + return@visit // MC uses this as well + } else if (!pkg.startsWith("javax/")) { + // Note: we cannot just use top level packages as those will be too generic and we'll run + // into this long standing bug: https://github.com/johnrengelman/shadow/issues/232 + val i = pkg.indexOf("/") + val i2 = pkg.indexOf("/", i + 1) + if (i2 > 0) { + pkgs += pkg.substring(0, i2) + } + } + } + } + pkgs + }.flatten().toSortedSet() + configureRelocationOutput.get().asFile.writeText(pkgs.joinToString("\n")) + } +} + +val bundleJar by tasks.registering(com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar::class) { + from(tasks.remapJar.flatMap { it.archiveFile }.map { zipTree(it) }) + + from(jGui.tasks.remapJar.flatMap { it.archiveFile }.map { zipTree(it) }) { + filesMatching("mixins.jgui.json") { + filter { it.replace("de.johni0702", "com.replaymod.lib.de.johni0702") } + } + filesMatching("mixins.jgui.refmap.json") { + filter { it.replace("de/johni0702", "com/replaymod/lib/de/johni0702") } + } + } + relocate("de.johni0702", "com.replaymod.lib.de.johni0702") + + manifest.inheritFrom(tasks.jar.get().manifest) + from(shade) + configurations = listOf(shadow) + exclude("META-INF/INDEX.LIST", "META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA", "module-info.class") + + dependsOn(configureRelocation) + inputs.file(configureRelocationOutput) + doFirst { + configureRelocationOutput.get().asFile.forEachLine { pkg -> + val pkgName = pkg.replace("/", ".") + relocate(pkgName, "com.replaymod.lib.$pkgName") + } + } + + // No need to shadow netty, MC provides it + // (actually, pre-1.12 ships a netty which is too old, so we need to shade it there anyway) + if (mcVersion >= 11200) { + relocate("com.github.steveice10.netty", "io.netty") + exclude("com/github/steveice10/netty/**") + } + + if (mcVersion >= 11400) { + // MC ships this + exclude("it/unimi/dsi/fastutil/**") + } + + minimize { + exclude(dependency(".*spongepowered:mixin:.*")) + } +} +tasks.assemble { dependsOn(bundleJar) } diff --git a/gradle.properties b/gradle.properties index ed80cc59..7b84fd48 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,9 @@ +essential.defaults.loom=0 +essential.defaults.loom.fabric-loader=net.fabricmc:fabric-loader:0.15.11 + # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. -org.gradle.jvmargs=-Xmx3G +org.gradle.jvmargs=-Xmx8G org.gradle.daemon=false org.gradle.parallel=true org.gradle.configureondemand=true diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e750102e..48c0a02c 100755 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/jGui b/jGui index bd41e57a..9b5b2104 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit bd41e57af0aefe7db7068e5f4b9f8eb5310c0878 +Subproject commit 9b5b2104aad687949ac4138efecd6866a4582241 diff --git a/root.gradle.kts b/root.gradle.kts index 72cfd411..18c2e7a0 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -2,9 +2,9 @@ import groovy.json.JsonOutput import java.io.ByteArrayOutputStream plugins { - id("fabric-loom") version "0.11-SNAPSHOT" apply false - id("com.replaymod.preprocess") version "48e02ad" + id("gg.essential.multi-version.root") id("com.github.hierynomus.license") version "0.15.0" + kotlin("jvm") version "1.9.24" apply false // workaround for EGT crashing without } val latestVersion = file("version.txt").readLines().first() @@ -36,6 +36,13 @@ subprojects { } } + if (name == "jGui") { + return@subprojects + } + val (_, minor) = name.split("-")[0].split(".") + val fabric = minor.toInt() >= 14 && !name.endsWith("-forge") + extra.set("loom.platform", if (fabric) "fabric" else "forge") + afterEvaluate { val projectBundleJar = project.tasks.findByName("bundleJar") if (projectBundleJar != null && projectBundleJar.hasProperty("archivePath") && project.name != "core") { @@ -91,8 +98,11 @@ fun generateVersionsJson(): Map { .filter { it != "core" } // Internal project used to automatically remap from Forge 1.12.2 to Fabric 1.14.4 .filter { it != "1.14.4-forge" } + // We dropped 1.8 with the switch to archloom but still kept its source in case someone + // volunteers to make it build again + .filterNot { it == "1.8" && versionComparator.compare(version, "2.6.16") >= 0 } // We dropped 1.7.10 with the Gradle 7 update but still kept its source in case someone - // volunteers to update FG 1.2 to Gradle 7. + // volunteers to ~~update FG 1.2 to Gradle 7~~ make it work with archloom. .filterNot { it == "1.7.10" && versionComparator.compare(version, "2.6.0") >= 0 } val versions = mcVersions.map { "$it-$version" }.toMutableList() when (version) { diff --git a/settings.gradle.kts b/settings.gradle.kts index bb1dd6e4..b332765d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,21 +6,19 @@ pluginManagement { google() maven("https://jitpack.io") maven("https://maven.fabricmc.net") + maven("https://maven.architectury.dev/") + maven("https://maven.minecraftforge.net") + maven("https://repo.essential.gg/repository/maven-public") } - resolutionStrategy { - eachPlugin { - when (requested.id.id) { - "com.replaymod.preprocess" -> { - useModule("com.github.replaymod:preprocessor:${requested.version}") - } - } - } + plugins { + id("gg.essential.multi-version.root") version "0.6.0" + id("com.github.johnrengelman.shadow") version "8.1.1" } } val jGuiVersions = listOf( // "1.7.10", - "1.8", + // "1.8", "1.8.9", "1.9.4", "1.12", @@ -43,7 +41,7 @@ val jGuiVersions = listOf( ) val replayModVersions = listOf( // "1.7.10", - "1.8", + // "1.8", "1.8.9", "1.9.4", "1.10.2", @@ -75,13 +73,13 @@ rootProject.buildFileName = "root.gradle.kts" include(":jGui") project(":jGui").apply { projectDir = file("jGui") - buildFileName = "preprocess.gradle.kts" + buildFileName = "root.gradle.kts" } jGuiVersions.forEach { version -> include(":jGui:$version") project(":jGui:$version").apply { projectDir = file("jGui/versions/$version") - buildFileName = "../../build.gradle" + buildFileName = "../../build.gradle.kts" } } @@ -89,6 +87,6 @@ replayModVersions.forEach { version -> include(":$version") project(":$version").apply { projectDir = file("versions/$version") - buildFileName = "../../build.gradle" + buildFileName = "../../build.gradle.kts" } } diff --git a/src/main/java/com/replaymod/render/EXRWriter.java b/src/main/java/com/replaymod/render/EXRWriter.java index 2b072bda..157ef848 100644 --- a/src/main/java/com/replaymod/render/EXRWriter.java +++ b/src/main/java/com/replaymod/render/EXRWriter.java @@ -101,7 +101,7 @@ public class EXRWriter implements FrameConsumer { for (int i = 0; i < numChannels; i++) { FloatBuffer channel = images.slice(); channel.position(width * height * i); - imagePointers.put(i, channel.slice()); + imagePointers.put(i, memAddress(channel)); if (i == 4) { depthChannel = channel; } else { @@ -125,8 +125,8 @@ public class EXRWriter implements FrameConsumer { int ret = SaveEXRImageToFile(image, header, path.toString(), err); if (ret != TINYEXR_SUCCESS) { - String message = err.getStringASCII(0); - FreeEXRErrorMessage(err.getByteBuffer(0)); + String message = memASCII(err.get(0)); + nFreeEXRErrorMessage(err.get(0)); throw new IOException(message); } } catch (Throwable t) { diff --git a/src/main/java/com/replaymod/replay/FullReplaySender.java b/src/main/java/com/replaymod/replay/FullReplaySender.java index 9d6ef35c..bbaa6cf5 100644 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/FullReplaySender.java @@ -404,7 +404,12 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend if (mc.world != null) { for (PlayerEntity playerEntity : mc.world.getPlayers()) { if (!playerEntity.updateNeeded && playerEntity instanceof OtherClientPlayerEntity) { + // FIXME preprocessor should (and used to) be able to map this + //#if MC>=11400 playerEntity.tickMovement(); + //#else + //$$ playerEntity.onLivingUpdate(); + //#endif } } } diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index 4c7f1a50..2a12a7e5 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -4,7 +4,7 @@ "name": "Replay Mod", "description": "A Mod which allows you to record, replay and share your Minecraft experience.", "version": "${version}", - "mcversion": "${mcversion}", + "mcversion": "${mcVersionStr}", "url": "https://replaymod.com", "updateUrl": "https://replaymod.com/download", "authorList": [ @@ -20,7 +20,7 @@ "name": "Replay Mod - Recording", "description": "Recording Module of the ReplayMod", "version": "${version}", - "mcversion": "${mcversion}", + "mcversion": "${mcVersionStr}", "url": "https://replaymod.com", "updateUrl": "https://replaymod.com/download", "authorList": [ @@ -37,7 +37,7 @@ "name": "Replay Mod - Replay", "description": "Replay Module of the ReplayMod", "version": "${version}", - "mcversion": "${mcversion}", + "mcversion": "${mcVersionStr}", "url": "https://replaymod.com", "updateUrl": "https://replaymod.com/download", "authorList": [ @@ -54,7 +54,7 @@ "name": "Replay Mod - Simple Pathing", "description": "Simple Pathing Module of the ReplayMod - aka the original pathing", "version": "${version}", - "mcversion": "${mcversion}", + "mcversion": "${mcVersionStr}", "url": "https://replaymod.com", "updateUrl": "https://replaymod.com/download", "authorList": [ @@ -71,7 +71,7 @@ "name": "Replay Mod - Render", "description": "Render Module of the ReplayMod", "version": "${version}", - "mcversion": "${mcversion}", + "mcversion": "${mcVersionStr}", "url": "https://replaymod.com", "updateUrl": "https://replaymod.com/download", "authorList": [ @@ -88,7 +88,7 @@ "name": "Replay Mod - Replay Editor", "description": "Replay Editor Module of the ReplayMod", "version": "${version}", - "mcversion": "${mcversion}", + "mcversion": "${mcVersionStr}", "url": "https://replaymod.com", "updateUrl": "https://replaymod.com/download", "authorList": [ @@ -105,7 +105,7 @@ "name": "Replay Mod - Extras", "description": "Extras Module of the ReplayMod - Small but neat additions", "version": "${version}", - "mcversion": "${mcversion}", + "mcversion": "${mcVersionStr}", "url": "https://replaymod.com", "updateUrl": "https://replaymod.com/download", "authorList": [ @@ -122,7 +122,7 @@ "name": "Replay Mod - Compatibility", "description": "Compatibility Module of the ReplayMod - Adds compatibility with other mods", "version": "${version}", - "mcversion": "${mcversion}", + "mcversion": "${mcVersionStr}", "url": "https://replaymod.com", "updateUrl": "https://replaymod.com/download", "authorList": [ diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java b/versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java index 6da12741..fd9b95e4 100644 --- a/versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java +++ b/versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java @@ -27,8 +27,6 @@ import static com.replaymod.core.versions.MCVer.getMinecraft; @Mod(modid = ReplayMod.MOD_ID, useMetadata = true, - version = "@MOD_VERSION@", - acceptedMinecraftVersions = "@MC_VERSION@", acceptableRemoteVersions = "*", //#if MC>=10800 clientSideOnly = true, diff --git a/versions/1.14.4-forge/gradle.properties b/versions/1.14.4-forge/gradle.properties new file mode 100644 index 00000000..7cd9cc48 --- /dev/null +++ b/versions/1.14.4-forge/gradle.properties @@ -0,0 +1 @@ +essential.defaults.loom.mappings=de.oceanlabs.mcp:mcp_snapshot:20190719-1.14.3@zip diff --git a/versions/1.18.1/gradle.properties b/versions/1.18.1/gradle.properties new file mode 100644 index 00000000..a702d47b --- /dev/null +++ b/versions/1.18.1/gradle.properties @@ -0,0 +1 @@ +essential.defaults.loom.mappings=net.fabricmc:yarn:1.18.1+build.1:v2 diff --git a/versions/1.18.2/gradle.properties b/versions/1.18.2/gradle.properties new file mode 100644 index 00000000..ad66fefe --- /dev/null +++ b/versions/1.18.2/gradle.properties @@ -0,0 +1 @@ +essential.defaults.loom.mappings=net.fabricmc:yarn:1.18.2+build.1:v2 diff --git a/versions/1.19.2/gradle.properties b/versions/1.19.2/gradle.properties new file mode 100644 index 00000000..9cca2054 --- /dev/null +++ b/versions/1.19.2/gradle.properties @@ -0,0 +1 @@ +essential.defaults.loom.mappings=net.fabricmc:yarn:1.19.2+build.28:v2 diff --git a/versions/1.19.3/gradle.properties b/versions/1.19.3/gradle.properties new file mode 100644 index 00000000..72a3a366 --- /dev/null +++ b/versions/1.19.3/gradle.properties @@ -0,0 +1,2 @@ +essential.defaults.loom.minecraft=com.mojang:minecraft:1.19.3-rc3 +essential.defaults.loom.mappings=net.fabricmc:yarn:1.19.3-rc3+build.1:v2 diff --git a/versions/1.20.2/logs/latest.log b/versions/1.20.2/logs/latest.log deleted file mode 100644 index e69de29b..00000000 diff --git a/versions/1.8.9/gradle.properties b/versions/1.8.9/gradle.properties new file mode 100644 index 00000000..4318326c --- /dev/null +++ b/versions/1.8.9/gradle.properties @@ -0,0 +1 @@ +essential.defaults.loom.forge=net.minecraftforge:forge:1.8.9-11.15.1.1722 From fe0677923ca7f9a6073daf61e99f1b6d958b85e5 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 12 May 2024 17:55:07 +0200 Subject: [PATCH 02/28] Let Minecraft handle packet decoding during playback We've done this ourselves only because it was easier at the beginning. However by now (and especially with 1.20.5), Minecraft's packet decoding has become substantially more sophisticated, to the point that it's probably a bad idea to try to do it ourselves. This commit gives back that responsibility to Minecraft by adding the standard decoder (and encoder because it's required for proper connection state management on modern versions) to our channel pipeline, changes the full and the quick replay sender to send raw `ByteBuf`s into the front of the channel, and moves the posititon of the full replay sender in the channel pipeline such that it can see and modify packets after Minecraft has decoded them. --- .../recording/ReplayModRecording.java | 3 +- .../replaymod/replay/FullReplaySender.java | 78 ++++--------------- .../replaymod/replay/QuickReplaySender.java | 52 +++---------- .../com/replaymod/replay/ReplayHandler.java | 53 +++++-------- versions/1.9.4/mapping.txt | 2 + 5 files changed, 50 insertions(+), 138 deletions(-) diff --git a/src/main/java/com/replaymod/recording/ReplayModRecording.java b/src/main/java/com/replaymod/recording/ReplayModRecording.java index f65e4467..ee8fbaac 100644 --- a/src/main/java/com/replaymod/recording/ReplayModRecording.java +++ b/src/main/java/com/replaymod/recording/ReplayModRecording.java @@ -9,6 +9,7 @@ import com.replaymod.recording.handler.ConnectionEventHandler; import com.replaymod.recording.handler.GuiHandler; import com.replaymod.recording.mixin.NetworkManagerAccessor; import com.replaymod.recording.packet.PacketListener; +import com.replaymod.replay.ReplayHandler; import io.netty.channel.Channel; import io.netty.util.AttributeKey; import net.minecraft.network.ClientConnection; @@ -93,7 +94,7 @@ public class ReplayModRecording implements Module { public void initiateRecording(ClientConnection networkManager) { Channel channel = ((NetworkManagerAccessor) networkManager).getChannel(); - if (channel.pipeline().get("ReplayModReplay_replaySender") != null) return; + if (channel.pipeline().get(ReplayHandler.PACKET_HANDLER_NAME) != null) return; //#if MC>=11400 if (channel.hasAttr(ATTR_CHECKED)) return; channel.attr(ATTR_CHECKED).set(null); diff --git a/src/main/java/com/replaymod/replay/FullReplaySender.java b/src/main/java/com/replaymod/replay/FullReplaySender.java index bbaa6cf5..fe2edfa8 100644 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/FullReplaySender.java @@ -15,8 +15,8 @@ import com.replaymod.replaystudio.protocol.PacketTypeRegistry; import com.replaymod.replaystudio.replay.ReplayFile; import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; -import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; @@ -28,9 +28,7 @@ import net.minecraft.client.gui.screen.NoticeScreen; import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.NetworkState; import net.minecraft.network.Packet; -import net.minecraft.network.PacketByteBuf; import net.minecraft.network.packet.s2c.play.GameMessageS2CPacket; import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; import net.minecraft.network.packet.s2c.play.DisconnectS2CPacket; @@ -140,7 +138,6 @@ import net.minecraft.network.packet.s2c.play.UnloadChunkS2CPacket; import net.minecraft.network.packet.s2c.play.ResourcePackSendS2CPacket; import net.minecraft.network.packet.s2c.play.SetCameraEntityS2CPacket; import net.minecraft.network.packet.s2c.play.TitleS2CPacket; -import net.minecraft.network.NetworkSide; //#else //$$ import org.apache.commons.io.Charsets; //#endif @@ -230,9 +227,9 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend protected ReplayFile replayFile; /** - * The channel handler context used to send packets to minecraft. + * The channel used to send packets to minecraft. */ - protected ChannelHandlerContext ctx; + protected Channel channel; /** * The replay input stream from which new packets are read. @@ -303,20 +300,17 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend /** * Create a new replay sender. * @param file The replay file - * @param asyncMode {@code true} for async mode, {@code false} otherwise - * @see #asyncMode */ - public FullReplaySender(ReplayHandler replayHandler, ReplayFile file, boolean asyncMode) throws IOException { + public FullReplaySender(ReplayHandler replayHandler, ReplayFile file) throws IOException { this.replayHandler = replayHandler; this.replayFile = file; - this.asyncMode = asyncMode; this.replayLength = file.getMetaData().getDuration(); events.register(); + } - if (asyncMode) { - new Thread(asyncSender, "replaymod-async-sender").start(); - } + public void setChannel(Channel channel) { + this.channel = channel; } /** @@ -383,8 +377,8 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend syncSender.shutdown(); events.unregister(); try { - channelInactive(ctx); - ctx.channel().pipeline().close(); + channel.pipeline().fireChannelInactive(); + channel.pipeline().close(); FileUtils.deleteDirectory(tempResourcePackFolder); } catch(Exception e) { e.printStackTrace(); @@ -425,14 +419,9 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend return; } - // When a packet is sent directly, perform no filtering - if(msg instanceof Packet) { - super.channelRead(ctx, msg); - } - - if (msg instanceof byte[]) { + if (msg instanceof Packet) { try { - Packet p = deserializePacket((byte[]) msg); + Packet p = (Packet) msg; if (p != null) { p = processPacket(p); @@ -478,29 +467,6 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend } - private Packet deserializePacket(byte[] bytes) throws IOException, IllegalAccessException, InstantiationException { - ByteBuf bb = Unpooled.wrappedBuffer(bytes); - PacketByteBuf pb = new PacketByteBuf(bb); - - int i = pb.readVarInt(); - - NetworkState state = asMc(registry.getState()); - //#if MC>=12002 - //$$ Packet p = state.getHandler(NetworkSide.CLIENTBOUND).createPacket(i, pb); - //#elseif MC>=11700 - //$$ Packet p = state.getPacketHandler(NetworkSide.CLIENTBOUND, i, pb); - //#else - //#if MC>=10800 - Packet p = state.getPacketHandler(NetworkSide.CLIENTBOUND, i); - //#else - //$$ Packet p = Packet.generatePacket(state.func_150755_b(), i); - //#endif - p.read(pb); - //#endif - - return p; - } - // If we do not give minecraft time to tick, there will be dead entity artifacts left in the world // Therefore we have to remove all loaded, dead entities manually if we are in sync mode. // We do this after every SpawnX packet and after the destroy entities packet. @@ -986,13 +952,6 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend //$$ } //#endif - @Override - @SuppressWarnings("unchecked") - public void channelActive(ChannelHandlerContext ctx) throws Exception { - this.ctx = ctx; - super.channelActive(ctx); - } - @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { // The embedded channel's event loop will consider every thread to be in it and as such provides no @@ -1073,9 +1032,6 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend private Runnable asyncSender = new Runnable() { public void run() { try { - while (ctx == null && !terminate) { - Thread.sleep(10); - } REPLAY_LOOP: while (!terminate) { synchronized (FullReplaySender.this) { @@ -1125,7 +1081,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend } // Process packet - channelRead(ctx, nextPacket.bytes); + channel.pipeline().fireChannelRead(Unpooled.wrappedBuffer(nextPacket.bytes)); nextPacket = null; lastTimeStamp = nextTimeStamp; @@ -1136,7 +1092,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend // Might be safe to do the same on older versions too, but I'd rather not poke the // monster that is Forge networking. //#if MC>=12002 - //$$ while (!ctx.channel().config().isAutoRead()) { + //$$ while (!channel.config().isAutoRead()) { //$$ Thread.sleep(0, 100_000); //$$ } //#endif @@ -1298,10 +1254,6 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend private void doSendPacketsTill(int timestamp) { try { - while (ctx == null && !terminate) { // Make sure channel is ready - Thread.sleep(10); - } - synchronized (this) { if (timestamp == lastTimeStamp) { // Do nothing if we're already there return; @@ -1343,7 +1295,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend } // Process packet - channelRead(ctx, pd.bytes); + channel.pipeline().fireChannelRead(Unpooled.wrappedBuffer(pd.bytes)); // MC as of 1.20.2 relies on autoRead, so it can update the connection state on the main // thread before the next packet is read. As such, we need to stall if that was just @@ -1351,7 +1303,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend // Might be safe to do the same on older versions too, but I'd rather not poke the // monster that is Forge networking. //#if MC>=12002 - //$$ while (!ctx.channel().config().isAutoRead()) { + //$$ while (!channel.config().isAutoRead()) { //$$ Thread.sleep(0, 100_000); //$$ } //#endif diff --git a/src/main/java/com/replaymod/replay/QuickReplaySender.java b/src/main/java/com/replaymod/replay/QuickReplaySender.java index 6641ddc5..5c91ee66 100644 --- a/src/main/java/com/replaymod/replay/QuickReplaySender.java +++ b/src/main/java/com/replaymod/replay/QuickReplaySender.java @@ -14,13 +14,10 @@ import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerAdapter; -import io.netty.channel.ChannelHandlerContext; import net.minecraft.client.MinecraftClient; -import net.minecraft.network.NetworkState; -import net.minecraft.network.NetworkSide; -import net.minecraft.network.Packet; import net.minecraft.network.PacketByteBuf; import javax.annotation.Nullable; @@ -31,7 +28,6 @@ import java.util.function.Consumer; import com.replaymod.core.utils.WrappedTimer; //#endif -import static com.replaymod.core.versions.MCVer.asMc; import static com.replaymod.core.versions.MCVer.getMinecraft; import static com.replaymod.core.versions.MCVer.getPacketTypeRegistry; import static com.replaymod.replay.ReplayModReplay.LOGGER; @@ -49,7 +45,7 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe private final ReplayModReplay mod; private final RandomAccessReplay replay; private final EventHandler eventHandler = new EventHandler(); - private ChannelHandlerContext ctx; + private Channel channel; private int currentTimeStamp; private double replaySpeed = 1; @@ -70,6 +66,7 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe @Override protected void dispatch(com.replaymod.replaystudio.protocol.Packet packet) { + // Convert ReplayStudio-Netty buffer into MC-Netty buffer com.github.steveice10.netty.buffer.ByteBuf byteBuf = packet.getBuf(); int size = byteBuf.readableBytes(); if (buf.length < size) { @@ -78,40 +75,14 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe byteBuf.getBytes(byteBuf.readerIndex(), buf, 0, size); ByteBuf wrappedBuf = Unpooled.wrappedBuffer(buf); wrappedBuf.writerIndex(size); - PacketByteBuf packetByteBuf = new PacketByteBuf(wrappedBuf); + packet.release(); - NetworkState state = asMc(packet.getRegistry().getState()); - //#if MC>=10809 - Packet mcPacket; - //#else - //$$ Packet mcPacket; - //#endif - //#if MC>=12002 - //$$ mcPacket = state.getHandler(NetworkSide.CLIENTBOUND).createPacket(packet.getId(), packetByteBuf); - //#elseif MC>=11700 - //$$ mcPacket = state.getPacketHandler(NetworkSide.CLIENTBOUND, packet.getId(), packetByteBuf); - //#elseif MC>=11500 - mcPacket = state.getPacketHandler(NetworkSide.CLIENTBOUND, packet.getId()); - //#else - //$$ try { - //$$ mcPacket = state.getPacketHandler(NetworkSide.CLIENTBOUND, packet.getId()); - //$$ } catch (IllegalAccessException | InstantiationException e) { - //$$ e.printStackTrace(); - //$$ return; - //$$ } - //#endif - if (mcPacket != null) { - //#if MC<11700 - try { - mcPacket.read(packetByteBuf); - } catch (IOException e) { - e.printStackTrace(); - return; - } - //#endif + // Combine id + payload + ByteBuf bufWithId = channel.alloc().heapBuffer(2 + wrappedBuf.readableBytes()); + new PacketByteBuf(bufWithId).writeVarInt(packet.getId()); + bufWithId.writeBytes(wrappedBuf); - ctx.fireChannelRead(mcPacket); - } + channel.pipeline().fireChannelRead(bufWithId); } }; } @@ -124,9 +95,8 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe eventHandler.unregister(); } - @Override - public void handlerAdded(ChannelHandlerContext ctx) { - this.ctx = ctx; + public void setChannel(Channel channel) { + this.channel = channel; } public ListenableFuture getInitializationPromise() { diff --git a/src/main/java/com/replaymod/replay/ReplayHandler.java b/src/main/java/com/replaymod/replay/ReplayHandler.java index 15b14a57..416d80ea 100644 --- a/src/main/java/com/replaymod/replay/ReplayHandler.java +++ b/src/main/java/com/replaymod/replay/ReplayHandler.java @@ -33,7 +33,9 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.DownloadingTerrainScreen; import net.minecraft.client.network.ClientLoginNetworkHandler; import net.minecraft.client.util.Window; +import net.minecraft.network.DecoderHandler; import net.minecraft.network.NetworkState; +import net.minecraft.network.PacketEncoder; import net.minecraft.util.crash.CrashReport; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; @@ -46,13 +48,6 @@ import java.util.*; //$$ import net.minecraft.client.resource.server.ServerResourcePackManager; //#endif -//#if MC>=12002 -//$$ import io.netty.channel.ChannelDuplexHandler; -//$$ import io.netty.channel.ChannelPromise; -//$$ import net.minecraft.network.handler.NetworkStateTransitionHandler; -//$$ import net.minecraft.network.packet.Packet; -//#endif - //#if MC>=12000 //$$ import com.mojang.blaze3d.systems.VertexSorter; //$$ import net.minecraft.client.gui.DrawContext; @@ -129,6 +124,8 @@ import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; public class ReplayHandler { + public static final String PACKET_HANDLER_NAME = "ReplayModReplay_packetHandler"; + private static MinecraftClient mc = getMinecraft(); /** @@ -180,7 +177,7 @@ public class ReplayHandler { markers = replayFile.getMarkers().or(Collections.emptySet()); - fullReplaySender = new FullReplaySender(this, replayFile, false); + fullReplaySender = new FullReplaySender(this, replayFile); //#if MC>=10800 quickReplaySender = new QuickReplaySender(ReplayModReplay.instance, replayFile); //#endif @@ -319,17 +316,25 @@ public class ReplayHandler { //$$ ChannelOutboundHandlerAdapter dummyHandler = new ChannelOutboundHandlerAdapter(); //$$ channel = new EmbeddedChannel(dummyHandler); //$$ channel.pipeline().remove(dummyHandler); + //$$ channel.pipeline().removeLast(); + //#endif + + quickReplaySender.setChannel(channel); + fullReplaySender.setChannel(channel); + + //#if MC>=12002 + //$$ channel.pipeline().addLast("decoder", new DecoderHandler(ClientConnection.CLIENTBOUND_PROTOCOL_KEY)); + //$$ channel.pipeline().addLast("encoder", new PacketEncoder(ClientConnection.SERVERBOUND_PROTOCOL_KEY)); + //#else + channel.pipeline().addLast("decoder", new DecoderHandler(NetworkSide.CLIENTBOUND)); + channel.pipeline().addLast("encoder", new PacketEncoder(NetworkSide.SERVERBOUND)); //#endif - //#if MC>=10800 - channel.pipeline().addLast("ReplayModReplay_quickReplaySender", quickReplaySender); - //#endif - channel.pipeline().addLast("ReplayModReplay_replaySender", fullReplaySender); //#if MC>=12002 - //$$ channel.pipeline().addLast("ReplayModReplay_transition", new DummyNetworkStateTransitionHandler()); //$$ channel.pipeline().addLast("bundler", new PacketBundler(ClientConnection.CLIENTBOUND_PROTOCOL_KEY)); //#elseif MC>=11904 //$$ channel.pipeline().addLast("bundler", new PacketBundler(NetworkSide.CLIENTBOUND)); //#endif + channel.pipeline().addLast(PACKET_HANDLER_NAME, quickMode ? quickReplaySender : fullReplaySender); channel.pipeline().addLast("packet_handler", networkManager); channel.pipeline().fireChannelActive(); @@ -459,6 +464,8 @@ public class ReplayHandler { targetCameraPosition = null; } + channel.pipeline().replace(PACKET_HANDLER_NAME, PACKET_HANDLER_NAME, quickMode ? quickReplaySender : fullReplaySender); + if (quickMode) { quickReplaySender.register(); quickReplaySender.restart(); @@ -810,24 +817,4 @@ public class ReplayHandler { //$$ } //#endif } - - //#if MC>=12002 - //$$ private static class DummyNetworkStateTransitionHandler extends ChannelDuplexHandler { - //$$ @Override - //$$ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - //$$ if (msg instanceof Packet packet) { - //$$ NetworkStateTransitionHandler.handle(ctx.channel().attr(ClientConnection.CLIENTBOUND_PROTOCOL_KEY), packet); - //$$ } - //$$ super.channelRead(ctx, msg); - //$$ } - //$$ - //$$ @Override - //$$ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { - //$$ if (msg instanceof Packet packet) { - //$$ NetworkStateTransitionHandler.handle(ctx.channel().attr(ClientConnection.SERVERBOUND_PROTOCOL_KEY), packet); - //$$ } - //$$ super.write(ctx, msg, promise); - //$$ } - //$$ } - //#endif } diff --git a/versions/1.9.4/mapping.txt b/versions/1.9.4/mapping.txt index 0538db5a..9e250f8b 100644 --- a/versions/1.9.4/mapping.txt +++ b/versions/1.9.4/mapping.txt @@ -25,6 +25,8 @@ net.minecraft.network.play.server.SPacketSpawnPlayer getDataManagerEntries() fun net.minecraft.client.multiplayer.ServerList saveSingleServer() func_147414_b() net.minecraft.util.SoundEvent com.replaymod.core.versions.MCVer.SoundEvent +net.minecraft.network.NettyPacketDecoder net.minecraft.util.MessageDeserializer +net.minecraft.network.NettyPacketEncoder net.minecraft.util.MessageSerializer net.minecraft.network.play.server.SPacketJoinGame net.minecraft.network.play.server.S01PacketJoinGame net.minecraft.network.play.server.SPacketChat net.minecraft.network.play.server.S02PacketChat net.minecraft.network.play.server.SPacketParticles net.minecraft.network.play.server.S2APacketParticles From c74ef8c0e41904be1daee48ad7688f434493ab57 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 13 May 2024 16:54:02 +0200 Subject: [PATCH 03/28] Let Minecraft handle packet decoding during recording We've done this ourselves only because it was easier at the beginning. However with 1.20.5, Minecraft's packet decoding became substantially more sophisticated, to the point that it's probably a bad idea to try to do it ourselves. Additionally, getting the packet ids, which we require for identifying the packets which we want to decode, has becomes significantly more difficult too, and this way it's a simple instanceof check. --- .../recording/packet/PacketListener.java | 111 ++++++------------ 1 file changed, 33 insertions(+), 78 deletions(-) diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index 1cd11622..3faaa5c8 100644 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -73,7 +73,6 @@ import java.util.concurrent.atomic.AtomicInteger; import static com.replaymod.core.versions.MCVer.*; import static com.replaymod.replaystudio.util.Utils.writeInt; -import static java.util.Objects.requireNonNull; //#if MC>=11904 //$$ import net.minecraft.network.PacketBundleHandler; @@ -92,28 +91,6 @@ public class PacketListener extends ChannelInboundHandlerAdapter { private static final MinecraftClient mc = getMinecraft(); private static final Logger logger = LogManager.getLogger(); - private static final ResourcePackSendS2CPacket RESOURCE_PACK_SEND_PACKET = - //#if MC>=12003 - //$$ new ResourcePackSendS2CPacket(null, "", "", false, null) - //#elseif MC>=11700 - //$$ new ResourcePackSendS2CPacket("", "", false, null) - //#else - new ResourcePackSendS2CPacket() - //#endif - ; - private static final int PACKET_ID_RESOURCE_PACK_SEND = getPacketId(NetworkState.PLAY, RESOURCE_PACK_SEND_PACKET); - //#if MC>=12002 - //$$ private static final int PACKET_ID_CONFIG_RESOURCE_PACK_SEND = getPacketId(NetworkState.CONFIGURATION, RESOURCE_PACK_SEND_PACKET); - //#endif - //#if MC>=11700 - //$$ private static final int PACKET_ID_LOGIN_COMPRESSION = getPacketId(NetworkState.LOGIN, new LoginCompressionS2CPacket(0)); - //#else - private static final int PACKET_ID_LOGIN_COMPRESSION = getPacketId(NetworkState.LOGIN, new LoginCompressionS2CPacket()); - //#endif - //#if MC<10904 - //$$ private static final int PACKET_ID_PLAY_COMPRESSION = getPacketId(EnumConnectionState.PLAY, new S46PacketSetCompressionLevel()); - //#endif - private final ReplayMod core; private final Path outputPath; private final ReplayFile replayFile; @@ -126,6 +103,7 @@ public class PacketListener extends ChannelInboundHandlerAdapter { private ReplayMetaData metaData; private ChannelHandlerContext context = null; + private Packet currentRawPacket; private final long startTime; private long lastSentPacket; @@ -199,17 +177,6 @@ public class PacketListener extends ChannelInboundHandlerAdapter { return; } try { - //#if MC>=11800 - if (packet.getRegistry().getState() == State.LOGIN && packet.getId() == PACKET_ID_LOGIN_COMPRESSION) { - return; // Replay data is never compressed on the packet level - } - //#if MC<10904 - //$$ if (packet.getRegistry().getState() == State.PLAY && packet.getId() == PACKET_ID_PLAY_COMPRESSION) { - //$$ return; // Replay data is never compressed on the packet level - //$$ } - //#endif - //#endif - long now = System.currentTimeMillis(); if (serverWasPaused) { timePassedWhilePaused = now - startTime - lastSentPacket; @@ -388,24 +355,15 @@ public class PacketListener extends ChannelInboundHandlerAdapter { //#endif } - if (packet != null) { - if (connectionState == NetworkState.PLAY && packet.getId() == PACKET_ID_RESOURCE_PACK_SEND - //#if MC>=12002 - //$$ || connectionState == NetworkState.CONFIGURATION && packet.getId() == PACKET_ID_CONFIG_RESOURCE_PACK_SEND - //#endif - ) { - ClientConnection connection = ctx.pipeline().get(ClientConnection.class); - save(resourcePackRecorder.handleResourcePack(connection, (ResourcePackSendS2CPacket) decodeMcPacket(packet))); - //#if MC>=12003 - //$$ super.channelRead(ctx, msg); - //#endif - return; + currentRawPacket = packet; + try { + super.channelRead(ctx, msg); + } finally { + if (currentRawPacket != null) { + currentRawPacket.release(); + currentRawPacket = null; } - - save(packet); } - - super.channelRead(ctx, msg); } private NetworkState getConnectionState() { @@ -448,26 +406,6 @@ public class PacketListener extends ChannelInboundHandlerAdapter { } } - private static net.minecraft.network.Packet decodeMcPacket(Packet packet) throws IOException, IllegalAccessException, InstantiationException { - NetworkState connectionState = asMc(packet.getRegistry().getState()); - int packetId = packet.getId(); - PacketByteBuf packetBuf = new PacketByteBuf(Unpooled.wrappedBuffer(packet.getBuf().nioBuffer())); - - //#if MC>=12002 - //$$ return connectionState.getHandler(NetworkSide.CLIENTBOUND).createPacket(packetId, packetBuf); - //#elseif MC>=11700 - //$$ return connectionState.getPacketHandler(NetworkSide.CLIENTBOUND, packetId, packetBuf); - //#else - //#if MC>=10800 - net.minecraft.network.Packet p = connectionState.getPacketHandler(NetworkSide.CLIENTBOUND, packetId); - //#else - //$$ net.minecraft.network.Packet p = net.minecraft.network.Packet.generatePacket(connectionState.func_150755_b(), packetId); - //#endif - p.read(packetBuf); - return p; - //#endif - } - private static Packet decodePacket(NetworkState connectionState, ByteBuf buf) { PacketByteBuf packetBuf = new PacketByteBuf(buf.slice()); int packetId = packetBuf.readVarInt(); @@ -480,14 +418,6 @@ public class PacketListener extends ChannelInboundHandlerAdapter { ); } - private static int getPacketId(NetworkState networkState, net.minecraft.network.Packet packet) { - try { - return requireNonNull(networkState.getPacketId(NetworkSide.CLIENTBOUND, packet)); - } catch (Exception e) { - throw new RuntimeException("Failed to determine packet id for " + packet.getClass(), e); - } - } - public void addMarker(String name) { addMarker(name, (int) getCurrentDuration()); } @@ -535,6 +465,17 @@ public class PacketListener extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + if (msg instanceof LoginCompressionS2CPacket) { + super.channelRead(ctx, msg); + return; + } + //#if MC<10904 + //$$ if (msg instanceof S46PacketSetCompressionLevel) { + //$$ super.channelRead(ctx, msg); + //$$ return; + //$$ } + //#endif + if (msg instanceof CustomPayloadS2CPacket) { CustomPayloadS2CPacket packet = (CustomPayloadS2CPacket) msg; if (Restrictions.PLUGIN_CHANNEL.equals(packet.getChannel())) { @@ -559,6 +500,20 @@ public class PacketListener extends ChannelInboundHandlerAdapter { saveMetaData(); } + if (msg instanceof ResourcePackSendS2CPacket) { + ClientConnection connection = ctx.pipeline().get(ClientConnection.class); + save(resourcePackRecorder.handleResourcePack(connection, (ResourcePackSendS2CPacket) msg)); + //#if MC>=12003 + //$$ super.channelRead(ctx, msg); + //#endif + return; + } + + if (currentRawPacket != null) { + save(currentRawPacket); + currentRawPacket = null; + } + super.channelRead(ctx, msg); } } From acd56a7ba337e11bb2dd9505be62795f8c557562 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 13 May 2024 17:27:22 +0200 Subject: [PATCH 04/28] Remove player list packet entry workaround No longer using ForgeGradle \o/ --- .../com/replaymod/core/versions/Patterns.java | 11 ++++++ .../mixin/MixinNetHandlerPlayClient.java | 38 +++---------------- 2 files changed, 16 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/replaymod/core/versions/Patterns.java b/src/main/java/com/replaymod/core/versions/Patterns.java index 984b3fb8..3475551c 100644 --- a/src/main/java/com/replaymod/core/versions/Patterns.java +++ b/src/main/java/com/replaymod/core/versions/Patterns.java @@ -21,6 +21,7 @@ import net.minecraft.network.NetworkSide; import net.minecraft.network.NetworkState; import net.minecraft.network.Packet; import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; +import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; import net.minecraft.resource.Resource; import net.minecraft.resource.ResourceManager; import net.minecraft.sound.SoundCategory; @@ -85,6 +86,7 @@ import net.minecraft.client.render.BufferBuilder; import java.io.IOException; import java.util.Collection; import java.util.List; +import java.util.UUID; class Patterns { //#if MC>=10904 @@ -955,6 +957,15 @@ class Patterns { //$$ @Pattern public void UnloadChunkPacket_getX() {} //#endif + @Pattern + public UUID getId(PlayerListS2CPacket.Entry entry) { + //#if MC>=11903 + //$$ return entry.profileId(); + //#else + return entry.getProfile().getId(); + //#endif + } + @Pattern public Identifier getSkinTexture(AbstractClientPlayerEntity player) { //#if MC>=12002 diff --git a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java index b4ac0a8b..9c0278a1 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java @@ -2,7 +2,6 @@ package com.replaymod.recording.mixin; import com.replaymod.core.versions.MCVer; import com.replaymod.recording.handler.RecordingEventHandler; -import com.replaymod.replaystudio.lib.viaversion.api.protocol.packet.State; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket; @@ -13,16 +12,9 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; //#if MC>=10800 -import com.replaymod.replaystudio.protocol.Packet; -import com.replaymod.replaystudio.protocol.PacketType; -import com.replaymod.replaystudio.protocol.packets.PacketPlayerListEntry; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import net.minecraft.network.PacketByteBuf; import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; import net.minecraft.client.network.PlayerListEntry; -import java.io.IOException; import java.util.Map; import java.util.UUID; //#else @@ -67,32 +59,12 @@ public abstract class MixinNetHandlerPlayClient { //#else if (handler != null && packet.getAction() == PlayerListS2CPacket.Action.ADD_PLAYER) { //#endif - // We cannot reference SPacketPlayerListItem.AddPlayerData directly for complicated (and yet to be - // resolved) reasons (see https://github.com/MinecraftForge/ForgeGradle/issues/472), so we use ReplayStudio - // to parse it instead. - ByteBuf byteBuf = Unpooled.buffer(); - try { - packet.write(new PacketByteBuf(byteBuf)); - - byteBuf.readerIndex(0); - byte[] array = new byte[byteBuf.readableBytes()]; - byteBuf.readBytes(array); - - for (PacketPlayerListEntry data : PacketPlayerListEntry.read(new Packet( - MCVer.getPacketTypeRegistry(State.PLAY), 0, PacketType.PlayerListEntry, - com.github.steveice10.netty.buffer.Unpooled.wrappedBuffer(array) - ))) { - if (data.getUuid() == null) continue; - // Only add spawn packet for our own player and only if he isn't known yet - if (data.getUuid().equals(mcStatic.player.getGameProfile().getId()) - && !this.playerListEntries.containsKey(data.getUuid())) { - handler.spawnRecordingPlayer(); - } + for (PlayerListS2CPacket.Entry entry : packet.getEntries()) { + UUID uuid = entry.getProfile().getId(); + // Only add spawn packet for our own player and only if he isn't known yet + if (uuid.equals(mcStatic.player.getGameProfile().getId()) && !this.playerListEntries.containsKey(uuid)) { + handler.spawnRecordingPlayer(); } - } catch (IOException e) { - throw new RuntimeException(e); // we just parsed this? - } finally { - byteBuf.release(); } } } From 8900d5a4fbbe70cfccd67aa31feeaab5c53782cd Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 19 May 2024 12:48:17 +0200 Subject: [PATCH 05/28] Split MixinGameRenderer into multiple mixins --- ...java => Mixin_PostRenderWorldCalback.java} | 17 +---------- .../mixin/Mixin_PreRenderHandCallback.java | 28 +++++++++++++++++++ .../mixin/DecoderHandlerAccessor.java | 1 + src/main/resources/mixins.core.replaymod.json | 3 +- 4 files changed, 32 insertions(+), 17 deletions(-) rename src/main/java/com/replaymod/core/mixin/{MixinGameRenderer.java => Mixin_PostRenderWorldCalback.java} (67%) create mode 100644 src/main/java/com/replaymod/core/mixin/Mixin_PreRenderHandCallback.java create mode 100644 src/main/java/com/replaymod/recording/mixin/DecoderHandlerAccessor.java diff --git a/src/main/java/com/replaymod/core/mixin/MixinGameRenderer.java b/src/main/java/com/replaymod/core/mixin/Mixin_PostRenderWorldCalback.java similarity index 67% rename from src/main/java/com/replaymod/core/mixin/MixinGameRenderer.java rename to src/main/java/com/replaymod/core/mixin/Mixin_PostRenderWorldCalback.java index a7c817a9..ec85fe86 100644 --- a/src/main/java/com/replaymod/core/mixin/MixinGameRenderer.java +++ b/src/main/java/com/replaymod/core/mixin/Mixin_PostRenderWorldCalback.java @@ -2,8 +2,6 @@ package com.replaymod.core.mixin; import com.replaymod.core.events.PostRenderWorldCallback; -import com.replaymod.core.events.PreRenderHandCallback; -import net.minecraft.client.render.Camera; import net.minecraft.client.render.GameRenderer; import net.minecraft.client.util.math.MatrixStack; import org.spongepowered.asm.mixin.Mixin; @@ -12,7 +10,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(GameRenderer.class) -public class MixinGameRenderer { +public class Mixin_PostRenderWorldCalback { @Inject( method = "renderWorld", at = @At( @@ -32,18 +30,5 @@ public class MixinGameRenderer { //#endif PostRenderWorldCallback.EVENT.invoker().postRenderWorld(matrixStack); } - - @Inject(method = "renderHand", at = @At("HEAD"), cancellable = true) - private void preRenderHand( - //#if MC>=11500 - MatrixStack matrixStack, - //#endif - Camera camera, - float partialTicks, - CallbackInfo ci) { - if (PreRenderHandCallback.EVENT.invoker().preRenderHand()) { - ci.cancel(); - } - } } //#endif diff --git a/src/main/java/com/replaymod/core/mixin/Mixin_PreRenderHandCallback.java b/src/main/java/com/replaymod/core/mixin/Mixin_PreRenderHandCallback.java new file mode 100644 index 00000000..e52b713f --- /dev/null +++ b/src/main/java/com/replaymod/core/mixin/Mixin_PreRenderHandCallback.java @@ -0,0 +1,28 @@ +//#if MC>=11400 +package com.replaymod.core.mixin; + +import com.replaymod.core.events.PreRenderHandCallback; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.util.math.MatrixStack; +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(GameRenderer.class) +public class Mixin_PreRenderHandCallback { + @Inject(method = "renderHand", at = @At("HEAD"), cancellable = true) + private void preRenderHand( + //#if MC>=11500 + MatrixStack matrixStack, + //#endif + Camera camera, + float partialTicks, + CallbackInfo ci) { + if (PreRenderHandCallback.EVENT.invoker().preRenderHand()) { + ci.cancel(); + } + } +} +//#endif diff --git a/src/main/java/com/replaymod/recording/mixin/DecoderHandlerAccessor.java b/src/main/java/com/replaymod/recording/mixin/DecoderHandlerAccessor.java new file mode 100644 index 00000000..b40cfd98 --- /dev/null +++ b/src/main/java/com/replaymod/recording/mixin/DecoderHandlerAccessor.java @@ -0,0 +1 @@ +// 1.20.6 and above diff --git a/src/main/resources/mixins.core.replaymod.json b/src/main/resources/mixins.core.replaymod.json index 7e10b9c9..eb682f0d 100644 --- a/src/main/resources/mixins.core.replaymod.json +++ b/src/main/resources/mixins.core.replaymod.json @@ -7,7 +7,8 @@ "Mixin_ContextualKeyBindings", //#if MC>=11400 "AbstractButtonWidgetAccessor", - "MixinGameRenderer", + "Mixin_PostRenderWorldCalback", + "Mixin_PreRenderHandCallback", "Mixin_InjectDynamicResourcePacks", //#endif //#if MC>=11400 From f388e4af549d368cf02cf0617c62b0e575805eb7 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 23 Jun 2024 20:01:11 +0200 Subject: [PATCH 06/28] Update MixinExtras and include it on all Fabric versions --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 39e0b76a..e3a4794e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -120,8 +120,8 @@ dependencies { }) } - if (mcVersion >= 11604) { - implementation(shadow(annotationProcessor("com.github.LlamaLad7:MixinExtras:0.1.1")!!)!!) + if (platform.isFabric) { + "include"(implementation(annotationProcessor("io.github.llamalad7:mixinextras-fabric:0.3.6")!!)!!) } implementation(shadow("com.googlecode.mp4parser:isoparser:1.1.7")!!) From 046a50f326350b0b604a4f9b3b46160effb3ec31 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 19 May 2024 12:52:42 +0200 Subject: [PATCH 07/28] Target WorldRenderer in Mixin_PostRenderWorldCalback --- .../mixin/Mixin_PostRenderWorldCalback.java | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/replaymod/core/mixin/Mixin_PostRenderWorldCalback.java b/src/main/java/com/replaymod/core/mixin/Mixin_PostRenderWorldCalback.java index ec85fe86..24561031 100644 --- a/src/main/java/com/replaymod/core/mixin/Mixin_PostRenderWorldCalback.java +++ b/src/main/java/com/replaymod/core/mixin/Mixin_PostRenderWorldCalback.java @@ -2,32 +2,26 @@ package com.replaymod.core.mixin; import com.replaymod.core.events.PostRenderWorldCallback; -import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.render.WorldRenderer; import net.minecraft.client.util.math.MatrixStack; 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(GameRenderer.class) +//#if MC>=11500 +import com.llamalad7.mixinextras.sugar.Local; +//#endif + +@Mixin(WorldRenderer.class) public class Mixin_PostRenderWorldCalback { - @Inject( - method = "renderWorld", - at = @At( - value = "FIELD", - target = "Lnet/minecraft/client/render/GameRenderer;renderHand:Z" - ) - ) - private void postRenderWorld( - float partialTicks, - long nanoTime, - //#if MC>=11500 - MatrixStack matrixStack, - //#endif - CallbackInfo ci) { - //#if MC<11500 - //$$ MatrixStack matrixStack = new MatrixStack(); - //#endif + @Inject(method = "render", at = @At("RETURN")) + //#if MC>=11500 + private void postRenderWorld(CallbackInfo ci, @Local(argsOnly = true) MatrixStack matrixStack) { + //#else + //$$ private void postRenderWorld(CallbackInfo ci) { + //$$ MatrixStack matrixStack = new MatrixStack(); + //#endif PostRenderWorldCallback.EVENT.invoker().postRenderWorld(matrixStack); } } From 4df627029ca37675d1a6e57376bd4b663fd9947b Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 19 May 2024 14:27:15 +0200 Subject: [PATCH 08/28] Fix race condition in PacketListener The ChannelHandlerContext was only set on the next received packet, however `save` could be called before that happened. --- .../handler/ConnectionEventHandler.java | 3 ++- .../recording/packet/PacketListener.java | 23 +++++-------------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java index ef71a08b..5318013f 100644 --- a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java @@ -153,8 +153,9 @@ public class ConnectionEventHandler { metaData.setGenerator("ReplayMod v" + ReplayMod.instance.getVersion()); metaData.setDate(System.currentTimeMillis()); metaData.setMcVersion(ReplayMod.instance.getMinecraftVersion()); - packetListener = new PacketListener(core, outputPath, replayFile, metaData); + Channel channel = ((NetworkManagerAccessor) networkManager).getChannel(); + packetListener = new PacketListener(core, channel, outputPath, replayFile, metaData); if (channel.pipeline().get(PacketListener.DECODER_KEY) != null) { // Regular channel, we'll inject our recorder directly before the decoder channel.pipeline().addBefore(PacketListener.DECODER_KEY, PacketListener.RAW_RECORDER_KEY, packetListener); diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index 3faaa5c8..c04f44bc 100644 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -22,6 +22,7 @@ import com.replaymod.replaystudio.replay.ReplayMetaData; import de.johni0702.minecraft.gui.container.VanillaGuiScreen; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; @@ -102,7 +103,7 @@ public class PacketListener extends ChannelInboundHandlerAdapter { private ReplayMetaData metaData; - private ChannelHandlerContext context = null; + private final Channel channel; private Packet currentRawPacket; private final long startTime; @@ -116,8 +117,9 @@ public class PacketListener extends ChannelInboundHandlerAdapter { */ private final AtomicInteger lastSaveMetaDataId = new AtomicInteger(); - public PacketListener(ReplayMod core, Path outputPath, ReplayFile replayFile, ReplayMetaData metaData) throws IOException { + public PacketListener(ReplayMod core, Channel channel, Path outputPath, ReplayFile replayFile, ReplayMetaData metaData) throws IOException { this.core = core; + this.channel = channel; this.outputPath = outputPath; this.replayFile = replayFile; this.metaData = metaData; @@ -309,15 +311,6 @@ public class PacketListener extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - if(ctx == null) { - if(context == null) { - return; - } else { - ctx = context; - } - } - this.context = ctx; - NetworkState connectionState = getConnectionState(); Packet packet = null; @@ -367,16 +360,12 @@ public class PacketListener extends ChannelInboundHandlerAdapter { } private NetworkState getConnectionState() { - ChannelHandlerContext ctx = context; - if (ctx == null) { - return NetworkState.LOGIN; - } //#if MC>=12002 //$$ AttributeKey> key = ClientConnection.CLIENTBOUND_PROTOCOL_KEY; - //$$ return ctx.channel().attr(key).get().getState(); + //$$ return channel.attr(key).get().getState(); //#else AttributeKey key = ClientConnection.ATTR_KEY_PROTOCOL; - return ctx.channel().attr(key).get(); + return channel.attr(key).get(); //#endif } From 675134e6d644a8a818f8c26c08af699060c1b79e Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 19 May 2024 15:09:07 +0200 Subject: [PATCH 09/28] Split outbound handler from FullReplaySender This because with 1.20.6, MC will require outbound messages to reach its handlers to switch between protocol versions. So we need our drop handler two be at the very end of the write processing chain. --- .../replaymod/replay/FullReplaySender.java | 24 ++----------------- .../com/replaymod/replay/ReplayHandler.java | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/replaymod/replay/FullReplaySender.java b/src/main/java/com/replaymod/replay/FullReplaySender.java index fe2edfa8..2ee44132 100644 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/FullReplaySender.java @@ -17,10 +17,9 @@ import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; -import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPromise; +import io.netty.channel.ChannelInboundHandlerAdapter; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.OtherClientPlayerEntity; import net.minecraft.client.gui.screen.DownloadingTerrainScreen; @@ -161,7 +160,7 @@ import static com.replaymod.replaystudio.util.Utils.readInt; * the replay restart from the beginning. */ @Sharable -public class FullReplaySender extends ChannelDuplexHandler implements ReplaySender { +public class FullReplaySender extends ChannelInboundHandlerAdapter implements ReplaySender { /** * These packets are ignored completely during replay. */ @@ -952,25 +951,6 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend //$$ } //#endif - @Override - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { - // The embedded channel's event loop will consider every thread to be in it and as such provides no - // guarantees that only one thread is using the pipeline at any one time. - // For reading the replay sender (either sync or async) is the only thread ever writing. - // For writing it may very well happen that multiple threads want to use the pipline at the same time. - // It's unclear whether the EmbeddedChannel is supposed to be thread-safe (the behavior of the event loop - // does suggest that). However it seems like it either isn't (likely) or there is a race condition. - // See: https://www.replaymod.com/forum/thread/1752#post8045 (https://paste.replaymod.com/lotacatuwo) - // To work around this issue, we just outright drop all write/flush requests (they aren't needed anyway). - // This still leaves channel handlers upstream with the threading issue but they all seem to cope well with it. - promise.setSuccess(); - } - - @Override - public void flush(ChannelHandlerContext ctx) throws Exception { - // See write method above - } - /** * Returns the speed of the replay. 1 being normal speed, 0.5 half and 2 twice as fast. * If 0 is returned, the replay is paused. diff --git a/src/main/java/com/replaymod/replay/ReplayHandler.java b/src/main/java/com/replaymod/replay/ReplayHandler.java index 416d80ea..dcd259bd 100644 --- a/src/main/java/com/replaymod/replay/ReplayHandler.java +++ b/src/main/java/com/replaymod/replay/ReplayHandler.java @@ -28,6 +28,8 @@ import de.johni0702.minecraft.gui.element.advanced.GuiProgressBar; import de.johni0702.minecraft.gui.layout.HorizontalLayout; import de.johni0702.minecraft.gui.popup.AbstractGuiPopup; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOutboundHandlerAdapter; +import io.netty.channel.ChannelPromise; import io.netty.channel.embedded.EmbeddedChannel; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.DownloadingTerrainScreen; @@ -318,6 +320,7 @@ public class ReplayHandler { //$$ channel.pipeline().remove(dummyHandler); //$$ channel.pipeline().removeLast(); //#endif + channel.pipeline().addFirst("ReplayModReplay_head", new DropOutboundMessagesHandler()); quickReplaySender.setChannel(channel); fullReplaySender.setChannel(channel); @@ -817,4 +820,25 @@ public class ReplayHandler { //$$ } //#endif } + + private static class DropOutboundMessagesHandler extends ChannelOutboundHandlerAdapter { + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { + // The embedded channel's event loop will consider every thread to be in it and as such provides no + // guarantees that only one thread is using the pipeline at any one time. + // For reading the replay sender (either sync or async) is the only thread ever writing. + // For writing it may very well happen that multiple threads want to use the pipline at the same time. + // It's unclear whether the EmbeddedChannel is supposed to be thread-safe (the behavior of the event loop + // does suggest that). However it seems like it either isn't (likely) or there is a race condition. + // See: https://www.replaymod.com/forum/thread/1752#post8045 (https://paste.replaymod.com/lotacatuwo) + // To work around this issue, we just outright drop all write/flush requests (they aren't needed anyway). + // This still leaves channel handlers upstream with the threading issue but they all seem to cope well with it. + promise.setSuccess(); + } + + @Override + public void flush(ChannelHandlerContext ctx) { + // See write method above + } + } } From 3f12413c6b5cbf6569cc8f292ae7e5c86da9fc70 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 19 May 2024 17:05:31 +0200 Subject: [PATCH 10/28] De-duplicate recording channel configuration --- .../handler/ConnectionEventHandler.java | 2 ++ .../recording/packet/PacketListener.java | 18 +----------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java index 5318013f..2635860b 100644 --- a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java @@ -159,9 +159,11 @@ public class ConnectionEventHandler { if (channel.pipeline().get(PacketListener.DECODER_KEY) != null) { // Regular channel, we'll inject our recorder directly before the decoder channel.pipeline().addBefore(PacketListener.DECODER_KEY, PacketListener.RAW_RECORDER_KEY, packetListener); + channel.pipeline().addAfter(PacketListener.DECODER_KEY, PacketListener.DECODED_RECORDER_KEY, packetListener.new DecodedPacketListener()); } else { // Integrated server passes packets directly, there's no splitting, decompression or decoding channel.pipeline().addFirst(PacketListener.RAW_RECORDER_KEY, packetListener); + channel.pipeline().addAfter(PacketListener.RAW_RECORDER_KEY, PacketListener.DECODED_RECORDER_KEY, packetListener.new DecodedPacketListener()); } recordingEventHandler = new RecordingEventHandler(packetListener); diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index c04f44bc..07027547 100644 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -218,22 +218,6 @@ public class PacketListener extends ChannelInboundHandlerAdapter { } } - @Override - public void handlerAdded(ChannelHandlerContext ctx) throws Exception { - super.handlerAdded(ctx); - - if (ctx.pipeline().get(DECODED_RECORDER_KEY) == null) { - if (ctx.pipeline().get(PacketListener.DECODER_KEY) != null) { - // Regular channel, we'll inject our decoded recorder directly after the decoder - ctx.pipeline().addAfter(DECODER_KEY, DECODED_RECORDER_KEY, new DecodedPacketListener()); - } else { - // Integrated server passes packets directly, there's no splitting, decompression or decoding - // The decoded packet handler can just go directly behind this hand - ctx.pipeline().addAfter(RAW_RECORDER_KEY, DECODED_RECORDER_KEY, new DecodedPacketListener()); - } - } - } - @Override public void channelInactive(ChannelHandlerContext ctx) { metaData.setDuration((int) lastSentPacket); @@ -450,7 +434,7 @@ public class PacketListener extends ChannelInboundHandlerAdapter { return resourcePackRecorder; } - private class DecodedPacketListener extends ChannelInboundHandlerAdapter { + public class DecodedPacketListener extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { From 5218feb6b6e57aebdbf356d5f59e628ec4ddb7fe Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 18 Jun 2024 14:48:26 +0200 Subject: [PATCH 11/28] Update to 1.20.6 --- build.gradle.kts | 10 ++- jGui | 2 +- root.gradle.kts | 2 + settings.gradle.kts | 2 + .../java/com/replaymod/core/ReplayMod.java | 11 ++- .../mixin/Mixin_PostRenderWorldCalback.java | 6 ++ .../mixin/Mixin_PreRenderHandCallback.java | 10 ++- .../replaymod/core/utils/Restrictions.java | 28 ++++++- .../core/versions/LangResourcePack.java | 11 ++- .../com/replaymod/core/versions/MCVer.java | 8 +- .../com/replaymod/core/versions/Patterns.java | 22 +++++- .../recording/ReplayModRecording.java | 10 ++- .../handler/ConnectionEventHandler.java | 6 ++ .../handler/RecordingEventHandler.java | 9 ++- .../mixin/MixinNetHandlerConfigClient.java | 1 + .../recording/packet/PacketListener.java | 73 ++++++++++++++++++- .../java/com/replaymod/render/blend/Util.java | 4 + .../render/gui/GuiVideoRenderer.java | 6 ++ .../render/mixin/Mixin_ChromaKeyColorSky.java | 4 +- .../mixin/Mixin_Omnidirectional_Camera.java | 4 + .../mixin/Mixin_Omnidirectional_Rotation.java | 17 ++++- .../mixin/Mixin_Stereoscopic_Camera.java | 25 ++++++- .../render/rendering/VideoRenderer.java | 14 +++- .../replaymod/replay/FullReplaySender.java | 3 + .../com/replaymod/replay/NoGuiScreenshot.java | 4 +- .../com/replaymod/replay/ReplayHandler.java | 49 ++++++++++++- .../replaymod/replay/mixin/MixinCamera.java | 17 +++++ .../preview/PathPreviewRenderer.java | 4 + .../resources/mixins.recording.replaymod.json | 6 ++ .../render/mixin/Mixin_ForceChunkLoading.java | 3 +- versions/1.20.6/.gitkeep | 0 .../mixin/DecoderHandlerAccessor.java | 16 ++++ .../mixin/MixinNetHandlerConfigClient.java | 62 ++++++++++++++++ 33 files changed, 424 insertions(+), 25 deletions(-) create mode 100644 src/main/java/com/replaymod/recording/mixin/MixinNetHandlerConfigClient.java create mode 100644 versions/1.20.6/.gitkeep create mode 100644 versions/1.20.6/src/main/java/com/replaymod/recording/mixin/DecoderHandlerAccessor.java create mode 100644 versions/1.20.6/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerConfigClient.java diff --git a/build.gradle.kts b/build.gradle.kts index e3a4794e..66d57726 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -85,6 +85,7 @@ dependencies { 12001 -> "0.83.1+1.20.1" 12002 -> "0.91.2+1.20.2" 12004 -> "0.91.2+1.20.4" + 12006 -> "0.98.0+1.20.6" else -> throw UnsupportedOperationException() } val fabricApiModules = mutableListOf( @@ -154,7 +155,7 @@ dependencies { implementation(shadow("com.github.ReplayMod.JavaBlend:2.79.0:a0696f8")!!) - implementation(shadow("com.github.ReplayMod:ReplayStudio:d9f7c11")!!) + implementation(shadow("com.github.ReplayMod:ReplayStudio:6d59510")!!) // FIXME this should be pulled in by ReplayStudio, and IntelliJ sees it, but javac for some reason does not implementation("com.github.viaversion:opennbt:0a02214") // 2.0-SNAPSHOT (ViaVersion Edition) @@ -163,6 +164,7 @@ dependencies { if (platform.isFabric) { val modMenuVersion = when { + mcVersion >= 12006 -> "10.0.0-beta.1" mcVersion >= 12003 -> "9.0.0-pre.1" mcVersion >= 12002 -> "8.0.0" mcVersion >= 12000 -> "7.0.1" @@ -179,11 +181,15 @@ dependencies { else -> null } if (modMenuVersion != null) { - modImplementation("com.terraformersmc:modmenu:$modMenuVersion") + modCompileOnly("com.terraformersmc:modmenu:$modMenuVersion") } else { // Oldest modmenu on their maven is 1.10.5 for MC 1.15.2; for older versions we won't run it in dev modCompileOnly("com.terraformersmc:modmenu:1.10.6") } + // Lacks maven dependencies + if (mcVersion == 12006) { + //modRuntimeOnly("net.fabricmc.fabric-api:fabric-api:0.98.0+1.20.6") + } } if (mcVersion >= 11600) { diff --git a/jGui b/jGui index 9b5b2104..1a9b23d0 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 9b5b2104aad687949ac4138efecd6866a4582241 +Subproject commit 1a9b23d0c92223bf3e6859452854066e841e0eb2 diff --git a/root.gradle.kts b/root.gradle.kts index 18c2e7a0..b97e261f 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -203,6 +203,7 @@ val doRelease by tasks.registering { defaultTasks("bundleJar") preprocess { + val mc12006 = createNode("1.20.6", 12006, "yarn") val mc12004 = createNode("1.20.4", 12004, "yarn") val mc12002 = createNode("1.20.2", 12002, "yarn") val mc12001 = createNode("1.20.1", 12001, "yarn") @@ -230,6 +231,7 @@ preprocess { val mc10800 = createNode("1.8", 10800, "srg") val mc10710 = createNode("1.7.10", 10710, "srg") + mc12006.link(mc12004) mc12004.link(mc12002, file("versions/mapping-fabric-1.20.4-1.20.2.txt")) mc12002.link(mc12001) mc12001.link(mc11904) diff --git a/settings.gradle.kts b/settings.gradle.kts index b332765d..c38a151c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -38,6 +38,7 @@ val jGuiVersions = listOf( "1.20.1", "1.20.2", "1.20.4", + "1.20.6", ) val replayModVersions = listOf( // "1.7.10", @@ -66,6 +67,7 @@ val replayModVersions = listOf( "1.20.1", "1.20.2", "1.20.4", + "1.20.6", ) rootProject.buildFileName = "root.gradle.kts" diff --git a/src/main/java/com/replaymod/core/ReplayMod.java b/src/main/java/com/replaymod/core/ReplayMod.java index d31a57f7..add813c7 100644 --- a/src/main/java/com/replaymod/core/ReplayMod.java +++ b/src/main/java/com/replaymod/core/ReplayMod.java @@ -36,6 +36,13 @@ import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; +//#if MC>=12006 +//$$ import net.minecraft.resource.ResourcePackInfo; +//$$ import net.minecraft.resource.ResourcePackSource; +//$$ import net.minecraft.text.Text; +//$$ import java.util.Optional; +//#endif + //#if MC>=11900 //#else import net.minecraft.client.options.Option; @@ -120,7 +127,9 @@ public class ReplayMod implements Module, Scheduler { return null; } } - //#if MC>=11903 + //#if MC>=12006 + //$$ return new DirectoryResourcePack(new ResourcePackInfo(JGUI_RESOURCE_PACK_NAME, Text.literal("jGui"), ResourcePackSource.NONE, Optional.empty()), folder.toPath()) { + //#elseif MC>=11903 //$$ return new DirectoryResourcePack(JGUI_RESOURCE_PACK_NAME, folder.toPath(), true) { //#else return new DirectoryResourcePack(folder) { diff --git a/src/main/java/com/replaymod/core/mixin/Mixin_PostRenderWorldCalback.java b/src/main/java/com/replaymod/core/mixin/Mixin_PostRenderWorldCalback.java index 24561031..641749c5 100644 --- a/src/main/java/com/replaymod/core/mixin/Mixin_PostRenderWorldCalback.java +++ b/src/main/java/com/replaymod/core/mixin/Mixin_PostRenderWorldCalback.java @@ -15,12 +15,18 @@ import com.llamalad7.mixinextras.sugar.Local; @Mixin(WorldRenderer.class) public class Mixin_PostRenderWorldCalback { + //#if MC>=12005 + //$$ @Inject(method = "render", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4fStack;popMatrix()Lorg/joml/Matrix4fStack;")) + //$$ private void postRenderWorld(CallbackInfo ci) { + //$$ MatrixStack matrixStack = new MatrixStack(); + //#else @Inject(method = "render", at = @At("RETURN")) //#if MC>=11500 private void postRenderWorld(CallbackInfo ci, @Local(argsOnly = true) MatrixStack matrixStack) { //#else //$$ private void postRenderWorld(CallbackInfo ci) { //$$ MatrixStack matrixStack = new MatrixStack(); + //#endif //#endif PostRenderWorldCallback.EVENT.invoker().postRenderWorld(matrixStack); } diff --git a/src/main/java/com/replaymod/core/mixin/Mixin_PreRenderHandCallback.java b/src/main/java/com/replaymod/core/mixin/Mixin_PreRenderHandCallback.java index e52b713f..012c93eb 100644 --- a/src/main/java/com/replaymod/core/mixin/Mixin_PreRenderHandCallback.java +++ b/src/main/java/com/replaymod/core/mixin/Mixin_PreRenderHandCallback.java @@ -10,15 +10,23 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//#if MC>=12005 +//$$ import org.joml.Matrix4f; +//#else +//#endif + @Mixin(GameRenderer.class) public class Mixin_PreRenderHandCallback { @Inject(method = "renderHand", at = @At("HEAD"), cancellable = true) private void preRenderHand( - //#if MC>=11500 + //#if MC>=11500 && MC<12005 MatrixStack matrixStack, //#endif Camera camera, float partialTicks, + //#if MC>=12005 + //$$ Matrix4f matrixStack, + //#endif CallbackInfo ci) { if (PreRenderHandCallback.EVENT.invoker().preRenderHand()) { ci.cancel(); diff --git a/src/main/java/com/replaymod/core/utils/Restrictions.java b/src/main/java/com/replaymod/core/utils/Restrictions.java index 0fc0e9f2..c1543e83 100644 --- a/src/main/java/com/replaymod/core/utils/Restrictions.java +++ b/src/main/java/com/replaymod/core/utils/Restrictions.java @@ -2,6 +2,12 @@ package com.replaymod.core.utils; import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; import net.minecraft.network.PacketByteBuf; + +//#if MC>=12006 +//$$ import net.minecraft.network.codec.PacketCodec; +//$$ import net.minecraft.network.packet.CustomPayload; +//#endif + //#if MC>=10904 import net.minecraft.util.Identifier; //#endif @@ -26,7 +32,9 @@ public class Restrictions { private boolean onlyRecordingPlayer; public String handle(CustomPayloadS2CPacket packet) { - //#if MC>=12002 + //#if MC>=12006 + //$$ PacketByteBuf buffer = new PacketByteBuf(Unpooled.wrappedBuffer(((Payload) packet.payload()).bytes())); + //#elseif MC>=12002 //$$ PacketByteBuf buffer = new PacketByteBuf(Unpooled.buffer()); //$$ packet.write(buffer); //#elseif MC>=10800 @@ -67,4 +75,22 @@ public class Restrictions { public boolean isOnlyRecordingPlayer() { return onlyRecordingPlayer; } + + //#if MC>=12006 + //$$ public static final CustomPayload.Id ID = CustomPayload.id(PLUGIN_CHANNEL.toString()); + //$$ public static final PacketCodec CODEC = PacketCodec.ofStatic( + //$$ (buf, payload) -> buf.writeBytes(payload.bytes()), + //$$ buf -> { + //$$ byte[] bytes = new byte[buf.readableBytes()]; + //$$ buf.readBytes(bytes); + //$$ return new Payload(bytes); + //$$ } + //$$ ); + //$$ public record Payload(byte[] bytes) implements CustomPayload { + //$$ @Override + //$$ public Id getId() { + //$$ return ID; + //$$ } + //$$ } + //#endif } diff --git a/src/main/java/com/replaymod/core/versions/LangResourcePack.java b/src/main/java/com/replaymod/core/versions/LangResourcePack.java index 41fa3e14..5e988552 100644 --- a/src/main/java/com/replaymod/core/versions/LangResourcePack.java +++ b/src/main/java/com/replaymod/core/versions/LangResourcePack.java @@ -34,6 +34,13 @@ import net.fabricmc.loader.api.ModContainer; //#else //#endif +//#if MC>=12006 +//$$ import net.minecraft.resource.ResourcePackInfo; +//$$ import net.minecraft.resource.ResourcePackSource; +//$$ import net.minecraft.text.Text; +//$$ import java.util.Optional; +//#endif + //#if MC>=11903 //$$ import java.util.Objects; //$$ import net.minecraft.resource.InputSupplier; @@ -64,7 +71,9 @@ public class LangResourcePack extends AbstractFileResourcePack { private final Path basePath; public LangResourcePack() { - //#if MC>=11903 + //#if MC>=12006 + //$$ super(new ResourcePackInfo(NAME, Text.literal("ReplayMod Translations"), ResourcePackSource.NONE, Optional.empty())); + //#elseif MC>=11903 //$$ super(NAME, true); //#else super(new File(NAME)); diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index 44e64f14..806b5f3c 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -397,7 +397,9 @@ public class MCVer { } public static void pushMatrix() { - //#if MC>=11700 + //#if MC>=12006 + //$$ RenderSystem.getModelViewStack().pushMatrix(); + //#elseif MC>=11700 //$$ RenderSystem.getModelViewStack().push(); //#else GlStateManager.pushMatrix(); @@ -406,7 +408,11 @@ public class MCVer { public static void popMatrix() { //#if MC>=11700 + //#if MC>=12006 + //$$ RenderSystem.getModelViewStack().popMatrix(); + //#else //$$ RenderSystem.getModelViewStack().pop(); + //#endif //$$ RenderSystem.applyModelViewMatrix(); //#else GlStateManager.popMatrix(); diff --git a/src/main/java/com/replaymod/core/versions/Patterns.java b/src/main/java/com/replaymod/core/versions/Patterns.java index 3475551c..1d7e7aec 100644 --- a/src/main/java/com/replaymod/core/versions/Patterns.java +++ b/src/main/java/com/replaymod/core/versions/Patterns.java @@ -21,6 +21,7 @@ import net.minecraft.network.NetworkSide; import net.minecraft.network.NetworkState; import net.minecraft.network.Packet; import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; +import net.minecraft.network.packet.s2c.play.DisconnectS2CPacket; import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; import net.minecraft.resource.Resource; import net.minecraft.resource.ResourceManager; @@ -576,7 +577,9 @@ class Patterns { @Pattern private static void GL11_glRotatef(float angle, float x, float y, float z) { - //#if MC>=11700 + //#if MC>=12006 + //$$ com.mojang.blaze3d.systems.RenderSystem.getModelViewStack().rotate(com.replaymod.core.versions.MCVer.quaternion(angle, new org.joml.Vector3f(x, y, z))); + //#elseif MC>=11700 //$$ com.mojang.blaze3d.systems.RenderSystem.getModelViewStack().multiply(com.replaymod.core.versions.MCVer.quaternion(angle, new net.minecraft.util.math.Vec3f(x, y, z))); //#else GL11.glRotatef(angle, x, y, z); @@ -917,7 +920,9 @@ class Patterns { @Pattern public Object channel(CustomPayloadS2CPacket packet) { - //#if MC>=12002 + //#if MC>=12006 + //$$ return packet.payload().getId().id(); + //#elseif MC>=12002 //$$ return packet.payload().id(); //#else return packet.getChannel(); @@ -925,6 +930,9 @@ class Patterns { } //#if MC>=10904 + //#if MC>=12006 + //$$ @Pattern public void getPacketId() {} + //#else @Pattern public Integer getPacketId(NetworkState state, NetworkSide side, Packet packet) throws Exception { //#if MC>=12002 @@ -933,6 +941,7 @@ class Patterns { return state.getPacketId(side, packet); //#endif } + //#endif @Pattern public int UnloadChunkPacket_getX(UnloadChunkS2CPacket packet) { @@ -983,4 +992,13 @@ class Patterns { return mc.options.debugEnabled; //#endif } + + @Pattern + public Text getMessage(DisconnectS2CPacket packet) { + //#if MC>=12006 + //$$ return packet.reason(); + //#else + return packet.getReason(); + //#endif + } } diff --git a/src/main/java/com/replaymod/recording/ReplayModRecording.java b/src/main/java/com/replaymod/recording/ReplayModRecording.java index ee8fbaac..edbba5fe 100644 --- a/src/main/java/com/replaymod/recording/ReplayModRecording.java +++ b/src/main/java/com/replaymod/recording/ReplayModRecording.java @@ -16,6 +16,10 @@ import net.minecraft.network.ClientConnection; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +//#if MC>=12006 +//$$ import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +//#endif + //#if FABRIC>=1 //#if MC>=11700 //$$ import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; @@ -73,7 +77,11 @@ public class ReplayModRecording implements Module { new GuiHandler(core).register(); //#if FABRIC>=1 - //#if MC>=11700 + //#if MC>=12006 + //$$ PayloadTypeRegistry.configurationS2C().register(Restrictions.ID, Restrictions.CODEC); + //$$ PayloadTypeRegistry.playS2C().register(Restrictions.ID, Restrictions.CODEC); + //$$ ClientPlayNetworking.registerGlobalReceiver(Restrictions.ID, (payload, context) -> {}); + //#elseif MC>=11700 //$$ ClientPlayNetworking.registerGlobalReceiver(Restrictions.PLUGIN_CHANNEL, (client, handler, buf, resp) -> {}); //#else ClientSidePacketRegistry.INSTANCE.register(Restrictions.PLUGIN_CHANNEL, (packetContext, packetByteBuf) -> {}); diff --git a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java index 2635860b..23814307 100644 --- a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java @@ -156,6 +156,11 @@ public class ConnectionEventHandler { Channel channel = ((NetworkManagerAccessor) networkManager).getChannel(); packetListener = new PacketListener(core, channel, outputPath, replayFile, metaData); + + //#if MC>=12005 + //$$ channel.pipeline().addBefore("inbound_config", PacketListener.RAW_RECORDER_KEY, packetListener); + //$$ channel.pipeline().addAfter("inbound_config", PacketListener.DECODED_RECORDER_KEY, packetListener.new DecodedPacketListener()); + //#else if (channel.pipeline().get(PacketListener.DECODER_KEY) != null) { // Regular channel, we'll inject our recorder directly before the decoder channel.pipeline().addBefore(PacketListener.DECODER_KEY, PacketListener.RAW_RECORDER_KEY, packetListener); @@ -165,6 +170,7 @@ public class ConnectionEventHandler { channel.pipeline().addFirst(PacketListener.RAW_RECORDER_KEY, packetListener); channel.pipeline().addAfter(PacketListener.RAW_RECORDER_KEY, PacketListener.DECODED_RECORDER_KEY, packetListener.new DecodedPacketListener()); } + //#endif recordingEventHandler = new RecordingEventHandler(packetListener); recordingEventHandler.register(); diff --git a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java index 8d948069..93596d7a 100644 --- a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java @@ -73,7 +73,12 @@ public class RecordingEventHandler extends EventRegistrations { private final PacketListener packetListener; private Double lastX, lastY, lastZ; - private final List playerItems = DefaultedList.ofSize(6, ItemStack.EMPTY); + //#if MC>=10904 + private static final int EQUIPMENT_SLOTS = EquipmentSlot.values().length; + //#else + //$$ private static final int EQUIPMENT_SLOTS = 5; + //#endif + private final List playerItems = DefaultedList.ofSize(EQUIPMENT_SLOTS, ItemStack.EMPTY); private int ticksSinceLastCorrection; private boolean wasSleeping; private int lastRiding = -1; @@ -279,7 +284,7 @@ public class RecordingEventHandler extends EventRegistrations { ItemStack stack = player.getEquippedStack(slot); int index = slot.ordinal(); //#else - //$$ for (int slot = 0; slot < 5; slot++) { + //$$ for (int slot = 0; slot < EQUIPMENT_SLOTS; slot++) { //$$ ItemStack stack = player.getEquipmentInSlot(slot); //$$ int index = slot; //#endif diff --git a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerConfigClient.java b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerConfigClient.java new file mode 100644 index 00000000..b40cfd98 --- /dev/null +++ b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerConfigClient.java @@ -0,0 +1 @@ +// 1.20.6 and above diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index 07027547..ca4b47ae 100644 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -23,9 +23,11 @@ import de.johni0702.minecraft.gui.container.VanillaGuiScreen; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; +import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelPromise; import io.netty.util.AttributeKey; import net.minecraft.client.MinecraftClient; import net.minecraft.network.ClientConnection; @@ -41,6 +43,15 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +//#if MC>=12006 +//$$ import com.replaymod.recording.mixin.DecoderHandlerAccessor; +//$$ import net.minecraft.network.NetworkState; +//$$ import net.minecraft.network.handler.DecoderHandler; +//$$ import net.minecraft.network.handler.NetworkStateTransitions; +//$$ import net.minecraft.network.packet.s2c.config.ReadyS2CPacket; +//$$ import net.minecraft.network.state.LoginStates; +//#endif + //#if MC>=12002 //$$ import net.minecraft.entity.EntityType; //$$ import net.minecraft.network.packet.s2c.play.EntitySpawnS2CPacket; @@ -307,6 +318,9 @@ public class PacketListener extends ChannelInboundHandlerAdapter { } else if (msg instanceof net.minecraft.network.Packet) { // for integrated server connections MC is passing the packet objects directly, so we need to encode them // ourselves to be able to store them + //#if MC>=12006 + //$$ // No longer applies. MC now encodes packets even for the integrated server connection. + //#else //#if MC>=11904 //#if MC>=12002 //$$ PacketBundleHandler bundleHandler = ctx.channel().attr(ClientConnection.CLIENTBOUND_PROTOCOL_KEY).get().getBundler(); @@ -330,6 +344,7 @@ public class PacketListener extends ChannelInboundHandlerAdapter { //#else packet = encodeMcPacket(connectionState, (net.minecraft.network.Packet) msg); //#endif + //#endif } currentRawPacket = packet; @@ -344,7 +359,13 @@ public class PacketListener extends ChannelInboundHandlerAdapter { } private NetworkState getConnectionState() { - //#if MC>=12002 + //#if MC>=12006 + //$$ var decoderHandler = (DecoderHandlerAccessor) channel.pipeline().get(DecoderHandler.class); + //$$ if (decoderHandler == null) { + //$$ return NetworkPhase.LOGIN; + //$$ } + //$$ return decoderHandler.getState().id(); + //#elseif MC>=12002 //$$ AttributeKey> key = ClientConnection.CLIENTBOUND_PROTOCOL_KEY; //$$ return channel.attr(key).get().getState(); //#else @@ -353,7 +374,25 @@ public class PacketListener extends ChannelInboundHandlerAdapter { //#endif } - private static Packet encodeMcPacket(NetworkState connectionState, net.minecraft.network.Packet packet) throws Exception { + private Packet encodeMcPacket(NetworkState connectionState, net.minecraft.network.Packet packet) throws Exception { + //#if MC>=12006 + //$$ var byteBuf = Unpooled.buffer(); + //$$ try { + //$$ NetworkState state; + //$$ if (connectionState == NetworkPhase.LOGIN) { + //$$ // Special case for our initial LoginSuccess packet which we only save after the pipeline has already + //$$ // started to transition to the next phase, so we can't just use its DecoderHandler (and luckily we + //$$ // also don't need it). + //$$ state = LoginStates.S2C; + //$$ } else { + //$$ state = ((DecoderHandlerAccessor) channel.pipeline().get(DecoderHandler.class)).getState(); + //$$ } + //$$ state.codec().encode(byteBuf, packet); + //$$ return decodePacket(state.id(), byteBuf); + //$$ } finally { + //$$ byteBuf.release(); + //$$ } + //#else //#if MC>=10800 Integer packetId = connectionState.getPacketId(NetworkSide.CLIENTBOUND, packet); //#else @@ -377,6 +416,7 @@ public class PacketListener extends ChannelInboundHandlerAdapter { } finally { byteBuf.release(); } + //#endif } private static Packet decodePacket(NetworkState connectionState, ByteBuf buf) { @@ -434,7 +474,7 @@ public class PacketListener extends ChannelInboundHandlerAdapter { return resourcePackRecorder; } - public class DecodedPacketListener extends ChannelInboundHandlerAdapter { + public class DecodedPacketListener extends ChannelDuplexHandler { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { @@ -482,6 +522,17 @@ public class PacketListener extends ChannelInboundHandlerAdapter { return; } + //#if MC>=12006 + //$$ // Special case: We need to inject another packet before this one, and we can only construct that + //$$ // packet on the main thread, so we'll skip saving this packet here and then manually re-add it after + //$$ // that other packet has been injected. + //$$ // See MixinNetHandlerConfigClient. + //$$ if (msg instanceof ReadyS2CPacket) { + //$$ super.channelRead(ctx, msg); + //$$ return; + //$$ } + //#endif + if (currentRawPacket != null) { save(currentRawPacket); currentRawPacket = null; @@ -489,5 +540,21 @@ public class PacketListener extends ChannelInboundHandlerAdapter { super.channelRead(ctx, msg); } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + //#if MC>=12006 + //$$ if (msg instanceof NetworkStateTransitions.DecoderTransitioner) { + //$$ // We need our DecodedPacketListener to stay right behind the decoder, however MC will on network state + //$$ // transitions insert the bundler in the middle, so we need to re-position our handler in that case. + //$$ msg = ((NetworkStateTransitions.DecoderTransitioner) msg).andThen(context -> { + //$$ context.pipeline().remove(this); + //$$ context.pipeline().addAfter(DECODER_KEY, DECODED_RECORDER_KEY, new DecodedPacketListener()); + //$$ }); + //$$ } + //#endif + + super.write(ctx, msg, promise); + } } } diff --git a/src/main/java/com/replaymod/render/blend/Util.java b/src/main/java/com/replaymod/render/blend/Util.java index 78138995..64f33b27 100644 --- a/src/main/java/com/replaymod/render/blend/Util.java +++ b/src/main/java/com/replaymod/render/blend/Util.java @@ -183,6 +183,9 @@ public class Util { } public static String getTileEntityId(BlockEntity tileEntity) { + //#if MC>=12006 + //$$ return net.minecraft.block.entity.BlockEntityType.getId(tileEntity.getType()).toString(); + //#else //#if MC>=11800 //$$ NbtCompound nbt = tileEntity.createNbt(); //#else @@ -194,6 +197,7 @@ public class Util { //#endif //#endif return nbt.getString("id"); + //#endif } public interface IOCallable { diff --git a/src/main/java/com/replaymod/render/gui/GuiVideoRenderer.java b/src/main/java/com/replaymod/render/gui/GuiVideoRenderer.java index 448cf5d0..72d5a9d3 100644 --- a/src/main/java/com/replaymod/render/gui/GuiVideoRenderer.java +++ b/src/main/java/com/replaymod/render/gui/GuiVideoRenderer.java @@ -112,7 +112,13 @@ public class GuiVideoRenderer extends GuiScreen implements Tickable { size(contentPanel, width - 10, height - 10); } }); + // FIXME default background doesn't work during rendering because the blur effect relies on the framebuffer + //#if MC>=12006 + //$$ setBackground(Background.NONE); + //$$ setBackgroundColor(new de.johni0702.minecraft.gui.utils.lwjgl.Color(32, 32, 32)); + //#else setBackground(Background.DIRT); + //#endif } public GuiVideoRenderer(VideoRenderer renderer) { diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_ChromaKeyColorSky.java b/src/main/java/com/replaymod/render/mixin/Mixin_ChromaKeyColorSky.java index 28872496..a98c4ff4 100644 --- a/src/main/java/com/replaymod/render/mixin/Mixin_ChromaKeyColorSky.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_ChromaKeyColorSky.java @@ -22,7 +22,9 @@ public abstract class Mixin_ChromaKeyColorSky { //#if MC>=11800 //$$ @Inject( - //#if MC>=11802 + //#if MC>=12005 + //$$ method = "renderSky(Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;FLnet/minecraft/client/render/Camera;ZLjava/lang/Runnable;)V", + //#elseif MC>=11802 //$$ method = "renderSky(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/util/math/Matrix4f;FLnet/minecraft/client/render/Camera;ZLjava/lang/Runnable;)V", //#else //$$ method = "renderSky(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/util/math/Matrix4f;FLjava/lang/Runnable;)V", diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java b/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java index b9726a4c..ae6feff1 100644 --- a/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java @@ -11,7 +11,11 @@ import org.spongepowered.asm.mixin.injection.ModifyArg; public abstract class Mixin_Omnidirectional_Camera implements EntityRendererHandler.IEntityRenderer { private static final String METHOD = "getBasicProjectionMatrix"; //#if MC>=11903 + //#if MC>=12005 + //$$ private static final String TARGET = "Lorg/joml/Matrix4f;perspective(FFFF)Lorg/joml/Matrix4f;"; + //#else //$$ private static final String TARGET = "Lorg/joml/Matrix4f;setPerspective(FFFF)Lorg/joml/Matrix4f;"; + //#endif //$$ private static final boolean TARGET_REMAP = false; //$$ private static final float OMNIDIRECTIONAL_FOV = (float) Math.PI / 2; //#else diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Rotation.java b/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Rotation.java index e7d567c7..f318342f 100644 --- a/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Rotation.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Rotation.java @@ -7,6 +7,11 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//#if MC>=12005 +//$$ import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +//$$ import org.joml.Matrix4f; +//#endif + //#if MC>=11500 import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.Vector3f; @@ -30,6 +35,10 @@ public abstract class Mixin_Omnidirectional_Rotation { return ((EntityRendererHandler.IEntityRenderer) getMinecraft().gameRenderer).replayModRender_getHandler(); } + //#if MC>=12005 + //$$ @ModifyExpressionValue(method = "renderWorld", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4f;rotationXYZ(FFF)Lorg/joml/Matrix4f;")) + //$$ private Matrix4f replayModRender_setupCubicFrameRotation(Matrix4f matrix) { + //#else //#if MC>=11500 @Inject(method = "renderWorld", at = @At("HEAD")) //#else @@ -47,6 +56,7 @@ public abstract class Mixin_Omnidirectional_Rotation { //#endif CallbackInfo ci ) { + //#endif if (getHandler() != null && getHandler().data instanceof CubicOpenGlFrameCapturer.Data) { CubicOpenGlFrameCapturer.Data data = (CubicOpenGlFrameCapturer.Data) getHandler().data; float angle = 0; @@ -78,7 +88,9 @@ public abstract class Mixin_Omnidirectional_Rotation { x = 1; break; } - //#if MC>=11500 + //#if MC>=12005 + //$$ matrix.rotateLocal(angle * (float) Math.PI / 180f, x, y, 0); + //#elseif MC>=11500 matrixStack.multiply(new Vector3f(x, y, 0).getDegreesQuaternion(angle)); //#else //$$ GL11.glRotatef(angle, x, y, 0); @@ -96,5 +108,8 @@ public abstract class Mixin_Omnidirectional_Rotation { //#endif //$$ } //#endif + //#if MC>=12005 + //$$ return matrix; + //#endif } } diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java b/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java index 885608e3..2b744a8e 100644 --- a/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java @@ -11,6 +11,11 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +//#if MC>=12005 +//$$ import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +//$$ import org.joml.Matrix4f; +//#endif + @Mixin(GameRenderer.class) public abstract class Mixin_Stereoscopic_Camera implements EntityRendererHandler.IEntityRenderer { @Inject(method = "getBasicProjectionMatrix", at = @At("RETURN"), cancellable = true) @@ -29,14 +34,30 @@ public abstract class Mixin_Stereoscopic_Camera implements EntityRendererHandler } } + //#if MC>=12005 + //$$ @ModifyExpressionValue(method = "renderWorld", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4f;rotationXYZ(FFF)Lorg/joml/Matrix4f;")) + //$$ private Matrix4f replayModRender_setupStereoscopicProjection(Matrix4f matrix) { + //#else @Inject(method = "renderWorld", at = @At("HEAD")) private void replayModRender_setupStereoscopicProjection(float partialTicks, long frameStartNano, MatrixStack matrixStack, CallbackInfo ci) { + //#endif if (replayModRender_getHandler() != null) { if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE) { - matrixStack.translate(0.1, 0, 0); + //#if MC>=12005 + //$$ matrix.translateLocal(0.1f, 0, 0); + //#else + matrixStack.translate(0.1f, 0, 0); + //#endif } else if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.RIGHT_EYE) { - matrixStack.translate(-0.1, 0, 0); + //#if MC>=12005 + //$$ matrix.translateLocal(-0.1f, 0, 0); + //#else + matrixStack.translate(-0.1f, 0, 0); + //#endif } } + //#if MC>=12005 + //$$ return matrix; + //#endif } } diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index 09743225..5d508dc6 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -512,9 +512,14 @@ public class VideoRenderer implements RenderInfo { //$$ , VertexSorter.BY_Z //#endif //$$ ); + //#if MC>=12006 + //$$ org.joml.Matrix4fStack matrixStack = RenderSystem.getModelViewStack(); + //$$ matrixStack.translation(0, 0, -2000); + //#else //$$ MatrixStack matrixStack = RenderSystem.getModelViewStack(); //$$ matrixStack.loadIdentity(); //$$ matrixStack.translate(0, 0, -2000); + //#endif //$$ RenderSystem.applyModelViewMatrix(); //$$ DiffuseLighting.enableGuiDepthLighting(); //#else @@ -558,13 +563,17 @@ public class VideoRenderer implements RenderInfo { int mouseX = (int) mc.mouse.getX() * window.getScaledWidth() / Math.max(window.getWidth(), 1); int mouseY = (int) mc.mouse.getY() * window.getScaledHeight() / Math.max(window.getHeight(), 1); + //#if MC>=12000 + //$$ DrawContext drawContext = new DrawContext(mc, mc.getBufferBuilders().getEntityVertexConsumers()); + //#endif + if (mc.getOverlay() != null) { Screen orgScreen = mc.currentScreen; try { mc.currentScreen = gui.toMinecraft(); mc.getOverlay().render( //#if MC>=12000 - //$$ new DrawContext(mc, mc.getBufferBuilders().getEntityVertexConsumers()), + //$$ drawContext, //#elseif MC>=11600 new MatrixStack(), //#endif @@ -582,6 +591,9 @@ public class VideoRenderer implements RenderInfo { //#endif mouseX, mouseY, 0); } + //#if MC>=12000 + //$$ drawContext.draw(); + //#endif //#else //$$ int mouseX = Mouse.getX() * window.getScaledWidth() / mc.displayWidth; //$$ int mouseY = window.getScaledHeight() - Mouse.getY() * window.getScaledHeight() / mc.displayHeight - 1; diff --git a/src/main/java/com/replaymod/replay/FullReplaySender.java b/src/main/java/com/replaymod/replay/FullReplaySender.java index 2ee44132..ca89ee9d 100644 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/FullReplaySender.java @@ -675,6 +675,9 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re //$$ packet.showDeathScreen(), //$$ packet.doLimitedCrafting(), //$$ withSpectatorMode(packet.commonPlayerSpawnInfo()) + //#if MC>=12006 + //$$ , packet.enforcesSecureChat() + //#endif //#else //#if MC>=11800 //$$ packet.hardcore(), diff --git a/src/main/java/com/replaymod/replay/NoGuiScreenshot.java b/src/main/java/com/replaymod/replay/NoGuiScreenshot.java index 69a995b6..04a659da 100644 --- a/src/main/java/com/replaymod/replay/NoGuiScreenshot.java +++ b/src/main/java/com/replaymod/replay/NoGuiScreenshot.java @@ -74,7 +74,9 @@ public class NoGuiScreenshot { //#endif float tickDelta = mc.getTickDelta(); - //#if MC>=11500 + //#if MC>=12006 + //$$ mc.gameRenderer.renderWorld(tickDelta, System.nanoTime()); + //#elseif MC>=11500 mc.gameRenderer.renderWorld(tickDelta, System.nanoTime(), new MatrixStack()); //#else //#if MC>=11400 diff --git a/src/main/java/com/replaymod/replay/ReplayHandler.java b/src/main/java/com/replaymod/replay/ReplayHandler.java index dcd259bd..bf638b00 100644 --- a/src/main/java/com/replaymod/replay/ReplayHandler.java +++ b/src/main/java/com/replaymod/replay/ReplayHandler.java @@ -46,6 +46,11 @@ import net.minecraft.network.ClientConnection; import java.io.IOException; import java.util.*; +//#if MC>=12006 +//$$ import net.minecraft.network.handler.NetworkStateTransitions; +//$$ import net.minecraft.network.state.LoginStates; +//#endif + //#if MC>=12003 //$$ import net.minecraft.client.resource.server.ServerResourcePackManager; //#endif @@ -325,6 +330,10 @@ public class ReplayHandler { quickReplaySender.setChannel(channel); fullReplaySender.setChannel(channel); + //#if MC>=12006 + //$$ channel.pipeline().addLast("inbound_config", new NetworkStateTransitions.InboundConfigurer()); + //$$ channel.pipeline().addLast("outbound_config", new NetworkStateTransitions.OutboundConfigurer()); + //#else //#if MC>=12002 //$$ channel.pipeline().addLast("decoder", new DecoderHandler(ClientConnection.CLIENTBOUND_PROTOCOL_KEY)); //$$ channel.pipeline().addLast("encoder", new PacketEncoder(ClientConnection.SERVERBOUND_PROTOCOL_KEY)); @@ -337,12 +346,19 @@ public class ReplayHandler { //#elseif MC>=11904 //$$ channel.pipeline().addLast("bundler", new PacketBundler(NetworkSide.CLIENTBOUND)); //#endif + //#endif channel.pipeline().addLast(PACKET_HANDLER_NAME, quickMode ? quickReplaySender : fullReplaySender); channel.pipeline().addLast("packet_handler", networkManager); channel.pipeline().fireChannelActive(); // MC usually transitions from handshake to login via the packets it sends. // We don't send any packets (there is no server to receive them), so we need to switch manually. + //#if MC>=12006 + //$$ networkManager.transitionInbound(LoginStates.S2C, new ClientLoginNetworkHandler( + //$$ networkManager, mc, null, null, false, null, it -> {}, null + //$$ )); + //$$ networkManager.transitionOutbound(LoginStates.C2S); + //#else //#if MC>=12002 //$$ channel.attr(ClientConnection.CLIENTBOUND_PROTOCOL_KEY).set(NetworkState.LOGIN.getHandler(NetworkSide.CLIENTBOUND)); //$$ channel.attr(ClientConnection.SERVERBOUND_PROTOCOL_KEY).set(NetworkState.LOGIN.getHandler(NetworkSide.SERVERBOUND)); @@ -363,6 +379,7 @@ public class ReplayHandler { , it -> {} //#endif )); + //#endif //#if MC>=11400 ((MinecraftAccessor) mc).setConnection(networkManager); @@ -657,7 +674,28 @@ public class ReplayHandler { long diff = targetTime - (replaySender.isHurrying() ? replaySender.getDesiredTimestamp() : replaySender.currentTimeStamp()); if (diff != 0) { if (diff > 0 && diff < 5000) { // Small difference and no time travel - replaySender.jumpToTime(targetTime); + if (replaySender.paused()) { + replaySender.setSyncModeAndWait(); + do { + replaySender.sendPacketsTill(targetTime); + targetTime += 500; + } while (mc.player == null || mc.currentScreen instanceof DownloadingTerrainScreen); + replaySender.setAsyncMode(true); + + for (int i = 0; i < Math.min(diff / 50, 3); i++) { + //#if MC>=10800 && MC<11400 + //$$ try { + //$$ mc.runTick(); + //$$ } catch (IOException e) { + //$$ e.printStackTrace(); // This should never be thrown but whatever + //$$ } + //#else + mc.tick(); + //#endif + } + } else { + replaySender.jumpToTime(targetTime); + } } else { // We either have to restart the replay or send a significant amount of packets // Render our please-wait-screen GuiScreen guiScreen = new GuiScreen(); @@ -696,9 +734,14 @@ public class ReplayHandler { //$$ , VertexSorter.BY_Z //#endif //$$ ); + //#if MC>=12006 + //$$ org.joml.Matrix4fStack matrixStack = RenderSystem.getModelViewStack(); + //$$ matrixStack.translation(0, 0, -2000); + //#else //$$ MatrixStack matrixStack = RenderSystem.getModelViewStack(); //$$ matrixStack.loadIdentity(); //$$ matrixStack.translate(0, 0, -2000); + //#endif //$$ RenderSystem.applyModelViewMatrix(); //$$ DiffuseLighting.enableGuiDepthLighting(); //#else @@ -719,7 +762,9 @@ public class ReplayHandler { guiScreen.toMinecraft().init(mc, window.getScaledWidth(), window.getScaledHeight()); //#if MC>=12000 - //$$ guiScreen.toMinecraft().render(new DrawContext(mc, mc.getBufferBuilders().getEntityVertexConsumers()), 0, 0, 0); + //$$ DrawContext drawContext = new DrawContext(mc, mc.getBufferBuilders().getEntityVertexConsumers()); + //$$ guiScreen.toMinecraft().render(drawContext, 0, 0, 0); + //$$ drawContext.draw(); //#elseif MC>=11600 guiScreen.toMinecraft().render(new MatrixStack(), 0, 0, 0); //#else diff --git a/src/main/java/com/replaymod/replay/mixin/MixinCamera.java b/src/main/java/com/replaymod/replay/mixin/MixinCamera.java index 7c1166d6..501b15ab 100644 --- a/src/main/java/com/replaymod/replay/mixin/MixinCamera.java +++ b/src/main/java/com/replaymod/replay/mixin/MixinCamera.java @@ -13,9 +13,18 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//#if MC>=12005 +//$$ import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +//$$ import org.joml.Matrix4f; +//#endif + @Mixin(GameRenderer.class) public class MixinCamera { @Shadow @Final private MinecraftClient client; + //#if MC>=12005 + //$$ @ModifyExpressionValue(method = "renderWorld", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4f;rotationXYZ(FFF)Lorg/joml/Matrix4f;")) + //$$ private Matrix4f applyRoll(Matrix4f matrix) { + //#else @Inject( method = "renderWorld", at = @At( @@ -24,9 +33,17 @@ public class MixinCamera { ) ) private void applyRoll(float float_1, long long_1, MatrixStack matrixStack, CallbackInfo ci) { + //#endif Entity entity = this.client.getCameraEntity() == null ? this.client.player : this.client.getCameraEntity(); if (entity instanceof CameraEntity) { + //#if MC>=12005 + //$$ matrix.rotateLocal(((CameraEntity) entity).roll * (float) Math.PI / 180f, 0f, 0f, 1f); + //#else matrixStack.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(((CameraEntity) entity).roll)); + //#endif } + //#if MC>=12005 + //$$ return matrix; + //#endif } } diff --git a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java index 50782934..d8eb78e6 100644 --- a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java +++ b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java @@ -108,7 +108,11 @@ public class PathPreviewRenderer extends EventRegistrations { //#endif //#if MC>=11700 + //#if MC>=12006 + //$$ RenderSystem.getModelViewStack().mul(matrixStack.peek().getPositionMatrix()); + //#else //$$ RenderSystem.getModelViewStack().method_34425(matrixStack.peek().getModel()); + //#endif //$$ RenderSystem.applyModelViewMatrix(); //#elseif MC>=11500 RenderSystem.multMatrix(matrixStack.peek().getModel()); diff --git a/src/main/resources/mixins.recording.replaymod.json b/src/main/resources/mixins.recording.replaymod.json index df7f09ea..db885b0f 100644 --- a/src/main/resources/mixins.recording.replaymod.json +++ b/src/main/resources/mixins.recording.replaymod.json @@ -6,6 +6,9 @@ "client": [ "AddServerScreenAccessor", "ClientLoginNetworkHandlerAccessor", + //#if MC>=12006 + //$$ "DecoderHandlerAccessor", + //#endif "EntityLivingBaseAccessor", "IntegratedServerAccessor", "NetworkManagerAccessor", @@ -31,6 +34,9 @@ //$$ "MixinGuiScreen", //$$ "MixinS26PacketMapChunkBulk", //#endif + //#if MC>=12006 + //$$ "MixinNetHandlerConfigClient", + //#endif "MixinNetHandlerLoginClient", "MixinNetHandlerPlayClient", //#if MC<11400 diff --git a/versions/1.20.2/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java b/versions/1.20.2/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java index 4843023e..50b4c372 100644 --- a/versions/1.20.2/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java +++ b/versions/1.20.2/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java @@ -1,5 +1,6 @@ package com.replaymod.render.mixin; +import com.llamalad7.mixinextras.sugar.Local; import com.replaymod.render.hooks.ForceChunkLoadingHook; import com.replaymod.render.hooks.IForceChunkLoading; import com.replaymod.render.utils.FlawlessFrames; @@ -50,7 +51,7 @@ public abstract class Mixin_ForceChunkLoading implements IForceChunkLoading { @Shadow protected abstract void applyFrustum(Frustum par1); @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;setupTerrain(Lnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/Frustum;ZZ)V")) - private void forceAllChunks(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) { + private void forceAllChunks(CallbackInfo ci, @Local(argsOnly = true) Camera camera) { if (replayModRender_hook == null) { return; } diff --git a/versions/1.20.6/.gitkeep b/versions/1.20.6/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/versions/1.20.6/src/main/java/com/replaymod/recording/mixin/DecoderHandlerAccessor.java b/versions/1.20.6/src/main/java/com/replaymod/recording/mixin/DecoderHandlerAccessor.java new file mode 100644 index 00000000..5fd091a4 --- /dev/null +++ b/versions/1.20.6/src/main/java/com/replaymod/recording/mixin/DecoderHandlerAccessor.java @@ -0,0 +1,16 @@ +package com.replaymod.recording.mixin; + +import net.minecraft.network.NetworkState; +import net.minecraft.network.handler.DecoderHandler; +import net.minecraft.network.listener.PacketListener; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import javax.annotation.Nonnull; + +@Mixin(DecoderHandler.class) +public interface DecoderHandlerAccessor { + @Accessor + @Nonnull + NetworkState getState(); +} diff --git a/versions/1.20.6/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerConfigClient.java b/versions/1.20.6/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerConfigClient.java new file mode 100644 index 00000000..58edc597 --- /dev/null +++ b/versions/1.20.6/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerConfigClient.java @@ -0,0 +1,62 @@ +package com.replaymod.recording.mixin; + +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.serialization.Codec; +import com.replaymod.core.versions.MCVer; +import com.replaymod.recording.ReplayModRecording; +import com.replaymod.recording.packet.PacketListener; +import com.replaymod.replaystudio.lib.viaversion.api.protocol.packet.State; +import com.replaymod.replaystudio.protocol.Packet; +import com.replaymod.replaystudio.protocol.PacketType; +import com.replaymod.replaystudio.protocol.PacketTypeRegistry; +import com.replaymod.replaystudio.protocol.packets.PacketEnabledPacksData; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import net.minecraft.client.network.ClientConfigurationNetworkHandler; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.registry.DynamicRegistryManager; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.world.dimension.DimensionType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +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.Map; + +@Mixin(ClientConfigurationNetworkHandler.class) +public abstract class MixinNetHandlerConfigClient { + @Inject(method = "onReady", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;transitionInbound(Lnet/minecraft/network/NetworkState;Lnet/minecraft/network/listener/PacketListener;)V")) + public void recordEnabledPackData(CallbackInfo ci, @Local DynamicRegistryManager.Immutable registryManager) { + PacketListener packetListener = ReplayModRecording.instance.getConnectionEventHandler().getPacketListener(); + if (packetListener == null) return; + + ByteBuf byteBuf = Unpooled.buffer(); + PacketByteBuf buf = new PacketByteBuf(byteBuf); + buf.writeString(PacketEnabledPacksData.ID); + buf.writeVarInt(1); + write(buf, registryManager.get(RegistryKeys.DIMENSION_TYPE), DimensionType.CODEC); + + byte[] bytes = new byte[byteBuf.readableBytes()]; + byteBuf.readBytes(bytes); + byteBuf.release(); + + PacketTypeRegistry registry = MCVer.getPacketTypeRegistry(State.CONFIGURATION); + packetListener.save(new Packet(registry, PacketType.ConfigCustomPayload, com.github.steveice10.netty.buffer.Unpooled.wrappedBuffer(bytes))); + packetListener.save(new Packet(registry, PacketType.ConfigFinish)); + } + + @Unique + private void write(PacketByteBuf buf, Registry registry, Codec codec) { + buf.writeString(registry.getKey().getValue().toString()); + buf.writeVarInt(registry.size()); + for (Map.Entry, T> entry : registry.getEntrySet()) { + buf.writeString(entry.getKey().getValue().toString()); + buf.writeNbt(codec.encodeStart(NbtOps.INSTANCE, entry.getValue()).getOrThrow()); + } + } +} From 76a68b7867fb42b4331e7becf305e6129cd2558d Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 18 Jun 2024 14:52:34 +0200 Subject: [PATCH 12/28] Prevent pausing in the middle of a bundle packet Because certain actions (e.g. switching to Quick Mode) will fail in this state. --- .../replaymod/replay/FullReplaySender.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/replaymod/replay/FullReplaySender.java b/src/main/java/com/replaymod/replay/FullReplaySender.java index ca89ee9d..4ed9f87e 100644 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/FullReplaySender.java @@ -11,6 +11,7 @@ import com.replaymod.core.utils.Restrictions; import com.replaymod.replay.camera.CameraEntity; import com.replaymod.replaystudio.io.ReplayInputStream; import com.replaymod.replaystudio.lib.viaversion.api.protocol.packet.State; +import com.replaymod.replaystudio.protocol.PacketType; import com.replaymod.replaystudio.protocol.PacketTypeRegistry; import com.replaymod.replaystudio.replay.ReplayFile; import de.johni0702.minecraft.gui.utils.EventRegistrations; @@ -267,6 +268,11 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re */ protected boolean hasWorldLoaded; + /** + * Whether we are currently in the middle of a bundle packet. + */ + protected boolean inBundle; + /** * The minecraft instance. */ @@ -1025,7 +1031,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re while (true) { try { // When playback is paused and the world has loaded (we don't want any dirt-screens) we sleep - while (paused() && hasWorldLoaded) { + while (paused() && hasWorldLoaded && !inBundle) { // Unless we are going to terminate, restart or jump if (terminate || startFromBeginning || desiredTimeStamp != -1) { break; @@ -1033,7 +1039,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re Thread.sleep(10); } - if (terminate) { + if (terminate && !inBundle) { break REPLAY_LOOP; } @@ -1053,7 +1059,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re // If we aren't jumping and the world has already been loaded (no dirt-screens) then wait // the required amount to get proper packet timing - if (!isHurrying() && hasWorldLoaded) { + if (!isHurrying() && hasWorldLoaded && !inBundle) { // Timestamp of when the next packet should be sent long expectedTime = realTimeStart + (long) (nextTimeStamp / replaySpeed); long now = System.currentTimeMillis(); @@ -1064,6 +1070,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re } // Process packet + if (nextPacket.type == PacketType.Bundle) inBundle = !inBundle; channel.pipeline().fireChannelRead(Unpooled.wrappedBuffer(nextPacket.bytes)); nextPacket = null; @@ -1111,6 +1118,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re // Restart the replay. hasWorldLoaded = false; + inBundle = false; lastTimeStamp = 0; registry = getPacketTypeRegistry(State.LOGIN); startFromBeginning = false; @@ -1243,6 +1251,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re } if (timestamp < lastTimeStamp) { // Restart the replay if we need to go backwards in time hasWorldLoaded = false; + inBundle = false; lastTimeStamp = 0; if (replayIn != null) { replayIn.close(); @@ -1271,13 +1280,14 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re } int nextTimeStamp = pd.timestamp; - if (nextTimeStamp > timestamp) { + if (nextTimeStamp > timestamp && !inBundle) { // We are done sending all packets nextPacket = pd; break; } // Process packet + if (pd.type == PacketType.Bundle) inBundle = !inBundle; channel.pipeline().fireChannelRead(Unpooled.wrappedBuffer(pd.bytes)); // MC as of 1.20.2 relies on autoRead, so it can update the connection state on the main @@ -1497,6 +1507,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re private final int timestamp; private final byte[] bytes; + private final PacketType type; PacketData(ReplayInputStream in) throws IOException { if (ReplayMod.isMinimalMode()) { @@ -1508,6 +1519,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re } bytes = new byte[length]; IOUtils.readFully(in, bytes); + type = PacketType.UnknownLogin; } else { com.replaymod.replaystudio.PacketData data = in.readPacket(); if (data == null) { @@ -1515,6 +1527,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re } timestamp = (int) data.getTime(); com.replaymod.replaystudio.protocol.Packet packet = data.getPacket(); + type = packet.getType(); // We need to re-encode ReplayStudio packets, so we can later decode them as NMS packets // The main reason we aren't reading them as NMS packets is that we want ReplayStudio to be able // to apply ViaVersion (and potentially other magic) to it. From 454e990849b30d668f7e918cd59e2ddd41643e53 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 23 Jun 2024 14:02:43 +0200 Subject: [PATCH 13/28] Replace InputReplayTimer with Mixin --- .../replaymod/replay/InputReplayTimer.java | 39 ++----------------- .../com/replaymod/replay/ReplayModReplay.java | 4 -- .../mixin/Mixin_HandleInputsInReplay.java | 16 ++++++++ .../resources/mixins.replay.replaymod.json | 1 + 4 files changed, 21 insertions(+), 39 deletions(-) create mode 100644 src/main/java/com/replaymod/replay/mixin/Mixin_HandleInputsInReplay.java diff --git a/src/main/java/com/replaymod/replay/InputReplayTimer.java b/src/main/java/com/replaymod/replay/InputReplayTimer.java index 5b0b3d15..dd64014f 100644 --- a/src/main/java/com/replaymod/replay/InputReplayTimer.java +++ b/src/main/java/com/replaymod/replay/InputReplayTimer.java @@ -1,13 +1,11 @@ package com.replaymod.replay; import com.replaymod.core.ReplayMod; -import com.replaymod.core.utils.WrappedTimer; import com.replaymod.core.versions.MCVer; import com.replaymod.replay.camera.CameraController; import com.replaymod.replay.camera.CameraEntity; import de.johni0702.minecraft.gui.versions.ScreenExt; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.RenderTickCounter; //#if MC>=11802 //$$ import net.minecraft.client.gui.screen.DownloadingTerrainScreen; @@ -33,36 +31,10 @@ import org.lwjgl.glfw.GLFW; //$$ import net.minecraft.client.multiplayer.WorldClient; //#endif -public class InputReplayTimer extends WrappedTimer { - private final ReplayModReplay mod; - private final MinecraftClient mc; - - public InputReplayTimer(RenderTickCounter wrapped, ReplayModReplay mod) { - super(wrapped); - this.mod = mod; - this.mc = mod.getCore().getMinecraft(); - } - - @Override - public - //#if MC>=11600 - int - //#else - //$$ void - //#endif - beginRenderTick( - //#if MC>=11400 - long sysClock - //#endif - ) { - //#if MC>=11600 - int ticksThisFrame = - //#endif - super.beginRenderTick( - //#if MC>=11400 - sysClock - //#endif - ); +public class InputReplayTimer { + public static void updateInReplay() { + ReplayModReplay mod = ReplayModReplay.instance; + MinecraftClient mc = mod.getCore().getMinecraft(); ReplayMod.instance.runTasks(); @@ -126,9 +98,6 @@ public class InputReplayTimer extends WrappedTimer { //#endif } - //#if MC>=11600 - return ticksThisFrame; - //#endif } public static void handleScroll(int wheel) { diff --git a/src/main/java/com/replaymod/replay/ReplayModReplay.java b/src/main/java/com/replaymod/replay/ReplayModReplay.java index cb225447..11459bd2 100644 --- a/src/main/java/com/replaymod/replay/ReplayModReplay.java +++ b/src/main/java/com/replaymod/replay/ReplayModReplay.java @@ -7,7 +7,6 @@ import com.google.common.util.concurrent.ListenableFuture; import com.replaymod.core.KeyBindingRegistry; import com.replaymod.core.Module; import com.replaymod.core.ReplayMod; -import com.replaymod.core.mixin.MinecraftAccessor; import com.replaymod.core.utils.ModCompat; import com.replaymod.core.versions.MCVer; import com.replaymod.core.versions.MCVer.Keyboard; @@ -152,9 +151,6 @@ public class ReplayModReplay implements Module { } }); - MinecraftAccessor mc = (MinecraftAccessor) core.getMinecraft(); - mc.setTimer(new InputReplayTimer(mc.getTimer(), this)); - new GuiHandler(this).register(); } diff --git a/src/main/java/com/replaymod/replay/mixin/Mixin_HandleInputsInReplay.java b/src/main/java/com/replaymod/replay/mixin/Mixin_HandleInputsInReplay.java new file mode 100644 index 00000000..7e87b2ba --- /dev/null +++ b/src/main/java/com/replaymod/replay/mixin/Mixin_HandleInputsInReplay.java @@ -0,0 +1,16 @@ +package com.replaymod.replay.mixin; + +import com.replaymod.replay.InputReplayTimer; +import net.minecraft.client.MinecraftClient; +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(MinecraftClient.class) +public abstract class Mixin_HandleInputsInReplay { + @Inject(method = "render", at = @At(value = "CONSTANT", args = "stringValue=scheduledExecutables")) + private void updateInReplay(CallbackInfo ci) { + InputReplayTimer.updateInReplay(); + } +} diff --git a/src/main/resources/mixins.replay.replaymod.json b/src/main/resources/mixins.replay.replaymod.json index bdd258a6..a6cc78d7 100644 --- a/src/main/resources/mixins.replay.replaymod.json +++ b/src/main/resources/mixins.replay.replaymod.json @@ -9,6 +9,7 @@ "entity_tracking.Mixin_FixPartialUpdates", "world_border.Mixin_UseReplayTime_ForMovement", "world_border.Mixin_UseReplayTime_ForTexture", + "Mixin_HandleInputsInReplay", "Mixin_FixNPCSkinCaching", //#if MC>=11900 //$$ "Mixin_AllowExpiredPlayerKeys", From 310dc90e1172fbd01000d14844e22f2e6e8c5e2a Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 23 Jun 2024 14:30:59 +0200 Subject: [PATCH 14/28] Remove WrappedTimer --- .../replaymod/core/mixin/TimerAccessor.java | 25 ------- .../java/com/replaymod/core/utils/Utils.java | 2 + .../replaymod/core/utils/WrappedTimer.java | 71 ------------------- .../player/AbstractTimelinePlayer.java | 10 +-- .../replaymod/pathing/player/ReplayTimer.java | 42 +++-------- .../render/rendering/VideoRenderer.java | 4 +- .../replaymod/replay/FullReplaySender.java | 4 +- .../replaymod/replay/QuickReplaySender.java | 7 +- .../com/replaymod/replay/ReplayHandler.java | 4 +- 9 files changed, 27 insertions(+), 142 deletions(-) delete mode 100644 src/main/java/com/replaymod/core/utils/WrappedTimer.java diff --git a/src/main/java/com/replaymod/core/mixin/TimerAccessor.java b/src/main/java/com/replaymod/core/mixin/TimerAccessor.java index 78f7da1a..ee4ef016 100644 --- a/src/main/java/com/replaymod/core/mixin/TimerAccessor.java +++ b/src/main/java/com/replaymod/core/mixin/TimerAccessor.java @@ -7,11 +7,6 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(RenderTickCounter.class) public interface TimerAccessor { - @Accessor("prevTimeMillis") - long getLastSyncSysClock(); - @Accessor("prevTimeMillis") - void setLastSyncSysClock(long value); - //#if MC>=11200 @Accessor("tickTime") float getTickLength(); @@ -23,25 +18,5 @@ public interface TimerAccessor { //$$ float getTimerSpeed(); //$$ @Accessor //$$ void setTimerSpeed(float value); - //$$ @Accessor - //$$ float getTicksPerSecond(); - //$$ @Accessor - //$$ void setTicksPerSecond(float value); - //$$ @Accessor - //$$ double getLastHRTime(); - //$$ @Accessor - //$$ void setLastHRTime(double value); - //$$ @Accessor - //$$ long getLastSyncHRClock(); - //$$ @Accessor - //$$ void setLastSyncHRClock(long value); - //$$ @Accessor - //$$ double getTimeSyncAdjustment(); - //$$ @Accessor - //$$ void setTimeSyncAdjustment(double value); - //$$ @Accessor - //$$ long getCounter(); - //$$ @Accessor - //$$ void setCounter(long value); //#endif } diff --git a/src/main/java/com/replaymod/core/utils/Utils.java b/src/main/java/com/replaymod/core/utils/Utils.java index e9706634..033a6d83 100644 --- a/src/main/java/com/replaymod/core/utils/Utils.java +++ b/src/main/java/com/replaymod/core/utils/Utils.java @@ -71,6 +71,8 @@ import static com.replaymod.core.versions.MCVer.getMinecraft; public class Utils { private static Logger LOGGER = LogManager.getLogger(); + public static final float DEFAULT_MS_PER_TICK = 1000 / 20; + private static InputStream getResourceAsStream(String path) { return Utils.class.getResourceAsStream(path); } diff --git a/src/main/java/com/replaymod/core/utils/WrappedTimer.java b/src/main/java/com/replaymod/core/utils/WrappedTimer.java deleted file mode 100644 index 754db425..00000000 --- a/src/main/java/com/replaymod/core/utils/WrappedTimer.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.replaymod.core.utils; - -import com.replaymod.core.mixin.TimerAccessor; -import net.minecraft.client.render.RenderTickCounter; - -public class WrappedTimer extends RenderTickCounter { - public static final float DEFAULT_MS_PER_TICK = 1000 / 20; - - protected final RenderTickCounter wrapped; - - public WrappedTimer(RenderTickCounter wrapped) { - //#if MC>=12003 - //$$ super(0, 0, f -> f); - //#elseif MC>=11400 - super(0, 0); - //#else - //$$ super(0); - //#endif - this.wrapped = wrapped; - copy(wrapped, this); - } - - @Override - public - //#if MC>=11600 - int - //#else - //$$ void - //#endif - beginRenderTick( - //#if MC>=11400 - long sysClock - //#endif - ) { - copy(this, wrapped); - try { - //#if MC>=11600 - return - //#endif - wrapped.beginRenderTick( - //#if MC>=11400 - sysClock - //#endif - ); - } finally { - copy(wrapped, this); - } - } - - protected void copy(RenderTickCounter from, RenderTickCounter to) { - TimerAccessor fromA = (TimerAccessor) from; - TimerAccessor toA = (TimerAccessor) to; - - //#if MC<11600 - //$$ to.ticksThisFrame = from.ticksThisFrame; - //#endif - to.tickDelta = from.tickDelta; - toA.setLastSyncSysClock(fromA.getLastSyncSysClock()); - to.lastFrameDuration = from.lastFrameDuration; - //#if MC>=11200 - toA.setTickLength(fromA.getTickLength()); - //#else - //$$ toA.setTicksPerSecond(fromA.getTicksPerSecond()); - //$$ toA.setLastHRTime(fromA.getLastHRTime()); - //$$ toA.setTimerSpeed(fromA.getTimerSpeed()); - //$$ toA.setLastSyncHRClock(fromA.getLastSyncHRClock()); - //$$ toA.setCounter(fromA.getCounter()); - //$$ toA.setTimeSyncAdjustment(fromA.getTimeSyncAdjustment()); - //#endif - } -} diff --git a/src/main/java/com/replaymod/pathing/player/AbstractTimelinePlayer.java b/src/main/java/com/replaymod/pathing/player/AbstractTimelinePlayer.java index a495399e..00b54bf3 100644 --- a/src/main/java/com/replaymod/pathing/player/AbstractTimelinePlayer.java +++ b/src/main/java/com/replaymod/pathing/player/AbstractTimelinePlayer.java @@ -8,7 +8,6 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import com.replaymod.core.mixin.MinecraftAccessor; import com.replaymod.core.mixin.TimerAccessor; -import com.replaymod.core.utils.WrappedTimer; import com.replaymod.replay.ReplayHandler; import com.replaymod.replaystudio.pathing.path.Keyframe; import com.replaymod.replaystudio.pathing.path.Path; @@ -20,6 +19,7 @@ import net.minecraft.client.render.RenderTickCounter; import javax.annotation.Nullable; import java.util.Iterator; +import static com.replaymod.core.utils.Utils.DEFAULT_MS_PER_TICK; import static com.replaymod.core.versions.MCVer.*; /** @@ -31,6 +31,7 @@ public abstract class AbstractTimelinePlayer extends EventRegistrations { private Timeline timeline; protected long startOffset; private boolean wasAsyncMode; + private RenderTickCounter orgTimer; private long lastTime; private long lastTimestamp; private ListenableFuture future; @@ -76,13 +77,14 @@ public abstract class AbstractTimelinePlayer extends EventRegistrations { lastTime = 0; MinecraftAccessor mcA = (MinecraftAccessor) mc; - ReplayTimer timer = new ReplayTimer(mcA.getTimer()); + orgTimer = mcA.getTimer(); + ReplayTimer timer = new ReplayTimer(); mcA.setTimer(timer); //noinspection ConstantConditions TimerAccessor timerA = (TimerAccessor) timer; //#if MC>=11200 - timerA.setTickLength(WrappedTimer.DEFAULT_MS_PER_TICK); + timerA.setTickLength(DEFAULT_MS_PER_TICK); timer.tickDelta = timer.ticksThisFrame = 0; //#else //$$ timer.timerSpeed = 1; @@ -103,7 +105,7 @@ public abstract class AbstractTimelinePlayer extends EventRegistrations { public void onTick() { if (future.isDone()) { MinecraftAccessor mcA = (MinecraftAccessor) mc; - mcA.setTimer(((ReplayTimer) mcA.getTimer()).getWrapped()); + mcA.setTimer(orgTimer); replayHandler.getReplaySender().setReplaySpeed(0); if (wasAsyncMode) { replayHandler.getReplaySender().setAsyncMode(true); diff --git a/src/main/java/com/replaymod/pathing/player/ReplayTimer.java b/src/main/java/com/replaymod/pathing/player/ReplayTimer.java index d970cb05..e187f740 100644 --- a/src/main/java/com/replaymod/pathing/player/ReplayTimer.java +++ b/src/main/java/com/replaymod/pathing/player/ReplayTimer.java @@ -1,27 +1,24 @@ package com.replaymod.pathing.player; -import com.replaymod.core.utils.WrappedTimer; import de.johni0702.minecraft.gui.utils.Event; import net.minecraft.client.render.RenderTickCounter; /** - * Wrapper around the current timer that prevents the timer from advancing by itself. + * A timer that does not advance by itself. */ -public class ReplayTimer extends WrappedTimer { - //#if MC>=12003 - //$$ private final RenderTickCounter state = new RenderTickCounter(0, 0, f -> f); - //#elseif MC>=11400 - private final RenderTickCounter state = new RenderTickCounter(0, 0); - //#else - //$$ private final Timer state = new Timer(0); - //#endif - +public class ReplayTimer extends RenderTickCounter { //#if MC>=11600 public int ticksThisFrame; //#endif - public ReplayTimer(RenderTickCounter wrapped) { - super(wrapped); + public ReplayTimer() { + //#if MC>=12003 + //$$ super(0, 0, f -> f); + //#elseif MC>=11400 + super(0, 0); + //#else + //$$ super(0); + //#endif } @Override @@ -41,29 +38,12 @@ public class ReplayTimer extends WrappedTimer { long sysClock //#endif ) { - copy(this, state); // Save our current state - try { - //#if MC>=11600 - ticksThisFrame = - //#endif - wrapped.beginRenderTick( - //#if MC>=11400 - sysClock - //#endif - ); // Update current state - } finally { - copy(state, this); // Restore our old state - UpdatedCallback.EVENT.invoker().onUpdate(); - } + UpdatedCallback.EVENT.invoker().onUpdate(); //#if MC>=11600 return ticksThisFrame; //#endif } - public RenderTickCounter getWrapped() { - return wrapped; - } - public interface UpdatedCallback { Event EVENT = Event.create((listeners) -> () -> { diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index 5d508dc6..017b2013 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -3,7 +3,6 @@ package com.replaymod.render.rendering; import com.mojang.blaze3d.platform.GlStateManager; import com.replaymod.core.mixin.MinecraftAccessor; import com.replaymod.core.mixin.TimerAccessor; -import com.replaymod.core.utils.WrappedTimer; import com.replaymod.core.versions.MCVer; import com.replaymod.pathing.player.AbstractTimelinePlayer; import com.replaymod.pathing.properties.TimestampProperty; @@ -85,6 +84,7 @@ import java.util.concurrent.FutureTask; import java.util.stream.Stream; import static com.google.common.collect.Iterables.getLast; +import static com.replaymod.core.utils.Utils.DEFAULT_MS_PER_TICK; import static com.replaymod.core.versions.MCVer.*; import static com.replaymod.render.ReplayModRender.LOGGER; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; @@ -207,7 +207,7 @@ public class VideoRenderer implements RenderInfo { int replayTime = videoStart - 1000; //#if MC>=11200 timer.tickDelta = 0; - ((TimerAccessor) timer).setTickLength(WrappedTimer.DEFAULT_MS_PER_TICK); + ((TimerAccessor) timer).setTickLength(DEFAULT_MS_PER_TICK); //#else //$$ timer.elapsedPartialTicks = timer.renderPartialTicks = 0; //$$ timer.timerSpeed = 1; diff --git a/src/main/java/com/replaymod/replay/FullReplaySender.java b/src/main/java/com/replaymod/replay/FullReplaySender.java index 4ed9f87e..20db8110 100644 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/FullReplaySender.java @@ -117,7 +117,6 @@ import net.minecraft.util.Identifier; //#endif //#if MC>=11200 -import com.replaymod.core.utils.WrappedTimer; import net.minecraft.network.packet.s2c.play.AdvancementUpdateS2CPacket; import net.minecraft.network.packet.s2c.play.SelectAdvancementTabS2CPacket; import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket; @@ -152,6 +151,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; +import static com.replaymod.core.utils.Utils.DEFAULT_MS_PER_TICK; import static com.replaymod.core.versions.MCVer.*; import static com.replaymod.replaystudio.util.Utils.readInt; @@ -985,7 +985,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re } TimerAccessor timer = (TimerAccessor) ((MinecraftAccessor) mc).getTimer(); //#if MC>=11200 - timer.setTickLength(WrappedTimer.DEFAULT_MS_PER_TICK / (float) d); + timer.setTickLength(DEFAULT_MS_PER_TICK / (float) d); //#else //$$ timer.setTimerSpeed((float) d); //#endif diff --git a/src/main/java/com/replaymod/replay/QuickReplaySender.java b/src/main/java/com/replaymod/replay/QuickReplaySender.java index 5c91ee66..f27a67cb 100644 --- a/src/main/java/com/replaymod/replay/QuickReplaySender.java +++ b/src/main/java/com/replaymod/replay/QuickReplaySender.java @@ -24,10 +24,7 @@ import javax.annotation.Nullable; import java.io.IOException; import java.util.function.Consumer; -//#if MC>=11200 -import com.replaymod.core.utils.WrappedTimer; -//#endif - +import static com.replaymod.core.utils.Utils.DEFAULT_MS_PER_TICK; import static com.replaymod.core.versions.MCVer.getMinecraft; import static com.replaymod.core.versions.MCVer.getPacketTypeRegistry; import static com.replaymod.replay.ReplayModReplay.LOGGER; @@ -164,7 +161,7 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe } TimerAccessor timer = (TimerAccessor) ((MinecraftAccessor) mc).getTimer(); //#if MC>=11200 - timer.setTickLength(WrappedTimer.DEFAULT_MS_PER_TICK / (float) factor); + timer.setTickLength(DEFAULT_MS_PER_TICK / (float) factor); //#else //$$ timer.setTimerSpeed((float) factor); //#endif diff --git a/src/main/java/com/replaymod/replay/ReplayHandler.java b/src/main/java/com/replaymod/replay/ReplayHandler.java index bf638b00..47a33c52 100644 --- a/src/main/java/com/replaymod/replay/ReplayHandler.java +++ b/src/main/java/com/replaymod/replay/ReplayHandler.java @@ -10,7 +10,6 @@ import com.replaymod.core.mixin.MinecraftAccessor; import com.replaymod.core.mixin.TimerAccessor; import com.replaymod.core.utils.Restrictions; import com.replaymod.core.utils.Utils; -import com.replaymod.core.utils.WrappedTimer; import com.replaymod.replay.camera.CameraEntity; import com.replaymod.replay.camera.SpectatorCameraController; import com.replaymod.replay.events.ReplayClosedCallback; @@ -124,6 +123,7 @@ import net.minecraft.network.NetworkSide; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import static com.replaymod.core.utils.Utils.DEFAULT_MS_PER_TICK; import static com.replaymod.core.versions.MCVer.*; import static com.replaymod.replay.ReplayModReplay.LOGGER; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; @@ -263,7 +263,7 @@ public class ReplayHandler { TimerAccessor timer = (TimerAccessor) ((MinecraftAccessor) mc).getTimer(); //#if MC>=11200 - timer.setTickLength(WrappedTimer.DEFAULT_MS_PER_TICK); + timer.setTickLength(DEFAULT_MS_PER_TICK); //#else //$$ timer.setTimerSpeed(1); //#endif From 1433fccaf109447e8ecf691f3749c28078179b41 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 23 Jun 2024 16:18:38 +0200 Subject: [PATCH 15/28] Update EGT to 0.6.1 --- jGui | 2 +- root.gradle.kts | 1 - settings.gradle.kts | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/jGui b/jGui index 1a9b23d0..7d60bf05 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 1a9b23d0c92223bf3e6859452854066e841e0eb2 +Subproject commit 7d60bf0532fe49f14575f725513e800b58613d47 diff --git a/root.gradle.kts b/root.gradle.kts index b97e261f..9fba13eb 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -4,7 +4,6 @@ import java.io.ByteArrayOutputStream plugins { id("gg.essential.multi-version.root") id("com.github.hierynomus.license") version "0.15.0" - kotlin("jvm") version "1.9.24" apply false // workaround for EGT crashing without } val latestVersion = file("version.txt").readLines().first() diff --git a/settings.gradle.kts b/settings.gradle.kts index c38a151c..4607dcc2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -11,7 +11,7 @@ pluginManagement { maven("https://repo.essential.gg/repository/maven-public") } plugins { - id("gg.essential.multi-version.root") version "0.6.0" + id("gg.essential.multi-version.root") version "0.6.1" id("com.github.johnrengelman.shadow") version "8.1.1" } } From a4e0abec7f5d6939574daa654d6f60dbc5cf34ca Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 23 Jun 2024 19:39:11 +0200 Subject: [PATCH 16/28] Update to 1.21 --- build.gradle.kts | 6 ++- jGui | 2 +- root.gradle.kts | 2 + settings.gradle.kts | 4 +- .../replaymod/core/KeyBindingRegistry.java | 3 +- .../java/com/replaymod/core/ReplayMod.java | 6 ++- .../replaymod/core/gui/GuiReplayButton.java | 4 +- .../core/mixin/MinecraftAccessor.java | 8 ++++ .../replaymod/core/mixin/MixinMinecraft.java | 10 +++- .../replaymod/core/mixin/TimerAccessor.java | 4 ++ .../replaymod/core/utils/Restrictions.java | 5 +- .../java/com/replaymod/core/utils/Utils.java | 14 +++++- .../core/versions/LangResourcePack.java | 4 +- .../com/replaymod/core/versions/MCVer.java | 6 ++- .../com/replaymod/core/versions/Patterns.java | 24 +++++++++- .../versions/scheduler/SchedulerImpl.java | 8 ++++ .../player/AbstractTimelinePlayer.java | 4 ++ .../replaymod/pathing/player/ReplayTimer.java | 19 ++++++++ .../handler/RecordingEventHandler.java | 16 ++++++- .../render/blend/BlendMaterials.java | 4 +- .../java/com/replaymod/render/blend/Util.java | 4 +- .../render/capturer/ODSFrameCapturer.java | 6 ++- .../render/gui/GuiVideoRenderer.java | 4 +- .../render/hooks/EntityRendererHandler.java | 4 +- .../mixin/Mixin_Omnidirectional_Rotation.java | 4 ++ .../mixin/Mixin_Stereoscopic_Camera.java | 4 ++ .../render/rendering/VideoRenderer.java | 12 +++-- .../com/replaymod/replay/NoGuiScreenshot.java | 8 ++++ .../replaymod/replay/mixin/MixinCamera.java | 4 ++ .../gui/GuiKeyframeTimeline.java | 10 ++++ .../preview/PathPreviewRenderer.java | 47 ++++++++++++++++++- versions/1.21/.gitkeep | 0 32 files changed, 228 insertions(+), 32 deletions(-) create mode 100644 versions/1.21/.gitkeep diff --git a/build.gradle.kts b/build.gradle.kts index 66d57726..d7bb33d6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,7 +3,7 @@ import gg.essential.gradle.util.* plugins { java - id("com.github.johnrengelman.shadow") apply false + id("io.github.goooler.shadow") apply false id("gg.essential.multi-version") id("gg.essential.defaults.repo") id("gg.essential.defaults.java") @@ -86,6 +86,7 @@ dependencies { 12002 -> "0.91.2+1.20.2" 12004 -> "0.91.2+1.20.4" 12006 -> "0.98.0+1.20.6" + 12100 -> "0.100.3+1.21" else -> throw UnsupportedOperationException() } val fabricApiModules = mutableListOf( @@ -155,7 +156,7 @@ dependencies { implementation(shadow("com.github.ReplayMod.JavaBlend:2.79.0:a0696f8")!!) - implementation(shadow("com.github.ReplayMod:ReplayStudio:6d59510")!!) + implementation(shadow("com.github.ReplayMod:ReplayStudio:5d17653db9")!!) // FIXME this should be pulled in by ReplayStudio, and IntelliJ sees it, but javac for some reason does not implementation("com.github.viaversion:opennbt:0a02214") // 2.0-SNAPSHOT (ViaVersion Edition) @@ -164,6 +165,7 @@ dependencies { if (platform.isFabric) { val modMenuVersion = when { + mcVersion >= 12100 -> "11.0.0-rc.4" mcVersion >= 12006 -> "10.0.0-beta.1" mcVersion >= 12003 -> "9.0.0-pre.1" mcVersion >= 12002 -> "8.0.0" diff --git a/jGui b/jGui index 7d60bf05..d2626659 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 7d60bf0532fe49f14575f725513e800b58613d47 +Subproject commit d2626659b0a7e6904787bf29904e319c0ca245aa diff --git a/root.gradle.kts b/root.gradle.kts index 9fba13eb..3342ee39 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -202,6 +202,7 @@ val doRelease by tasks.registering { defaultTasks("bundleJar") preprocess { + val mc12100 = createNode("1.21", 12100, "yarn") val mc12006 = createNode("1.20.6", 12006, "yarn") val mc12004 = createNode("1.20.4", 12004, "yarn") val mc12002 = createNode("1.20.2", 12002, "yarn") @@ -230,6 +231,7 @@ preprocess { val mc10800 = createNode("1.8", 10800, "srg") val mc10710 = createNode("1.7.10", 10710, "srg") + mc12100.link(mc12006) mc12006.link(mc12004) mc12004.link(mc12002, file("versions/mapping-fabric-1.20.4-1.20.2.txt")) mc12002.link(mc12001) diff --git a/settings.gradle.kts b/settings.gradle.kts index 4607dcc2..dac8a4c8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -12,7 +12,7 @@ pluginManagement { } plugins { id("gg.essential.multi-version.root") version "0.6.1" - id("com.github.johnrengelman.shadow") version "8.1.1" + id("io.github.goooler.shadow") version "8.1.7" } } @@ -39,6 +39,7 @@ val jGuiVersions = listOf( "1.20.2", "1.20.4", "1.20.6", + "1.21", ) val replayModVersions = listOf( // "1.7.10", @@ -68,6 +69,7 @@ val replayModVersions = listOf( "1.20.2", "1.20.4", "1.20.6", + "1.21", ) rootProject.buildFileName = "root.gradle.kts" diff --git a/src/main/java/com/replaymod/core/KeyBindingRegistry.java b/src/main/java/com/replaymod/core/KeyBindingRegistry.java index 40eff2ee..0b671c79 100644 --- a/src/main/java/com/replaymod/core/KeyBindingRegistry.java +++ b/src/main/java/com/replaymod/core/KeyBindingRegistry.java @@ -22,6 +22,7 @@ import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.minecraft.client.util.InputUtil; import net.minecraft.util.Identifier; import static com.replaymod.core.ReplayMod.MOD_ID; +import static de.johni0702.minecraft.gui.versions.MCVer.identifier; //#else //$$ import net.minecraftforge.fml.client.registry.ClientRegistry; //#endif @@ -66,7 +67,7 @@ public class KeyBindingRegistry extends EventRegistrations { if (keyCode == 0) { keyCode = -1; } - Identifier id = new Identifier(MOD_ID, name.substring(LangResourcePack.LEGACY_KEY_PREFIX.length())); + Identifier id = identifier(MOD_ID, name.substring(LangResourcePack.LEGACY_KEY_PREFIX.length())); //#if MC>=11600 String key = String.format("key.%s.%s", id.getNamespace(), id.getPath()); KeyBinding keyBinding = new KeyBinding(key, InputUtil.Type.KEYSYM, keyCode, CATEGORY); diff --git a/src/main/java/com/replaymod/core/ReplayMod.java b/src/main/java/com/replaymod/core/ReplayMod.java index add813c7..ed1535dc 100644 --- a/src/main/java/com/replaymod/core/ReplayMod.java +++ b/src/main/java/com/replaymod/core/ReplayMod.java @@ -36,6 +36,8 @@ import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; +import static de.johni0702.minecraft.gui.versions.MCVer.identifier; + //#if MC>=12006 //$$ import net.minecraft.resource.ResourcePackInfo; //$$ import net.minecraft.resource.ResourcePackSource; @@ -52,9 +54,9 @@ public class ReplayMod implements Module, Scheduler { public static final String MOD_ID = "replaymod"; - public static final Identifier TEXTURE = new Identifier("replaymod", "replay_gui.png"); + public static final Identifier TEXTURE = identifier("replaymod", "replay_gui.png"); public static final int TEXTURE_SIZE = 256; - public static final Identifier LOGO_FAVICON = new Identifier("replaymod", "favicon_logo.png"); + public static final Identifier LOGO_FAVICON = identifier("replaymod", "favicon_logo.png"); private static final MinecraftClient mc = MCVer.getMinecraft(); diff --git a/src/main/java/com/replaymod/core/gui/GuiReplayButton.java b/src/main/java/com/replaymod/core/gui/GuiReplayButton.java index 2ee4d9e4..d14468e6 100644 --- a/src/main/java/com/replaymod/core/gui/GuiReplayButton.java +++ b/src/main/java/com/replaymod/core/gui/GuiReplayButton.java @@ -6,8 +6,10 @@ import de.johni0702.minecraft.gui.element.GuiButton; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; import net.minecraft.util.Identifier; +import static de.johni0702.minecraft.gui.versions.MCVer.identifier; + public class GuiReplayButton extends GuiButton { - public static final Identifier ICON = new Identifier("replaymod", "logo_button.png"); + public static final Identifier ICON = identifier("replaymod", "logo_button.png"); @Override public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) { diff --git a/src/main/java/com/replaymod/core/mixin/MinecraftAccessor.java b/src/main/java/com/replaymod/core/mixin/MinecraftAccessor.java index 5e09f787..14a720bd 100644 --- a/src/main/java/com/replaymod/core/mixin/MinecraftAccessor.java +++ b/src/main/java/com/replaymod/core/mixin/MinecraftAccessor.java @@ -29,6 +29,13 @@ import java.util.concurrent.CompletableFuture; @Mixin(MinecraftClient.class) public interface MinecraftAccessor { + //#if MC>=12100 + //$$ @Accessor("renderTickCounter") + //$$ RenderTickCounter.Dynamic getTimer(); + //$$ @Accessor("renderTickCounter") + //$$ @Mutable + //$$ void setTimer(RenderTickCounter.Dynamic value); + //#else @Accessor("renderTickCounter") RenderTickCounter getTimer(); @Accessor("renderTickCounter") @@ -36,6 +43,7 @@ public interface MinecraftAccessor { @Mutable //#endif void setTimer(RenderTickCounter value); + //#endif //#if MC>=11400 @Accessor diff --git a/src/main/java/com/replaymod/core/mixin/MixinMinecraft.java b/src/main/java/com/replaymod/core/mixin/MixinMinecraft.java index 754cd090..f9f93277 100644 --- a/src/main/java/com/replaymod/core/mixin/MixinMinecraft.java +++ b/src/main/java/com/replaymod/core/mixin/MixinMinecraft.java @@ -48,16 +48,22 @@ public abstract class MixinMinecraft } //#endif + //#if MC>=12100 + //$$ private static final String GAME_RENDERER_RENDER = "Lnet/minecraft/client/render/GameRenderer;render(Lnet/minecraft/client/render/RenderTickCounter;Z)V"; + //#else + private static final String GAME_RENDERER_RENDER = "Lnet/minecraft/client/render/GameRenderer;render(FJZ)V"; + //#endif + @Inject(method = "render", at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/render/GameRenderer;render(FJZ)V")) + target = GAME_RENDERER_RENDER)) private void preRender(boolean unused, CallbackInfo ci) { PreRenderCallback.EVENT.invoker().preRender(); } @Inject(method = "render", at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/render/GameRenderer;render(FJZ)V", + target = GAME_RENDERER_RENDER, shift = At.Shift.AFTER)) private void postRender(boolean unused, CallbackInfo ci) { PostRenderCallback.EVENT.invoker().postRender(); diff --git a/src/main/java/com/replaymod/core/mixin/TimerAccessor.java b/src/main/java/com/replaymod/core/mixin/TimerAccessor.java index ee4ef016..3f9eed1e 100644 --- a/src/main/java/com/replaymod/core/mixin/TimerAccessor.java +++ b/src/main/java/com/replaymod/core/mixin/TimerAccessor.java @@ -5,7 +5,11 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.gen.Accessor; +//#if MC>=12100 +//$$ @Mixin(RenderTickCounter.Dynamic.class) +//#else @Mixin(RenderTickCounter.class) +//#endif public interface TimerAccessor { //#if MC>=11200 @Accessor("tickTime") diff --git a/src/main/java/com/replaymod/core/utils/Restrictions.java b/src/main/java/com/replaymod/core/utils/Restrictions.java index c1543e83..a85df613 100644 --- a/src/main/java/com/replaymod/core/utils/Restrictions.java +++ b/src/main/java/com/replaymod/core/utils/Restrictions.java @@ -10,6 +10,7 @@ import net.minecraft.network.PacketByteBuf; //#if MC>=10904 import net.minecraft.util.Identifier; +import static de.johni0702.minecraft.gui.versions.MCVer.identifier; //#endif //#if MC<=10710 || MC>=12002 @@ -22,7 +23,7 @@ import net.minecraft.util.Identifier; */ public class Restrictions { //#if MC>=11400 - public static final Identifier PLUGIN_CHANNEL = new Identifier("replaymod", "restrict"); + public static final Identifier PLUGIN_CHANNEL = identifier("replaymod", "restrict"); //#else //$$ public static final String PLUGIN_CHANNEL = "Replay|Restrict"; //#endif @@ -77,7 +78,7 @@ public class Restrictions { } //#if MC>=12006 - //$$ public static final CustomPayload.Id ID = CustomPayload.id(PLUGIN_CHANNEL.toString()); + //$$ public static final CustomPayload.Id ID = new CustomPayload.Id<>(PLUGIN_CHANNEL); //$$ public static final PacketCodec CODEC = PacketCodec.ofStatic( //$$ (buf, payload) -> buf.writeBytes(payload.bytes()), //$$ buf -> { diff --git a/src/main/java/com/replaymod/core/utils/Utils.java b/src/main/java/com/replaymod/core/utils/Utils.java index 033a6d83..061598fe 100644 --- a/src/main/java/com/replaymod/core/utils/Utils.java +++ b/src/main/java/com/replaymod/core/utils/Utils.java @@ -68,6 +68,10 @@ import java.util.function.Consumer; import static com.replaymod.core.versions.MCVer.getMinecraft; +//#if MC>=12100 +//$$ import net.minecraft.util.crash.ReportType; +//#endif + public class Utils { private static Logger LOGGER = LogManager.getLogger(); @@ -248,7 +252,11 @@ public class Utils { public static GuiInfoPopup error(Logger logger, GuiContainer container, CrashReport crashReport, Runnable onClose) { // Convert crash report to string - String crashReportStr = crashReport.asString(); + String crashReportStr = crashReport.asString( + //#if MC>=12100 + //$$ ReportType.MINECRAFT_CRASH_REPORT + //#endif + ); // Log via logger logger.error(crashReportStr); @@ -259,7 +267,11 @@ public class Utils { File folder = new File(getMinecraft().runDirectory, "crash-reports"); File file = new File(folder, "crash-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + "-client.txt"); logger.debug("Saving crash report to file: {}", file); + //#if MC>=12100 + //$$ crashReport.writeToFile(file.toPath(), ReportType.MINECRAFT_CRASH_REPORT); + //#else crashReport.writeToFile(file); + //#endif } catch (Throwable t) { logger.error("Saving crash report file:", t); } diff --git a/src/main/java/com/replaymod/core/versions/LangResourcePack.java b/src/main/java/com/replaymod/core/versions/LangResourcePack.java index 5e988552..03c0c74d 100644 --- a/src/main/java/com/replaymod/core/versions/LangResourcePack.java +++ b/src/main/java/com/replaymod/core/versions/LangResourcePack.java @@ -28,6 +28,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; +import static de.johni0702.minecraft.gui.versions.MCVer.identifier; + //#if FABRIC>=1 import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; @@ -253,7 +255,7 @@ public class LangResourcePack extends AbstractFileResourcePack { .map(LANG_FILE_NAME_PATTERN::matcher) .filter(Matcher::matches) .map(matcher -> String.format("%s_%s.json", matcher.group(1), matcher.group(1))) - .map(name -> new Identifier(ReplayMod.MOD_ID, "lang/" + name)) + .map(name -> identifier(ReplayMod.MOD_ID, "lang/" + name)) .forEach(consumer); } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index 806b5f3c..341bd2d6 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -454,13 +454,15 @@ public class MCVer { //#if MC>=11700 //$$ .normal(n.x, n.y, n.z) //#endif - .next(); + ; + buffer.next(); buffer.vertex(p2.x, p2.y, p2.z) .color(r, g, b, a) //#if MC>=11700 //$$ .normal(n.x, n.y, n.z) //#endif - .next(); + ; + buffer.next(); } public static void bindTexture(Identifier id) { diff --git a/src/main/java/com/replaymod/core/versions/Patterns.java b/src/main/java/com/replaymod/core/versions/Patterns.java index 1d7e7aec..49954a56 100644 --- a/src/main/java/com/replaymod/core/versions/Patterns.java +++ b/src/main/java/com/replaymod/core/versions/Patterns.java @@ -46,6 +46,7 @@ import org.lwjgl.opengl.GL11; //#endif //#if MC>=11600 +import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.Vector3f; import net.minecraft.util.math.Matrix4f; @@ -367,6 +368,9 @@ class Patterns { //#endif } + //#if MC>=12100 + //$$ @Pattern private static void Tessellator_getBuffer() {} + //#else @Pattern private static BufferBuilder Tessellator_getBuffer(Tessellator tessellator) { //#if MC>=10800 @@ -375,6 +379,20 @@ class Patterns { //$$ return new BufferBuilder(tessellator); //#endif } + //#endif + + //#if MC>=11600 + @Pattern + private static void VertexConsumer_next(VertexConsumer buffer) { + //#if MC>=12100 + //$$ buffer./*next()*/getClass(); + //#else + buffer.next(); + //#endif + } + //#else + //$$ private static void VertexConsumer_next() {} + //#endif //#if MC<11700 @Pattern @@ -477,7 +495,9 @@ class Patterns { @Pattern private static float getRenderPartialTicks(MinecraftClient mc) { - //#if MC>=10900 + //#if MC>=12100 + //$$ return mc.getRenderTickCounter().getTickDelta(true); + //#elseif MC>=10900 return mc.getTickDelta(); //#else //$$ return ((com.replaymod.core.mixin.MinecraftAccessor) mc).getTimer().renderPartialTicks; @@ -524,7 +544,7 @@ class Patterns { //#endif } - //#if MC>=11600 + //#if MC>=11600 && MC<12100 @Pattern private static void BufferBuilder_beginLineStrip(BufferBuilder buffer, VertexFormat vertexFormat) { //#if MC>=11700 diff --git a/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java b/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java index dc3664fe..7c8ac70f 100644 --- a/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java +++ b/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java @@ -9,6 +9,10 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +//#if MC>=12100 +//$$ import net.minecraft.util.crash.ReportType; +//#endif + public class SchedulerImpl implements Scheduler { private static final MinecraftClient mc = MinecraftClient.getInstance(); @@ -113,7 +117,11 @@ public class SchedulerImpl implements Scheduler { runnable.run(); } catch (CrashException e) { e.printStackTrace(); + //#if MC>=12100 + //$$ System.err.println(e.getReport().asString(ReportType.MINECRAFT_CRASH_REPORT)); + //#else System.err.println(e.getReport().asString()); + //#endif mc.setCrashReport(e.getReport()); } finally { inRunLater = false; diff --git a/src/main/java/com/replaymod/pathing/player/AbstractTimelinePlayer.java b/src/main/java/com/replaymod/pathing/player/AbstractTimelinePlayer.java index 00b54bf3..b41ad1ee 100644 --- a/src/main/java/com/replaymod/pathing/player/AbstractTimelinePlayer.java +++ b/src/main/java/com/replaymod/pathing/player/AbstractTimelinePlayer.java @@ -31,7 +31,11 @@ public abstract class AbstractTimelinePlayer extends EventRegistrations { private Timeline timeline; protected long startOffset; private boolean wasAsyncMode; + //#if MC>=12100 + //$$ private RenderTickCounter.Dynamic orgTimer; + //#else private RenderTickCounter orgTimer; + //#endif private long lastTime; private long lastTimestamp; private ListenableFuture future; diff --git a/src/main/java/com/replaymod/pathing/player/ReplayTimer.java b/src/main/java/com/replaymod/pathing/player/ReplayTimer.java index e187f740..db650995 100644 --- a/src/main/java/com/replaymod/pathing/player/ReplayTimer.java +++ b/src/main/java/com/replaymod/pathing/player/ReplayTimer.java @@ -6,7 +6,11 @@ import net.minecraft.client.render.RenderTickCounter; /** * A timer that does not advance by itself. */ +//#if MC>=12100 +//$$ public class ReplayTimer extends RenderTickCounter.Dynamic { +//#else public class ReplayTimer extends RenderTickCounter { +//#endif //#if MC>=11600 public int ticksThisFrame; //#endif @@ -37,13 +41,28 @@ public class ReplayTimer extends RenderTickCounter { //#if MC>=11400 long sysClock //#endif + //#if MC>=12100 + //$$ , boolean tick + //#endif ) { + //#if MC>=12100 + //$$ if (!tick) return 0; + //#endif UpdatedCallback.EVENT.invoker().onUpdate(); //#if MC>=11600 return ticksThisFrame; //#endif } + //#if MC>=12100 + //$$ public float tickDelta; + //$$ + //$$ @Override + //$$ public float getTickDelta(boolean bl) { + //$$ return tickDelta; + //$$ } + //#endif + public interface UpdatedCallback { Event EVENT = Event.create((listeners) -> () -> { diff --git a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java index 93596d7a..ec851793 100644 --- a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java @@ -113,7 +113,21 @@ public class RecordingEventHandler extends EventRegistrations { try { ClientPlayerEntity player = mc.player; assert player != null; - //#if MC>=12002 + //#if MC>=12100 + //$$ packetListener.save(new EntitySpawnS2CPacket( + //$$ player.getId(), + //$$ player.getUuid(), + //$$ player.getX(), + //$$ player.getY(), + //$$ player.getZ(), + //$$ player.getPitch(), + //$$ player.getYaw(), + //$$ player.getType(), + //$$ 0, + //$$ player.getVelocity(), + //$$ player.getHeadYaw() + //$$ )); + //#elseif MC>=12002 //$$ packetListener.save(new EntitySpawnS2CPacket(player)); //#else packetListener.save(new PlayerSpawnS2CPacket(player)); diff --git a/src/main/java/com/replaymod/render/blend/BlendMaterials.java b/src/main/java/com/replaymod/render/blend/BlendMaterials.java index 1248352f..125c6990 100644 --- a/src/main/java/com/replaymod/render/blend/BlendMaterials.java +++ b/src/main/java/com/replaymod/render/blend/BlendMaterials.java @@ -5,8 +5,8 @@ import com.replaymod.render.blend.data.DMaterial; import com.replaymod.render.blend.data.DPackedFile; import com.replaymod.render.blend.data.DTexture; import de.johni0702.minecraft.gui.versions.Image; -import net.minecraft.client.util.GlAllocationUtils; import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import java.io.ByteArrayOutputStream; @@ -25,7 +25,7 @@ public class BlendMaterials { // Read raw image data from GL int width = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_WIDTH); int height = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_HEIGHT); - ByteBuffer buffer = GlAllocationUtils.allocateByteBuffer(width * height * 4); + ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * 4); GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); // Convert to Image diff --git a/src/main/java/com/replaymod/render/blend/Util.java b/src/main/java/com/replaymod/render/blend/Util.java index 64f33b27..a2d26181 100644 --- a/src/main/java/com/replaymod/render/blend/Util.java +++ b/src/main/java/com/replaymod/render/blend/Util.java @@ -5,13 +5,13 @@ import de.johni0702.minecraft.gui.utils.lwjgl.vector.Matrix4f; import de.johni0702.minecraft.gui.utils.lwjgl.vector.Quaternion; import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.util.GlAllocationUtils; import net.minecraft.nbt.CompoundTag; import net.minecraft.block.entity.BlockEntity; import org.blender.dna.Link; import org.blender.dna.ListBase; import org.blender.utils.BlenderFactory; import org.cakelab.blender.nio.CPointer; +import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import java.io.IOException; @@ -39,7 +39,7 @@ public class Util { } } - private static FloatBuffer floatBuffer = GlAllocationUtils.allocateByteBuffer(16 * 4).asFloatBuffer(); + private static FloatBuffer floatBuffer = BufferUtils.createByteBuffer(16 * 4).asFloatBuffer(); public static Matrix4f getGlMatrix(int matrix) { floatBuffer.clear(); //#if MC>=11400 diff --git a/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java b/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java index 925257fe..ea5dead6 100644 --- a/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java +++ b/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java @@ -19,9 +19,11 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; +import static de.johni0702.minecraft.gui.versions.MCVer.identifier; + public class ODSFrameCapturer implements FrameCapturer { - private static final Identifier vertexResource = new Identifier("replaymod", "shader/ods.vert"); - private static final Identifier fragmentResource = new Identifier("replaymod", "shader/ods.frag"); + private static final Identifier vertexResource = identifier("replaymod", "shader/ods.vert"); + private static final Identifier fragmentResource = identifier("replaymod", "shader/ods.frag"); private final CubicPboOpenGlFrameCapturer left, right; private final Program shaderProgram; diff --git a/src/main/java/com/replaymod/render/gui/GuiVideoRenderer.java b/src/main/java/com/replaymod/render/gui/GuiVideoRenderer.java index 72d5a9d3..1b10cdff 100644 --- a/src/main/java/com/replaymod/render/gui/GuiVideoRenderer.java +++ b/src/main/java/com/replaymod/render/gui/GuiVideoRenderer.java @@ -27,8 +27,10 @@ import net.minecraft.client.texture.NativeImage; import java.nio.ByteBuffer; +import static de.johni0702.minecraft.gui.versions.MCVer.identifier; + public class GuiVideoRenderer extends GuiScreen implements Tickable { - private static final Identifier NO_PREVIEW_TEXTURE = new Identifier("replaymod", "logo.png"); + private static final Identifier NO_PREVIEW_TEXTURE = identifier("replaymod", "logo.png"); private final VideoRenderer renderer; diff --git a/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java b/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java index ee68b87e..e05d21ca 100644 --- a/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java +++ b/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java @@ -93,7 +93,9 @@ public class EntityRendererHandler extends EventRegistrations implements WorldRe gameRenderer.setRenderHand(false); // makes no sense, we wouldn't even know where to put it } - //#if MC>=11400 + //#if MC>=12100 + //$$ mc.gameRenderer.render(mc.getRenderTickCounter(), true); + //#elseif MC>=11400 mc.gameRenderer.render(partialTicks, finishTimeNano, true); //#else //$$ mc.setIngameNotInFocus(); // this should already be the case but it somehow still sometimes is not diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Rotation.java b/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Rotation.java index f318342f..abb95b3a 100644 --- a/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Rotation.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Rotation.java @@ -36,7 +36,11 @@ public abstract class Mixin_Omnidirectional_Rotation { } //#if MC>=12005 + //#if MC>=12100 + //$$ @ModifyExpressionValue(method = "renderWorld", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4f;rotation(Lorg/joml/Quaternionfc;)Lorg/joml/Matrix4f;")) + //#else //$$ @ModifyExpressionValue(method = "renderWorld", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4f;rotationXYZ(FFF)Lorg/joml/Matrix4f;")) + //#endif //$$ private Matrix4f replayModRender_setupCubicFrameRotation(Matrix4f matrix) { //#else //#if MC>=11500 diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java b/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java index 2b744a8e..fbd07d4c 100644 --- a/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java @@ -35,7 +35,11 @@ public abstract class Mixin_Stereoscopic_Camera implements EntityRendererHandler } //#if MC>=12005 + //#if MC>=12100 + //$$ @ModifyExpressionValue(method = "renderWorld", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4f;rotation(Lorg/joml/Quaternionfc;)Lorg/joml/Matrix4f;")) + //#else //$$ @ModifyExpressionValue(method = "renderWorld", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4f;rotationXYZ(FFF)Lorg/joml/Matrix4f;")) + //#endif //$$ private Matrix4f replayModRender_setupStereoscopicProjection(Matrix4f matrix) { //#else @Inject(method = "renderWorld", at = @At("HEAD")) diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index 017b2013..4cca8e87 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -5,6 +5,7 @@ import com.replaymod.core.mixin.MinecraftAccessor; import com.replaymod.core.mixin.TimerAccessor; import com.replaymod.core.versions.MCVer; import com.replaymod.pathing.player.AbstractTimelinePlayer; +import com.replaymod.pathing.player.ReplayTimer; import com.replaymod.pathing.properties.TimestampProperty; import com.replaymod.render.CameraPathExporter; import com.replaymod.render.EXRWriter; @@ -37,7 +38,6 @@ import net.minecraft.sound.SoundEvent; import net.minecraft.util.Identifier; import net.minecraft.util.crash.CrashException; import net.minecraft.sound.SoundCategory; -import net.minecraft.client.render.RenderTickCounter; import org.lwjgl.glfw.GLFW; //#if MC>=12000 @@ -87,11 +87,12 @@ import static com.google.common.collect.Iterables.getLast; import static com.replaymod.core.utils.Utils.DEFAULT_MS_PER_TICK; import static com.replaymod.core.versions.MCVer.*; import static com.replaymod.render.ReplayModRender.LOGGER; +import static de.johni0702.minecraft.gui.versions.MCVer.identifier; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; public class VideoRenderer implements RenderInfo { - private static final Identifier SOUND_RENDER_SUCCESS = new Identifier("replaymod", "render_success"); + private static final Identifier SOUND_RENDER_SUCCESS = identifier("replaymod", "render_success"); private final MinecraftClient mc = MCVer.getMinecraft(); private final RenderSettings settings; private final ReplayHandler replayHandler; @@ -191,7 +192,7 @@ public class VideoRenderer implements RenderInfo { // Because this might take some time to prepare we'll render the GUI at least once to not confuse the user drawGui(); - RenderTickCounter timer = ((MinecraftAccessor) mc).getTimer(); + ReplayTimer timer = (ReplayTimer) ((MinecraftAccessor) mc).getTimer(); // Play up to one second before starting to render // This is necessary in order to ensure that all entities have at least two position packets @@ -268,7 +269,7 @@ public class VideoRenderer implements RenderInfo { } // Updating the timer will cause the timeline player to update the game state - RenderTickCounter timer = ((MinecraftAccessor) mc).getTimer(); + ReplayTimer timer = (ReplayTimer) ((MinecraftAccessor) mc).getTimer(); //#if MC>=11600 int elapsedTicks = //#endif @@ -276,6 +277,9 @@ public class VideoRenderer implements RenderInfo { //#if MC>=11400 MCVer.milliTime() //#endif + //#if MC>=12100 + //$$ , true + //#endif ); //#if MC<11600 //$$ int elapsedTicks = timer.ticksThisFrame; diff --git a/src/main/java/com/replaymod/replay/NoGuiScreenshot.java b/src/main/java/com/replaymod/replay/NoGuiScreenshot.java index 04a659da..aa51376f 100644 --- a/src/main/java/com/replaymod/replay/NoGuiScreenshot.java +++ b/src/main/java/com/replaymod/replay/NoGuiScreenshot.java @@ -11,6 +11,10 @@ import net.minecraft.client.util.ScreenshotUtils; import static com.replaymod.core.versions.MCVer.popMatrix; import static com.replaymod.core.versions.MCVer.pushMatrix; +//#if MC>=12100 +//$$ import net.minecraft.client.render.RenderTickCounter; +//#endif + //#if MC>=11500 import net.minecraft.client.util.math.MatrixStack; //#endif @@ -73,6 +77,9 @@ public class NoGuiScreenshot { GlStateManager.enableTexture(); //#endif + //#if MC>=12100 + //$$ mc.gameRenderer.renderWorld(RenderTickCounter.ONE); + //#else float tickDelta = mc.getTickDelta(); //#if MC>=12006 //$$ mc.gameRenderer.renderWorld(tickDelta, System.nanoTime()); @@ -89,6 +96,7 @@ public class NoGuiScreenshot { //#endif //#endif //#endif + //#endif mc.getFramebuffer().endWrite(); popMatrix(); diff --git a/src/main/java/com/replaymod/replay/mixin/MixinCamera.java b/src/main/java/com/replaymod/replay/mixin/MixinCamera.java index 501b15ab..2970f39b 100644 --- a/src/main/java/com/replaymod/replay/mixin/MixinCamera.java +++ b/src/main/java/com/replaymod/replay/mixin/MixinCamera.java @@ -22,7 +22,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; public class MixinCamera { @Shadow @Final private MinecraftClient client; //#if MC>=12005 + //#if MC>=12100 + //$$ @ModifyExpressionValue(method = "renderWorld", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4f;rotation(Lorg/joml/Quaternionfc;)Lorg/joml/Matrix4f;")) + //#else //$$ @ModifyExpressionValue(method = "renderWorld", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4f;rotationXYZ(FFF)Lorg/joml/Matrix4f;")) + //#endif //$$ private Matrix4f applyRoll(Matrix4f matrix) { //#else @Inject( diff --git a/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java b/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java index da17ba14..bb7a7850 100644 --- a/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java +++ b/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java @@ -153,8 +153,12 @@ public class GuiKeyframeTimeline extends AbstractGuiTimeline=12100 + //$$ BufferBuilder buffer = tessellator.begin(net.minecraft.client.render.VertexFormat.DrawMode.LINE_STRIP, VertexFormats.LINES); + //#else BufferBuilder buffer = tessellator.getBuffer(); buffer.begin(GL11.GL_LINE_STRIP, VertexFormats.POSITION_COLOR); + //#endif // Start just below the top border of the replay timeline Vector2f p1 = new Vector2f(replayTimelineLeft + positionXReplayTimeline, replayTimelineTop + BORDER_TOP); @@ -178,7 +182,13 @@ public class GuiKeyframeTimeline extends AbstractGuiTimeline=12100 + //$$ try (var builtBuffer = buffer.end()) { + //$$ net.minecraft.client.render.BufferRenderer.drawWithGlobalProgram(builtBuffer); + //$$ } + //#else tessellator.draw(); + //#endif popScissorState(); //#if MC<11700 GL11.glEnable(GL11.GL_TEXTURE_2D); diff --git a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java index d8eb78e6..9257e437 100644 --- a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java +++ b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java @@ -46,9 +46,10 @@ import static com.replaymod.core.versions.MCVer.bindTexture; import static com.replaymod.core.versions.MCVer.emitLine; import static com.replaymod.core.versions.MCVer.popMatrix; import static com.replaymod.core.versions.MCVer.pushMatrix; +import static de.johni0702.minecraft.gui.versions.MCVer.identifier; public class PathPreviewRenderer extends EventRegistrations { - private static final Identifier CAMERA_HEAD = new Identifier("replaymod", "camera_head.png"); + private static final Identifier CAMERA_HEAD = identifier("replaymod", "camera_head.png"); private static final MinecraftClient mc = MCVer.getMinecraft(); private static final int SLOW_PATH_COLOR = 0xffcccc; @@ -246,8 +247,12 @@ public class PathPreviewRenderer extends EventRegistrations { if (distanceSquared(view, pos2) > renderDistanceSquared) return; Tessellator tessellator = Tessellator.getInstance(); + //#if MC>=12100 + //$$ BufferBuilder buffer = tessellator.begin(net.minecraft.client.render.VertexFormat.DrawMode.LINES, VertexFormats.LINES); + //#else BufferBuilder buffer = tessellator.getBuffer(); buffer.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); + //#endif emitLine(buffer, Vector3f.sub(pos1, view, null), Vector3f.sub(pos2, view, null), color); @@ -256,7 +261,13 @@ public class PathPreviewRenderer extends EventRegistrations { //$$ RenderSystem.disableCull(); //#endif GL11.glLineWidth(3); + //#if MC>=12100 + //$$ try (var builtBuffer = buffer.end()) { + //$$ net.minecraft.client.render.BufferRenderer.drawWithGlobalProgram(builtBuffer); + //$$ } + //#else tessellator.draw(); + //#endif //#if MC>=11700 //$$ RenderSystem.enableCull(); //#endif @@ -284,8 +295,12 @@ public class PathPreviewRenderer extends EventRegistrations { float maxY = 0.5f; Tessellator tessellator = Tessellator.getInstance(); + //#if MC>=12100 + //$$ BufferBuilder buffer = tessellator.begin(net.minecraft.client.render.VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE); + //#else BufferBuilder buffer = tessellator.getBuffer(); buffer.begin(GL11.GL_QUADS, VertexFormats.POSITION_TEXTURE); + //#endif buffer.vertex(minX, minY, 0).texture(posX + size, posY + size).next(); buffer.vertex(minX, maxY, 0).texture(posX + size, posY).next(); @@ -303,7 +318,13 @@ public class PathPreviewRenderer extends EventRegistrations { //$$ RenderSystem.applyModelViewMatrix(); //$$ RenderSystem.setShader(GameRenderer::getPositionTexShader); //#endif + //#if MC>=12100 + //$$ try (var builtBuffer = buffer.end()) { + //$$ net.minecraft.client.render.BufferRenderer.drawWithGlobalProgram(builtBuffer); + //$$ } + //#else tessellator.draw(); + //#endif popMatrix(); } @@ -322,8 +343,12 @@ public class PathPreviewRenderer extends EventRegistrations { //draw the position line Tessellator tessellator = Tessellator.getInstance(); + //#if MC>=12100 + //$$ BufferBuilder buffer = tessellator.begin(net.minecraft.client.render.VertexFormat.DrawMode.LINES, VertexFormats.LINES); + //#else BufferBuilder buffer = tessellator.getBuffer(); buffer.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); + //#endif emitLine(buffer, new Vector3f(0, 0, 0), new Vector3f(0, 0, 2), 0x00ff00aa); @@ -334,7 +359,13 @@ public class PathPreviewRenderer extends EventRegistrations { GL11.glDisable(GL11.GL_TEXTURE_2D); //#endif + //#if MC>=12100 + //$$ try (var builtBuffer = buffer.end()) { + //$$ net.minecraft.client.render.BufferRenderer.drawWithGlobalProgram(builtBuffer); + //$$ } + //#else tessellator.draw(); + //#endif //#if MC<11700 GL11.glEnable(GL11.GL_TEXTURE_2D); @@ -344,9 +375,17 @@ public class PathPreviewRenderer extends EventRegistrations { float cubeSize = 0.5f; + //#if MC>=12100 + //$$ float r = -cubeSize/2; + //#else double r = -cubeSize/2; + //#endif + //#if MC>=12100 + //$$ buffer = tessellator.begin(net.minecraft.client.render.VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR); + //#else buffer.begin(GL11.GL_QUADS, VertexFormats.POSITION_TEXTURE_COLOR); + //#endif //back buffer.vertex(r, r + cubeSize, r).texture(3 * 8 / 64f, 8 / 64f).color(255, 255, 255, 200).next(); @@ -388,7 +427,13 @@ public class PathPreviewRenderer extends EventRegistrations { //$$ RenderSystem.applyModelViewMatrix(); //$$ RenderSystem.setShader(GameRenderer::getPositionTexColorShader); //#endif + //#if MC>=12100 + //$$ try (var builtBuffer = buffer.end()) { + //$$ net.minecraft.client.render.BufferRenderer.drawWithGlobalProgram(builtBuffer); + //$$ } + //#else tessellator.draw(); + //#endif popMatrix(); } diff --git a/versions/1.21/.gitkeep b/versions/1.21/.gitkeep new file mode 100644 index 00000000..e69de29b From d70e41006d896b839c8413f37656bfe30c5b0091 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 23 Jun 2024 21:02:17 +0200 Subject: [PATCH 17/28] Add ReplayStudio as submodule instead of JitPack Because JitPack breaks Gradle variants so we get the Java 17 jar even when we use the Java 8 variant. This works for building via Gradle. However it does not work for usage from IntelliJ, where you must currently publishToMavenLocal ReplayStudio and then depend on that version. Still looking for a better solution there. --- .gitmodules | 3 +++ ReplayStudio | 1 + build.gradle.kts | 8 +++++++- settings.gradle.kts | 2 ++ 4 files changed, 13 insertions(+), 1 deletion(-) create mode 160000 ReplayStudio diff --git a/.gitmodules b/.gitmodules index 0d1b3611..b8b3fdb2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,6 @@ [submodule "src/main/resources/assets/replaymod/lang"] path = src/main/resources/assets/replaymod/lang url = https://github.com/ReplayMod/Translations +[submodule "ReplayStudio"] + path = ReplayStudio + url = ../ReplayStudio diff --git a/ReplayStudio b/ReplayStudio new file mode 160000 index 00000000..5d17653d --- /dev/null +++ b/ReplayStudio @@ -0,0 +1 @@ +Subproject commit 5d17653db9b10f4b4741ab4af659595855cd10f8 diff --git a/build.gradle.kts b/build.gradle.kts index d7bb33d6..2b0f1bfd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -156,7 +156,13 @@ dependencies { implementation(shadow("com.github.ReplayMod.JavaBlend:2.79.0:a0696f8")!!) - implementation(shadow("com.github.ReplayMod:ReplayStudio:5d17653db9")!!) + implementation(shadow("com.github.ReplayMod:ReplayStudio") { + attributes { + // Force use of jar (as opposed to classes directory) because only the jar contains the relocated ViaVersion + // Doesn't seem to work for IDE though, so will have to publishToMavenLocal it for that. + attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR)) + } + }) // FIXME this should be pulled in by ReplayStudio, and IntelliJ sees it, but javac for some reason does not implementation("com.github.viaversion:opennbt:0a02214") // 2.0-SNAPSHOT (ViaVersion Edition) diff --git a/settings.gradle.kts b/settings.gradle.kts index dac8a4c8..92068ff5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -74,6 +74,8 @@ val replayModVersions = listOf( rootProject.buildFileName = "root.gradle.kts" +includeBuild("ReplayStudio") + include(":jGui") project(":jGui").apply { projectDir = file("jGui") From 2b2ab2ba8b7d4cf9fe29c5a64af8a5187dc06653 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 25 Jun 2024 10:30:43 +0200 Subject: [PATCH 18/28] Fix time keyframe lines rendering below timeline --- .../com/replaymod/core/versions/MCVer.java | 19 ++++++++++++++----- .../gui/GuiKeyframeTimeline.java | 8 +++++--- .../preview/PathPreviewRenderer.java | 4 ++-- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index 341bd2d6..1f5e5471 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -10,6 +10,7 @@ import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.util.math.MatrixStack; import net.minecraft.network.NetworkState; import net.minecraft.util.Identifier; import net.minecraft.util.Util; @@ -437,11 +438,11 @@ public class MCVer { //$$ } //#endif - public static void emitLine(BufferBuilder buffer, Vector2f p1, Vector2f p2, int color) { - emitLine(buffer, new Vector3f(p1.x, p1.y, 0), new Vector3f(p2.x, p2.y, 0), color); + public static void emitLine(MatrixStack matrixStack, BufferBuilder buffer, Vector2f p1, Vector2f p2, int color) { + emitLine(matrixStack, buffer, new Vector3f(p1.x, p1.y, 0), new Vector3f(p2.x, p2.y, 0), color); } - public static void emitLine(BufferBuilder buffer, Vector3f p1, Vector3f p2, int color) { + public static void emitLine(MatrixStack matrixStack, BufferBuilder buffer, Vector3f p1, Vector3f p2, int color) { int r = color >> 24 & 0xff; int g = color >> 16 & 0xff; int b = color >> 8 & 0xff; @@ -449,14 +450,22 @@ public class MCVer { //#if MC>=11700 //$$ Vector3f n = Vector3f.sub(p2, p1, null); //#endif - buffer.vertex(p1.x, p1.y, p1.z) + //#if MC>=11600 + buffer.vertex(matrixStack.peek().getModel(), p1.x, p1.y, p1.z) + //#else + //$$ buffer.vertex(p1.x, p1.y, p1.z) + //#endif .color(r, g, b, a) //#if MC>=11700 //$$ .normal(n.x, n.y, n.z) //#endif ; buffer.next(); - buffer.vertex(p2.x, p2.y, p2.z) + //#if MC>=11600 + buffer.vertex(matrixStack.peek().getModel(), p2.x, p2.y, p2.z) + //#else + //$$ buffer.vertex(p2.x, p2.y, p2.z) + //#endif .color(r, g, b, a) //#if MC>=11700 //$$ .normal(n.x, n.y, n.z) diff --git a/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java b/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java index bb7a7850..efa25f1f 100644 --- a/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java +++ b/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java @@ -22,6 +22,7 @@ import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector2f; import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.VertexFormats; +import net.minecraft.client.util.math.MatrixStack; import org.apache.commons.lang3.tuple.Pair; import de.johni0702.minecraft.gui.utils.lwjgl.Point; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; @@ -169,9 +170,10 @@ public class GuiKeyframeTimeline extends AbstractGuiTimeline=11700 //$$ RenderSystem.setShader(GameRenderer::getRenderTypeLinesShader); diff --git a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java index 9257e437..35af5819 100644 --- a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java +++ b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java @@ -254,7 +254,7 @@ public class PathPreviewRenderer extends EventRegistrations { buffer.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); //#endif - emitLine(buffer, Vector3f.sub(pos1, view, null), Vector3f.sub(pos2, view, null), color); + emitLine(new MatrixStack(), buffer, Vector3f.sub(pos1, view, null), Vector3f.sub(pos2, view, null), color); //#if MC>=11700 //$$ RenderSystem.setShader(GameRenderer::getRenderTypeLinesShader); @@ -350,7 +350,7 @@ public class PathPreviewRenderer extends EventRegistrations { buffer.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); //#endif - emitLine(buffer, new Vector3f(0, 0, 0), new Vector3f(0, 0, 2), 0x00ff00aa); + emitLine(new MatrixStack(), buffer, new Vector3f(0, 0, 0), new Vector3f(0, 0, 2), 0x00ff00aa); //#if MC>=11700 //$$ RenderSystem.applyModelViewMatrix(); From 486056de243d7d96c67616a8c8ff2d545d4d3491 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 25 Jun 2024 10:31:12 +0200 Subject: [PATCH 19/28] Fix recording whith login-phase custom packets --- .../replaymod/recording/handler/ConnectionEventHandler.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java index 23814307..05230373 100644 --- a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java @@ -158,8 +158,9 @@ public class ConnectionEventHandler { packetListener = new PacketListener(core, channel, outputPath, replayFile, metaData); //#if MC>=12005 - //$$ channel.pipeline().addBefore("inbound_config", PacketListener.RAW_RECORDER_KEY, packetListener); - //$$ channel.pipeline().addAfter("inbound_config", PacketListener.DECODED_RECORDER_KEY, packetListener.new DecodedPacketListener()); + //$$ String target = channel.pipeline().get("inbound_config") != null ? "inbound_config" : PacketListener.DECODER_KEY; + //$$ channel.pipeline().addBefore(target, PacketListener.RAW_RECORDER_KEY, packetListener); + //$$ channel.pipeline().addAfter(target, PacketListener.DECODED_RECORDER_KEY, packetListener.new DecodedPacketListener()); //#else if (channel.pipeline().get(PacketListener.DECODER_KEY) != null) { // Regular channel, we'll inject our recorder directly before the decoder From a04fd5b00b0be30d1d24f3ca577f85315b0bb09c Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 30 Jun 2024 20:26:07 +0200 Subject: [PATCH 20/28] Move ReplayStudio submodule into `libs` folder --- .gitmodules | 2 +- ReplayStudio => libs/ReplayStudio | 0 settings.gradle.kts | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename ReplayStudio => libs/ReplayStudio (100%) diff --git a/.gitmodules b/.gitmodules index b8b3fdb2..7c4d6156 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,5 +6,5 @@ path = src/main/resources/assets/replaymod/lang url = https://github.com/ReplayMod/Translations [submodule "ReplayStudio"] - path = ReplayStudio + path = libs/ReplayStudio url = ../ReplayStudio diff --git a/ReplayStudio b/libs/ReplayStudio similarity index 100% rename from ReplayStudio rename to libs/ReplayStudio diff --git a/settings.gradle.kts b/settings.gradle.kts index 92068ff5..4eba5b03 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -74,7 +74,7 @@ val replayModVersions = listOf( rootProject.buildFileName = "root.gradle.kts" -includeBuild("ReplayStudio") +includeBuild("libs/ReplayStudio") include(":jGui") project(":jGui").apply { From 329530de0e5f3909aad299b59156aed0b3d9cb97 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 1 Jul 2024 12:24:53 +0200 Subject: [PATCH 21/28] Update ReplayStudio so it works via includeBuild --- build.gradle.kts | 12 +++--------- libs/ReplayStudio | 2 +- root.gradle.kts | 3 +-- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 2b0f1bfd..40724baa 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -156,15 +156,9 @@ dependencies { implementation(shadow("com.github.ReplayMod.JavaBlend:2.79.0:a0696f8")!!) - implementation(shadow("com.github.ReplayMod:ReplayStudio") { - attributes { - // Force use of jar (as opposed to classes directory) because only the jar contains the relocated ViaVersion - // Doesn't seem to work for IDE though, so will have to publishToMavenLocal it for that. - attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR)) - } - }) - // FIXME this should be pulled in by ReplayStudio, and IntelliJ sees it, but javac for some reason does not - implementation("com.github.viaversion:opennbt:0a02214") // 2.0-SNAPSHOT (ViaVersion Edition) + implementation(shadow("com.github.ReplayMod:ReplayStudio")!!) + // FIXME hack because I don't know how to get this to be inherited properly + implementation(rootProject.files("libs/ReplayStudio/.gradle/prebundled-jars/viaVersion.jar")) implementation(project(path = jGui.path, configuration = "namedElements")) implementation(shadow("com.github.ReplayMod:lwjgl-utils:27dcd66")!!) diff --git a/libs/ReplayStudio b/libs/ReplayStudio index 5d17653d..872810f8 160000 --- a/libs/ReplayStudio +++ b/libs/ReplayStudio @@ -1 +1 @@ -Subproject commit 5d17653db9b10f4b4741ab4af659595855cd10f8 +Subproject commit 872810f8444d20040f083af20f4d390aa1999036 diff --git a/root.gradle.kts b/root.gradle.kts index 3342ee39..68715784 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -34,8 +34,7 @@ subprojects { maven("https://jitpack.io") } } - - if (name == "jGui") { + if (name == "jGui" || name == "ReplayStudio") { return@subprojects } val (_, minor) = name.split("-")[0].split(".") From 8adb65d72418fac0c90711dfc122169296d937b4 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 1 Jul 2024 12:48:23 +0200 Subject: [PATCH 22/28] Move old mapping files to standard location --- root.gradle.kts | 14 +++++++------- .../mapping.txt => mapping-forge-1.11-1.10.2.txt} | 0 .../mapping.txt => mapping-forge-1.11.2-1.11.txt} | 0 .../mapping.txt => mapping-forge-1.12-1.11.2.txt} | 0 ...mapping.txt => mapping-forge-1.14.4-1.12.2.txt} | 0 .../mapping.txt => mapping-forge-1.8-1.7.10.txt} | 0 .../mapping.txt => mapping-forge-1.8.9-1.8.txt} | 0 .../mapping.txt => mapping-forge-1.9.4-1.8.9.txt} | 0 8 files changed, 7 insertions(+), 7 deletions(-) rename versions/{1.11/mapping.txt => mapping-forge-1.11-1.10.2.txt} (100%) rename versions/{1.11.2/mapping.txt => mapping-forge-1.11.2-1.11.txt} (100%) rename versions/{1.12/mapping.txt => mapping-forge-1.12-1.11.2.txt} (100%) rename versions/{1.14.4-forge/mapping.txt => mapping-forge-1.14.4-1.12.2.txt} (100%) rename versions/{1.8/mapping.txt => mapping-forge-1.8-1.7.10.txt} (100%) rename versions/{1.8.9/mapping.txt => mapping-forge-1.8.9-1.8.txt} (100%) rename versions/{1.9.4/mapping.txt => mapping-forge-1.9.4-1.8.9.txt} (100%) diff --git a/root.gradle.kts b/root.gradle.kts index 68715784..37fe3c51 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -247,14 +247,14 @@ preprocess { mc11601.link(mc11502, file("versions/mapping-fabric-1.16.1-1.15.2.txt")) mc11502.link(mc11404, file("versions/mapping-fabric-1.15.2-1.14.4.txt")) mc11404.link(mc11404Forge, file("versions/mapping-1.14.4-fabric-forge.txt")) - mc11404Forge.link(mc11202, file("versions/1.14.4-forge/mapping.txt")) + mc11404Forge.link(mc11202, file("versions/mapping-forge-1.14.4-1.12.2.txt")) mc11202.link(mc11201) mc11201.link(mc11200) - mc11200.link(mc11102, file("versions/1.12/mapping.txt")) - mc11102.link(mc11100, file("versions/1.11.2/mapping.txt")) - mc11100.link(mc11002, file("versions/1.11/mapping.txt")) + mc11200.link(mc11102, file("versions/mapping-forge-1.12-1.11.2.txt")) + mc11102.link(mc11100, file("versions/mapping-forge-1.11.2-1.11.txt")) + mc11100.link(mc11002, file("versions/mapping-forge-1.11-1.10.2.txt")) mc11002.link(mc10904) - mc10904.link(mc10809, file("versions/1.9.4/mapping.txt")) - mc10809.link(mc10800, file("versions/1.8.9/mapping.txt")) - mc10800.link(mc10710, file("versions/1.8/mapping.txt")) + mc10904.link(mc10809, file("versions/mapping-forge-1.9.4-1.8.9.txt")) + mc10809.link(mc10800, file("versions/mapping-forge-1.8.9-1.8.txt")) + mc10800.link(mc10710, file("versions/mapping-forge-1.8-1.7.10.txt")) } diff --git a/versions/1.11/mapping.txt b/versions/mapping-forge-1.11-1.10.2.txt similarity index 100% rename from versions/1.11/mapping.txt rename to versions/mapping-forge-1.11-1.10.2.txt diff --git a/versions/1.11.2/mapping.txt b/versions/mapping-forge-1.11.2-1.11.txt similarity index 100% rename from versions/1.11.2/mapping.txt rename to versions/mapping-forge-1.11.2-1.11.txt diff --git a/versions/1.12/mapping.txt b/versions/mapping-forge-1.12-1.11.2.txt similarity index 100% rename from versions/1.12/mapping.txt rename to versions/mapping-forge-1.12-1.11.2.txt diff --git a/versions/1.14.4-forge/mapping.txt b/versions/mapping-forge-1.14.4-1.12.2.txt similarity index 100% rename from versions/1.14.4-forge/mapping.txt rename to versions/mapping-forge-1.14.4-1.12.2.txt diff --git a/versions/1.8/mapping.txt b/versions/mapping-forge-1.8-1.7.10.txt similarity index 100% rename from versions/1.8/mapping.txt rename to versions/mapping-forge-1.8-1.7.10.txt diff --git a/versions/1.8.9/mapping.txt b/versions/mapping-forge-1.8.9-1.8.txt similarity index 100% rename from versions/1.8.9/mapping.txt rename to versions/mapping-forge-1.8.9-1.8.txt diff --git a/versions/1.9.4/mapping.txt b/versions/mapping-forge-1.9.4-1.8.9.txt similarity index 100% rename from versions/1.9.4/mapping.txt rename to versions/mapping-forge-1.9.4-1.8.9.txt From b4ead9e0647687537a3a61022b59311df9357a6d Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 7 Jul 2024 10:32:55 +0200 Subject: [PATCH 23/28] Update ReplayStudio 1e96fda Fix SquashFilter dropping config-phase custom packets --- libs/ReplayStudio | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ReplayStudio b/libs/ReplayStudio index 872810f8..1e96fda6 160000 --- a/libs/ReplayStudio +++ b/libs/ReplayStudio @@ -1 +1 @@ -Subproject commit 872810f8444d20040f083af20f4d390aa1999036 +Subproject commit 1e96fda6052562477a54a7ced778f25a547f40ae From 6b5993ad64ce37d9db4652e7288a01eeb614f7c6 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 7 Jul 2024 11:02:41 +0200 Subject: [PATCH 24/28] Fix post-screenshot popup being invisible while HUD is hidden --- .../extras/advancedscreenshots/GuiCreateScreenshot.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java index cda0409d..c102d433 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java @@ -6,6 +6,7 @@ import com.replaymod.render.gui.GuiRenderSettings; import com.replaymod.replay.ReplayModReplay; import de.johni0702.minecraft.gui.container.GuiContainer; import de.johni0702.minecraft.gui.container.GuiPanel; +import de.johni0702.minecraft.gui.container.GuiScreen; import de.johni0702.minecraft.gui.element.GuiLabel; import de.johni0702.minecraft.gui.function.Loadable; import de.johni0702.minecraft.gui.layout.GridLayout; @@ -58,8 +59,9 @@ public class GuiCreateScreenshot extends GuiRenderSettings implements Loadable { boolean success = new ScreenshotRenderer(settings).renderScreenshot(); if (success) { - new GuiUploadScreenshot(ReplayModReplay.instance.getReplayHandler().getOverlay(), mod, - settings).open(); + GuiScreen screen = createBaseScreen(); + new GuiUploadScreenshot(screen, mod, settings).open(); + screen.display(); } } catch (Throwable t) { From b537822d3cb96a482217d1ea4e73569d5248344f Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 10 Jul 2024 17:36:01 +0200 Subject: [PATCH 25/28] Enable Gradle daemon Now that we no longer have to deal with ForgeGradle, we can actually use this pretty fundamental Gradle feature again. --- gradle.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 7b84fd48..c37f96f1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,6 +4,5 @@ essential.defaults.loom.fabric-loader=net.fabricmc:fabric-loader:0.15.11 # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. org.gradle.jvmargs=-Xmx8G -org.gradle.daemon=false org.gradle.parallel=true org.gradle.configureondemand=true From d2cdcb02fc4fe59824008176f420fe792181fe81 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 10 Jul 2024 18:20:19 +0200 Subject: [PATCH 26/28] Remove unnecessary isTransitive exclusion Now that it's using Modrinth maven, there won't be any transitive dependencies anyway. --- build.gradle.kts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 40724baa..3c654f09 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -195,9 +195,7 @@ dependencies { } if (mcVersion >= 11600) { - modCompileOnly("maven.modrinth:iris:1.18.x-v1.2.0") { - isTransitive = false // we do not want to upgrade our libs, we only need this to compile our mixins - } + modCompileOnly("maven.modrinth:iris:1.18.x-v1.2.0") } testImplementation("junit:junit:4.11") From ca6ae4b9838f6d470a8ad68f6e457fc60003a044 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 10 Jul 2024 19:07:00 +0200 Subject: [PATCH 27/28] Fix ODS export with Iris 1.7 --- build.gradle.kts | 9 +++++++-- root.gradle.kts | 2 +- versions/mapping-fabric-1.20.1-1.19.4.txt | 5 +++++ 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 versions/mapping-fabric-1.20.1-1.19.4.txt diff --git a/build.gradle.kts b/build.gradle.kts index 3c654f09..3a4d6414 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -194,8 +194,13 @@ dependencies { } } - if (mcVersion >= 11600) { - modCompileOnly("maven.modrinth:iris:1.18.x-v1.2.0") + val irisVersion = when { + mcVersion >= 12000 -> "1.7.2+1.20.1" + mcVersion >= 11600 -> "1.18.x-v1.2.0" + else -> null + } + if (irisVersion != null) { + modCompileOnly("maven.modrinth:iris:$irisVersion") } testImplementation("junit:junit:4.11") diff --git a/root.gradle.kts b/root.gradle.kts index 37fe3c51..e554ebc7 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -234,7 +234,7 @@ preprocess { mc12006.link(mc12004) mc12004.link(mc12002, file("versions/mapping-fabric-1.20.4-1.20.2.txt")) mc12002.link(mc12001) - mc12001.link(mc11904) + mc12001.link(mc11904, file("versions/mapping-fabric-1.20.1-1.19.4.txt")) mc11904.link(mc11903) mc11903.link(mc11902, file("versions/mapping-fabric-1.19.3-1.19.2.txt")) mc11902.link(mc11901) diff --git a/versions/mapping-fabric-1.20.1-1.19.4.txt b/versions/mapping-fabric-1.20.1-1.19.4.txt new file mode 100644 index 00000000..47490df5 --- /dev/null +++ b/versions/mapping-fabric-1.20.1-1.19.4.txt @@ -0,0 +1,5 @@ +net.irisshaders.iris.Iris net.coderbot.iris.Iris +net.irisshaders.iris.config.IrisConfig net.coderbot.iris.config.IrisConfig +net.irisshaders.iris.gl.uniform.UniformHolder net.coderbot.iris.gl.uniform.UniformHolder +net.irisshaders.iris.gl.uniform.UniformUpdateFrequency net.coderbot.iris.gl.uniform.UniformUpdateFrequency +net.irisshaders.iris.uniforms.CommonUniforms net.coderbot.iris.uniforms.CommonUniforms From 1836b7fb18b596b66fdea5e2423b0be42cf74f35 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 10 Jul 2024 19:07:19 +0200 Subject: [PATCH 28/28] Fix Iris shader animation time on 1.21 --- .../render/hooks/EntityRendererHandler.java | 7 ++++++ .../Mixin_FakeSystemTimeUniforms_Iris.java | 1 + .../resources/mixins.render.replaymod.json | 3 +++ .../Mixin_FakeSystemTimeUniforms_Iris.java | 25 +++++++++++++++++++ 4 files changed, 36 insertions(+) create mode 100644 src/main/java/com/replaymod/render/mixin/Mixin_FakeSystemTimeUniforms_Iris.java create mode 100644 versions/1.21/src/main/java/com/replaymod/render/mixin/Mixin_FakeSystemTimeUniforms_Iris.java diff --git a/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java b/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java index e05d21ca..7695388b 100644 --- a/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java +++ b/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java @@ -41,6 +41,8 @@ public class EntityRendererHandler extends EventRegistrations implements WorldRe private final long startTime; + private long fakeFinishTimeNano; + public EntityRendererHandler(RenderSettings settings, RenderInfo renderInfo) { this.settings = settings; this.renderInfo = renderInfo; @@ -71,6 +73,7 @@ public class EntityRendererHandler extends EventRegistrations implements WorldRe } public void renderWorld(float partialTicks, long finishTimeNano) { + fakeFinishTimeNano = finishTimeNano; //#if MC>=11400 PreRenderCallback.EVENT.invoker().preRender(); //#else @@ -142,6 +145,10 @@ public class EntityRendererHandler extends EventRegistrations implements WorldRe return this.renderInfo; } + public long getFakeFinishTimeNano() { + return fakeFinishTimeNano; + } + public interface IEntityRenderer { void replayModRender_setHandler(EntityRendererHandler handler); EntityRendererHandler replayModRender_getHandler(); diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_FakeSystemTimeUniforms_Iris.java b/src/main/java/com/replaymod/render/mixin/Mixin_FakeSystemTimeUniforms_Iris.java new file mode 100644 index 00000000..21fcd479 --- /dev/null +++ b/src/main/java/com/replaymod/render/mixin/Mixin_FakeSystemTimeUniforms_Iris.java @@ -0,0 +1 @@ +// 1.21+ diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index bd3761e4..28795704 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -14,6 +14,9 @@ "Mixin_ChromaKeyColorSky", "Mixin_ChromaKeyDisableFog", "Mixin_ChromaKeyForceSky", + //#if MC>=12100 + //$$ "Mixin_FakeSystemTimeUniforms_Iris", + //#endif "Mixin_ForceChunkLoading", "Mixin_HideNameTags", "Mixin_HideNameTags_LivingEntity", diff --git a/versions/1.21/src/main/java/com/replaymod/render/mixin/Mixin_FakeSystemTimeUniforms_Iris.java b/versions/1.21/src/main/java/com/replaymod/render/mixin/Mixin_FakeSystemTimeUniforms_Iris.java new file mode 100644 index 00000000..042d8008 --- /dev/null +++ b/versions/1.21/src/main/java/com/replaymod/render/mixin/Mixin_FakeSystemTimeUniforms_Iris.java @@ -0,0 +1,25 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.hooks.EntityRendererHandler; +import net.irisshaders.iris.uniforms.SystemTimeUniforms; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.GameRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Pseudo +@Mixin(value = SystemTimeUniforms.Timer.class, remap = false) +public class Mixin_FakeSystemTimeUniforms_Iris { + @ModifyVariable(method = "beginFrame", at = @At("HEAD"), argsOnly = true) + private long useReplayTimeDuringRender(long frameStartTimeNs) { + GameRenderer gameRenderer = MinecraftClient.getInstance().gameRenderer; + EntityRendererHandler entityRendererHandler = + ((EntityRendererHandler.IEntityRenderer) gameRenderer).replayModRender_getHandler(); + if (entityRendererHandler != null) { + frameStartTimeNs = entityRendererHandler.getFakeFinishTimeNano(); + } + return frameStartTimeNs; + } +}