diff --git a/.gitignore b/.gitignore index 37399e16..0b48d75f 100644 Binary files a/.gitignore and b/.gitignore differ diff --git a/.gitmodules b/.gitmodules index 0d1b3611..7c4d6156 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 = libs/ReplayStudio + url = ../ReplayStudio 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..3a4d6414 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,348 @@ +import com.replaymod.gradle.preprocess.PreprocessTask +import gg.essential.gradle.util.* + +plugins { + java + id("io.github.goooler.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" + 12006 -> "0.98.0+1.20.6" + 12100 -> "0.100.3+1.21" + 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 (platform.isFabric) { + "include"(implementation(annotationProcessor("io.github.llamalad7:mixinextras-fabric:0.3.6")!!)!!) + } + + 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")!!) + // 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")!!) + + 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" + 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) { + 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") + } + } + + 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") +} + +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..c37f96f1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,8 @@ +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.daemon=false +org.gradle.jvmargs=-Xmx8G 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..d2626659 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit bd41e57af0aefe7db7068e5f4b9f8eb5310c0878 +Subproject commit d2626659b0a7e6904787bf29904e319c0ca245aa diff --git a/libs/ReplayStudio b/libs/ReplayStudio new file mode 160000 index 00000000..1e96fda6 --- /dev/null +++ b/libs/ReplayStudio @@ -0,0 +1 @@ +Subproject commit 1e96fda6052562477a54a7ced778f25a547f40ae diff --git a/root.gradle.kts b/root.gradle.kts index 72cfd411..e554ebc7 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -2,8 +2,7 @@ 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" } @@ -35,6 +34,12 @@ subprojects { maven("https://jitpack.io") } } + if (name == "jGui" || name == "ReplayStudio") { + 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") @@ -91,8 +96,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) { @@ -193,6 +201,8 @@ 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") val mc12001 = createNode("1.20.1", 12001, "yarn") @@ -220,9 +230,11 @@ 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) - 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) @@ -235,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/settings.gradle.kts b/settings.gradle.kts index bb1dd6e4..4eba5b03 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.1" + id("io.github.goooler.shadow") version "8.1.7" } } val jGuiVersions = listOf( // "1.7.10", - "1.8", + // "1.8", "1.8.9", "1.9.4", "1.12", @@ -40,10 +38,12 @@ val jGuiVersions = listOf( "1.20.1", "1.20.2", "1.20.4", + "1.20.6", + "1.21", ) val replayModVersions = listOf( // "1.7.10", - "1.8", + // "1.8", "1.8.9", "1.9.4", "1.10.2", @@ -68,20 +68,24 @@ val replayModVersions = listOf( "1.20.1", "1.20.2", "1.20.4", + "1.20.6", + "1.21", ) rootProject.buildFileName = "root.gradle.kts" +includeBuild("libs/ReplayStudio") + 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 +93,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/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 d31a57f7..ed1535dc 100644 --- a/src/main/java/com/replaymod/core/ReplayMod.java +++ b/src/main/java/com/replaymod/core/ReplayMod.java @@ -36,6 +36,15 @@ 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; +//$$ import net.minecraft.text.Text; +//$$ import java.util.Optional; +//#endif + //#if MC>=11900 //#else import net.minecraft.client.options.Option; @@ -45,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(); @@ -120,7 +129,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/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/Mixin_PostRenderWorldCalback.java b/src/main/java/com/replaymod/core/mixin/Mixin_PostRenderWorldCalback.java new file mode 100644 index 00000000..641749c5 --- /dev/null +++ b/src/main/java/com/replaymod/core/mixin/Mixin_PostRenderWorldCalback.java @@ -0,0 +1,34 @@ +//#if MC>=11400 +package com.replaymod.core.mixin; + +import com.replaymod.core.events.PostRenderWorldCallback; +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; + +//#if MC>=11500 +import com.llamalad7.mixinextras.sugar.Local; +//#endif + +@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); + } +} +//#endif diff --git a/src/main/java/com/replaymod/core/mixin/MixinGameRenderer.java b/src/main/java/com/replaymod/core/mixin/Mixin_PreRenderHandCallback.java similarity index 55% rename from src/main/java/com/replaymod/core/mixin/MixinGameRenderer.java rename to src/main/java/com/replaymod/core/mixin/Mixin_PreRenderHandCallback.java index a7c817a9..012c93eb 100644 --- a/src/main/java/com/replaymod/core/mixin/MixinGameRenderer.java +++ b/src/main/java/com/replaymod/core/mixin/Mixin_PreRenderHandCallback.java @@ -1,7 +1,6 @@ //#if MC>=11400 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; @@ -11,35 +10,23 @@ 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 MixinGameRenderer { - @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 - PostRenderWorldCallback.EVENT.invoker().postRenderWorld(matrixStack); - } +//#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/mixin/TimerAccessor.java b/src/main/java/com/replaymod/core/mixin/TimerAccessor.java index 78f7da1a..3f9eed1e 100644 --- a/src/main/java/com/replaymod/core/mixin/TimerAccessor.java +++ b/src/main/java/com/replaymod/core/mixin/TimerAccessor.java @@ -5,13 +5,12 @@ 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 { - @Accessor("prevTimeMillis") - long getLastSyncSysClock(); - @Accessor("prevTimeMillis") - void setLastSyncSysClock(long value); - //#if MC>=11200 @Accessor("tickTime") float getTickLength(); @@ -23,25 +22,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/Restrictions.java b/src/main/java/com/replaymod/core/utils/Restrictions.java index 0fc0e9f2..a85df613 100644 --- a/src/main/java/com/replaymod/core/utils/Restrictions.java +++ b/src/main/java/com/replaymod/core/utils/Restrictions.java @@ -2,8 +2,15 @@ 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; +import static de.johni0702.minecraft.gui.versions.MCVer.identifier; //#endif //#if MC<=10710 || MC>=12002 @@ -16,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 @@ -26,7 +33,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 +76,22 @@ public class Restrictions { public boolean isOnlyRecordingPlayer() { return onlyRecordingPlayer; } + + //#if MC>=12006 + //$$ 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 -> { + //$$ 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/utils/Utils.java b/src/main/java/com/replaymod/core/utils/Utils.java index e9706634..061598fe 100644 --- a/src/main/java/com/replaymod/core/utils/Utils.java +++ b/src/main/java/com/replaymod/core/utils/Utils.java @@ -68,9 +68,15 @@ 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(); + public static final float DEFAULT_MS_PER_TICK = 1000 / 20; + private static InputStream getResourceAsStream(String path) { return Utils.class.getResourceAsStream(path); } @@ -246,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); @@ -257,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/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/core/versions/LangResourcePack.java b/src/main/java/com/replaymod/core/versions/LangResourcePack.java index 41fa3e14..03c0c74d 100644 --- a/src/main/java/com/replaymod/core/versions/LangResourcePack.java +++ b/src/main/java/com/replaymod/core/versions/LangResourcePack.java @@ -28,12 +28,21 @@ 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; //#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 +73,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)); @@ -244,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 44e64f14..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; @@ -397,7 +398,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 +409,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(); @@ -431,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; @@ -443,18 +450,28 @@ 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 - .next(); - buffer.vertex(p2.x, p2.y, p2.z) + ; + buffer.next(); + //#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) //#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 984b3fb8..49954a56 100644 --- a/src/main/java/com/replaymod/core/versions/Patterns.java +++ b/src/main/java/com/replaymod/core/versions/Patterns.java @@ -21,6 +21,8 @@ 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; import net.minecraft.sound.SoundCategory; @@ -44,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; @@ -85,6 +88,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 @@ -364,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 @@ -372,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 @@ -474,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; @@ -521,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 @@ -574,7 +597,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); @@ -915,7 +940,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(); @@ -923,6 +950,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 @@ -931,6 +961,7 @@ class Patterns { return state.getPacketId(side, packet); //#endif } + //#endif @Pattern public int UnloadChunkPacket_getX(UnloadChunkS2CPacket packet) { @@ -955,6 +986,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 @@ -972,4 +1012,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/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/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) { diff --git a/src/main/java/com/replaymod/pathing/player/AbstractTimelinePlayer.java b/src/main/java/com/replaymod/pathing/player/AbstractTimelinePlayer.java index a495399e..b41ad1ee 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,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; @@ -76,13 +81,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 +109,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..db650995 100644 --- a/src/main/java/com/replaymod/pathing/player/ReplayTimer.java +++ b/src/main/java/com/replaymod/pathing/player/ReplayTimer.java @@ -1,27 +1,28 @@ 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 - +//#if MC>=12100 +//$$ public class ReplayTimer extends RenderTickCounter.Dynamic { +//#else +public class ReplayTimer extends RenderTickCounter { +//#endif //#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 @@ -40,29 +41,27 @@ public class ReplayTimer extends WrappedTimer { //#if MC>=11400 long sysClock //#endif - ) { - copy(this, state); // Save our current state - try { - //#if MC>=11600 - ticksThisFrame = + //#if MC>=12100 + //$$ , boolean tick //#endif - wrapped.beginRenderTick( - //#if MC>=11400 - sysClock - //#endif - ); // Update current state - } finally { - copy(state, this); // Restore our old state - UpdatedCallback.EVENT.invoker().onUpdate(); - } + ) { + //#if MC>=12100 + //$$ if (!tick) return 0; + //#endif + UpdatedCallback.EVENT.invoker().onUpdate(); //#if MC>=11600 return ticksThisFrame; //#endif } - public RenderTickCounter getWrapped() { - return wrapped; - } + //#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/ReplayModRecording.java b/src/main/java/com/replaymod/recording/ReplayModRecording.java index f65e4467..edbba5fe 100644 --- a/src/main/java/com/replaymod/recording/ReplayModRecording.java +++ b/src/main/java/com/replaymod/recording/ReplayModRecording.java @@ -9,12 +9,17 @@ 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; 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; @@ -72,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) -> {}); @@ -93,7 +102,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/recording/handler/ConnectionEventHandler.java b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java index ef71a08b..05230373 100644 --- a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java @@ -153,15 +153,25 @@ 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 MC>=12005 + //$$ 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 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()); } + //#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..ec851793 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; @@ -108,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)); @@ -279,7 +298,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/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/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/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(); } } } diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index 1cd11622..ca4b47ae 100644 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -22,9 +22,12 @@ 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.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; @@ -40,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; @@ -73,7 +85,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 +103,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; @@ -125,7 +114,8 @@ public class PacketListener extends ChannelInboundHandlerAdapter { private ReplayMetaData metaData; - private ChannelHandlerContext context = null; + private final Channel channel; + private Packet currentRawPacket; private final long startTime; private long lastSentPacket; @@ -138,8 +128,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; @@ -199,17 +190,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; @@ -249,22 +229,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); @@ -342,15 +306,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; @@ -363,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(); @@ -386,43 +344,55 @@ public class PacketListener extends ChannelInboundHandlerAdapter { //#else packet = encodeMcPacket(connectionState, (net.minecraft.network.Packet) msg); //#endif + //#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() { - ChannelHandlerContext ctx = context; - if (ctx == null) { - return NetworkState.LOGIN; - } - //#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 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 } - 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 @@ -446,25 +416,6 @@ public class PacketListener extends ChannelInboundHandlerAdapter { } finally { byteBuf.release(); } - } - - 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 } @@ -480,14 +431,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()); } @@ -531,10 +474,21 @@ public class PacketListener extends ChannelInboundHandlerAdapter { return resourcePackRecorder; } - private class DecodedPacketListener extends ChannelInboundHandlerAdapter { + public class DecodedPacketListener extends ChannelDuplexHandler { @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,7 +513,48 @@ 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 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; + } + 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/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/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 78138995..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 @@ -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/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 448cf5d0..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; @@ -112,7 +114,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/hooks/EntityRendererHandler.java b/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java index ee68b87e..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 @@ -93,7 +96,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 @@ -140,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_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_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/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..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 @@ -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,14 @@ public abstract class Mixin_Omnidirectional_Rotation { return ((EntityRendererHandler.IEntityRenderer) getMinecraft().gameRenderer).replayModRender_getHandler(); } + //#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 @Inject(method = "renderWorld", at = @At("HEAD")) //#else @@ -47,6 +60,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 +92,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 +112,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..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 @@ -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,34 @@ 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")) 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..4cca8e87 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -3,9 +3,9 @@ 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.player.ReplayTimer; import com.replaymod.pathing.properties.TimestampProperty; import com.replaymod.render.CameraPathExporter; import com.replaymod.render.EXRWriter; @@ -38,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 @@ -85,13 +84,15 @@ 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 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 @@ -207,7 +208,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; @@ -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; @@ -512,9 +516,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 +567,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 +595,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 9d6ef35c..20db8110 100644 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/FullReplaySender.java @@ -11,16 +11,16 @@ 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; import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; -import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.Channel; 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; @@ -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; @@ -119,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; @@ -140,7 +137,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 @@ -155,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; @@ -164,7 +161,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. */ @@ -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. @@ -271,6 +268,11 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend */ protected boolean hasWorldLoaded; + /** + * Whether we are currently in the middle of a bundle packet. + */ + protected boolean inBundle; + /** * The minecraft instance. */ @@ -303,20 +305,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 +382,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(); @@ -404,7 +403,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 } } } @@ -420,14 +424,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); @@ -473,29 +472,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. @@ -705,6 +681,9 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend //$$ packet.showDeathScreen(), //$$ packet.doLimitedCrafting(), //$$ withSpectatorMode(packet.commonPlayerSpawnInfo()) + //#if MC>=12006 + //$$ , packet.enforcesSecureChat() + //#endif //#else //#if MC>=11800 //$$ packet.hardcore(), @@ -981,32 +960,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 - // 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. @@ -1032,7 +985,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend } 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 @@ -1068,9 +1021,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) { @@ -1081,7 +1031,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend 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; @@ -1089,7 +1039,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend Thread.sleep(10); } - if (terminate) { + if (terminate && !inBundle) { break REPLAY_LOOP; } @@ -1109,7 +1059,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend // 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(); @@ -1120,7 +1070,8 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend } // Process packet - channelRead(ctx, nextPacket.bytes); + if (nextPacket.type == PacketType.Bundle) inBundle = !inBundle; + channel.pipeline().fireChannelRead(Unpooled.wrappedBuffer(nextPacket.bytes)); nextPacket = null; lastTimeStamp = nextTimeStamp; @@ -1131,7 +1082,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 @@ -1167,6 +1118,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend // Restart the replay. hasWorldLoaded = false; + inBundle = false; lastTimeStamp = 0; registry = getPacketTypeRegistry(State.LOGIN); startFromBeginning = false; @@ -1293,16 +1245,13 @@ 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; } 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(); @@ -1331,14 +1280,15 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend } int nextTimeStamp = pd.timestamp; - if (nextTimeStamp > timestamp) { + if (nextTimeStamp > timestamp && !inBundle) { // We are done sending all packets nextPacket = pd; break; } // Process packet - channelRead(ctx, pd.bytes); + 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 // thread before the next packet is read. As such, we need to stall if that was just @@ -1346,7 +1296,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 @@ -1557,6 +1507,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend private final int timestamp; private final byte[] bytes; + private final PacketType type; PacketData(ReplayInputStream in) throws IOException { if (ReplayMod.isMinimalMode()) { @@ -1568,6 +1519,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend } bytes = new byte[length]; IOUtils.readFully(in, bytes); + type = PacketType.UnknownLogin; } else { com.replaymod.replaystudio.PacketData data = in.readPacket(); if (data == null) { @@ -1575,6 +1527,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend } 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. 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/NoGuiScreenshot.java b/src/main/java/com/replaymod/replay/NoGuiScreenshot.java index 69a995b6..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,8 +77,13 @@ public class NoGuiScreenshot { GlStateManager.enableTexture(); //#endif + //#if MC>=12100 + //$$ mc.gameRenderer.renderWorld(RenderTickCounter.ONE); + //#else 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 @@ -87,6 +96,7 @@ public class NoGuiScreenshot { //#endif //#endif //#endif + //#endif mc.getFramebuffer().endWrite(); popMatrix(); diff --git a/src/main/java/com/replaymod/replay/QuickReplaySender.java b/src/main/java/com/replaymod/replay/QuickReplaySender.java index 6641ddc5..f27a67cb 100644 --- a/src/main/java/com/replaymod/replay/QuickReplaySender.java +++ b/src/main/java/com/replaymod/replay/QuickReplaySender.java @@ -14,24 +14,17 @@ 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; import java.io.IOException; import java.util.function.Consumer; -//#if MC>=11200 -import com.replaymod.core.utils.WrappedTimer; -//#endif - -import static com.replaymod.core.versions.MCVer.asMc; +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; @@ -49,7 +42,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 +63,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 +72,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 +92,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() { @@ -194,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 15b14a57..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; @@ -28,12 +27,16 @@ 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; 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; @@ -42,15 +45,13 @@ import net.minecraft.network.ClientConnection; import java.io.IOException; import java.util.*; -//#if MC>=12003 -//$$ import net.minecraft.client.resource.server.ServerResourcePackManager; +//#if MC>=12006 +//$$ import net.minecraft.network.handler.NetworkStateTransitions; +//$$ import net.minecraft.network.state.LoginStates; //#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; +//#if MC>=12003 +//$$ import net.minecraft.client.resource.server.ServerResourcePackManager; //#endif //#if MC>=12000 @@ -122,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; @@ -129,6 +131,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 +184,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 @@ -259,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 @@ -319,22 +323,42 @@ public class ReplayHandler { //$$ ChannelOutboundHandlerAdapter dummyHandler = new ChannelOutboundHandlerAdapter(); //$$ channel = new EmbeddedChannel(dummyHandler); //$$ channel.pipeline().remove(dummyHandler); + //$$ channel.pipeline().removeLast(); + //#endif + channel.pipeline().addFirst("ReplayModReplay_head", new DropOutboundMessagesHandler()); + + 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)); + //#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 + //#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)); @@ -355,6 +379,7 @@ public class ReplayHandler { , it -> {} //#endif )); + //#endif //#if MC>=11400 ((MinecraftAccessor) mc).setConnection(networkManager); @@ -459,6 +484,8 @@ public class ReplayHandler { targetCameraPosition = null; } + channel.pipeline().replace(PACKET_HANDLER_NAME, PACKET_HANDLER_NAME, quickMode ? quickReplaySender : fullReplaySender); + if (quickMode) { quickReplaySender.register(); quickReplaySender.restart(); @@ -647,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(); @@ -686,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 @@ -709,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 @@ -811,23 +866,24 @@ 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 + 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 + } + } } 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/MixinCamera.java b/src/main/java/com/replaymod/replay/mixin/MixinCamera.java index 7c1166d6..2970f39b 100644 --- a/src/main/java/com/replaymod/replay/mixin/MixinCamera.java +++ b/src/main/java/com/replaymod/replay/mixin/MixinCamera.java @@ -13,9 +13,22 @@ 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 + //#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( method = "renderWorld", at = @At( @@ -24,9 +37,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/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/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java b/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java index da17ba14..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; @@ -153,8 +154,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); @@ -165,9 +170,10 @@ public class GuiKeyframeTimeline extends AbstractGuiTimeline=11700 //$$ RenderSystem.setShader(GameRenderer::getRenderTypeLinesShader); @@ -178,7 +184,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 50782934..35af5819 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; @@ -108,7 +109,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()); @@ -242,17 +247,27 @@ 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); + emitLine(new MatrixStack(), buffer, Vector3f.sub(pos1, view, null), Vector3f.sub(pos2, view, null), color); //#if MC>=11700 //$$ RenderSystem.setShader(GameRenderer::getRenderTypeLinesShader); //$$ 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 @@ -280,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(); @@ -299,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(); } @@ -318,10 +343,14 @@ 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); + emitLine(new MatrixStack(), buffer, new Vector3f(0, 0, 0), new Vector3f(0, 0, 2), 0x00ff00aa); //#if MC>=11700 //$$ RenderSystem.applyModelViewMatrix(); @@ -330,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); @@ -340,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(); @@ -384,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/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/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 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/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/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", diff --git a/version.txt b/version.txt index 55cc4f6a..58654fe7 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.6.15 +2.6.16 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/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.11/mapping.txt b/versions/1.20.6/.gitkeep similarity index 100% rename from versions/1.11/mapping.txt rename to versions/1.20.6/.gitkeep 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()); + } + } +} diff --git a/versions/1.20.2/logs/latest.log b/versions/1.21/.gitkeep similarity index 100% rename from versions/1.20.2/logs/latest.log rename to versions/1.21/.gitkeep 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; + } +} 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 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 diff --git a/versions/mapping-forge-1.11-1.10.2.txt b/versions/mapping-forge-1.11-1.10.2.txt new file mode 100644 index 00000000..e69de29b 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 97% rename from versions/1.9.4/mapping.txt rename to versions/mapping-forge-1.9.4-1.8.9.txt index 0538db5a..9e250f8b 100644 --- a/versions/1.9.4/mapping.txt +++ b/versions/mapping-forge-1.9.4-1.8.9.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