Release 2.6.0

This commit is contained in:
Jonas Herzig
2021-07-31 16:01:48 +02:00
237 changed files with 5894 additions and 5681 deletions

2
Jenkinsfile vendored
View File

@@ -13,7 +13,7 @@ pipeline {
[$class: 'ArbitraryFileCache', excludes: '', includes: '**/*', path: '.gradle/user_home/wrapper'], [$class: 'ArbitraryFileCache', excludes: '', includes: '**/*', path: '.gradle/user_home/wrapper'],
[$class: 'ArbitraryFileCache', excludes: '', includes: '**/*', path: '.gradle/loom-cache'], [$class: 'ArbitraryFileCache', excludes: '', includes: '**/*', path: '.gradle/loom-cache'],
]) { ]) {
sh './gradlew :jGui:1.7.10:setupCIWorkspace :1.7.10:setupCIWorkspace' // sh './gradlew :jGui:1.7.10:setupCIWorkspace :1.7.10:setupCIWorkspace'
sh './gradlew --parallel' sh './gradlew --parallel'
} }
archiveArtifacts 'versions/*/build/libs/*.jar' archiveArtifacts 'versions/*/build/libs/*.jar'

View File

@@ -7,8 +7,8 @@ Make sure your sub-projects are up-to-date: `git submodule update --init --recur
For compiling 1.7.10, you must run `./gradlew :jGui:1.7.10:setupDecompWorkspace :1.7.10:setupDecompWorkspace` once after the initial clone. This may take quite some time. For compiling 1.7.10, you must run `./gradlew :jGui:1.7.10:setupDecompWorkspace :1.7.10:setupDecompWorkspace` once after the initial clone. This may take quite some time.
### No IDE ### No IDE
You can build the mod by running `./gradlew build` (or just `./gradlew shadowJar`). You can then find the final jar files in `versions/$MCVERSION/build/libs/`. You can build the mod by running `./gradlew build` (or just `./gradlew bundleJar`). You can then find the final jar files in `versions/$MCVERSION/build/libs/`.
You can also build single versions by running `./gradlew :1.8:build` (or just `./gradlew :1.8:shadowJar`) (builds the MC 1.8 version). You can also build single versions by running `./gradlew :1.8:build` (or just `./gradlew :1.8:bundleJar`) (builds the MC 1.8 version).
### IntelliJ ### IntelliJ
Ensure you have at least IDEA 2020.1. Ensure you have at least IDEA 2020.1.
@@ -30,55 +30,9 @@ The `master` branch is solely to be used for the `version.json` file that contai
used by the clients to check for updates of this mod. used by the clients to check for updates of this mod.
### The Preprocessor ### The Preprocessor
To support multiple Minecraft versions with the ReplayMod, a [JCP](https://github.com/raydac/java-comment-preprocessor)-inspired preprocessor is used: To support multiple Minecraft versions with the ReplayMod, a [JCP](https://github.com/raydac/java-comment-preprocessor)-inspired preprocessor is used.
```java It has by now acquired a lot more sophisticated features to make it as noninvasive as possible.
//#if MC>=11200 Please read the [preprocessor's README](https://github.com/ReplayMod/preprocessor/blob/master/README.md) to understand how it works.
// This is the block for MC >= 1.12.0
category.addDetail(name, callable::call);
//#else
//$$ // This is the block for MC < 1.12.0
//$$ category.setDetail(name, callable::call);
//#endif
```
Any comments starting with `//$$` will automatically be introduced / removed based on the surrounding condition(s).
Normal comments are left untouched. The `//#else` branch is optional.
Conditions can be nested arbitrarily but their indention shall always be equal to the indention of the code at the `//#if` line.
The `//$$` shall be aligned with the inner-most `//#if`.
```java
//#if MC>=10904
public CPacketResourcePackStatus makeStatusPacket(String hash, Action action) {
//#if MC>=11002
return new CPacketResourcePackStatus(action);
//#else
//$$ return new CPacketResourcePackStatus(hash, action);
//#endif
}
//#else
//$$ public C19PacketResourcePackStatus makeStatusPacket(String hash, Action action) {
//$$ return new C19PacketResourcePackStatus(hash, action);
//$$ }
//#endif
```
Code for the more recent MC version shall be placed in the first branch of the if-else-construct.
Version-dependent import statements shall be placed separately from and after all other imports.
Common version dependent code (including the fml and forge event bus) are available as static methods/fields in the `MCVer` class.
The source code in `src/main` is generally for the most recent Minecraft version and is automatically passed through the
preprocessor when any of the other versions are built (gradle projects `:1.8`, `:1.8.9`, etc.).
Do **NOT** edit any of the code in `versions/$MCVERSION/build/` as it is automatically generated and will be overwritten without warning.
You can change the version of the code in `src/main` if you wish to develop/debug with another version of Minecraft:
```bash
./gradle :1.9.4:setCoreVersion # switches all sources in src/main to 1.9.4
```
If you do so, you'll also have to refresh the project in your IDE.
Make sure to switch back to the most recent branch before committing!
Care should also be taken that switching to a different branch and back doesn't introduce any uncommitted changes (e.g. due to different indention, especially in case of nested conditions).
Some files may use the same preprocessor with different keywords.
If required, more file extensions and keywords can be added in the `preprocess` block of the `versions/common.gradle` script.
### Versioning ### Versioning
The ReplayMod uses the versioning scheme outlined [here](http://mcforge.readthedocs.io/en/latest/conventions/versioning/) The ReplayMod uses the versioning scheme outlined [here](http://mcforge.readthedocs.io/en/latest/conventions/versioning/)

View File

@@ -21,7 +21,7 @@ buildscript {
if (!fabric) { if (!fabric) {
maven { maven {
name = "forge" name = "forge"
url = "https://files.minecraftforge.net/maven" url = "https://maven.minecraftforge.net"
} }
} }
maven { maven {
@@ -32,21 +32,21 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.2' classpath 'gradle.plugin.com.github.jengelman.gradle.plugins:shadow:7.0.0'
if (fabric) { if (fabric) {
classpath 'fabric-loom:fabric-loom.gradle.plugin:0.5-SNAPSHOT' classpath 'fabric-loom:fabric-loom.gradle.plugin:0.8-SNAPSHOT'
} else if (mcVersion >= 11400) { } else if (mcVersion >= 11400) {
classpath('net.minecraftforge.gradle:ForgeGradle:3.+'){ 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 exclude group: 'trove', module: 'trove' // preprocessor/idea requires more recent one
} }
} else if (mcVersion >= 10800) { } else if (mcVersion >= 10800) {
classpath('com.github.ReplayMod:ForgeGradle:' + ( classpath('com.github.ReplayMod:ForgeGradle:' + (
mcVersion >= 11200 ? 'b64de9c' : // FG 2.3 mcVersion >= 11200 ? '34ab703' : // FG 2.3
mcVersion >= 10904 ? '5bb7a53' : // FG 2.2 mcVersion >= 10904 ? '5d1e8d8' : // FG 2.2
'fc1eabc' // FG 2.1 'd1a7165' // FG 2.1
) + ':all') ) + ':all')
} else { } else {
classpath 'com.github.ReplayMod:ForgeGradle:5fca6853:all' // FG 1.2 classpath 'com.github.ReplayMod:ForgeGradle:a8a9e0ca:all' // FG 1.2
} }
} }
} }
@@ -102,12 +102,16 @@ preprocess {
".vert": PreprocessTask.DEFAULT_KEYWORDS, ".vert": PreprocessTask.DEFAULT_KEYWORDS,
".frag": 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}") def mcVersionStr = "${(int)(mcVersion/10000)}.${(int)(mcVersion/100)%100}" + (mcVersion%100==0 ? '' : ".${mcVersion%100}")
sourceCompatibility = 1.8 sourceCompatibility = targetCompatibility = mcVersion >= 11700 ? 16 : 1.8
targetCompatibility = 1.8 tasks.withType(JavaCompile).configureEach {
options.release = mcVersion >= 11700 ? 16 : 8
}
if (mcVersion >= 11400) { if (mcVersion >= 11400) {
sourceSets { sourceSets {
@@ -122,7 +126,9 @@ archivesBaseName = "replaymod"
if (FABRIC) { if (FABRIC) {
minecraft { minecraft {
refmapName = 'mixins.replaymod.refmap.json' refmapName = 'mixins.replaymod.refmap.json'
autoGenIDERuns = true runConfigs.all {
ideConfigGenerated = true
}
} }
} else { } else {
minecraft { minecraft {
@@ -197,6 +203,12 @@ repositories {
name = "fabric" name = "fabric"
url = "https://maven.fabricmc.net/" url = "https://maven.fabricmc.net/"
} }
maven {
url 'https://maven.terraformersmc.com/releases/'
content {
includeGroup 'com.terraformersmc'
}
}
maven { maven {
url 'https://jitpack.io' url 'https://jitpack.io'
content { content {
@@ -208,17 +220,17 @@ repositories {
configurations { configurations {
// Include dep in fat jar without relocation and, when forge supports it, without exploding (TODO) // Include dep in fat jar without relocation and, when forge supports it, without exploding (TODO)
shade shade
compile.extendsFrom shade implementation.extendsFrom shade
// Include dep in fat jar with relocation and minimization // Include dep in fat jar with relocation and minimization
shadow shadow
compile.extendsFrom shadow implementation.extendsFrom shadow
} }
def shadeExclusions = { def shadeExclusions = {
// Cannot just add these to the shade configuration because they'd be inherited by the compile configuration then // 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-jdk5'
exclude group: 'com.google.guava', module: 'guava' // provided by MC exclude group: 'com.google.guava', module: 'guava' // provided by MC
exclude group: 'com.google.code.gson', module: 'gson' // provided by MC exclude group: 'com.google.code.gson', module: 'gson' // provided by MC (or manually bundled for 1.11.2 and below)
} }
dependencies { dependencies {
@@ -229,6 +241,8 @@ dependencies {
11601: '1.16.1', 11601: '1.16.1',
11603: '1.16.3', 11603: '1.16.3',
11604: '1.16.4', 11604: '1.16.4',
11700: '1.17',
11701: '1.17.1',
][mcVersion] ][mcVersion]
mappings 'net.fabricmc:yarn:' + [ mappings 'net.fabricmc:yarn:' + [
11404: '1.14.4+build.16', 11404: '1.14.4+build.16',
@@ -236,20 +250,18 @@ dependencies {
11601: '1.16.1+build.17:v2', 11601: '1.16.1+build.17:v2',
11603: '1.16.3+build.1:v2', 11603: '1.16.3+build.1:v2',
11604: '1.16.4+build.6:v2', 11604: '1.16.4+build.6:v2',
11700: '1.17+build.13:v2',
11701: '1.17.1+build.29:v2',
][mcVersion] ][mcVersion]
modCompile 'net.fabricmc:fabric-loader:' + [ modImplementation 'net.fabricmc:fabric-loader:0.11.6'
11404: '0.7.8+build.189',
11502: '0.7.8+build.189',
11601: '0.8.8+build.202',
11603: '0.9.1+build.205',
11604: '0.10.6+build.214',
][mcVersion]
def fabricApiVersion = [ def fabricApiVersion = [
11404: '0.4.3+build.247-1.14', 11404: '0.4.3+build.247-1.14',
11502: '0.5.1+build.294-1.15', 11502: '0.5.1+build.294-1.15',
11601: '0.14.0+build.371-1.16', 11601: '0.14.0+build.371-1.16',
11603: '0.17.1+build.394-1.16', 11603: '0.17.1+build.394-1.16',
11604: '0.25.1+build.416-1.16', 11604: '0.25.1+build.416-1.16',
11700: '0.36.0+1.17',
11701: '0.37.1+1.17',
][mcVersion] ][mcVersion]
def fabricApiModules = [ def fabricApiModules = [
"api-base", "api-base",
@@ -260,8 +272,11 @@ dependencies {
if (mcVersion >= 11600) { if (mcVersion >= 11600) {
fabricApiModules.add("key-binding-api-v1") fabricApiModules.add("key-binding-api-v1")
} }
if (mcVersion >= 11700) {
fabricApiModules.add("networking-api-v1")
}
fabricApiModules.each { module -> fabricApiModules.each { module ->
modCompile fabricApi.module("fabric-$module", fabricApiVersion) modImplementation fabricApi.module("fabric-$module", fabricApiVersion)
include fabricApi.module("fabric-$module", fabricApiVersion) include fabricApi.module("fabric-$module", fabricApiVersion)
} }
} }
@@ -302,6 +317,11 @@ dependencies {
} }
} }
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' shadow 'com.github.javagl.JglTF:jgltf-model:3af6de4'
if (FABRIC) { if (FABRIC) {
@@ -312,7 +332,7 @@ dependencies {
shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8' shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8'
shadow "com.github.ReplayMod:ReplayStudio:a1f82a7", shadeExclusions shadow "com.github.ReplayMod:ReplayStudio:a67fb11", shadeExclusions
implementation(jGui){ implementation(jGui){
transitive = false // FG 1.2 puts all MC deps into the compile configuration and we don't want to shade those transitive = false // FG 1.2 puts all MC deps into the compile configuration and we don't want to shade those
@@ -320,17 +340,22 @@ dependencies {
shadow 'com.github.ReplayMod:lwjgl-utils:27dcd66' shadow 'com.github.ReplayMod:lwjgl-utils:27dcd66'
if (FABRIC) { if (FABRIC) {
if (mcVersion >= 11602) { if (mcVersion >= 11700) {
// TODO re-add to runtime once available modImplementation 'com.terraformersmc:modmenu:2.0.0-beta.7'
modCompileOnly 'io.github.prospector:modmenu:1.14.0+build.24' } else if (mcVersion >= 11602) {
modImplementation 'com.terraformersmc:modmenu:1.16.8'
} else if (mcVersion >= 11600) { } else if (mcVersion >= 11600) {
modCompile 'io.github.prospector:modmenu:1.14.0+build.24' modImplementation 'io.github.prospector:modmenu:1.14.0+build.24'
} else { } else {
modCompile 'io.github.prospector.modmenu:ModMenu:1.6.2-92' modImplementation 'io.github.prospector.modmenu:ModMenu:1.6.2-92'
} }
} }
testCompile 'junit:junit:4.11' if (mcVersion >= 11600) {
modCompileOnly 'com.github.IrisShaders:Iris:1.0.0'
}
testImplementation 'junit:junit:4.11'
} }
if (mcVersion <= 10710) { if (mcVersion <= 10710) {
@@ -422,8 +447,12 @@ task configureRelocation() {
} }
} }
tasks.removeByName('shadowJar') // we want to base our shadowed jar on the reobfJar output, not the sourceSet output // we want to base our shadowed jar on the reobfJar output, not the sourceSet output
task shadowJar(type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { // 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() } from { (FABRIC ? tasks.remapJar : tasks.jar).archiveFile.get() }
dependsOn { FABRIC ? tasks.remapJar : (mcVersion >= 10800 ? tasks.reobfJar : tasks.reobf) } dependsOn { FABRIC ? tasks.remapJar : (mcVersion >= 10800 ? tasks.reobfJar : tasks.reobf) }
@@ -469,7 +498,7 @@ task shadowJar(type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar)
exclude(dependency('.*spongepowered:mixin:.*')) exclude(dependency('.*spongepowered:mixin:.*'))
} }
} }
tasks.assemble.dependsOn tasks.shadowJar tasks.assemble.dependsOn tasks.bundleJar
jar { jar {
classifier = 'raw' classifier = 'raw'
@@ -484,6 +513,15 @@ jar {
'FMLAT': 'replaymod_at.cfg' '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 { processResources {

View File

@@ -358,7 +358,8 @@ There are **7 Encoding Presets** you can choose from:
While these video files are of perfect quality, most **non-FFmpeg-based video players and video editing software** (e.g. QuickTime Player, Sony Vegas and Adobe Premiere) can't play these videos. Therefore, you should instead use the **MP4 - High Quality** preset in most cases. While these video files are of perfect quality, most **non-FFmpeg-based video players and video editing software** (e.g. QuickTime Player, Sony Vegas and Adobe Premiere) can't play these videos. Therefore, you should instead use the **MP4 - High Quality** preset in most cases.
- **PNG Sequence** - **PNG Sequence**
Exports the sequence as individual frames in the **PNG Format**. Exports the sequence as individual frames in the **PNG Format**.
**Warning:** This can create a huge amount of files, so make sure to save them in a separate folder. The images are of perfect quality.
Depth map images are 32-bit float encoded in the 8-bit components in BGRA order and will need some kind of post-processing to be useful in most editors.
- **OpenEXR Sequence** (Minecraft 1.14 and above) - **OpenEXR Sequence** (Minecraft 1.14 and above)
Exports the sequence as individual frames in the **OpenEXR Format**. Exports the sequence as individual frames in the **OpenEXR Format**.
The images are of perfect quality and may contain The images are of perfect quality and may contain

Binary file not shown.

View File

@@ -1,6 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=7bdbad1e4f54f13c8a78abc00c26d44dd8709d4aedb704d913fb1bb78ac025dc distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

18
gradlew vendored
View File

@@ -1,5 +1,21 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
############################################################################## ##############################################################################
## ##
## Gradle start up script for UN*X ## Gradle start up script for UN*X
@@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS="" DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD="maximum"

18
gradlew.bat vendored
View File

@@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem http://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS= set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome

2
jGui

Submodule jGui updated: 6641836321...71d361746e

View File

@@ -2,8 +2,8 @@ import groovy.json.JsonOutput
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
plugins { plugins {
id("fabric-loom") version "0.5-SNAPSHOT" apply false id("fabric-loom") version "0.8-SNAPSHOT" apply false
id("com.replaymod.preprocess") version "24ac087" id("com.replaymod.preprocess") version "123fb7a"
id("com.github.hierynomus.license") version "0.15.0" id("com.github.hierynomus.license") version "0.15.0"
} }
@@ -25,12 +25,7 @@ if (gitDescribe().endsWith("*")) {
group = "com.replaymod" group = "com.replaymod"
// Loom tries to find the active mixin version by recursing up to the root project and checking each project's val bundleJar by tasks.creating(Copy::class) {
// compileClasspath and build script classpath (in that order). Since we've loom in our root project's classpath,
// loom will only find it after checking the root project's compileClasspath (which doesn't exist by default).
configurations.register("compileClasspath")
val shadowJar by tasks.creating(Copy::class) {
into("$buildDir/libs") into("$buildDir/libs")
} }
@@ -42,10 +37,10 @@ subprojects {
} }
afterEvaluate { afterEvaluate {
val projectShadowJar = project.tasks.findByName("shadowJar") val projectBundleJar = project.tasks.findByName("bundleJar")
if (projectShadowJar != null && projectShadowJar.hasProperty("archivePath") && project.name != "core") { if (projectBundleJar != null && projectBundleJar.hasProperty("archivePath") && project.name != "core") {
shadowJar.dependsOn(projectShadowJar) bundleJar.dependsOn(projectBundleJar)
shadowJar.from(projectShadowJar.withGroovyBuilder { getProperty("archivePath") }) bundleJar.from(projectBundleJar.withGroovyBuilder { getProperty("archivePath") })
} }
} }
} }
@@ -178,36 +173,41 @@ val doRelease by tasks.registering {
} }
} }
defaultTasks("shadowJar") defaultTasks("bundleJar")
preprocess { preprocess {
"1.16.4"(11604, "yarn") { val mc11701 = createNode("1.17.1", 11701, "yarn")
"1.16.1"(11601, "yarn") { val mc11700 = createNode("1.17", 11700, "yarn")
"1.15.2"(11502, "yarn") { val mc11604 = createNode("1.16.4", 11604, "yarn")
"1.14.4"(11404, "yarn", file("versions/mapping-fabric-1.15.2-1.14.4.txt")) { val mc11601 = createNode("1.16.1", 11601, "yarn")
"1.14.4-forge"(11404, "srg", file("versions/mapping-1.14.4-fabric-forge.txt")) { val mc11502 = createNode("1.15.2", 11502, "yarn")
"1.12.2"(11202, "srg", file("versions/1.14.4-forge/mapping.txt")) { val mc11404 = createNode("1.14.4", 11404, "yarn")
"1.12.1"(11201, "srg") { val mc11404Forge = createNode("1.14.4-forge", 11404, "srg")
"1.12"(11200, "srg") { val mc11202 = createNode("1.12.2", 11202, "srg")
"1.11.2"(11102, "srg", file("versions/1.12/mapping.txt")) { val mc11201 = createNode("1.12.1", 11201, "srg")
"1.11"(11100, "srg", file("versions/1.11.2/mapping.txt")) { val mc11200 = createNode("1.12", 11200, "srg")
"1.10.2"(11002, "srg", file("versions/1.11/mapping.txt")) { val mc11102 = createNode("1.11.2", 11102, "srg")
"1.9.4"(10904, "srg") { val mc11100 = createNode("1.11", 11100, "srg")
"1.8.9"(10809, "srg", file("versions/1.9.4/mapping.txt")) { val mc11002 = createNode("1.10.2", 11002, "srg")
"1.8"(10800, "srg", file("versions/1.8.9/mapping.txt")) { val mc10904 = createNode("1.9.4", 10904, "srg")
"1.7.10"(10710, "srg", file("versions/1.8/mapping.txt")) val mc10809 = createNode("1.8.9", 10809, "srg")
} val mc10800 = createNode("1.8", 10800, "srg")
} val mc10710 = createNode("1.7.10", 10710, "srg")
}
} mc11701.link(mc11700)
} mc11700.link(mc11604, file("versions/mapping-fabric-1.17-1.16.4.txt"))
} mc11604.link(mc11601)
} mc11601.link(mc11502)
} 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"))
} 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"))
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"))
} }

View File

@@ -19,7 +19,7 @@ pluginManagement {
} }
val jGuiVersions = listOf( val jGuiVersions = listOf(
"1.7.10", // "1.7.10",
"1.8", "1.8",
"1.8.9", "1.8.9",
"1.9.4", "1.9.4",
@@ -28,10 +28,12 @@ val jGuiVersions = listOf(
"1.14.4", "1.14.4",
"1.15.2", "1.15.2",
"1.16.1", "1.16.1",
"1.16.4" "1.16.4",
"1.17",
"1.17.1",
) )
val replayModVersions = listOf( val replayModVersions = listOf(
"1.7.10", // "1.7.10",
"1.8", "1.8",
"1.8.9", "1.8.9",
"1.9.4", "1.9.4",
@@ -45,7 +47,9 @@ val replayModVersions = listOf(
"1.14.4", "1.14.4",
"1.15.2", "1.15.2",
"1.16.1", "1.16.1",
"1.16.4" "1.16.4",
"1.17",
"1.17.1",
) )
rootProject.buildFileName = "root.gradle.kts" rootProject.buildFileName = "root.gradle.kts"

View File

@@ -1,185 +1 @@
//#if MC<11400 // 1.12.2 and below
//$$ package com.replaymod.compat.bettersprinting;
//$$
//$$ import com.replaymod.replay.ReplayModReplay;
//$$ import com.replaymod.replay.events.ReplayChatMessageEvent;
//$$ import net.minecraft.client.Minecraft;
//$$ import net.minecraft.client.multiplayer.PlayerControllerMP;
//$$ import net.minecraft.entity.Entity;
//$$ import net.minecraft.entity.player.EntityPlayer;
//$$ import net.minecraftforge.client.event.GuiOpenEvent;
//$$ import net.minecraftforge.common.MinecraftForge;
//$$
//#if MC>=10904
//$$ import net.minecraft.block.state.IBlockState;
//$$ import net.minecraft.util.SoundCategory;
//$$ import net.minecraft.util.SoundEvent;
//$$ import net.minecraft.util.math.BlockPos;
//$$ import net.minecraft.world.IWorldEventListener;
//$$ import net.minecraft.world.World;
//$$
//$$ import javax.annotation.Nullable;
//#else
//#if MC>= 10800
//$$ import net.minecraft.util.BlockPos;
//#endif
//$$ import net.minecraft.world.IWorldAccess;
//#endif
//$$
//#if MC>=10800
//$$ import net.minecraftforge.fml.common.Loader;
//$$ import net.minecraftforge.fml.common.ModContainer;
//$$ import net.minecraftforge.fml.common.eventhandler.EventPriority;
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//$$ import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion;
//$$ import net.minecraftforge.fml.common.versioning.Restriction;
//$$ import net.minecraftforge.fml.common.versioning.VersionRange;
//#else
//$$ import cpw.mods.fml.common.Loader;
//$$ import cpw.mods.fml.common.ModContainer;
//$$ import cpw.mods.fml.common.eventhandler.EventPriority;
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//$$ import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
//$$ import cpw.mods.fml.common.versioning.Restriction;
//$$ import cpw.mods.fml.common.versioning.VersionRange;
//#endif
//$$
//$$ import java.util.Collections;
//$$
//$$ import static com.replaymod.compat.ReplayModCompat.LOGGER;
//$$ import static com.replaymod.core.versions.MCVer.*;
//$$
//$$ /**
//$$ * Old Better Sprinting versions replace the vanilla player with their own, overridden instance (replacing the camera entity).
//$$ *
//$$ * See: https://github.com/chylex/Better-Sprinting/blob/1.8/src/main/java/chylex/bettersprinting/client/player/impl/LogicImplOverride.java
//$$ */
//$$ public class DisableBetterSprinting {
//$$ private static final VersionRange OLD_VERSION = VersionRange.newRange(null,
//$$ Collections.singletonList(new Restriction(null, false, new DefaultArtifactVersion("2.0.0"), false)));
//$$ private static final String LOGIC_CLASS_NAME = "chylex.bettersprinting.client.player.impl.LogicImplOverride";
//$$ private static final String CONTROLLER_OVERRIDE_CLASS_NAME = LOGIC_CLASS_NAME + "$PlayerControllerMPOverride";
//$$
//$$ public static void register() {
//$$ Loader.instance().getModList().stream()
//$$ .filter(mod -> mod.getModId().equalsIgnoreCase("bettersprinting"))
//$$ .findFirst()
//$$ .map(ModContainer::getProcessedVersion).filter(OLD_VERSION::containsVersion)
//$$ .ifPresent($_ -> MinecraftForge.EVENT_BUS.register(new DisableBetterSprinting()));
//$$ }
//$$
//$$ private DisableBetterSprinting() {
//$$ LOGGER.info("BetterSprinting workaround enabled");
//$$ }
//$$
//$$ private final Minecraft mc = Minecraft.getMinecraft();
//$$ private PlayerControllerMP originalController;
//$$ private BetterSprintingWorldAccess worldAccessHook = new BetterSprintingWorldAccess();
//$$
//$$ @SubscribeEvent(priority = EventPriority.HIGH)
//$$ public void beforeGuiOpenEvent(GuiOpenEvent event) {
//$$ if (ReplayModReplay.instance.getReplayHandler() != null && mc.world != null) {
//$$ // During replay, get ready to revert BetterSprinting's overwritten playerController
//$$ originalController = mc.playerController;
//#if MC>=10904
//$$ mc.world.addEventListener(worldAccessHook);
//#else
//$$ mc.theWorld.addWorldAccess(worldAccessHook);
//#endif
//$$ }
//$$ }
//$$
//$$ @SubscribeEvent(priority = EventPriority.LOW)
//$$ public void afterGuiOpenEvent(GuiOpenEvent event) {
//$$ if (ReplayModReplay.instance.getReplayHandler() != null && mc.world != null) {
//#if MC>=10904
//$$ mc.world.addEventListener(worldAccessHook);
//#else
//$$ mc.theWorld.addWorldAccess(worldAccessHook);
//#endif
//$$ }
//$$ }
//$$
//$$ @SubscribeEvent
//$$ public void onReplayChatMessage(ReplayChatMessageEvent event) {
//$$ // Suppress this message if it's the Better Sprinting warning message
//$$ for (StackTraceElement elem : Thread.currentThread().getStackTrace()) {
//$$ if (LOGIC_CLASS_NAME.equals(elem.getClassName())) {
//$$ LOGGER.info("BetterSprinting warning message suppressed.");
//$$ event.setCanceled(true);
//$$ return;
//$$ }
//$$ }
//$$ }
//$$
//$$ private class BetterSprintingWorldAccess
//#if MC>=10904
//$$ implements IWorldEventListener
//#else
//$$ implements IWorldAccess
//#endif
//$$ {
//$$ @Override
//#if MC>=10800
//$$ public void onEntityRemoved(Entity entityIn) {
//#else
//$$ public void onEntityDestroy(Entity entityIn) {
//#endif
//$$ if (mc.playerController != null && mc.playerController.getClass().getName().equals(CONTROLLER_OVERRIDE_CLASS_NAME)) {
//$$ // Someone has secretly swapped out the player controller and is about to substitute their own player entity.
//$$ // This is the right time to destroy their plan.
//$$ LOGGER.info("Preventing player controller {} from being replaced by BetterSprinting with {}.", originalController, mc.playerController);
//$$ mc.playerController = originalController;
//$$ }
//$$ }
//$$
//$$ @Override public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) {}
//#if MC>=10800
//$$ @Override public void notifyLightSet(BlockPos pos) {}
//$$ @Override public void spawnParticle(int p_180442_1_, boolean p_180442_2_, double p_180442_3_, double p_180442_5_, double p_180442_7_, double p_180442_9_, double p_180442_11_, double p_180442_13_, int... p_180442_15_) {}
//$$ @Override public void onEntityAdded(Entity entityIn) {}
//$$ @Override public void broadcastSound(int p_180440_1_, BlockPos p_180440_2_, int p_180440_3_) {}
//$$ @Override public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) {}
//#else
//$$ @Override public void markBlockForRenderUpdate(int x, int y, int z) {}
//$$ @Override public void spawnParticle(String p_72708_1_, double p_72708_2_, double p_72708_4_, double p_72708_6_, double p_72708_8_, double p_72708_10_, double p_72708_12_) {}
//$$ @Override public void onEntityCreate(Entity entityIn) {}
//$$ @Override public void broadcastSound(int p_180440_1_, int x, int y, int z, int p_180440_3_) {}
//$$ @Override public void destroyBlockPartially(int breakerId, int x, int y, int z, int progress) {}
//$$ @Override public void onStaticEntitiesChanged() {}
//#endif
//#if MC>=10904
//$$ @Override public void notifyBlockUpdate(World worldIn, BlockPos pos, IBlockState oldState, IBlockState newState, int flags) {}
//$$ @Override public void playSoundToAllNearExcept(@Nullable EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) {}
//$$ @Override public void playRecord(SoundEvent soundIn, BlockPos pos) {}
//$$ @Override public void playEvent(EntityPlayer player, int type, BlockPos blockPosIn, int data) {}
//#if MC>=11100
//#if MC>=11102
//$$ @Override public void spawnParticle(int p_190570_1_, boolean p_190570_2_, boolean p_190570_3_, double p_190570_4_, double p_190570_6_, double p_190570_8_, double p_190570_10_, double p_190570_12_, double p_190570_14_, int... p_190570_16_) {}
//#else
//$$ @Override public void func_190570_a(int p_190570_1_, boolean p_190570_2_, boolean p_190570_3_, double p_190570_4_, double p_190570_6_, double p_190570_8_, double p_190570_10_, double p_190570_12_, double p_190570_14_, int... p_190570_16_) {}
//#endif
//#endif
//#else
//#if MC>=10800
//$$ @Override public void markBlockForUpdate(BlockPos pos) {}
//$$ @Override public void playRecord(String recordName, BlockPos blockPosIn) {}
//#else
//$$ @Override public void markBlockForUpdate(int x, int y, int z) {}
//$$ @Override public void playRecord(String recordName, int x, int y, int z) {}
//#endif
//$$ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) {}
//$$ @Override public void playSoundToNearExcept(EntityPlayer except, String soundName, double x, double y, double z, float volume, float pitch) {}
//#if MC>=10809
//$$ @Override public void playAuxSFX(EntityPlayer p_180439_1_, int p_180439_2_, BlockPos blockPosIn, int p_180439_4_) {}
//#else
//#if MC>=10800
//$$ @Override public void playAusSFX(EntityPlayer p_180439_1_, int p_180439_2_, BlockPos blockPosIn, int p_180439_4_) {}
//#else
//$$ @Override public void playAuxSFX(EntityPlayer p_72706_1_, int p_72706_2_, int p_72706_3_, int p_72706_4_, int p_72706_5_, int p_72706_6_) {}
//#endif
//#endif
//#endif
//$$ }
//$$ }
//#endif

View File

@@ -1,46 +1 @@
//#if MC<11400 // 1.12.2 and below
//$$ package com.replaymod.compat.mapwriter.mixin;
//$$
//$$ import com.replaymod.replay.ReplayModReplay;
//$$ import net.minecraft.client.Minecraft;
//$$ import net.minecraft.client.multiplayer.ServerData;
//$$ import org.spongepowered.asm.mixin.Mixin;
//$$ import org.spongepowered.asm.mixin.Shadow;
//$$ import org.spongepowered.asm.mixin.injection.At;
//$$ import org.spongepowered.asm.mixin.injection.Inject;
//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
//$$
//#if MC>=10800
//$$ import net.minecraftforge.fml.common.Loader;
//#else
//$$ import cpw.mods.fml.common.Loader;
//#endif
//$$
//$$ /**
//$$ * Approximately this for <1.12: https://github.com/Vectron/mapwriter/commit/68234520c7a3a0ae8201a085d7e66369900586ac
//$$ */
//$$ @Mixin(Minecraft.class)
//$$ public abstract class MixinMinecraft {
//$$
//$$ @Shadow
//$$ private ServerData currentServerData;
//$$
//$$ @Inject(method = "getCurrentServerData", cancellable = true, at = @At("HEAD"))
//$$ private void replayModCompat_fixBug96(CallbackInfoReturnable<ServerData> ci) {
//$$ if (currentServerData == null
//$$ && (Loader.isModLoaded("mapwriter") || Loader.isModLoaded("MapWriter"))
//$$ && ReplayModReplay.instance.getReplayHandler() != null) {
//$$ for (StackTraceElement elem : Thread.currentThread().getStackTrace()) {
//$$ if ("mapwriter.util.Utils".equals(elem.getClassName()) && "getWorldName".equals(elem.getMethodName())) {
//#if MC>=10809
//$$ ci.setReturnValue(new ServerData(null, "replay", false));
//#else
//$$ ci.setReturnValue(new ServerData(null, "replay"));
//#endif
//$$ return;
//$$ }
//$$ }
//$$ }
//$$ }
//$$ }
//#endif

View File

@@ -1,32 +1 @@
//#if MC<11400 // 1.12.2 and below
//$$ package com.replaymod.compat.oranges17animations;
//$$
//$$ import com.replaymod.replay.camera.CameraEntity;
//$$ import de.johni0702.minecraft.gui.utils.EventRegistrations;
//$$ import net.minecraft.client.Minecraft;
//$$ import net.minecraftforge.client.event.RenderLivingEvent;
//$$ import net.minecraftforge.fml.common.eventhandler.EventPriority;
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//$$
//$$ import static com.replaymod.core.versions.MCVer.*;
//$$
//$$ /**
//$$ * Orange seems to have copied vast parts of the RendererLivingEntity into their ArmorAnimation class which cancels the RenderLivingEvent.Pre and calls its own code instead.
//$$ * This breaks our mixin which assures that, even though the camera is in spectator mode, it cannot see invisible entities.
//$$ *
//$$ * To fix this issue, we simply cancel the RenderLivingEvent.Pre before it gets to ArmorAnimation if the entity is invisible.
//$$ */
//$$ public class HideInvisibleEntities extends EventRegistrations {
//$$ private final Minecraft mc = Minecraft.getMinecraft();
//$$ private final boolean modLoaded = isModLoaded("animations");
//$$
//$$ @SubscribeEvent(priority = EventPriority.HIGH)
//$$ public void preRenderLiving(RenderLivingEvent.Pre event) {
//$$ if (modLoaded) {
//$$ if (mc.player instanceof CameraEntity && getEntity(event).isInvisible()) {
//$$ event.setCanceled(true);
//$$ }
//$$ }
//$$ }
//$$ }
//#endif

View File

@@ -1,21 +1,13 @@
//#if MC>=10800 //#if MC>=10800
package com.replaymod.compat.shaders; package com.replaymod.compat.shaders;
import com.replaymod.core.events.PreRenderCallback;
import com.replaymod.render.hooks.EntityRendererHandler; import com.replaymod.render.hooks.EntityRendererHandler;
import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.utils.EventRegistrations;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import static com.replaymod.core.versions.MCVer.getRenderPartialTicks;
//#if FABRIC>=1
import com.replaymod.core.events.PreRenderCallback;
//#else
//$$ import net.minecraftforge.eventbus.api.SubscribeEvent;
//$$ import net.minecraftforge.event.TickEvent;
//#endif
public class ShaderBeginRender extends EventRegistrations { public class ShaderBeginRender extends EventRegistrations {
private final MinecraftClient mc = MinecraftClient.getInstance(); private final MinecraftClient mc = MinecraftClient.getInstance();
@@ -25,14 +17,8 @@ public class ShaderBeginRender extends EventRegistrations {
* as this would usually get called by EntityRenderer#renderWorld, * as this would usually get called by EntityRenderer#renderWorld,
* which we're not calling during rendering. * which we're not calling during rendering.
*/ */
//#if FABRIC>=1
{ on(PreRenderCallback.EVENT, this::onRenderTickStart); } { on(PreRenderCallback.EVENT, this::onRenderTickStart); }
private void onRenderTickStart() { private void onRenderTickStart() {
//#else
//$$ @SubscribeEvent
//$$ public void onRenderTickStart(TickEvent.RenderTickEvent event) {
//$$ if (event.phase != TickEvent.Phase.START) return;
//#endif
if (ShaderReflection.shaders_beginRender == null) return; if (ShaderReflection.shaders_beginRender == null) return;
if (ShaderReflection.config_isShaders == null) return; if (ShaderReflection.config_isShaders == null) return;
@@ -48,7 +34,7 @@ public class ShaderBeginRender extends EventRegistrations {
//#if MC>=11400 //#if MC>=11400
mc.gameRenderer.getCamera(), mc.gameRenderer.getCamera(),
//#endif //#endif
getRenderPartialTicks(), 0); mc.getTickDelta(), 0);
} catch (IllegalAccessException | InvocationTargetException e) { } catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@@ -1,52 +1 @@
//#if MC<=10710 // 1.7.10 and below
//$$ package com.replaymod.compat.shaders.mixin;
//$$
//$$ import com.replaymod.render.hooks.EntityRendererHandler;
//$$ import com.replaymod.replay.ReplayHandler;
//$$ import com.replaymod.replay.ReplayModReplay;
//$$ import net.minecraft.client.Minecraft;
//$$ import org.spongepowered.asm.mixin.Mixin;
//$$ import org.spongepowered.asm.mixin.Pseudo;
//$$ import org.spongepowered.asm.mixin.Shadow;
//$$ import org.spongepowered.asm.mixin.injection.At;
//$$ import org.spongepowered.asm.mixin.injection.Redirect;
//$$
//$$ @Pseudo
//$$ @Mixin(targets = "shadersmod/client/Shaders", remap = false)
//$$ public abstract class MixinShaders {
//$$
//$$ @Shadow static Minecraft mc;
//$$ @Shadow static long systemTime;
//$$ @Shadow static long lastSystemTime;
//$$ @Shadow static long diffSystemTime;
//$$ @Shadow static int frameCounter;
//$$ @Shadow static float frameTime;
//$$ @Shadow static float frameTimeCounter;
//$$
//$$ @Redirect(method = "beginRender", at = @At(value = "INVOKE", target = "Ljava/lang/System;currentTimeMillis()J"))
//$$ private static long replayModCompat_currentTimeMillis() {
//$$ ReplayHandler replayHandler = ReplayModReplay.instance.getReplayHandler();
//$$ if (replayHandler != null) {
//$$ systemTime = replayHandler.getReplaySender().currentTimeStamp();
//$$
//$$ // We need to manipulate all the other previous-frame-time-based variables too
//$$
//$$ lastSystemTime = 0; // Draw all frames as if they were the first ones
//$$ // diffSystemTime will be set to 0 by Shaders
//$$ // frameTime will be set to 0 by Shaders
//$$ frameTimeCounter = systemTime / 1000f; // will be %= 3600f by Shaders
//$$
//$$ // Set frameCounter only if rendering is in progress
//$$ EntityRendererHandler entityRendererHandler =
//$$ ((EntityRendererHandler.IEntityRenderer) mc.entityRenderer).replayModRender_getHandler();
//$$ if (entityRendererHandler != null) {
//$$ frameCounter = entityRendererHandler.getRenderInfo().getFramesDone();
//$$ }
//$$
//$$ return systemTime;
//$$ }
//$$ return System.currentTimeMillis();
//$$ }
//$$
//$$ }
//#endif

View File

@@ -2,11 +2,11 @@ package com.replaymod.core;
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.replaymod.core.events.PreRenderCallback;
import com.replaymod.core.mixin.KeyBindingAccessor; import com.replaymod.core.mixin.KeyBindingAccessor;
import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.utils.EventRegistrations;
import com.replaymod.core.events.KeyBindingEventCallback; import com.replaymod.core.events.KeyBindingEventCallback;
import com.replaymod.core.events.KeyEventCallback; import com.replaymod.core.events.KeyEventCallback;
import com.replaymod.core.versions.MCVer;
import net.minecraft.client.options.KeyBinding; import net.minecraft.client.options.KeyBinding;
import net.minecraft.util.crash.CrashReport; import net.minecraft.util.crash.CrashReport;
import net.minecraft.util.crash.CrashReportSection; import net.minecraft.util.crash.CrashReportSection;
@@ -22,15 +22,6 @@ import static com.replaymod.core.ReplayMod.MOD_ID;
//$$ import net.minecraftforge.fml.client.registry.ClientRegistry; //$$ import net.minecraftforge.fml.client.registry.ClientRegistry;
//#endif //#endif
//#if MC>=11400
import com.replaymod.core.events.PreRenderCallback;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//$$ import net.minecraftforge.fml.common.gameevent.TickEvent;
//$$ import org.lwjgl.input.Keyboard;
//$$ import static com.replaymod.core.versions.MCVer.FML_BUS;
//#endif
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@@ -102,15 +93,7 @@ public class KeyBindingRegistry extends EventRegistrations {
return Collections.unmodifiableSet(onlyInReplay); return Collections.unmodifiableSet(onlyInReplay);
} }
//#if MC>=11400
{ on(PreRenderCallback.EVENT, this::handleRepeatedKeyBindings); } { on(PreRenderCallback.EVENT, this::handleRepeatedKeyBindings); }
//#else
//$$ @SubscribeEvent
//$$ public void onTick(TickEvent.RenderTickEvent event) {
//$$ if (event.phase != TickEvent.Phase.START) return;
//$$ handleRepeatedKeyBindings();
//$$ }
//#endif
public void handleRepeatedKeyBindings() { public void handleRepeatedKeyBindings() {
for (Binding binding : bindings.values()) { for (Binding binding : bindings.values()) {
@@ -137,8 +120,8 @@ public class KeyBindingRegistry extends EventRegistrations {
} catch (Throwable cause) { } catch (Throwable cause) {
CrashReport crashReport = CrashReport.create(cause, "Handling Key Binding"); CrashReport crashReport = CrashReport.create(cause, "Handling Key Binding");
CrashReportSection category = crashReport.addElement("Key Binding"); CrashReportSection category = crashReport.addElement("Key Binding");
MCVer.addDetail(category, "Key Binding", () -> binding.name); category.add("Key Binding", () -> binding.name);
MCVer.addDetail(category, "Handler", runnable::toString); category.add("Handler", runnable::toString);
throw new CrashException(crashReport); throw new CrashException(crashReport);
} }
} }
@@ -155,8 +138,8 @@ public class KeyBindingRegistry extends EventRegistrations {
} catch (Throwable cause) { } catch (Throwable cause) {
CrashReport crashReport = CrashReport.create(cause, "Handling Raw Key Binding"); CrashReport crashReport = CrashReport.create(cause, "Handling Raw Key Binding");
CrashReportSection category = crashReport.addElement("Key Binding"); CrashReportSection category = crashReport.addElement("Key Binding");
MCVer.addDetail(category, "Key Code", () -> "" + keyCode); category.add("Key Code", () -> "" + keyCode);
MCVer.addDetail(category, "Handler", handler::toString); category.add("Handler", handler::toString);
throw new CrashException(crashReport); throw new CrashException(crashReport);
} }
} }
@@ -177,7 +160,12 @@ public class KeyBindingRegistry extends EventRegistrations {
} }
public String getBoundKey() { public String getBoundKey() {
return MCVer.getBoundKey(keyBinding); try {
return keyBinding.getBoundKeyLocalizedText().getString();
} catch (ArrayIndexOutOfBoundsException e) {
// Apparently windows likes to press strange keys, see https://www.replaymod.com/forum/thread/55
return "Unknown";
}
} }
public boolean isBound() { public boolean isBound() {

View File

@@ -1,104 +1 @@
package com.replaymod.core; // 1.12.2 and below
//#if MC<11400
//$$ import net.minecraft.launchwrapper.Launch;
//$$ import org.apache.logging.log4j.LogManager;
//$$ import org.spongepowered.asm.launch.MixinBootstrap;
//$$ import org.spongepowered.asm.mixin.Mixins;
//$$
//$$ import net.minecraftforge.fml.relauncher.CoreModManager;
//$$ import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
//#if MC<10800
//$$ import com.replaymod.core.asm.GLErrorTransformer;
//$$ import com.replaymod.core.asm.GLStateTrackerTransformer;
//$$
//$$ import java.util.ArrayList;
//$$ import java.util.List;
//#endif
//$$
//$$ import java.io.File;
//$$ import java.net.URISyntaxException;
//$$ import java.net.URL;
//$$ import java.security.CodeSource;
//$$ import java.util.Map;
//$$
//$$ @IFMLLoadingPlugin.TransformerExclusions("com.replaymod.core.asm.")
//$$ public class LoadingPlugin implements IFMLLoadingPlugin {
//$$
//$$ public LoadingPlugin() {
//$$ if (Launch.blackboard.get("fml.deobfuscatedEnvironment") != Boolean.FALSE) {
//$$ // Outside of the dev env, this is the job of the tweaker
//$$ MixinBootstrap.init();
//$$ }
//$$
//$$ Mixins.addConfiguration("mixins.core.replaymod.json");
//$$ Mixins.addConfiguration("mixins.recording.replaymod.json");
//$$ Mixins.addConfiguration("mixins.render.replaymod.json");
//$$ Mixins.addConfiguration("mixins.render.blend.replaymod.json");
//$$ Mixins.addConfiguration("mixins.replay.replaymod.json");
//$$ Mixins.addConfiguration("mixins.compat.mapwriter.replaymod.json");
//$$ Mixins.addConfiguration("mixins.compat.shaders.replaymod.json");
//$$ Mixins.addConfiguration("mixins.extras.playeroverview.replaymod.json");
//$$
//$$ CodeSource codeSource = getClass().getProtectionDomain().getCodeSource();
//$$ if (codeSource != null) {
//$$ URL location = codeSource.getLocation();
//$$ try {
//$$ File file = new File(location.toURI());
//$$ if (file.isFile()) {
//$$ // This forces forge to reexamine the jar file for FML mods
//$$ // Should eventually be handled by Mixin itself, maybe?
//#if MC>=10809
//$$ CoreModManager.getIgnoredMods().remove(file.getName());
//#else
//$$ CoreModManager.getLoadedCoremods().remove(file.getName());
//#if MC<=10710
//$$ CoreModManager.getReparseableCoremods().add(file.getName());
//#endif
//#endif
//$$ }
//$$ } catch (URISyntaxException e) {
//$$ e.printStackTrace();
//$$ }
//$$ } else {
//$$ LogManager.getLogger().warn("No CodeSource, if this is not a development environment we might run into problems!");
//$$ LogManager.getLogger().warn(getClass().getProtectionDomain());
//$$ }
//$$ }
//$$
//$$ @Override
//$$ public String[] getASMTransformerClass() {
//#if MC>=10800
//$$ return new String[]{
//$$ };
//#else
//$$ List<String> transformers = new ArrayList<>();
//$$ if ("true".equals(System.getProperty("replaymod.glerrors", "false"))) {
//$$ transformers.add(GLErrorTransformer.class.getName());
//$$ }
//$$ transformers.add(GLStateTrackerTransformer.class.getName());
//$$ return transformers.stream().toArray(String[]::new);
//#endif
//$$ }
//$$
//$$ @Override
//$$ public String getModContainerClass() {
//$$ return null;
//$$ }
//$$
//$$ @Override
//$$ public String getSetupClass() {
//$$ return null;
//$$ }
//$$
//$$ @Override
//$$ public void injectData(Map<String, Object> data) {
//$$ }
//$$
//$$ @Override
//$$ public String getAccessTransformerClass() {
//$$ return null;
//$$ }
//$$
//$$ }
//#endif

View File

@@ -5,87 +5,32 @@ import com.replaymod.compat.ReplayModCompat;
import com.replaymod.core.gui.GuiBackgroundProcesses; import com.replaymod.core.gui.GuiBackgroundProcesses;
import com.replaymod.core.gui.GuiReplaySettings; import com.replaymod.core.gui.GuiReplaySettings;
import com.replaymod.core.gui.RestoreReplayGui; import com.replaymod.core.gui.RestoreReplayGui;
import com.replaymod.core.mixin.MinecraftAccessor;
import com.replaymod.core.versions.MCVer; import com.replaymod.core.versions.MCVer;
import com.replaymod.core.versions.scheduler.Scheduler;
import com.replaymod.core.versions.scheduler.SchedulerImpl;
import com.replaymod.editor.ReplayModEditor; import com.replaymod.editor.ReplayModEditor;
import com.replaymod.extras.ReplayModExtras; import com.replaymod.extras.ReplayModExtras;
import com.replaymod.recording.ReplayModRecording; import com.replaymod.recording.ReplayModRecording;
import com.replaymod.render.ReplayModRender; import com.replaymod.render.ReplayModRender;
import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.ReplayModReplay;
import com.replaymod.replaystudio.lib.viaversion.api.protocol.version.ProtocolVersion;
import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ZipReplayFile; import com.replaymod.replaystudio.replay.ZipReplayFile;
import com.replaymod.replaystudio.studio.ReplayStudio; import com.replaymod.replaystudio.studio.ReplayStudio;
import com.replaymod.replaystudio.us.myles.ViaVersion.api.protocol.ProtocolVersion;
import com.replaymod.replaystudio.util.I18n; import com.replaymod.replaystudio.util.I18n;
import com.replaymod.replaystudio.viaversion.ViaVersionPacketConverter;
import com.replaymod.simplepathing.ReplayModSimplePathing; import com.replaymod.simplepathing.ReplayModSimplePathing;
import de.johni0702.minecraft.gui.container.GuiScreen; import de.johni0702.minecraft.gui.container.GuiScreen;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.util.Identifier; import net.minecraft.client.options.Option;
import net.minecraft.resource.DirectoryResourcePack; import net.minecraft.resource.DirectoryResourcePack;
import net.minecraft.text.Text;
import net.minecraft.text.Style;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText; import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
import net.minecraft.util.crash.CrashException; import net.minecraft.util.Identifier;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
//#if MC>=11400
import net.minecraft.client.options.Option;
import net.minecraft.util.thread.ReentrantThreadExecutor;
//#endif
//#if FABRIC>=1
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.loader.api.FabricLoader;
//#else
//$$ import com.google.common.util.concurrent.ListenableFutureTask;
//$$ import net.minecraftforge.eventbus.api.SubscribeEvent;
//$$ import java.util.Queue;
//$$ import java.util.concurrent.FutureTask;
//$$
//#if MC>=11400
//$$ import com.replaymod.core.versions.LangResourcePack;
//$$ import net.minecraft.resources.IPackFinder;
//$$ import net.minecraft.resources.ResourcePackInfo;
//$$ import net.minecraftforge.fml.DeferredWorkQueue;
//$$ import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
//$$ import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
//$$ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
//$$ import net.minecraftforge.versions.mcp.MCPVersion;
//#else
//$$ import static com.replaymod.core.versions.MCVer.FML_BUS;
//$$ import net.minecraft.client.resources.IResourcePack;
//$$ import net.minecraftforge.common.config.Configuration;
//#endif
//$$
//#if MC>=10800
//$$ import net.minecraft.client.GameSettings;
//#endif
//$$
//#if MC>=11400
//$$ import net.minecraftforge.fml.ModList;
//#else
//$$ import net.minecraftforge.fml.common.Loader;
//$$ import net.minecraftforge.fml.common.Mod.EventHandler;
//$$ import net.minecraftforge.fml.common.Mod.Instance;
//$$ import net.minecraftforge.fml.common.event.FMLInitializationEvent;
//$$ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
//#if MC>=10800
//$$ import net.minecraftforge.fml.client.FMLClientHandler;
//#else
//$$ import com.replaymod.replay.InputReplayTimer;
//$$
//$$ import java.util.ArrayDeque;
//#endif
//#endif
//$$ import net.minecraftforge.fml.common.Mod;
//#if MC<11400
//$$ import net.minecraftforge.fml.common.gameevent.TickEvent;
//#endif
//#endif
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
@@ -102,43 +47,9 @@ import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
//#if FABRIC<=0 public class ReplayMod implements Module, Scheduler {
//#if MC>=11400
//$$ @Mod(ReplayMod.MOD_ID)
//#else
//$$ @Mod(modid = ReplayMod.MOD_ID,
//$$ useMetadata = true,
//$$ version = "@MOD_VERSION@",
//$$ acceptedMinecraftVersions = "@MC_VERSION@",
//$$ acceptableRemoteVersions = "*",
//#if MC>=10800
//$$ clientSideOnly = true,
//$$ updateJSON = "https://raw.githubusercontent.com/ReplayMod/ReplayMod/master/versions.json",
//#endif
//$$ guiFactory = "com.replaymod.core.gui.GuiFactory")
//#endif
//#endif
public class ReplayMod implements
//#if FABRIC>=1
ClientModInitializer,
//#endif
Module
{
public static String getMinecraftVersion() {
//#if MC>=11400
return MinecraftClient.getInstance().getGame().getVersion().getName();
//#else
//#if MC>=11400
//$$ return MCPVersion.getMCVersion();
//#else
//$$ return Loader.MC_VERSION;
//#endif
//#endif
}
public static final String MOD_ID = "replaymod"; public static final String MOD_ID = "replaymod";
@@ -148,23 +59,15 @@ public class ReplayMod implements
private static final MinecraftClient mc = MCVer.getMinecraft(); private static final MinecraftClient mc = MCVer.getMinecraft();
//#if MC<11400 private final ReplayModBackend backend;
//$$ @Deprecated private final SchedulerImpl scheduler = new SchedulerImpl();
//$$ public static Configuration config;
//#endif
private final KeyBindingRegistry keyBindingRegistry = new KeyBindingRegistry(); private final KeyBindingRegistry keyBindingRegistry = new KeyBindingRegistry();
private final SettingsRegistry settingsRegistry = new SettingsRegistry(); private final SettingsRegistry settingsRegistry = new SettingsRegistry();
{ {
settingsRegistry.register(Setting.class); settingsRegistry.register(Setting.class);
} }
// The instance of your mod that Forge uses.
//#if MC>=11400
{ instance = this; } { instance = this; }
//#else
//$$ @Instance(MOD_ID)
//#endif
public static ReplayMod instance; public static ReplayMod instance;
private final List<Module> modules = new ArrayList<>(); private final List<Module> modules = new ArrayList<>();
@@ -181,15 +84,15 @@ public class ReplayMod implements
*/ */
private boolean minimalMode; private boolean minimalMode;
public ReplayMod() { public ReplayMod(ReplayModBackend backend) {
this.backend = backend;
I18n.setI18n(net.minecraft.client.resource.language.I18n::translate); I18n.setI18n(net.minecraft.client.resource.language.I18n::translate);
//#if MC>=11400
// Check Minecraft protocol version for compatibility // Check Minecraft protocol version for compatibility
if (!ProtocolVersion.isRegistered(MCVer.getProtocolVersion()) && !Boolean.parseBoolean(System.getProperty("replaymod.skipversioncheck", "false"))) { if (!ProtocolVersion.isRegistered(MCVer.getProtocolVersion()) && !Boolean.parseBoolean(System.getProperty("replaymod.skipversioncheck", "false"))) {
minimalMode = true; minimalMode = true;
} }
//#endif
// Register all RM modules // Register all RM modules
modules.add(this); modules.add(this);
@@ -202,21 +105,9 @@ public class ReplayMod implements
modules.add(new ReplayModExtras(this)); modules.add(new ReplayModExtras(this));
modules.add(new ReplayModCompat()); modules.add(new ReplayModCompat());
//#if MC>=11400
settingsRegistry.register(); settingsRegistry.register();
//#endif
} }
//#if MC<=11400
//$$ @EventHandler
//$$ public void init(FMLPreInitializationEvent event) {
//$$ config = new Configuration(event.getSuggestedConfigurationFile());
//$$ config.load();
//$$ settingsRegistry.setConfiguration(config);
//$$ settingsRegistry.save(); // Save default values to disk
//$$ }
//#endif
public KeyBindingRegistry getKeyBindingRegistry() { public KeyBindingRegistry getKeyBindingRegistry() {
return keyBindingRegistry; return keyBindingRegistry;
} }
@@ -256,6 +147,8 @@ public class ReplayMod implements
try { try {
Files.setAttribute(path, "dos:hidden", true); Files.setAttribute(path, "dos:hidden", true);
} catch (UnsupportedOperationException ignored) { } catch (UnsupportedOperationException ignored) {
} catch (Exception e) {
e.printStackTrace();
} }
return path; return path;
} }
@@ -275,19 +168,14 @@ public class ReplayMod implements
return replayFolder.resolve(relative); return replayFolder.resolve(relative);
} }
public static final DirectoryResourcePack jGuiResourcePack; public static final DirectoryResourcePack jGuiResourcePack = createJGuiResourcePack();
public static final String JGUI_RESOURCE_PACK_NAME = "replaymod_jgui"; public static final String JGUI_RESOURCE_PACK_NAME = "replaymod_jgui";
static { // Note: even preInit is too late and we'd have to issue another resource reload private static DirectoryResourcePack createJGuiResourcePack() {
jGuiResourcePack = initJGuiResourcePack();
}
private static DirectoryResourcePack initJGuiResourcePack() {
File folder = new File("../jGui/src/main/resources"); File folder = new File("../jGui/src/main/resources");
if (!folder.exists()) { if (!folder.exists()) {
return null; return null;
} }
//noinspection UnnecessaryLocalVariable return new DirectoryResourcePack(folder) {
DirectoryResourcePack jGuiResourcePack = new DirectoryResourcePack(folder) {
@Override @Override
//#if MC>=11400 //#if MC>=11400
public String getName() { public String getName() {
@@ -315,56 +203,13 @@ public class ReplayMod implements
} }
} }
}; };
//#if MC<=11202
//$$ @SuppressWarnings("unchecked")
//$$ List<IResourcePack> defaultResourcePacks = ((MinecraftAccessor) mc).getDefaultResourcePacks();
//$$ defaultResourcePacks.add(jGuiResourcePack);
//#endif
//#if MC<=10710
//$$ FolderResourcePack mainResourcePack = new FolderResourcePack(new File("../src/main/resources")) {
//$$ @Override
//$$ protected InputStream getInputStreamByName(String resourceName) throws IOException {
//$$ try {
//$$ return super.getInputStreamByName(resourceName);
//$$ } catch (IOException e) {
//$$ if ("pack.mcmeta".equals(resourceName)) {
//$$ return new ByteArrayInputStream(("{\"pack\": {\"description\": \"dummy pack for mod resources in dev-env\", \"pack_format\": 1}}").getBytes(StandardCharsets.UTF_8));
//$$ }
//$$ throw e;
//$$ }
//$$ }
//$$ };
//$$ defaultResourcePacks.add(mainResourcePack);
//#endif
return jGuiResourcePack;
} }
//#if FABRIC>=1 void initModules() {
@Override
public void onInitializeClient() {
modules.forEach(Module::initCommon); modules.forEach(Module::initCommon);
modules.forEach(Module::initClient); modules.forEach(Module::initClient);
modules.forEach(m -> m.registerKeyBindings(keyBindingRegistry)); modules.forEach(m -> m.registerKeyBindings(keyBindingRegistry));
} }
//#else
//#if MC>=11400
//$$ {
//$$ FMLJavaModLoadingContext.get().getModEventBus().addListener((FMLCommonSetupEvent event) -> modules.forEach(Module::initCommon));
//$$ FMLJavaModLoadingContext.get().getModEventBus().addListener((FMLClientSetupEvent event) -> modules.forEach(Module::initClient));
//$$ FMLJavaModLoadingContext.get().getModEventBus().addListener((FMLClientSetupEvent event) -> modules.forEach(m -> m.registerKeyBindings(keyBindingRegistry)));
//$$ }
//#else
//$$ @EventHandler
//$$ public void init(FMLInitializationEvent event) {
//$$ modules.forEach(Module::initCommon);
//$$ modules.forEach(Module::initClient);
//$$ modules.forEach(m -> m.registerKeyBindings(keyBindingRegistry));
//$$ }
//#endif
//#endif
@Override @Override
public void registerKeyBindings(KeyBindingRegistry registry) { public void registerKeyBindings(KeyBindingRegistry registry) {
@@ -375,26 +220,16 @@ public class ReplayMod implements
@Override @Override
public void initClient() { public void initClient() {
//#if MC<=10710
//$$ FML_BUS.register(this); // For runLater(Runnable)
//#endif
backgroundProcesses.register(); backgroundProcesses.register();
keyBindingRegistry.register(); keyBindingRegistry.register();
// 1.7.10 crashes when render distance > 16 // 1.7.10 crashes when render distance > 16
//#if MC>=10800 //#if MC>=10800
if (!MCVer.hasOptifine()) { if (!MCVer.hasOptifine()) {
//#if MC>=11400
Option.RENDER_DISTANCE.setMax(64f); Option.RENDER_DISTANCE.setMax(64f);
//#else
//$$ GameSettings.Options.RENDER_DISTANCE.setValueMax(64f);
//#endif
} }
//#endif //#endif
testIfMoeshAndExitMinecraft();
runPostStartup(() -> { runPostStartup(() -> {
final long DAYS = 24 * 60 * 60 * 1000; final long DAYS = 24 * 60 * 60 * 1000;
@@ -493,231 +328,41 @@ public class ReplayMod implements
}); });
} }
/** @Override
* Execute the given runnable on the main client thread, returning only after it has been run (or after 30 seconds).
*/
public void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException { public void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException {
//#if MC>=11400 scheduler.runSync(runnable);
if (mc.isOnThread()) {
runnable.run();
} else {
executor.submit(() -> {
runnable.run();
return null;
}).get(30, TimeUnit.SECONDS);
}
//#else
//$$ if (mc.isCallingFromMinecraftThread()) {
//$$ runnable.run();
//$$ } else {
//$$ FutureTask<Void> future = new FutureTask<>(runnable, null);
//$$ runLater(future);
//$$ future.get(30, TimeUnit.SECONDS);
//$$ }
//#endif
} }
/** @Override
* Execute the given runnable after game has started (once the overlay has been closed).
* Most importantly, it will run after resources (including language keys!) have been loaded.
* Below 1.14, this is equivalent to {@link #runLater(Runnable)}.
*/
public void runPostStartup(Runnable runnable) { public void runPostStartup(Runnable runnable) {
runLater(new Runnable() { scheduler.runPostStartup(runnable);
@Override
public void run() {
//#if MC>=11400
if (getMinecraft().overlay != null) {
// delay until after resources have been loaded
runLater(this);
return;
}
//#endif
runnable.run();
}
});
} }
/** @Override
* Set when the currently running code has been scheduled by runLater.
* If this is the case, subsequent calls to runLater have to be delayed until all scheduled tasks have been
* processed, otherwise a livelock may occur.
*/
private boolean inRunLater = false;
//#if MC>=11400
private boolean inRenderTaskQueue = false;
// Starting 1.14 MC clears the queue of scheduled tasks on disconnect.
// This works fine for MC since it uses the queue only for packet handling but breaks our assumption that
// stuff submitted via runLater is actually always run (e.g. recording might not be fully stopped because parts
// of that are run via runLater and stopping the recording happens right around the time MC clears the queue).
// Luckily, that's also the version where MC pulled out the executor implementation, so we can just spin up our own.
public static class ReplayModExecutor extends ReentrantThreadExecutor<Runnable> {
private final Thread mcThread = Thread.currentThread();
// Fail-fast in case we ever switch to async loading and forget to change this
// (except for fabric 1.15+ because it loads the mod before the client thread is set)
//#if FABRIC<1 || MC<11500
//$$ { if (!MinecraftClient.getInstance().isOnThread()) throw new RuntimeException(); }
//#endif
private ReplayModExecutor(String string_1) {
super(string_1);
}
@Override
protected Runnable createTask(Runnable runnable) {
return runnable;
}
@Override
protected boolean canExecute(Runnable runnable) {
return true;
}
@Override
protected Thread getThread() {
return mcThread;
}
@Override
public void runTasks() {
super.runTasks();
}
}
public final ReplayModExecutor executor = new ReplayModExecutor("Client/ReplayMod");
//#endif
// Pre-1.14 MC would hold the lock on the scheduledTasks queue while executing its tasks
// such that no new tasks could be submitted while one of them was running.
// This would cause issues with long-running tasks (e.g. video rendering) as it would
// block all async tasks (e.g. skin loading).
public void runLaterWithoutLock(Runnable runnable) { public void runLaterWithoutLock(Runnable runnable) {
//#if MC>=11400 scheduler.runLaterWithoutLock(runnable);
// MC 1.14+ no longer synchronizes on the queue while running its tasks
runLater(runnable);
//#else
//$$ runLater(() -> runLaterWithoutLock(runnable), runnable);
//#endif
} }
@Override
public void runLater(Runnable runnable) { public void runLater(Runnable runnable) {
runLater(runnable, () -> runLater(runnable)); scheduler.runLater(runnable);
} }
private void runLater(Runnable runnable, Runnable defer) { @Override
//#if MC>=11400 public void runTasks() {
if (mc.isOnThread() && inRunLater && !inRenderTaskQueue) { scheduler.runTasks();
((MinecraftAccessor) mc).getRenderTaskQueue().offer(() -> {
inRenderTaskQueue = true;
try {
defer.run();
} finally {
inRenderTaskQueue = false;
}
});
} else {
executor.send(() -> {
inRunLater = true;
try {
runnable.run();
} catch (CrashException e) {
e.printStackTrace();
System.err.println(e.getReport().asString());
mc.setCrashReport(e.getReport());
} finally {
inRunLater = false;
}
});
}
//#else
//$$ if (mc.isCallingFromMinecraftThread() && inRunLater) {
//#if MC>=10800
//$$ FML_BUS.register(new Object() {
//$$ @SubscribeEvent
//$$ public void onRenderTick(TickEvent.RenderTickEvent event) {
//$$ if (event.phase == TickEvent.Phase.START) {
//$$ FML_BUS.unregister(this);
//$$ defer.run();
//$$ }
//$$ }
//$$ });
//#else
//$$ FML_BUS.register(new RunLaterHelper(defer));
//#endif
//$$ return;
//$$ }
//#if MC>=10800
//$$ Queue<FutureTask<?>> tasks = ((MinecraftAccessor) mc).getScheduledTasks();
//$$ //noinspection SynchronizationOnLocalVariableOrMethodParameter
//$$ synchronized (tasks) {
//#else
//$$ Queue<ListenableFutureTask<?>> tasks = scheduledTasks;
//$$ synchronized (scheduledTasks) {
//#endif
//$$ tasks.add(ListenableFutureTask.create(() -> {
//$$ inRunLater = true;
//$$ try {
//$$ runnable.run();
//$$ } catch (ReportedException e) {
//$$ e.printStackTrace();
//$$ System.err.println(e.getCrashReport().getCompleteReport());
//$$ mc.crashed(e.getCrashReport());
//$$ } finally {
//$$ inRunLater = false;
//$$ }
//$$ }, null));
//$$ }
//#endif
} }
//#if MC<=10710
//$$ // 1.7.10: Cannot use MC's because it is processed only during ticks (so not at all when replay is paused)
//$$ private final Queue<ListenableFutureTask<?>> scheduledTasks = new ArrayDeque<>();
//$$
//$$ // in 1.7.10 apparently events can't be delivered to anonymous classes
//$$ public class RunLaterHelper {
//$$ private final Runnable defer;
//$$
//$$ private RunLaterHelper(Runnable defer) {
//$$ this.defer = defer;
//$$ }
//$$
//$$ @SubscribeEvent
//$$ public void onRenderTick(TickEvent.RenderTickEvent event) {
//$$ if (event.phase == TickEvent.Phase.START) {
//$$ FML_BUS.unregister(this);
//$$ defer.run();
//$$ }
//$$ }
//$$ }
//$$
//$$ @SubscribeEvent
//$$ public void runScheduledTasks(InputReplayTimer.RunScheduledTasks event) {
//$$ synchronized (scheduledTasks) {
//$$ while (!scheduledTasks.isEmpty()) {
//$$ scheduledTasks.poll().run();
//$$ }
//$$ }
//$$ }
//#endif
public String getVersion() { public String getVersion() {
//#if FABRIC>=1 return backend.getVersion();
return FabricLoader.getInstance().getModContainer(MOD_ID)
.orElseThrow(IllegalStateException::new)
.getMetadata().getVersion().toString();
//#else
//#if MC>=11400
//$$ return ModList.get().getModContainerById(MOD_ID).get().getModInfo().getVersion().toString();
//#else
//$$ return Loader.instance().getIndexedModList().get(MOD_ID).getVersion();
//#endif
//#endif
} }
private void testIfMoeshAndExitMinecraft() { public String getMinecraftVersion() {
if("currentPlayer".equals("Moesh")) { return backend.getMinecraftVersion();
System.exit(-1); }
}
public boolean isModLoaded(String id) {
return backend.isModLoaded(id);
} }
public MinecraftClient getMinecraft() { public MinecraftClient getMinecraft() {

View File

@@ -0,0 +1,29 @@
package com.replaymod.core;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.loader.api.FabricLoader;
import static com.replaymod.core.ReplayMod.MOD_ID;
public class ReplayModBackend implements ClientModInitializer {
private final ReplayMod mod = new ReplayMod(this);
@Override
public void onInitializeClient() {
mod.initModules();
}
public String getVersion() {
return FabricLoader.getInstance().getModContainer(MOD_ID)
.orElseThrow(IllegalStateException::new)
.getMetadata().getVersion().toString();
}
public String getMinecraftVersion() {
return mod.getMinecraft().getGame().getVersion().getName();
}
public boolean isModLoaded(String id) {
return FabricLoader.getInstance().isModLoaded(id.toLowerCase());
}
}

View File

@@ -1,14 +1,8 @@
//#if FABRIC>=1 //#if FABRIC>=1
package com.replaymod.core; package com.replaymod.core;
import com.replaymod.extras.modcore.ModCoreInstaller;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import org.spongepowered.asm.mixin.Mixins; import org.spongepowered.asm.mixin.Mixins;
import java.io.File;
import java.util.Optional;
// We need to wait for MM to call us, otherwise we might initialize our mixins before it calls optifabric which would // We need to wait for MM to call us, otherwise we might initialize our mixins before it calls optifabric which would
// result in OF classes not existing while our mixins get resolved. // result in OF classes not existing while our mixins get resolved.
public class ReplayModMMLauncher implements Runnable { public class ReplayModMMLauncher implements Runnable {
@@ -32,43 +26,6 @@ public class ReplayModMMLauncher implements Runnable {
Mixins.addConfiguration("mixins.render.blend.replaymod.json"); Mixins.addConfiguration("mixins.render.blend.replaymod.json");
Mixins.addConfiguration("mixins.render.replaymod.json"); Mixins.addConfiguration("mixins.render.replaymod.json");
Mixins.addConfiguration("mixins.replay.replaymod.json"); Mixins.addConfiguration("mixins.replay.replaymod.json");
try {
initModCore();
} catch (Throwable t) {
System.err.println("ReplayMod caught error during ModCore init:");
t.printStackTrace();
}
}
// Forge equivalent is in ReplayModTweaker
private void initModCore() {
if (System.getProperty("REPLAYMOD_SKIP_MODCORE", "false").equalsIgnoreCase("true")) {
System.out.println("ReplayMod not initializing ModCore because REPLAYMOD_SKIP_MODCORE is true.");
return;
}
if (FabricLoader.getInstance().isDevelopmentEnvironment()) {
System.out.println("ReplayMod not initializing ModCore because we're in a development environment.");
return;
}
File gameDir = FabricLoader.getInstance().getGameDirectory();
Optional<ModContainer> minecraft = FabricLoader.getInstance().getModContainer("minecraft");
if (!minecraft.isPresent()) {
System.err.println("ReplayMod could not determine Minecraft version, skipping ModCore.");
return;
}
String mcVer = minecraft.get().getMetadata().getVersion().getFriendlyString();
int result = ModCoreInstaller.initialize(gameDir, mcVer + "_fabric");
if (result != -2) { // Don't even bother logging the result if there's no ModCore for this version.
System.out.println("ReplayMod ModCore init result: " + result);
}
if (ModCoreInstaller.isErrored()) {
System.err.println(ModCoreInstaller.getError());
}
} }
} }
//#endif //#endif

View File

@@ -1,130 +1,18 @@
package com.replaymod.core; package com.replaymod.core;
import com.replaymod.core.events.SettingsChangedCallback; import com.replaymod.core.events.SettingsChangedCallback;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.*; import java.util.*;
//#if MC>=11400
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
//#else
//#if MC>=11400
//$$ import net.minecraftforge.common.ForgeConfigSpec;
//$$ import net.minecraftforge.fml.ModLoadingContext;
//$$ import net.minecraftforge.fml.config.ModConfig;
//$$ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
//#else
//$$ import net.minecraftforge.common.config.Configuration;
//#endif
//#endif
import static com.replaymod.core.versions.MCVer.*;
public class SettingsRegistry { public class SettingsRegistry {
private static Logger LOGGER = LogManager.getLogger(); private final Map<SettingKey<?>, Object> settings = Collections.synchronizedMap(new LinkedHashMap<>());
private Map<SettingKey<?>, Object> settings = Collections.synchronizedMap(new LinkedHashMap<>()); final SettingsRegistryBackend backend = new SettingsRegistryBackend(settings);
//#if MC>=11400
private final Path configFile = getMinecraft().runDirectory.toPath().resolve("config/replaymod.json");
//#else
//$$ private static final Object NULL_OBJECT = new Object();
//#if MC>=11400
//$$ private ForgeConfigSpec spec;
//$$ private ModConfig config;
//#else
//$$ private Configuration configuration;
//#endif
//#endif
//#if MC>=11400
public void register() { public void register() {
String config; backend.register();
if (Files.exists(configFile)) {
try {
config = new String(Files.readAllBytes(configFile), StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
return;
}
} else {
save();
return;
}
Gson gson = new Gson();
JsonObject root = gson.fromJson(config, JsonObject.class);
if (root == null) {
LOGGER.error("Config file {} appears corrupted: {}", configFile, config);
save();
return;
}
for (Map.Entry<SettingKey<?>, Object> entry : settings.entrySet()) {
SettingKey<?> key = entry.getKey();
JsonElement category = root.get(key.getCategory());
if (category != null && category.isJsonObject()) {
JsonElement valueElem = category.getAsJsonObject().get(key.getKey());
if (valueElem == null || !valueElem.isJsonPrimitive()) continue;
JsonPrimitive value = valueElem.getAsJsonPrimitive();
if (key.getDefault() instanceof Boolean && value.isBoolean()) {
entry.setValue(value.getAsBoolean());
}
if (key.getDefault() instanceof Integer && value.isNumber()) {
entry.setValue(value.getAsNumber().intValue());
}
if (key.getDefault() instanceof Double && value.isNumber()) {
entry.setValue(value.getAsNumber().doubleValue());
}
if (key.getDefault() instanceof String && value.isString()) {
entry.setValue(value.getAsString());
}
}
}
} }
//#else
//#if MC>=11400
//$$ public void register() {
//$$ if (spec == null) {
//$$ ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder();
//$$ for (SettingKey<?> key : settings.keySet()) {
//$$ builder
//$$ .translation(key.getDisplayString())
//$$ .define(key.getCategory() + "." + key.getKey(), key.getDefault());
//$$ }
//$$ spec = builder.build();
//$$ }
//$$ FMLJavaModLoadingContext.get().getModEventBus().addListener(this::load);
//$$ ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, spec);
//$$ }
//$$
//$$ private void load(ModConfig.Loading event) {
//$$ config = event.getConfig();
//$$ for (Map.Entry<SettingKey<?>, Object> entry : settings.entrySet()) {
//$$ SettingKey<?> key = entry.getKey();
//$$ Object value = config.getConfigData().get(key.getCategory() + "." + key.getKey());
//$$ entry.setValue(value == null ? key.getDefault() : value);
//$$ }
//$$ }
//#else
//$$ public void setConfiguration(Configuration configuration) {
//$$ this.configuration = configuration;
//$$
//$$ List<SettingKey<?>> keys = new ArrayList<>(settings.keySet());
//$$ settings.clear();
//$$ for (SettingKey key : keys) {
//$$ register(key);
//$$ }
//$$ }
//#endif
//#endif
public void register(Class<?> settingsClass) { public void register(Class<?> settingsClass) {
for (Field field : settingsClass.getDeclaredFields()) { for (Field field : settingsClass.getDeclaredFields()) {
@@ -140,34 +28,8 @@ public class SettingsRegistry {
} }
public void register(SettingKey<?> key) { public void register(SettingKey<?> key) {
//#if MC>=11400
settings.put(key, key.getDefault()); settings.put(key, key.getDefault());
//#else backend.register(key);
//#if MC>=11400
//$$ if (spec != null) {
//$$ throw new IllegalStateException("Cannot register more settings are spec has been built.");
//$$ }
//$$ settings.put(key, NULL_OBJECT);
//#else
//$$ Object value;
//$$ if (configuration != null) {
//$$ if (key.getDefault() instanceof Boolean) {
//$$ value = configuration.get(key.getCategory(), key.getKey(), (Boolean) key.getDefault()).getBoolean();
//$$ } else if (key.getDefault() instanceof Integer) {
//$$ value = configuration.get(key.getCategory(), key.getKey(), (Integer) key.getDefault()).getInt();
//$$ } else if (key.getDefault() instanceof Double) {
//$$ value = configuration.get(key.getCategory(), key.getKey(), (Double) key.getDefault()).getDouble();
//$$ } else if (key.getDefault() instanceof String) {
//$$ value = configuration.get(key.getCategory(), key.getKey(), (String) key.getDefault()).getString();
//$$ } else {
//$$ throw new IllegalArgumentException("Default type " + key.getDefault().getClass() + " not supported.");
//$$ }
//$$ } else {
//$$ value = NULL_OBJECT;
//$$ }
//$$ settings.put(key, value);
//#endif
//#endif
} }
public Set<SettingKey<?>> getSettings() { public Set<SettingKey<?>> getSettings() {
@@ -183,68 +45,13 @@ public class SettingsRegistry {
} }
public <T> void set(SettingKey<T> key, T value) { public <T> void set(SettingKey<T> key, T value) {
//#if MC<11400 backend.update(key, value);
//#if MC>=11400
//$$ if (config != null) {
//$$ config.getConfigData().set(key.getCategory() + "." + key.getKey(), value);
//$$ }
//#else
//$$ if (key.getDefault() instanceof Boolean) {
//$$ configuration.get(key.getCategory(), key.getKey(), (Boolean) key.getDefault()).set((Boolean) value);
//$$ } else if (key.getDefault() instanceof Integer) {
//$$ configuration.get(key.getCategory(), key.getKey(), (Integer) key.getDefault()).set((Integer) value);
//$$ } else if (key.getDefault() instanceof Double) {
//$$ configuration.get(key.getCategory(), key.getKey(), (Double) key.getDefault()).set((Double) value);
//$$ } else if (key.getDefault() instanceof String) {
//$$ configuration.get(key.getCategory(), key.getKey(), (String) key.getDefault()).set((String) value);
//$$ } else {
//$$ throw new IllegalArgumentException("Default type " + key.getDefault().getClass() + " not supported.");
//$$ }
//#endif
//#endif
settings.put(key, value); settings.put(key, value);
SettingsChangedCallback.EVENT.invoker().onSettingsChanged(this, key); SettingsChangedCallback.EVENT.invoker().onSettingsChanged(this, key);
} }
public void save() { public void save() {
//#if MC>=11400 backend.save();
JsonObject root = new JsonObject();
for (Map.Entry<SettingKey<?>, Object> entry : settings.entrySet()) {
SettingKey<?> key = entry.getKey();
JsonObject category = root.getAsJsonObject(key.getCategory());
if (category == null) {
category = new JsonObject();
root.add(key.getCategory(), category);
}
Object value = entry.getValue();
if (value instanceof Boolean) {
category.addProperty(key.getKey(), (Boolean) value);
}
if (value instanceof Number) {
category.addProperty(key.getKey(), (Number) value);
}
if (value instanceof String) {
category.addProperty(key.getKey(), (String) value);
}
}
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String config = gson.toJson(root);
try {
Files.createDirectories(configFile.getParent());
Files.write(configFile, config.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}
//#else
//#if MC>=11400
//$$ if (config != null) {
//$$ config.save();
//$$ }
//#else
//$$ configuration.save();
//#endif
//#endif
} }
public interface SettingKey<T> { public interface SettingKey<T> {

View File

@@ -0,0 +1,188 @@
package com.replaymod.core;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.replaymod.core.events.SettingsChangedCallback;
import net.minecraft.client.MinecraftClient;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.List;
import java.util.Map;
import static com.replaymod.core.versions.MCVer.getMinecraft;
class SettingsRegistryBackend {
private static final Logger LOGGER = LogManager.getLogger();
private final Map<SettingsRegistry.SettingKey<?>, Object> settings;
private final Path configFile = getMinecraft().runDirectory.toPath().resolve("config/replaymod.json");
SettingsRegistryBackend(Map<SettingsRegistry.SettingKey<?>, Object> settings) {
this.settings = settings;
}
public void register() {
load(true);
try {
registerWatcher();
} catch (IOException e) {
LOGGER.warn("Failed to setup file watcher for {}, live-reloading is disabled. Cause: {}", configFile, e);
}
}
private void load(boolean createIfMissingOrBroken) {
String config;
if (Files.exists(configFile)) {
try {
config = new String(Files.readAllBytes(configFile), StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
return;
}
} else {
if (createIfMissingOrBroken) {
save();
}
return;
}
Gson gson = new Gson();
JsonObject root = gson.fromJson(config, JsonObject.class);
if (root == null) {
LOGGER.error("Config file {} appears corrupted: {}", configFile, config);
if (createIfMissingOrBroken) {
save();
}
return;
}
for (Map.Entry<SettingsRegistry.SettingKey<?>, Object> entry : settings.entrySet()) {
SettingsRegistry.SettingKey<?> key = entry.getKey();
JsonElement category = root.get(key.getCategory());
if (category != null && category.isJsonObject()) {
JsonElement valueElem = category.getAsJsonObject().get(key.getKey());
if (valueElem == null || !valueElem.isJsonPrimitive()) continue;
JsonPrimitive value = valueElem.getAsJsonPrimitive();
if (key.getDefault() instanceof Boolean && value.isBoolean()) {
entry.setValue(value.getAsBoolean());
}
if (key.getDefault() instanceof Integer && value.isNumber()) {
entry.setValue(value.getAsNumber().intValue());
}
if (key.getDefault() instanceof Double && value.isNumber()) {
entry.setValue(value.getAsNumber().doubleValue());
}
if (key.getDefault() instanceof String && value.isString()) {
String valueStr = value.getAsString();
if (entry instanceof SettingsRegistry.MultipleChoiceSettingKey) {
@SuppressWarnings("unchecked")
List<String> choices = ((SettingsRegistry.MultipleChoiceSettingKey<String>) entry).getChoices();
if (choices.stream().noneMatch(valueStr::equals)) {
continue;
}
}
entry.setValue(valueStr);
}
}
}
}
private void registerWatcher() throws IOException {
WatchService watchService = configFile.getFileSystem().newWatchService();
configFile.getParent().register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY);
Thread thread = new Thread(() -> {
while (true) {
WatchKey nextKey;
try {
nextKey = watchService.take();
} catch (InterruptedException e) {
return;
}
for (WatchEvent<?> event : nextKey.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
if (kind == StandardWatchEventKinds.OVERFLOW) {
continue;
}
Path fileName = ((Path) event.context());
if (fileName.equals(configFile.getFileName())) {
MinecraftClient.getInstance().send(this::reload);
}
}
if (!nextKey.reset()) {
return;
}
}
});
thread.setName("replaymod-config-watcher");
thread.setDaemon(true);
thread.start();
}
private void reload() {
load(false);
SettingsRegistry settingsRegistry = ReplayMod.instance.getSettingsRegistry();
for (SettingsRegistry.SettingKey<?> key : settings.keySet()) {
SettingsChangedCallback.EVENT.invoker().onSettingsChanged(settingsRegistry, key);
}
}
@SuppressWarnings("unused")
public void register(SettingsRegistry.SettingKey<?> key) {
}
@SuppressWarnings("unused")
public <T> void update(SettingsRegistry.SettingKey<T> key, T value) {
}
public void save() {
JsonObject root = new JsonObject();
for (Map.Entry<SettingsRegistry.SettingKey<?>, Object> entry : settings.entrySet()) {
SettingsRegistry.SettingKey<?> key = entry.getKey();
JsonObject category = root.getAsJsonObject(key.getCategory());
if (category == null) {
category = new JsonObject();
root.add(key.getCategory(), category);
}
Object value = entry.getValue();
if (value instanceof Boolean) {
category.addProperty(key.getKey(), (Boolean) value);
}
if (value instanceof Number) {
category.addProperty(key.getKey(), (Number) value);
}
if (value instanceof String) {
category.addProperty(key.getKey(), (String) value);
if (key instanceof SettingsRegistry.MultipleChoiceSettingKey) {
@SuppressWarnings("unchecked")
List<String> choices = ((SettingsRegistry.MultipleChoiceSettingKey<String>) key).getChoices();
JsonArray array = new JsonArray();
for (String choice : choices) {
array.add(choice);
}
category.add(key.getKey() + "_valid_values", array);
}
}
}
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String config = gson.toJson(root);
try {
Files.createDirectories(configFile.getParent());
Files.write(configFile, config.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -1,95 +1 @@
//#if MC<=10710 // 1.7.10 and below
//$$ package com.replaymod.core.asm;
//$$
//$$ import net.minecraft.launchwrapper.IClassTransformer;
//$$ import org.lwjgl.opengl.GL11;
//$$ import org.lwjgl.util.glu.GLU;
//$$ import org.objectweb.asm.ClassReader;
//$$ import org.objectweb.asm.ClassVisitor;
//$$ import org.objectweb.asm.ClassWriter;
//$$ import org.objectweb.asm.MethodVisitor;
//$$ import org.objectweb.asm.Opcodes;
//$$
//$$ /**
//$$ * Insert glGetError checks after all calls to any method in any GL*, ARB* and EXT* classes
//$$ */
//$$ public class GLErrorTransformer implements IClassTransformer {
//$$ private static final String GL_CLASS = "org.lwjgl.opengl.GL";
//$$ private static final String GL = GL_CLASS.replace('.', '/');
//$$ private static final String ARB_CLASS = "org.lwjgl.opengl.ARB";
//$$ private static final String ARB = ARB_CLASS.replace('.', '/');
//$$ private static final String EXT_CLASS = "org.lwjgl.opengl.EXT";
//$$ private static final String EXT = EXT_CLASS.replace('.', '/');
//$$ private static final String GLErrorTransformer_CLASS = GLErrorTransformer.class.getName();
//$$ private static final String GLErrorTransformer = GLErrorTransformer_CLASS.replace('.', '/');
//$$
//$$ @Override
//$$ public byte[] transform(String name, String transformedName, byte[] basicClass) {
//$$ if (basicClass == null) return null;
//$$
//$$ ClassReader reader = new ClassReader(basicClass);
//$$ ClassWriter writer = new ClassWriter(reader, 0);
//$$ reader.accept(new ClassVisitor(Opcodes.ASM5, writer) {
//$$ @Override
//$$ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
//$$ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
//$$ return new MethodVisitor(Opcodes.ASM5, mv) {
//$$ @Override
//$$ public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
//$$ super.visitMethodInsn(opcode, owner, name, desc, itf);
//$$ if (owner.startsWith(GL) || owner.startsWith(ARB) || owner.startsWith(EXT)) {
//$$ visitLdcInsn(owner.replace('/', '.'));
//$$ visitLdcInsn(name);
//$$ super.visitMethodInsn(Opcodes.INVOKESTATIC, GLErrorTransformer, "glErrorCheck", "(Ljava/lang/String;Ljava/lang/String;)V", false);
//$$ }
//$$ }
//$$
//$$ @Override
//$$ public void visitMaxs(int maxStack, int maxLocals) {
//$$ super.visitMaxs(maxStack + 2, maxLocals);
//$$ }
//$$ };
//$$ }
//$$ }, 0);
//$$ return writer.toByteArray();
//$$ }
//$$
//$$ private static boolean inGlBegin;
//$$
//$$ @SuppressWarnings("unused") // Called via ASM
//$$ public static void glErrorCheck(String cls, String method) {
//$$ if (method.equals("glBegin") && cls.equals(GL_CLASS + "11")) {
//$$ if (inGlBegin) {
//$$ // glBegin within glBegin
//$$ throw new GLError(GL11.GL_INVALID_OPERATION, cls, method);
//$$ }
//$$ inGlBegin = true;
//$$ return;
//$$ }
//$$ if (inGlBegin && method.equals("glEnd") && cls.equals(GL_CLASS + "11")) {
//$$ inGlBegin = false;
//$$ }
//$$ if (inGlBegin) {
//$$ return; // Cannot call glGetError in between of glBegin and glEnd
//$$ }
//$$ int err = GL11.glGetError();
//$$ if (err != 0) {
//$$ GLError e = new GLError(err, cls, method);
//$$ if ("true".equals(System.getProperty("replaymod.glerrors.throw", "true"))) {
//$$ throw e;
//$$ } else {
//$$ e.printStackTrace();
//$$ }
//$$ }
//$$ }
//$$
//$$ public static class GLError extends RuntimeException {
//$$ private GLError(int err, String cls, String method) {
//$$ super(GLU.gluErrorString(err) + " (" + err + ")");
//$$ StackTraceElement[] stack = getStackTrace();
//$$ stack[0] = new StackTraceElement(cls, method, stack[0].getFileName(), stack[0].getLineNumber());
//$$ setStackTrace(stack);
//$$ }
//$$ }
//$$ }
//#endif

View File

@@ -1,106 +1 @@
//#if MC<=10710 // 1.7.10 and below
//$$ package com.replaymod.core.asm;
//$$
//$$ import net.minecraft.launchwrapper.IClassTransformer;
//$$ import org.objectweb.asm.ClassReader;
//$$ import org.objectweb.asm.ClassVisitor;
//$$ import org.objectweb.asm.ClassWriter;
//$$ import org.objectweb.asm.MethodVisitor;
//$$ import org.objectweb.asm.Opcodes;
//$$
//$$ import java.util.HashSet;
//$$ import java.util.Set;
//$$
//$$ /**
//$$ * Redirect all calls to GL11.glEnable and GL11.glDisable to the GLStateTracker (excluding that class itself).
//$$ */
//$$ public class GLStateTrackerTransformer implements IClassTransformer {
//$$ private static final String GL11_CLASS = "org.lwjgl.opengl.GL11";
//$$ private static final String GL11 = GL11_CLASS.replace('.', '/');
//$$ private static final String glEnable = "glEnable";
//$$ private static final String glDisable = "glDisable";
//$$ private static final String GLStateTracker_CLASS = "com.replaymod.render.hooks.GLStateTracker";
//$$ private static final String GLStateTracker = GLStateTracker_CLASS.replace('.', '/');
//$$ private static final String hook_glEnable = "hook_glEnable";
//$$ private static final String hook_glDisable = "hook_glDisable";
//$$
//$$ @Override
//$$ public byte[] transform(String name, String transformedName, byte[] basicClass) {
//$$ if (basicClass == null) return null;
//$$ // Ignore the state tracker itself
//$$ if (name.equals(GLStateTracker_CLASS)) return basicClass;
//$$
//$$ ClassReader reader = new ClassReader(basicClass);
//$$ Set<Method> eligibleMethods = findEligibleMethods(reader);
//$$ if (eligibleMethods.isEmpty()) {
//$$ return basicClass;
//$$ }
//$$
//$$ ClassWriter writer = new ClassWriter(reader, 0);
//$$ reader.accept(new ClassVisitor(Opcodes.ASM5, writer) {
//$$ @Override
//$$ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
//$$ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
//$$ if (!eligibleMethods.contains(new Method(name, desc))) {
//$$ return mv;
//$$ }
//$$ return new MethodVisitor(Opcodes.ASM5, mv) {
//$$ @Override
//$$ public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
//$$ if (owner.equals(GL11)) {
//$$ if (name.equals(glEnable)) {
//$$ owner = GLStateTracker;
//$$ name = hook_glEnable;
//$$ } else if (name.equals(glDisable)) {
//$$ owner = GLStateTracker;
//$$ name = hook_glDisable;
//$$ }
//$$ }
//$$ super.visitMethodInsn(opcode, owner, name, desc, itf);
//$$ }
//$$ };
//$$ }
//$$ }, 0);
//$$ return writer.toByteArray();
//$$ }
//$$
//$$ private Set<Method> findEligibleMethods(ClassReader reader) {
//$$ Set<Method> eligibleMethods = new HashSet<>();
//$$ reader.accept(new ClassVisitor(Opcodes.ASM5) {
//$$ @Override
//$$ public MethodVisitor visitMethod(int access, String methodName, String methodDesc, String signature, String[] exceptions) {
//$$ return new MethodVisitor(Opcodes.ASM5) {
//$$ @Override
//$$ public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
//$$ if (owner.equals(GL11) && (name.equals(glEnable) || name.equals(glDisable))) {
//$$ eligibleMethods.add(new Method(methodName, methodDesc));
//$$ }
//$$ }
//$$ };
//$$ }
//$$ }, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
//$$ return eligibleMethods;
//$$ }
//$$
//$$ private static class Method {
//$$ private final String name, desc;
//$$
//$$ private Method(String name, String desc) {
//$$ this.name = name;
//$$ this.desc = desc;
//$$ }
//$$
//$$ @Override
//$$ public boolean equals(Object o) {
//$$ if (o == null || getClass() != o.getClass()) return false;
//$$ Method method = (Method) o;
//$$ return name.equals(method.name) && desc.equals(method.desc);
//$$ }
//$$
//$$ @Override
//$$ public int hashCode() {
//$$ return name.hashCode() ^ desc.hashCode();
//$$ }
//$$ }
//$$ }
//#endif

View File

@@ -1,4 +1,3 @@
//#if MC>=11400
package com.replaymod.core.events; package com.replaymod.core.events;
import de.johni0702.minecraft.gui.utils.Event; import de.johni0702.minecraft.gui.utils.Event;
@@ -14,4 +13,3 @@ public interface PostRenderCallback {
void postRender(); void postRender();
} }
//#endif

View File

@@ -1,33 +1,16 @@
//#if MC>=11400
package com.replaymod.core.events; package com.replaymod.core.events;
import de.johni0702.minecraft.gui.utils.Event; import de.johni0702.minecraft.gui.utils.Event;
//#if MC>=11500
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
//#endif
public interface PostRenderWorldCallback { public interface PostRenderWorldCallback {
Event<PostRenderWorldCallback> EVENT = Event.create((listeners) -> Event<PostRenderWorldCallback> EVENT = Event.create((listeners) ->
//#if MC>=11500
(MatrixStack matrixStack) -> { (MatrixStack matrixStack) -> {
//#else
//$$ () -> {
//#endif
for (PostRenderWorldCallback listener : listeners) { for (PostRenderWorldCallback listener : listeners) {
listener.postRenderWorld( listener.postRenderWorld(matrixStack);
//#if MC>=11500
matrixStack
//#endif
);
} }
} }
); );
void postRenderWorld( void postRenderWorld(MatrixStack matrixStack);
//#if MC>=11500
MatrixStack matrixStack
//#endif
);
} }
//#endif

View File

@@ -1,4 +1,3 @@
//#if MC>=11400
package com.replaymod.core.events; package com.replaymod.core.events;
import de.johni0702.minecraft.gui.utils.Event; import de.johni0702.minecraft.gui.utils.Event;
@@ -14,4 +13,3 @@ public interface PreRenderCallback {
void preRender(); void preRender();
} }
//#endif

View File

@@ -1,4 +1,3 @@
//#if MC>=11400
package com.replaymod.core.events; package com.replaymod.core.events;
import de.johni0702.minecraft.gui.utils.Event; import de.johni0702.minecraft.gui.utils.Event;
@@ -17,4 +16,3 @@ public interface PreRenderHandCallback {
boolean preRenderHand(); boolean preRenderHand();
} }
//#endif

View File

@@ -12,30 +12,15 @@ import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.utils.EventRegistrations;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
//#if FABRIC>=1
import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback; import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback;
import net.minecraft.client.gui.screen.Screen;
//#else
//$$ import net.minecraftforge.client.event.GuiScreenEvent;
//$$ import net.minecraftforge.common.MinecraftForge;
//$$ import net.minecraftforge.eventbus.api.SubscribeEvent;
//$$ import static com.replaymod.core.versions.MCVer.getGui;
//#endif
import static com.replaymod.core.versions.MCVer.getMinecraft; import static com.replaymod.core.versions.MCVer.getMinecraft;
public class GuiBackgroundProcesses extends EventRegistrations { public class GuiBackgroundProcesses extends EventRegistrations {
private GuiPanel panel = new GuiPanel().setLayout(new VerticalLayout().setSpacing(10)); private GuiPanel panel = new GuiPanel().setLayout(new VerticalLayout().setSpacing(10));
//#if FABRIC>=1
{ on(InitScreenCallback.EVENT, (screen, buttons) -> onGuiInit(screen)); } { on(InitScreenCallback.EVENT, (screen, buttons) -> onGuiInit(screen)); }
private void onGuiInit(Screen guiScreen) { private void onGuiInit(net.minecraft.client.gui.screen.Screen guiScreen) {
//#else
//$$ @SubscribeEvent
//$$ public void onGuiInit(GuiScreenEvent.InitGuiEvent.Post event) {
//$$ net.minecraft.client.gui.screen.Screen guiScreen = getGui(event);
//#endif
if (guiScreen != getMinecraft().currentScreen) return; // people tend to construct GuiScreens without opening them if (guiScreen != getMinecraft().currentScreen) return; // people tend to construct GuiScreens without opening them
VanillaGuiScreen vanillaGui = VanillaGuiScreen.wrap(guiScreen); VanillaGuiScreen vanillaGui = VanillaGuiScreen.wrap(guiScreen);

View File

@@ -1,63 +1 @@
//#if MC<11400 // 1.12.2 and below
//$$ package com.replaymod.core.gui;
//$$
//$$ import com.replaymod.core.ReplayMod;
//$$ import net.minecraft.client.Minecraft;
//$$ import net.minecraft.client.gui.GuiScreen;
//$$
//#if MC>=10800
//$$ import net.minecraftforge.fml.client.IModGuiFactory;
//#else
//$$ import cpw.mods.fml.client.IModGuiFactory;
//#endif
//$$
//$$ import java.util.Set;
//$$
//$$ @SuppressWarnings("unused")
//$$ public class GuiFactory implements IModGuiFactory {
//$$ @Override
//$$ public void initialize(Minecraft minecraftInstance) {
//$$
//$$ }
//$$
//#if MC>=11200
//$$ @Override
//$$ public boolean hasConfigGui() {
//$$ return true;
//$$ }
//$$
//$$ @Override
//$$ public GuiScreen createConfigGui(GuiScreen parentScreen) {
//$$ return new GuiReplaySettings(parentScreen, ReplayMod.instance.getSettingsRegistry()).toMinecraft();
//$$ }
//#else
//$$ @Override
//$$ public Class<? extends GuiScreen> mainConfigGuiClass() {
//$$ return ConfigGuiWrapper.class;
//$$ }
//$$
//$$ @Override
//$$ public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element) {
//$$ return null;
//$$ }
//$$
//$$ public static class ConfigGuiWrapper extends GuiScreen {
//$$ private final GuiScreen parent;
//$$
//$$ public ConfigGuiWrapper(GuiScreen parent) {
//$$ this.parent = parent;
//$$ }
//$$
//$$ @Override
//$$ public void initGui() {
//$$ new GuiReplaySettings(parent, ReplayMod.instance.getSettingsRegistry()).display();
//$$ }
//$$ }
//#endif
//$$
//$$ @Override
//$$ public Set<RuntimeOptionCategoryElement> runtimeGuiCategories() {
//$$ return null;
//$$ }
//$$ }
//#endif

View File

@@ -1,17 +1,19 @@
package com.replaymod.core.gui; package com.replaymod.core.gui;
import com.replaymod.core.ReplayMod;
import de.johni0702.minecraft.gui.GuiRenderer; import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.RenderInfo; import de.johni0702.minecraft.gui.RenderInfo;
import de.johni0702.minecraft.gui.element.GuiButton; import de.johni0702.minecraft.gui.element.GuiButton;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.util.Identifier;
public class GuiReplayButton extends GuiButton { public class GuiReplayButton extends GuiButton {
public static final Identifier ICON = new Identifier("replaymod", "logo_button.png");
@Override @Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) { public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
super.draw(renderer, size, renderInfo); super.draw(renderer, size, renderInfo);
renderer.bindTexture(ReplayMod.LOGO_FAVICON); renderer.bindTexture(ICON);
renderer.drawTexturedRect(3, 3, 0, 0, size.getWidth() - 6, size.getHeight() - 6, 1, 1, 1, 1); renderer.drawTexturedRect(3, 3, 0, 0, size.getWidth() - 6, size.getHeight() - 6, 1, 1, 1, 1);
} }
} }

View File

@@ -2,19 +2,31 @@
package com.replaymod.core.gui; package com.replaymod.core.gui;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
import io.github.prospector.modmenu.api.ModMenuApi;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import java.util.function.Function; import java.util.function.Function;
//#if MC>=11700
//$$ import com.terraformersmc.modmenu.api.ConfigScreenFactory;
//$$ import com.terraformersmc.modmenu.api.ModMenuApi;
//#else
import io.github.prospector.modmenu.api.ModMenuApi;
//#endif
public class ModMenuApiImpl implements ModMenuApi { public class ModMenuApiImpl implements ModMenuApi {
//#if MC<11700
@Override @Override
public String getModId() { public String getModId() {
return ReplayMod.MOD_ID; return ReplayMod.MOD_ID;
} }
//#endif
@Override @Override
//#if MC>=11700
//$$ public ConfigScreenFactory<?> getModConfigScreenFactory() {
//#else
public Function<Screen, ? extends Screen> getConfigScreenFactory() { public Function<Screen, ? extends Screen> getConfigScreenFactory() {
//#endif
return parent -> new GuiReplaySettings(parent, ReplayMod.instance.getSettingsRegistry()).toMinecraft(); return parent -> new GuiReplaySettings(parent, ReplayMod.instance.getSettingsRegistry()).toMinecraft();
} }
} }

View File

@@ -2,32 +2,33 @@ package com.replaymod.core.mixin;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List; //#if MC>=11700
//$$ import net.minecraft.client.gui.Drawable;
//#if MC>=11400 //$$ import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.widget.AbstractButtonWidget; //$$ import net.minecraft.client.gui.Selectable;
//#else //#else
//$$ import net.minecraft.client.gui.GuiButton;
//#endif //#endif
//#if MC>=11400 //#if MC>=11400
import net.minecraft.client.gui.Element; import net.minecraft.client.gui.widget.AbstractButtonWidget;
import org.spongepowered.asm.mixin.gen.Invoker;
//#else
//$$ import net.minecraft.client.gui.GuiButton;
//$$ import org.spongepowered.asm.mixin.gen.Accessor;
//$$ import java.util.List;
//#endif //#endif
@Mixin(Screen.class) @Mixin(Screen.class)
public interface GuiScreenAccessor { public interface GuiScreenAccessor {
//#if MC>=11400 //#if MC>=11700
@Accessor //$$ @Invoker("addDrawableChild")
List<AbstractButtonWidget> getButtons(); //$$ <T extends Element & Drawable & Selectable> T invokeAddButton(T drawableElement);
//#elseif MC>=11400
@Invoker
<T extends AbstractButtonWidget> T invokeAddButton(T button);
//#else //#else
//$$ @Accessor("buttonList") //$$ @Accessor("buttonList")
//$$ List<GuiButton> getButtons(); //$$ List<GuiButton> getButtons();
//#endif //#endif
//#if MC>=11400
@Accessor
List<Element> getChildren();
//#endif
} }

View File

@@ -1,9 +1,11 @@
package com.replaymod.core.mixin; package com.replaymod.core.mixin;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.network.ClientConnection;
import net.minecraft.util.crash.CrashReport; import net.minecraft.util.crash.CrashReport;
import net.minecraft.client.render.RenderTickCounter; import net.minecraft.client.render.RenderTickCounter;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Queue; import java.util.Queue;
@@ -26,6 +28,9 @@ public interface MinecraftAccessor {
@Accessor("renderTickCounter") @Accessor("renderTickCounter")
RenderTickCounter getTimer(); RenderTickCounter getTimer();
@Accessor("renderTickCounter") @Accessor("renderTickCounter")
//#if MC>=11200
@Mutable
//#endif
void setTimer(RenderTickCounter value); void setTimer(RenderTickCounter value);
//#if MC>=11400 //#if MC>=11400
@@ -50,4 +55,9 @@ public interface MinecraftAccessor {
//$$ @Accessor //$$ @Accessor
//$$ List<IResourcePack> getDefaultResourcePacks(); //$$ List<IResourcePack> getDefaultResourcePacks();
//#endif //#endif
//#if MC>=11400
@Accessor
void setConnection(ClientConnection connection);
//#endif
} }

View File

@@ -5,15 +5,12 @@ import com.replaymod.core.events.PostRenderWorldCallback;
import com.replaymod.core.events.PreRenderHandCallback; import com.replaymod.core.events.PreRenderHandCallback;
import net.minecraft.client.render.Camera; import net.minecraft.client.render.Camera;
import net.minecraft.client.render.GameRenderer; import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.util.math.MatrixStack;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//#if MC>=11500
import net.minecraft.client.util.math.MatrixStack;
//#endif
@Mixin(GameRenderer.class) @Mixin(GameRenderer.class)
public class MixinGameRenderer { public class MixinGameRenderer {
@Inject( @Inject(
@@ -30,11 +27,10 @@ public class MixinGameRenderer {
MatrixStack matrixStack, MatrixStack matrixStack,
//#endif //#endif
CallbackInfo ci) { CallbackInfo ci) {
PostRenderWorldCallback.EVENT.invoker().postRenderWorld( //#if MC<11500
//#if MC>=11500 //$$ MatrixStack matrixStack = new MatrixStack();
matrixStack //#endif
//#endif PostRenderWorldCallback.EVENT.invoker().postRenderWorld(matrixStack);
);
} }
@Inject(method = "renderHand", at = @At("HEAD"), cancellable = true) @Inject(method = "renderHand", at = @At("HEAD"), cancellable = true)

View File

@@ -2,19 +2,12 @@ package com.replaymod.core.mixin;
import com.replaymod.core.events.KeyBindingEventCallback; import com.replaymod.core.events.KeyBindingEventCallback;
import com.replaymod.core.events.KeyEventCallback; import com.replaymod.core.events.KeyEventCallback;
import net.minecraft.client.Keyboard;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//#if MC>=11400
import net.minecraft.client.Keyboard;
//#else
//$$ import net.minecraft.client.settings.KeyBinding;
//$$ import org.lwjgl.input.Keyboard;
//#endif
//#if MC>=11400
@Mixin(Keyboard.class) @Mixin(Keyboard.class)
public class MixinKeyboardListener { public class MixinKeyboardListener {
private static final String ON_KEY_PRESSED = "Lnet/minecraft/client/options/KeyBinding;onKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;)V"; private static final String ON_KEY_PRESSED = "Lnet/minecraft/client/options/KeyBinding;onKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;)V";
@@ -31,21 +24,3 @@ public class MixinKeyboardListener {
KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent(); KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent();
} }
} }
//#else
//$$ @Mixin(KeyBinding.class)
//$$ public class MixinKeyboardListener {
//$$ @Inject(method = "onTick", at = @At("HEAD"), cancellable = true)
//$$ private static void beforeKeyBindingTick(CallbackInfo ci) {
//$$ int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey();
//$$ int action = Keyboard.getEventKeyState() ? KeyEventCallback.ACTION_PRESS : KeyEventCallback.ACTION_RELEASE;
//$$ if (KeyEventCallback.EVENT.invoker().onKeyEvent(keyCode, 0, action, 0)) {
//$$ ci.cancel();
//$$ }
//$$ }
//$$
//$$ @Inject(method = "onTick", at = @At("RETURN"))
//$$ private static void afterKeyBindingTick(CallbackInfo ci) {
//$$ KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent();
//$$ }
//$$ }
//#endif

View File

@@ -1,4 +1,3 @@
//#if MC>=11400
package com.replaymod.core.mixin; package com.replaymod.core.mixin;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
@@ -13,6 +12,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -24,16 +24,26 @@ import java.util.Set;
*/ */
@Mixin(KeyBinding.class) @Mixin(KeyBinding.class)
public class Mixin_ContextualKeyBindings { public class Mixin_ContextualKeyBindings {
//#if MC>=11200
@Shadow @Final private static Map<String, KeyBinding> keysById; @Shadow @Final private static Map<String, KeyBinding> keysById;
@Unique private static Collection<KeyBinding> keyBindings() { return Mixin_ContextualKeyBindings.keysById.values(); }
//#else
//$$ @Shadow @Final private static List<KeyBinding> KEYBIND_ARRAY;
//$$ @Unique private static Collection<KeyBinding> keyBindings() { return Mixin_ContextualKeyBindings.KEYBIND_ARRAY; }
//#endif
@Unique private static final List<KeyBinding> temporarilyRemoved = new ArrayList<>(); @Unique private static final List<KeyBinding> temporarilyRemoved = new ArrayList<>();
@Inject(method = "updateKeysByCode", at = @At("HEAD")) @Inject(method = "updateKeysByCode", at = @At("HEAD"))
private static void preContextualKeyBindings(CallbackInfo ci) { private static void preContextualKeyBindings(CallbackInfo ci) {
Set<KeyBinding> onlyInReplay = ReplayMod.instance.getKeyBindingRegistry().getOnlyInReplay(); ReplayMod mod = ReplayMod.instance;
if (mod == null) {
return;
}
Set<KeyBinding> onlyInReplay = mod.getKeyBindingRegistry().getOnlyInReplay();
if (ReplayModReplay.instance.getReplayHandler() != null) { if (ReplayModReplay.instance.getReplayHandler() != null) {
// In replay, remove any conflicting key bindings, so that ours are guaranteed in // In replay, remove any conflicting key bindings, so that ours are guaranteed in
Mixin_ContextualKeyBindings.keysById.values().removeIf(keyBinding -> { keyBindings().removeIf(keyBinding -> {
for (KeyBinding exclusiveBinding : onlyInReplay) { for (KeyBinding exclusiveBinding : onlyInReplay) {
if (keyBinding.equals(exclusiveBinding) && keyBinding != exclusiveBinding) { if (keyBinding.equals(exclusiveBinding) && keyBinding != exclusiveBinding) {
temporarilyRemoved.add(keyBinding); temporarilyRemoved.add(keyBinding);
@@ -44,20 +54,25 @@ public class Mixin_ContextualKeyBindings {
}); });
} else { } else {
// Not in a replay, remove all replay-exclusive keybindings // Not in a replay, remove all replay-exclusive keybindings
for (KeyBinding keyBinding : onlyInReplay) { keyBindings().removeIf(keyBinding -> {
if (Mixin_ContextualKeyBindings.keysById.remove(keyBinding.getTranslationKey()) != null) { if (onlyInReplay.contains(keyBinding)) {
temporarilyRemoved.add(keyBinding); temporarilyRemoved.add(keyBinding);
return true;
} }
} return false;
});
} }
} }
@Inject(method = "updateKeysByCode", at = @At("RETURN")) @Inject(method = "updateKeysByCode", at = @At("RETURN"))
private static void postContextualKeyBindings(CallbackInfo ci) { private static void postContextualKeyBindings(CallbackInfo ci) {
for (KeyBinding keyBinding : temporarilyRemoved) { for (KeyBinding keyBinding : temporarilyRemoved) {
//#if MC>=11200
Mixin_ContextualKeyBindings.keysById.put(keyBinding.getTranslationKey(), keyBinding); Mixin_ContextualKeyBindings.keysById.put(keyBinding.getTranslationKey(), keyBinding);
//#else
//$$ keyBindings().add(keyBinding);
//#endif
} }
temporarilyRemoved.clear(); temporarilyRemoved.clear();
} }
} }
//#endif

View File

@@ -1,22 +1 @@
//#if MC<10800 // 1.7.10 and below
//$$ package com.replaymod.core.mixin;
//$$
//$$ import net.minecraft.client.resources.IResourcePack;
//$$ import net.minecraft.client.resources.ResourcePackRepository;
//$$ import org.spongepowered.asm.mixin.Mixin;
//$$ import org.spongepowered.asm.mixin.gen.Accessor;
//$$
//$$ import java.io.File;
//$$
//$$ @Mixin(ResourcePackRepository.class)
//$$ public interface ResourcePackRepositoryAccessor {
//$$ @Accessor("field_148533_g")
//$$ boolean isActive();
//$$ @Accessor("field_148533_g")
//$$ void setActive(boolean value);
//$$ @Accessor("field_148532_f")
//$$ void setPack(IResourcePack value);
//$$ @Accessor("field_148534_e")
//$$ File getCacheDir();
//$$ }
//#endif

View File

@@ -2,6 +2,7 @@ package com.replaymod.core.mixin;
import net.minecraft.client.render.RenderTickCounter; import net.minecraft.client.render.RenderTickCounter;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(RenderTickCounter.class) @Mixin(RenderTickCounter.class)
@@ -15,6 +16,7 @@ public interface TimerAccessor {
@Accessor("tickTime") @Accessor("tickTime")
float getTickLength(); float getTickLength();
@Accessor("tickTime") @Accessor("tickTime")
@Mutable
void setTickLength(float value); void setTickLength(float value);
//#else //#else
//$$ @Accessor //$$ @Accessor

View File

@@ -1,127 +1 @@
//#if FABRIC>=1 // Forge only
// Fabric equivalent is in ReplayModMMLauncher
//#else
//#if MC>=11400
//$$ // Generally not supported by RM
//#else
//$$ package com.replaymod.core.tweaker;
//$$
//$$ import com.replaymod.extras.modcore.ModCoreInstaller;
//$$ import net.minecraft.launchwrapper.ITweaker;
//$$ import net.minecraft.launchwrapper.Launch;
//$$ import net.minecraft.launchwrapper.LaunchClassLoader;
//$$ import org.spongepowered.asm.launch.GlobalProperties;
//$$ import org.spongepowered.asm.launch.MixinBootstrap;
//$$ import org.spongepowered.asm.launch.platform.MixinPlatformManager;
//$$
//$$ import java.io.File;
//$$ import java.net.URI;
//$$ import java.net.URISyntaxException;
//$$ import java.util.List;
//$$
//#if MC>=11200
//$$ import org.spongepowered.asm.launch.platform.container.ContainerHandleURI;
//#endif
//$$
//$$ public class ReplayModTweaker implements ITweaker {
//$$
//$$ private static final String MIXIN_TWEAKER = "org.spongepowered.asm.launch.MixinTweaker";
//$$
//$$ public ReplayModTweaker() {
//$$ injectMixinTweaker();
//$$ }
//$$
//$$ private void injectMixinTweaker() {
//$$ @SuppressWarnings("unchecked")
//$$ List<String> tweakClasses = (List<String>) Launch.blackboard.get("TweakClasses");
//$$
//$$ // If the MixinTweaker is already queued (because of another mod), then there's nothing we need to to
//$$ if (tweakClasses.contains(MIXIN_TWEAKER)) {
//$$ return;
//$$ }
//$$
//$$ // If it is already booted, we're also good to go
//$$ if (GlobalProperties.get(GlobalProperties.Keys.INIT) != null) {
//$$ return;
//$$ }
//$$
//$$ System.out.println("Injecting MixinTweaker from ReplayModTweaker");
//$$
//$$ // Otherwise, we need to take things into our own hands because the normal way to chainload a tweaker
//$$ // (by adding it to the TweakClasses list during injectIntoClassLoader) is too late for Mixin.
//$$ // Instead we instantiate the MixinTweaker on our own and add it to the current Tweaks list immediately.
//$$ Launch.classLoader.addClassLoaderExclusion(MIXIN_TWEAKER.substring(0, MIXIN_TWEAKER.lastIndexOf('.')));
//$$ @SuppressWarnings("unchecked")
//$$ List<ITweaker> tweaks = (List<ITweaker>) Launch.blackboard.get("Tweaks");
//$$ try {
//$$ tweaks.add((ITweaker) Class.forName(MIXIN_TWEAKER, true, Launch.classLoader).newInstance());
//$$ } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
//$$ throw new RuntimeException(e);
//$$ }
//$$ }
//$$
//$$ @Override
//$$ public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
//$$ }
//$$
//$$ @Override
//$$ public void injectIntoClassLoader(LaunchClassLoader classLoader) {
//$$ // Add our jar as a Mixin container (cause normally Mixin detects those via the TweakClass manifest entry)
//$$ URI uri;
//$$ try {
//$$ uri = this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI();
//$$ } catch (URISyntaxException e) {
//$$ throw new RuntimeException(e);
//$$ }
//$$ MixinPlatformManager platform = MixinBootstrap.getPlatform();
//#if MC>=11200
//$$ platform.addContainer(new ContainerHandleURI(uri));
//#else
//$$ platform.addContainer(uri);
//#endif
//$$
//#if MC>=11202 && MC<=11202
//$$ initModCore("1.12.2");
//#endif
//#if MC>=10809 && MC<=10809
//$$ initModCore("1.8.9");
//#endif
//$$ }
//$$
//$$ @Override
//$$ public String getLaunchTarget() {
//$$ return null;
//$$ }
//$$
//$$ @Override
//$$ public String[] getLaunchArguments() {
//$$ return new String[0];
//$$ }
//$$
//$$ private void initModCore(String mcVer) {
//$$ try {
//$$ if (System.getProperty("REPLAYMOD_SKIP_MODCORE", "false").equalsIgnoreCase("true")) {
//$$ System.out.println("ReplayMod not initializing ModCore because REPLAYMOD_SKIP_MODCORE is true.");
//$$ return;
//$$ }
//$$
//$$ if ((Boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment")) {
//$$ System.out.println("ReplayMod not initializing ModCore because we're in a development environment.");
//$$ return;
//$$ }
//$$
//$$ int result = ModCoreInstaller.initialize(Launch.minecraftHome, mcVer + "_forge");
//$$ if (result != -2) { // Don't even bother logging the result if there's no ModCore for this version.
//$$ System.out.println("ReplayMod ModCore init result: " + result);
//$$ }
//$$ if (ModCoreInstaller.isErrored()) {
//$$ System.err.println(ModCoreInstaller.getError());
//$$ }
//$$ } catch (Throwable t) {
//$$ System.err.println("ReplayMod caught error during ModCore init:");
//$$ t.printStackTrace();
//$$ }
//$$ }
//$$ }
//#endif
//#endif

View File

@@ -0,0 +1,30 @@
package com.replaymod.core.utils;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.File;
import java.io.IOException;
public class FileTypeAdapter extends TypeAdapter<File> {
@Override
public void write(JsonWriter out, File value) throws IOException {
out.value(value.getPath());
}
@Override
public File read(JsonReader in) throws IOException {
String path;
if (in.peek() == JsonToken.BEGIN_OBJECT) {
in.beginObject();
in.nextName();
path = in.nextString();
in.endObject();
} else {
path = in.nextString();
}
return new File(path);
}
}

View File

@@ -1,89 +1,12 @@
package com.replaymod.core.utils; package com.replaymod.core.utils;
import com.replaymod.replaystudio.data.ModInfo; import com.replaymod.replaystudio.data.ModInfo;
import net.minecraft.util.Identifier;
//#if FABRIC>=1
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.minecraft.util.registry.Registry;
//#else
//#if MC>=11200
//$$ import net.minecraftforge.registries.ForgeRegistry;
//$$ import net.minecraftforge.registries.RegistryManager;
//#else
//$$ import net.minecraftforge.fml.common.registry.GameData;
//$$ import java.util.stream.Stream;
//#endif
//$$
//#if MC>=11400
//$$ import net.minecraftforge.fml.ModList;
//#else
//$$ import net.minecraftforge.fml.common.Loader;
//$$ import net.minecraftforge.fml.common.ModContainer;
//#endif
//#endif
import java.util.*; import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class ModCompat { public class ModCompat {
@SuppressWarnings("unchecked")
public static Collection<ModInfo> getInstalledNetworkMods() { public static Collection<ModInfo> getInstalledNetworkMods() {
//#if MC>=11400 return ModInfoGetter.getInstalledNetworkMods();
//#if FABRIC>=1
Map<String, ModInfo> modInfoMap = FabricLoader.getInstance().getAllMods().stream()
.map(ModContainer::getMetadata)
.map(m -> new ModInfo(m.getId(), m.getName(), m.getVersion().toString()))
.collect(Collectors.toMap(ModInfo::getId, Function.identity()));
return Registry.REGISTRIES.stream()
.map(Registry::getIds).flatMap(Set::stream)
//#else
//$$ Map<String, ModInfo> modInfoMap = ModList.get().getMods().stream()
//$$ .map(m -> new ModInfo(m.getModId(), m.getDisplayName(), m.getVersion().toString()))
//$$ .collect(Collectors.toMap(ModInfo::getId, Function.identity()));
//$$ return RegistryManager.ACTIVE.takeSnapshot(false).keySet().stream()
//$$ .map(RegistryManager.ACTIVE::getRegistry)
//$$ .map(ForgeRegistry::getKeys).flatMap(Set::stream)
//#endif
.map(Identifier::getNamespace).filter(s -> !s.equals("minecraft")).distinct()
.map(modInfoMap::get).filter(Objects::nonNull)
.collect(Collectors.toList());
//#else
//$$ Map<String, ModContainer> ignoreCaseMap = Loader.instance().getModList().stream()
//$$ .collect(Collectors.toMap(m -> m.getModId().toLowerCase(), Function.identity()));
//#if MC>=11200
//$$ return RegistryManager.ACTIVE.takeSnapshot(false).keySet().stream()
//$$ .map(RegistryManager.ACTIVE::getRegistry)
//$$ .map(ForgeRegistry::getKeys).flatMap(Set::stream)
//$$ .map(ResourceLocation::getResourceDomain).filter(s -> !s.equals("minecraft")).distinct()
//$$ .map(String::toLowerCase).map(ignoreCaseMap::get).filter(mod -> mod != null)
//$$ .map(mod -> new ModInfo(mod.getModId(), mod.getName(), mod.getVersion()))
//$$ .collect(Collectors.toList());
//#else
//#if MC>=10800
//$$ return Stream.concat(
//$$ ((Set<ResourceLocation>) GameData.getBlockRegistry().getKeys()).stream(),
//$$ ((Set<ResourceLocation>) GameData.getItemRegistry().getKeys()).stream()
//$$ ).map(ResourceLocation::getResourceDomain).filter(s -> !s.equals("minecraft")).distinct()
//$$ .map(String::toLowerCase).map(ignoreCaseMap::get).filter(mod -> mod != null)
//$$ .map(mod -> new ModInfo(mod.getModId(), mod.getName(), mod.getVersion()))
//$$ .collect(Collectors.toList());
//#else
//$$ return Stream.concat(
//$$ ((Set<String>) GameData.getBlockRegistry().getKeys()).stream(),
//$$ ((Set<String>) GameData.getItemRegistry().getKeys()).stream()
//$$ ).map(name -> {
//$$ if (!name.contains(":")) return null; // Still using old names without namespace, can't do anything, ignore
//$$ return name.split(":", 2)[0];
//$$ }).filter(s -> !s.equals("minecraft")).distinct()
//$$ .map(String::toLowerCase).map(ignoreCaseMap::get).filter(mod -> mod != null)
//$$ .map(mod -> new ModInfo(mod.getModId(), mod.getName(), mod.getVersion()))
//$$ .collect(Collectors.toList());
//#endif
//#endif
//#endif
} }
public static final class ModInfoDifference { public static final class ModInfoDifference {

View File

@@ -0,0 +1,25 @@
package com.replaymod.core.utils;
import com.replaymod.replaystudio.data.ModInfo;
import net.minecraft.util.Identifier;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.minecraft.util.registry.Registry;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
class ModInfoGetter {
static Collection<ModInfo> getInstalledNetworkMods() {
Map<String, ModInfo> modInfoMap = FabricLoader.getInstance().getAllMods().stream()
.map(ModContainer::getMetadata)
.map(m -> new ModInfo(m.getId(), m.getName(), m.getVersion().toString()))
.collect(Collectors.toMap(ModInfo::getId, Function.identity()));
return Registry.REGISTRIES.stream()
.map(Registry::getIds).flatMap(Set::stream)
.map(Identifier::getNamespace).filter(s -> !s.equals("minecraft")).distinct()
.map(modInfoMap::get).filter(Objects::nonNull)
.collect(Collectors.toList());
}
}

View File

@@ -10,8 +10,6 @@ import net.minecraft.util.Identifier;
//$$ import io.netty.buffer.Unpooled; //$$ import io.netty.buffer.Unpooled;
//#endif //#endif
import static com.replaymod.core.versions.MCVer.readString;
/** /**
* Restrictions set by the server, * Restrictions set by the server,
* @see <a href="https://gist.github.com/Johni0702/2547c463e51f65f312cb">Replay Restrictions Gist</a> * @see <a href="https://gist.github.com/Johni0702/2547c463e51f65f312cb">Replay Restrictions Gist</a>
@@ -34,7 +32,7 @@ public class Restrictions {
//$$ PacketBuffer buffer = new PacketBuffer(Unpooled.wrappedBuffer(packet.func_149168_d())); //$$ PacketBuffer buffer = new PacketBuffer(Unpooled.wrappedBuffer(packet.func_149168_d()));
//#endif //#endif
while (buffer.isReadable()) { while (buffer.isReadable()) {
String name = readString(buffer, 64); String name = buffer.readString(64);
boolean active = buffer.readBoolean(); boolean active = buffer.readBoolean();
// if ("no_xray".equals(name)) { // if ("no_xray".equals(name)) {
// noXray = active; // noXray = active;

View File

@@ -0,0 +1,142 @@
package com.replaymod.core.utils;
import java.util.function.Consumer;
import java.util.function.Function;
public abstract class Result<Ok, Err> {
public static <Ok, Err> OkImpl<Ok, Err> ok(Ok value) {
return new OkImpl<>(value);
}
public static <Ok, Err> ErrImpl<Ok, Err> err(Err value) {
return new ErrImpl<>(value);
}
public abstract boolean isOk();
public abstract boolean isErr();
public abstract Ok okOrNull();
public abstract Err errOrNull();
public abstract void ifOk(Consumer<Ok> consumer);
public abstract void ifErr(Consumer<Err> consumer);
public abstract Ok okOrElse(Function<Err, Ok> orElse);
public abstract Err errOrElse(Function<Ok, Err> orElse);
public abstract <T> Result<T, Err> mapOk(Function<Ok, T> func);
public abstract <T> Result<Ok, T> mapErr(Function<Err, T> func);
private static class OkImpl<Ok, Err> extends Result<Ok, Err> {
private final Ok value;
public OkImpl(Ok value) {
this.value = value;
}
@Override
public boolean isOk() {
return true;
}
@Override
public boolean isErr() {
return false;
}
@Override
public Ok okOrNull() {
return this.value;
}
@Override
public Err errOrNull() {
return null;
}
@Override
public void ifOk(Consumer<Ok> consumer) {
consumer.accept(this.value);
}
@Override
public void ifErr(Consumer<Err> consumer) {
}
@Override
public Ok okOrElse(Function<Err, Ok> orElse) {
return this.value;
}
@Override
public Err errOrElse(Function<Ok, Err> orElse) {
return orElse.apply(this.value);
}
@Override
public <V> Result<V, Err> mapOk(Function<Ok, V> func) {
return ok(func.apply(this.value));
}
@SuppressWarnings("unchecked")
@Override
public <T> Result<Ok, T> mapErr(Function<Err, T> func) {
return (Result<Ok, T>) this;
}
}
private static class ErrImpl<Ok, Err> extends Result<Ok, Err> {
private final Err value;
public ErrImpl(Err value) {
this.value = value;
}
@Override
public boolean isOk() {
return false;
}
@Override
public boolean isErr() {
return true;
}
@Override
public Ok okOrNull() {
return null;
}
@Override
public Err errOrNull() {
return this.value;
}
@Override
public void ifOk(Consumer<Ok> consumer) {
}
@Override
public void ifErr(Consumer<Err> consumer) {
consumer.accept(this.value);
}
@Override
public Ok okOrElse(Function<Err, Ok> orElse) {
return orElse.apply(this.value);
}
@Override
public Err errOrElse(Function<Ok, Err> orElse) {
return this.value;
}
@SuppressWarnings("unchecked")
@Override
public <V> Result<V, Err> mapOk(Function<Ok, V> func) {
return (Result<V, Err>) this;
}
@Override
public <T> Result<Ok, T> mapErr(Function<Err, T> func) {
return err(func.apply(this.value));
}
}
}

View File

@@ -7,7 +7,7 @@ import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
import com.replaymod.replaystudio.us.myles.ViaVersion.api.protocol.ProtocolVersion; import com.replaymod.replaystudio.lib.viaversion.api.protocol.version.ProtocolVersion;
import de.johni0702.minecraft.gui.GuiRenderer; import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.RenderInfo; import de.johni0702.minecraft.gui.RenderInfo;
import de.johni0702.minecraft.gui.container.AbstractGuiScrollable; import de.johni0702.minecraft.gui.container.AbstractGuiScrollable;
@@ -245,18 +245,10 @@ public class Utils {
logger.trace("Opening crash report popup GUI"); logger.trace("Opening crash report popup GUI");
GuiCrashReportPopup popup = new GuiCrashReportPopup(container, crashReportStr); GuiCrashReportPopup popup = new GuiCrashReportPopup(container, crashReportStr);
Futures.addCallback(popup.getFuture(), new FutureCallback<Void>() { popup.onClosed(() -> {
@Override logger.trace("Crash report popup closed");
public void onSuccess(@Nullable Void result) { if (onClose != null) {
logger.trace("Crash report popup closed"); onClose.run();
if (onClose != null) {
onClose.run();
}
}
@Override
public void onFailure(Throwable t) {
logger.error("During error popup:", t);
} }
}); });
return popup; return popup;
@@ -329,18 +321,10 @@ public class Utils {
LOGGER.trace("Minimal mode active, denying action, opening popup"); LOGGER.trace("Minimal mode active, denying action, opening popup");
MinimalModeUnsupportedPopup popup = new MinimalModeUnsupportedPopup(container); MinimalModeUnsupportedPopup popup = new MinimalModeUnsupportedPopup(container);
Futures.addCallback(popup.getFuture(), new FutureCallback<Void>() { popup.onClosed(() -> {
@Override LOGGER.trace("Minimal mode popup closed");
public void onSuccess(@Nullable Void result) { if (onPopupClosed != null) {
LOGGER.trace("Minimal mode popup closed"); onPopupClosed.run();
if (onPopupClosed != null) {
onPopupClosed.run();
}
}
@Override
public void onFailure(Throwable t) {
LOGGER.error("During minimal mode popup:", t);
} }
}); });
return false; return false;
@@ -353,7 +337,7 @@ public class Utils {
ProtocolVersion latestVersion = ProtocolVersion.getProtocols() ProtocolVersion latestVersion = ProtocolVersion.getProtocols()
.stream() .stream()
.max(Comparator.comparing(ProtocolVersion::getId)) .max(Comparator.comparing(ProtocolVersion::getVersion))
.orElseThrow(RuntimeException::new); .orElseThrow(RuntimeException::new);
getInfo().addElements(new VerticalLayout.Data(0.5), getInfo().addElements(new VerticalLayout.Data(0.5),
new GuiLabel() new GuiLabel()

View File

@@ -0,0 +1 @@
// 1.7.10 and below

View File

@@ -0,0 +1 @@
// 1.12.2 and below

View File

@@ -1,43 +1,27 @@
package com.replaymod.core.versions; package com.replaymod.core.versions;
import com.mojang.blaze3d.platform.GlStateManager;
import com.replaymod.core.mixin.GuiScreenAccessor; import com.replaymod.core.mixin.GuiScreenAccessor;
import com.replaymod.core.mixin.MinecraftAccessor; import com.replaymod.replaystudio.lib.viaversion.api.protocol.packet.State;
import com.replaymod.replaystudio.lib.viaversion.api.protocol.version.ProtocolVersion;
import com.replaymod.replaystudio.protocol.PacketTypeRegistry; import com.replaymod.replaystudio.protocol.PacketTypeRegistry;
import com.replaymod.replaystudio.us.myles.ViaVersion.api.protocol.ProtocolVersion; import de.johni0702.minecraft.gui.MinecraftGuiRenderer;
import com.replaymod.replaystudio.us.myles.ViaVersion.packets.State; import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector2f;
import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.options.KeyBinding; import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.entity.EntityRenderDispatcher;
import net.minecraft.client.model.ModelPart;
import net.minecraft.util.crash.CrashReportSection;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Util; import net.minecraft.util.Util;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import net.minecraft.world.chunk.WorldChunk;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
//#if MC>=11600 //#if MC>=11600
import net.minecraft.resource.ResourcePackSource; import net.minecraft.resource.ResourcePackSource;
//#endif //#endif
//#if MC>=11500
import net.minecraft.client.model.ModelPart.Cuboid;
import java.util.ArrayList;
//#else
//$$ import net.minecraft.client.model.Box;
//#endif
//#if MC>=11400 //#if MC>=11400
import com.replaymod.core.mixin.AbstractButtonWidgetAccessor; import com.replaymod.render.mixin.MainWindowAccessor;
import net.minecraft.SharedConstants; import net.minecraft.SharedConstants;
import net.minecraft.client.gl.Framebuffer;
import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.AbstractButtonWidget; import net.minecraft.client.gui.widget.AbstractButtonWidget;
@@ -56,22 +40,10 @@ import net.minecraft.text.TranslatableText;
//$$ import net.minecraft.realms.RealmsSharedConstants; //$$ import net.minecraft.realms.RealmsSharedConstants;
//#endif //#endif
//#if FABRIC>=1
//#else
//$$ import net.minecraft.entity.LivingEntity;
//$$ import net.minecraftforge.client.event.GuiScreenEvent;
//$$ import net.minecraftforge.client.event.RenderGameOverlayEvent;
//$$ import net.minecraftforge.client.event.RenderLivingEvent;
//$$ import net.minecraftforge.common.MinecraftForge;
//$$ import net.minecraftforge.eventbus.api.IEventBus;
//#endif
//#if MC>=11400 //#if MC>=11400
import net.minecraft.client.util.Window;
import net.minecraft.client.util.InputUtil; import net.minecraft.client.util.InputUtil;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
//#else //#else
//$$ import net.minecraft.client.gui.ScaledResolution;
//$$ import net.minecraft.client.resources.ResourcePackRepository; //$$ import net.minecraft.client.resources.ResourcePackRepository;
//$$ import net.minecraftforge.fml.client.FMLClientHandler; //$$ import net.minecraftforge.fml.client.FMLClientHandler;
//$$ import org.apache.logging.log4j.LogManager; //$$ import org.apache.logging.log4j.LogManager;
@@ -80,28 +52,13 @@ import org.lwjgl.glfw.GLFW;
//$$ import java.io.IOException; //$$ import java.io.IOException;
//#endif //#endif
//#if MC>=11400
import net.minecraft.client.sound.PositionedSoundInstance;
//#else
//$$ import net.minecraft.client.audio.PositionedSoundRecord;
//#endif
//#if MC>=10904 //#if MC>=10904
import com.replaymod.render.blend.mixin.ParticleAccessor; import com.replaymod.render.blend.mixin.ParticleAccessor;
import net.minecraft.client.particle.Particle; import net.minecraft.client.particle.Particle;
import net.minecraft.sound.SoundEvent;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
//#endif //#endif
//#if MC>=10809
import net.minecraft.client.render.VertexFormats;
//#else
//$$ import net.minecraftforge.fml.common.FMLCommonHandler;
//#endif
//#if MC>=10800 //#if MC>=10800
import net.minecraft.client.render.BufferBuilder;
import com.mojang.blaze3d.platform.GlStateManager;
import net.minecraft.client.render.VertexFormat; import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.render.VertexFormatElement; import net.minecraft.client.render.VertexFormatElement;
//#if MC<11500 //#if MC<11500
@@ -109,28 +66,17 @@ import net.minecraft.client.render.VertexFormatElement;
//#endif //#endif
//#else //#else
//$$ import com.replaymod.core.mixin.ResourcePackRepositoryAccessor; //$$ import com.replaymod.core.mixin.ResourcePackRepositoryAccessor;
//$$ import com.google.common.util.concurrent.Futures;
//$$ import io.netty.handler.codec.DecoderException; //$$ import io.netty.handler.codec.DecoderException;
//$$ import net.minecraft.client.renderer.entity.RenderManager;
//$$ import net.minecraft.client.resources.FileResourcePack; //$$ import net.minecraft.client.resources.FileResourcePack;
//$$ import net.minecraft.network.PacketBuffer;
//$$ //$$
//$$ import static org.lwjgl.opengl.GL11.*; //$$ import static org.lwjgl.opengl.GL11.*;
//#endif //#endif
//#if FABRIC>=1
import net.fabricmc.loader.api.FabricLoader;
//#else
//#if MC>=11400
//$$ import net.minecraftforge.fml.ModList;
//#else
//$$ import net.minecraftforge.fml.common.Loader;
//#endif
//#endif
import java.io.File; import java.io.File;
import java.net.URI; import java.net.URI;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.Optional; import java.util.Optional;
@@ -138,29 +84,6 @@ import java.util.Optional;
* Abstraction over things that have changed between different MC versions. * Abstraction over things that have changed between different MC versions.
*/ */
public class MCVer { public class MCVer {
private static Logger LOGGER = LogManager.getLogger();
//#if FABRIC<=0
//$$ public static IEventBus FORGE_BUS = MinecraftForge.EVENT_BUS;
//#if MC>=10809
//$$ public static IEventBus FML_BUS = FORGE_BUS;
//#else
//$$ public static EventBus FML_BUS = FMLCommonHandler.instance().bus();
//#endif
//#endif
public static boolean isModLoaded(String id) {
//#if FABRIC>=1
return FabricLoader.getInstance().isModLoaded(id.toLowerCase());
//#else
//#if MC>=11400
//$$ return ModList.get().isLoaded(id.toLowerCase());
//#else
//$$ return Loader.isModLoaded(id);
//#endif
//#endif
}
public static int getProtocolVersion() { public static int getProtocolVersion() {
//#if MC>=11400 //#if MC>=11400
return SharedConstants.getGameVersion().getProtocolVersion(); return SharedConstants.getGameVersion().getProtocolVersion();
@@ -176,271 +99,33 @@ public class MCVer {
); );
} }
public static void addDetail(CrashReportSection category, String name, Callable<String> callable) { public static void resizeMainWindow(MinecraftClient mc, int width, int height) {
//#if MC>=10904
//#if MC>=11200
category.add(name, callable::call);
//#else
//$$ category.setDetail(name, callable::call);
//#endif
//#else
//$$ category.addCrashSectionCallable(name, callable);
//#endif
}
public static double Entity_getX(Entity entity) {
//#if MC>=11500
return entity.getX();
//#else
//$$ return entity.x;
//#endif
}
public static double Entity_getY(Entity entity) {
//#if MC>=11500
return entity.getY();
//#else
//$$ return entity.y;
//#endif
}
public static double Entity_getZ(Entity entity) {
//#if MC>=11500
return entity.getZ();
//#else
//$$ return entity.z;
//#endif
}
public static void Entity_setPos(Entity entity, double x, double y, double z) {
//#if MC>=11500
entity.setPos(x, y, z);
//#else
//$$ entity.x = x;
//$$ entity.y = y;
//$$ entity.z = z;
//#endif
}
//#if MC>=11400
public static void width(AbstractButtonWidget button, int value) {
button.setWidth(value);
}
public static int width(AbstractButtonWidget button) {
return button.getWidth();
}
public static int height(AbstractButtonWidget button) {
return ((AbstractButtonWidgetAccessor) button).getHeight();
}
//#else
//$$ public static void width(GuiButton button, int value) {
//$$ button.width = value;
//$$ }
//$$
//$$ public static int width(GuiButton button) {
//$$ return button.width;
//$$ }
//$$
//$$ public static int height(GuiButton button) {
//$$ return button.height;
//$$ }
//#endif
//#if FABRIC<=0
//#if MC>=11400
//$$ public static void addButton(GuiScreenEvent.InitGuiEvent event, Widget button) {
//$$ event.addWidget(button);
//$$ }
//$$
//$$ public static void removeButton(GuiScreenEvent.InitGuiEvent event, Widget button) {
//$$ event.removeWidget(button);
//$$ }
//$$
//$$ public static List<Widget> getButtonList(GuiScreenEvent.InitGuiEvent event) {
//$$ return event.getWidgetList();
//$$ }
//$$
//$$ public static Widget getButton(GuiScreenEvent.ActionPerformedEvent event) {
//$$ return event.getButton();
//$$ }
//#else
//$$ public static void addButton(GuiScreenEvent.InitGuiEvent event, GuiButton button) {
//#if MC>=11400 //#if MC>=11400
//$$ event.addButton(button); Framebuffer fb = mc.getFramebuffer();
//#else if (fb.viewportWidth != width || fb.viewportHeight != height) {
//$$ getButtonList(event).add(button); fb.resize(width, height, false);
}
//noinspection ConstantConditions
MainWindowAccessor mainWindow = (MainWindowAccessor) (Object) mc.getWindow();
mainWindow.setFramebufferWidth(width);
mainWindow.setFramebufferHeight(height);
//#if MC>=11500
mc.gameRenderer.onResized(width, height);
//#endif //#endif
//$$ }
//$$
//$$ public static void removeButton(GuiScreenEvent.InitGuiEvent event, GuiButton button) {
//#if MC>=11400
//$$ event.removeButton(button);
//#else //#else
//$$ getButtonList(event).remove(button); //$$ if (width != mc.displayWidth || height != mc.displayHeight) {
//#endif //$$ mc.resize(width, height);
//$$ }
//$$
//$$ @SuppressWarnings("unchecked")
//$$ public static List<GuiButton> getButtonList(GuiScreenEvent.InitGuiEvent event) {
//#if MC>=10904
//$$ return event.getButtonList();
//#else
//$$ return event.buttonList;
//#endif
//$$ }
//$$
//$$ public static GuiButton getButton(GuiScreenEvent.ActionPerformedEvent event) {
//#if MC>=10904
//$$ return event.getButton();
//#else
//$$ return event.button;
//#endif
//$$ }
//#endif
//$$
//$$ public static Screen getGui(GuiScreenEvent event) {
//#if MC>=10904
//$$ return event.getGui();
//#else
//$$ return event.gui;
//#endif
//$$ }
//$$
//$$ public static LivingEntity getEntity(RenderLivingEvent event) {
//#if MC>=10904
//$$ return event.getEntity();
//#else
//$$ return event.entity;
//#endif
//$$ }
//#endif
public static String readString(PacketByteBuf buffer, int max) {
//#if MC>=10800
return buffer.readString(max);
//#else
//$$ try {
//$$ return buffer.readStringFromBuffer(max);
//$$ } catch (IOException e) {
//$$ throw new DecoderException(e);
//$$ } //$$ }
//#endif //#endif
} }
//#if FABRIC<=0 //#if MC<10800
//$$ public static RenderGameOverlayEvent.ElementType getType(RenderGameOverlayEvent event) { //$$ public static String tryReadString(PacketBuffer buffer, int max) {
//#if MC>=10904 //$$ try {
//$$ return event.getType(); //$$ return buffer.readStringFromBuffer(max);
//#else //$$ } catch (IOException e) {
//$$ return event.type; //$$ throw new DecoderException(e);
//#endif //$$ }
//$$ }
//#endif
//#if MC>=10800
public static Entity getRenderViewEntity(MinecraftClient mc) {
return mc.getCameraEntity();
}
//#else
//$$ public static EntityLivingBase getRenderViewEntity(Minecraft mc) {
//$$ return mc.renderViewEntity;
//$$ }
//#endif
//#if MC>=10800
public static void setRenderViewEntity(MinecraftClient mc, Entity entity) {
mc.setCameraEntity(entity);
}
//#else
//$$ public static void setRenderViewEntity(Minecraft mc, EntityLivingBase entity) {
//$$ mc.renderViewEntity = entity;
//$$ }
//#endif
public static Entity getRiddenEntity(Entity ridden) {
//#if MC>=10904
return ridden.getVehicle();
//#else
//$$ return ridden.ridingEntity;
//#endif
}
public static Iterable<Entity> loadedEntityList(ClientWorld world) {
//#if MC>=11400
return world.getEntities();
//#else
//$$ return world.loadedEntityList;
//#endif
}
@SuppressWarnings("unchecked")
public static Collection<Entity>[] getEntityLists(WorldChunk chunk) {
//#if MC>=10800
return chunk.getEntitySectionArray();
//#else
//$$ return chunk.entityLists;
//#endif
}
@SuppressWarnings("unchecked")
//#if MC>=11500
public static List<Cuboid> cubeList(ModelPart modelRenderer) {
return new ArrayList<>(); // FIXME 1.15
}
//#else
//$$ public static List<Box> cubeList(ModelPart modelRenderer) {
//$$ return modelRenderer.boxes;
//$$ }
//#endif
@SuppressWarnings("unchecked")
public static List<PlayerEntity> playerEntities(World world) {
//#if MC>=11400
return (List) world.getPlayers();
//#else
//$$ return world.playerEntities;
//#endif
}
public static boolean isOnMainThread() {
//#if MC>=11400
return getMinecraft().isOnThread();
//#else
//$$ return getMinecraft().isCallingFromMinecraftThread();
//#endif
}
public static void scheduleOnMainThread(Runnable runnable) {
//#if MC>=11400
getMinecraft().send(runnable);
//#else
//$$ getMinecraft().addScheduledTask(runnable);
//#endif
}
//#if MC>=11400
public static Window getWindow(MinecraftClient mc) {
//#if MC>=11500
return mc.getWindow();
//#else
//$$ return mc.window;
//#endif
}
//#endif
//#if MC>=11400
public static Window newScaledResolution(MinecraftClient mc) {
return getWindow(mc);
}
//#else
//$$ public static ScaledResolution newScaledResolution(Minecraft mc) {
//#if MC>=10809
//$$ return new ScaledResolution(mc);
//#else
//$$ return new ScaledResolution(mc, mc.displayWidth, mc.displayHeight);
//#endif
//$$ } //$$ }
//#endif //#endif
@@ -501,69 +186,6 @@ public class MCVer {
//#endif //#endif
} }
//#if MC>=10800
public static BufferBuilder Tessellator_getBufferBuilder() {
return Tessellator.getInstance().getBuffer();
}
//#else
//$$ public static Tessellator Tessellator_getBufferBuilder() {
//$$ return Tessellator.instance;
//$$ }
//#endif
public static void BufferBuilder_beginPosCol(int mode) {
Tessellator_getBufferBuilder().begin(
mode
//#if MC>=10809
, VertexFormats.POSITION_COLOR
//#endif
);
}
public static void BufferBuilder_addPosCol(double x, double y, double z, int r, int g, int b, int a) {
//#if MC>=10809
Tessellator_getBufferBuilder().vertex(x, y, z).color(r, g, b, a).next();
//#else
//$$ Tessellator_getBufferBuilder().setColorRGBA(r, g, b, a);
//$$ Tessellator_getBufferBuilder().addVertex(x, y, z);
//#endif
}
public static void BufferBuilder_beginPosTex(int mode) {
Tessellator_getBufferBuilder().begin(
mode
//#if MC>=10809
, VertexFormats.POSITION_TEXTURE
//#endif
);
}
public static void BufferBuilder_addPosTex(double x, double y, double z, float u, float v) {
//#if MC>=10809
Tessellator_getBufferBuilder().vertex(x, y, z).texture(u, v).next();
//#else
//$$ Tessellator_getBufferBuilder().addVertexWithUV(x, y, z, u, v);
//#endif
}
public static void BufferBuilder_beginPosTexCol(int mode) {
Tessellator_getBufferBuilder().begin(
mode
//#if MC>=10809
, VertexFormats.POSITION_TEXTURE_COLOR
//#endif
);
}
public static void BufferBuilder_addPosTexCol(double x, double y, double z, float u, float v, int r, int g, int b, int a) {
//#if MC>=10809
Tessellator_getBufferBuilder().vertex(x, y, z).texture(u, v).color(r, g, b, a).next();
//#else
//$$ Tessellator_getBufferBuilder().setColorRGBA(r, g, b, a);
//$$ Tessellator_getBufferBuilder().addVertexWithUV(x, y, z, u, v);
//#endif
}
//#if MC>=10800 //#if MC>=10800
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static List<VertexFormatElement> getElements(VertexFormat vertexFormat) { public static List<VertexFormatElement> getElements(VertexFormat vertexFormat) {
@@ -571,30 +193,16 @@ public class MCVer {
} }
//#endif //#endif
public static Tessellator Tessellator_getInstance() { //#if MC<10800
//#if MC>=10800 //$$ public static RenderManager getRenderManager(@SuppressWarnings("unused") Minecraft mc) {
return Tessellator.getInstance(); //$$ return RenderManager.instance;
//#else //$$ }
//$$ return Tessellator.instance; //#endif
//#endif
}
public static EntityRenderDispatcher getRenderManager() {
//#if MC>=10800
return getMinecraft().getEntityRenderDispatcher();
//#else
//$$ return RenderManager.instance;
//#endif
}
public static MinecraftClient getMinecraft() { public static MinecraftClient getMinecraft() {
return MinecraftClient.getInstance(); return MinecraftClient.getInstance();
} }
public static float getRenderPartialTicks() {
return ((MinecraftAccessor) getMinecraft()).getTimer().tickDelta;
}
public static void addButton( public static void addButton(
Screen screen, Screen screen,
//#if MC>=11400 //#if MC>=11400
@@ -604,14 +212,15 @@ public class MCVer {
//#endif //#endif
) { ) {
GuiScreenAccessor acc = (GuiScreenAccessor) screen; GuiScreenAccessor acc = (GuiScreenAccessor) screen;
acc.getButtons().add(button);
//#if MC>=11400 //#if MC>=11400
acc.getChildren().add(button); acc.invokeAddButton(button);
//#else
//$$ acc.getButtons().add(button);
//#endif //#endif
} }
//#if MC>=11400 //#if MC>=11400
public static Optional<AbstractButtonWidget> findButton(List<AbstractButtonWidget> buttonList, @SuppressWarnings("unused") String text, @SuppressWarnings("unused") int id) { public static Optional<AbstractButtonWidget> findButton(Iterable<AbstractButtonWidget> buttonList, @SuppressWarnings("unused") String text, @SuppressWarnings("unused") int id) {
//#if MC>=11600 //#if MC>=11600
final TranslatableText message = new TranslatableText(text); final TranslatableText message = new TranslatableText(text);
//#else //#else
@@ -621,11 +230,17 @@ public class MCVer {
if (message.equals(b.getMessage())) { if (message.equals(b.getMessage())) {
return Optional.of(b); return Optional.of(b);
} }
//#if MC>=11600
// Fuzzy match (copy does not include children)
if (b.getMessage() != null && b.getMessage().copy().equals(message)) {
return Optional.of(b);
}
//#endif
} }
return Optional.empty(); return Optional.empty();
} }
//#else //#else
//$$ public static Optional<GuiButton> findButton(List<GuiButton> buttonList, @SuppressWarnings("unused") String text, int id) { //$$ public static Optional<GuiButton> findButton(Iterable<GuiButton> buttonList, @SuppressWarnings("unused") String text, int id) {
//$$ for (GuiButton b : buttonList) { //$$ for (GuiButton b : buttonList) {
//$$ if (b.id == id) { //$$ if (b.id == id) {
//$$ return Optional.of(b); //$$ return Optional.of(b);
@@ -671,26 +286,6 @@ public class MCVer {
//#endif //#endif
} }
public static void bindTexture(Identifier texture) {
//#if MC>=11500
getMinecraft().getTextureManager().bindTexture(texture);
//#else
//#if MC>=11400
//$$ getMinecraft().getTextureManager().bindTexture(texture);
//#else
//$$ getMinecraft().renderEngine.bindTexture(texture);
//#endif
//#endif
}
public static float cos(float val) {
return MathHelper.cos(val);
}
public static float sin(float val) {
return MathHelper.sin(val);
}
//#if MC>=10904 //#if MC>=10904
// TODO: this can be inlined once https://github.com/SpongePowered/Mixin/issues/305 is fixed // TODO: this can be inlined once https://github.com/SpongePowered/Mixin/issues/305 is fixed
public static Vec3d getPosition(Particle particle, float partialTicks) { public static Vec3d getPosition(Particle particle, float partialTicks) {
@@ -733,52 +328,68 @@ public class MCVer {
} }
public static void openURL(URI url) { public static void openURL(URI url) {
//#if MC>=11400
//#if MC>=11400 //#if MC>=11400
Util.getOperatingSystem().open(url); Util.getOperatingSystem().open(url);
//#else //#else
//$$ Util.getOSType().openURI(url);
//#endif
//#else
//$$ try { //$$ try {
//$$ Desktop.getDesktop().browse(url); //$$ Desktop.getDesktop().browse(url);
//$$ } catch (Throwable e) { //$$ } catch (Throwable e) {
//$$ LOGGER.error("Failed to open URL: ", e); //$$ LogManager.getLogger().error("Failed to open URL: ", e);
//$$ } //$$ }
//#endif //#endif
} }
public static String getBoundKey(KeyBinding keyBinding) { public static void pushMatrix() {
try { //#if MC>=11700
//#if MC>=11600 //$$ RenderSystem.getModelViewStack().push();
return keyBinding.getBoundKeyLocalizedText().getString(); //#else
//#else GlStateManager.pushMatrix();
//#if MC>=11400 //#endif
//$$ return keyBinding.getLocalizedName();
//#else
//$$ return Keyboard.getKeyName(keyBinding.getKeyCode());
//#endif
//#endif
} catch (ArrayIndexOutOfBoundsException e) {
// Apparently windows likes to press strange keys, see https://www.replaymod.com/forum/thread/55
return "Unknown";
}
} }
public static void playSound(Identifier sound) { public static void popMatrix() {
getMinecraft().getSoundManager().play( //#if MC>=11700
//#if MC>=11400 //$$ RenderSystem.getModelViewStack().pop();
PositionedSoundInstance.master(new SoundEvent(sound), 1.0F) //$$ RenderSystem.applyModelViewMatrix();
//#elseif MC>=10904 //#else
//$$ PositionedSoundRecord.getMasterRecord(new SoundEvent(sound), 1.0F) GlStateManager.popMatrix();
//#elseif MC>=10800 //#endif
//$$ PositionedSoundRecord.create(sound, 1.0F)
//#else
//$$ PositionedSoundRecord.createPositionedSoundRecord(sound, 1.0F)
//#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(BufferBuilder buffer, Vector3f p1, Vector3f p2, int color) {
int r = color >> 24 & 0xff;
int g = color >> 16 & 0xff;
int b = color >> 8 & 0xff;
int a = color & 0xff;
//#if MC>=11700
//$$ Vector3f n = Vector3f.sub(p2, p1, null);
//#endif
buffer.vertex(p1.x, p1.y, p1.z)
.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)
.color(r, g, b, a)
//#if MC>=11700
//$$ .normal(n.x, n.y, n.z)
//#endif
.next();
}
public static void bindTexture(Identifier id) {
new MinecraftGuiRenderer(null).bindTexture(id);
}
//#if MC<10900
//$$ public static class SoundEvent {}
//#endif
//#if MC>=11400 //#if MC>=11400
private static Boolean hasOptifine; private static Boolean hasOptifine;
public static boolean hasOptifine() { public static boolean hasOptifine() {

View File

@@ -0,0 +1,502 @@
package com.replaymod.core.versions;
import com.replaymod.gradle.remap.Pattern;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.options.KeyBinding;
import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.texture.TextureManager;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.entity.EntityRenderDispatcher;
import net.minecraft.client.sound.PositionedSoundInstance;
import net.minecraft.util.crash.CrashReportSection;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.Identifier;
import net.minecraft.world.World;
import net.minecraft.world.chunk.WorldChunk;
//#if MC>=11700
//#else
import org.lwjgl.opengl.GL11;
//#endif
//#if MC>=11400
import net.minecraft.client.gui.widget.AbstractButtonWidget;
import net.minecraft.client.util.Window;
//#else
//$$ import net.minecraft.client.gui.GuiButton;
//#endif
//#if MC>=10904
import net.minecraft.sound.SoundEvent;
import net.minecraft.util.crash.CrashCallable;
//#else
//$$ import java.util.concurrent.Callable;
//#endif
//#if MC>=10809
import net.minecraft.client.render.VertexFormats;
//#else
//#endif
//#if MC>=10800
import net.minecraft.client.render.BufferBuilder;
//#else
//$$ import net.minecraft.entity.EntityLivingBase;
//#endif
import java.util.Collection;
import java.util.List;
class Patterns {
//#if MC>=10904
@Pattern
private static void addCrashCallable(CrashReportSection category, String name, CrashCallable<String> callable) {
//#if MC>=11200
category.add(name, callable);
//#else
//$$ category.setDetail(name, callable);
//#endif
}
//#else
//$$ @Pattern
//$$ private static void addCrashCallable(CrashReportCategory category, String name, Callable<String> callable) {
//$$ category.addCrashSectionCallable(name, callable);
//$$ }
//#endif
@Pattern
private static double Entity_getX(Entity entity) {
//#if MC>=11500
return entity.getX();
//#else
//$$ return entity.x;
//#endif
}
@Pattern
private static double Entity_getY(Entity entity) {
//#if MC>=11500
return entity.getY();
//#else
//$$ return entity.y;
//#endif
}
@Pattern
private static double Entity_getZ(Entity entity) {
//#if MC>=11500
return entity.getZ();
//#else
//$$ return entity.z;
//#endif
}
@Pattern
private static void Entity_setYaw(Entity entity, float value) {
//#if MC>=11700
//$$ entity.setYaw(value);
//#else
entity.yaw = value;
//#endif
}
@Pattern
private static float Entity_getYaw(Entity entity) {
//#if MC>=11700
//$$ return entity.getYaw();
//#else
return entity.yaw;
//#endif
}
@Pattern
private static void Entity_setPitch(Entity entity, float value) {
//#if MC>=11700
//$$ entity.setPitch(value);
//#else
entity.pitch = value;
//#endif
}
@Pattern
private static float Entity_getPitch(Entity entity) {
//#if MC>=11700
//$$ return entity.getPitch();
//#else
return entity.pitch;
//#endif
}
@Pattern
private static void Entity_setPos(Entity entity, double x, double y, double z) {
//#if MC>=11500
entity.setPos(x, y, z);
//#else
//$$ { net.minecraft.entity.Entity self = entity; self.x = x; self.y = y; self.z = z; }
//#endif
}
//#if MC>=11400
@Pattern
private static void setWidth(AbstractButtonWidget button, int value) {
button.setWidth(value);
}
@Pattern
private static int getWidth(AbstractButtonWidget button) {
return button.getWidth();
}
@Pattern
private static int getHeight(AbstractButtonWidget button) {
//#if MC>=11600
return button.getHeight();
//#else
//$$ return ((com.replaymod.core.mixin.AbstractButtonWidgetAccessor) button).getHeight();
//#endif
}
//#else
//$$ @Pattern
//$$ private static void setWidth(GuiButton button, int value) {
//$$ button.width = value;
//$$ }
//$$
//$$ @Pattern
//$$ private static int getWidth(GuiButton button) {
//$$ return button.width;
//$$ }
//$$
//$$ @Pattern
//$$ private static int getHeight(GuiButton button) {
//$$ return button.height;
//$$ }
//#endif
@Pattern
private static String readString(PacketByteBuf buffer, int max) {
//#if MC>=10800
return buffer.readString(max);
//#else
//$$ return com.replaymod.core.versions.MCVer.tryReadString(buffer, max);
//#endif
}
@Pattern
//#if MC>=10800
private static Entity getRenderViewEntity(MinecraftClient mc) {
return mc.getCameraEntity();
}
//#else
//$$ private static EntityLivingBase getRenderViewEntity(Minecraft mc) {
//$$ return mc.renderViewEntity;
//$$ }
//#endif
@Pattern
//#if MC>=10800
private static void setRenderViewEntity(MinecraftClient mc, Entity entity) {
mc.setCameraEntity(entity);
}
//#else
//$$ private static void setRenderViewEntity(Minecraft mc, EntityLivingBase entity) {
//$$ mc.renderViewEntity = entity;
//$$ }
//#endif
@Pattern
private static Entity getVehicle(Entity passenger) {
//#if MC>=10904
return passenger.getVehicle();
//#else
//$$ return passenger.ridingEntity;
//#endif
}
@Pattern
private static Iterable<Entity> loadedEntityList(ClientWorld world) {
//#if MC>=11400
return world.getEntities();
//#else
//#if MC>=10809
//$$ return world.loadedEntityList;
//#else
//$$ return ((java.util.List<net.minecraft.entity.Entity>) world.loadedEntityList);
//#endif
//#endif
}
@Pattern
//#if MC>=11700
//$$ private static void getEntitySectionArray() {}
//#else
private static Collection<Entity>[] getEntitySectionArray(WorldChunk chunk) {
//#if MC>=11700
//$$ return obsolete(chunk);
//#elseif MC>=10800
return chunk.getEntitySectionArray();
//#else
//$$ return chunk.entityLists;
//#endif
}
//#endif
@Pattern
private static List<? extends PlayerEntity> playerEntities(World world) {
//#if MC>=11400
return world.getPlayers();
//#elseif MC>=10809
//$$ return world.playerEntities;
//#else
//$$ return ((List<? extends net.minecraft.entity.player.EntityPlayer>) world.playerEntities);
//#endif
}
@Pattern
private static boolean isOnMainThread(MinecraftClient mc) {
//#if MC>=11400
return mc.isOnThread();
//#else
//$$ return mc.isCallingFromMinecraftThread();
//#endif
}
@Pattern
private static void scheduleOnMainThread(MinecraftClient mc, Runnable runnable) {
//#if MC>=11400
mc.send(runnable);
//#else
//$$ mc.addScheduledTask(runnable);
//#endif
}
@Pattern
private static Window getWindow(MinecraftClient mc) {
//#if MC>=11500
return mc.getWindow();
//#elseif MC>=11400
//$$ return mc.window;
//#else
//$$ return new com.replaymod.core.versions.Window(mc);
//#endif
}
@Pattern
private static BufferBuilder Tessellator_getBuffer(Tessellator tessellator) {
//#if MC>=10800
return tessellator.getBuffer();
//#else
//$$ return new BufferBuilder(tessellator);
//#endif
}
//#if MC<11700
@Pattern
private static void BufferBuilder_beginPosCol(BufferBuilder buffer, int mode) {
//#if MC>=10809
buffer.begin(mode, VertexFormats.POSITION_COLOR);
//#else
//$$ buffer.startDrawing(mode /* POSITION_COLOR */);
//#endif
}
@Pattern
private static void BufferBuilder_addPosCol(BufferBuilder buffer, double x, double y, double z, int r, int g, int b, int a) {
//#if MC>=10809
buffer.vertex(x, y, z).color(r, g, b, a).next();
//#else
//$$ { WorldRenderer $buffer = buffer; double $x = x; double $y = y; double $z = z; $buffer.setColorRGBA(r, g, b, a); $buffer.addVertex($x, $y, $z); }
//#endif
}
@Pattern
private static void BufferBuilder_beginPosTex(BufferBuilder buffer, int mode) {
//#if MC>=10809
buffer.begin(mode, VertexFormats.POSITION_TEXTURE);
//#else
//$$ buffer.startDrawing(mode /* POSITION_TEXTURE */);
//#endif
}
@Pattern
private static void BufferBuilder_addPosTex(BufferBuilder buffer, double x, double y, double z, float u, float v) {
//#if MC>=10809
buffer.vertex(x, y, z).texture(u, v).next();
//#else
//$$ buffer.addVertexWithUV(x, y, z, u, v);
//#endif
}
@Pattern
private static void BufferBuilder_beginPosTexCol(BufferBuilder buffer, int mode) {
//#if MC>=10809
buffer.begin(mode, VertexFormats.POSITION_TEXTURE_COLOR);
//#else
//$$ buffer.startDrawing(mode /* POSITION_TEXTURE_COLOR */);
//#endif
}
@Pattern
private static void BufferBuilder_addPosTexCol(BufferBuilder buffer, double x, double y, double z, float u, float v, int r, int g, int b, int a) {
//#if MC>=10809
buffer.vertex(x, y, z).texture(u, v).color(r, g, b, a).next();
//#else
//$$ { WorldRenderer $buffer = buffer; double $x = x; double $y = y; double $z = z; float $u = u; float $v = v; $buffer.setColorRGBA(r, g, b, a); $buffer.addVertexWithUV($x, $y, $z, $u, $v); }
//#endif
}
//#else
//$$ @Pattern private static void BufferBuilder_beginPosCol() {}
//$$ @Pattern private static void BufferBuilder_addPosCol() {}
//$$ @Pattern private static void BufferBuilder_beginPosTex() {}
//$$ @Pattern private static void BufferBuilder_addPosTex() {}
//$$ @Pattern private static void BufferBuilder_beginPosTexCol() {}
//$$ @Pattern private static void BufferBuilder_addPosTexCol() {}
//#endif
@Pattern
private static Tessellator Tessellator_getInstance() {
//#if MC>=10800
return Tessellator.getInstance();
//#else
//$$ return Tessellator.instance;
//#endif
}
@Pattern
private static EntityRenderDispatcher getEntityRenderDispatcher(MinecraftClient mc) {
//#if MC>=10800
return mc.getEntityRenderDispatcher();
//#else
//$$ return com.replaymod.core.versions.MCVer.getRenderManager(mc);
//#endif
}
@Pattern
private static float getCameraYaw(EntityRenderDispatcher dispatcher) {
//#if MC>=11500
return dispatcher.camera.getYaw();
//#else
//$$ return dispatcher.cameraYaw;
//#endif
}
@Pattern
private static float getCameraPitch(EntityRenderDispatcher dispatcher) {
//#if MC>=11500
return dispatcher.camera.getPitch();
//#else
//$$ return dispatcher.cameraPitch;
//#endif
}
@Pattern
private static float getRenderPartialTicks(MinecraftClient mc) {
//#if MC>=10900
return mc.getTickDelta();
//#else
//$$ return ((com.replaymod.core.mixin.MinecraftAccessor) mc).getTimer().renderPartialTicks;
//#endif
}
@Pattern
private static TextureManager getTextureManager(MinecraftClient mc) {
//#if MC>=11400
return mc.getTextureManager();
//#else
//$$ return mc.renderEngine;
//#endif
}
@Pattern
private static String getBoundKeyName(KeyBinding keyBinding) {
//#if MC>=11600
return keyBinding.getBoundKeyLocalizedText().getString();
//#elseif MC>=11400
//$$ return keyBinding.getLocalizedName();
//#else
//$$ return org.lwjgl.input.Keyboard.getKeyName(keyBinding.getKeyCode());
//#endif
}
@Pattern
private static PositionedSoundInstance master(Identifier sound, float pitch) {
//#if MC>=10900
return PositionedSoundInstance.master(new SoundEvent(sound), pitch);
//#elseif MC>=10800
//$$ return PositionedSoundRecord.create(sound, pitch);
//#else
//$$ return PositionedSoundRecord.createPositionedSoundRecord(sound, pitch);
//#endif
}
@Pattern
private static boolean isKeyBindingConflicting(KeyBinding a, KeyBinding b) {
//#if MC>=10900
return a.equals(b);
//#else
//$$ return (a.getKeyCode() == b.getKeyCode());
//#endif
}
//#if MC>=11600
@Pattern
private static void BufferBuilder_beginLineStrip(BufferBuilder buffer, VertexFormat vertexFormat) {
//#if MC>=11700
//$$ buffer.begin(net.minecraft.client.render.VertexFormat.DrawMode.LINE_STRIP, VertexFormats.LINES);
//#else
buffer.begin(GL11.GL_LINE_STRIP, VertexFormats.POSITION_COLOR);
//#endif
}
@Pattern
private static void BufferBuilder_beginLines(BufferBuilder buffer) {
//#if MC>=11700
//$$ buffer.begin(net.minecraft.client.render.VertexFormat.DrawMode.LINES, VertexFormats.LINES);
//#else
buffer.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR);
//#endif
}
@Pattern
private static void BufferBuilder_beginQuads(BufferBuilder buffer, VertexFormat vertexFormat) {
//#if MC>=11700
//$$ buffer.begin(net.minecraft.client.render.VertexFormat.DrawMode.QUADS, vertexFormat);
//#else
buffer.begin(GL11.GL_QUADS, vertexFormat);
//#endif
}
//#else
//$$ @Pattern private static void BufferBuilder_beginLineStrip() {}
//$$ @Pattern private static void BufferBuilder_beginLines() {}
//$$ @Pattern private static void BufferBuilder_beginQuads() {}
//#endif
@Pattern
private static void GL11_glLineWidth(float width) {
//#if MC>=11700
//$$ com.mojang.blaze3d.systems.RenderSystem.lineWidth(width);
//#else
GL11.glLineWidth(width);
//#endif
}
@Pattern
private static void GL11_glTranslatef(float x, float y, float z) {
//#if MC>=11700
//$$ com.mojang.blaze3d.systems.RenderSystem.getModelViewStack().translate(x, y, z);
//#else
GL11.glTranslatef(x, y, z);
//#endif
}
@Pattern
private static void GL11_glRotatef(float angle, float x, float y, float z) {
//#if MC>=11700
//$$ { float $angle = angle; com.mojang.blaze3d.systems.RenderSystem.getModelViewStack().multiply(new net.minecraft.util.math.Quaternion(new net.minecraft.util.math.Vec3f(x, y, z), $angle, true)); }
//#else
GL11.glRotatef(angle, x, y, z);
//#endif
}
}

View File

@@ -0,0 +1 @@
// 1.12.2 and below

View File

@@ -0,0 +1 @@
// Forge only

View File

@@ -0,0 +1 @@
// 1.12.2 and before

View File

@@ -0,0 +1,30 @@
package com.replaymod.core.versions.scheduler;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
public interface Scheduler {
/**
* Execute the given runnable on the main client thread, returning only after it has been run (or after 30 seconds).
*/
void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException;
/**
* Execute the given runnable after game has started (once the overlay has been closed).
* Most importantly, it will run after resources (including language keys!) have been loaded.
* Below 1.14, this is equivalent to {@link #runLater(Runnable)}.
*/
void runPostStartup(Runnable runnable);
/**
* Pre-1.14 MC would hold the lock on the scheduledTasks queue while executing its tasks
* such that no new tasks could be submitted while one of them was running.
* This would cause issues with long-running tasks (e.g. video rendering) as it would
* block all async tasks (e.g. skin loading).
*/
void runLaterWithoutLock(Runnable runnable);
void runLater(Runnable runnable);
void runTasks();
}

View File

@@ -0,0 +1,124 @@
package com.replaymod.core.versions.scheduler;
import com.replaymod.core.mixin.MinecraftAccessor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.util.crash.CrashException;
import net.minecraft.util.thread.ReentrantThreadExecutor;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class SchedulerImpl implements Scheduler {
private static final MinecraftClient mc = MinecraftClient.getInstance();
@Override
public void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException {
if (mc.isOnThread()) {
runnable.run();
} else {
executor.submit(() -> {
runnable.run();
return null;
}).get(30, TimeUnit.SECONDS);
}
}
@Override
public void runPostStartup(Runnable runnable) {
runLater(new Runnable() {
@Override
public void run() {
if (mc.getOverlay() != null) {
// delay until after resources have been loaded
runLater(this);
return;
}
runnable.run();
}
});
}
/**
* Set when the currently running code has been scheduled by runLater.
* If this is the case, subsequent calls to runLater have to be delayed until all scheduled tasks have been
* processed, otherwise a livelock may occur.
*/
private boolean inRunLater = false;
private boolean inRenderTaskQueue = false;
// Starting 1.14 MC clears the queue of scheduled tasks on disconnect.
// This works fine for MC since it uses the queue only for packet handling but breaks our assumption that
// stuff submitted via runLater is actually always run (e.g. recording might not be fully stopped because parts
// of that are run via runLater and stopping the recording happens right around the time MC clears the queue).
// Luckily, that's also the version where MC pulled out the executor implementation, so we can just spin up our own.
public static class ReplayModExecutor extends ReentrantThreadExecutor<Runnable> {
private final Thread mcThread = Thread.currentThread();
private ReplayModExecutor(String string_1) {
super(string_1);
}
@Override
protected Runnable createTask(Runnable runnable) {
return runnable;
}
@Override
protected boolean canExecute(Runnable runnable) {
return true;
}
@Override
protected Thread getThread() {
return mcThread;
}
@Override
public void runTasks() {
super.runTasks();
}
}
public final ReplayModExecutor executor = new ReplayModExecutor("Client/ReplayMod");
@Override
public void runTasks() {
executor.runTasks();
}
@Override
public void runLaterWithoutLock(Runnable runnable) {
// MC 1.14+ no longer synchronizes on the queue while running its tasks
runLater(runnable);
}
@Override
public void runLater(Runnable runnable) {
runLater(runnable, () -> runLater(runnable));
}
private void runLater(Runnable runnable, Runnable defer) {
if (mc.isOnThread() && inRunLater && !inRenderTaskQueue) {
((MinecraftAccessor) mc).getRenderTaskQueue().offer(() -> {
inRenderTaskQueue = true;
try {
defer.run();
} finally {
inRenderTaskQueue = false;
}
});
} else {
executor.send(() -> {
inRunLater = true;
try {
runnable.run();
} catch (CrashException e) {
e.printStackTrace();
System.err.println(e.getReport().asString());
mc.setCrashReport(e.getReport());
} finally {
inRunLater = false;
}
});
}
}
}

View File

@@ -12,9 +12,9 @@ import com.replaymod.replaystudio.protocol.PacketTypeRegistry;
import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ReplayMetaData; import com.replaymod.replaystudio.replay.ReplayMetaData;
import com.replaymod.replaystudio.stream.IteratorStream; import com.replaymod.replaystudio.stream.IteratorStream;
import com.replaymod.replaystudio.us.myles.ViaVersion.api.Pair;
import com.replaymod.replaystudio.util.Utils; import com.replaymod.replaystudio.util.Utils;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.tuple.Pair;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -115,7 +115,7 @@ public class MarkerProcessor {
try (ReplayFile inputReplayFile = mod.openReplay(path)) { try (ReplayFile inputReplayFile = mod.openReplay(path)) {
metaData = inputReplayFile.getMetaData(); metaData = inputReplayFile.getMetaData();
} }
return Collections.singletonList(new Pair<>(path, metaData)); return Collections.singletonList(Pair.of(path, metaData));
} }
String replayName = FilenameUtils.getBaseName(path.getFileName().toString()); String replayName = FilenameUtils.getBaseName(path.getFileName().toString());
@@ -249,7 +249,7 @@ public class MarkerProcessor {
outputReplayFile.save(); outputReplayFile.save();
outputPaths.add(new Pair(outputPath, metaData)); outputPaths.add(Pair.of(outputPath, metaData));
} }
} }

View File

@@ -1,6 +1,5 @@
package com.replaymod.editor.handler; package com.replaymod.editor.handler;
import de.johni0702.minecraft.gui.utils.EventRegistrations;
import com.replaymod.core.utils.Utils; import com.replaymod.core.utils.Utils;
import com.replaymod.editor.ReplayModEditor; import com.replaymod.editor.ReplayModEditor;
import com.replaymod.editor.gui.GuiEditReplay; import com.replaymod.editor.gui.GuiEditReplay;
@@ -8,31 +7,15 @@ import com.replaymod.replay.gui.screen.GuiReplayViewer;
import de.johni0702.minecraft.gui.container.AbstractGuiScreen; import de.johni0702.minecraft.gui.container.AbstractGuiScreen;
import de.johni0702.minecraft.gui.container.GuiScreen; import de.johni0702.minecraft.gui.container.GuiScreen;
import de.johni0702.minecraft.gui.element.GuiButton; import de.johni0702.minecraft.gui.element.GuiButton;
import net.minecraft.util.crash.CrashReport; import de.johni0702.minecraft.gui.utils.EventRegistrations;
//#if FABRIC>=1
import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback; import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.util.crash.CrashReport;
import net.minecraft.client.gui.widget.AbstractButtonWidget;
import java.util.List;
//#else
//$$ import net.minecraftforge.client.event.GuiScreenEvent;
//$$ import net.minecraftforge.eventbus.api.SubscribeEvent;
//#endif
import java.io.IOException; import java.io.IOException;
import static com.replaymod.core.versions.MCVer.*;
public class GuiHandler extends EventRegistrations { public class GuiHandler extends EventRegistrations {
//#if FABRIC>=1 { on(InitScreenCallback.EVENT, (vanillaGuiScreen, buttonList) -> injectIntoReplayViewer(vanillaGuiScreen)); }
{ on(InitScreenCallback.EVENT, this::injectIntoReplayViewer); } public void injectIntoReplayViewer(net.minecraft.client.gui.screen.Screen vanillaGuiScreen) {
public void injectIntoReplayViewer(Screen vanillaGuiScreen, List<AbstractButtonWidget> buttonList) {
//#else
//$$ @SubscribeEvent
//$$ public void injectIntoReplayViewer(GuiScreenEvent.InitGuiEvent.Post event) {
//$$ net.minecraft.client.gui.screen.Screen vanillaGuiScreen = getGui(event);
//#endif
AbstractGuiScreen guiScreen = GuiScreen.from(vanillaGuiScreen); AbstractGuiScreen guiScreen = GuiScreen.from(vanillaGuiScreen);
if (!(guiScreen instanceof GuiReplayViewer)) { if (!(guiScreen instanceof GuiReplayViewer)) {
return; return;

View File

@@ -1,6 +1,8 @@
package com.replaymod.extras; package com.replaymod.extras;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
import com.replaymod.core.events.PostRenderCallback;
import com.replaymod.core.events.PreRenderCallback;
import com.replaymod.core.versions.MCVer.Keyboard; import com.replaymod.core.versions.MCVer.Keyboard;
import com.replaymod.replay.ReplayHandler; import com.replaymod.replay.ReplayHandler;
import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.ReplayModReplay;
@@ -14,14 +16,6 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects; import net.minecraft.entity.effect.StatusEffects;
//#if FABRIC>=1
import com.replaymod.core.events.PreRenderCallback;
import com.replaymod.core.events.PostRenderCallback;
//#else
//$$ import net.minecraftforge.eventbus.api.SubscribeEvent;
//$$ import net.minecraftforge.event.TickEvent;
//#endif
public class FullBrightness extends EventRegistrations implements Extra { public class FullBrightness extends EventRegistrations implements Extra {
private ReplayMod core; private ReplayMod core;
private ReplayModReplay module; private ReplayModReplay module;
@@ -72,14 +66,8 @@ public class FullBrightness extends EventRegistrations implements Extra {
return Type.Gamma; return Type.Gamma;
} }
//#if FABRIC>=1
{ on(PreRenderCallback.EVENT, this::preRender); } { on(PreRenderCallback.EVENT, this::preRender); }
private void preRender() { private void preRender() {
//#else
//$$ @SubscribeEvent
//$$ public void preRender(TickEvent.RenderTickEvent event) {
//$$ if (event.phase != TickEvent.Phase.START) return;
//#endif
if (active && module.getReplayHandler() != null) { if (active && module.getReplayHandler() != null) {
Type type = getType(); Type type = getType();
if (type == Type.Gamma || type == Type.Both) { if (type == Type.Gamma || type == Type.Both) {
@@ -98,14 +86,8 @@ public class FullBrightness extends EventRegistrations implements Extra {
} }
} }
//#if FABRIC>=1
{ on(PostRenderCallback.EVENT, this::postRender); } { on(PostRenderCallback.EVENT, this::postRender); }
private void postRender() { private void postRender() {
//#else
//$$ @SubscribeEvent
//$$ public void postRender(TickEvent.RenderTickEvent event) {
//$$ if (event.phase != TickEvent.Phase.END) return;
//#endif
if (active && module.getReplayHandler() != null) { if (active && module.getReplayHandler() != null) {
Type type = getType(); Type type = getType();
if (type == Type.Gamma || type == Type.Both) { if (type == Type.Gamma || type == Type.Both) {

View File

@@ -1,164 +0,0 @@
package com.replaymod.extras;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.versions.MCVer;
import de.johni0702.minecraft.gui.container.AbstractGuiScreen;
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.GuiButton;
import de.johni0702.minecraft.gui.element.GuiLabel;
import de.johni0702.minecraft.gui.function.Tickable;
import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.popup.AbstractGuiPopup;
import de.johni0702.minecraft.gui.utils.Colors;
import org.apache.commons.io.FileUtils;
import javax.net.ssl.HttpsURLConnection;
import java.io.File;
import java.io.FileOutputStream;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import static com.replaymod.core.utils.Utils.SSL_SOCKET_FACTORY;
import static com.replaymod.extras.ReplayModExtras.LOGGER;
public class OpenEyeExtra implements Extra {
private static final String DOWNLOAD_URL = "https://www.replaymod.com/dl/openeye/" + ReplayMod.getMinecraftVersion();
private ReplayMod mod;
@Override
public void register(ReplayMod mod) throws Exception {
this.mod = mod;
boolean isOpenEyeLoaded = MCVer.isModLoaded("OpenEye");
if (!isOpenEyeLoaded && mod.getSettingsRegistry().get(Setting.ASK_FOR_OPEN_EYE)) {
new Thread(() -> {
try {
LOGGER.trace("Checking for OpenEye availability");
HttpsURLConnection connection = (HttpsURLConnection) new URL(DOWNLOAD_URL).openConnection();
connection.setSSLSocketFactory(SSL_SOCKET_FACTORY);
connection.setRequestMethod("HEAD");
connection.connect();
LOGGER.trace("Got response code: {}", connection.getResponseCode());
if (connection.getResponseCode() == 200) {
mod.runLater(() -> new OfferGui(GuiScreen.wrap(mod.getMinecraft().currentScreen)).display());
} else {
LOGGER.info("Cannot offer OpenEye, server returned: {} {}",
connection.getResponseCode(), connection.getResponseMessage());
}
connection.disconnect();
} catch (Throwable e) {
LOGGER.error("Failed to check for OpenEye availability:", e);
}
}).start();
}
}
public class OfferGui extends AbstractGuiScreen<OfferGui> {
public final GuiScreen parent;
public final GuiPanel textPanel = new GuiPanel().setLayout(new VerticalLayout().setSpacing(3))
.addElements(new VerticalLayout.Data(0.5),
new GuiLabel().setI18nText("replaymod.gui.offeropeneye1"),
new GuiLabel().setI18nText("replaymod.gui.offeropeneye2"),
new GuiLabel().setI18nText("replaymod.gui.offeropeneye3"),
new GuiLabel().setI18nText("replaymod.gui.offeropeneye4"),
new GuiLabel().setI18nText("replaymod.gui.offeropeneye5"),
new GuiLabel().setI18nText("replaymod.gui.offeropeneye6"),
new GuiLabel().setI18nText("replaymod.gui.offeropeneye7"),
new GuiLabel().setI18nText("replaymod.gui.offeropeneye8"));
public final GuiPanel buttonPanel = new GuiPanel()
.setLayout(new HorizontalLayout(HorizontalLayout.Alignment.CENTER).setSpacing(5));
public final GuiPanel contentPanel = new GuiPanel(this).setLayout(new VerticalLayout().setSpacing(20))
.addElements(new VerticalLayout.Data(0.5), textPanel, buttonPanel);
public final GuiButton yesButton = new GuiButton(buttonPanel).setSize(150, 20).setI18nLabel("gui.yes");
public final GuiButton noButton = new GuiButton(buttonPanel).setSize(150, 20).setI18nLabel("gui.no");
public OfferGui(GuiScreen parent) {
this.parent = parent;
yesButton.onClick(() -> {
GuiPopup popup = new GuiPopup(OfferGui.this);
new Thread(() -> {
try {
File targetFile = new File(mod.getMinecraft().runDirectory, "mods/" + ReplayMod.getMinecraftVersion() + "/OpenEye.jar");
FileUtils.forceMkdir(targetFile.getParentFile());
HttpsURLConnection connection = (HttpsURLConnection) new URL(DOWNLOAD_URL).openConnection();
connection.setSSLSocketFactory(SSL_SOCKET_FACTORY);
ReadableByteChannel in = Channels.newChannel(connection.getInputStream());
FileChannel out = new FileOutputStream(targetFile).getChannel();
out.transferFrom(in, 0, Long.MAX_VALUE);
} catch (Throwable e) {
e.printStackTrace();
} finally {
mod.runLater(() -> {
popup.close();
parent.display();
});
}
}).start();
});
noButton.onClick(() -> {
mod.getSettingsRegistry().set(Setting.ASK_FOR_OPEN_EYE, false);
mod.getSettingsRegistry().save();
parent.display();
});
setLayout(new CustomLayout<OfferGui>() {
@Override
protected void layout(OfferGui container, int width, int height) {
pos(contentPanel, width / 2 - width(contentPanel) / 2, height / 2 - height(contentPanel) / 2);
}
});
}
@Override
protected OfferGui getThis() {
return this;
}
}
public static final class GuiPopup extends AbstractGuiPopup<GuiPopup> {
GuiPopup(GuiContainer container) {
super(container);
popup.addElements(null, new GuiIndicator().setColor(Colors.BLACK));
setBackgroundColor(Colors.DARK_TRANSPARENT);
open();
}
@Override
public void close() {
super.close();
}
@Override
protected GuiPopup getThis() {
return this;
}
private static final class GuiIndicator extends GuiLabel implements Tickable {
private int tick;
@Override
public void tick() {
tick++;
setText(new String[]{
"Ooooo",
"oOooo",
"ooOoo",
"oooOo",
"ooooO",
"oooOo",
"ooOoo",
"oOooo",
}[tick / 5 % 8]);
}
}
}
}

View File

@@ -24,8 +24,7 @@ public class ReplayModExtras implements Module {
YoutubeUpload.class, YoutubeUpload.class,
FullBrightness.class, FullBrightness.class,
QuickMode.class, QuickMode.class,
HotkeyButtons.class, HotkeyButtons.class
OpenEyeExtra.class
); );
private final Map<Class<? extends Extra>, Extra> instances = new HashMap<>(); private final Map<Class<? extends Extra>, Extra> instances = new HashMap<>();

View File

@@ -4,22 +4,15 @@ import com.replaymod.core.versions.MCVer;
import com.replaymod.render.RenderSettings; import com.replaymod.render.RenderSettings;
import com.replaymod.render.blend.BlendState; import com.replaymod.render.blend.BlendState;
import com.replaymod.render.capturer.RenderInfo; import com.replaymod.render.capturer.RenderInfo;
import com.replaymod.render.hooks.ForceChunkLoadingHook;
import com.replaymod.render.rendering.Pipelines; import com.replaymod.render.rendering.Pipelines;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.util.Window;
import net.minecraft.util.crash.CrashReport; import net.minecraft.util.crash.CrashReport;
//#if MC>=11400 import static com.replaymod.core.versions.MCVer.resizeMainWindow;
import com.replaymod.render.mixin.MainWindowAccessor;
import static com.replaymod.core.versions.MCVer.getWindow;
//#endif
//#if MC>=10800
import com.replaymod.render.hooks.ChunkLoadingRenderGlobal;
//#endif
import static com.replaymod.core.versions.MCVer.getRenderPartialTicks;
public class ScreenshotRenderer implements RenderInfo { public class ScreenshotRenderer implements RenderInfo {
@@ -35,20 +28,13 @@ public class ScreenshotRenderer implements RenderInfo {
public boolean renderScreenshot() throws Throwable { public boolean renderScreenshot() throws Throwable {
try { try {
//#if MC>=11400 Window window = mc.getWindow();
int displayWidthBefore = getWindow(mc).getFramebufferWidth(); int widthBefore = window.getFramebufferWidth();
int displayHeightBefore = getWindow(mc).getFramebufferHeight(); int heightBefore = window.getFramebufferHeight();
//#else
//$$ int displayWidthBefore = mc.displayWidth;
//$$ int displayHeightBefore = mc.displayHeight;
//#endif
boolean hideGUIBefore = mc.options.hudHidden; boolean hideGUIBefore = mc.options.hudHidden;
mc.options.hudHidden = true; mc.options.hudHidden = true;
//#if MC>=10800 ForceChunkLoadingHook clrg = new ForceChunkLoadingHook(mc.worldRenderer);
ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.worldRenderer);
//#endif
if (settings.getRenderMethod() == RenderSettings.RenderMethod.BLEND) { if (settings.getRenderMethod() == RenderSettings.RenderMethod.BLEND) {
BlendState.setState(new BlendState(settings.getOutputFile())); BlendState.setState(new BlendState(settings.getOutputFile()));
@@ -58,27 +44,10 @@ public class ScreenshotRenderer implements RenderInfo {
new ScreenshotWriter(settings.getOutputFile())).run(); new ScreenshotWriter(settings.getOutputFile())).run();
} }
//#if MC>=10800
clrg.uninstall(); clrg.uninstall();
//#endif
mc.options.hudHidden = hideGUIBefore; mc.options.hudHidden = hideGUIBefore;
//#if MC>=11400 resizeMainWindow(mc, widthBefore, heightBefore);
//noinspection ConstantConditions
MainWindowAccessor acc = (MainWindowAccessor) (Object) getWindow(mc);
acc.setFramebufferWidth(displayWidthBefore);
acc.setFramebufferHeight(displayHeightBefore);
mc.getFramebuffer().resize(displayWidthBefore, displayHeightBefore
//#if MC>=11400
, false
//#endif
);
//#if MC>=11500
mc.gameRenderer.onResized(displayWidthBefore, displayHeightBefore);
//#endif
//#else
//$$ mc.resize(displayWidthBefore, displayHeightBefore);
//#endif
return true; return true;
} catch (OutOfMemoryError e) { } catch (OutOfMemoryError e) {
e.printStackTrace(); e.printStackTrace();
@@ -107,7 +76,7 @@ public class ScreenshotRenderer implements RenderInfo {
@Override @Override
public float updateForNextFrame() { public float updateForNextFrame() {
framesDone++; framesDone++;
return getRenderPartialTicks(); return mc.getTickDelta();
} }
@Override @Override

View File

@@ -1,485 +0,0 @@
/* Based on https://github.com/Sk1erLLC/ModCore-Example-Mod/blob/4a362fa1c67cee28bdfc82bd5a99a30896b081fb/src/main/java/club/sk1er/mods/modcoreexample/ModCoreInstaller.java
*
* MIT License
*
* Copyright (c) 2020 Sk1er LLC
* Copyright (c) 2020 ModCore Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.replaymod.extras.modcore;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.TextArea;
import java.awt.Toolkit;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
//#if FABRIC>=1
import net.fabricmc.loader.api.FabricLoader;
//#else
//#if MC>=11400
//#else
//$$ import net.minecraft.launchwrapper.Launch;
//$$ import java.net.URLClassLoader;
//$$ import java.util.LinkedHashSet;
//#endif
//#endif
public class ModCoreInstaller {
private static final String VERSION_URL = "https://api.sk1er.club/modcore_versions";
private static final String className = "club.sk1er.mods.core.tweaker.ModCoreTweaker";
private static boolean errored = false;
private static String error;
private static File dataDir = null;
private static boolean isInitalized() {
try {
//#if MC<11400
//$$ LinkedHashSet<String> objects = new LinkedHashSet<>();
//$$ objects.add(className);
//$$ Launch.classLoader.clearNegativeEntries(objects);
//#endif
return Class.forName(className) != null;
} catch (ClassNotFoundException ignored) {
}
return false;
}
public static boolean isErrored() {
return errored;
}
public static String getError() {
return error;
}
private static void bail(String error) {
errored = true;
ModCoreInstaller.error = error;
}
private static JsonHolder readFile(File in) {
try {
return new JsonHolder(FileUtils.readFileToString(in));
} catch (IOException ignored) {
}
return new JsonHolder();
}
private static boolean initializeModCore(File gameDir) {
try {
Class<?> modCore = Class.forName("club.sk1er.mods.core.tweaker.ModCoreTweaker");
Method initialize = modCore.getMethod("initialize", File.class);
initialize.invoke(null, gameDir);
System.out.println("Loaded ModCore Successfully");
return true;
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
System.out.println("Did NOT initialize ModCore Successfully");
return false;
}
public static int initialize(File gameDir, String minecraftVersion) {
if (isInitalized()) return -1;
JsonHolder jsonHolder = fetchJSON(VERSION_URL);
if (!jsonHolder.has(minecraftVersion)) {
System.out.println("No ModCore target for " + minecraftVersion + ". This in fine, unless you're specifically looking for ModCore.");
return -2;
}
dataDir = new File(gameDir, "modcore");
if (!dataDir.exists()) {
if (!dataDir.mkdirs()) {
bail("Unable to create necessary files");
return 1;
}
}
String latestRemote = jsonHolder.optString(minecraftVersion);
boolean failed = jsonHolder.getKeys().size() == 0 || (jsonHolder.has("success") && !jsonHolder.optBoolean("success"));
File metadataFile = new File(dataDir, "metadata.json");
JsonHolder localMetadata = readFile(metadataFile);
if (failed) latestRemote = localMetadata.optString(minecraftVersion);
File modcoreFile = new File(dataDir, "Sk1er Modcore-" + latestRemote + " (" + minecraftVersion + ").jar");
if (!modcoreFile.exists() || !localMetadata.optString(minecraftVersion).equalsIgnoreCase(latestRemote) && !failed) {
//File does not exist, or is out of date, download it
File old = new File(dataDir, "Sk1er Modcore-" + localMetadata.optString(minecraftVersion) + " (" + minecraftVersion + ").jar");
if (old.exists()) old.delete();
if (!download("https://static.sk1er.club/repo/mods/modcore/" + latestRemote + "/" + minecraftVersion + "/ModCore-" + latestRemote + " (" + minecraftVersion + ").jar", latestRemote, modcoreFile, minecraftVersion, localMetadata)) {
bail("Unable to download");
return 2;
}
}
addToClasspath(modcoreFile);
if (!isInitalized()) {
bail("Something went wrong and it did not add the jar to the class path. Local file exists? " + modcoreFile.exists());
return 3;
}
return initializeModCore(gameDir) ? 0 : 4;
}
public static void addToClasspath(File file) {
try {
URL url = file.toURI().toURL();
ClassLoader classLoader = ModCoreInstaller.class.getClassLoader();
//#if MC>=11400
Method method = classLoader.getClass().getDeclaredMethod("addURL", URL.class);
//#else
//$$ Launch.classLoader.addURL(url);
//$$ Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
//#endif
method.setAccessible(true);
method.invoke(classLoader, url);
} catch (Exception e) {
throw new RuntimeException("Unexpected exception", e);
}
}
private static boolean download(String url, String version, File file, String mcver, JsonHolder versionData) {
url = url.replace(" ", "%20");
System.out.println("Downloading ModCore " + " version " + version + " from: " + url);
JFrame frame = new JFrame("ModCore Initializer");
JProgressBar bar = new JProgressBar();
TextArea comp = new TextArea("", 1, 1, TextArea.SCROLLBARS_NONE);
frame.getContentPane().add(comp);
frame.getContentPane().add(bar);
GridLayout manager = new GridLayout();
frame.setLayout(manager);
manager.setColumns(1);
manager.setRows(2);
comp.setText("Downloading Sk1er ModCore Library Version " + version + " for Minecraft " + mcver);
comp.setSize(399, 80);
comp.setEditable(false);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
Dimension preferredSize = new Dimension(400, 225);
bar.setSize(preferredSize);
frame.setSize(preferredSize);
frame.setResizable(false);
bar.setBorderPainted(true);
bar.setMinimum(0);
bar.setStringPainted(true);
frame.setVisible(true);
frame.setLocation(dim.width / 2 - frame.getSize().width / 2, dim.height / 2 - frame.getSize().height / 2);
Font font = bar.getFont();
bar.setFont(new Font(font.getName(), font.getStyle(), font.getSize() * 4));
comp.setFont(new Font(font.getName(), font.getStyle(), font.getSize() * 2));
try {
URL u = new URL(url);
HttpURLConnection connection = (HttpURLConnection) u.openConnection();
connection.setRequestMethod("GET");
connection.setUseCaches(true);
connection.addRequestProperty("User-Agent", "Mozilla/4.76 (Sk1er Modcore Initializer)");
connection.setReadTimeout(15000);
connection.setConnectTimeout(15000);
connection.setDoOutput(true);
InputStream is = connection.getInputStream();
int contentLength = connection.getContentLength();
FileOutputStream outputStream = new FileOutputStream(file);
byte[] buffer = new byte[1024];
System.out.println("MAX: " + contentLength);
bar.setMaximum(contentLength);
int read;
bar.setValue(0);
while ((read = is.read(buffer)) > 0) {
outputStream.write(buffer, 0, read);
bar.setValue(bar.getValue() + 1024);
}
outputStream.close();
FileUtils.write(new File(dataDir, "metadata.json"), versionData.put(mcver, version).toString());
} catch (Exception e) {
e.printStackTrace();
frame.dispose();
return false;
}
frame.dispose();
return true;
}
public static final JsonHolder fetchJSON(String url) {
return new JsonHolder(fetchString(url));
}
public static final String fetchString(String url) {
url = url.replace(" ", "%20");
System.out.println("Fetching " + url);
try {
URL u = new URL(url);
HttpURLConnection connection = (HttpURLConnection) u.openConnection();
connection.setRequestMethod("GET");
connection.setUseCaches(true);
connection.addRequestProperty("User-Agent", "Mozilla/4.76 (Sk1er ModCore)");
connection.setReadTimeout(15000);
connection.setConnectTimeout(15000);
connection.setDoOutput(true);
InputStream is = connection.getInputStream();
return IOUtils.toString(is, Charset.defaultCharset());
} catch (Exception e) {
e.printStackTrace();
}
return "Failed to fetch";
}
//Added because we need to use before ModCore is loaded
static class JsonHolder {
private JsonObject object;
public JsonHolder(JsonObject object) {
this.object = object;
}
public JsonHolder(String raw) {
if (raw == null)
object = new JsonObject();
else
try {
this.object = new JsonParser().parse(raw).getAsJsonObject();
} catch (Exception e) {
this.object = new JsonObject();
e.printStackTrace();
}
}
public JsonHolder() {
this(new JsonObject());
}
@Override
public String toString() {
if (object != null)
return object.toString();
return "{}";
}
public JsonHolder put(String key, boolean value) {
object.addProperty(key, value);
return this;
}
public void mergeNotOverride(JsonHolder merge) {
merge(merge, false);
}
public void mergeOverride(JsonHolder merge) {
merge(merge, true);
}
public void merge(JsonHolder merge, boolean override) {
JsonObject object = merge.getObject();
for (String s : merge.getKeys()) {
if (override || !this.has(s))
put(s, object.get(s));
}
}
private void put(String s, JsonElement element) {
this.object.add(s, element);
}
public JsonHolder put(String key, String value) {
object.addProperty(key, value);
return this;
}
public JsonHolder put(String key, int value) {
object.addProperty(key, value);
return this;
}
public JsonHolder put(String key, double value) {
object.addProperty(key, value);
return this;
}
public JsonHolder put(String key, long value) {
object.addProperty(key, value);
return this;
}
private JsonHolder defaultOptJSONObject(String key, JsonObject fallBack) {
try {
return new JsonHolder(object.get(key).getAsJsonObject());
} catch (Exception e) {
return new JsonHolder(fallBack);
}
}
public JsonArray defaultOptJSONArray(String key, JsonArray fallback) {
try {
return object.get(key).getAsJsonArray();
} catch (Exception e) {
return fallback;
}
}
public JsonArray optJSONArray(String key) {
return defaultOptJSONArray(key, new JsonArray());
}
public boolean has(String key) {
return object.has(key);
}
public long optLong(String key, long fallback) {
try {
return object.get(key).getAsLong();
} catch (Exception e) {
return fallback;
}
}
public long optLong(String key) {
return optLong(key, 0);
}
public boolean optBoolean(String key, boolean fallback) {
try {
return object.get(key).getAsBoolean();
} catch (Exception e) {
return fallback;
}
}
public boolean optBoolean(String key) {
return optBoolean(key, false);
}
public JsonObject optActualJSONObject(String key) {
try {
return object.get(key).getAsJsonObject();
} catch (Exception e) {
return new JsonObject();
}
}
public JsonHolder optJSONObject(String key) {
return defaultOptJSONObject(key, new JsonObject());
}
public int optInt(String key, int fallBack) {
try {
return object.get(key).getAsInt();
} catch (Exception e) {
return fallBack;
}
}
public int optInt(String key) {
return optInt(key, 0);
}
public String defaultOptString(String key, String fallBack) {
try {
return object.get(key).getAsString();
} catch (Exception e) {
return fallBack;
}
}
public String optString(String key) {
return defaultOptString(key, "");
}
public double optDouble(String key, double fallBack) {
try {
return object.get(key).getAsDouble();
} catch (Exception e) {
return fallBack;
}
}
public List<String> getKeys() {
List<String> tmp = new ArrayList<>();
object.entrySet().forEach(e -> tmp.add(e.getKey()));
return tmp;
}
public double optDouble(String key) {
return optDouble(key, 0.0);
}
public JsonObject getObject() {
return object;
}
public boolean isNull(String key) {
return object.has(key) && object.get(key).isJsonNull();
}
public JsonHolder put(String values, JsonHolder values1) {
return put(values, values1.getObject());
}
public JsonHolder put(String values, JsonObject object) {
this.object.add(values, object);
return this;
}
public void put(String blacklisted, JsonArray jsonElements) {
this.object.add(blacklisted, jsonElements);
}
public void remove(String header) {
object.remove(header);
}
}
}

View File

@@ -2,6 +2,7 @@ package com.replaymod.extras.playeroverview;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
import com.replaymod.core.events.PreRenderHandCallback;
import com.replaymod.core.utils.Utils; import com.replaymod.core.utils.Utils;
import com.replaymod.extras.Extra; import com.replaymod.extras.Extra;
import com.replaymod.replay.ReplayHandler; import com.replaymod.replay.ReplayHandler;
@@ -14,23 +15,11 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
//#if MC>=11400 //#if MC>=11400
import com.replaymod.core.events.PreRenderHandCallback;
import java.util.stream.Collectors; import java.util.stream.Collectors;
//#else //#else
//$$ import net.minecraftforge.client.event.RenderHandEvent;
//$$
//#if MC>=11400
//#else
//$$ import org.lwjgl.input.Keyboard; //$$ import org.lwjgl.input.Keyboard;
//#endif
//$$
//#if MC>=10800 //#if MC>=10800
//$$ import com.google.common.base.Predicate; //$$ import com.google.common.base.Predicate;
//#if MC>=11400
//$$ import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
//#else //#else
//$$ import cpw.mods.fml.common.eventhandler.EventPriority; //$$ import cpw.mods.fml.common.eventhandler.EventPriority;
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent; //$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
@@ -126,18 +115,9 @@ public class PlayerOverview extends EventRegistrations implements Extra {
hiddenPlayers.clear(); hiddenPlayers.clear();
} }
//#if MC>=11400
{ on(PreRenderHandCallback.EVENT, this::shouldHideHand); } { on(PreRenderHandCallback.EVENT, this::shouldHideHand); }
//#else
//$$ @SubscribeEvent
//$$ public void oRenderHand(RenderHandEvent event) {
//$$ if (shouldHideHand()) {
//$$ event.setCanceled(true);
//$$ }
//$$ }
//#endif
private boolean shouldHideHand() { private boolean shouldHideHand() {
Entity view = getRenderViewEntity(module.getCore().getMinecraft()); Entity view = module.getCore().getMinecraft().getCameraEntity();
return view != null && isHidden(view.getUuid()); return view != null && isHidden(view.getUuid());
} }

View File

@@ -53,13 +53,13 @@ public class PlayerOverviewGui extends GuiScreen implements Closeable {
public final GuiCheckbox checkAll = new GuiCheckbox(contentPanel){ public final GuiCheckbox checkAll = new GuiCheckbox(contentPanel){
@Override @Override
public void onClick() { public void onClick() {
playersScrollable.forEach(IGuiCheckbox.class).setChecked(true); playersScrollable.invokeAll(IGuiCheckbox.class, e -> e.setChecked(true));
} }
}.setLabel("").setChecked(true).setTooltip(new GuiTooltip().setI18nText("replaymod.gui.playeroverview.showall")); }.setLabel("").setChecked(true).setTooltip(new GuiTooltip().setI18nText("replaymod.gui.playeroverview.showall"));
public final GuiCheckbox uncheckAll = new GuiCheckbox(contentPanel){ public final GuiCheckbox uncheckAll = new GuiCheckbox(contentPanel){
@Override @Override
public void onClick() { public void onClick() {
playersScrollable.forEach(IGuiCheckbox.class).setChecked(false); playersScrollable.invokeAll(IGuiCheckbox.class, e -> e.setChecked(false));
} }
}.setLabel("").setChecked(false).setTooltip(new GuiTooltip().setI18nText("replaymod.gui.playeroverview.hideall")); }.setLabel("").setChecked(false).setTooltip(new GuiTooltip().setI18nText("replaymod.gui.playeroverview.hideall"));

View File

@@ -31,7 +31,6 @@ import net.minecraft.util.Util;
//$$ import org.lwjgl.Sys; //$$ import org.lwjgl.Sys;
//#endif //#endif
import javax.annotation.Nullable;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.imageio.ImageReader; import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageInputStream;
@@ -116,36 +115,27 @@ public class GuiYoutubeUpload extends GuiScreen {
public final GuiButton thumbnailButton = new GuiButton().onClick(new Runnable() { public final GuiButton thumbnailButton = new GuiButton().onClick(new Runnable() {
@Override @Override
public void run() { public void run() {
Futures.addCallback( GuiFileChooserPopup.openLoadGui(
GuiFileChooserPopup.openLoadGui(GuiYoutubeUpload.this, "replaymod.gui.load", GuiYoutubeUpload.this,
ImageIO.getReaderFileSuffixes()).getFuture(), "replaymod.gui.load",
new FutureCallback<File>() { ImageIO.getReaderFileSuffixes()
@Override ).onAccept(file -> {
public void onSuccess(@Nullable File result) { thumbnailButton.setLabel(file.getName());
if (result != null) { Image image;
thumbnailButton.setLabel(result.getName()); try {
Image image; thumbnailImage = IOUtils.toByteArray(new FileInputStream(file));
try { ImageInputStream in = ImageIO.createImageInputStream(new ByteArrayInputStream(thumbnailImage));
thumbnailImage = IOUtils.toByteArray(new FileInputStream(result)); ImageReader reader = ImageIO.getImageReaders(in).next();
ImageInputStream in = ImageIO.createImageInputStream(new ByteArrayInputStream(thumbnailImage)); thumbnailFormat = reader.getFormatName().toLowerCase();
ImageReader reader = ImageIO.getImageReaders(in).next(); image = Image.read(new ByteArrayInputStream(thumbnailImage));
thumbnailFormat = reader.getFormatName().toLowerCase(); } catch (Throwable t) {
image = Image.read(new ByteArrayInputStream(thumbnailImage)); t.printStackTrace();
} catch (Throwable t) { thumbnailImage = null;
t.printStackTrace(); image = null;
thumbnailImage = null; }
image = null; thumbnail.setTexture(image);
} inputValidation.run();
thumbnail.setTexture(image); });
inputValidation.run();
}
}
@Override
public void onFailure(Throwable t) {
throw new RuntimeException(t);
}
});
} }
}).setSize(200, 20).setI18nLabel("replaymod.gui.videothumbnail"); }).setSize(200, 20).setI18nLabel("replaymod.gui.videothumbnail");
@@ -191,7 +181,7 @@ public class GuiYoutubeUpload extends GuiScreen {
} }
private void setState(boolean uploading) { private void setState(boolean uploading) {
forEach(GuiElement.class).setEnabled(!uploading); invokeAll(GuiElement.class, e -> e.setEnabled(!uploading));
uploadButton.setEnabled(); uploadButton.setEnabled();
if (uploading) { if (uploading) {
uploadButton.onClick(() -> { uploadButton.onClick(() -> {

View File

@@ -3,19 +3,11 @@ package com.replaymod.extras.youtube;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
import com.replaymod.extras.Extra; import com.replaymod.extras.Extra;
import com.replaymod.render.gui.GuiRenderingDone; import com.replaymod.render.gui.GuiRenderingDone;
import de.johni0702.minecraft.gui.container.GuiScreen; import de.johni0702.minecraft.gui.container.AbstractGuiScreen;
import de.johni0702.minecraft.gui.element.GuiButton; import de.johni0702.minecraft.gui.element.GuiButton;
import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.utils.EventRegistrations;
import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback;
//#if FABRIC>=1
import de.johni0702.minecraft.gui.versions.callbacks.OpenGuiScreenCallback;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
//#else
//$$ import net.minecraftforge.client.event.GuiScreenEvent;
//$$ import net.minecraftforge.eventbus.api.SubscribeEvent;
//#endif
import static com.replaymod.core.versions.MCVer.*;
public class YoutubeUpload extends EventRegistrations implements Extra { public class YoutubeUpload extends EventRegistrations implements Extra {
@Override @Override
@@ -23,16 +15,11 @@ public class YoutubeUpload extends EventRegistrations implements Extra {
register(); register();
} }
//#if FABRIC>=1 { on(InitScreenCallback.EVENT, ((screen, buttons) -> onGuiOpen(screen))); }
{ on(OpenGuiScreenCallback.EVENT, this::onGuiOpen); }
private void onGuiOpen(Screen vanillaGui) { private void onGuiOpen(Screen vanillaGui) {
//#else AbstractGuiScreen<?> abstractScreen = de.johni0702.minecraft.gui.container.GuiScreen.from(vanillaGui);
//$$ @SubscribeEvent if (abstractScreen instanceof GuiRenderingDone) {
//$$ public void onGuiOpen(GuiScreenEvent.InitGuiEvent.Post event) { GuiRenderingDone gui = (GuiRenderingDone) abstractScreen;
//$$ net.minecraft.client.gui.screen.Screen vanillaGui = getGui(event);
//#endif
if (GuiScreen.from(vanillaGui) instanceof GuiRenderingDone) {
GuiRenderingDone gui = (GuiRenderingDone) GuiScreen.from(vanillaGui);
// Check if there already is a youtube button // Check if there already is a youtube button
if (gui.actionsPanel.getChildren().stream().anyMatch(it -> it instanceof YoutubeButton)) { if (gui.actionsPanel.getChildren().stream().anyMatch(it -> it instanceof YoutubeButton)) {
return; // Button already added return; // Button already added

View File

@@ -0,0 +1,11 @@
package com.replaymod.gradle.remap;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface Pattern {
}

View File

@@ -65,18 +65,15 @@ public class GuiKeyframeRepository extends GuiScreen implements Closeable, Typea
public final GuiButton overwriteButton = new GuiButton().onClick(new Runnable() { public final GuiButton overwriteButton = new GuiButton().onClick(new Runnable() {
@Override @Override
public void run() { public void run() {
GuiYesNoPopup popup = GuiYesNoPopup.open(GuiKeyframeRepository.this, GuiYesNoPopup.open(GuiKeyframeRepository.this,
new GuiLabel().setI18nText("replaymod.gui.keyframerepo.overwrite").setColor(Colors.BLACK) new GuiLabel().setI18nText("replaymod.gui.keyframerepo.overwrite").setColor(Colors.BLACK)
).setYesI18nLabel("gui.yes").setNoI18nLabel("gui.no"); ).setYesI18nLabel("gui.yes").setNoI18nLabel("gui.no").onAccept(() -> {
Utils.addCallback(popup.getFuture(), doIt -> { for (Entry entry : selectedEntries) {
if (doIt) { timelines.put(entry.name, currentTimeline);
for (Entry entry : selectedEntries) {
timelines.put(entry.name, currentTimeline);
}
overwriteButton.setDisabled();
save();
} }
}, Throwable::printStackTrace); overwriteButton.setDisabled();
save();
});
} }
}).setSize(75, 20).setI18nLabel("replaymod.gui.overwrite").setDisabled(); }).setSize(75, 20).setI18nLabel("replaymod.gui.overwrite").setDisabled();
public final GuiButton saveAsButton = new GuiButton().onClick(new Runnable() { public final GuiButton saveAsButton = new GuiButton().onClick(new Runnable() {
@@ -103,21 +100,11 @@ public class GuiKeyframeRepository extends GuiScreen implements Closeable, Typea
&& !timelines.containsKey(nameField.getText())); && !timelines.containsKey(nameField.getText()));
} }
}); });
Futures.addCallback(popup.getFuture(), new FutureCallback<Boolean>() { popup.onAccept(() -> {
@Override String name = nameField.getText();
public void onSuccess(Boolean save) { timelines.put(name, currentTimeline);
if (save) { list.getListPanel().addElements(null, new Entry(name));
String name = nameField.getText(); save();
timelines.put(name, currentTimeline);
list.getListPanel().addElements(null, new Entry(name));
save();
}
}
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
}); });
} }
}).setSize(75, 20).setI18nLabel("replaymod.gui.saveas"); }).setSize(75, 20).setI18nLabel("replaymod.gui.saveas");
@@ -161,50 +148,29 @@ public class GuiKeyframeRepository extends GuiScreen implements Closeable, Typea
&& !timelines.containsKey(nameField.getText())); && !timelines.containsKey(nameField.getText()));
} }
}); });
Futures.addCallback(popup.getFuture(), new FutureCallback<Boolean>() { popup.onAccept(() -> {
@Override String name = nameField.getText();
public void onSuccess(Boolean save) { timelines.put(name, timelines.remove(selectedEntry.name));
if (save) { selectedEntry.name = name;
String name = nameField.getText(); selectedEntry.label.setText(name);
timelines.put(name, timelines.remove(selectedEntry.name)); save();
selectedEntry.name = name;
selectedEntry.label.setText(name);
save();
}
}
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
}); });
} }
}).setSize(75, 20).setI18nLabel("replaymod.gui.rename").setDisabled(); }).setSize(75, 20).setI18nLabel("replaymod.gui.rename").setDisabled();
public final GuiButton removeButton = new GuiButton().onClick(new Runnable() { public final GuiButton removeButton = new GuiButton().onClick(new Runnable() {
@Override @Override
public void run() { public void run() {
GuiYesNoPopup popup = GuiYesNoPopup.open(GuiKeyframeRepository.this, GuiYesNoPopup.open(GuiKeyframeRepository.this,
new GuiLabel().setI18nText("replaymod.gui.keyframerepo.delete").setColor(Colors.BLACK) new GuiLabel().setI18nText("replaymod.gui.keyframerepo.delete").setColor(Colors.BLACK)
).setYesI18nLabel("replaymod.gui.delete").setNoI18nLabel("replaymod.gui.cancel"); ).setYesI18nLabel("replaymod.gui.delete").setNoI18nLabel("replaymod.gui.cancel").onAccept(() -> {
Futures.addCallback(popup.getFuture(), new FutureCallback<Boolean>() { for (Entry entry : selectedEntries) {
@Override timelines.remove(entry.name);
public void onSuccess(Boolean delete) { list.getListPanel().removeElement(entry);
if (delete) {
for (Entry entry : selectedEntries) {
timelines.remove(entry.name);
list.getListPanel().removeElement(entry);
}
selectedEntries.clear();
updateButtons();
save();
}
} }
@Override selectedEntries.clear();
public void onFailure(Throwable t) { updateButtons();
t.printStackTrace(); save();
}
}); });
} }
}).setSize(75, 20).setI18nLabel("replaymod.gui.remove").setDisabled(); }).setSize(75, 20).setI18nLabel("replaymod.gui.remove").setDisabled();

View File

@@ -4,7 +4,6 @@ import com.replaymod.core.ReplayMod;
import com.replaymod.core.utils.Utils; import com.replaymod.core.utils.Utils;
import com.replaymod.core.versions.MCVer; import com.replaymod.core.versions.MCVer;
import com.replaymod.editor.gui.MarkerProcessor; import com.replaymod.editor.gui.MarkerProcessor;
import com.replaymod.recording.Setting;
import com.replaymod.recording.packet.PacketListener; import com.replaymod.recording.packet.PacketListener;
import de.johni0702.minecraft.gui.container.GuiPanel; import de.johni0702.minecraft.gui.container.GuiPanel;
import de.johni0702.minecraft.gui.container.VanillaGuiScreen; import de.johni0702.minecraft.gui.container.VanillaGuiScreen;
@@ -12,23 +11,15 @@ import de.johni0702.minecraft.gui.element.GuiButton;
import de.johni0702.minecraft.gui.layout.CustomLayout; import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout; import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.utils.EventRegistrations;
import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback;
import net.minecraft.client.gui.screen.GameMenuScreen; import net.minecraft.client.gui.screen.GameMenuScreen;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
//#if FABRIC>=1
import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback;
//#else
//$$ import net.minecraftforge.client.event.GuiScreenEvent;
//$$ import net.minecraftforge.common.MinecraftForge;
//$$ import net.minecraftforge.eventbus.api.SubscribeEvent;
//$$
//$$ import static com.replaymod.core.versions.MCVer.getGui;
//#endif
//#if MC>=11400 //#if MC>=11400
import net.minecraft.client.gui.widget.AbstractButtonWidget; import net.minecraft.client.gui.widget.AbstractButtonWidget;
//#endif //#endif
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
@@ -85,19 +76,14 @@ public class GuiRecordingControls extends EventRegistrations {
buttonPauseResume.setEnabled(!stopped); buttonPauseResume.setEnabled(!stopped);
} }
//#if FABRIC>=1
{ on(InitScreenCallback.EVENT, this::injectIntoIngameMenu); } { on(InitScreenCallback.EVENT, this::injectIntoIngameMenu); }
private void injectIntoIngameMenu(Screen guiScreen, List<AbstractButtonWidget> buttonList) { private void injectIntoIngameMenu(Screen guiScreen,
//#else //#if MC>=11400
//$$ @SubscribeEvent Collection<AbstractButtonWidget> buttonList
//$$ public void injectIntoIngameMenu(GuiScreenEvent.InitGuiEvent.Post event) { //#else
//$$ Screen guiScreen = getGui(event); //$$ Collection<net.minecraft.client.gui.GuiButton> buttonList
//#if MC>=11400 //#endif
//$$ List<Widget> buttonList = MCVer.getButtonList(event); ) {
//#else
//$$ List<net.minecraft.client.gui.GuiButton> buttonList = MCVer.getButtonList(event);
//#endif
//#endif
if (!(guiScreen instanceof GameMenuScreen)) { if (!(guiScreen instanceof GameMenuScreen)) {
return; return;
} }

View File

@@ -1,27 +1,18 @@
package com.replaymod.recording.gui; package com.replaymod.recording.gui;
import com.replaymod.core.SettingsRegistry; import com.replaymod.core.SettingsRegistry;
import com.replaymod.core.versions.MCVer;
import com.replaymod.recording.Setting; import com.replaymod.recording.Setting;
import de.johni0702.minecraft.gui.GuiRenderer; import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.MinecraftGuiRenderer; import de.johni0702.minecraft.gui.MinecraftGuiRenderer;
import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.utils.EventRegistrations;
import de.johni0702.minecraft.gui.versions.callbacks.RenderHudCallback;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer; import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
//#if FABRIC>=1
import de.johni0702.minecraft.gui.versions.callbacks.RenderHudCallback;
//#else
//$$ import net.minecraftforge.client.event.RenderGameOverlayEvent;
//$$ import net.minecraftforge.common.MinecraftForge;
//$$ import net.minecraftforge.eventbus.api.SubscribeEvent;
//#endif
import static com.replaymod.core.ReplayMod.TEXTURE; import static com.replaymod.core.ReplayMod.TEXTURE;
import static com.replaymod.core.ReplayMod.TEXTURE_SIZE; import static com.replaymod.core.ReplayMod.TEXTURE_SIZE;
import static com.replaymod.core.versions.MCVer.*;
import static com.mojang.blaze3d.platform.GlStateManager.*; import static com.mojang.blaze3d.platform.GlStateManager.*;
/** /**
@@ -41,27 +32,18 @@ public class GuiRecordingOverlay extends EventRegistrations {
/** /**
* Render the recording icon and text in the top left corner of the screen. * Render the recording icon and text in the top left corner of the screen.
*/ */
//#if FABRIC>=1
{ on(RenderHudCallback.EVENT, (stack, partialTicks) -> renderRecordingIndicator(stack)); } { on(RenderHudCallback.EVENT, (stack, partialTicks) -> renderRecordingIndicator(stack)); }
private void renderRecordingIndicator(MatrixStack stack) { private void renderRecordingIndicator(MatrixStack stack) {
//#else
//$$ @SubscribeEvent
//$$ public void renderRecordingIndicator(RenderGameOverlayEvent.Post event) {
//$$ if (getType(event) != RenderGameOverlayEvent.ElementType.ALL) return;
//$$ MatrixStack stack = new MatrixStack();
//#endif
if (guiControls.isStopped()) return; if (guiControls.isStopped()) return;
if (settingsRegistry.get(Setting.INDICATOR)) { if (settingsRegistry.get(Setting.INDICATOR)) {
TextRenderer fontRenderer = mc.textRenderer; TextRenderer fontRenderer = mc.textRenderer;
String text = guiControls.isPaused() ? I18n.translate("replaymod.gui.paused") : I18n.translate("replaymod.gui.recording"); String text = guiControls.isPaused() ? I18n.translate("replaymod.gui.paused") : I18n.translate("replaymod.gui.recording");
fontRenderer.draw( MinecraftGuiRenderer renderer = new MinecraftGuiRenderer(stack);
//#if MC>=11600 renderer.drawString(30, 18 - (fontRenderer.fontHeight / 2), 0xffffffff, text.toUpperCase());
stack, renderer.bindTexture(TEXTURE);
//#endif //#if MC<11700
text.toUpperCase(), 30, 18 - (fontRenderer.fontHeight / 2), 0xffffffff);
bindTexture(TEXTURE);
enableAlphaTest(); enableAlphaTest();
GuiRenderer renderer = new MinecraftGuiRenderer(stack, MCVer.newScaledResolution(mc)); //#endif
renderer.drawTexturedRect(10, 10, 58, 20, 16, 16, 16, 16, TEXTURE_SIZE, TEXTURE_SIZE); renderer.drawTexturedRect(10, 10, 58, 20, 16, 16, 16, 16, TEXTURE_SIZE, TEXTURE_SIZE);
} }
} }

View File

@@ -5,7 +5,6 @@ import com.replaymod.core.utils.Utils;
import com.replaymod.recording.Setting; import com.replaymod.recording.Setting;
import com.replaymod.replay.gui.screen.GuiReplayViewer; import com.replaymod.replay.gui.screen.GuiReplayViewer;
import com.replaymod.replaystudio.replay.ReplayMetaData; import com.replaymod.replaystudio.replay.ReplayMetaData;
import com.replaymod.replaystudio.us.myles.ViaVersion.api.Pair;
import de.johni0702.minecraft.gui.container.AbstractGuiScreen; import de.johni0702.minecraft.gui.container.AbstractGuiScreen;
import de.johni0702.minecraft.gui.container.GuiContainer; import de.johni0702.minecraft.gui.container.GuiContainer;
import de.johni0702.minecraft.gui.container.GuiPanel; import de.johni0702.minecraft.gui.container.GuiPanel;
@@ -25,6 +24,7 @@ import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.util.crash.CrashReport; import net.minecraft.util.crash.CrashReport;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;

View File

@@ -3,6 +3,7 @@ package com.replaymod.recording.handler;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
import com.replaymod.core.utils.ModCompat; import com.replaymod.core.utils.ModCompat;
import com.replaymod.core.utils.Utils; import com.replaymod.core.utils.Utils;
import com.replaymod.core.versions.MCVer;
import com.replaymod.editor.gui.MarkerProcessor; import com.replaymod.editor.gui.MarkerProcessor;
import com.replaymod.recording.ServerInfoExt; import com.replaymod.recording.ServerInfoExt;
import com.replaymod.recording.Setting; import com.replaymod.recording.Setting;
@@ -137,7 +138,7 @@ public class ConnectionEventHandler {
metaData.setCustomServerName(serverName); metaData.setCustomServerName(serverName);
metaData.setGenerator("ReplayMod v" + ReplayMod.instance.getVersion()); metaData.setGenerator("ReplayMod v" + ReplayMod.instance.getVersion());
metaData.setDate(System.currentTimeMillis()); metaData.setDate(System.currentTimeMillis());
metaData.setMcVersion(ReplayMod.getMinecraftVersion()); metaData.setMcVersion(ReplayMod.instance.getMinecraftVersion());
packetListener = new PacketListener(core, outputPath, replayFile, metaData); packetListener = new PacketListener(core, outputPath, replayFile, metaData);
Channel channel = ((NetworkManagerAccessor) networkManager).getChannel(); Channel channel = ((NetworkManagerAccessor) networkManager).getChannel();
channel.pipeline().addBefore(packetHandlerKey, "replay_recorder", packetListener); channel.pipeline().addBefore(packetHandlerKey, "replay_recorder", packetListener);

View File

@@ -1,31 +1 @@
//#if MC<11400 // 1.12.2 and below
//$$ package com.replaymod.recording.handler;
//$$
//$$ import io.netty.channel.ChannelHandlerContext;
//$$ import io.netty.channel.SimpleChannelInboundHandler;
//$$ import net.minecraftforge.fml.common.network.handshake.FMLHandshakeMessage;
//$$
//$$ /**
//$$ * Filters out all handshake packets that were sent for recording but must
//$$ * not actually be handled.
//$$ * This handler is only present when connected to the integrated server as
//$$ * otherwise all packets must be handled.
//$$ *
//$$ * When in single player, the game state packets must never be handled
//$$ * otherwise wired bugs related to semi-singletons can occur.
//$$ * See https://bugs.replaymod.com/show_bug.cgi?id=44
//$$ */
//$$ public class FMLHandshakeFilter extends SimpleChannelInboundHandler<FMLHandshakeMessage> {
//$$ @Override
//$$ protected void channelRead0(ChannelHandlerContext ctx, FMLHandshakeMessage msg) throws Exception {
//#if MC>=10800
//$$ if (!(msg instanceof FMLHandshakeMessage.RegistryData)) {
//#else
//$$ if (!(msg instanceof FMLHandshakeMessage.ModIdData)) {
//#endif
//$$ // Pass on everything but RegistryData messages
//$$ ctx.fireChannelRead(msg);
//$$ }
//$$ }
//$$ }
//#endif

View File

@@ -14,23 +14,13 @@ import de.johni0702.minecraft.gui.element.GuiToggleButton;
import de.johni0702.minecraft.gui.layout.CustomLayout; import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.popup.GuiInfoPopup; import de.johni0702.minecraft.gui.popup.GuiInfoPopup;
import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.utils.EventRegistrations;
import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback;
import net.minecraft.client.gui.screen.AddServerScreen; import net.minecraft.client.gui.screen.AddServerScreen;
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
import net.minecraft.client.gui.screen.world.SelectWorldScreen; import net.minecraft.client.gui.screen.world.SelectWorldScreen;
import net.minecraft.client.network.ServerInfo; import net.minecraft.client.network.ServerInfo;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
//#if FABRIC>=1
import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback;
import net.minecraft.client.gui.screen.Screen;
//#else
//$$ import net.minecraftforge.client.event.GuiScreenEvent;
//$$ import net.minecraftforge.common.MinecraftForge;
//$$ import net.minecraftforge.eventbus.api.SubscribeEvent;
//$$
//$$ import static com.replaymod.core.versions.MCVer.getGui;
//#endif
public class GuiHandler extends EventRegistrations { public class GuiHandler extends EventRegistrations {
private final ReplayMod mod; private final ReplayMod mod;
@@ -39,14 +29,8 @@ public class GuiHandler extends EventRegistrations {
this.mod = mod; this.mod = mod;
} }
//#if FABRIC>=1
{ on(InitScreenCallback.EVENT, (screen, buttons) -> onGuiInit(screen)); } { on(InitScreenCallback.EVENT, (screen, buttons) -> onGuiInit(screen)); }
private void onGuiInit(Screen gui) { private void onGuiInit(net.minecraft.client.gui.screen.Screen gui) {
//#else
//$$ @SubscribeEvent
//$$ public void onGuiInit(GuiScreenEvent.InitGuiEvent.Post event) {
//$$ net.minecraft.client.gui.screen.Screen gui = getGui(event);
//#endif
if (gui instanceof SelectWorldScreen || gui instanceof MultiplayerScreen) { if (gui instanceof SelectWorldScreen || gui instanceof MultiplayerScreen) {
boolean sp = gui instanceof SelectWorldScreen; boolean sp = gui instanceof SelectWorldScreen;
SettingsRegistry settingsRegistry = mod.getSettingsRegistry(); SettingsRegistry settingsRegistry = mod.getSettingsRegistry();

View File

@@ -1,10 +1,13 @@
package com.replaymod.recording.handler; package com.replaymod.recording.handler;
import com.replaymod.core.events.PreRenderCallback;
import com.replaymod.recording.mixin.IntegratedServerAccessor; import com.replaymod.recording.mixin.IntegratedServerAccessor;
import com.replaymod.recording.packet.PacketListener; import com.replaymod.recording.packet.PacketListener;
import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.utils.EventRegistrations;
import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.entity.Entity;
import net.minecraft.network.packet.s2c.play.BlockBreakingProgressS2CPacket; import net.minecraft.network.packet.s2c.play.BlockBreakingProgressS2CPacket;
import net.minecraft.network.packet.s2c.play.EntityAnimationS2CPacket; import net.minecraft.network.packet.s2c.play.EntityAnimationS2CPacket;
import net.minecraft.network.packet.s2c.play.EntityAttachS2CPacket; import net.minecraft.network.packet.s2c.play.EntityAttachS2CPacket;
@@ -20,15 +23,11 @@ import net.minecraft.network.Packet;
import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.server.integrated.IntegratedServer;
// FIXME not (yet?) 1.13 import net.minecraftforge.event.entity.minecart.MinecartInteractEvent; // FIXME not (yet?) 1.13 import net.minecraftforge.event.entity.minecart.MinecartInteractEvent;
//#if FABRIC>=1 //#if FABRIC<1
import com.replaymod.core.events.PreRenderCallback;
import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback;
//#else
//$$ import net.minecraft.network.play.server.SCollectItemPacket; //$$ import net.minecraft.network.play.server.SCollectItemPacket;
//$$ import net.minecraftforge.event.entity.player.PlayerSleepInBedEvent; //$$ import net.minecraftforge.event.entity.player.PlayerSleepInBedEvent;
//$$ import net.minecraftforge.eventbus.api.SubscribeEvent; //$$ import net.minecraftforge.eventbus.api.SubscribeEvent;
//$$ import net.minecraftforge.event.entity.player.PlayerEvent.ItemPickupEvent; //$$ import net.minecraftforge.event.entity.player.PlayerEvent.ItemPickupEvent;
//$$ import net.minecraftforge.event.TickEvent;
//#endif //#endif
//#if MC>=11600 //#if MC>=11600
@@ -139,24 +138,18 @@ public class RecordingEventHandler extends EventRegistrations {
} }
//#endif //#endif
//#if FABRIC>=1
{ on(PreTickCallback.EVENT, this::onPlayerTick); } { on(PreTickCallback.EVENT, this::onPlayerTick); }
private void onPlayerTick() { private void onPlayerTick() {
if (mc.player == null) return; if (mc.player == null) return;
//#else
//$$ @SubscribeEvent
//$$ public void onPlayerTick(TickEvent.ClientTickEvent e) {
//$$ if(e.phase != TickEvent.Phase.START || mc.player == null) return;
//#endif
ClientPlayerEntity player = mc.player; ClientPlayerEntity player = mc.player;
try { try {
boolean force = false; boolean force = false;
if(lastX == null || lastY == null || lastZ == null) { if(lastX == null || lastY == null || lastZ == null) {
force = true; force = true;
lastX = Entity_getX(player); lastX = player.getX();
lastY = Entity_getY(player); lastY = player.getY();
lastZ = Entity_getZ(player); lastZ = player.getZ();
} }
ticksSinceLastCorrection++; ticksSinceLastCorrection++;
@@ -165,13 +158,13 @@ public class RecordingEventHandler extends EventRegistrations {
force = true; force = true;
} }
double dx = Entity_getX(player) - lastX; double dx = player.getX() - lastX;
double dy = Entity_getY(player) - lastY; double dy = player.getY() - lastY;
double dz = Entity_getZ(player) - lastZ; double dz = player.getZ() - lastZ;
lastX = Entity_getX(player); lastX = player.getX();
lastY = Entity_getY(player); lastY = player.getY();
lastZ = Entity_getZ(player); lastZ = player.getZ();
Packet packet; Packet packet;
if (force || Math.abs(dx) > 8.0 || Math.abs(dy) > 8.0 || Math.abs(dz) > 8.0) { if (force || Math.abs(dx) > 8.0 || Math.abs(dy) > 8.0 || Math.abs(dz) > 8.0) {
@@ -317,18 +310,16 @@ public class RecordingEventHandler extends EventRegistrations {
//Leaving Ride //Leaving Ride
if((!player.isRiding() && lastRiding != -1) || Entity vehicle = player.getVehicle();
(player.isRiding() && lastRiding != getRiddenEntity(player).getEntityId())) { int vehicleId = vehicle == null ? -1 : vehicle.getEntityId();
if(!player.isRiding()) { if (lastRiding != vehicleId) {
lastRiding = -1; lastRiding = vehicleId;
} else {
lastRiding = getRiddenEntity(player).getEntityId();
}
packetListener.save(new EntityAttachS2CPacket( packetListener.save(new EntityAttachS2CPacket(
//#if MC<10904 //#if MC<10904
//$$ 0, //$$ 0,
//#endif //#endif
player, getRiddenEntity(player) player,
vehicle
)); ));
} }
@@ -465,14 +456,8 @@ public class RecordingEventHandler extends EventRegistrations {
} }
} }
//#if FABRIC>=1
{ on(PreRenderCallback.EVENT, this::checkForGamePaused); } { on(PreRenderCallback.EVENT, this::checkForGamePaused); }
private void checkForGamePaused() { private void checkForGamePaused() {
//#else
//$$ @SubscribeEvent
//$$ public void checkForGamePaused(TickEvent.RenderTickEvent event) {
//$$ if (event.phase != TickEvent.Phase.START) return;
//#endif
if (mc.isIntegratedServerRunning()) { if (mc.isIntegratedServerRunning()) {
IntegratedServer server = mc.getServer(); IntegratedServer server = mc.getServer();
if (server != null && ((IntegratedServerAccessor) server).isGamePaused()) { if (server != null && ((IntegratedServerAccessor) server).isGamePaused()) {

View File

@@ -1,45 +1 @@
//#if MC<=10710 // 1.7.10 and below
//$$ package com.replaymod.recording.mixin;
//$$
//$$ import de.johni0702.minecraft.gui.container.VanillaGuiScreen;
//$$ import net.minecraft.client.gui.GuiScreen;
//$$ import org.lwjgl.input.Keyboard;
//$$ import org.lwjgl.input.Mouse;
//$$ import org.spongepowered.asm.mixin.Mixin;
//$$ import org.spongepowered.asm.mixin.Shadow;
//$$ import org.spongepowered.asm.mixin.injection.At;
//$$ import org.spongepowered.asm.mixin.injection.Inject;
//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//$$
//$$ import static com.replaymod.core.versions.MCVer.*;
//$$
//$$ @Mixin(GuiScreen.class)
//$$ public abstract class MixinGuiScreen {
//$$
//$$ @Inject(method = "handleInput", at = @At("HEAD"), cancellable = true)
//$$ private void handleJGuiInput(CallbackInfo ci) {
//$$ ci.cancel();
//$$ if (Mouse.isCreated()) {
//$$ while (Mouse.next()) {
//$$ if (FORGE_BUS.post(new VanillaGuiScreen.MouseInputEvent())) {
//$$ continue;
//$$ }
//$$ handleMouseInput();
//$$ }
//$$ }
//$$
//$$ if (Keyboard.isCreated()) {
//$$ while (Keyboard.next()) {
//$$ if (FORGE_BUS.post(new VanillaGuiScreen.KeyboardInputEvent())) {
//$$ continue;
//$$ }
//$$ handleKeyboardInput();
//$$ }
//$$ }
//$$ }
//$$
//$$ @Shadow public abstract void handleMouseInput();
//$$
//$$ @Shadow public abstract void handleKeyboardInput();
//$$ }
//#endif

View File

@@ -1,35 +1,26 @@
package com.replaymod.recording.mixin; package com.replaymod.recording.mixin;
import com.replaymod.core.versions.MCVer;
import com.replaymod.recording.ReplayModRecording; import com.replaymod.recording.ReplayModRecording;
import com.replaymod.recording.handler.RecordingEventHandler.RecordingEventSender;
import net.minecraft.client.network.ClientLoginNetworkHandler; import net.minecraft.client.network.ClientLoginNetworkHandler;
import net.minecraft.network.ClientConnection; import net.minecraft.network.ClientConnection;
import net.minecraft.network.Packet;
import net.minecraft.network.packet.s2c.login.LoginQueryRequestS2CPacket;
import net.minecraft.network.packet.s2c.login.LoginSuccessS2CPacket;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//#if MC>=11400
import com.replaymod.core.versions.MCVer;
import com.replaymod.recording.handler.RecordingEventHandler.RecordingEventSender;
import net.minecraft.network.Packet;
import net.minecraft.network.packet.s2c.login.LoginQueryRequestS2CPacket;
import net.minecraft.network.packet.s2c.login.LoginSuccessS2CPacket;
//#else
//$$ import net.minecraftforge.fml.common.network.FMLNetworkEvent;
//#endif
@Mixin(ClientLoginNetworkHandler.class) @Mixin(ClientLoginNetworkHandler.class)
public abstract class MixinNetHandlerLoginClient { public abstract class MixinNetHandlerLoginClient {
@Shadow @Final @Shadow
//#if MC>=10800
private ClientConnection connection; private ClientConnection connection;
//#else
//$$ private NetworkManager field_147393_d;
//#endif
//#if MC>=11400
@Inject(method = "onQueryRequest", at=@At("HEAD")) @Inject(method = "onQueryRequest", at=@At("HEAD"))
private void earlyInitiateRecording(LoginQueryRequestS2CPacket packet, CallbackInfo ci) { private void earlyInitiateRecording(LoginQueryRequestS2CPacket packet, CallbackInfo ci) {
initiateRecording(packet); initiateRecording(packet);
@@ -50,27 +41,4 @@ public abstract class MixinNetHandlerLoginClient {
eventSender.getRecordingEventHandler().onPacket(packet); eventSender.getRecordingEventHandler().onPacket(packet);
} }
} }
//#else
//$$ /**
//$$ * Starts the recording right before switching into PLAY state.
//$$ * We cannot use the {@link FMLNetworkEvent.ClientConnectedToServerEvent}
//$$ * as it only fires after the forge handshake.
//$$ */
//$$ @Inject(method = "handleLoginSuccess", at=@At("HEAD"))
//$$ public void replayModRecording_initiateRecording(CallbackInfo cb) {
//#if MC>=10800
//$$ ReplayModRecording.instance.initiateRecording(this.networkManager);
//#else
//$$ ReplayModRecording.instance.initiateRecording(this.field_147393_d);
//#endif
//$$ }
//#endif
// Race condition in Forge's networking (not sure if still present in 1.13)
//#if MC>=11200 && MC<11400
//$$ @Inject(method = "handleLoginSuccess", at=@At("RETURN"))
//$$ public void replayModRecording_raceConditionWorkAround(CallbackInfo cb) {
//$$ ((NetworkManagerAccessor) this.networkManager).getChannel().config().setAutoRead(true);
//$$ }
//#endif
} }

View File

@@ -57,7 +57,7 @@ public abstract class MixinNetHandlerPlayClient {
//$$ @Inject(method = "handlePlayerListItem", at=@At("HEAD")) //$$ @Inject(method = "handlePlayerListItem", at=@At("HEAD"))
//#endif //#endif
public void recordOwnJoin(PlayerListS2CPacket packet, CallbackInfo ci) { public void recordOwnJoin(PlayerListS2CPacket packet, CallbackInfo ci) {
if (!MCVer.isOnMainThread()) return; if (!mcStatic.isOnThread()) return;
if (mcStatic.player == null) return; if (mcStatic.player == null) return;
RecordingEventHandler handler = getRecordingEventHandler(); RecordingEventHandler handler = getRecordingEventHandler();

View File

@@ -1,70 +1 @@
//#if MC<11400 // 1.12.2 and below
//$$ package com.replaymod.recording.mixin;
//$$
//$$ import com.replaymod.recording.handler.FMLHandshakeFilter;
//$$ import io.netty.channel.ChannelPipeline;
//$$ import io.netty.channel.embedded.EmbeddedChannel;
//$$ import net.minecraftforge.fml.common.network.handshake.FMLHandshakeCodec;
//$$ import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher;
//$$ import net.minecraftforge.fml.relauncher.Side;
//$$ import org.spongepowered.asm.mixin.Mixin;
//$$ import org.spongepowered.asm.mixin.Shadow;
//$$ import org.spongepowered.asm.mixin.injection.At;
//$$ import org.spongepowered.asm.mixin.injection.Inject;
//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//$$
//#if MC>=11200
//$$ import io.netty.channel.ChannelConfig;
//$$ import net.minecraft.network.EnumConnectionState;
//$$ import net.minecraft.network.NetworkManager;
//$$ import org.spongepowered.asm.mixin.injection.Redirect;
//#endif
//$$
//$$ @Mixin(value = NetworkDispatcher.class, remap = false)
//$$ public abstract class MixinNetworkDispatcher {
//$$
//$$ @Shadow
//$$ private Side side;
//$$
//$$ @Shadow
//$$ private EmbeddedChannel handshakeChannel;
//$$
//$$ /**
//$$ * Always sets fml:isLocal to false on the server side.
//$$ * This effectively removes the difference in the FML handshake between SP and MP
//$$ * and forces the block/item ids, etc. to always be send.
//$$ * Injects a {@link FMLHandshakeFilter} on the client side to filter out
//$$ * those extra, unexpected packets.
//$$ */
//$$ @Inject(method = "insertIntoChannel", at=@At("HEAD"))
//$$ public void replayModRecording_setupForLocalRecording(CallbackInfo cb) {
//$$ // If we're in multiplayer, everything is fine as is
//$$ if (!handshakeChannel.attr(NetworkDispatcher.IS_LOCAL).get()) return;
//$$
//$$ if (side == Side.SERVER) {
//$$ // On the server side, force all packets to be sent
//$$ handshakeChannel.attr(NetworkDispatcher.IS_LOCAL).set(false);
//$$ } else {
//$$ // On the client side, discard additional packets
//$$ ChannelPipeline pipeline = handshakeChannel.pipeline();
//$$ pipeline.addAfter(pipeline.context(FMLHandshakeCodec.class).name(),
//$$ "replaymod_filter", new FMLHandshakeFilter());
//$$ }
//$$ }
//$$
//#if MC>=11200
//$$ @Redirect(method = "clientListenForServerHandshake", at = @At(value = "INVOKE", remap = true, target =
//$$ "Lnet/minecraft/network/NetworkManager;setConnectionState(Lnet/minecraft/network/EnumConnectionState;)V"))
//$$ public void replayModRecording_raceConditionWorkAround1(NetworkManager self, EnumConnectionState ignored) { }
//$$
//$$ @Redirect(method = "insertIntoChannel", at = @At(value = "INVOKE", target =
//$$ "Lio/netty/channel/ChannelConfig;setAutoRead(Z)Lio/netty/channel/ChannelConfig;"))
//$$ public ChannelConfig replayModRecording_raceConditionWorkAround2(ChannelConfig self, boolean autoRead) {
//$$ if (side == Side.CLIENT) {
//$$ autoRead = false;
//$$ }
//$$ return self.setAutoRead(autoRead);
//$$ }
//#endif
//$$ }
//#endif

View File

@@ -1,32 +1 @@
package com.replaymod.recording.mixin; // 1.9.4 - 1.12.2
//#if MC>=10904 && MC<11400
//$$ import com.replaymod.recording.handler.RecordingEventHandler;
//$$ import net.minecraft.client.Minecraft;
//$$ import net.minecraft.client.multiplayer.PlayerControllerMP;
//$$ import net.minecraft.util.math.BlockPos;
//$$ import net.minecraft.world.World;
//$$ import org.spongepowered.asm.mixin.Mixin;
//$$ import org.spongepowered.asm.mixin.Shadow;
//$$ import org.spongepowered.asm.mixin.injection.At;
//$$ import org.spongepowered.asm.mixin.injection.Redirect;
//$$
//$$ import static com.replaymod.core.versions.MCVer.*;
//$$
//$$ @Mixin(PlayerControllerMP.class)
//$$ public abstract class MixinPlayerControllerMP implements RecordingEventHandler.RecordingEventSender {
//$$
//$$ @Shadow
//$$ private Minecraft mc;
//$$
//$$ // Redirects the call to playEvent without the initial player argument to the method with that argument
//$$ // The new method will then play it and (if applicable) record it. (See MixinWorldClient)
//$$ // This is necessary for the block break event (particles and sound) to be recorded. Otherwise it looks like the
//$$ // event was emitted because of a packet (player will be null) and not as it actually was (by the player).
//$$ @Redirect(method = "onPlayerDestroyBlock", at = @At(value = "INVOKE",
//$$ target = "Lnet/minecraft/world/World;playEvent(ILnet/minecraft/util/math/BlockPos;I)V"))
//$$ public void replayModRecording_playEvent_fixed(World world, int type, BlockPos pos, int data) {
//$$ world.playEvent(mc.player, type, pos, data);
//$$ }
//$$ }
//#endif

View File

@@ -1,38 +1 @@
//#if MC<=10710 // 1.7.10 and below
//$$ package com.replaymod.recording.mixin;
//$$
//$$ import net.minecraft.network.PacketBuffer;
//$$ import net.minecraft.network.play.server.S21PacketChunkData;
//$$ import net.minecraft.network.play.server.S26PacketMapChunkBulk;
//$$ import org.spongepowered.asm.mixin.Mixin;
//$$ import org.spongepowered.asm.mixin.Shadow;
//$$ import org.spongepowered.asm.mixin.injection.At;
//$$ import org.spongepowered.asm.mixin.injection.Inject;
//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//$$
//$$ import java.util.concurrent.Semaphore;
//$$
//$$ @Mixin({ S21PacketChunkData.class, S26PacketMapChunkBulk.class })
//$$ public abstract class MixinS26PacketMapChunkBulk {
//$$
//$$ private byte[] rawData;
//$$
//$$ @Shadow(remap = false)
//$$ private Semaphore deflateGate;
//$$
//$$ @Inject(method = "readPacketData", at = @At("HEAD"))
//$$ private void replayModRecording_readRawPacketData(PacketBuffer data, CallbackInfo ci) {
//$$ int readerIndex = data.readerIndex();
//$$ data.readBytes(rawData = new byte[data.readableBytes()]);
//$$ data.readerIndex(readerIndex);
//$$ }
//$$
//$$ @Inject(method = "writePacketData", at = @At("HEAD"), cancellable = true)
//$$ private void replayModRecording_writePacketData(PacketBuffer data, CallbackInfo ci) {
//$$ if (rawData != null && deflateGate == null) {
//$$ data.writeBytes(rawData);
//$$ ci.cancel();
//$$ }
//$$ }
//$$ }
//#endif

View File

@@ -20,13 +20,13 @@ import com.replaymod.replaystudio.data.Marker;
import com.replaymod.replaystudio.io.ReplayOutputStream; import com.replaymod.replaystudio.io.ReplayOutputStream;
import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ReplayMetaData; import com.replaymod.replaystudio.replay.ReplayMetaData;
import com.replaymod.replaystudio.us.myles.ViaVersion.api.Pair;
import de.johni0702.minecraft.gui.container.VanillaGuiScreen; import de.johni0702.minecraft.gui.container.VanillaGuiScreen;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket;
import net.minecraft.network.packet.s2c.play.DisconnectS2CPacket; import net.minecraft.network.packet.s2c.play.DisconnectS2CPacket;
import net.minecraft.network.packet.s2c.play.ItemPickupAnimationS2CPacket; import net.minecraft.network.packet.s2c.play.ItemPickupAnimationS2CPacket;
@@ -40,6 +40,7 @@ import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import net.minecraft.util.crash.CrashReport; import net.minecraft.util.crash.CrashReport;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@@ -163,8 +164,8 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
// to happen on the main thread so we can guarantee correct ordering of inbound and inject packets. // to happen on the main thread so we can guarantee correct ordering of inbound and inject packets.
// Otherwise, injected packets may end up further down the packet stream than they were supposed to and other // Otherwise, injected packets may end up further down the packet stream than they were supposed to and other
// inbound packets which may rely on the injected packet would behave incorrectly when played back. // inbound packets which may rely on the injected packet would behave incorrectly when played back.
if (!MCVer.isOnMainThread()) { if (!mc.isOnThread()) {
MCVer.scheduleOnMainThread(() -> save(packet)); mc.send(() -> save(packet));
return; return;
} }
try { try {
@@ -295,7 +296,7 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
if (core.getSettingsRegistry().get(Setting.AUTO_POST_PROCESS) && !ReplayMod.isMinimalMode()) { if (core.getSettingsRegistry().get(Setting.AUTO_POST_PROCESS) && !ReplayMod.isMinimalMode()) {
outputPaths = MarkerProcessor.apply(outputPath, guiSavingReplay.getProgressBar()::setProgress); outputPaths = MarkerProcessor.apply(outputPath, guiSavingReplay.getProgressBar()::setProgress);
} else { } else {
outputPaths = Collections.singletonList(new Pair<>(outputPath, metaData)); outputPaths = Collections.singletonList(Pair.of(outputPath, metaData));
} }
} catch (Exception e) { } catch (Exception e) {
logger.error("Saving replay file:", e); logger.error("Saving replay file:", e);
@@ -339,7 +340,8 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
//#if MC>=10800 //#if MC>=10800
if (packet instanceof ResourcePackSendS2CPacket) { if (packet instanceof ResourcePackSendS2CPacket) {
save(resourcePackRecorder.handleResourcePack((ResourcePackSendS2CPacket) packet)); ClientConnection connection = ctx.pipeline().get(ClientConnection.class);
save(resourcePackRecorder.handleResourcePack(connection, (ResourcePackSendS2CPacket) packet));
return; return;
} }
//#else //#else
@@ -488,15 +490,15 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
} }
public void addMarker(String name, int timestamp) { public void addMarker(String name, int timestamp) {
Entity view = getRenderViewEntity(mc); Entity view = mc.getCameraEntity();
Marker marker = new Marker(); Marker marker = new Marker();
marker.setName(name); marker.setName(name);
marker.setTime(timestamp); marker.setTime(timestamp);
if (view != null) { if (view != null) {
marker.setX(Entity_getX(view)); marker.setX(view.getX());
marker.setY(Entity_getY(view)); marker.setY(view.getY());
marker.setZ(Entity_getZ(view)); marker.setZ(view.getZ());
marker.setYaw(view.yaw); marker.setYaw(view.yaw);
marker.setPitch(view.pitch); marker.setPitch(view.pitch);
} }

View File

@@ -37,7 +37,6 @@ import java.util.concurrent.CompletableFuture;
//#else //#else
//$$ import com.google.common.util.concurrent.ListenableFuture; //$$ import com.google.common.util.concurrent.ListenableFuture;
//#endif //#endif
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.network.ClientConnection; import net.minecraft.network.ClientConnection;
//#else //#else
//$$ import com.replaymod.core.mixin.ResourcePackRepositoryAccessor; //$$ import com.replaymod.core.mixin.ResourcePackRepositoryAccessor;
@@ -111,10 +110,8 @@ public class ResourcePackRecorder {
} }
public synchronized ResourcePackSendS2CPacket handleResourcePack(ResourcePackSendS2CPacket packet) { public synchronized ResourcePackSendS2CPacket handleResourcePack(ClientConnection netManager, ResourcePackSendS2CPacket packet) {
final int requestId = nextRequestId++; final int requestId = nextRequestId++;
final ClientPlayNetworkHandler netHandler = mc.getNetworkHandler();
final ClientConnection netManager = netHandler.getConnection();
final String url = packet.getURL(); final String url = packet.getURL();
final String hash = packet.getSHA1(); final String hash = packet.getSHA1();
@@ -138,7 +135,7 @@ public class ResourcePackRecorder {
final ServerInfo serverData = mc.getCurrentServerEntry(); final ServerInfo serverData = mc.getCurrentServerEntry();
if (serverData != null && serverData.getResourcePack() == ServerInfo.ResourcePackState.ENABLED) { if (serverData != null && serverData.getResourcePack() == ServerInfo.ResourcePackState.ENABLED) {
netManager.send(makeStatusPacket(hash, Status.ACCEPTED)); netManager.send(makeStatusPacket(hash, Status.ACCEPTED));
downloadResourcePackFuture(requestId, url, hash); downloadResourcePackFuture(netManager, requestId, url, hash);
} else if (serverData != null && serverData.getResourcePack() != ServerInfo.ResourcePackState.PROMPT) { } else if (serverData != null && serverData.getResourcePack() != ServerInfo.ResourcePackState.PROMPT) {
netManager.send(makeStatusPacket(hash, Status.DECLINED)); netManager.send(makeStatusPacket(hash, Status.DECLINED));
} else { } else {
@@ -156,7 +153,7 @@ public class ResourcePackRecorder {
} }
if (result) { if (result) {
netManager.send(makeStatusPacket(hash, Status.ACCEPTED)); netManager.send(makeStatusPacket(hash, Status.ACCEPTED));
downloadResourcePackFuture(requestId, url, hash); downloadResourcePackFuture(netManager, requestId, url, hash);
} else { } else {
netManager.send(makeStatusPacket(hash, Status.DECLINED)); netManager.send(makeStatusPacket(hash, Status.DECLINED));
} }
@@ -172,13 +169,18 @@ public class ResourcePackRecorder {
} }
} }
return new ResourcePackSendS2CPacket("replay://" + requestId, ""); return new ResourcePackSendS2CPacket(
"replay://" + requestId, ""
//#if MC>=11700
//$$ , packet.isRequired(), packet.getPrompt()
//#endif
);
} }
private void downloadResourcePackFuture(int requestId, String url, final String hash) { private void downloadResourcePackFuture(ClientConnection connection, int requestId, String url, final String hash) {
addCallback(downloadResourcePack(requestId, url, hash), addCallback(downloadResourcePack(requestId, url, hash),
result -> mc.getNetworkHandler().sendPacket(makeStatusPacket(hash, Status.SUCCESSFULLY_LOADED)), result -> connection.send(makeStatusPacket(hash, Status.SUCCESSFULLY_LOADED)),
throwable -> mc.getNetworkHandler().sendPacket(makeStatusPacket(hash, Status.FAILED_DOWNLOAD))); throwable -> connection.send(makeStatusPacket(hash, Status.FAILED_DOWNLOAD)));
} }
private private
@@ -190,7 +192,11 @@ public class ResourcePackRecorder {
downloadResourcePack(final int requestId, String url, String hash) { downloadResourcePack(final int requestId, String url, String hash) {
ClientBuiltinResourcePackProvider packFinder = mc.getResourcePackDownloader(); ClientBuiltinResourcePackProvider packFinder = mc.getResourcePackDownloader();
((IDownloadingPackFinder) packFinder).setRequestCallback(file -> recordResourcePack(file, requestId)); ((IDownloadingPackFinder) packFinder).setRequestCallback(file -> recordResourcePack(file, requestId));
//#if MC>=11700
//$$ return packFinder.download(url, hash, true);
//#else
return packFinder.download(url, hash); return packFinder.download(url, hash);
//#endif
} }
public interface IDownloadingPackFinder { public interface IDownloadingPackFinder {

View File

@@ -126,8 +126,8 @@ public class FFmpegWriter implements FrameConsumer<BitmapFrame> {
} }
CrashReport report = CrashReport.create(t, "Exporting frame"); CrashReport report = CrashReport.create(t, "Exporting frame");
CrashReportSection exportDetails = report.addElement("Export details"); CrashReportSection exportDetails = report.addElement("Export details");
MCVer.addDetail(exportDetails, "Export command", settings::getExportCommand); exportDetails.add("Export command", settings::getExportCommand);
MCVer.addDetail(exportDetails, "Export args", commandArgs::toString); exportDetails.add("Export args", commandArgs::toString);
MCVer.getMinecraft().setCrashReport(report); MCVer.getMinecraft().setCrashReport(report);
} finally { } finally {
channels.values().forEach(it -> ByteBufferPool.release(it.getByteBuffer())); channels.values().forEach(it -> ByteBufferPool.release(it.getByteBuffer()));

View File

@@ -0,0 +1,71 @@
package com.replaymod.render;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.blend.Util.IOConsumer;
import com.replaymod.render.frame.BitmapFrame;
import com.replaymod.render.rendering.Channel;
import com.replaymod.render.rendering.FrameConsumer;
import com.replaymod.render.utils.ByteBufferPool;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import de.johni0702.minecraft.gui.versions.Image;
import net.minecraft.util.crash.CrashReport;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
public class PNGWriter implements FrameConsumer<BitmapFrame> {
private final Path outputFolder;
public PNGWriter(Path outputFolder) throws IOException {
this.outputFolder = outputFolder;
Files.createDirectories(outputFolder);
}
@Override
public void consume(Map<Channel, BitmapFrame> channels) {
BitmapFrame bgraFrame = channels.get(Channel.BRGA);
BitmapFrame depthFrame = channels.get(Channel.DEPTH);
try {
if (bgraFrame != null) {
withImage(bgraFrame, image ->
image.writePNG(outputFolder.resolve(bgraFrame.getFrameId() + ".png").toFile()));
}
if (depthFrame != null) {
withImage(depthFrame, image ->
image.writePNG(outputFolder.resolve(depthFrame.getFrameId() + ".depth.png").toFile()));
}
} catch (Throwable t) {
MCVer.getMinecraft().setCrashReport(CrashReport.create(t, "Exporting EXR frame"));
} finally {
channels.values().forEach(it -> ByteBufferPool.release(it.getByteBuffer()));
}
}
private void withImage(BitmapFrame frame, IOConsumer<Image> consumer) throws IOException {
ByteBuffer buffer = frame.getByteBuffer();
ReadableDimension size = frame.getSize();
int width = size.getWidth();
int height = size.getHeight();
try (Image image = new Image(width, height)) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
byte b = buffer.get();
byte g = buffer.get();
byte r = buffer.get();
byte a = buffer.get();
image.setRGBA(x, y, r, g, b, a);
}
}
consumer.accept(image);
}
}
@Override
public void close() {
}
}

View File

@@ -1,10 +1,13 @@
package com.replaymod.render; package com.replaymod.render;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import com.replaymod.core.utils.FileTypeAdapter;
import com.replaymod.core.versions.MCVer; import com.replaymod.core.versions.MCVer;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableColor; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableColor;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
import net.minecraft.util.Util; import net.minecraft.util.Util;
import org.apache.maven.artifact.versioning.ComparableVersion;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -19,16 +22,6 @@ import java.util.Optional;
import static com.replaymod.render.ReplayModRender.LOGGER; import static com.replaymod.render.ReplayModRender.LOGGER;
//#if MC>=11400
import org.apache.maven.artifact.versioning.ComparableVersion;
//#else
//#if MC>=10800
//$$ import net.minecraftforge.fml.common.versioning.ComparableVersion;
//#else
//$$ import cpw.mods.fml.common.versioning.ComparableVersion;
//#endif
//#endif
public class RenderSettings { public class RenderSettings {
public enum RenderMethod { public enum RenderMethod {
DEFAULT, STEREOSCOPIC, CUBIC, EQUIRECTANGULAR, ODS, BLEND; DEFAULT, STEREOSCOPIC, CUBIC, EQUIRECTANGULAR, ODS, BLEND;
@@ -69,8 +62,6 @@ public class RenderSettings {
public enum EncodingPreset { public enum EncodingPreset {
MP4_CUSTOM("-an -c:v libx264 -b:v %BITRATE% -pix_fmt yuv420p \"%FILENAME%\"", "mp4"), MP4_CUSTOM("-an -c:v libx264 -b:v %BITRATE% -pix_fmt yuv420p \"%FILENAME%\"", "mp4"),
MP4_DEFAULT("-an -c:v libx264 -preset ultrafast -pix_fmt yuv420p \"%FILENAME%\"", "mp4"),
MP4_POTATO("-an -c:v libx264 -preset ultrafast -crf 51 -pix_fmt yuv420p \"%FILENAME%\"", "mp4"), MP4_POTATO("-an -c:v libx264 -preset ultrafast -crf 51 -pix_fmt yuv420p \"%FILENAME%\"", "mp4"),
WEBM_CUSTOM("-an -c:v libvpx -b:v %BITRATE% -pix_fmt yuv420p \"%FILENAME%\"", "webm"), WEBM_CUSTOM("-an -c:v libvpx -b:v %BITRATE% -pix_fmt yuv420p \"%FILENAME%\"", "webm"),
@@ -81,7 +72,7 @@ public class RenderSettings {
EXR(null, "exr"), EXR(null, "exr"),
PNG("\"%FILENAME%-%06d.png\"", "png"); PNG(null, "png");
private final String preset; private final String preset;
private final String fileExtension; private final String fileExtension;
@@ -155,6 +146,7 @@ public class RenderSettings {
private final int videoHeight; private final int videoHeight;
private final int framesPerSecond; private final int framesPerSecond;
private final int bitRate; private final int bitRate;
@JsonAdapter(FileTypeAdapter.class)
private final File outputFile; private final File outputFile;
private final boolean renderNameTags; private final boolean renderNameTags;
@@ -342,9 +334,13 @@ public class RenderSettings {
} }
} }
// Homebrew doesn't seem to reliably symlink its installed binaries either // Homebrew doesn't seem to reliably symlink its installed binaries either
File homebrewFolder = new File("/usr/local/Cellar/ffmpeg"); // and there's multiple locations for where Homebrew is.
String[] homebrewVersions = homebrewFolder.list(); for (String path : new String[]{"/usr/local", "/opt/homebrew"}) {
if (homebrewVersions != null) { File homebrewFolder = new File(path + "/Cellar/ffmpeg");
String[] homebrewVersions = homebrewFolder.list();
if (homebrewVersions == null) {
continue;
}
Optional<File> latestOpt = Arrays.stream(homebrewVersions) Optional<File> latestOpt = Arrays.stream(homebrewVersions)
.map(ComparableVersion::new) // Convert file name to comparable version .map(ComparableVersion::new) // Convert file name to comparable version
.sorted(Comparator.reverseOrder()) // Sort for latest version .sorted(Comparator.reverseOrder()) // Sort for latest version

View File

@@ -7,4 +7,6 @@ public final class Setting<T> {
new SettingsRegistry.SettingKeys<>("advanced", "renderPath", null, "./replay_videos/"); new SettingsRegistry.SettingKeys<>("advanced", "renderPath", null, "./replay_videos/");
public static final SettingsRegistry.SettingKey<Boolean> SKIP_POST_RENDER_GUI = public static final SettingsRegistry.SettingKey<Boolean> SKIP_POST_RENDER_GUI =
new SettingsRegistry.SettingKeys<>("advanced", "skipPostRenderGui", null, false); new SettingsRegistry.SettingKeys<>("advanced", "skipPostRenderGui", null, false);
public static final SettingsRegistry.SettingKey<Boolean> FRAME_TIME_FROM_WORLD_TIME =
new SettingsRegistry.SettingKeys<>("render", "frameTimeFromWorldTime", null, false);
} }

View File

@@ -1,6 +1,5 @@
package com.replaymod.render.blend; package com.replaymod.render.blend;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.capturer.RenderInfo; import com.replaymod.render.capturer.RenderInfo;
import com.replaymod.render.capturer.WorldRenderer; import com.replaymod.render.capturer.WorldRenderer;
import com.replaymod.render.frame.BitmapFrame; import com.replaymod.render.frame.BitmapFrame;
@@ -8,6 +7,7 @@ import com.replaymod.render.rendering.Channel;
import com.replaymod.render.rendering.FrameCapturer; import com.replaymod.render.rendering.FrameCapturer;
import com.replaymod.render.utils.ByteBufferPool; import com.replaymod.render.utils.ByteBufferPool;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import net.minecraft.client.MinecraftClient;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
@@ -37,7 +37,7 @@ public class BlendFrameCapturer implements FrameCapturer<BitmapFrame> {
renderInfo.updateForNextFrame(); renderInfo.updateForNextFrame();
BlendState.getState().preFrame(framesDone); BlendState.getState().preFrame(framesDone);
worldRenderer.renderWorld(MCVer.getRenderPartialTicks(), null); worldRenderer.renderWorld(MinecraftClient.getInstance().getTickDelta(), null);
BlendState.getState().postFrame(framesDone); BlendState.getState().postFrame(framesDone);
BitmapFrame frame = new BitmapFrame(framesDone++, new Dimension(0, 0), 0, ByteBufferPool.allocate(0)); BitmapFrame frame = new BitmapFrame(framesDone++, new Dimension(0, 0), 0, ByteBufferPool.allocate(0));

View File

@@ -9,6 +9,7 @@ import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f;
import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexFormat; import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.render.VertexFormatElement; import net.minecraft.client.render.VertexFormatElement;
import net.minecraft.client.render.VertexFormats;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
//#if MC>=11500 //#if MC>=11500
@@ -62,7 +63,9 @@ public class BlendMeshBuilder
} }
@Override @Override
//#if MC>=10809 //#if MC>=11700
//$$ public void begin(VertexFormat.DrawMode mode, VertexFormat vertexFormat) {
//#elseif MC>=10809
public void begin(int mode, VertexFormat vertexFormat) { public void begin(int mode, VertexFormat vertexFormat) {
//#else //#else
//$$ public void startDrawing(int mode) { //$$ public void startDrawing(int mode) {
@@ -82,7 +85,7 @@ public class BlendMeshBuilder
if (!wellBehaved) { if (!wellBehaved) {
// In case the calling code finishes with Tessellator.getInstance().draw() // In case the calling code finishes with Tessellator.getInstance().draw()
BufferBuilder_beginPosTexCol(mode); Tessellator.getInstance().getBuffer().begin(mode, VertexFormats.POSITION_TEXTURE_COLOR);
} }
//#if MC>=10809 //#if MC>=10809
@@ -147,7 +150,17 @@ public class BlendMeshBuilder
//#endif //#endif
} }
public static DMesh addBufferToMesh(ByteBuffer buffer, int mode, VertexFormat vertexFormat, DMesh mesh, ReadableVector3f vertOffset) { public static DMesh addBufferToMesh(
ByteBuffer buffer,
//#if MC>=11700
//$$ VertexFormat.DrawMode mode,
//#else
int mode,
//#endif
VertexFormat vertexFormat,
DMesh mesh,
ReadableVector3f vertOffset
) {
//#if MC>=11400 //#if MC>=11400
int vertexCount = buffer.remaining() / vertexFormat.getVertexSize(); int vertexCount = buffer.remaining() / vertexFormat.getVertexSize();
//#else //#else
@@ -156,7 +169,18 @@ public class BlendMeshBuilder
return addBufferToMesh(buffer, vertexCount, mode, vertexFormat, mesh, vertOffset); return addBufferToMesh(buffer, vertexCount, mode, vertexFormat, mesh, vertOffset);
} }
public static DMesh addBufferToMesh(ByteBuffer buffer, int vertexCount, int mode, VertexFormat vertexFormat, DMesh mesh, ReadableVector3f vertOffset) { public static DMesh addBufferToMesh(
ByteBuffer buffer,
int vertexCount,
//#if MC>=11700
//$$ VertexFormat.DrawMode mode,
//#else
int mode,
//#endif
VertexFormat vertexFormat,
DMesh mesh,
ReadableVector3f vertOffset
) {
if (mesh == null) { if (mesh == null) {
mesh = new DMesh(); mesh = new DMesh();
} }
@@ -260,7 +284,11 @@ public class BlendMeshBuilder
// Bundle vertices into shapes and add them to the mesh // Bundle vertices into shapes and add them to the mesh
switch (mode) { switch (mode) {
//#if MC>=11700
//$$ case TRIANGLES:
//#else
case GL11.GL_TRIANGLES: case GL11.GL_TRIANGLES:
//#endif
for (int i = 0; i < vertices.size(); i+=3) { for (int i = 0; i < vertices.size(); i+=3) {
mesh.addTriangle( mesh.addTriangle(
vertices.get(i ), vertices.get(i ),
@@ -276,7 +304,11 @@ public class BlendMeshBuilder
); );
} }
break; break;
//#if MC>=11700
//$$ case QUADS:
//#else
case GL11.GL_QUADS: case GL11.GL_QUADS:
//#endif
for (int i = 0; i < vertices.size(); i+=4) { for (int i = 0; i < vertices.size(); i+=4) {
mesh.addQuad( mesh.addQuad(
vertices.get(i ), vertices.get(i ),

View File

@@ -88,7 +88,7 @@ public class BlendState implements Exporter {
} catch (IOException e) { } catch (IOException e) {
CrashReport report = CrashReport.create(e, "Setup of blend exporter"); CrashReport report = CrashReport.create(e, "Setup of blend exporter");
CrashReportSection category = report.addElement("Exporter"); CrashReportSection category = report.addElement("Exporter");
addDetail(category, "Exporter", exporter::toString); category.add("Exporter", exporter::toString);
throw new CrashException(report); throw new CrashException(report);
} }
} }
@@ -102,7 +102,7 @@ public class BlendState implements Exporter {
} catch (IOException e) { } catch (IOException e) {
CrashReport report = CrashReport.create(e, "Tear down of blend exporter"); CrashReport report = CrashReport.create(e, "Tear down of blend exporter");
CrashReportSection category = report.addElement("Exporter"); CrashReportSection category = report.addElement("Exporter");
addDetail(category, "Exporter", exporter::toString); category.add("Exporter", exporter::toString);
throw new CrashException(report); throw new CrashException(report);
} }
} }
@@ -139,8 +139,8 @@ public class BlendState implements Exporter {
} catch (IOException e) { } catch (IOException e) {
CrashReport report = CrashReport.create(e, "Pre frame of blend exporter"); CrashReport report = CrashReport.create(e, "Pre frame of blend exporter");
CrashReportSection category = report.addElement("Exporter"); CrashReportSection category = report.addElement("Exporter");
addDetail(category, "Exporter", exporter::toString); category.add("Exporter", exporter::toString);
addDetail(category, "Frame", () -> String.valueOf(frame)); category.add("Frame", () -> String.valueOf(frame));
throw new CrashException(report); throw new CrashException(report);
} }
} }
@@ -154,8 +154,8 @@ public class BlendState implements Exporter {
} catch (IOException e) { } catch (IOException e) {
CrashReport report = CrashReport.create(e, "Post frame of blend exporter"); CrashReport report = CrashReport.create(e, "Post frame of blend exporter");
CrashReportSection category = report.addElement("Exporter"); CrashReportSection category = report.addElement("Exporter");
addDetail(category, "Exporter", exporter::toString); category.add("Exporter", exporter::toString);
addDetail(category, "Frame", () -> String.valueOf(frame)); category.add("Frame", () -> String.valueOf(frame));
throw new CrashException(report); throw new CrashException(report);
} }
} }

View File

@@ -39,7 +39,7 @@ public class Util {
} }
} }
private static FloatBuffer floatBuffer = GlAllocationUtils.allocateFloatBuffer(16); private static FloatBuffer floatBuffer = GlAllocationUtils.allocateByteBuffer(16 * 4).asFloatBuffer();
public static Matrix4f getGlMatrix(int matrix) { public static Matrix4f getGlMatrix(int matrix) {
floatBuffer.clear(); floatBuffer.clear();
//#if MC>=11400 //#if MC>=11400

View File

@@ -21,7 +21,6 @@ import net.minecraft.client.model.ModelPart;
import java.io.IOException; import java.io.IOException;
import static com.replaymod.core.versions.MCVer.*;
import static com.replaymod.render.blend.Util.isGlTextureMatrixIdentity; import static com.replaymod.render.blend.Util.isGlTextureMatrixIdentity;
public class ModelRendererExporter implements Exporter { public class ModelRendererExporter implements Exporter {
@@ -86,11 +85,13 @@ public class ModelRendererExporter implements Exporter {
DMesh mesh = new DMesh(); DMesh mesh = new DMesh();
BlendMeshBuilder builder = new BlendMeshBuilder(mesh); BlendMeshBuilder builder = new BlendMeshBuilder(mesh);
//#if MC>=11500 //#if MC>=11500
for (Cuboid box : cubeList(model)) { // FIXME 1.15
// FIXME 1.15 //#elseif MC>=10809
} //$$ for (Box box : model.boxes) {
//$$ box.render(builder, scale);
//$$ }
//#else //#else
//$$ for (Box box : cubeList(model)) { //$$ for (ModelBox box : (java.util.List<ModelBox>) model.cubeList) {
//$$ box.render(builder, scale); //$$ box.render(builder, scale);
//$$ } //$$ }
//#endif //#endif

View File

@@ -11,6 +11,7 @@ import com.replaymod.render.blend.mixin.ParticleAccessor;
import de.johni0702.minecraft.gui.utils.lwjgl.vector.Matrix4f; import de.johni0702.minecraft.gui.utils.lwjgl.vector.Matrix4f;
import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import org.lwjgl.opengl.GL11;
//#if MC>=11400 //#if MC>=11400
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@@ -169,7 +170,7 @@ public class ParticlesExporter implements Exporter {
builder.setReverseOffset(offset); builder.setReverseOffset(offset);
builder.setWellBehaved(true); builder.setWellBehaved(true);
//#if MC>=10809 //#if MC>=10809
builder.begin(7, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT); builder.begin(GL11.GL_QUADS, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT);
//#else //#else
//$$ builder.startDrawingQuads(); //$$ builder.startDrawingQuads();
//#endif //#endif

View File

@@ -0,0 +1,156 @@
//#if MC>=11600
package com.replaymod.render.capturer;
import com.mojang.blaze3d.platform.GlStateManager;
import com.replaymod.render.RenderSettings;
import com.replaymod.render.frame.CubicOpenGlFrame;
import com.replaymod.render.frame.ODSOpenGlFrame;
import com.replaymod.render.frame.OpenGlFrame;
import com.replaymod.render.rendering.Channel;
import com.replaymod.render.rendering.FrameCapturer;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.coderbot.iris.Iris;
import net.coderbot.iris.config.IrisConfig;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static com.replaymod.core.versions.MCVer.popMatrix;
import static com.replaymod.core.versions.MCVer.pushMatrix;
import static com.replaymod.core.versions.MCVer.resizeMainWindow;
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
public class IrisODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
public static final String SHADER_PACK_NAME = "assets/replaymod/iris/ods";
public static IrisODSFrameCapturer INSTANCE;
private final CubicPboOpenGlFrameCapturer left, right;
private final String prevShaderPack;
private int direction;
private boolean isLeftEye;
public IrisODSFrameCapturer(WorldRenderer worldRenderer, final RenderInfo renderInfo, int frameSize) {
RenderInfo fakeInfo = new RenderInfo() {
private int call;
private float partialTicks;
@Override
public ReadableDimension getFrameSize() {
return renderInfo.getFrameSize();
}
@Override
public int getFramesDone() {
return renderInfo.getFramesDone();
}
@Override
public int getTotalFrames() {
return renderInfo.getTotalFrames();
}
@Override
public float updateForNextFrame() {
if (call++ % 2 == 0) {
partialTicks = renderInfo.updateForNextFrame();
}
return partialTicks;
}
@Override
public RenderSettings getRenderSettings() {
return renderInfo.getRenderSettings();
}
};
left = new CubicStereoFrameCapturer(worldRenderer, fakeInfo, frameSize);
right = new CubicStereoFrameCapturer(worldRenderer, fakeInfo, frameSize);
INSTANCE = this;
prevShaderPack = Iris.getIrisConfig().getShaderPackName().orElse(null);
setShaderPack(SHADER_PACK_NAME);
}
private static void setShaderPack(String name) {
IrisConfig irisConfig = Iris.getIrisConfig();
irisConfig.setShaderPackName(name);
try {
irisConfig.save();
Iris.reload();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public int getDirection() {
return direction;
}
public boolean isLeftEye() {
return isLeftEye;
}
@Override
public boolean isDone() {
return left.isDone() && right.isDone();
}
@Override
public Map<Channel, ODSOpenGlFrame> process() {
isLeftEye = true;
Map<Channel, CubicOpenGlFrame> leftChannels = left.process();
isLeftEye = false;
Map<Channel, CubicOpenGlFrame> rightChannels = right.process();
if (leftChannels != null && rightChannels != null) {
Map<Channel, ODSOpenGlFrame> result = new HashMap<>();
for (Channel channel : Channel.values()) {
CubicOpenGlFrame leftFrame = leftChannels.get(channel);
CubicOpenGlFrame rightFrame = rightChannels.get(channel);
if (leftFrame != null && rightFrame != null) {
result.put(channel, new ODSOpenGlFrame(leftFrame, rightFrame));
}
}
return result;
}
return null;
}
@Override
public void close() throws IOException {
left.close();
right.close();
INSTANCE = null;
setShaderPack(prevShaderPack);
}
private class CubicStereoFrameCapturer extends CubicPboOpenGlFrameCapturer {
public CubicStereoFrameCapturer(WorldRenderer worldRenderer, RenderInfo renderInfo, int frameSize) {
super(worldRenderer, renderInfo, frameSize);
}
@Override
protected OpenGlFrame renderFrame(int frameId, float partialTicks, CubicOpenGlFrameCapturer.Data captureData) {
resizeMainWindow(mc, getFrameWidth(), getFrameHeight());
pushMatrix();
frameBuffer().beginWrite(true);
GlStateManager.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
//#if MC>=11400
, false
//#endif
);
GlStateManager.enableTexture();
direction = captureData.ordinal();
worldRenderer.renderWorld(partialTicks, null);
frameBuffer().endWrite();
popMatrix();
return captureFrame(frameId, captureData);
}
}
}
//#endif

View File

@@ -1,5 +1,6 @@
package com.replaymod.render.capturer; package com.replaymod.render.capturer;
import com.mojang.blaze3d.platform.GlStateManager;
import com.replaymod.render.rendering.Channel; import com.replaymod.render.rendering.Channel;
import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.utils.EventRegistrations;
import com.replaymod.render.RenderSettings; import com.replaymod.render.RenderSettings;
@@ -15,12 +16,13 @@ import net.minecraft.util.crash.CrashReport;
import net.minecraft.util.crash.CrashException; import net.minecraft.util.crash.CrashException;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import static com.mojang.blaze3d.platform.GlStateManager.*;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static com.replaymod.core.versions.MCVer.popMatrix;
import static com.replaymod.core.versions.MCVer.pushMatrix;
import static com.replaymod.core.versions.MCVer.resizeMainWindow;
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
@@ -164,17 +166,17 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
@Override @Override
protected OpenGlFrame renderFrame(int frameId, float partialTicks, CubicOpenGlFrameCapturer.Data captureData) { protected OpenGlFrame renderFrame(int frameId, float partialTicks, CubicOpenGlFrameCapturer.Data captureData) {
resize(getFrameWidth(), getFrameHeight()); resizeMainWindow(mc, getFrameWidth(), getFrameHeight());
pushMatrix(); pushMatrix();
frameBuffer().beginWrite(true); frameBuffer().beginWrite(true);
clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT GlStateManager.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
//#if MC>=11400 //#if MC>=11400
, false , false
//#endif //#endif
); );
enableTexture(); GlStateManager.enableTexture();
directionVariable.set(captureData.ordinal()); directionVariable.set(captureData.ordinal());
worldRenderer.renderWorld(partialTicks, null); worldRenderer.renderWorld(partialTicks, null);

View File

@@ -1,5 +1,6 @@
package com.replaymod.render.capturer; package com.replaymod.render.capturer;
import com.mojang.blaze3d.platform.GlStateManager;
import com.replaymod.core.versions.MCVer; import com.replaymod.core.versions.MCVer;
import com.replaymod.render.frame.OpenGlFrame; import com.replaymod.render.frame.OpenGlFrame;
import com.replaymod.render.rendering.Frame; import com.replaymod.render.rendering.Frame;
@@ -16,17 +17,9 @@ import org.lwjgl.opengl.GL12;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
//#if MC>=11400 import static com.replaymod.core.versions.MCVer.popMatrix;
import com.replaymod.render.mixin.MainWindowAccessor; import static com.replaymod.core.versions.MCVer.pushMatrix;
import static com.replaymod.core.versions.MCVer.getWindow; import static com.replaymod.core.versions.MCVer.resizeMainWindow;
//#endif
//#if MC>=10800
import static com.mojang.blaze3d.platform.GlStateManager.*;
//#else
//$$ import static com.replaymod.core.versions.MCVer.GlStateManager.*;
//#endif
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
@@ -36,7 +29,7 @@ public abstract class OpenGlFrameCapturer<F extends Frame, D extends CaptureData
protected int framesDone; protected int framesDone;
private Framebuffer frameBuffer; private Framebuffer frameBuffer;
private final MinecraftClient mc = MCVer.getMinecraft(); protected final MinecraftClient mc = MCVer.getMinecraft();
public OpenGlFrameCapturer(WorldRenderer worldRenderer, RenderInfo renderInfo) { public OpenGlFrameCapturer(WorldRenderer worldRenderer, RenderInfo renderInfo) {
this.worldRenderer = worldRenderer; this.worldRenderer = worldRenderer;
@@ -85,17 +78,17 @@ public abstract class OpenGlFrameCapturer<F extends Frame, D extends CaptureData
} }
protected OpenGlFrame renderFrame(int frameId, float partialTicks, D captureData) { protected OpenGlFrame renderFrame(int frameId, float partialTicks, D captureData) {
resize(getFrameWidth(), getFrameHeight()); resizeMainWindow(mc, getFrameWidth(), getFrameHeight());
pushMatrix(); pushMatrix();
frameBuffer().beginWrite(true); frameBuffer().beginWrite(true);
clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT GlStateManager.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
//#if MC>=11400 //#if MC>=11400
, false , false
//#endif //#endif
); );
enableTexture(); GlStateManager.enableTexture();
worldRenderer.renderWorld(partialTicks, captureData); worldRenderer.renderWorld(partialTicks, captureData);
@@ -115,30 +108,6 @@ public abstract class OpenGlFrameCapturer<F extends Frame, D extends CaptureData
return new OpenGlFrame(frameId, new Dimension(getFrameWidth(), getFrameHeight()), 4, buffer); return new OpenGlFrame(frameId, new Dimension(getFrameWidth(), getFrameHeight()), 4, buffer);
} }
protected void resize(int width, int height) {
//#if MC>=11400
Framebuffer fb = mc.getFramebuffer();
if (fb.viewportWidth != width || fb.viewportHeight != height) {
fb.resize(width, height
//#if MC>=11400
, false
//#endif
);
}
//noinspection ConstantConditions
MainWindowAccessor mainWindow = (MainWindowAccessor) (Object) getWindow(mc);
mainWindow.setFramebufferWidth(width);
mainWindow.setFramebufferHeight(height);
//#if MC>=11500
mc.gameRenderer.onResized(width, height);
//#endif
//#else
//$$ if (width != mc.displayWidth || height != mc.displayHeight) {
//$$ mc.resize(width, height);
//$$ }
//#endif
}
@Override @Override
public void close() throws IOException { public void close() throws IOException {
} }

View File

@@ -19,7 +19,6 @@ import net.minecraft.util.crash.CrashException;
import java.util.Arrays; import java.util.Arrays;
import java.util.function.Consumer; import java.util.function.Consumer;
import static com.replaymod.core.versions.MCVer.addDetail;
import static com.replaymod.render.ReplayModRender.LOGGER; import static com.replaymod.render.ReplayModRender.LOGGER;
public class GuiExportFailed extends GuiScreen { public class GuiExportFailed extends GuiScreen {
@@ -33,8 +32,8 @@ public class GuiExportFailed extends GuiScreen {
// If they haven't, then this is probably a faulty ffmpeg installation and there's nothing we can do // If they haven't, then this is probably a faulty ffmpeg installation and there's nothing we can do
CrashReport crashReport = CrashReport.create(e, "Exporting video"); CrashReport crashReport = CrashReport.create(e, "Exporting video");
CrashReportSection details = crashReport.addElement("Export details"); CrashReportSection details = crashReport.addElement("Export details");
addDetail(details, "Settings", settings::toString); details.add("Settings", settings::toString);
addDetail(details, "FFmpeg log", e::getLog); details.add("FFmpeg log", e::getLog);
throw new CrashException(crashReport); throw new CrashException(crashReport);
} else { } else {
// If they have, ask them whether it was intentional // If they have, ask them whether it was intentional

View File

@@ -2,6 +2,7 @@ package com.replaymod.render.gui;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
import com.replaymod.core.utils.Result;
import com.replaymod.core.utils.Utils; import com.replaymod.core.utils.Utils;
import com.replaymod.core.versions.MCVer; import com.replaymod.core.versions.MCVer;
import com.replaymod.render.RenderSettings; import com.replaymod.render.RenderSettings;
@@ -14,7 +15,6 @@ import com.replaymod.replay.ReplayModReplay;
import com.replaymod.replay.ReplaySender; import com.replaymod.replay.ReplaySender;
import com.replaymod.replaystudio.pathing.path.Timeline; import com.replaymod.replaystudio.pathing.path.Timeline;
import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.us.myles.ViaVersion.api.Pair;
import de.johni0702.minecraft.gui.GuiRenderer; import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.RenderInfo; import de.johni0702.minecraft.gui.RenderInfo;
import de.johni0702.minecraft.gui.container.AbstractGuiClickableContainer; import de.johni0702.minecraft.gui.container.AbstractGuiClickableContainer;
@@ -31,6 +31,7 @@ import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.GridLayout; import de.johni0702.minecraft.gui.layout.GridLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout; import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.popup.AbstractGuiPopup; import de.johni0702.minecraft.gui.popup.AbstractGuiPopup;
import de.johni0702.minecraft.gui.popup.GuiInfoPopup;
import de.johni0702.minecraft.gui.utils.Colors; import de.johni0702.minecraft.gui.utils.Colors;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
@@ -39,6 +40,7 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.NoticeScreen; import net.minecraft.client.gui.screen.NoticeScreen;
import net.minecraft.util.crash.CrashReport; import net.minecraft.util.crash.CrashReport;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.tuple.Pair;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -88,7 +90,7 @@ public class GuiRenderQueue extends AbstractGuiPopup<GuiRenderQueue> implements
private final AbstractGuiScreen<?> container; private final AbstractGuiScreen<?> container;
private final ReplayHandler replayHandler; private final ReplayHandler replayHandler;
private final Set<Entry> selectedEntries = new HashSet<>(); private final Set<Entry> selectedEntries = new HashSet<>();
private final Supplier<Timeline> timelineSupplier; private final Supplier<Result<Timeline, String[]>> timelineSupplier;
private boolean opened; private boolean opened;
{ {
@@ -113,7 +115,7 @@ public class GuiRenderQueue extends AbstractGuiPopup<GuiRenderQueue> implements
private final ReplayModRender mod = ReplayModRender.instance; private final ReplayModRender mod = ReplayModRender.instance;
private final List<RenderJob> jobs = mod.getRenderQueue(); private final List<RenderJob> jobs = mod.getRenderQueue();
public GuiRenderQueue(AbstractGuiScreen<?> container, ReplayHandler replayHandler, Supplier<Timeline> timelineSupplier) { public GuiRenderQueue(AbstractGuiScreen<?> container, ReplayHandler replayHandler, Supplier<Result<Timeline, String[]>> timelineSupplier) {
super(container); super(container);
this.container = container; this.container = container;
this.replayHandler = replayHandler; this.replayHandler = replayHandler;
@@ -127,7 +129,7 @@ public class GuiRenderQueue extends AbstractGuiPopup<GuiRenderQueue> implements
list.getListPanel().addElements(null, new Entry(renderJob)); list.getListPanel().addElements(null, new Entry(renderJob));
} }
addButton.onClick(this::addButtonClicked); addButton.onClick(() -> addButtonClicked().ifErr(lines -> GuiInfoPopup.open(container, lines)));
editButton.onClick(() -> { editButton.onClick(() -> {
Entry job = selectedEntries.iterator().next(); Entry job = selectedEntries.iterator().next();
@@ -267,15 +269,12 @@ public class GuiRenderQueue extends AbstractGuiPopup<GuiRenderQueue> implements
}); });
} }
private GuiRenderSettings addButtonClicked() { private Result<GuiRenderSettings, String[]> addButtonClicked() {
Timeline timeline = timelineSupplier.get(); return timelineSupplier.get().mapOk(timeline -> {
if (timeline != null) {
GuiRenderSettings popup = addJob(timeline); GuiRenderSettings popup = addJob(timeline);
popup.open(); popup.open();
return popup; return popup;
} else { });
return null;
}
} }
public GuiRenderSettings addJob(Timeline timeline) { public GuiRenderSettings addJob(Timeline timeline) {
@@ -317,9 +316,8 @@ public class GuiRenderQueue extends AbstractGuiPopup<GuiRenderQueue> implements
@Override @Override
public void open() { public void open() {
if (jobs.isEmpty() && timelineSupplier != null) { if (jobs.isEmpty() && timelineSupplier != null) {
if (addButtonClicked() == null) { addButtonClicked().ifErr(lines ->
close(); GuiInfoPopup.open(container, lines).onClosed(this::close));
}
return; return;
} }
@@ -348,7 +346,7 @@ public class GuiRenderQueue extends AbstractGuiPopup<GuiRenderQueue> implements
renderButton.setEnabled(jobs.size() > 0); renderButton.setEnabled(jobs.size() > 0);
renderButton.setI18nLabel("replaymod.gui.renderqueue.render" + (selected > 0 ? "selected" : "all")); renderButton.setI18nLabel("replaymod.gui.renderqueue.render" + (selected > 0 ? "selected" : "all"));
String[] compatError = VideoRenderer.checkCompat(); String[] compatError = VideoRenderer.checkCompat(jobs.stream().map(RenderJob::getSettings));
if (compatError != null) { if (compatError != null) {
renderButton.setDisabled().setTooltip(new GuiTooltip().setText(compatError)); renderButton.setDisabled().setTooltip(new GuiTooltip().setText(compatError));
} }

View File

@@ -1,8 +1,6 @@
package com.replaymod.render.gui; package com.replaymod.render.gui;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.InstanceCreator; import com.google.gson.InstanceCreator;
@@ -39,7 +37,6 @@ import net.minecraft.client.gui.screen.NoticeScreen;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
import net.minecraft.util.crash.CrashReport; import net.minecraft.util.crash.CrashReport;
import javax.annotation.Nullable;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
@@ -73,7 +70,7 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
if (renderMethodDropdown.getSelectedValue() == RenderSettings.RenderMethod.BLEND) { if (renderMethodDropdown.getSelectedValue() == RenderSettings.RenderMethod.BLEND) {
encodingPresetDropdown.setSelected(RenderSettings.EncodingPreset.BLEND); encodingPresetDropdown.setSelected(RenderSettings.EncodingPreset.BLEND);
} else { } else {
encodingPresetDropdown.setSelected(RenderSettings.EncodingPreset.MP4_DEFAULT); encodingPresetDropdown.setSelected(RenderSettings.EncodingPreset.MP4_CUSTOM);
} }
} }
updateInputs(); updateInputs();
@@ -131,25 +128,13 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
encodingPresetDropdown.getSelectedValue().getFileExtension()); encodingPresetDropdown.getSelectedValue().getFileExtension());
popup.setFolder(getParentFile(outputFile)); popup.setFolder(getParentFile(outputFile));
popup.setFileName(outputFile.getName()); popup.setFileName(outputFile.getName());
Futures.addCallback( popup.onAccept(file -> {
popup.getFuture(), if (!file.getName().equals(outputFile.getName())) {
new FutureCallback<File>() { userDefinedOutputFileName = true;
@Override }
public void onSuccess(@Nullable File result) { outputFile = file;
if (result != null) { outputFileButton.setLabel(file.getName());
if (!result.getName().equals(outputFile.getName())) { });
userDefinedOutputFileName = true;
}
outputFile = result;
outputFileButton.setLabel(result.getName());
}
}
@Override
public void onFailure(Throwable t) {
throw new RuntimeException(t);
}
});
} }
}); });
@@ -378,7 +363,7 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
videoHeight.setTextColor(Colors.RED); videoHeight.setTextColor(Colors.RED);
} }
String[] compatError = VideoRenderer.checkCompat(); String[] compatError = VideoRenderer.checkCompat(save(false));
if (resolutionError != null) { if (resolutionError != null) {
renderButton.setDisabled().setTooltip(new GuiTooltip().setI18nText(resolutionError)); renderButton.setDisabled().setTooltip(new GuiTooltip().setI18nText(resolutionError));
} else if (compatError != null) { } else if (compatError != null) {
@@ -401,10 +386,10 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
case CUBIC: case CUBIC:
case EQUIRECTANGULAR: case EQUIRECTANGULAR:
case ODS: case ODS:
stabilizePanel.forEach(IGuiCheckbox.class).setEnabled(); stabilizePanel.invokeAll(IGuiCheckbox.class, GuiElement::setEnabled);
break; break;
default: default:
stabilizePanel.forEach(IGuiCheckbox.class).setDisabled(); stabilizePanel.invokeAll(IGuiCheckbox.class, GuiElement::setDisabled);
} }
// Enable/Disable Spherical FOV slider // Enable/Disable Spherical FOV slider
@@ -421,8 +406,9 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
// Enable/Disable various options for blend export // Enable/Disable various options for blend export
boolean isEXR = encodingPresetDropdown.getSelectedValue() == RenderSettings.EncodingPreset.EXR; boolean isEXR = encodingPresetDropdown.getSelectedValue() == RenderSettings.EncodingPreset.EXR;
boolean isPNG = encodingPresetDropdown.getSelectedValue() == RenderSettings.EncodingPreset.PNG;
boolean isBlend = renderMethod == RenderSettings.RenderMethod.BLEND; boolean isBlend = renderMethod == RenderSettings.RenderMethod.BLEND;
boolean isFFmpeg = !isBlend && !isEXR; boolean isFFmpeg = !isBlend && !isEXR && !isPNG;
if (isBlend) { if (isBlend) {
videoWidth.setDisabled(); videoWidth.setDisabled();
videoHeight.setDisabled(); videoHeight.setDisabled();
@@ -432,11 +418,11 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
exportArguments.setEnabled(isFFmpeg); exportArguments.setEnabled(isFFmpeg);
antiAliasingDropdown.setEnabled(isFFmpeg); antiAliasingDropdown.setEnabled(isFFmpeg);
if (isEXR) { if (isEXR || isPNG) {
depthMap.setEnabled().setTooltip(null); depthMap.setEnabled().setTooltip(null);
} else { } else {
depthMap.setDisabled().setTooltip(new GuiTooltip().setColor(Colors.RED) depthMap.setDisabled().setTooltip(new GuiTooltip().setColor(Colors.RED)
.setI18nText("replaymod.gui.rendersettings.depthmap.onlyexr")); .setI18nText("replaymod.gui.rendersettings.depthmap.only_exr_or_png"));
} }
// Enable/Disable export args reset button // Enable/Disable export args reset button
@@ -520,7 +506,8 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
} }
RenderSettings.EncodingPreset encodingPreset = settings.getEncodingPreset(); RenderSettings.EncodingPreset encodingPreset = settings.getEncodingPreset();
/* encodingPreset can be null from a previously supported and later removed preset */ /* encodingPreset can be null from a previously supported and later removed preset */
if (encodingPreset == null || !encodingPreset.isSupported()) { boolean invalidEncodingPreset = encodingPreset == null || !encodingPreset.isSupported();
if (invalidEncodingPreset) {
encodingPreset = getDefaultRenderSettings().getEncodingPreset(); encodingPreset = getDefaultRenderSettings().getEncodingPreset();
} }
encodingPresetDropdown.setSelected(encodingPreset); encodingPresetDropdown.setSelected(encodingPreset);
@@ -569,7 +556,7 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
antiAliasingDropdown.setSelected(settings.getAntiAliasing()); antiAliasingDropdown.setSelected(settings.getAntiAliasing());
exportCommand.setText(settings.getExportCommand()); exportCommand.setText(settings.getExportCommand());
String exportArguments = settings.getExportArguments(); String exportArguments = settings.getExportArguments();
if (exportArguments == null || settings.getEncodingPreset() == null) { if (exportArguments == null || settings.getEncodingPreset() == null || invalidEncodingPreset) {
// backwards compat, see RenderSettings#exportArguments // backwards compat, see RenderSettings#exportArguments
exportArguments = encodingPreset.getValue(); exportArguments = encodingPreset.getValue();
} }
@@ -642,8 +629,8 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
} }
private RenderSettings getDefaultRenderSettings() { private RenderSettings getDefaultRenderSettings() {
return new RenderSettings(RenderSettings.RenderMethod.DEFAULT, RenderSettings.EncodingPreset.MP4_DEFAULT, 1920, 1080, 60, 10 << 20, null, return new RenderSettings(RenderSettings.RenderMethod.DEFAULT, RenderSettings.EncodingPreset.MP4_CUSTOM, 1920, 1080, 60, 20 << 20, null,
true, false, false, false, null, 360, 180, false, false, false, RenderSettings.AntiAliasing.NONE, "", RenderSettings.EncodingPreset.MP4_DEFAULT.getValue(), false); true, false, false, false, null, 360, 180, false, false, false, RenderSettings.AntiAliasing.NONE, "", RenderSettings.EncodingPreset.MP4_CUSTOM.getValue(), false);
} }
@Override @Override

Some files were not shown because too many files have changed in this diff Show More