Release 2.6.16

This commit is contained in:
Jonas Herzig
2024-07-10 19:37:17 +02:00
84 changed files with 1346 additions and 1348 deletions

BIN
.gitignore vendored

Binary file not shown.

3
.gitmodules vendored
View File

@@ -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

View File

@@ -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'

348
build.gradle.kts Normal file
View File

@@ -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<String>()
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) }

View File

@@ -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

View File

@@ -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

2
jGui

Submodule jGui updated: bd41e57af0...d2626659b0

1
libs/ReplayStudio Submodule

Submodule libs/ReplayStudio added at 1e96fda605

View File

@@ -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<String, Any> {
.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"))
}

View File

@@ -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"
}
}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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

View File

@@ -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();

View File

@@ -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

View File

@@ -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();

View File

@@ -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
}

View File

@@ -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<Payload> ID = new CustomPayload.Id<>(PLUGIN_CHANNEL);
//$$ public static final PacketCodec<? super PacketByteBuf, Payload> 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<? extends CustomPayload> getId() {
//$$ return ID;
//$$ }
//$$ }
//#endif
}

View File

@@ -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);
}

View File

@@ -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
}
}

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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
}
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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<Void> 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);

View File

@@ -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<UpdatedCallback> EVENT = Event.create((listeners) ->

View File

@@ -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);

View File

@@ -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();

View File

@@ -73,7 +73,12 @@ public class RecordingEventHandler extends EventRegistrations {
private final PacketListener packetListener;
private Double lastX, lastY, lastZ;
private final List<ItemStack> 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<ItemStack> 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

View File

@@ -0,0 +1 @@
// 1.20.6 and above

View File

@@ -0,0 +1 @@
// 1.20.6 and above

View File

@@ -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();
}
}
}

View File

@@ -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<NetworkState.PacketHandler<?>> key = ClientConnection.CLIENTBOUND_PROTOCOL_KEY;
//$$ return ctx.channel().attr(key).get().getState();
//$$ return channel.attr(key).get().getState();
//#else
AttributeKey<NetworkState> 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);
}
}
}

View File

@@ -101,7 +101,7 @@ public class EXRWriter implements FrameConsumer<BitmapFrame> {
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<BitmapFrame> {
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) {

View File

@@ -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

View File

@@ -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<R> {

View File

@@ -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<ODSOpenGlFrame> {
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;

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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",

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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;

View File

@@ -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.

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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<Void> 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

View File

@@ -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
}
}
}

View File

@@ -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();
}

View File

@@ -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
}
}

View File

@@ -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();
}
}

View File

@@ -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<GuiKeyframeTimeline
final int color = 0xff0000ff;
Tessellator tessellator = Tessellator.getInstance();
//#if MC>=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<GuiKeyframeTimeline
// And finally another vertical bit (the timeline is already crammed enough, so only the border)
Vector2f p4 = new Vector2f(keyframeTimelineLeft + positionXKeyframeTimeline, keyframeTimelineTop + BORDER_TOP);
emitLine(buffer, p1, p2, color);
emitLine(buffer, p2, p3, color);
emitLine(buffer, p3, p4, color);
MatrixStack matrixStack = renderer.getMatrixStack();
emitLine(matrixStack, buffer, p1, p2, color);
emitLine(matrixStack, buffer, p2, p3, color);
emitLine(matrixStack, buffer, p3, p4, color);
//#if MC>=11700
//$$ RenderSystem.setShader(GameRenderer::getRenderTypeLinesShader);
@@ -178,7 +184,13 @@ public class GuiKeyframeTimeline extends AbstractGuiTimeline<GuiKeyframeTimeline
pushScissorState();
setScissorDisabled();
GL11.glLineWidth(2);
//#if MC>=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);

View File

@@ -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();
}

View File

@@ -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": [

View File

@@ -7,7 +7,8 @@
"Mixin_ContextualKeyBindings",
//#if MC>=11400
"AbstractButtonWidgetAccessor",
"MixinGameRenderer",
"Mixin_PostRenderWorldCalback",
"Mixin_PreRenderHandCallback",
"Mixin_InjectDynamicResourcePacks",
//#endif
//#if MC>=11400

View File

@@ -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

View File

@@ -14,6 +14,9 @@
"Mixin_ChromaKeyColorSky",
"Mixin_ChromaKeyDisableFog",
"Mixin_ChromaKeyForceSky",
//#if MC>=12100
//$$ "Mixin_FakeSystemTimeUniforms_Iris",
//#endif
"Mixin_ForceChunkLoading",
"Mixin_HideNameTags",
"Mixin_HideNameTags_LivingEntity",

View File

@@ -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",

View File

@@ -1 +1 @@
2.6.15
2.6.16

View File

@@ -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,

View File

@@ -0,0 +1 @@
essential.defaults.loom.mappings=de.oceanlabs.mcp:mcp_snapshot:20190719-1.14.3@zip

View File

@@ -0,0 +1 @@
essential.defaults.loom.mappings=net.fabricmc:yarn:1.18.1+build.1:v2

View File

@@ -0,0 +1 @@
essential.defaults.loom.mappings=net.fabricmc:yarn:1.18.2+build.1:v2

View File

@@ -0,0 +1 @@
essential.defaults.loom.mappings=net.fabricmc:yarn:1.19.2+build.28:v2

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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<T extends PacketListener> {
@Accessor
@Nonnull
NetworkState<T> getState();
}

View File

@@ -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 <T> void write(PacketByteBuf buf, Registry<T> registry, Codec<T> codec) {
buf.writeString(registry.getKey().getValue().toString());
buf.writeVarInt(registry.size());
for (Map.Entry<RegistryKey<T>, T> entry : registry.getEntrySet()) {
buf.writeString(entry.getKey().getValue().toString());
buf.writeNbt(codec.encodeStart(NbtOps.INSTANCE, entry.getValue()).getOrThrow());
}
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1 @@
essential.defaults.loom.forge=net.minecraftforge:forge:1.8.9-11.15.1.1722

View File

@@ -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

View File

View File

@@ -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