Merge branch 'johni/1.13-pre' into johni/blend

This commit is contained in:
Jonas Herzig
2019-03-13 16:07:32 +01:00
177 changed files with 7973 additions and 3552 deletions

View File

@@ -8,8 +8,9 @@ pipeline:
commands:
- curl --fail --create-dirs -o $HOME/.gradle/init.d/mirror.gradle https://maven.johni0702.de/config/gradle
- git config --global user.email "replaymod@drone" && git config --global user.name "Drone"
- REPRODUCIBLE_BUILD=1 ./gradlew :1.7.10:setupCIWorkspace :jGui:1.7.10:setupCIWorkspace
- SIGNED_JAR=$(! git describe --exact 2>&1 > /dev/null; echo $?) REPRODUCIBLE_BUILD=1 ./gradlew $(bash -c "echo :{1.7.10,1.8,1.8.9,1.9.4,1.10.2,1.11,1.11.2,1.12,1.12.1,1.12.2}:reobfJar") --parallel
- ./gradlew --old-gradle :1.7.10:setupCIWorkspace :jGui:1.7.10:setupCIWorkspace
- ./gradlew --old-gradle :1.7.10:reobfJar
- ./gradlew $(bash -c "echo :{1.8,1.8.9,1.9.4,1.10.2,1.11,1.11.2,1.12,1.12.1,1.12.2,1.13.2}:reobfJar") --parallel
- mkdir -p build/libs && mv versions/*/build/libs/* build/libs/
archive:
image: plugins/s3

View File

@@ -1 +1 @@
eyJhbGciOiJIUzI1NiJ9.cGlwZWxpbmU6CiAgY2xvbmU6CiAgICBpbWFnZTogcGx1Z2lucy9naXQKICAgIHRhZ3M6IHRydWUKICAgIHJlY3Vyc2l2ZTogdHJ1ZQogIGJ1aWxkOgogICAgaW1hZ2U6IG1hdmVuOjMuMy45LWpkay04CiAgICBjb21tYW5kczoKICAgICAgLSBjdXJsIC0tZmFpbCAtLWNyZWF0ZS1kaXJzIC1vICRIT01FLy5ncmFkbGUvaW5pdC5kL21pcnJvci5ncmFkbGUgaHR0cHM6Ly9tYXZlbi5qb2huaTA3MDIuZGUvY29uZmlnL2dyYWRsZQogICAgICAtIGdpdCBjb25maWcgLS1nbG9iYWwgdXNlci5lbWFpbCAicmVwbGF5bW9kQGRyb25lIiAmJiBnaXQgY29uZmlnIC0tZ2xvYmFsIHVzZXIubmFtZSAiRHJvbmUiCiAgICAgIC0gUkVQUk9EVUNJQkxFX0JVSUxEPTEgLi9ncmFkbGV3IDoxLjcuMTA6c2V0dXBDSVdvcmtzcGFjZSA6akd1aToxLjcuMTA6c2V0dXBDSVdvcmtzcGFjZQogICAgICAtIFNJR05FRF9KQVI9JCghIGdpdCBkZXNjcmliZSAtLWV4YWN0IDI-JjEgPiAvZGV2L251bGw7IGVjaG8gJD8pIFJFUFJPRFVDSUJMRV9CVUlMRD0xIC4vZ3JhZGxldyAkKGJhc2ggLWMgImVjaG8gOnsxLjcuMTAsMS44LDEuOC45LDEuOS40LDEuMTAuMiwxLjExLDEuMTEuMiwxLjEyLDEuMTIuMSwxLjEyLjJ9OnJlb2JmSmFyIikgLS1wYXJhbGxlbAogICAgICAtIG1rZGlyIC1wIGJ1aWxkL2xpYnMgJiYgbXYgdmVyc2lvbnMvKi9idWlsZC9saWJzLyogYnVpbGQvbGlicy8KICBhcmNoaXZlOgogICAgaW1hZ2U6IHBsdWdpbnMvczMKICAgIGFjbDogcHVibGljLXJlYWQKICAgIHJlZ2lvbjogInVzLWVhc3QtMSIKICAgIGJ1Y2tldDogInJlcGxheW1vZCIKICAgIHBhdGhfc3R5bGU6IHRydWUKICAgIHNvdXJjZTogYnVpbGQvbGlicy8qCiAgICBzdHJpcF9wcmVmaXg6IGJ1aWxkL2xpYnMvCiAgICB0YXJnZXQ6IC8K.2bNe9Pd4FUTIP9VTrFR4YuHJkgCmjIbfBCUu-Wrvap8
eyJhbGciOiJIUzI1NiJ9.cGlwZWxpbmU6CiAgY2xvbmU6CiAgICBpbWFnZTogcGx1Z2lucy9naXQKICAgIHRhZ3M6IHRydWUKICAgIHJlY3Vyc2l2ZTogdHJ1ZQogIGJ1aWxkOgogICAgaW1hZ2U6IG1hdmVuOjMuMy45LWpkay04CiAgICBjb21tYW5kczoKICAgICAgLSBjdXJsIC0tZmFpbCAtLWNyZWF0ZS1kaXJzIC1vICRIT01FLy5ncmFkbGUvaW5pdC5kL21pcnJvci5ncmFkbGUgaHR0cHM6Ly9tYXZlbi5qb2huaTA3MDIuZGUvY29uZmlnL2dyYWRsZQogICAgICAtIGdpdCBjb25maWcgLS1nbG9iYWwgdXNlci5lbWFpbCAicmVwbGF5bW9kQGRyb25lIiAmJiBnaXQgY29uZmlnIC0tZ2xvYmFsIHVzZXIubmFtZSAiRHJvbmUiCiAgICAgIC0gLi9ncmFkbGV3IC0tb2xkLWdyYWRsZSA6MS43LjEwOnNldHVwQ0lXb3Jrc3BhY2UgOmpHdWk6MS43LjEwOnNldHVwQ0lXb3Jrc3BhY2UKICAgICAgLSAuL2dyYWRsZXcgLS1vbGQtZ3JhZGxlIDoxLjcuMTA6cmVvYmZKYXIKICAgICAgLSAuL2dyYWRsZXcgJChiYXNoIC1jICJlY2hvIDp7MS44LDEuOC45LDEuOS40LDEuMTAuMiwxLjExLDEuMTEuMiwxLjEyLDEuMTIuMSwxLjEyLjIsMS4xMy4yfTpyZW9iZkphciIpIC0tcGFyYWxsZWwKICAgICAgLSBta2RpciAtcCBidWlsZC9saWJzICYmIG12IHZlcnNpb25zLyovYnVpbGQvbGlicy8qIGJ1aWxkL2xpYnMvCiAgYXJjaGl2ZToKICAgIGltYWdlOiBwbHVnaW5zL3MzCiAgICBhY2w6IHB1YmxpYy1yZWFkCiAgICByZWdpb246ICJ1cy1lYXN0LTEiCiAgICBidWNrZXQ6ICJyZXBsYXltb2QiCiAgICBwYXRoX3N0eWxlOiB0cnVlCiAgICBzb3VyY2U6IGJ1aWxkL2xpYnMvKgogICAgc3RyaXBfcHJlZml4OiBidWlsZC9saWJzLwogICAgdGFyZ2V0OiAvCg.xvkvCrkXlWrSXghw1bLwsewIfd0vJZyz-Wk15airj_s

BIN
.gitignore vendored

Binary file not shown.

View File

@@ -8,6 +8,10 @@ After the initial clone, running `./gradlew setupDecompWorkspace` is necessary.
This will also be necessary if the `replaymod_at.cfg` file has been changed (getting errors about code that is trying
to access private fields is a good indication that this has happened).
**Note**: ForgeGradle 1.2 (used for 1.7.10) is not compatible with Gradle 4.
As such, you need to use an older version (Gradle 3.x) to build the ReplayMod for 1.7.10.
An easy way to do that is to pass `--old-gradle` as the first argument to the Gradle wrapper shell script: `./gradlew --old-gradle build`
### No IDE
You can build the mod by running `./gradlew build`. 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` (builds the MC 1.8 version).

View File

@@ -1,3 +1,6 @@
apply plugin: 'eclipse'
apply plugin: 'idea'
import groovy.json.JsonOutput
def latestVersion = file('version.txt').readLines().first()
@@ -13,7 +16,7 @@ if (releaseCommit == currentCommit) {
version = "$latestVersion-$diff-g${currentCommit.substring(0, 7)}"
}
if (gitDescribe().endsWith('*')) {
version = "$version*"
version = "$version-dirty"
}
group= "com.replaymod"
@@ -23,18 +26,6 @@ subprojects {
repositories {
maven { url 'https://jitpack.io' }
}
configurations.classpath.resolutionStrategy.eachDependency { dep ->
if (System.getenv('REPRODUCIBLE_BUILD') == '1') return
def req = dep.target
// Substitute FG 2.0 with custom fork that works with Gradle 3
if (req.group == 'net.minecraftforge.gradle' && req.name == 'ForgeGradle' && req.version == '2.0-SNAPSHOT') {
dep.useTarget 'com.github.ReplayMod:ForgeGradle:dd521d0'
}
// Substitute FG 2.1 with custom fork that works with Gradle 3
if (req.group == 'net.minecraftforge.gradle' && req.name == 'ForgeGradle' && req.version == '2.1-SNAPSHOT') {
dep.useTarget 'com.github.ReplayMod:ForgeGradle:9c2f79c'
}
}
}
// Thanks for wasting my time gradle...

5
gradle.properties Normal file
View File

@@ -0,0 +1,5 @@
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
# This is required to provide enough memory for the Minecraft decompilation process.
org.gradle.jvmargs=-Xmx3G
org.gradle.daemon=false
org.gradle.parallel=

View File

View File

@@ -30,24 +30,24 @@ cddfc1a07301f2fa07a5e1b6897e455d397d6d5c547d45082c267a1ee2c75f70 /com/github/Mod
7191124b8491d36b9fc1eb1a4e0f8ef710a4b98e27dde92854c24d45457fd9d0 /com/github/ModCoderPack/MCInjector/05aa80e/MCInjector-05aa80e.pom
ecf57aab63509ec0ce3937c2215bc3a2e3cb6357cd11095978db18bd3251731a /com/github/ModCoderPack/MCInjector/7258466/MCInjector-7258466.jar
dc7ed1f4f0ddd8f5ce3b449db944907a5eb2855dbbbc59b08dad1247ebafba33 /com/github/ModCoderPack/MCInjector/7258466/MCInjector-7258466.pom
e1a215146621ab100c5d88c6c65e7b76c91f2a06ab8714ac438738ddec5ea904 /com/github/ReplayMod/ReplayStudio/1.10.2/3680c2e/1.10.2-3680c2e.jar
da0b27f2719bf829f91eb4d6ea7d6e54c71b301a19578bafe6ec05e72ed04a6a /com/github/ReplayMod/ReplayStudio/1.10.2/3680c2e/1.10.2-3680c2e.pom
67e8b400d005235bd2825717864c4a9341567302877c857c3681adc74802b2ba /com/github/ReplayMod/ReplayStudio/1.11.2/3680c2e/1.11.2-3680c2e.jar
ff786e8da1d52bfdca8abe58bc83cf9200e027a85212da633e795811b5c8b1ee /com/github/ReplayMod/ReplayStudio/1.11.2/3680c2e/1.11.2-3680c2e.pom
68da074f5cccd590c9584efc885f6ea842a15f1ce968aad04cbac6af2c8ecf49 /com/github/ReplayMod/ReplayStudio/1.11/3680c2e/1.11-3680c2e.jar
79a6ed9587d6b23f5221b0fdff12f01de4859dc985f3cdbebf081edd4e478a54 /com/github/ReplayMod/ReplayStudio/1.11/3680c2e/1.11-3680c2e.pom
60549740b778011d5e4a8b786805c6de8c518ce8f627cf70369b2c71f0d399c4 /com/github/ReplayMod/ReplayStudio/1.12.1/3680c2e/1.12.1-3680c2e.jar
da248126087579d384175fa36eb654c8755027727aff6c285cd8e4e056ddf424 /com/github/ReplayMod/ReplayStudio/1.12.1/3680c2e/1.12.1-3680c2e.pom
30ecf796e3697cf7d86c21f245695e659b39f55f2aecf40864ec6ac2c0eeae87 /com/github/ReplayMod/ReplayStudio/1.12.2/3680c2e/1.12.2-3680c2e.jar
73c4c53e5f18cffd921db81019510c47afb306eb2aea86377f44fc91e8b45130 /com/github/ReplayMod/ReplayStudio/1.12.2/3680c2e/1.12.2-3680c2e.pom
2f0e27b40a0c3ac298573c6a2fad24829e968731676305b5f1c471a827ac7458 /com/github/ReplayMod/ReplayStudio/1.12/3680c2e/1.12-3680c2e.jar
282e2fa0ef80206ab592f90f8585d5ecf5adfb110dcd1cb5204971257e3fd44e /com/github/ReplayMod/ReplayStudio/1.12/3680c2e/1.12-3680c2e.pom
1aa22b15d5e89258fc58c2a310c915937cf93b42bf27b9fefc04d20b6b07b19c /com/github/ReplayMod/ReplayStudio/1.7.10/3680c2e/1.7.10-3680c2e.jar
fbd4bfe141d845248bb095d59f3aaf273bf20ad849cec89d21594754a69f3f53 /com/github/ReplayMod/ReplayStudio/1.7.10/3680c2e/1.7.10-3680c2e.pom
96b37e76cf8b4aac4f0419d84ba6427da156cd7c4f41f9b9380d149893dd50a7 /com/github/ReplayMod/ReplayStudio/1.8/3680c2e/1.8-3680c2e.jar
7a68b798f4029b98b391076992d39633b3060d06d43edc25422edbbed09914f5 /com/github/ReplayMod/ReplayStudio/1.8/3680c2e/1.8-3680c2e.pom
5e5bea81fd85631a5f80973fab581e991d793d543e2bbbdbf1bebc15b4a279cd /com/github/ReplayMod/ReplayStudio/1.9.4/3680c2e/1.9.4-3680c2e.jar
cb0a152f7c720de75325b2cb857879596edf8c4b0de6f5b39168a1be1aa6709f /com/github/ReplayMod/ReplayStudio/1.9.4/3680c2e/1.9.4-3680c2e.pom
72dd4d393e1103a8719629c2231b7fc4ac307f339c24d0da94c6cc1d050838ec /com/github/ReplayMod/ReplayStudio/1.10.2/2d8d41d/1.10.2-2d8d41d.jar
6849dab3156262b109d07bba0ac56ed996f6581b2f7f4065c88afe0a9d3a620c /com/github/ReplayMod/ReplayStudio/1.10.2/2d8d41d/1.10.2-2d8d41d.pom
868ce8eb3c2cf8628edb952828cbfec26fa9c443a33a6125a912c40548e0a835 /com/github/ReplayMod/ReplayStudio/1.11.2/2d8d41d/1.11.2-2d8d41d.jar
599546e6a69a60df616f657f3bda58d0d4e58103a17de351c65941e0b53bc658 /com/github/ReplayMod/ReplayStudio/1.11.2/2d8d41d/1.11.2-2d8d41d.pom
4ccffcdea734d26004364737b90cc394049a11f3ab0d47c66cdd2f0d5728e316 /com/github/ReplayMod/ReplayStudio/1.11/2d8d41d/1.11-2d8d41d.jar
e8e9bf0ee84eb6f89ed6ec28d5142fc0cdb68eea74a763a6f8ee5f4ee8af00d2 /com/github/ReplayMod/ReplayStudio/1.11/2d8d41d/1.11-2d8d41d.pom
57fef9ef4cbcf766f73122556d05aab6e80fecc3c9b12d0efdfb090500d422cf /com/github/ReplayMod/ReplayStudio/1.12.2/2d8d41d/1.12.2-2d8d41d.jar
55601b8a60329c2b5271dd8a44f7dd82bbf4288d698e840c111edeb9a0b52517 /com/github/ReplayMod/ReplayStudio/1.12.2/2d8d41d/1.12.2-2d8d41d.pom
f175ad66645b7fdf6e472ccac0e01893ea22cfb7812636013d0982b6280b4663 /com/github/ReplayMod/ReplayStudio/1.12.1/2d8d41d/1.12.1-2d8d41d.jar
d3ea142c6ef67c84d1b0f658a8a17612465fc2d89fb8c10fe15def51392a9fc2 /com/github/ReplayMod/ReplayStudio/1.12.1/2d8d41d/1.12.1-2d8d41d.pom
bcf66a214b72615ba0d60a7d4a8be0ae3480baa5a65aa37732616d0d7154fe68 /com/github/ReplayMod/ReplayStudio/1.12/2d8d41d/1.12-2d8d41d.jar
6681d0640cb569a2b2c8c082371e80f96e67b3ba292a4ba56cf188a71a6d915b /com/github/ReplayMod/ReplayStudio/1.12/2d8d41d/1.12-2d8d41d.pom
7f718341faa2b1203b078e8a416b74ae195dc98f98eebb0e08eb462cf98d6cd7 /com/github/ReplayMod/ReplayStudio/1.7.10/2d8d41d/1.7.10-2d8d41d.jar
d482d4a1d6b3b169822512ecb8a296ed43cbdba2f3ae85cc391c9e890526b7e7 /com/github/ReplayMod/ReplayStudio/1.7.10/2d8d41d/1.7.10-2d8d41d.pom
dc19cacb7b2e8dbce84200f78f0799ec8509343777b6d7511614e4b3a48e6f26 /com/github/ReplayMod/ReplayStudio/1.8/2d8d41d/1.8-2d8d41d.pom
6497cc087743beaaf397cda6d2ca76eb5afa37dae9889ea587ef8deae6483edd /com/github/ReplayMod/ReplayStudio/1.8/2d8d41d/1.8-2d8d41d.jar
9134cdee78eaac0c2c4a4728cef40fb8b9c824cbb587efdde5d768f23f295dfc /com/github/ReplayMod/ReplayStudio/1.9.4/2d8d41d/1.9.4-2d8d41d.jar
67faf1d44985182c4056ddbde300db813ca424b3f07818172eedcfc0f0a2c496 /com/github/ReplayMod/ReplayStudio/1.9.4/2d8d41d/1.9.4-2d8d41d.pom
bfdcda4cbf23f28392384818a1417c2d6df687e15ce77530ef96381393102f8a /com/github/SpongePowered/MixinGradle/dcfaf61/MixinGradle-dcfaf61.jar
3552e0c04817d91d1b6671a051d0e1d952c8b6a8eec57b54e829de9fa3ddf002 /com/github/SpongePowered/MixinGradle/dcfaf61/MixinGradle-dcfaf61.pom
c6ebd74cd6108b8c372c95b842725ee5bd6d3303ba26cb00f18bc92f80b47956 /com/github/tony19/named-regexp/0.2.3/named-regexp-0.2.3.jar

View File

@@ -34,7 +34,7 @@ popd
java -Dproxywitness.httpUris=http://export.mcpbot.bspk.rs/versions.json \
-Dproxywitness.useCache=false \
-jar deps/proxy-witness/build/libs/proxy-witness.jar \
"$PROXY_PORT" checksums.txt > proxy.log 2>&1 &
"$PROXY_PORT" checksums.empty.txt > proxy.log 2>&1 &
proxy_pid=$!
trap "kill $proxy_pid" EXIT

BIN
gradle/wrapper/gradle-wrapper-old.jar vendored Executable file

Binary file not shown.

View File

@@ -0,0 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-all.zip
distributionSha256Sum=69d99ade952de3727b65a88f3188ee72231ff4e28c2d00aacfc96a42c6d6f303

View File

@@ -2,5 +2,5 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-all.zip
distributionSha256Sum=69d99ade952de3727b65a88f3188ee72231ff4e28c2d00aacfc96a42c6d6f303
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip
distributionSha256Sum=39e2d5803bbd5eaf6c8efe07067b0e5a00235e8c71318642b2ed262920b27721

7
gradlew vendored
View File

@@ -65,7 +65,12 @@ cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ "$1" == "--old-gradle" ]; then
shift
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper-old.jar
else
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
fi
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then

2
jGui

Submodule jGui updated: 097131041b...79b0aaf3e9

View File

@@ -1,12 +1,47 @@
def f = file('versions/core/mcVersion')
def coreMcVersion = f.exists() ? f.readLines().first() as int : 11302
def jGuiVersions = []
def replayModVersions = []
if (gradle.gradleVersion.startsWith('3.')) {
if (coreMcVersion <= 10710) {
jGuiVersions += ['core']
replayModVersions += ['core']
}
jGuiVersions += [
'1.7.10',
]
replayModVersions += [
'1.7.10',
]
} else {
if (coreMcVersion > 10710) {
jGuiVersions += ['core']
replayModVersions += ['core']
}
jGuiVersions += [
'1.8',
'1.8.9',
'1.9.4',
'1.12',
'1.13.2'
]
replayModVersions += [
'1.8',
'1.8.9',
'1.9.4',
'1.10.2',
'1.11',
'1.11.2',
'1.12',
'1.12.1',
'1.12.2',
'1.13.2'
]
}
include ':jGui'
[
'core',
'1.7.10',
'1.8',
'1.8.9',
'1.9.4',
'1.12'
].each { version ->
jGuiVersions.each { version ->
include ":jGui:$version"
project(":jGui:$version").with {
projectDir = file("jGui/versions/$version")
@@ -14,20 +49,7 @@ include ':jGui'
}
}
def versions = [
'core',
'1.7.10',
'1.8',
'1.8.9',
'1.9.4',
'1.10.2',
'1.11',
'1.11.2',
'1.12',
'1.12.1',
'1.12.2'
]
versions.each { version ->
replayModVersions.each { version ->
include ":$version"
project(":$version").with {
projectDir = file("versions/$version")

View File

@@ -27,7 +27,13 @@ public class OptifineReflection {
public static void reloadLang() {
try {
Class.forName("Lang").getDeclaredMethod("resourcesReloaded").invoke(null);
Class<?> langClass;
try {
langClass = Class.forName("Lang"); // Pre Optifine 1.12.2 E1
} catch (ClassNotFoundException ignore) {
langClass = Class.forName("net.optifine.Lang"); // Post Optifine 1.12.2 E1
}
langClass.getDeclaredMethod("resourcesReloaded").invoke(null);
} catch (ClassNotFoundException ignore) {
// no optifine installed
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {

View File

@@ -25,16 +25,19 @@ public class ShaderReflection {
static {
try {
shaders_frameTimeCounter = Class.forName("shadersmod.client.Shaders")
.getDeclaredField("frameTimeCounter");
Class<?> shadersClass;
try {
shadersClass = Class.forName("shadersmod.client.Shaders"); // Pre Optifine 1.12.2 E1
} catch (ClassNotFoundException ignore) {
shadersClass = Class.forName("net.optifine.shaders.Shaders"); // Post Optifine 1.12.2 E1
}
shaders_frameTimeCounter = shadersClass.getDeclaredField("frameTimeCounter");
shaders_frameTimeCounter.setAccessible(true);
shaders_isShadowPass = Class.forName("shadersmod.client.Shaders")
.getDeclaredField("isShadowPass");
shaders_isShadowPass = shadersClass.getDeclaredField("isShadowPass");
shaders_isShadowPass.setAccessible(true);
shaders_beginRender = Class.forName("shadersmod.client.Shaders")
.getDeclaredMethod("beginRender", Minecraft.class, float.class, long.class);
shaders_beginRender = shadersClass.getDeclaredMethod("beginRender", Minecraft.class, float.class, long.class);
shaders_beginRender.setAccessible(true);
renderGlobal_chunksToUpdateForced = Class.forName("net.minecraft.client.renderer.RenderGlobal")

View File

@@ -9,7 +9,10 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Pseudo
@Mixin(targets = "shadersmod/client/ShadersRender", remap = false)
@Mixin(targets = {
"shadersmod/client/ShadersRender", // Pre Optifine 1.12.2 E1
"net/optifine/shaders/ShadersRender" // Post Optifine 1.12.2 E1
}, remap = false)
public abstract class MixinShadersRender {
@Inject(method = "renderHand0", at = @At("HEAD"), cancellable = true)

View File

@@ -6,12 +6,19 @@ import com.replaymod.core.versions.MCVer;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.util.ReportedException;
import org.lwjgl.input.Keyboard;
//#if MC>=11300
//#else
//$$ import org.lwjgl.input.Keyboard;
//#endif
//#if MC>=10800
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.InputEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
//#else
@@ -95,24 +102,25 @@ public class KeyBindingRegistry {
} catch (Throwable cause) {
CrashReport crashReport = CrashReport.makeCrashReport(cause, "Handling Key Binding");
CrashReportCategory category = crashReport.makeCategory("Key Binding");
category.addCrashSection("Key Binding", keyBinding);
MCVer.addDetail(category, "Key Binding", keyBinding::toString);
MCVer.addDetail(category, "Handler", runnable::toString);
throw new ReportedException(crashReport);
throw newReportedException(crashReport);
}
}
}
public void handleRaw() {
int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey();
//int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey();
int keyCode = -1; // FIXME
for (final Runnable runnable : rawHandlers.get(keyCode)) {
try {
runnable.run();
} catch (Throwable cause) {
CrashReport crashReport = CrashReport.makeCrashReport(cause, "Handling Raw Key Binding");
CrashReportCategory category = crashReport.makeCategory("Key Binding");
category.addCrashSection("Key Code", keyCode);
MCVer.addDetail(category, "Key Code", () -> "" + keyCode);
MCVer.addDetail(category, "Handler", runnable::toString);
throw new ReportedException(crashReport);
throw newReportedException(crashReport);
}
}
}

View File

@@ -1,12 +1,13 @@
package com.replaymod.core;
import org.apache.logging.log4j.LogManager;
import org.spongepowered.asm.launch.MixinBootstrap;
import org.spongepowered.asm.mixin.Mixins;
//#if MC<11300
//$$ import org.apache.logging.log4j.LogManager;
//$$ import org.spongepowered.asm.launch.MixinBootstrap;
//$$ import org.spongepowered.asm.mixin.Mixins;
//$$
//#if MC>=10800
import net.minecraftforge.fml.relauncher.CoreModManager;
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
//$$ import net.minecraftforge.fml.relauncher.CoreModManager;
//$$ import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
//#else
//$$ import com.replaymod.core.asm.GLErrorTransformer;
//$$ import com.replaymod.core.asm.GLStateTrackerTransformer;
@@ -16,57 +17,57 @@ import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
//$$ 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() {
MixinBootstrap.init();
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?
//$$
//$$ 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() {
//$$ MixinBootstrap.init();
//$$ 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());
//$$ 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() {
//$$ }
//$$ } 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[]{
};
//$$ return new String[]{
//$$ };
//#else
//$$ List<String> transformers = new ArrayList<>();
//$$ if ("true".equals(System.getProperty("replaymod.glerrors", "false"))) {
@@ -75,25 +76,26 @@ public class LoadingPlugin implements IFMLLoadingPlugin {
//$$ 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;
}
}
//$$ }
//$$
//$$ @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

@@ -0,0 +1,10 @@
package com.replaymod.core;
public interface Module {
// FMLCommonSetupEvent for 1.13+, FMLInitializationEvent below
default void initCommon() {}
// FMLClientSetupEvent for 1.13+, FMLInitializationEvent (if client) below
default void initClient() {}
// FMLClientSetupEvent for 1.13+, FMLInitializationEvent below
default void registerKeyBindings(KeyBindingRegistry registry) {}
}

View File

@@ -2,21 +2,42 @@ package com.replaymod.core;
import com.google.common.io.Files;
import com.google.common.util.concurrent.ListenableFutureTask;
import com.replaymod.core.gui.GuiBackgroundProcesses;
import com.replaymod.core.gui.GuiReplaySettings;
import com.replaymod.core.gui.RestoreReplayGui;
import com.replaymod.core.handler.MainMenuHandler;
import com.replaymod.core.utils.OpenGLUtils;
import com.replaymod.core.versions.MCVer;
import com.replaymod.editor.ReplayModEditor;
import com.replaymod.extras.ReplayModExtras;
import com.replaymod.online.ReplayModOnline;
import com.replaymod.recording.ReplayModRecording;
import com.replaymod.render.ReplayModRender;
import com.replaymod.replay.ReplayModReplay;
import com.replaymod.replaystudio.util.I18n;
import com.replaymod.simplepathing.ReplayModSimplePathing;
import de.johni0702.minecraft.gui.container.GuiScreen;
import lombok.Getter;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.FolderResourcePack;
import net.minecraft.client.resources.IResourcePack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.config.Configuration;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.FileUtils;
//#if MC>=11300
import com.replaymod.core.versions.LangResourcePack;
import net.minecraft.resources.FolderPack;
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 net.minecraft.client.resources.FolderResourcePack;
//$$ import net.minecraft.client.resources.IResourcePack;
//$$ import net.minecraftforge.common.config.Configuration;
//#endif
//#if MC>=10904
import net.minecraft.util.text.*;
//#else
@@ -28,18 +49,23 @@ import net.minecraft.util.text.*;
//#endif
//#if MC>=10800
import net.minecraft.client.settings.GameSettings;
import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.common.Loader;
//#if MC>=11300
import net.minecraft.client.GameSettings;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModList;
//#else
//$$ import net.minecraft.client.settings.GameSettings;
//$$ import net.minecraftforge.fml.client.FMLClientHandler;
//$$ 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.ModContainer;
//$$ import net.minecraftforge.fml.common.event.FMLInitializationEvent;
//$$ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.Mod.Instance;
import net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.EventBus;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
//#else
//$$ import cpw.mods.fml.common.Loader;
@@ -48,9 +74,7 @@ import net.minecraftforge.fml.common.gameevent.TickEvent;
//$$ import cpw.mods.fml.common.Mod.Instance;
//$$ import cpw.mods.fml.common.ModContainer;
//$$ import cpw.mods.fml.common.event.FMLInitializationEvent;
//$$ import cpw.mods.fml.common.event.FMLPostInitializationEvent;
//$$ import cpw.mods.fml.common.event.FMLPreInitializationEvent;
//$$ import cpw.mods.fml.common.eventhandler.EventBus;
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//$$ import cpw.mods.fml.common.gameevent.TickEvent;
//$$ import com.replaymod.replay.InputReplayTimer;
@@ -62,48 +86,108 @@ import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.FutureTask;
import static com.replaymod.core.versions.MCVer.*;
@Mod(modid = ReplayMod.MOD_ID,
useMetadata = true,
version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*",
//#if MC>=11300
@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",
//$$ clientSideOnly = true,
//$$ updateJSON = "https://raw.githubusercontent.com/ReplayMod/ReplayMod/master/versions.json",
//#endif
guiFactory = "com.replaymod.core.gui.GuiFactory")
public class ReplayMod {
//$$ guiFactory = "com.replaymod.core.gui.GuiFactory")
//#endif
public class ReplayMod implements Module {
public static ModContainer getContainer() {
return Loader.instance().getIndexedModList().get(MOD_ID);
//#if MC>=11300
return ModList.get().getModContainerById(MOD_ID).get();
//#else
//$$ return Loader.instance().getIndexedModList().get(MOD_ID);
//#endif
}
@Getter(lazy = true)
private static final String minecraftVersion = Loader.MC_VERSION;
//#if MC>=11300
private static final String minecraftVersion = MCPVersion.getMCVersion();
//#else
//$$ private static final String minecraftVersion = Loader.MC_VERSION;
//#endif
public static final String MOD_ID = "replaymod";
public static final ResourceLocation TEXTURE = new ResourceLocation("replaymod", "replay_gui.png");
public static final int TEXTURE_SIZE = 256;
private static final Minecraft mc = Minecraft.getMinecraft();
private static final Minecraft mc = MCVer.getMinecraft();
@Deprecated
public static Configuration config;
//#if MC<11300
//$$ @Deprecated
//$$ public static Configuration config;
//#endif
private final KeyBindingRegistry keyBindingRegistry = new KeyBindingRegistry();
private final SettingsRegistry settingsRegistry = new SettingsRegistry();
{
settingsRegistry.register(Setting.class);
}
// The instance of your mod that Forge uses.
@Instance(MOD_ID)
//#if MC>=11300
{ instance = this; }
//#else
//$$ @Instance(MOD_ID)
//#endif
public static ReplayMod instance;
private final List<Module> modules = new ArrayList<>();
private final GuiBackgroundProcesses backgroundProcesses = new GuiBackgroundProcesses();
public ReplayMod() {
I18n.setI18n(net.minecraft.client.resources.I18n::format);
//#if MC>=11300
DeferredWorkQueue.runLater(() -> MCVer.getMinecraft().resourcePackRepository.addPackFinder(new LangResourcePack.Finder()));
//#endif
// Register all RM modules
modules.add(this);
modules.add(new ReplayModRecording(this));
ReplayModReplay replayModule = new ReplayModReplay(this);
modules.add(replayModule);
modules.add(new ReplayModOnline(this, replayModule));
modules.add(new ReplayModRender(this));
modules.add(new ReplayModSimplePathing(this));
modules.add(new ReplayModEditor(this));
modules.add(new ReplayModExtras(this));
//#if MC>=11300
settingsRegistry.register();
//#endif
}
//#if MC<=11300
//$$ @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() {
return keyBindingRegistry;
}
@@ -114,33 +198,28 @@ public class ReplayMod {
public File getReplayFolder() throws IOException {
String path = getSettingsRegistry().get(Setting.RECORDING_PATH);
File folder = new File(path.startsWith("./") ? getMinecraft().mcDataDir : null, path);
File folder = new File(path.startsWith("./") ? mcDataDir(getMinecraft()) : null, path);
FileUtils.forceMkdir(folder);
return folder;
}
@EventHandler
public void preInit(FMLPreInitializationEvent event) {
// Initialize the static OpenGL info field from the minecraft main thread
// Unfortunately lwjgl uses static methods so we have to make use of magic init calls as well
OpenGLUtils.init();
I18n.setI18n(net.minecraft.client.resources.I18n::format);
config = new Configuration(event.getSuggestedConfigurationFile());
config.load();
settingsRegistry.setConfiguration(config);
}
//#ifdef DEV_ENV
static { // Note: even preInit is too late and we'd have to issue another resource reload
@SuppressWarnings("unchecked")
List<IResourcePack> defaultResourcePacks = mc.defaultResourcePacks;
FolderResourcePack jGuiResourcePack = new FolderResourcePack(new File("../jGui/src/main/resources")) {
//#if MC>=11300
FolderPack jGuiResourcePack = new FolderPack(new File("../jGui/src/main/resources")) {
@Override
protected InputStream getInputStreamByName(String resourceName) throws IOException {
protected InputStream getInputStream(String resourceName) throws IOException {
try {
return super.getInputStreamByName(resourceName);
return super.getInputStream(resourceName);
//#else
//$$ List<IResourcePack> defaultResourcePacks = mc.defaultResourcePacks;
//$$ FolderResourcePack jGuiResourcePack = new FolderResourcePack(new File("../jGui/src/main/resources")) {
//$$ @Override
//$$ protected InputStream getInputStreamByName(String resourceName) throws IOException {
//$$ try {
//$$ return super.getInputStreamByName(resourceName);
//#endif
} catch (IOException e) {
if ("pack.mcmeta".equals(resourceName)) {
return new ByteArrayInputStream(("{\"pack\": {\"description\": \"dummy pack for jGui resources in dev-env\", \"pack_format\": 1}}").getBytes(Charsets.UTF_8));
@@ -149,7 +228,16 @@ public class ReplayMod {
}
}
};
defaultResourcePacks.add(jGuiResourcePack);
//#if MC>=11300
mc.resourcePackRepository.addPackFinder(new IPackFinder() {
@Override
public <T extends ResourcePackInfo> void addPackInfosToMap(Map<String, T> map, ResourcePackInfo.IFactory<T> factory) {
map.put("jgui", ResourcePackInfo.func_195793_a("jgui", true, () -> jGuiResourcePack, factory, ResourcePackInfo.Priority.BOTTOM));
}
});
//#else
//$$ defaultResourcePacks.add(jGuiResourcePack);
//#endif
//#if MC<=10710
//$$ FolderResourcePack mainResourcePack = new FolderResourcePack(new File("../src/main/resources")) {
//$$ @Override
@@ -169,30 +257,43 @@ public class ReplayMod {
}
//#endif
@EventHandler
public void init(FMLInitializationEvent event) {
getSettingsRegistry().register(Setting.class);
//#if MC>=11300
{
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
@Override
public void registerKeyBindings(KeyBindingRegistry registry) {
registry.registerKeyBinding("replaymod.input.settings", 0, () -> {
new GuiReplaySettings(null, settingsRegistry).display();
});
}
@Override
public void initClient() {
new MainMenuHandler().register();
//#if MC<=10710
//$$ FML_BUS.register(this); // For runLater(Runnable)
//#endif
FML_BUS.register(keyBindingRegistry);
getKeyBindingRegistry().registerKeyBinding("replaymod.input.settings", 0, () -> {
new GuiReplaySettings(null, settingsRegistry).display();
});
}
@EventHandler
public void postInit(FMLPostInitializationEvent event) throws IOException {
settingsRegistry.save(); // Save default values to disk
FORGE_BUS.register(backgroundProcesses);
// 1.7.10 crashes when render distance > 16
//#if MC>=10800
if(!FMLClientHandler.instance().hasOptifine())
GameSettings.Options.RENDER_DISTANCE.setValueMax(64f);
//if(!FMLClientHandler.instance().hasOptifine()) FIXME 1.13 update
GameSettings.Options.RENDER_DISTANCE.setValueMax(64f);
//#endif
testIfMoeshAndExitMinecraft();
@@ -240,19 +341,18 @@ public class ReplayMod {
public void runLater(Runnable runnable) {
if (mc.isCallingFromMinecraftThread() && inRunLater) {
EventBus bus = FORGE_BUS;
//#if MC>=10800
bus.register(new Object() {
FORGE_BUS.register(new Object() {
@SubscribeEvent
public void onRenderTick(TickEvent.RenderTickEvent event) {
if (event.phase == TickEvent.Phase.START) {
runLater(runnable);
bus.unregister(this);
FORGE_BUS.unregister(this);
}
}
});
//#else
//$$ bus.register(new RunLaterHelper(runnable));
//$$ FORGE_BUS.register(new RunLaterHelper(runnable));
//#endif
return;
}
@@ -309,7 +409,11 @@ public class ReplayMod {
//#endif
public String getVersion() {
return getContainer().getVersion();
//#if MC>=11300
return getContainer().getModInfo().getVersion().toString();
//#else
//$$ return getContainer().getVersion();
//#endif
}
private void testIfMoeshAndExitMinecraft() {
@@ -355,4 +459,8 @@ public class ReplayMod {
mc.ingameGUI.getChatGUI().printChatMessage(text);
}
}
public GuiBackgroundProcesses getBackgroundProcesses() {
return backgroundProcesses;
}
}

View File

@@ -1,30 +1,67 @@
package com.replaymod.core;
import com.replaymod.core.events.SettingsChangedEvent;
import net.minecraft.client.resources.I18n;
import net.minecraftforge.common.config.Configuration;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
//#if MC>=11300
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
import static com.replaymod.core.versions.MCVer.*;
public class SettingsRegistry {
private static final Object NULL_OBJECT = new Object();
private Map<SettingKey<?>, Object> settings = new ConcurrentHashMap<>();
private Configuration configuration;
//#if MC>=11300
private ForgeConfigSpec spec;
private ModConfig config;
//#else
//$$ private Configuration configuration;
//#endif
public void setConfiguration(Configuration configuration) {
this.configuration = configuration;
//#if MC>=11300
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);
}
List<SettingKey<?>> keys = new ArrayList<>(settings.keySet());
settings.clear();
for (SettingKey key : keys) {
register(key);
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
public void register(Class<?> settingsClass) {
for (Field field : settingsClass.getDeclaredFields()) {
@@ -40,23 +77,30 @@ public class SettingsRegistry {
}
public void register(SettingKey<?> key) {
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;
//#if MC>=11300
if (spec != null) {
throw new IllegalStateException("Cannot register more settings are spec has been built.");
}
settings.put(key, value);
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
}
public Set<SettingKey<?>> getSettings() {
@@ -72,23 +116,35 @@ public class SettingsRegistry {
}
public <T> void set(SettingKey<T> key, T value) {
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.");
//#if MC>=11300
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
settings.put(key, value);
FML_BUS.post(new SettingsChangedEvent(this, key));
}
public void save() {
configuration.save();
//#if MC>=11300
if (config != null) {
config.save();
}
//#else
//$$ configuration.save();
//#endif
}
public interface SettingKey<T> {
@@ -127,7 +183,7 @@ public class SettingsRegistry {
@Override
public String getDisplayString() {
return displayString == null ? null : I18n.format(displayString);
return displayString;
}
@Override

View File

@@ -5,7 +5,11 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor;
//#if MC>=10800
import net.minecraftforge.fml.common.eventhandler.Event;
//#if MC>=11300
import net.minecraftforge.eventbus.api.Event;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.Event;
//#endif
//#else
//$$ import cpw.mods.fml.common.eventhandler.Event;
//#endif

View File

@@ -0,0 +1,135 @@
package com.replaymod.core.gui;
import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.RenderInfo;
import de.johni0702.minecraft.gui.container.AbstractGuiContainer;
import de.johni0702.minecraft.gui.container.GuiPanel;
import de.johni0702.minecraft.gui.container.GuiScreen;
import de.johni0702.minecraft.gui.container.VanillaGuiScreen;
import de.johni0702.minecraft.gui.element.GuiElement;
import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraftforge.client.event.GuiScreenEvent;
import net.minecraftforge.common.MinecraftForge;
//#if MC>=10800
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
//#else
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//#endif
import static com.replaymod.core.versions.MCVer.getGui;
import static com.replaymod.core.versions.MCVer.getMinecraft;
public class GuiBackgroundProcesses {
private GuiPanel panel = new GuiPanel().setLayout(new VerticalLayout().setSpacing(10));
public void register() {
MinecraftForge.EVENT_BUS.register(this);
}
public void unregister() {
MinecraftForge.EVENT_BUS.unregister(this);
}
@SubscribeEvent
public void onGuiInit(GuiScreenEvent.InitGuiEvent.Post event) {
if (getGui(event) != getMinecraft().currentScreen) return; // people tend to construct GuiScreens without opening them
VanillaGuiScreen.setup(getGui(event)).setLayout(new CustomLayout<GuiScreen>() {
@Override
protected void layout(GuiScreen container, int width, int height) {
pos(panel, width - 5 - width(panel), 5);
}
}).addElements(null, panel);
}
public void addProcess(GuiElement<?> element) {
panel.addElements(new VerticalLayout.Data(1.0),
new Element(element));
}
public void removeProcess(GuiElement<?> element) {
for (GuiElement child : panel.getChildren()) {
if (((Element) child).inner == element) {
panel.removeElement(child);
return;
}
}
}
private static class Element extends AbstractGuiContainer<Element> {
private GuiElement inner;
Element(GuiElement inner) {
this.inner = inner;
addElements(null, inner);
setLayout(new CustomLayout<Element>() {
@Override
protected void layout(Element container, int width, int height) {
pos(inner, 10, 10);
size(inner, width - 20, height - 20);
}
});
}
@Override
public ReadableDimension getMinSize() {
ReadableDimension minSize = inner.getMinSize();
return new Dimension(minSize.getWidth() + 20, minSize.getHeight() + 20);
}
@Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
final int u0 = 0;
final int v0 = 39;
renderer.bindTexture(TEXTURE);
int w = size.getWidth();
int h = size.getHeight();
// Corners
renderer.drawTexturedRect(0, 0, u0, v0, 5, 5); // Top left
renderer.drawTexturedRect(w - 5, 0, u0 + 12, v0, 5, 5); // Top right
renderer.drawTexturedRect(0, h - 5, u0, v0 + 12, 5, 5); // Bottom left
renderer.drawTexturedRect(w - 5, h - 5, u0 + 12, v0 + 12, 5, 5); // Bottom right
// Top and bottom edge
for (int x = 5; x < w - 5; x += 5) {
int rx = Math.min(5, w - 5 - x);
renderer.drawTexturedRect(x, 0, u0 + 6, v0, rx, 5); // Top
renderer.drawTexturedRect(x, h - 5, u0 + 6, v0 + 12, rx, 5); // Bottom
}
// Left and right edge
for (int y = 5; y < h - 5; y += 5) {
int ry = Math.min(5, h - 5 - y);
renderer.drawTexturedRect(0, y, u0, v0 + 6, 5, ry); // Left
renderer.drawTexturedRect(w - 5, y, u0 + 12, v0 + 6, 5, ry); // Right
}
// Center
for (int x = 5; x < w - 5; x += 5) {
for (int y = 5; y < h - 5; y += 5) {
int rx = Math.min(5, w - 5 - x);
int ry = Math.min(5, h - 5 - y);
renderer.drawTexturedRect(x, y, u0 + 6, v0 + 6, rx, ry);
}
}
super.draw(renderer, size, renderInfo);
}
@Override
protected Element getThis() {
return this;
}
}
}

View File

@@ -41,7 +41,7 @@ public class GuiReplaySettings extends AbstractGuiScreen<GuiReplaySettings> {
@SuppressWarnings("unchecked")
final SettingsRegistry.SettingKey<Boolean> booleanKey = (SettingsRegistry.SettingKey<Boolean>) key;
final GuiToggleButton button = new GuiToggleButton<>().setSize(150, 20)
.setLabel(key.getDisplayString()).setSelected(settingsRegistry.get(booleanKey) ? 0 : 1)
.setI18nLabel(key.getDisplayString()).setSelected(settingsRegistry.get(booleanKey) ? 0 : 1)
.setValues(I18n.format("options.on"), I18n.format("options.off"));
element = button.onClick(new Runnable() {
@Override
@@ -60,7 +60,7 @@ public class GuiReplaySettings extends AbstractGuiScreen<GuiReplaySettings> {
for (int j = 0; j < entries.length; j++) {
Object value = values.get(j);
entries[j] = new MultipleChoiceDropdownEntry(value,
multipleChoiceKey.getDisplayString() + ": " + I18n.format(value.toString()));
I18n.format(multipleChoiceKey.getDisplayString()) + ": " + I18n.format(value.toString()));
if (currentValue.equals(value)) {
selected = j;
}

View File

@@ -43,6 +43,9 @@ public class RestoreReplayGui extends AbstractGuiScreen<RestoreReplayGui> {
yesButton.onClick(() -> {
try {
ReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), null, file);
// Commit all not-yet-committed files into the main zip file.
// If we don't do this, then re-writing packet data below can actually overwrite uncommitted packet data!
replayFile.save();
ReplayMetaData metaData = replayFile.getMetaData();
if (metaData != null && metaData.getDuration() == 0) {
// Try to restore replay duration

View File

@@ -1,5 +1,6 @@
package com.replaymod.core.handler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiMainMenu;
import net.minecraft.client.gui.GuiScreen;
@@ -9,13 +10,15 @@ import net.minecraftforge.common.MinecraftForge;
import org.lwjgl.opengl.GL11;
//#if MC>=10800
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
//#else
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//#endif
import java.io.IOException;
import static com.replaymod.core.versions.MCVer.*;
/**
@@ -37,17 +40,18 @@ public class MainMenuHandler {
if (x(button) + button.width < gui.width / 2 - 100
|| x(button) > gui.width / 2 + 100
|| y(button) > gui.height / 4 + 10 + 4 * 24) continue;
// Move button up to make space for two rows of buttons
// Move button up to make space for one rows of buttons
// and then move back down by 10 to compensate for the space to the exit button that was already there
int offset = -2 * 24 + 10;
int offset = -1 * 24 + 10;
y(button, y(button) + offset);
//#if MC>=11202
if (button == gui.realmsButton) {
//#if MC>=11300
if (button.id == 14) {
realmsOffset = offset;
}
//#endif
}
//#if MC>=11202
//#if MC>=11300
if (realmsOffset != 0 && gui.realmsNotification instanceof GuiScreenRealmsProxy) {
gui.realmsNotification = new RealmsNotificationProxy((GuiScreenRealmsProxy) gui.realmsNotification, realmsOffset);
}
@@ -55,7 +59,7 @@ public class MainMenuHandler {
}
}
//#if MC>=11202
//#if MC>=11300
private static class RealmsNotificationProxy extends GuiScreen {
private final GuiScreenRealmsProxy proxy;
private final int offset;
@@ -66,30 +70,25 @@ public class MainMenuHandler {
}
@Override
public void setGuiSize(int w, int h) {
proxy.setGuiSize(w, h);
public void setWorldAndResolution(Minecraft mc, int width, int height) {
proxy.setWorldAndResolution(mc, width, height);
}
@Override
public void initGui() {
proxy.initGui();
public void tick() {
proxy.tick();
}
@Override
public void updateScreen() {
proxy.updateScreen();
}
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
public void render(int mouseX, int mouseY, float partialTicks) {
GL11.glTranslated(0, offset, 0);
proxy.drawScreen(mouseX, mouseY - offset, partialTicks);
proxy.render(mouseX, mouseY - offset, partialTicks);
GL11.glTranslated(0, -offset, 0);
}
@Override
public void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
proxy.mouseClicked(mouseX, mouseY - offset, mouseButton);
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) {
return proxy.mouseClicked(mouseX, mouseY - offset, mouseButton);
}
@Override

View File

@@ -11,11 +11,16 @@ import net.minecraftforge.registries.RegistryManager;
//#else
//$$ import cpw.mods.fml.common.registry.GameData;
//#endif
//$$ import java.util.stream.Stream;
//#endif
//#if MC>=10800
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.ModContainer;
//#if MC>=11300
import net.minecraftforge.fml.ModList;
//#else
//$$ import net.minecraftforge.fml.common.Loader;
//$$ import net.minecraftforge.fml.common.ModContainer;
//#endif
//#else
//$$ import cpw.mods.fml.common.Loader;
//$$ import cpw.mods.fml.common.ModContainer;
@@ -24,22 +29,32 @@ import net.minecraftforge.fml.common.ModContainer;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ModCompat {
@SuppressWarnings("unchecked")
public static Collection<ModInfo> getInstalledNetworkMods() {
Map<String, ModContainer> ignoreCaseMap = Loader.instance().getModList().stream()
.collect(Collectors.toMap(m -> m.getModId().toLowerCase(), Function.identity()));
//#if MC>=11200
//#if MC>=11300
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)
.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()))
.map(ResourceLocation::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(),
@@ -61,6 +76,7 @@ public class ModCompat {
//$$ .collect(Collectors.toList());
//#endif
//#endif
//#endif
}
public static final class ModInfoDifference {

View File

@@ -1,26 +0,0 @@
package com.replaymod.core.utils;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import java.nio.IntBuffer;
public class OpenGLUtils {
public static final int VIEWPORT_MAX_WIDTH;
public static final int VIEWPORT_MAX_HEIGHT;
static {
IntBuffer buffer = BufferUtils.createIntBuffer(16);
GL11.glGetInteger(GL11.GL_MAX_VIEWPORT_DIMS, buffer);
VIEWPORT_MAX_WIDTH = buffer.get();
VIEWPORT_MAX_HEIGHT = buffer.get();
}
/**
* Magic init method which has to be called from the OpenGL thread so the variables in this class
* can be initialized successfully.
* Does not perform any work on its own.
*/
public static void init() {
}
}

View File

@@ -3,6 +3,7 @@ package com.replaymod.core.utils;
import net.minecraft.network.PacketBuffer;
//#if MC>=10904
import net.minecraft.network.play.server.SPacketCustomPayload;
import net.minecraft.util.ResourceLocation;
//#else
//$$ import net.minecraft.network.play.server.S3FPacketCustomPayload;
//#endif
@@ -18,7 +19,11 @@ import static com.replaymod.core.versions.MCVer.readString;
* @see <a href="https://gist.github.com/Johni0702/2547c463e51f65f312cb">Replay Restrictions Gist</a>
*/
public class Restrictions {
public static final String PLUGIN_CHANNEL = "Replay|Restrict";
//#if MC>=11300
public static final ResourceLocation PLUGIN_CHANNEL = new ResourceLocation("replaymod", "restrict");
//#else
//$$ public static final String PLUGIN_CHANNEL = "Replay|Restrict";
//#endif
private boolean noXray;
private boolean noNoclip;
private boolean onlyFirstPerson;

View File

@@ -18,15 +18,20 @@ import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.popup.GuiInfoPopup;
import de.johni0702.minecraft.gui.utils.Colors;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import de.johni0702.minecraft.gui.versions.MCVer;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.crash.CrashReport;
import net.minecraft.util.ResourceLocation;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.FilenameUtils;
import org.apache.logging.log4j.Logger;
import org.lwjgl.input.Keyboard;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
//#if MC>=11300
//#else
//$$ import org.lwjgl.input.Keyboard;
//#endif
//#if MC>=10800
import net.minecraft.client.network.NetworkPlayerInfo;
@@ -64,16 +69,30 @@ import java.util.Date;
import java.util.UUID;
import java.util.function.Consumer;
import static net.minecraft.client.Minecraft.getMinecraft;
import static com.replaymod.core.versions.MCVer.Minecraft_mcDataDir;
import static com.replaymod.core.versions.MCVer.getMinecraft;
public class Utils {
private static InputStream getResourceAsStream(String path) {
// FIXME this seems broken in 1.13, hence the workaround. probably want to open an issue with modlauncher (or forge?)
//#ifdef DEV_ENV
try {
return new java.io.FileInputStream(new File("../src/main/resources" + path));
} catch (java.io.FileNotFoundException e) {
throw new RuntimeException(e);
}
//#else
//$$ return Utils.class.getResourceAsStream(path);
//#endif
}
public static final BufferedImage DEFAULT_THUMBNAIL;
static {
BufferedImage thumbnail;
try {
thumbnail = ImageIO.read(Utils.class.getClassLoader().getResourceAsStream("default_thumb.jpg"));
thumbnail = ImageIO.read(getResourceAsStream("/default_thumb.jpg"));
} catch (Exception e) {
thumbnail = new BufferedImage(1, 1, BufferedImage.TYPE_3BYTE_BGR);
e.printStackTrace();
@@ -98,7 +117,7 @@ public class Utils {
static {
// Largely from https://community.letsencrypt.org/t/134/37
try (InputStream in = Utils.class.getResourceAsStream("/dst_root_ca_x3.pem")){
try (InputStream in = getResourceAsStream("/dst_root_ca_x3.pem")){
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(in);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
@@ -189,7 +208,11 @@ public class Utils {
}
public static boolean isCtrlDown() {
return Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL);
//#if MC>=11300
return GuiScreen.isCtrlKeyDown();
//#else
//$$ return Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL);
//#endif
}
public static <T> void addCallback(ListenableFuture<T> future, Consumer<T> onSuccess, Consumer<Throwable> onFailure) {
@@ -216,7 +239,7 @@ public class Utils {
// Try to save the crash report
if (crashReport.getFile() == null) {
try {
File folder = new File(getMinecraft().mcDataDir, "crash-reports");
File folder = new File(Minecraft_mcDataDir(getMinecraft()), "crash-reports");
File file = new File(folder, "crash-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + "-client.txt");
logger.debug("Saving crash report to file: {}", file);
crashReport.saveToFile(file);
@@ -263,7 +286,7 @@ public class Utils {
// Replace close button with panel containing close and copy buttons
GuiButton copyToClipboardButton = new GuiButton().setI18nLabel("chat.copy").onClick(() ->
GuiScreen.setClipboardString(crashReport)).setSize(150, 20);
MCVer.setClipboardString(crashReport)).setSize(150, 20);
GuiButton closeButton = getCloseButton();
popup.removeElement(closeButton);
popup.addElements(new VerticalLayout.Data(1),
@@ -281,4 +304,17 @@ public class Utils {
super.draw(renderer, size, renderInfo);
}
}
public static <T extends Throwable> void throwIfInstanceOf(Throwable t, Class<T> cls) throws T {
if (cls.isInstance(t)) {
throw cls.cast(t);
}
}
public static void throwIfUnchecked(Throwable t) {
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else if (t instanceof Error) {
throw (Error) t;
}
}
}

View File

@@ -8,15 +8,27 @@ public class WrappedTimer extends Timer {
protected final Timer wrapped;
public WrappedTimer(Timer wrapped) {
super(0);
//#if MC>=11300
super(0, 0);
//#else
//$$ super(0);
//#endif
this.wrapped = wrapped;
copy(wrapped, this);
}
@Override
public void updateTimer() {
public void updateTimer(
//#if MC>=11300
long sysClock
//#endif
) {
copy(this, wrapped);
wrapped.updateTimer();
wrapped.updateTimer(
//#if MC>=11300
sysClock
//#endif
);
copy(wrapped, this);
}

View File

@@ -0,0 +1,146 @@
//#if MC>=11300
package com.replaymod.core.versions;
import com.google.gson.Gson;
import com.replaymod.core.ReplayMod;
import net.minecraft.resources.AbstractResourcePack;
import net.minecraft.resources.IPackFinder;
import net.minecraft.resources.IResourcePack;
import net.minecraft.resources.ResourcePackFileNotFoundException;
import net.minecraft.resources.ResourcePackInfo;
import net.minecraft.resources.ResourcePackType;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.packs.ModFileResourcePack;
import net.minecraftforge.fml.packs.ResourcePackLoader;
import org.apache.commons.io.IOUtils;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringBufferInputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* Resource pack which on-the-fly converts pre-1.13 language files into 1.13 json format.
*/
public class LangResourcePack extends AbstractResourcePack {
private static final Gson GSON = new Gson();
private static final String NAME = "replaymod_lang";
private static final Pattern JSON_FILE_PATTERN = Pattern.compile("^assets/" + ReplayMod.MOD_ID + "/lang/([a-z][a-z])_([a-z][a-z]).json$");
private static final Pattern LANG_FILE_NAME_PATTERN = Pattern.compile("^([a-z][a-z])_([a-z][a-z]).lang$");
LangResourcePack() {
super(new File(NAME));
}
private ModFileResourcePack getParent() {
return ResourcePackLoader.getResourcePackFor(ReplayMod.MOD_ID).orElseThrow(() -> new RuntimeException("Failed to get ReplayMod resource pack!"));
}
private String langName(String path) {
Matcher matcher = JSON_FILE_PATTERN.matcher(path);
if (!matcher.matches()) return null;
return String.format("%s_%s.lang", matcher.group(1), matcher.group(2).toUpperCase());
}
private Path langPath(String path) {
ModFileResourcePack parent = getParent();
if (parent == null) return null;
ModFile modFile = parent.getModFile();
String langName = langName(path);
if (langName == null) return null;
return modFile.getLocator().findPath(modFile, "assets", ReplayMod.MOD_ID, "lang", langName);
}
private String convertValue(String value) {
return value;
}
@Override
protected InputStream getInputStream(String path) throws IOException {
if ("pack.mcmeta".equals(path)) {
return new StringBufferInputStream("{\"pack\": {\"description\": \"ReplayMod language files\", \"pack_format\": 4}}");
}
Path langPath = langPath(path);
if (langPath == null) throw new ResourcePackFileNotFoundException(file, path);
String langFile;
try (InputStream in = Files.newInputStream(langPath)) {
langFile = IOUtils.toString(in);
}
Map<String, String> properties = new HashMap<>();
for (String line : langFile.split("\n")) {
if (line.trim().isEmpty() || line.trim().startsWith("#")) continue;
int i = line.indexOf('=');
String key = line.substring(0, i);
String value = line.substring(i + 1);
value = convertValue(value);
properties.put(key, value);
}
return new ByteArrayInputStream(GSON.toJson(properties).getBytes(StandardCharsets.UTF_8));
}
@Override
protected boolean resourceExists(String path) {
Path langPath = langPath(path);
return langPath != null && Files.exists(langPath);
}
@Override
public Collection<ResourceLocation> getAllResourceLocations(ResourcePackType resourcePackType, String path, int maxDepth, Predicate<String> filter) {
if (resourcePackType == ResourcePackType.CLIENT_RESOURCES && "lang".equals(path)) {
IResourcePack parent = getParent();
if (parent == null) return Collections.emptyList();
return parent.getAllResourceLocations(resourcePackType, path, maxDepth, name -> {
Matcher matcher = LANG_FILE_NAME_PATTERN.matcher(name);
if (matcher.matches()) {
return filter.test(String.format("%s_%s.json", matcher.group(1), matcher.group(1)));
} else {
return false;
}
}).stream().map(resourceLocation -> {
String p = resourceLocation.getPath().substring(0, "assets/lang/xx_XX".length()) + ".json";
return new ResourceLocation(resourceLocation.getNamespace(), p);
}).collect(Collectors.toList());
} else {
return Collections.emptyList();
}
}
@Override
public Set<String> getResourceNamespaces(ResourcePackType resourcePackType) {
if (resourcePackType == ResourcePackType.CLIENT_RESOURCES) {
return Collections.singleton("replaymod");
} else {
return Collections.emptySet();
}
}
@Override
public void close() {}
public static class Finder implements IPackFinder {
@Override
public <T extends ResourcePackInfo> void addPackInfosToMap(Map<String, T> packList, ResourcePackInfo.IFactory<T> factory) {
packList.put(NAME, ResourcePackInfo.func_195793_a(NAME, true, LangResourcePack::new, factory, ResourcePackInfo.Priority.BOTTOM));
}
}
}
//#endif

View File

@@ -6,9 +6,6 @@ import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.model.ModelBox;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.client.multiplayer.ServerData;
import net.minecraft.client.multiplayer.ServerList;
import net.minecraft.client.multiplayer.WorldClient;
@@ -16,8 +13,8 @@ import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.resources.ResourcePackRepository;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
@@ -25,6 +22,7 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.network.Packet;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.Util;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.client.event.GuiScreenEvent;
@@ -32,6 +30,25 @@ import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.event.RenderLivingEvent;
import net.minecraftforge.common.MinecraftForge;
//#if MC>=11300
import net.minecraft.client.MainWindow;
import net.minecraft.client.renderer.entity.model.ModelBox;
import net.minecraft.client.renderer.entity.model.ModelRenderer;
import net.minecraft.client.util.InputMappings;
import net.minecraft.crash.ReportedException;
import org.lwjgl.glfw.GLFW;
//#else
//$$ import net.minecraft.client.gui.ScaledResolution;
//$$ import net.minecraft.client.model.ModelBox;
//$$ import net.minecraft.client.model.ModelRenderer;
//$$ import net.minecraft.client.resources.ResourcePackRepository;
//$$ import net.minecraft.util.ReportedException;
//$$ import org.apache.logging.log4j.LogManager;
//$$ import org.lwjgl.Sys;
//$$ import java.awt.Desktop;
//#endif
//#if MC>=10904
//#if MC>=11200
import net.minecraft.client.renderer.BufferBuilder;
@@ -63,7 +80,11 @@ import net.minecraft.client.renderer.GlStateManager.BooleanState;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
import net.minecraft.world.WorldType;
import net.minecraftforge.fml.common.eventhandler.EventBus;
//#if MC>=11300
import net.minecraftforge.eventbus.api.IEventBus;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.EventBus;
//#endif
//#else
//$$ import com.google.common.util.concurrent.Futures;
//$$ import com.replaymod.render.hooks.GLStateTracker;
@@ -85,12 +106,17 @@ import java.util.concurrent.Callable;
* Abstraction over things that have changed between different MC versions.
*/
public class MCVer {
public static EventBus FORGE_BUS = MinecraftForge.EVENT_BUS;
//#if MC>=11300
public static IEventBus FORGE_BUS = MinecraftForge.EVENT_BUS;
public static IEventBus FML_BUS = FORGE_BUS;
//#else
//$$ public static EventBus FORGE_BUS = MinecraftForge.EVENT_BUS;
//#if MC>=10809
public static EventBus FML_BUS = FORGE_BUS;
//$$ public static EventBus FML_BUS = FORGE_BUS;
//#else
//$$ public static EventBus FML_BUS = FMLCommonHandler.instance().bus();
//#endif
//#endif
public static void addDetail(CrashReportCategory category, String name, Callable<String> callable) {
//#if MC>=10904
@@ -104,6 +130,22 @@ public class MCVer {
//#endif
}
public static void addButton(GuiScreenEvent.InitGuiEvent event, GuiButton button) {
//#if MC>=11300
event.addButton(button);
//#else
//$$ getButtonList(event).add(button);
//#endif
}
public static void removeButton(GuiScreenEvent.InitGuiEvent event, GuiButton button) {
//#if MC>=11300
event.removeButton(button);
//#else
//$$ getButtonList(event).remove(button);
//#endif
}
@SuppressWarnings("unchecked")
public static List<GuiButton> getButtonList(GuiScreenEvent.InitGuiEvent event) {
//#if MC>=10904
@@ -226,6 +268,14 @@ public class MCVer {
//#endif
//#endif
public static File mcDataDir(Minecraft mc) {
//#if MC>=11300
return mc.gameDir;
//#else
//$$ return mc.mcDataDir;
//#endif
}
//#if MC>=10800
public static Entity getRenderViewEntity(Minecraft mc) {
return mc.getRenderViewEntity();
@@ -318,8 +368,11 @@ public class MCVer {
}
public static BooleanState fog() {
//#if MC>=11300
return GlStateManager.FOG.fog;
//#else
//#if MC>=10809
return GlStateManager.fogState.fog;
//$$ return GlStateManager.fogState.fog;
//#else
//#if MC>=10800
//$$ return GlStateManager.fogState.field_179049_a;
@@ -327,11 +380,15 @@ public class MCVer {
//$$ return GLStateTracker.getInstance().fog;
//#endif
//#endif
//#endif
}
public static void fog(BooleanState fog) {
//#if MC>=11300
GlStateManager.FOG.fog = fog;
//#else
//#if MC>=10809
GlStateManager.fogState.fog = fog;
//$$ GlStateManager.fogState.fog = fog;
//#else
//#if MC>=10800
//$$ GlStateManager.fogState.field_179049_a = fog;
@@ -339,22 +396,31 @@ public class MCVer {
//$$ GLStateTracker.getInstance().fog = fog;
//#endif
//#endif
//#endif
}
public static BooleanState texture2DState(int index) {
//#if MC>=11300
return GlStateManager.TEXTURES[index].texture2DState;
//#else
//#if MC>=10800
return GlStateManager.textureState[index].texture2DState;
//$$ return GlStateManager.textureState[index].texture2DState;
//#else
//$$ return GLStateTracker.getInstance().texture[index];
//#endif
//#endif
}
public static void texture2DState(int index, BooleanState texture2DState) {
//#if MC>=11300
GlStateManager.TEXTURES[index].texture2DState = texture2DState;
//#else
//#if MC>=10800
GlStateManager.textureState[index].texture2DState = texture2DState;
//$$ GlStateManager.textureState[index].texture2DState = texture2DState;
//#else
//$$ GLStateTracker.getInstance().texture[index] = texture2DState;
//#endif
//#endif
}
public static void ServerList_saveSingleServer(ServerData serverData) {
@@ -373,18 +439,29 @@ public class MCVer {
//#endif
}
public static ScaledResolution newScaledResolution(Minecraft mc) {
//#if MC>=10809
return new ScaledResolution(mc);
//#else
//$$ return new ScaledResolution(mc, mc.displayWidth, mc.displayHeight);
//#endif
}
public static ListenableFuture setServerResourcePack(ResourcePackRepository repo, File file) {
//#if MC>=11300
public static MainWindow newScaledResolution(Minecraft mc) {
return mc.mainWindow;
}
//#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
public static ListenableFuture setServerResourcePack(File file) {
//#if MC>=11300
return getMinecraft().getPackFinder().func_195741_a(file);
//#else
//$$ ResourcePackRepository repo = getMinecraft().getResourcePackRepository();
//#if MC>=10809
//#if MC>=11200
return repo.setServerResourcePack(file);
//$$ return repo.setServerResourcePack(file);
//#else
//$$ return repo.setResourcePackInstance(file);
//#endif
@@ -398,6 +475,7 @@ public class MCVer {
//$$ return Futures.immediateFuture(null);
//#endif
//#endif
//#endif
}
public static boolean isKeyDown(KeyBinding keyBinding) {
@@ -566,12 +644,36 @@ public class MCVer {
public static RenderManager getRenderManager() {
//#if MC>=10800
return Minecraft.getMinecraft().getRenderManager();
return getMinecraft().getRenderManager();
//#else
//$$ return RenderManager.instance;
//#endif
}
public static Minecraft getMinecraft() {
//#if MC>=11300
return Minecraft.getInstance();
//#else
//$$ return Minecraft.getMinecraft();
//#endif
}
public static long milliTime() {
//#if MC>=11300
return Util.milliTime();
//#else
//$$ return Minecraft.getSystemTime();
//#endif
}
public static File Minecraft_mcDataDir(Minecraft mc) {
//#if MC>=11300
return mc.gameDir;
//#else
//$$ return mc.mcDataDir;
//#endif
}
public static int floor(double val) {
//#if MC>=11102
return MathHelper.floor(val);
@@ -580,6 +682,14 @@ public class MCVer {
//#endif
}
public static void bindTexture(ResourceLocation texture) {
//#if MC>=11300
getMinecraft().getTextureManager().bindTexture(texture);
//#else
//$$ getMinecraft().renderEngine.bindTexture(texture);
//#endif
}
public static float cos(float val) {
return MathHelper.cos(val);
}
@@ -612,6 +722,40 @@ public class MCVer {
//#endif
}
public static ReportedException newReportedException(CrashReport crashReport) {
return new ReportedException(crashReport);
}
public static void openFile(File file) {
//#if MC>=11300
Util.getOSType().openFile(file);
//#else
//$$ String path = file.getAbsolutePath();
//$$
//$$ // First try OS specific methods
//$$ try {
//$$ switch (Util.getOSType()) {
//$$ case WINDOWS:
//$$ Runtime.getRuntime().exec(String.format("cmd.exe /C start \"Open file\" \"%s\"", path));
//$$ return;
//$$ case OSX:
//$$ Runtime.getRuntime().exec(new String[]{"/usr/bin/open", path});
//$$ return;
//$$ }
//$$ } catch (IOException e) {
//$$ LogManager.getLogger().error("Cannot open file", e);
//$$ }
//$$
//$$ // Otherwise try to java way
//$$ try {
//$$ Desktop.getDesktop().browse(file.toURI());
//$$ } catch (Throwable throwable) {
//$$ // And if all fails, lwjgl
//$$ Sys.openURL("file://" + path);
//$$ }
//#endif
}
//#if MC<=10710
//$$ public static class GlStateManager {
//$$ public static void resetColor() { /* nop */ }
@@ -628,4 +772,59 @@ public class MCVer {
//$$ public static void rotate(float angle, float x, float y, float z) { glRotatef(angle, x, y, z); }
//$$ }
//#endif
//#if MC>=11300
public static void color(float r, float g, float b, float a) { GlStateManager.color4f(r, g, b, a); }
public static void enableAlpha() { GlStateManager.enableAlphaTest(); }
public static void disableAlpha() { GlStateManager.disableAlphaTest(); }
public static void tryBlendFuncSeparate(int l, int r, int vl, int vr) { GlStateManager.blendFuncSeparate(l, r, vl, vr); }
public static void colorLogicOp(int op) { GlStateManager.logicOp(op); }
public static abstract class Keyboard {
public static final int KEY_LCONTROL = GLFW.GLFW_KEY_LEFT_CONTROL;
public static final int KEY_LSHIFT = GLFW.GLFW_KEY_LEFT_SHIFT;
public static final int KEY_ESCAPE = GLFW.GLFW_KEY_ESCAPE;
public static final int KEY_HOME = GLFW.GLFW_KEY_HOME;
public static final int KEY_END = GLFW.GLFW_KEY_END;
public static final int KEY_UP = GLFW.GLFW_KEY_UP;
public static final int KEY_DOWN = GLFW.GLFW_KEY_DOWN;
public static final int KEY_LEFT = GLFW.GLFW_KEY_LEFT;
public static final int KEY_RIGHT = GLFW.GLFW_KEY_RIGHT;
public static final int KEY_BACK = GLFW.GLFW_KEY_BACKSPACE;
public static final int KEY_DELETE = GLFW.GLFW_KEY_DELETE;
public static final int KEY_RETURN = GLFW.GLFW_KEY_ENTER;
public static final int KEY_TAB = GLFW.GLFW_KEY_TAB;
public static final int KEY_F1 = GLFW.GLFW_KEY_F1;
public static final int KEY_A = GLFW.GLFW_KEY_A;
public static final int KEY_B = GLFW.GLFW_KEY_B;
public static final int KEY_C = GLFW.GLFW_KEY_C;
public static final int KEY_D = GLFW.GLFW_KEY_D;
public static final int KEY_E = GLFW.GLFW_KEY_E;
public static final int KEY_F = GLFW.GLFW_KEY_F;
public static final int KEY_G = GLFW.GLFW_KEY_G;
public static final int KEY_H = GLFW.GLFW_KEY_H;
public static final int KEY_I = GLFW.GLFW_KEY_I;
public static final int KEY_J = GLFW.GLFW_KEY_J;
public static final int KEY_K = GLFW.GLFW_KEY_K;
public static final int KEY_L = GLFW.GLFW_KEY_L;
public static final int KEY_M = GLFW.GLFW_KEY_M;
public static final int KEY_N = GLFW.GLFW_KEY_N;
public static final int KEY_O = GLFW.GLFW_KEY_O;
public static final int KEY_P = GLFW.GLFW_KEY_P;
public static final int KEY_Q = GLFW.GLFW_KEY_Q;
public static final int KEY_R = GLFW.GLFW_KEY_R;
public static final int KEY_S = GLFW.GLFW_KEY_S;
public static final int KEY_T = GLFW.GLFW_KEY_T;
public static final int KEY_U = GLFW.GLFW_KEY_U;
public static final int KEY_V = GLFW.GLFW_KEY_V;
public static final int KEY_W = GLFW.GLFW_KEY_W;
public static final int KEY_X = GLFW.GLFW_KEY_X;
public static final int KEY_Y = GLFW.GLFW_KEY_Y;
public static final int KEY_Z = GLFW.GLFW_KEY_Z;
public static boolean isKeyDown(int keyCode) {
return InputMappings.isKeyDown(keyCode);
}
}
//#endif
}

View File

@@ -1,49 +1,29 @@
package com.replaymod.editor;
import com.replaymod.core.Module;
import com.replaymod.core.ReplayMod;
import com.replaymod.editor.handler.GuiHandler;
import com.replaymod.online.Setting;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
//#if MC>=10800
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
//#else
//$$ import cpw.mods.fml.common.Mod;
//$$ import cpw.mods.fml.common.event.FMLInitializationEvent;
//$$ import cpw.mods.fml.common.event.FMLPreInitializationEvent;
//#endif
@Mod(modid = ReplayModEditor.MOD_ID,
version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*",
//#if MC>=10800
clientSideOnly = true,
//#endif
useMetadata = true)
public class ReplayModEditor {
public static final String MOD_ID = "replaymod-editor";
@Mod.Instance(MOD_ID)
public class ReplayModEditor implements Module {
{ instance = this; }
public static ReplayModEditor instance;
private ReplayMod core;
public static Logger LOGGER;
public static Logger LOGGER = LogManager.getLogger();
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
ReplayModEditor.LOGGER = event.getModLog();
core = ReplayMod.instance;
public ReplayModEditor(ReplayMod core) {
this.core = core;
core.getSettingsRegistry().register(Setting.class);
}
@Mod.EventHandler
public void init(FMLInitializationEvent event) {
new GuiHandler(this).register();
@Override
public void initClient() {
new GuiHandler().register();
}
public ReplayMod getCore() {

View File

@@ -0,0 +1,262 @@
package com.replaymod.editor.gui;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.utils.Utils;
import com.replaymod.editor.ReplayModEditor;
import com.replaymod.replay.gui.overlay.GuiMarkerTimeline;
import com.replaymod.replaystudio.data.Marker;
import com.replaymod.replaystudio.replay.ZipReplayFile;
import com.replaymod.replaystudio.studio.ReplayStudio;
import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.container.GuiContainer;
import de.johni0702.minecraft.gui.container.GuiPanel;
import de.johni0702.minecraft.gui.element.GuiButton;
import de.johni0702.minecraft.gui.element.GuiHorizontalScrollbar;
import de.johni0702.minecraft.gui.element.GuiTexturedButton;
import de.johni0702.minecraft.gui.element.GuiTooltip;
import de.johni0702.minecraft.gui.element.advanced.GuiProgressBar;
import de.johni0702.minecraft.gui.element.advanced.GuiTimelineTime;
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.lwjgl.Color;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.crash.CrashReport;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
public class GuiEditReplay extends AbstractGuiPopup<GuiEditReplay> {
private final Path inputPath;
private final EditTimeline timeline;
private final GuiTimelineTime<GuiMarkerTimeline> timelineTime = new GuiTimelineTime<>();
private final GuiHorizontalScrollbar scrollbar = new GuiHorizontalScrollbar().setSize(300, 9);
private final GuiTexturedButton zoomInButton = new GuiTexturedButton().setSize(9, 9)
.onClick(() -> zoomTimeline(2d / 3d))
.setTexture(ReplayMod.TEXTURE, ReplayMod.TEXTURE_SIZE).setTexturePosH(40, 20)
.setTooltip(new GuiTooltip().setI18nText("replaymod.gui.ingame.menu.zoomin"));
private final GuiTexturedButton zoomOutButton = new GuiTexturedButton().setSize(9, 9)
.onClick(() -> zoomTimeline(3d / 2d))
.setTexture(ReplayMod.TEXTURE, ReplayMod.TEXTURE_SIZE).setTexturePosH(40, 30)
.setTooltip(new GuiTooltip().setI18nText("replaymod.gui.ingame.menu.zoomout"));
private final GuiPanel zoomButtonPanel = new GuiPanel()
.setLayout(new VerticalLayout(VerticalLayout.Alignment.CENTER).setSpacing(2))
.addElements(null, zoomInButton, zoomOutButton);
private Set<Marker> markers;
protected GuiEditReplay(GuiContainer container, Path inputPath) throws IOException {
super(container);
this.inputPath = inputPath;
try (ZipReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), inputPath.toFile())) {
markers = replayFile.getMarkers().or(HashSet::new);
timeline = new EditTimeline(new HashSet<>(markers), markers -> this.markers = markers);
timeline.setSize(300, 20)
.setMarkers()
.setLength(replayFile.getMetaData().getDuration())
.onClick(timeline::setCursorPosition);
}
timelineTime.setTimeline(timeline);
scrollbar.onValueChanged(() -> {
timeline.setOffset((int) (scrollbar.getPosition() * timeline.getLength()));
timeline.setZoom(scrollbar.getZoom());
}).setZoom(1);
GuiPanel timelinePanel = new GuiPanel()
.setSize(300, 40)
.setLayout(new CustomLayout<GuiPanel>() {
@Override
protected void layout(GuiPanel container, int width, int height) {
pos(zoomButtonPanel, width - width(zoomButtonPanel), 10);
pos(timelineTime, 0, 2);
size(timelineTime, x(zoomButtonPanel), 8);
pos(timeline, 0, y(timelineTime) + height(timelineTime));
size(timeline, x(zoomButtonPanel) - 2, 20);
pos(scrollbar, 0, y(timeline) + height(timeline) + 1);
size(scrollbar, x(zoomButtonPanel) - 2, 9);
}
})
.addElements(null, timelineTime, timeline, scrollbar, zoomButtonPanel);
GuiButton buttonAddSplit = new GuiButton()
.setSize(100, 20)
.setI18nLabel("replaymod.gui.edit.split")
.setTooltip(new GuiTooltip().setI18nText("replaymod.gui.edit.split.tooltip"))
.onClick(() -> {
Marker marker = new Marker();
marker.setTime(timeline.getCursorPosition());
marker.setName(MarkerProcessor.MARKER_NAME_SPLIT);
timeline.addMarker(marker);
});
GuiButton buttonInsertCut = new GuiButton()
.setSize(100, 20)
.setI18nLabel("replaymod.gui.edit.cut.start")
.setTooltip(new GuiTooltip().setI18nText("replaymod.gui.edit.cut.tooltip"))
.onClick(() -> {
Marker marker = new Marker();
marker.setTime(timeline.getCursorPosition());
marker.setName(MarkerProcessor.MARKER_NAME_START_CUT);
timeline.addMarker(marker);
});
GuiButton buttonEndCut = new GuiButton()
.setSize(100, 20)
.setI18nLabel("replaymod.gui.edit.cut.end")
.setTooltip(new GuiTooltip().setI18nText("replaymod.gui.edit.cut.tooltip"))
.onClick(() -> {
Marker marker = new Marker();
marker.setTime(timeline.getCursorPosition());
marker.setName(MarkerProcessor.MARKER_NAME_END_CUT);
timeline.addMarker(marker);
});
GuiPanel controlPanel = new GuiPanel()
.setLayout(new HorizontalLayout().setSpacing(4))
.addElements(null, buttonAddSplit, buttonInsertCut, buttonEndCut);
GuiButton applyButton = new GuiButton().setI18nLabel("replaymod.gui.edit.apply").setSize(150, 20).onClick(this::apply);
GuiButton closeButton = new GuiButton().setI18nLabel("replaymod.gui.close").setSize(150, 20).onClick(this::close);
GuiPanel buttonPanel = new GuiPanel()
.setLayout(new HorizontalLayout().setSpacing(8))
.addElements(null, applyButton, closeButton);
popup.setLayout(new VerticalLayout(VerticalLayout.Alignment.TOP).setSpacing(10));
popup.addElements(new VerticalLayout.Data(0.5), timelinePanel, controlPanel, buttonPanel);
}
private void zoomTimeline(double factor) {
scrollbar.setZoom(scrollbar.getZoom() * factor);
}
private void apply() {
ProgressPopup progressPopup = new ProgressPopup(this);
new Thread(() -> {
try (ZipReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), inputPath.toFile())) {
replayFile.writeMarkers(markers);
replayFile.save();
} catch (IOException e) {
Utils.error(ReplayModEditor.LOGGER, this, CrashReport.makeCrashReport(e, "Writing markers"), this::close);
}
try {
MarkerProcessor.apply(inputPath, progressPopup.progressBar::setProgress);
} catch (IOException e) {
Utils.error(ReplayModEditor.LOGGER, this, CrashReport.makeCrashReport(e, "Running marker processor"), this::close);
}
ReplayMod.instance.runLater(() -> {
progressPopup.close();
close();
});
}).start();
}
@Override
public void open() {
super.open();
}
@Override
protected GuiEditReplay getThis() {
return this;
}
private class ProgressPopup extends AbstractGuiPopup<ProgressPopup> {
private final GuiProgressBar progressBar = new GuiProgressBar(popup).setSize(300, 20);
ProgressPopup(GuiContainer container) {
super(container);
open();
}
@Override
public void close() {
super.close();
}
@Override
protected ProgressPopup getThis() {
return this;
}
}
private class EditTimeline extends GuiMarkerTimeline {
EditTimeline(Set<Marker> markers, Consumer<Set<Marker>> saveMarkers) {
super(markers, saveMarkers);
}
@Override
protected void drawMarkers(GuiRenderer renderer, ReadableDimension size) {
drawCutQuads(renderer, size);
super.drawMarkers(renderer, size);
}
@Override
protected void drawMarker(GuiRenderer renderer, ReadableDimension size, Marker marker, int markerX) {
if (MarkerProcessor.MARKER_NAME_SPLIT.equals(marker.getName())) {
int height = size.getHeight() - BORDER_BOTTOM - BORDER_TOP - MARKER_SIZE + 1;
for (int y = 0; y < height; y += 3) {
renderer.drawRect(markerX, BORDER_TOP + y, 1, 2, Color.WHITE);
}
}
super.drawMarker(renderer, size, marker, markerX);
}
private void drawCutQuads(GuiRenderer renderer, ReadableDimension size) {
boolean inCut = false;
int startTime = 0;
for (Marker marker : markers.stream().sorted(Comparator.comparing(Marker::getTime)).collect(Collectors.toList())) {
if (MarkerProcessor.MARKER_NAME_START_CUT.equals(marker.getName()) && !inCut) {
inCut = true;
startTime = marker.getTime();
} else if (MarkerProcessor.MARKER_NAME_END_CUT.equals(marker.getName()) && inCut) {
drawCutQuad(renderer, size, startTime, marker.getTime());
inCut = false;
}
}
if (inCut) {
drawCutQuad(renderer, size, startTime, getLength());
}
}
private void drawCutQuad(GuiRenderer renderer, ReadableDimension size, int startFrameTime, int endFrameTime) {
int visibleWidth = size.getWidth() - BORDER_LEFT - BORDER_RIGHT;
int startTime = getOffset();
int visibleTime = (int) (getZoom() * getLength());
int endTime = getOffset() + visibleTime;
if (startFrameTime >= endTime || endFrameTime <= startTime) {
return; // Segment out of display range
}
double relativeStart = startFrameTime - startTime;
double relativeEnd = endFrameTime - startTime;
int startX = BORDER_LEFT + Math.max(0, (int) (relativeStart / visibleTime * visibleWidth) + MARKER_SIZE / 2 + 1);
int endX = BORDER_LEFT + Math.min(visibleWidth, (int) (relativeEnd / visibleTime * visibleWidth) - MARKER_SIZE / 2);
if (startX < endX) {
renderer.drawRect(startX + 1, size.getHeight() - BORDER_BOTTOM - MARKER_SIZE,
endX - startX - 2, MARKER_SIZE - 2, Color.RED);
}
}
}
}

View File

@@ -34,10 +34,10 @@ import de.johni0702.minecraft.gui.popup.AbstractGuiPopup;
import de.johni0702.minecraft.gui.popup.GuiInfoPopup;
import de.johni0702.minecraft.gui.popup.GuiYesNoPopup;
import de.johni0702.minecraft.gui.utils.Colors;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.crash.CrashReport;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.util.ReadableDimension;
import javax.annotation.Nullable;
import java.io.File;

View File

@@ -1,7 +1,10 @@
package com.replaymod.editor.gui;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.gson.JsonObject;
import com.replaymod.core.utils.Utils;
import com.replaymod.replay.gui.screen.GuiReplayViewer;
import com.replaymod.replaystudio.data.Marker;
import com.replaymod.replaystudio.filter.ChangeTimestampFilter;
import com.replaymod.replaystudio.filter.RemoveFilter;
@@ -12,21 +15,20 @@ import com.replaymod.replaystudio.replay.ZipReplayFile;
import com.replaymod.replaystudio.stream.PacketStream;
import com.replaymod.replaystudio.studio.ReplayStudio;
import de.johni0702.minecraft.gui.container.GuiPanel;
import de.johni0702.minecraft.gui.element.GuiButton;
import de.johni0702.minecraft.gui.element.GuiLabel;
import de.johni0702.minecraft.gui.element.GuiNumberField;
import de.johni0702.minecraft.gui.element.advanced.GuiDropdownMenu;
import de.johni0702.minecraft.gui.layout.GridLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import net.minecraft.client.resources.I18n;
import net.minecraft.crash.CrashReport;
import org.apache.commons.io.IOCase;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.util.Dimension;
import javax.annotation.Nullable;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -50,9 +52,10 @@ public class GuiTrimPanel extends GuiPanel {
private final GuiReplayEditor gui;
public final GuiDropdownMenu<File> inputReplays = new GuiDropdownMenu<File>(this)
.setMinSize(new Dimension(200, 20)).onSelection(i -> updateSelectedReplay())
.setToString(f -> f == NO_REPLAY ? "" : Utils.fileNameToReplayName(f.getName()));
private final GuiButton inputReplayButton = new GuiButton(this)
.setMinSize(new Dimension(200, 20))
.setMaxSize(new Dimension(350, 20));
private File inputReplay = NO_REPLAY;
public final GuiNumberField startHour = newGuiNumberField();
public final GuiNumberField startMin = newGuiNumberField();
@@ -104,24 +107,31 @@ public class GuiTrimPanel extends GuiPanel {
endMarker.setToString(toString).setMinSize(new Dimension(100, 20)).onSelection(i ->
onSelectedMarkerChanged(endMarker, endHour, endMin, endSec, endMilli));
File[] files = null;
try {
File folder = gui.getMod().getReplayFolder();
files = folder.listFiles((FileFilter) new SuffixFileFilter(".mcpr", IOCase.INSENSITIVE));
} catch (IOException e) {
Utils.error(LOGGER, gui, CrashReport.makeCrashReport(e, "Listing available replays"), gui.backButton::onClick);
}
if (files == null) {
LOGGER.warn("Replay file list is null, has the replay folder been deleted?");
files = new File[0];
} else {
LOGGER.debug("Found {} replays in the replay folder", files.length);
}
if (files.length == 0) {
inputReplays.setValues(NO_REPLAY);
} else {
inputReplays.setValues(files);
}
inputReplayButton.onClick(() -> {
File folder;
try {
folder = gui.getMod().getReplayFolder();
} catch (IOException e) {
Utils.error(LOGGER, gui, CrashReport.makeCrashReport(e, "Getting replay folder"), gui.backButton::onClick);
return;
}
GuiReplayViewer.GuiSelectReplayPopup popup = GuiReplayViewer.GuiSelectReplayPopup.openGui(gui, folder);
Futures.addCallback(popup.getFuture(), new FutureCallback<File>() {
@Override
public void onSuccess(@Nullable File result) {
if (result != null) {
inputReplay = result;
updateSelectedReplay();
updateReadyState();
}
}
@Override
public void onFailure(Throwable t) {
Utils.error(LOGGER, gui, CrashReport.makeCrashReport(t, "Selecting replay"), gui.backButton::onClick);
}
});
});
updateSelectedReplay();
updateReadyState();
@@ -135,7 +145,7 @@ public class GuiTrimPanel extends GuiPanel {
JsonObject config = new JsonObject();
config.addProperty("offset", -start);
// Pass filters to save dialog
gui.save(inputReplays.getSelectedValue(),
gui.save(inputReplay,
Pair.of(new PacketStream.FilterInfo(new SquashFilter(), -1, start), new JsonObject()),
Pair.of(new PacketStream.FilterInfo(ctf, start, end), config),
Pair.of(new PacketStream.FilterInfo(new RemoveFilter(), end, -1), new JsonObject())
@@ -161,7 +171,11 @@ public class GuiTrimPanel extends GuiPanel {
}
private void updateSelectedReplay() {
File file = inputReplays.getSelectedValue();
File file = inputReplay;
// Update input button label
inputReplayButton.setLabel(file == NO_REPLAY ? I18n.format("gui.none") : Utils.fileNameToReplayName(file.getName()));
// Load markers and meta data from replay file
ReplayMetaData metaData;
Set<Marker> markers;
@@ -196,6 +210,6 @@ public class GuiTrimPanel extends GuiPanel {
}
private void updateReadyState() {
gui.saveButton.setEnabled(inputReplays.getSelectedValue() != NO_REPLAY);
gui.saveButton.setEnabled(inputReplay != NO_REPLAY);
}
}

View File

@@ -0,0 +1,180 @@
package com.replaymod.editor.gui;
import com.replaymod.replaystudio.PacketData;
import com.replaymod.replaystudio.Studio;
import com.replaymod.replaystudio.data.Marker;
import com.replaymod.replaystudio.filter.SquashFilter;
import com.replaymod.replaystudio.filter.StreamFilter;
import com.replaymod.replaystudio.io.ReplayInputStream;
import com.replaymod.replaystudio.io.ReplayOutputStream;
import com.replaymod.replaystudio.replay.ReplayMetaData;
import com.replaymod.replaystudio.replay.ZipReplayFile;
import com.replaymod.replaystudio.stream.IteratorStream;
import com.replaymod.replaystudio.studio.ReplayStudio;
import com.replaymod.replaystudio.util.Utils;
import org.apache.commons.io.FilenameUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
public class MarkerProcessor {
/**
* Signals the start of a section which is to be cut from the replay.
*/
public static final String MARKER_NAME_START_CUT = "_RM_START_CUT";
/**
* Signals the end of a section which is to be cut from the replay.
*/
public static final String MARKER_NAME_END_CUT = "_RM_END_CUT";
/**
* Signals the point at which a replay is to be split into multiple replays.
* If it is found in a section which is to be cut, that section will be cut from both replays.
*/
public static final String MARKER_NAME_SPLIT = "_RM_SPLIT";
private static boolean hasWork(Path path) throws IOException {
try (ZipReplayFile inputReplayFile = new ZipReplayFile(new ReplayStudio(), path.toFile())) {
return inputReplayFile.getMarkers().or(HashSet::new).stream().anyMatch(m -> m.getName().startsWith("_RM_"));
}
}
public static void apply(Path path, Consumer<Float> progress) throws IOException {
if (!hasWork(path)) {
return;
}
String replayName = FilenameUtils.getBaseName(path.getFileName().toString());
int splitCounter = 0;
Studio studio = new ReplayStudio();
SquashFilter squashFilter = new SquashFilter();
squashFilter.init(studio, null);
Path inputPath = path.resolveSibling("raw").resolve(path.getFileName());
Files.createDirectories(inputPath.getParent());
Files.move(path, inputPath);
try (ZipReplayFile inputReplayFile = new ZipReplayFile(studio, inputPath.toFile())) {
List<Marker> markers = inputReplayFile.getMarkers().or(HashSet::new)
.stream().sorted(Comparator.comparing(Marker::getTime)).collect(Collectors.toList());
Iterator<Marker> markerIterator = markers.iterator();
boolean anySplit = markers.stream().anyMatch(m -> m.getName().equals(MARKER_NAME_SPLIT));
int inputDuration = inputReplayFile.getMetaData().getDuration();
ReplayInputStream replayInputStream = inputReplayFile.getPacketData(studio, true);
int timeOffset = 0;
SquashFilter cutFilter = null;
int startCutOffset = 0;
PacketData nextPacket = replayInputStream.readPacket();
Marker nextMarker = markerIterator.next();
while (nextPacket != null) {
try (ZipReplayFile outputReplayFile = new ZipReplayFile(studio, null,
(anySplit ? path.resolveSibling(replayName + "_" + splitCounter + ".mcpr") : path).toFile())) {
long duration = 0;
Set<Marker> outputMarkers = new HashSet<>();
ReplayMetaData metaData = inputReplayFile.getMetaData();
metaData.setDate(metaData.getDate() + timeOffset);
try (ReplayOutputStream replayOutputStream = outputReplayFile.writePacketData(true)) {
if (cutFilter != null) {
cutFilter = squashFilter;
} else if (splitCounter > 0) {
List<PacketData> packets = new ArrayList<>();
squashFilter.onEnd(
new IteratorStream(packets.listIterator(), (StreamFilter) null),
timeOffset
);
for (PacketData packet : packets) {
replayOutputStream.write(0, packet.getPacket());
}
}
while (nextPacket != null) {
if (nextMarker != null && nextPacket.getTime() > nextMarker.getTime()) {
if (MARKER_NAME_START_CUT.equals(nextMarker.getName())) {
startCutOffset = nextMarker.getTime();
cutFilter = new SquashFilter();
} else if (MARKER_NAME_END_CUT.equals(nextMarker.getName())) {
timeOffset += nextMarker.getTime() - startCutOffset;
if (cutFilter != null) {
List<PacketData> packets = new ArrayList<>();
cutFilter.onEnd(
new IteratorStream(packets.listIterator(), (StreamFilter) null),
nextMarker.getTime()
);
for (PacketData packet : packets) {
replayOutputStream.write(nextMarker.getTime() - timeOffset, packet.getPacket());
}
cutFilter = null;
}
} else if (MARKER_NAME_SPLIT.equals(nextMarker.getName())) {
splitCounter++;
timeOffset = nextMarker.getTime();
startCutOffset = timeOffset;
nextMarker = markerIterator.hasNext() ? markerIterator.next() : null;
break;
} else {
nextMarker.setTime(nextMarker.getTime() - timeOffset);
outputMarkers.add(nextMarker);
}
nextMarker = markerIterator.hasNext() ? markerIterator.next() : null;
continue;
}
squashFilter.onPacket(null, nextPacket);
if (cutFilter != null) {
if (cutFilter != squashFilter) {
cutFilter.onPacket(null, nextPacket);
}
} else {
replayOutputStream.write(nextPacket.getTime() - timeOffset, nextPacket.getPacket());
duration = nextPacket.getTime() - timeOffset;
}
nextPacket = replayInputStream.readPacket();
if (nextPacket != null) {
progress.accept((float) nextPacket.getTime() / (float) inputDuration);
} else {
progress.accept(1f);
}
}
}
metaData.setDuration((int) duration);
outputReplayFile.writeMetaData(metaData);
outputReplayFile.writeMarkers(outputMarkers);
outputReplayFile.writeModInfo(inputReplayFile.getModInfo());
// We could filter these but ReplayStudio doesn't yet provide a nice method for determining
// which ones are used.
Map<Integer, String> resourcePackIndex = inputReplayFile.getResourcePackIndex();
if (resourcePackIndex != null) {
outputReplayFile.writeResourcePackIndex(resourcePackIndex);
for (String hash : resourcePackIndex.values()) {
try (InputStream in = inputReplayFile.getResourcePack(hash).get();
OutputStream out = outputReplayFile.writeResourcePack(hash)) {
Utils.copy(in, out);
}
}
}
outputReplayFile.save();
}
}
}
}
}

View File

@@ -1,55 +1,55 @@
package com.replaymod.editor.handler;
import com.replaymod.core.utils.Utils;
import com.replaymod.editor.ReplayModEditor;
import com.replaymod.editor.gui.GuiReplayEditor;
import com.replaymod.editor.gui.GuiEditReplay;
import com.replaymod.replay.gui.screen.GuiReplayViewer;
import de.johni0702.minecraft.gui.container.AbstractGuiScreen;
import de.johni0702.minecraft.gui.container.GuiScreen;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiMainMenu;
import net.minecraft.client.resources.I18n;
import de.johni0702.minecraft.gui.element.GuiButton;
import net.minecraft.crash.CrashReport;
import net.minecraftforge.client.event.GuiScreenEvent;
//#if MC>=10800
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
//#else
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//#endif
import java.io.IOException;
import static com.replaymod.core.versions.MCVer.*;
public class GuiHandler {
private static final int BUTTON_REPLAY_EDITOR = 17890237;
private final ReplayModEditor mod;
public GuiHandler(ReplayModEditor mod) {
this.mod = mod;
}
public void register() {
FML_BUS.register(this);
FORGE_BUS.register(this);
}
@SubscribeEvent
public void injectIntoMainMenu(GuiScreenEvent.InitGuiEvent event) {
if (!(getGui(event) instanceof GuiMainMenu)) {
public void injectIntoReplayViewer(GuiScreenEvent.InitGuiEvent.Post event) {
AbstractGuiScreen guiScreen = GuiScreen.from(getGui(event));
if (!(guiScreen instanceof GuiReplayViewer)) {
return;
}
GuiButton button = new GuiButton(BUTTON_REPLAY_EDITOR, getGui(event).width / 2 + 2,
getGui(event).height / 4 + 10 + 3 * 24, I18n.format("replaymod.gui.replayeditor"));
button.width = button.width / 2 - 2;
getButtonList(event).add(button);
}
@SubscribeEvent
public void onButton(GuiScreenEvent.ActionPerformedEvent.Pre event) {
if(!getButton(event).enabled) return;
if (getGui(event) instanceof GuiMainMenu) {
if (getButton(event).id == BUTTON_REPLAY_EDITOR) {
new GuiReplayEditor(GuiScreen.wrap(getGui(event)), mod.getCore()).display();
final GuiReplayViewer replayViewer = (GuiReplayViewer) guiScreen;
// Inject Edit button
replayViewer.replaySpecificButtons.add(new GuiButton(replayViewer.editorButton).onClick(() -> {
try {
new GuiEditReplay(replayViewer, replayViewer.list.getSelected().file.toPath()) {
@Override
protected void close() {
super.close();
replayViewer.list.load();
}
}.open();
} catch (IOException e) {
Utils.error(ReplayModEditor.LOGGER, replayViewer, CrashReport.makeCrashReport(e, "Opening replay editor"), () -> {});
}
}
}).setSize(73, 20).setI18nLabel("replaymod.gui.edit").setDisabled());
}
}

View File

@@ -8,11 +8,21 @@ import com.replaymod.replay.gui.overlay.GuiReplayOverlay;
import de.johni0702.minecraft.gui.element.GuiImage;
import de.johni0702.minecraft.gui.element.IGuiImage;
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import net.minecraft.client.settings.GameSettings;
import org.lwjgl.input.Keyboard;
//#if MC>=11300
import com.replaymod.core.versions.MCVer.Keyboard;
import net.minecraft.client.GameSettings;
//#else
//$$ import net.minecraft.client.settings.GameSettings;
//$$ import org.lwjgl.input.Keyboard;
//#endif
//#if MC>=10800
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
import net.minecraftforge.fml.common.gameevent.TickEvent;
//#else
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
@@ -28,7 +38,11 @@ public class FullBrightness implements Extra {
private GameSettings gameSettings;
private boolean active;
private float originalGamma;
//#if MC>=11300
private double originalGamma;
//#else
//$$ private float originalGamma;
//#endif
@Override
public void register(final ReplayMod mod) throws Exception {
@@ -39,7 +53,11 @@ public class FullBrightness implements Extra {
@Override
public void run() {
active = !active;
mod.getMinecraft().entityRenderer.lightmapUpdateNeeded = true;
//#if MC>=11300
mod.getMinecraft().entityRenderer.tick(); // need to tick once to update lightmap when replay is paused
//#else
//$$ mod.getMinecraft().entityRenderer.lightmapUpdateNeeded = true;
//#endif
ReplayHandler replayHandler = module.getReplayHandler();
if (replayHandler != null) {
updateIndicator(replayHandler.getOverlay());

View File

@@ -16,13 +16,21 @@ import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.GridLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.layout.LayoutData;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.client.resources.I18n;
import org.lwjgl.input.Keyboard;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
//#if MC>=11300
//#else
//$$ import org.lwjgl.input.Keyboard;
//#endif
//#if MC>=10800
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
//#else
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//#endif
@@ -89,7 +97,11 @@ public class HotkeyButtons implements Extra {
// There doesn't seem to be an KeyBindingUpdate event, so we'll just update it every time
String keyName = "???";
try {
keyName = Keyboard.getKeyName(keyBinding.getKeyCode());
//#if MC>=11300
keyName = keyBinding.func_197978_k();
//#else
//$$ keyName = Keyboard.getKeyName(keyBinding.getKeyCode());
//#endif
} catch (ArrayIndexOutOfBoundsException e) {
// Apparently windows likes to press strange keys, see https://www.replaymod.com/forum/thread/55
}

View File

@@ -1,134 +0,0 @@
package com.replaymod.extras;
import com.google.common.collect.ImmutableSet;
import com.replaymod.compat.optifine.OptifineReflection;
import com.replaymod.core.ReplayMod;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.IResourcePack;
import net.minecraft.client.resources.data.IMetadataSection;
import net.minecraft.util.ResourceLocation;
import org.apache.commons.io.IOUtils;
//#if MC>=10904
import net.minecraft.client.resources.data.MetadataSerializer;
//#else
//$$ import net.minecraft.client.resources.data.IMetadataSerializer;
//#endif
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import static com.replaymod.extras.ReplayModExtras.LOGGER;
public class LocalizationExtra implements Extra {
private static final String ZIP_FILE_URL = "https://github.com/ReplayMod/Translations/archive/master.zip";
private static final String LANG_PREFIX = "Translations-master/";
@Override
public void register(ReplayMod mod) throws Exception {
final Minecraft mc = mod.getMinecraft();
if (Boolean.parseBoolean(System.getProperty("replaymod.offline", "false"))) {
return;
}
Thread localizedResourcePackLoader = new Thread(() -> {
try {
// Download zip of lang files
LOGGER.debug("Downloading languages from {}", ZIP_FILE_URL);
Map<String, byte[]> languages = new HashMap<>();
try (InputStream urlIn = new URL(ZIP_FILE_URL).openStream();
ZipInputStream in = new ZipInputStream(urlIn)) {
ZipEntry entry;
while ((entry = in.getNextEntry()) != null) {
String name = entry.getName();
if (!name.startsWith(LANG_PREFIX) || !name.endsWith(".lang")) {
continue;
}
name = name.substring(LANG_PREFIX.length());
languages.put(name, IOUtils.toByteArray(in));
LOGGER.debug("Added language file {}", name);
}
}
LOGGER.debug("Downloaded {} languages", languages.size());
// Add lang files as resource pack
mc.addScheduledTask(() -> {
@SuppressWarnings("unchecked")
List<IResourcePack> defaultResourcePacks = mc.defaultResourcePacks;
defaultResourcePacks.add(new LocalizedResourcePack(languages));
mc.getLanguageManager().onResourceManagerReload(mc.getResourceManager());
// Optifine does its own, additional language data loading
OptifineReflection.reloadLang();
LOGGER.debug("Added language files to resource packs and reloaded LanguageManager");
});
} catch (Throwable t) {
LOGGER.error("Loading localized resource pack:", t);
}
}, "localizedResourcePackLoader");
localizedResourcePackLoader.setDaemon(true);
localizedResourcePackLoader.start();
}
public static class LocalizedResourcePack implements IResourcePack {
private final Pattern LANG_PATTERN = Pattern.compile("^lang/([.+].lang)$");
private final Map<String, byte[]> languages;
public LocalizedResourcePack(Map<String, byte[]> languages) {
this.languages = languages;
}
@Override
public InputStream getInputStream(ResourceLocation loc) {
if (!"replaymod".equals(loc.getResourceDomain())) return null;
Matcher matcher = LANG_PATTERN.matcher(loc.getResourcePath());
if (matcher.matches()) {
byte[] bytes = languages.get(matcher.group());
if (bytes != null) {
return new ByteArrayInputStream(bytes);
}
}
return null;
}
@Override
public boolean resourceExists(ResourceLocation loc) {
// Assumes that getInputStream returns a ByteArrayInputStream that doesn't need to be closed
return getInputStream(loc) != null;
}
@Override
public Set<String> getResourceDomains() {
return ImmutableSet.of("replaymod");
}
//#if MC>=10904
@Override
public <T extends IMetadataSection> T getPackMetadata(MetadataSerializer metadataSerializer, String metadataSectionName) throws IOException {
//#else
//$$ @Override
//$$ public IMetadataSection getPackMetadata(IMetadataSerializer metadataSerializer, String metadataSectionName) throws IOException {
//#endif
return null;
}
@Override
public BufferedImage getPackImage() throws IOException {
return null;
}
@Override
public String getPackName() {
return "ReplayModLocalizationResourcePack";
}
}
}

View File

@@ -1,7 +1,7 @@
package com.replaymod.extras;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.Setting;
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;
@@ -16,11 +16,15 @@ import de.johni0702.minecraft.gui.popup.AbstractGuiPopup;
import de.johni0702.minecraft.gui.utils.Colors;
import org.apache.commons.io.FileUtils;
//#if MC>=11300
import net.minecraftforge.fml.ModList;
//#else
//#if MC>=10800
import net.minecraftforge.fml.common.Loader;
//$$ import net.minecraftforge.fml.common.Loader;
//#else
//$$ import cpw.mods.fml.common.Loader;
//#endif
//#endif
import javax.net.ssl.HttpsURLConnection;
import java.io.File;
@@ -34,17 +38,20 @@ 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/" + Loader.MC_VERSION;
private static final Setting<Boolean> ASK_FOR_OPEN_EYE = new Setting<>("advanced", "askForOpenEye", null, true);
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;
mod.getSettingsRegistry().register(ASK_FOR_OPEN_EYE);
if (!Loader.isModLoaded("OpenEye") && mod.getSettingsRegistry().get(ASK_FOR_OPEN_EYE)) {
//#if MC>=11300
boolean isOpenEyeLoaded = ModList.get().isLoaded("openeye");
//#else
//$$ boolean isOpenEyeLoaded = Loader.isModLoaded("OpenEye");
//#endif
if (!isOpenEyeLoaded && mod.getSettingsRegistry().get(Setting.ASK_FOR_OPEN_EYE)) {
new Thread(() -> {
try {
LOGGER.trace("Checking for OpenEye availability");
@@ -93,7 +100,7 @@ public class OpenEyeExtra implements Extra {
GuiPopup popup = new GuiPopup(OfferGui.this);
new Thread(() -> {
try {
File targetFile = new File(mod.getMinecraft().mcDataDir, "mods/" + Loader.MC_VERSION + "/OpenEye.jar");
File targetFile = new File(MCVer.mcDataDir(mod.getMinecraft()), "mods/" + ReplayMod.getMinecraftVersion() + "/OpenEye.jar");
FileUtils.forceMkdir(targetFile.getParentFile());
HttpsURLConnection connection = (HttpsURLConnection) new URL(DOWNLOAD_URL).openConnection();
@@ -112,7 +119,7 @@ public class OpenEyeExtra implements Extra {
}).start();
});
noButton.onClick(() -> {
mod.getSettingsRegistry().set(ASK_FOR_OPEN_EYE, false);
mod.getSettingsRegistry().set(Setting.ASK_FOR_OPEN_EYE, false);
mod.getSettingsRegistry().save();
parent.display();
});

View File

@@ -1,40 +1,22 @@
package com.replaymod.extras;
import com.replaymod.core.Module;
import com.replaymod.core.ReplayMod;
import com.replaymod.extras.advancedscreenshots.AdvancedScreenshots;
import com.replaymod.extras.playeroverview.PlayerOverview;
import com.replaymod.extras.urischeme.UriSchemeExtra;
import com.replaymod.extras.youtube.YoutubeUpload;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
//#if MC>=10800
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
//#else
//$$ import cpw.mods.fml.common.Mod;
//$$ import cpw.mods.fml.common.event.FMLInitializationEvent;
//$$ import cpw.mods.fml.common.event.FMLPreInitializationEvent;
//#endif
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Mod(modid = ReplayModExtras.MOD_ID,
version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*",
//#if MC>=10800
clientSideOnly = true,
//#endif
useMetadata = true)
public class ReplayModExtras {
public static final String MOD_ID = "replaymod-extras";
@Mod.Instance(MOD_ID)
public class ReplayModExtras implements Module {
{ instance = this; }
public static ReplayModExtras instance;
private static final List<Class<? extends Extra>> builtin = Arrays.asList(
@@ -44,22 +26,19 @@ public class ReplayModExtras {
YoutubeUpload.class,
FullBrightness.class,
HotkeyButtons.class,
LocalizationExtra.class,
OpenEyeExtra.class
);
private final Map<Class<? extends Extra>, Extra> instances = new HashMap<>();
public static Logger LOGGER;
public static Logger LOGGER = LogManager.getLogger();
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
LOGGER = event.getModLog();
ReplayMod.instance.getSettingsRegistry().register(Setting.class);
public ReplayModExtras(ReplayMod core) {
core.getSettingsRegistry().register(Setting.class);
}
@Mod.EventHandler
public void init(FMLInitializationEvent event) {
@Override
public void initClient() {
for (Class<? extends Extra> cls : builtin) {
try {
Extra extra = cls.newInstance();

View File

@@ -3,6 +3,8 @@ package com.replaymod.extras;
import com.replaymod.core.SettingsRegistry;
public final class Setting<T> {
public static final SettingsRegistry.SettingKey<Boolean> ASK_FOR_OPEN_EYE =
new SettingsRegistry.SettingKeys<>("advanced", "askForOpenEye", null, true);
public static final SettingsRegistry.SettingKey<Boolean> SKIP_POST_SCREENSHOT_GUI =
new SettingsRegistry.SettingKeys<>("advanced", "skipPostScreenshotGui", null, false);
}

View File

@@ -2,14 +2,22 @@ package com.replaymod.extras.advancedscreenshots;
import com.replaymod.core.ReplayMod;
import com.replaymod.extras.Extra;
import com.replaymod.replay.events.ReplayDispatchKeypressesEvent;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiControls;
import net.minecraftforge.common.MinecraftForge;
import org.lwjgl.input.Keyboard;
//#if MC<11300
//$$ import com.replaymod.core.versions.MCVer;
//$$ import com.replaymod.replay.events.ReplayDispatchKeypressesEvent;
//$$ import net.minecraft.client.Minecraft;
//$$ import net.minecraft.client.gui.GuiControls;
//$$ import net.minecraftforge.client.event.GuiScreenEvent;
//$$ import org.lwjgl.input.Keyboard;
//#endif
//#if MC>=10800
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#if MC>=11300
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
//#else
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//#endif
@@ -18,29 +26,36 @@ public class AdvancedScreenshots implements Extra {
private ReplayMod mod;
private final Minecraft mc = Minecraft.getMinecraft();
@Override
public void register(ReplayMod mod) throws Exception {
public void register(ReplayMod mod) {
this.mod = mod;
MinecraftForge.EVENT_BUS.register(this);
}
@SubscribeEvent
public void onDispatchKeypresses(ReplayDispatchKeypressesEvent.Pre event) {
int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() : Keyboard.getEventKey();
// all the conditions required to trigger a screenshot condensed in a single if statement
if (keyCode != 0 && !Keyboard.isRepeatEvent()
&& (!(mc.currentScreen instanceof GuiControls) || ((GuiControls) mc.currentScreen).time <= mc.getSystemTime() - 20L)
&& Keyboard.getEventKeyState()
&& keyCode == mc.gameSettings.keyBindScreenshot.getKeyCode()) {
ReplayMod.instance.runLater(() -> {
new GuiCreateScreenshot(mod).display();
});
event.setCanceled(true);
//#if MC>=11300
private static AdvancedScreenshots instance; { instance = this; }
public static void take() {
if (instance != null) {
instance.takeScreenshot();
}
}
//#else
//$$ @SubscribeEvent
//$$ public void onDispatchKeypresses(ReplayDispatchKeypressesEvent.Pre event) {
//$$ Minecraft mc = MCVer.getMinecraft();
//$$ if (mc.currentScreen instanceof GuiControls) return;
//$$ if (!Keyboard.getEventKeyState()) return;
//$$ if (Keyboard.isRepeatEvent()) return;
//$$ int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() : Keyboard.getEventKey();
//$$ if (keyCode == 0 || keyCode != mc.gameSettings.keyBindScreenshot.getKeyCode()) return;
//$$
//$$ takeScreenshot();
//$$
//$$ event.setCanceled(true);
//$$ }
//#endif
private void takeScreenshot() {
ReplayMod.instance.runLater(() -> new GuiCreateScreenshot(mod).display());
}
}

View File

@@ -1,6 +1,7 @@
package com.replaymod.extras.advancedscreenshots;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.RenderSettings;
import com.replaymod.render.gui.GuiRenderSettings;
import com.replaymod.replay.ReplayModReplay;
@@ -12,10 +13,9 @@ import de.johni0702.minecraft.gui.layout.GridLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout;
import net.minecraft.crash.CrashReport;
import net.minecraft.util.ScreenShotHelper;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import static com.replaymod.core.utils.Utils.error;
@@ -82,13 +82,12 @@ public class GuiCreateScreenshot extends GuiRenderSettings implements Loadable {
@Override
protected File generateOutputFile(RenderSettings.EncodingPreset encodingPreset) {
File screenshotFolder = new File(getMinecraft().mcDataDir, "screenshots");
File screenshotFolder = new File(MCVer.mcDataDir(getMinecraft()), "screenshots");
return ScreenShotHelper.getTimestampedPNGFileForDirectory(screenshotFolder);
}
@Override
protected Property getConfigProperty(Configuration configuration) {
return configuration.get("screenshotsettings", "settings", "{}",
"Last state of the screenshot settings GUI. Internal use only.");
protected Path getSettingsPath() {
return MCVer.mcDataDir(getMinecraft()).toPath().resolve("config/replaymod-screenshotsettings.json");
}
}

View File

@@ -12,7 +12,7 @@ import de.johni0702.minecraft.gui.element.GuiLabel;
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.popup.AbstractGuiPopup;
import org.lwjgl.util.ReadableColor;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableColor;
import java.awt.*;
import java.io.IOException;

View File

@@ -1,14 +1,15 @@
package com.replaymod.extras.advancedscreenshots;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.RenderSettings;
import com.replaymod.render.blend.BlendState;
import com.replaymod.render.capturer.RenderInfo;
import com.replaymod.render.rendering.Pipelines;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import lombok.RequiredArgsConstructor;
import net.minecraft.client.Minecraft;
import net.minecraft.crash.CrashReport;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
//#if MC>=10800
import com.replaymod.render.hooks.ChunkLoadingRenderGlobal;
@@ -17,7 +18,7 @@ import com.replaymod.render.hooks.ChunkLoadingRenderGlobal;
@RequiredArgsConstructor
public class ScreenshotRenderer implements RenderInfo {
private final Minecraft mc = Minecraft.getMinecraft();
private final Minecraft mc = MCVer.getMinecraft();
private final RenderSettings settings;
@@ -25,8 +26,13 @@ public class ScreenshotRenderer implements RenderInfo {
public boolean renderScreenshot() throws Throwable {
try {
int displayWidthBefore = mc.displayWidth;
int displayHeightBefore = mc.displayHeight;
//#if MC>=11300
int displayWidthBefore = mc.mainWindow.framebufferWidth;
int displayHeightBefore = mc.mainWindow.framebufferHeight;
//#else
//$$ int displayWidthBefore = mc.displayWidth;
//$$ int displayHeightBefore = mc.displayHeight;
//#endif
boolean hideGUIBefore = mc.gameSettings.hideGUI;
mc.gameSettings.hideGUI = true;
@@ -48,12 +54,18 @@ public class ScreenshotRenderer implements RenderInfo {
//#endif
mc.gameSettings.hideGUI = hideGUIBefore;
mc.resize(displayWidthBefore, displayHeightBefore);
//#if MC>=11300
mc.mainWindow.framebufferWidth = displayWidthBefore;
mc.mainWindow.framebufferHeight = displayHeightBefore;
mc.getFramebuffer().createBindFramebuffer(displayWidthBefore, displayHeightBefore);
//#else
//$$ mc.resize(displayWidthBefore, displayHeightBefore);
//#endif
return true;
} catch (OutOfMemoryError e) {
e.printStackTrace();
CrashReport report = CrashReport.makeCrashReport(e, "Creating Equirectangular Screenshot");
Minecraft.getMinecraft().crashed(report);
MCVer.getMinecraft().crashed(report);
}
return false;
}

View File

@@ -2,13 +2,13 @@ package com.replaymod.extras.advancedscreenshots;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.utils.Utils;
import com.replaymod.core.versions.MCVer;
import com.replaymod.extras.ReplayModExtras;
import com.replaymod.render.frame.RGBFrame;
import com.replaymod.render.rendering.FrameConsumer;
import com.replaymod.replay.ReplayModReplay;
import net.minecraft.client.Minecraft;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.crash.CrashReport;
import org.lwjgl.util.ReadableDimension;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
@@ -48,7 +48,7 @@ public class ScreenshotWriter implements FrameConsumer<RGBFrame> {
} catch (OutOfMemoryError e) {
e.printStackTrace();
CrashReport report = CrashReport.makeCrashReport(e, "Exporting frame");
Minecraft.getMinecraft().crashed(report);
MCVer.getMinecraft().crashed(report);
} catch (Throwable t) {
CrashReport report = CrashReport.makeCrashReport(t, "Exporting frame");

View File

@@ -11,11 +11,19 @@ import com.replaymod.replay.events.ReplayOpenEvent;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.client.event.RenderHandEvent;
import org.lwjgl.input.Keyboard;
//#if MC>=11300
//#else
//$$ import org.lwjgl.input.Keyboard;
//#endif
//#if MC>=10800
import com.google.common.base.Predicate;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
//#else
//$$ import cpw.mods.fml.common.eventhandler.EventPriority;
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;

View File

@@ -18,15 +18,13 @@ import de.johni0702.minecraft.gui.function.Closeable;
import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.utils.Colors;
import net.minecraft.client.audio.PositionedSoundRecord;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
//#if MC>=10904
import net.minecraft.init.MobEffects;
import net.minecraft.init.SoundEvents;
//#else
//$$ import net.minecraft.potion.Potion;
//#endif
@@ -55,30 +53,12 @@ public class PlayerOverviewGui extends GuiScreen implements Closeable {
public final GuiCheckbox checkAll = new GuiCheckbox(contentPanel){
@Override
public void onClick() {
//#if MC>=10904
getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(SoundEvents.UI_BUTTON_CLICK, 1.0F));
//#else
//#if MC>=10800
//$$ getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.create(BUTTON_SOUND, 1.0F));
//#else
//$$ getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.createPositionedSoundRecord(BUTTON_SOUND, 1.0F));
//#endif
//#endif
playersScrollable.forEach(IGuiCheckbox.class).setChecked(true);
}
}.setLabel("").setChecked(true).setTooltip(new GuiTooltip().setI18nText("replaymod.gui.playeroverview.showall"));
public final GuiCheckbox uncheckAll = new GuiCheckbox(contentPanel){
@Override
public void onClick() {
//#if MC>=10904
getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(SoundEvents.UI_BUTTON_CLICK, 1.0F));
//#else
//#if MC>=10800
//$$ getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.create(BUTTON_SOUND, 1.0F));
//#else
//$$ getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.createPositionedSoundRecord(BUTTON_SOUND, 1.0F));
//#endif
//#endif
playersScrollable.forEach(IGuiCheckbox.class).setChecked(false);
}
}.setLabel("").setChecked(false).setTooltip(new GuiTooltip().setI18nText("replaymod.gui.playeroverview.hideall"));
@@ -135,11 +115,15 @@ public class PlayerOverviewGui extends GuiScreen implements Closeable {
}
}.setSize(16, 16),
new GuiLabel().setText(
//#if MC>=11300
p.getName().getFormattedText()
//#else
//#if MC>=10800
p.getName()
//$$ p.getName()
//#else
//$$ p.getDisplayName()
//#endif
//#endif
).setColor(isSpectator(p) ? Colors.DKGREY : Colors.WHITE)
).onClick(new Runnable() {
@Override
@@ -196,11 +180,15 @@ public class PlayerOverviewGui extends GuiScreen implements Closeable {
public int compare(EntityPlayer o1, EntityPlayer o2) {
if (isSpectator(o1) && !isSpectator(o2)) return 1;
if (isSpectator(o2) && !isSpectator(o1)) return -1;
//#if MC>=11300
return o1.getName().getFormattedText().compareToIgnoreCase(o2.getName().getFormattedText());
//#else
//#if MC>=10800
return o1.getName().compareToIgnoreCase(o2.getName());
//$$ return o1.getName().compareToIgnoreCase(o2.getName());
//#else
//$$ return o1.getDisplayName().compareToIgnoreCase(o2.getDisplayName());
//#endif
//#endif
}
}
}

View File

@@ -1,6 +1,5 @@
package com.replaymod.extras.urischeme;
import com.replaymod.core.ReplayMod;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.StringBuilderWriter;
@@ -17,7 +16,7 @@ public class LinuxUriScheme extends UriScheme {
public void install() throws URISyntaxException, IOException {
File file = new File("replaymod.desktop");
File iconFile = new File("replaymod-icon.jpg");
String path = ReplayMod.getContainer().getSource().getAbsolutePath().replace("\\", "\\\\").replace("\"", "\\\"");
String path = findJarFile().getAbsolutePath().replace("\\", "\\\\").replace("\"", "\\\"");
String content =
"[Desktop Entry]\n" +
"Name=ReplayMod\n" +

View File

@@ -6,6 +6,9 @@ import javax.swing.*;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.CodeSource;
import java.util.Arrays;
public abstract class UriScheme {
@@ -82,4 +85,19 @@ public abstract class UriScheme {
}
public abstract void install() throws Exception;
File findJarFile() throws IOException {
CodeSource codeSource = UriScheme.class.getProtectionDomain().getCodeSource();
if (codeSource != null) {
URL location = codeSource.getLocation();
if (location != null) {
try {
return new File(location.toURI());
} catch (URISyntaxException e) {
throw new IOException(e);
}
}
}
throw new IOException("No jar file found. Is this a development environment?");
}
}

View File

@@ -1,6 +1,5 @@
package com.replaymod.extras.urischeme;
import com.replaymod.core.ReplayMod;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.StringBuilderWriter;
@@ -9,7 +8,7 @@ import java.io.IOException;
public class WindowsUriScheme extends UriScheme {
@Override
public void install() throws IOException, InterruptedException {
String path = ReplayMod.getContainer().getSource().getAbsolutePath().replace("\\", "\\\\").replace("\"", "\\\"");
String path = findJarFile().getAbsolutePath().replace("\\", "\\\\").replace("\"", "\\\"");
regAdd("\\replaymod /f /ve /d \"URL:replaymod Protocol\"");
regAdd("\\replaymod /f /v \"URL Protocol\" /d \"\"");
regAdd("\\replaymod\\shell\\open\\command /f /ve /d \"java -cp \\\"" + path + "\\\" " + UriScheme.class.getName() + " \\\"%1\\\"\"");

View File

@@ -18,12 +18,17 @@ import de.johni0702.minecraft.gui.element.advanced.GuiTextArea;
import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.popup.GuiFileChooserPopup;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import joptsimple.internal.Strings;
import lombok.RequiredArgsConstructor;
import net.minecraft.client.resources.I18n;
import org.apache.commons.io.IOUtils;
import org.lwjgl.Sys;
import org.lwjgl.util.ReadableDimension;
//#if MC>=11300
import net.minecraft.util.Util;
//#else
//$$ import org.lwjgl.Sys;
//#endif
import javax.annotation.Nullable;
import javax.imageio.ImageIO;
@@ -213,7 +218,11 @@ public class GuiYoutubeUpload extends GuiScreen {
try {
Desktop.getDesktop().browse(new URL(url).toURI());
} catch(Throwable throwable) {
Sys.openURL(url);
//#if MC>=11300
Util.getOSType().openURI(url);
//#else
//$$ Sys.openURL(url);
//#endif
}
upload = null;
progressBar.setLabel(I18n.format("replaymod.gui.ytuploadprogress.done", url));

View File

@@ -9,7 +9,11 @@ import net.minecraftforge.client.event.GuiScreenEvent;
import net.minecraftforge.common.MinecraftForge;
//#if MC>=10800
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
//#else
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//#endif

View File

@@ -21,8 +21,10 @@ import com.google.api.services.youtube.model.VideoSnippet;
import com.google.api.services.youtube.model.VideoStatus;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.io.Files;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.RenderSettings;
import com.replaymod.render.metadata.MetadataInjector;
import lombok.Getter;
@@ -41,8 +43,7 @@ import static com.replaymod.extras.ReplayModExtras.LOGGER;
public class YoutubeUploader {
private static final String CLIENT_ID = "743126594724-mfe7pj1k7e47uu5pk4503c8st9vj9ibu.apps.googleusercontent.com";
private static final String CLIENT_SECRET = "gMwcy3mRYCRamCIjJIYP7rqc";
private static final String FFMPEG_ODS =
"-i %s -vf scale=iw:iw*9/16,setdar=16:9 -c:v libx264 -preset slow -crf 16 %s";
private static final String FFMPEG_MP4 = "-i %s -c:v libx264 -preset slow -crf 16 %s";
private static final JsonFactory JSON_FACTORY = new GsonFactory();
private final NetHttpTransport httpTransport;
private final DataStoreFactory dataStoreFactory;
@@ -78,7 +79,7 @@ public class YoutubeUploader {
this.videoVisibility = videoVisibility;
this.videoSnippet = videoSnippet;
this.httpTransport = GoogleNetHttpTransport.newTrustedTransport();
this.dataStoreFactory = new FileDataStoreFactory(minecraft.mcDataDir);
this.dataStoreFactory = new FileDataStoreFactory(MCVer.mcDataDir(minecraft));
}
@@ -131,68 +132,73 @@ public class YoutubeUploader {
}
private File preUpload() throws InterruptedException, IOException {
if (settings.getRenderMethod() == RenderSettings.RenderMethod.ODS) {
File tmpFile = new File(videoFile.getParentFile(), System.currentTimeMillis() + ".mp4");
tmpFile.deleteOnExit();
File outputFile = videoFile;
String args = String.format(FFMPEG_ODS, videoFile.getName(), tmpFile.getName());
if (settings.getRenderMethod().isSpherical()) {
// inject spherical metadata for YouTube unless already done
CommandLine commandLine = new CommandLine(settings.getExportCommand());
commandLine.addArguments(args);
LOGGER.info("Re-encoding for ODS with {} {}", settings.getExportCommand(), args);
Process process = new ProcessBuilder(commandLine.toStrings()).directory(videoFile.getParentFile()).start();
boolean isMp4 = Files.getFileExtension(outputFile.getName()).equalsIgnoreCase("mp4");
final AtomicBoolean active = new AtomicBoolean(true);
final InputStream in = process.getErrorStream();
new Thread(() -> {
try {
StringBuilder sb = new StringBuilder();
while (active.get()) {
char c = (char) in.read();
if (c == '\r') {
String str = sb.toString();
LOGGER.debug("[FFmpeg] {}", str);
if (str.startsWith("frame=")) {
str = str.substring(6).trim();
str = str.substring(0, str.indexOf(' '));
double frame = Integer.parseInt(str);
progress = Suppliers.ofInstance(frame / videoFrames);
if (!isMp4) {
// convert non-mp4 videos into mp4 format to be able to inject metadata
outputFile = new File(outputFile.getParentFile(), System.currentTimeMillis() + ".mp4");
outputFile.deleteOnExit();
String args = String.format(FFMPEG_MP4, videoFile.getName(), outputFile.getName());
CommandLine commandLine = new CommandLine(settings.getExportCommandOrDefault());
commandLine.addArguments(args);
LOGGER.info("Re-encoding for metadata injection with {} {}", commandLine.getExecutable(), args);
Process process = new ProcessBuilder(commandLine.toStrings()).directory(outputFile.getParentFile()).start();
final AtomicBoolean active = new AtomicBoolean(true);
final InputStream in = process.getErrorStream();
new Thread(() -> {
try {
StringBuilder sb = new StringBuilder();
while (active.get()) {
char c = (char) in.read();
if (c == '\r') {
String str = sb.toString();
LOGGER.debug("[FFmpeg] {}", str);
if (str.startsWith("frame=")) {
str = str.substring(6).trim();
str = str.substring(0, str.indexOf(' '));
double frame = Integer.parseInt(str);
progress = Suppliers.ofInstance(frame / videoFrames);
}
sb = new StringBuilder();
} else {
sb.append(c);
}
sb = new StringBuilder();
} else {
sb.append(c);
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}).start();
int result;
try {
result = process.waitFor();
} catch (InterruptedException e) {
process.destroy();
throw e;
} finally {
active.set(false);
}
if (result != 0) {
throw new IOException("FFmpeg returned: " + result);
}
}).start();
int result;
try {
result = process.waitFor();
} catch (InterruptedException e) {
process.destroy();
throw e;
} finally {
active.set(false);
}
if (result != 0) {
throw new IOException("FFmpeg returned: " + result);
}
MetadataInjector.injectODSMetadata(tmpFile);
return tmpFile;
} else if (settings.getRenderMethod() == RenderSettings.RenderMethod.EQUIRECTANGULAR) {
// if metadata hasn't been injected before, inject it before the upload
if (!settings.isInject360Metadata()) {
MetadataInjector.inject360Metadata(videoFile);
if (!settings.isInjectSphericalMetadata() || !isMp4) {
MetadataInjector.injectMetadata(settings.getRenderMethod(), outputFile,
settings.getTargetVideoWidth(), settings.getTargetVideoHeight(),
settings.getSphericalFovX(), settings.getSphericalFovY());
}
}
return videoFile;
return outputFile;
}
private Video doUpload(YouTube youTube, File processedFile) throws IOException {

View File

@@ -1,6 +1,6 @@
package com.replaymod.online;
import net.minecraft.client.Minecraft;
import com.replaymod.core.versions.MCVer;
import java.util.Random;
@@ -9,7 +9,7 @@ public class AuthenticationHash {
private static final Random random = new Random();
public AuthenticationHash() {
username = Minecraft.getMinecraft().getSession().getUsername();
username = MCVer.getMinecraft().getSession().getUsername();
currentTime = System.currentTimeMillis();
randomLong = random.nextLong();
hash = getAuthenticationHash();

View File

@@ -1,63 +1,65 @@
package com.replaymod.online;
import com.replaymod.online.api.ApiClient;
import com.replaymod.online.api.AuthData;
import com.replaymod.online.api.replay.holders.AuthConfirmation;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
/**
* Auth data stored in a {@link Configuration}.
*/
public class ConfigurationAuthData implements AuthData {
private final Configuration config;
private String userName;
private String authKey;
public ConfigurationAuthData(Configuration config) {
this.config = config;
}
/**
* Loads the data from the configuration and checks for its validity.
* If the data is invalid, it is removed from the config.
* @param apiClient Api client used for validating the auth data
*/
public void load(ApiClient apiClient) {
Property property = config.get("authkey", "authkey", (String) null);
if (property != null) {
String authKey = property.getString();
AuthConfirmation result = apiClient.checkAuthkey(authKey);
if (result != null) {
this.authKey = authKey;
this.userName = result.getUsername();
} else {
setData(null, null);
}
}
}
@Override
public String getUserName() {
return userName;
}
@Override
public String getAuthKey() {
return authKey;
}
@Override
public void setData(String userName, String authKey) {
this.userName = userName;
this.authKey = authKey;
config.removeCategory(config.getCategory("authkey"));
if (authKey != null) {
// Note: .get() actually creates the entry with the default value if it doesn't exist
config.get("authkey", "authkey", authKey);
}
config.save();
}
}
//#if MC<11300
//$$ package com.replaymod.online;
//$$
//$$ import com.replaymod.online.api.ApiClient;
//$$ import com.replaymod.online.api.AuthData;
//$$ import com.replaymod.online.api.replay.holders.AuthConfirmation;
//$$ import net.minecraftforge.common.config.Configuration;
//$$ import net.minecraftforge.common.config.Property;
//$$
//$$ /**
//$$ * Auth data stored in a {@link Configuration}.
//$$ */
//$$ public class ConfigurationAuthData implements AuthData {
//$$
//$$ private final Configuration config;
//$$ private String userName;
//$$ private String authKey;
//$$
//$$ public ConfigurationAuthData(Configuration config) {
//$$ this.config = config;
//$$ }
//$$
//$$ /**
//$$ * Loads the data from the configuration and checks for its validity.
//$$ * If the data is invalid, it is removed from the config.
//$$ * @param apiClient Api client used for validating the auth data
//$$ */
//$$ public void load(ApiClient apiClient) {
//$$ Property property = config.get("authkey", "authkey", (String) null);
//$$ if (property != null) {
//$$ String authKey = property.getString();
//$$ AuthConfirmation result = apiClient.checkAuthkey(authKey);
//$$ if (result != null) {
//$$ this.authKey = authKey;
//$$ this.userName = result.getUsername();
//$$ } else {
//$$ setData(null, null);
//$$ }
//$$ }
//$$ }
//$$
//$$ @Override
//$$ public String getUserName() {
//$$ return userName;
//$$ }
//$$
//$$ @Override
//$$ public String getAuthKey() {
//$$ return authKey;
//$$ }
//$$
//$$ @Override
//$$ public void setData(String userName, String authKey) {
//$$ this.userName = userName;
//$$ this.authKey = authKey;
//$$
//$$ config.removeCategory(config.getCategory("authkey"));
//$$ if (authKey != null) {
//$$ // Note: .get() actually creates the entry with the default value if it doesn't exist
//$$ config.get("authkey", "authkey", authKey);
//$$ }
//$$ config.save();
//$$ }
//$$ }
//#endif

View File

@@ -0,0 +1,69 @@
package com.replaymod.online;
import com.replaymod.online.api.ApiClient;
import com.replaymod.online.api.AuthData;
import com.replaymod.online.api.replay.holders.AuthConfirmation;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
/**
* Auth data stored in a plain text file.
*/
public class PlainFileAuthData implements AuthData {
private final Path path;
private String userName;
private String authKey;
public PlainFileAuthData(Path path) {
this.path = path;
}
/**
* Loads the data from the JSON file and checks for its validity.
* If the data is invalid, the JSON file is removed.
* @param apiClient Api client used for validating the auth data
*/
public void load(ApiClient apiClient) throws IOException {
String authKey;
try {
authKey = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
} catch (NoSuchFileException | FileNotFoundException ignored) {
return;
}
AuthConfirmation result = apiClient.checkAuthkey(authKey);
if (result != null) {
this.authKey = authKey;
this.userName = result.getUsername();
} else {
Files.deleteIfExists(path);
}
}
@Override
public String getUserName() {
return userName;
}
@Override
public String getAuthKey() {
return authKey;
}
@Override
public void setData(String userName, String authKey) {
this.userName = userName;
this.authKey = authKey;
try {
Files.write(path, authKey.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE_NEW);
} catch (IOException e) {
ReplayModOnline.LOGGER.error("Saving auth data:", e);
}
}
}

View File

@@ -1,7 +1,10 @@
package com.replaymod.online;
import com.replaymod.core.Module;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.versions.MCVer;
import com.replaymod.online.api.ApiClient;
import com.replaymod.online.api.AuthData;
import com.replaymod.online.gui.GuiLoginPrompt;
import com.replaymod.online.gui.GuiReplayDownloading;
import com.replaymod.online.gui.GuiSaveModifiedReplay;
@@ -12,48 +15,36 @@ import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ZipReplayFile;
import com.replaymod.replaystudio.studio.ReplayStudio;
import de.johni0702.minecraft.gui.container.GuiScreen;
import net.minecraftforge.common.config.Configuration;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
//#if MC>=10800
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.common.config.Configuration;
//#if MC>=10800
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#else
//$$ import cpw.mods.fml.common.Mod;
//$$ import cpw.mods.fml.common.event.FMLInitializationEvent;
//$$ import cpw.mods.fml.common.event.FMLPostInitializationEvent;
//$$ import cpw.mods.fml.common.event.FMLPreInitializationEvent;
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//#endif
//#endif
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import static com.replaymod.core.versions.MCVer.*;
import static net.minecraft.client.Minecraft.getMinecraft;
@Mod(modid = ReplayModOnline.MOD_ID,
version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*",
//#if MC>=10800
clientSideOnly = true,
//#endif
useMetadata = true)
public class ReplayModOnline {
public static final String MOD_ID = "replaymod-online";
@Mod.Instance(MOD_ID)
public class ReplayModOnline implements Module {
{ instance = this; }
public static ReplayModOnline instance;
private ReplayMod core;
private ReplayModReplay replayModule;
public static Logger LOGGER;
public static Logger LOGGER = LogManager.getLogger();
private ApiClient apiClient;
@@ -64,22 +55,31 @@ public class ReplayModOnline {
*/
private File currentReplayOutputFile;
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
LOGGER = event.getModLog();
core = ReplayMod.instance;
replayModule = ReplayModReplay.instance;
public ReplayModOnline(ReplayMod core, ReplayModReplay replayModule) {
this.core = core;
this.replayModule = replayModule;
core.getSettingsRegistry().register(Setting.class);
Configuration config = new Configuration(event.getSuggestedConfigurationFile());
ConfigurationAuthData authData = new ConfigurationAuthData(config);
apiClient = new ApiClient(authData);
authData.load(apiClient);
}
@Mod.EventHandler
public void init(FMLInitializationEvent event) {
@Override
public void initClient() {
Path path = MCVer.mcDataDir(MCVer.getMinecraft()).toPath().resolve("config/replaymod-online.token");
PlainFileAuthData authData = new PlainFileAuthData(path);
apiClient = new ApiClient(authData);
if (Files.notExists(path)) {
AuthData oldAuthData = loadOldAuthData();
if (oldAuthData != null) {
authData.setData(oldAuthData.getUserName(), oldAuthData.getAuthKey());
}
} else {
try {
authData.load(apiClient);
} catch (IOException e) {
ReplayModOnline.LOGGER.error("Loading auth data:", e);
}
}
if (!getDownloadsFolder().exists()){
if (!getDownloadsFolder().mkdirs()) {
LOGGER.warn("Failed to create downloads folder: " + getDownloadsFolder());
@@ -88,10 +88,7 @@ public class ReplayModOnline {
new GuiHandler(this).register();
FML_BUS.register(this);
}
@Mod.EventHandler
public void postInit(FMLPostInitializationEvent event) {
// Initial login prompt
if (!core.getSettingsRegistry().get(Setting.SKIP_LOGIN_PROMPT)) {
if (!isLoggedIn()) {
@@ -103,6 +100,23 @@ public class ReplayModOnline {
}
}
/**
* Loads old auth data from the legacy Configuration system and stores it in the new json file.
* Always returns null on 1.13+ where the Configuration system has been removed.
*/
private AuthData loadOldAuthData() {
//#if MC<11300
//$$ Path path = MCVer.mcDataDir(MCVer.getMinecraft()).toPath().resolve("config/replaymod-online.cfg");
//$$ Configuration config = new Configuration(path.toFile());
//$$ ConfigurationAuthData authData = new ConfigurationAuthData(config);
//$$ authData.load(new ApiClient(authData));
//$$ if (authData.getAuthKey() != null) {
//$$ return authData;
//$$ }
//#endif
return null;
}
public ReplayMod getCore() {
return core;
}
@@ -125,7 +139,7 @@ public class ReplayModOnline {
public File getDownloadsFolder() {
String path = core.getSettingsRegistry().get(Setting.DOWNLOAD_PATH);
return new File(path.startsWith("./") ? getMinecraft().mcDataDir : null, path);
return new File(path.startsWith("./") ? mcDataDir(getMinecraft()) : null, path);
}
public File getDownloadedFile(int id) {

View File

@@ -6,6 +6,7 @@ import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.mojang.authlib.exceptions.AuthenticationException;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.versions.MCVer;
import com.replaymod.online.AuthenticationHash;
import com.replaymod.online.api.replay.ReplayModApiMethods;
import com.replaymod.online.api.replay.SearchQuery;
@@ -30,7 +31,7 @@ import static com.replaymod.core.utils.Utils.SSL_SOCKET_FACTORY;
public class ApiClient {
private static final Minecraft mc = Minecraft.getMinecraft();
private static final Minecraft mc = MCVer.getMinecraft();
private static final Gson gson = new Gson();
private static final JsonParser jsonParser = new JsonParser();

View File

@@ -9,7 +9,8 @@ public enum MinecraftVersion {
MC_1_11_2("Minecraft 1.11.2", "1.11.2"),
MC_1_12("Minecraft 1.12", "1.12"),
MC_1_12_1("Minecraft 1.12.1", "1.12.1"),
MC_1_12_2("Minecraft 1.12.2", "1.12.2");
MC_1_12_2("Minecraft 1.12.2", "1.12.2"),
MC_1_13_2("Minecraft 1.13.2", "1.13.2");
private String niceName, apiName;

View File

@@ -1,7 +1,6 @@
package com.replaymod.online.gui;
import com.mojang.authlib.exceptions.AuthenticationException;
import com.replaymod.core.versions.MCVer;
import com.replaymod.online.api.ApiClient;
import com.replaymod.online.api.ApiException;
import de.johni0702.minecraft.gui.container.AbstractGuiScreen;
@@ -13,9 +12,9 @@ import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.utils.Consumers;
import de.johni0702.minecraft.gui.utils.Utils;
import com.replaymod.core.utils.Patterns;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableColor;
import net.minecraft.client.gui.FontRenderer;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableColor;
import static com.replaymod.core.versions.MCVer.*;

View File

@@ -37,9 +37,9 @@ import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.popup.GuiYesNoPopup;
import de.johni0702.minecraft.gui.utils.Colors;
import de.johni0702.minecraft.gui.utils.Consumer;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import org.apache.commons.lang3.StringUtils;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
import java.awt.image.BufferedImage;
import java.io.IOException;
@@ -462,7 +462,7 @@ public class GuiReplayCenter extends GuiScreen {
@Override
public ReadableDimension calcMinSize(GuiContainer<?> container) {
return new org.lwjgl.util.Dimension(300, thumbnail.getMinSize().getHeight());
return new Dimension(300, thumbnail.getMinSize().getHeight());
}
});
}

View File

@@ -15,9 +15,14 @@ import de.johni0702.minecraft.gui.function.Typeable;
import de.johni0702.minecraft.gui.layout.GridLayout;
import de.johni0702.minecraft.gui.popup.AbstractGuiPopup;
import de.johni0702.minecraft.gui.utils.Colors;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadablePoint;
import net.minecraft.client.resources.I18n;
import org.lwjgl.input.Keyboard;
import org.lwjgl.util.ReadablePoint;
//#if MC>=11300
import com.replaymod.core.versions.MCVer.Keyboard;
//#else
//$$ import org.lwjgl.input.Keyboard;
//#endif
import java.util.ArrayList;
import java.util.List;

View File

@@ -33,13 +33,16 @@ import de.johni0702.minecraft.gui.popup.AbstractGuiPopup;
import de.johni0702.minecraft.gui.popup.GuiYesNoPopup;
import de.johni0702.minecraft.gui.utils.Colors;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.crash.CrashReport;
import net.minecraft.util.ReportedException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
//#if MC>=11300
//#else
//$$ import net.minecraft.client.settings.GameSettings;
//#endif
import javax.annotation.Nullable;
import java.awt.image.BufferedImage;
import java.io.File;
@@ -47,6 +50,7 @@ import java.io.IOException;
import java.util.Set;
import java.util.stream.Collectors;
import static com.replaymod.core.versions.MCVer.newReportedException;
import static java.util.Arrays.stream;
public class GuiUploadReplay extends GuiScreen {
@@ -130,7 +134,7 @@ public class GuiUploadReplay extends GuiScreen {
metaData = replayFile.getMetaData();
optThumbnail = replayFile.getThumb();
} catch (IOException e) {
throw new ReportedException(CrashReport.makeCrashReport(e, "Read replay file " + file.getName()));
throw newReportedException(CrashReport.makeCrashReport(e, "Read replay file " + file.getName()));
}
// Apply to gui
@@ -147,7 +151,11 @@ public class GuiUploadReplay extends GuiScreen {
// Get name of key used for thumbnail creation
KeyBindingRegistry registry = mod.getCore().getKeyBindingRegistry();
KeyBinding keyBinding = registry.getKeyBindings().get("replaymod.input.thumbnail");
String keyName = keyBinding == null ? "???" : GameSettings.getKeyDisplayString(keyBinding.getKeyCode());
//#if MC>=11300
String keyName = keyBinding == null ? "???" : keyBinding.func_197978_k();
//#else
//$$ String keyName = keyBinding == null ? "???" : GameSettings.getKeyDisplayString(keyBinding.getKeyCode());
//#endif
// No thumbnail, show default thumbnail and hint on how to create one
thumbnail.setTexture(Utils.DEFAULT_THUMBNAIL);

View File

@@ -15,7 +15,12 @@ import net.minecraft.client.resources.I18n;
import net.minecraftforge.client.event.GuiScreenEvent;
//#if MC>=10800
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
import java.util.ArrayList;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
//#else
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//#endif
@@ -44,9 +49,21 @@ public class GuiHandler {
return;
}
GuiButton button = new GuiButton(BUTTON_REPLAY_CENTER, getGui(event).width / 2 - 100,
getGui(event).height / 4 + 10 + 4 * 24, I18n.format("replaymod.gui.replaycenter"));
getButtonList(event).add(button);
GuiButton button = new GuiButton(
BUTTON_REPLAY_CENTER,
getGui(event).width / 2 + 2,
getGui(event).height / 4 + 10 + 4 * 24,
I18n.format("replaymod.gui.replaycenter")
) {
//#if MC>=11300
@Override
public void onClick(double mouseX, double mouseY) {
onButton(new GuiScreenEvent.ActionPerformedEvent.Pre(getGui(event), this, new ArrayList<>()));
}
//#endif
};
button.width = button.width / 2 - 2;
addButton(event, button);
}
@SubscribeEvent
@@ -57,22 +74,15 @@ public class GuiHandler {
}
final GuiReplayViewer replayViewer = (GuiReplayViewer) guiScreen;
// Inject Upload button
for (GuiElement element : replayViewer.replayButtonPanel.getChildren()) {
if (element instanceof GuiPanel && (((GuiPanel) element).getChildren().isEmpty())) {
new de.johni0702.minecraft.gui.element.GuiButton((GuiPanel) element).onClick(new Runnable() {
@Override
public void run() {
File replayFile = replayViewer.list.getSelected().file;
GuiUploadReplay uploadGui = new GuiUploadReplay(replayViewer, mod, replayFile);
if (mod.isLoggedIn()) {
uploadGui.display();
} else {
new GuiLoginPrompt(mod.getApiClient(), replayViewer, uploadGui, true);
}
}
}).setSize(73, 20).setI18nLabel("replaymod.gui.upload").setDisabled();
replayViewer.replaySpecificButtons.add(new de.johni0702.minecraft.gui.element.GuiButton(replayViewer.uploadButton).onClick(() -> {
File replayFile = replayViewer.list.getSelected().file;
GuiUploadReplay uploadGui = new GuiUploadReplay(replayViewer, mod, replayFile);
if (mod.isLoggedIn()) {
uploadGui.display();
} else {
new GuiLoginPrompt(mod.getApiClient(), replayViewer, uploadGui, true);
}
}
}).setSize(73, 20).setI18nLabel("replaymod.gui.upload").setDisabled());
}
@SubscribeEvent

View File

@@ -28,8 +28,8 @@ import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.popup.GuiYesNoPopup;
import de.johni0702.minecraft.gui.utils.Colors;
import de.johni0702.minecraft.gui.utils.Consumer;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import java.io.IOException;
import java.util.LinkedHashMap;
@@ -229,6 +229,7 @@ public class GuiKeyframeRepository extends GuiScreen implements Closeable {
timelines.putAll(replayFile.getTimelines(registry));
for (Map.Entry<String, Timeline> entry : timelines.entrySet()) {
if (entry.getKey().isEmpty()) continue; // don't show auto-save slot
list.getListPanel().addElements(null, new Entry(entry.getKey()));
}
}

View File

@@ -14,7 +14,11 @@ import com.replaymod.replaystudio.pathing.path.Timeline;
import net.minecraft.client.Minecraft;
//#if MC>=10800
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
//#else
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//#endif
@@ -28,7 +32,7 @@ import static com.replaymod.core.versions.MCVer.*;
* Plays a timeline.
*/
public abstract class AbstractTimelinePlayer {
private final Minecraft mc = Minecraft.getMinecraft();
private final Minecraft mc = getMinecraft();
private final ReplayHandler replayHandler;
private Timeline timeline;
protected long startOffset;

View File

@@ -4,7 +4,11 @@ import com.replaymod.core.utils.WrappedTimer;
import net.minecraft.util.Timer;
//#if MC>=10800
import net.minecraftforge.fml.common.eventhandler.Event;
//#if MC>=11300
import net.minecraftforge.eventbus.api.Event;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.Event;
//#endif
//#else
//$$ import cpw.mods.fml.common.eventhandler.Event;
//#endif
@@ -15,16 +19,28 @@ import static com.replaymod.core.versions.MCVer.*;
* Wrapper around the current timer that prevents the timer from advancing by itself.
*/
public class ReplayTimer extends WrappedTimer {
private final Timer state = new Timer(0);
//#if MC>=11300
private final Timer state = new Timer(0, 0);
//#else
//$$ private final Timer state = new Timer(0);
//#endif
public ReplayTimer(Timer wrapped) {
super(wrapped);
}
@Override
public void updateTimer() {
public void updateTimer(
//#if MC>=11300
long sysClock
//#endif
) {
copy(this, state); // Save our current state
super.updateTimer(); // Update current state
wrapped.updateTimer(
//#if MC>=11300
sysClock
//#endif
); // Update current state
copy(state, this); // Restore our old state
FML_BUS.post(new UpdatedEvent());
}

View File

@@ -1,85 +1,99 @@
package com.replaymod.recording;
import com.replaymod.core.KeyBindingRegistry;
import com.replaymod.core.Module;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.utils.Restrictions;
import com.replaymod.recording.handler.ConnectionEventHandler;
import com.replaymod.recording.handler.GuiHandler;
import com.replaymod.recording.packet.PacketListener;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandler;
import io.netty.util.AttributeKey;
import net.minecraft.network.NetworkManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.input.Keyboard;
//#if MC>=11300
import com.replaymod.core.versions.MCVer.Keyboard;
//#else
//$$ import org.lwjgl.input.Keyboard;
//#endif
//#if MC>=10800
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.EventBus;
import net.minecraftforge.fml.common.network.NetworkRegistry;
//#if MC>=11300
import net.minecraftforge.fml.network.NetworkRegistry;
//#else
//$$ import net.minecraftforge.fml.common.network.NetworkRegistry;
//#endif
//#else
//$$ import cpw.mods.fml.common.Mod;
//$$ import cpw.mods.fml.common.event.FMLInitializationEvent;
//$$ import cpw.mods.fml.common.event.FMLPreInitializationEvent;
//$$ import cpw.mods.fml.common.eventhandler.EventBus;
//$$ import cpw.mods.fml.common.network.NetworkRegistry;
//#endif
import static com.replaymod.core.versions.MCVer.*;
@Mod(modid = ReplayModRecording.MOD_ID,
version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*",
//#if MC>=10800
clientSideOnly = true,
//#endif
useMetadata = true)
public class ReplayModRecording {
public static final String MOD_ID = "replaymod-recording";
public class ReplayModRecording implements Module {
@Mod.Instance(MOD_ID)
private static final Logger LOGGER = LogManager.getLogger();
//#if MC>=11300
private static final AttributeKey<Void> ATTR_CHECKED = AttributeKey.newInstance("ReplayModRecording_checked");
//#endif
{ instance = this; }
public static ReplayModRecording instance;
private ReplayMod core;
private Logger logger;
private ConnectionEventHandler connectionEventHandler;
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
logger = event.getModLog();
core = ReplayMod.instance;
public ReplayModRecording(ReplayMod mod) {
core = mod;
core.getSettingsRegistry().register(Setting.class);
}
core.getKeyBindingRegistry().registerKeyBinding("replaymod.input.marker", Keyboard.KEY_M, new Runnable() {
@Override
public void registerKeyBindings(KeyBindingRegistry registry) {
registry.registerKeyBinding("replaymod.input.marker", Keyboard.KEY_M, new Runnable() {
@Override
public void run() {
PacketListener packetListener = connectionEventHandler.getPacketListener();
if (packetListener != null) {
packetListener.addMarker();
packetListener.addMarker(null);
core.printInfoToChat("replaymod.chat.addedmarker");
}
}
});
}
@Mod.EventHandler
public void init(FMLInitializationEvent event) {
EventBus bus = FML_BUS;
bus.register(connectionEventHandler = new ConnectionEventHandler(logger, core));
@Override
public void initClient() {
FML_BUS.register(connectionEventHandler = new ConnectionEventHandler(LOGGER, core));
new GuiHandler(core).register();
NetworkRegistry.INSTANCE.newChannel(Restrictions.PLUGIN_CHANNEL, new RestrictionsChannelHandler());
//#if MC>=11300
NetworkRegistry.newEventChannel(Restrictions.PLUGIN_CHANNEL, () -> "0", any -> true, any -> true);
//#else
//$$ NetworkRegistry.INSTANCE.newChannel(Restrictions.PLUGIN_CHANNEL, new RestrictionsChannelHandler());
//#endif
}
@ChannelHandler.Sharable
private static class RestrictionsChannelHandler extends ChannelDuplexHandler {}
public void initiateRecording(NetworkManager networkManager) {
Channel channel = networkManager.channel();
if (channel.pipeline().get("ReplayModReplay_replaySender") != null) return;
//#if MC>=11300
if (channel.hasAttr(ATTR_CHECKED)) return;
channel.attr(ATTR_CHECKED).set(null);
//#endif
connectionEventHandler.onConnectedToServerEvent(networkManager);
}
public ConnectionEventHandler getConnectionEventHandler() {
return connectionEventHandler;
}
}

View File

@@ -6,12 +6,14 @@ public final class Setting<T> extends SettingsRegistry.SettingKeys<T> {
public static final Setting<Boolean> RECORD_SINGLEPLAYER = make("recordSingleplayer", "recordsingleplayer", true);
public static final Setting<Boolean> RECORD_SERVER = make("recordServer", "recordserver", true);
public static final Setting<Boolean> INDICATOR = make("indicator", "indicator", true);
public static final Setting<Boolean> AUTO_START_RECORDING = make("autoStartRecording", "autostartrecording", true);
public static final Setting<Boolean> AUTO_POST_PROCESS = make("autoPostProcess", null, true);
private static <T> Setting<T> make(String key, String displayName, T defaultValue) {
return new Setting<>(key, displayName, defaultValue);
}
public Setting(String key, String displayString, T defaultValue) {
super("recording", key, "replaymod.gui.settings." + displayString, defaultValue);
super("recording", key, displayString == null ? null : "replaymod.gui.settings." + displayString, defaultValue);
}
}

View File

@@ -0,0 +1,110 @@
package com.replaymod.recording.gui;
import com.replaymod.core.ReplayMod;
import com.replaymod.editor.gui.MarkerProcessor;
import com.replaymod.recording.Setting;
import com.replaymod.recording.packet.PacketListener;
import de.johni0702.minecraft.gui.container.GuiPanel;
import de.johni0702.minecraft.gui.container.GuiScreen;
import de.johni0702.minecraft.gui.container.VanillaGuiScreen;
import de.johni0702.minecraft.gui.element.GuiButton;
import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import net.minecraft.client.gui.GuiIngameMenu;
import net.minecraftforge.client.event.GuiScreenEvent;
import net.minecraftforge.common.MinecraftForge;
//#if MC>=10800
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
//#else
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//#endif
import static com.replaymod.core.versions.MCVer.getGui;
public class GuiRecordingControls {
private ReplayMod core;
private PacketListener packetListener;
private boolean paused;
private boolean stopped;
private GuiPanel panel = new GuiPanel().setLayout(new HorizontalLayout().setSpacing(4));
private GuiButton buttonPauseResume = new GuiButton(panel).onClick(() -> {
if (paused) {
packetListener.addMarker(MarkerProcessor.MARKER_NAME_END_CUT);
} else {
packetListener.addMarker(MarkerProcessor.MARKER_NAME_START_CUT);
}
paused = !paused;
updateState();
}).setSize(98, 20);
private GuiButton buttonStartStop = new GuiButton(panel).onClick(() -> {
if (stopped) {
paused = false;
packetListener.addMarker(MarkerProcessor.MARKER_NAME_END_CUT);
core.printInfoToChat("replaymod.chat.recordingstarted");
} else {
int timestamp = (int) packetListener.getCurrentDuration();
if (!paused) {
packetListener.addMarker(MarkerProcessor.MARKER_NAME_START_CUT, timestamp);
}
packetListener.addMarker(MarkerProcessor.MARKER_NAME_SPLIT, timestamp + 1);
}
stopped = !stopped;
updateState();
}).setSize(98, 20);
public GuiRecordingControls(ReplayMod core, PacketListener packetListener) {
this.core = core;
this.packetListener = packetListener;
paused = stopped = !core.getSettingsRegistry().get(Setting.AUTO_START_RECORDING);
updateState();
}
public void register() {
MinecraftForge.EVENT_BUS.register(this);
}
public void unregister() {
MinecraftForge.EVENT_BUS.unregister(this);
}
@SubscribeEvent
public void onGuiInit(GuiScreenEvent.InitGuiEvent.Post event) {
if (getGui(event) instanceof GuiIngameMenu) {
show((GuiIngameMenu) getGui(event));
}
}
private void updateState() {
buttonPauseResume.setI18nLabel("replaymod.gui.recording." + (paused ? "resume" : "pause"));
buttonStartStop.setI18nLabel("replaymod.gui.recording." + (stopped ? "start" : "stop"));
buttonPauseResume.setEnabled(!stopped);
}
public void show(GuiIngameMenu gui) {
VanillaGuiScreen.setup(gui).setLayout(new CustomLayout<GuiScreen>() {
@Override
protected void layout(GuiScreen container, int width, int height) {
pos(panel, width / 2 - 100, height / 4 + 128);
}
}).addElements(null, panel);
}
public boolean isPaused() {
return paused;
}
public boolean isStopped() {
return stopped;
}
}

View File

@@ -10,10 +10,15 @@ import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.common.MinecraftForge;
//#if MC>=10800
import net.minecraft.client.renderer.GlStateManager;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
import static net.minecraft.client.renderer.GlStateManager.*;
//#else
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//$$ import static com.replaymod.core.versions.MCVer.GlStateManager.*;
//#endif
import static com.replaymod.core.ReplayMod.TEXTURE;
@@ -26,10 +31,12 @@ import static com.replaymod.core.versions.MCVer.*;
public class GuiRecordingOverlay {
private final Minecraft mc;
private final SettingsRegistry settingsRegistry;
private final GuiRecordingControls guiControls;
public GuiRecordingOverlay(Minecraft mc, SettingsRegistry settingsRegistry) {
public GuiRecordingOverlay(Minecraft mc, SettingsRegistry settingsRegistry, GuiRecordingControls guiControls) {
this.mc = mc;
this.settingsRegistry = settingsRegistry;
this.guiControls = guiControls;
}
public void register() {
@@ -47,12 +54,14 @@ public class GuiRecordingOverlay {
@SubscribeEvent
public void renderRecordingIndicator(RenderGameOverlayEvent.Post event) {
if (getType(event) != RenderGameOverlayEvent.ElementType.ALL) return;
if (guiControls.isStopped()) return;
if (settingsRegistry.get(Setting.INDICATOR)) {
FontRenderer fontRenderer = getFontRenderer(mc);
fontRenderer.drawString(I18n.format("replaymod.gui.recording").toUpperCase(), 30, 18 - (fontRenderer.FONT_HEIGHT / 2), 0xffffffff);
mc.renderEngine.bindTexture(TEXTURE);
GlStateManager.resetColor();
GlStateManager.enableAlpha();
String text = guiControls.isPaused() ? I18n.format("replaymod.gui.paused") : I18n.format("replaymod.gui.recording");
fontRenderer.drawString(text.toUpperCase(), 30, 18 - (fontRenderer.FONT_HEIGHT / 2), 0xffffffff);
bindTexture(TEXTURE);
resetColor();
enableAlpha();
Gui.drawModalRectWithCustomSizedTexture(10, 10, 58, 20, 16, 16, TEXTURE_SIZE, TEXTURE_SIZE);
}
}

View File

@@ -3,7 +3,9 @@ package com.replaymod.recording.handler;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.utils.ModCompat;
import com.replaymod.core.utils.Utils;
import com.replaymod.editor.gui.MarkerProcessor;
import com.replaymod.recording.Setting;
import com.replaymod.recording.gui.GuiRecordingControls;
import com.replaymod.recording.gui.GuiRecordingOverlay;
import com.replaymod.recording.packet.PacketListener;
import com.replaymod.replaystudio.replay.ReplayFile;
@@ -15,19 +17,19 @@ import net.minecraft.network.NetworkManager;
import org.apache.logging.log4j.Logger;
//#if MC>=10800
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientDisconnectionFromServerEvent;
//#if MC>=11300
import net.minecraft.world.dimension.DimensionType;
//#endif
import static com.replaymod.core.versions.MCVer.WorldType_DEBUG_ALL_BLOCK_STATES;
//#else
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//$$ import cpw.mods.fml.common.network.FMLNetworkEvent.ClientDisconnectionFromServerEvent;
//#endif
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import static com.replaymod.core.versions.MCVer.getMinecraft;
/**
* Handles connection events and initiates recording if enabled.
*/
@@ -36,7 +38,7 @@ public class ConnectionEventHandler {
private static final String packetHandlerKey = "packet_handler";
private static final String DATE_FORMAT = "yyyy_MM_dd_HH_mm_ss";
private static final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
private static final Minecraft mc = Minecraft.getMinecraft();
private static final Minecraft mc = getMinecraft();
private final Logger logger;
private final ReplayMod core;
@@ -44,6 +46,7 @@ public class ConnectionEventHandler {
private RecordingEventHandler recordingEventHandler;
private PacketListener packetListener;
private GuiRecordingOverlay guiOverlay;
private GuiRecordingControls guiControls;
public ConnectionEventHandler(Logger logger, ReplayMod core) {
this.logger = logger;
@@ -55,7 +58,11 @@ public class ConnectionEventHandler {
boolean local = networkManager.isLocalChannel();
if (local) {
//#if MC>=10800
if (mc.getIntegratedServer().getEntityWorld().getWorldType() == WorldType_DEBUG_ALL_BLOCK_STATES) {
//#if MC>=11300
if (mc.getIntegratedServer().getWorld(DimensionType.OVERWORLD).getWorldType() == WorldType_DEBUG_ALL_BLOCK_STATES) {
//#else
//$$ if (mc.getIntegratedServer().getEntityWorld().getWorldType() == WorldType_DEBUG_ALL_BLOCK_STATES) {
//#endif
logger.info("Debug World recording is not supported.");
return;
}
@@ -74,10 +81,10 @@ public class ConnectionEventHandler {
String worldName;
if (local) {
worldName = mc.getIntegratedServer().getWorldName();
} else if (Minecraft.getMinecraft().getCurrentServerData() != null) {
worldName = Minecraft.getMinecraft().getCurrentServerData().serverIP;
} else if (mc.getCurrentServerData() != null) {
worldName = mc.getCurrentServerData().serverIP;
//#if MC>=11100
} else if (Minecraft.getMinecraft().isConnectedToRealms()) {
} else if (mc.isConnectedToRealms()) {
// we can't access the server name without tapping too deep in the Realms Library
worldName = "A Realms Server";
//#endif
@@ -97,28 +104,36 @@ public class ConnectionEventHandler {
ReplayMetaData metaData = new ReplayMetaData();
metaData.setSingleplayer(local);
metaData.setServerName(worldName);
metaData.setGenerator("ReplayMod v" + ReplayMod.getContainer().getVersion());
metaData.setGenerator("ReplayMod v" + ReplayMod.instance.getVersion());
metaData.setDate(System.currentTimeMillis());
metaData.setMcVersion(ReplayMod.getMinecraftVersion());
packetListener = new PacketListener(replayFile, metaData);
packetListener = new PacketListener(core, currentFile.toPath(), replayFile, metaData);
networkManager.channel().pipeline().addBefore(packetHandlerKey, "replay_recorder", packetListener);
recordingEventHandler = new RecordingEventHandler(packetListener);
recordingEventHandler.register();
guiOverlay = new GuiRecordingOverlay(mc, core.getSettingsRegistry());
guiControls = new GuiRecordingControls(core, packetListener);
guiControls.register();
guiOverlay = new GuiRecordingOverlay(mc, core.getSettingsRegistry(), guiControls);
guiOverlay.register();
core.printInfoToChat("replaymod.chat.recordingstarted");
if (core.getSettingsRegistry().get(Setting.AUTO_START_RECORDING)) {
core.printInfoToChat("replaymod.chat.recordingstarted");
} else {
packetListener.addMarker(MarkerProcessor.MARKER_NAME_START_CUT, 0);
}
} catch (Throwable e) {
e.printStackTrace();
core.printWarningToChat("replaymod.chat.recordingfailed");
}
}
@SubscribeEvent
public void onDisconnectedFromServerEvent(ClientDisconnectionFromServerEvent event) {
public void reset() {
if (packetListener != null) {
guiControls.unregister();
guiControls = null;
guiOverlay.unregister();
guiOverlay = null;
recordingEventHandler.unregister();

View File

@@ -1,34 +1,36 @@
package com.replaymod.recording.handler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
//#if MC<11300
//$$ package com.replaymod.recording.handler;
//$$
//$$ import io.netty.channel.ChannelHandlerContext;
//$$ import io.netty.channel.SimpleChannelInboundHandler;
//$$
//#if MC>=10800
import net.minecraftforge.fml.common.network.handshake.FMLHandshakeMessage;
//$$ import net.minecraftforge.fml.common.network.handshake.FMLHandshakeMessage;
//#else
//$$ import cpw.mods.fml.common.network.handshake.FMLHandshakeMessage;
//#endif
/**
* 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 {
//$$
//$$ /**
//$$ * 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)) {
//$$ if (!(msg instanceof FMLHandshakeMessage.RegistryData)) {
//#else
//$$ if (!(msg instanceof FMLHandshakeMessage.ModIdData)) {
//#endif
// Pass on everything but RegistryData messages
ctx.fireChannelRead(msg);
}
}
}
//$$ // Pass on everything but RegistryData messages
//$$ ctx.fireChannelRead(msg);
//$$ }
//$$ }
//$$ }
//#endif

View File

@@ -17,7 +17,11 @@ import net.minecraftforge.client.event.GuiScreenEvent;
import net.minecraftforge.common.MinecraftForge;
//#if MC>=10800
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
//#else
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//#endif

View File

@@ -7,11 +7,15 @@ import net.minecraft.item.ItemStack;
import net.minecraft.network.Packet;
import net.minecraft.network.play.server.*;
import net.minecraft.server.integrated.IntegratedServer;
import net.minecraftforge.event.entity.minecart.MinecartInteractEvent;
// FIXME not (yet?) 1.13 import net.minecraftforge.event.entity.minecart.MinecartInteractEvent;
import net.minecraftforge.event.entity.player.PlayerSleepInBedEvent;
//#if MC>=10904
import net.minecraft.entity.EntityLiving;
//#if MC>=11300
import net.minecraft.entity.EntityLivingBase;
//#else
//$$ import net.minecraft.entity.EntityLiving;
//#endif
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.util.EnumHand;
@@ -25,7 +29,11 @@ import net.minecraft.util.math.BlockPos;
//#endif
//#if MC>=10800
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
import net.minecraftforge.fml.common.gameevent.PlayerEvent.ItemPickupEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.PlayerTickEvent;
@@ -42,7 +50,7 @@ import static com.replaymod.core.versions.MCVer.*;
public class RecordingEventHandler {
private final Minecraft mc = Minecraft.getMinecraft();
private final Minecraft mc = getMinecraft();
private final PacketListener packetListener;
private Double lastX, lastY, lastZ;
@@ -75,6 +83,12 @@ public class RecordingEventHandler {
}
}
//#if MC>=11300
public void onPacket(Packet<?> packet) {
packetListener.save(packet);
}
//#endif
public void onPlayerJoin() {
try {
//#if MC>=10904
@@ -171,9 +185,15 @@ public class RecordingEventHandler {
byte newPitch = (byte) ((int) (e.player.rotationPitch * 256.0F / 360.0F));
//#if MC>=10904
packet = new SPacketEntity.S17PacketEntityLookMove(e.player.getEntityId(),
//#if MC>=11300
packet = new SPacketEntity.Move(
//#else
//$$ packet = new SPacketEntity.S17PacketEntityLookMove(
//#endif
e.player.getEntityId(),
(short) Math.round(dx * 4096), (short) Math.round(dy * 4096), (short) Math.round(dz * 4096),
newYaw, newPitch, e.player.onGround);
newYaw, newPitch, e.player.onGround
);
//#else
//$$ packet = new S14PacketEntity.S17PacketEntityLookMove(e.player.getEntityId(),
//$$ (byte) Math.round(dx * 32), (byte) Math.round(dy * 32), (byte) Math.round(dz * 32),
@@ -300,9 +320,15 @@ public class RecordingEventHandler {
//Leaving Ride
if((!player(mc).isRiding() && lastRiding != -1) ||
(player(mc).isRiding() && lastRiding != getRidingEntity(player(mc)).getEntityId())) {
if(!player(mc).isRiding()) {
//#if MC>=11300
if((!player(mc).isPassenger() && lastRiding != -1) ||
(player(mc).isPassenger() && lastRiding != getRidingEntity(player(mc)).getEntityId())) {
if(!player(mc).isPassenger()) {
//#else
//$$ if((!player(mc).isRiding() && lastRiding != -1) ||
//$$ (player(mc).isRiding() && lastRiding != getRidingEntity(player(mc)).getEntityId())) {
//$$ if(!player(mc).isRiding()) {
//#endif
lastRiding = -1;
} else {
lastRiding = getRidingEntity(player(mc)).getEntityId();
@@ -331,7 +357,11 @@ public class RecordingEventHandler {
lastActiveHand = player(mc).getActiveHand();
EntityDataManager dataManager = new EntityDataManager(null);
int state = (wasHandActive ? 1 : 0) | (lastActiveHand == EnumHand.OFF_HAND ? 2 : 0);
dataManager.register(EntityLiving.HAND_STATES, (byte) state);
//#if MC>=11300
dataManager.register(EntityLivingBase.LIVING_FLAGS, (byte) state);
//#else
//$$ dataManager.register(EntityLiving.HAND_STATES, (byte) state);
//#endif
packetListener.save(new SPacketEntityMetadata(player(mc).getEntityId(), dataManager, true));
}
//#endif
@@ -346,8 +376,17 @@ public class RecordingEventHandler {
try {
//#if MC>=11100
//#if MC>=11200
packetListener.save(new SPacketCollectItem(event.pickedUp.getEntityId(), event.player.getEntityId(),
event.pickedUp.getItem().getMaxStackSize()));
//#if MC>=11300
ItemStack stack = event.getStack();
packetListener.save(new SPacketCollectItem(
event.getOriginalEntity().getEntityId(),
event.getPlayer().getEntityId(),
event.getStack().getCount()
));
//#else
//$$ packetListener.save(new SPacketCollectItem(event.pickedUp.getEntityId(), event.player.getEntityId(),
//$$ event.pickedUp.getItem().getMaxStackSize()));
//#endif
//#else
//$$ packetListener.save(new SPacketCollectItem(event.pickedUp.getEntityId(), event.player.getEntityId(),
//$$ event.pickedUp.getEntityItem().getMaxStackSize()));
@@ -394,6 +433,7 @@ public class RecordingEventHandler {
}
}
/* FIXME event not (yet?) on 1.13
@SubscribeEvent
public void enterMinecart(MinecartInteractEvent event) {
try {
@@ -418,6 +458,7 @@ public class RecordingEventHandler {
e.printStackTrace();
}
}
*/
//#if MC>=10800
public void onBlockBreakAnim(int breakerId, BlockPos pos, int progress) {

View File

@@ -0,0 +1,36 @@
//#if MC>=11300
package com.replaymod.recording.mixin;
import com.google.common.util.concurrent.ListenableFuture;
import com.replaymod.recording.packet.ResourcePackRecorder;
import de.johni0702.minecraft.gui.utils.Consumer;
import net.minecraft.client.resources.DownloadingPackFinder;
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 java.io.File;
@Mixin(DownloadingPackFinder.class)
public abstract class MixinDownloadingPackFinder implements ResourcePackRecorder.IDownloadingPackFinder {
private Consumer<File> requestCallback;
@Override
public void setRequestCallback(Consumer<File> callback) {
requestCallback = callback;
}
@Shadow
public abstract ListenableFuture<Object> func_195741_a(File file);
@Redirect(method = "downloadResourcePack", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/DownloadingPackFinder;func_195741_a(Ljava/io/File;)Lcom/google/common/util/concurrent/ListenableFuture;"))
private ListenableFuture<Object> recordDownloadedPack(DownloadingPackFinder downloadingPackFinder, File file) {
if (requestCallback != null) {
requestCallback.consume(file);
requestCallback = null;
}
return func_195741_a(file);
}
}
//#endif

View File

@@ -0,0 +1,45 @@
//#if MC>=11300
package com.replaymod.recording.mixin;
import com.replaymod.core.versions.MCVer;
import com.replaymod.extras.advancedscreenshots.AdvancedScreenshots;
import com.replaymod.replay.ReplayModReplay;
import net.minecraft.client.KeyboardListener;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.client.shader.Framebuffer;
import net.minecraft.util.ScreenShotHelper;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.fml.hooks.BasicEventHooks;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.io.File;
import java.util.function.Consumer;
@Mixin(KeyboardListener.class)
public abstract class MixinKeyboardListener {
@Inject(method = "onKeyEvent", at = @At("HEAD"), cancellable = true)
private void dispatchKeyEvent(long windowPointer, int key, int scanCode, int action, int modifiers, CallbackInfo ci) {
// FIXME this is a hack and will hopefully be done properly by forge before its release (MinecraftForge#5481)
// (and therefore before RM's release), this code will have to be removed then and handling code updated
KeyBinding keyBindChat = MCVer.getMinecraft().gameSettings.keyBindChat;
if (action == 1 && keyBindChat.matchesKey(key, scanCode)) {
keyBindChat.pressTime++;
BasicEventHooks.fireKeyInput();
ci.cancel();
}
}
@Redirect(method = "onKeyEvent", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/ScreenShotHelper;saveScreenshot(Ljava/io/File;IILnet/minecraft/client/shader/Framebuffer;Ljava/util/function/Consumer;)V"))
private void takeScreenshot(File p_148260_0_, int p_148260_1_, int p_148260_2_, Framebuffer p_148260_3_, Consumer<ITextComponent> p_148260_4_) {
if (ReplayModReplay.instance.getReplayHandler() != null) {
AdvancedScreenshots.take();
} else {
ScreenShotHelper.saveScreenshot(p_148260_0_, p_148260_1_, p_148260_2_, p_148260_3_, p_148260_4_);
}
}
}
//#endif

View File

@@ -0,0 +1,41 @@
//#if MC>=11300
package com.replaymod.recording.mixin;
import com.replaymod.replay.InputReplayTimer;
import com.replaymod.replay.ReplayModReplay;
import net.minecraft.client.MouseHelper;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(MouseHelper.class)
public abstract class MixinMouseHelper {
//#ifdef DEV_ENV
@Shadow
private boolean mouseGrabbed;
@Inject(method = "grabMouse", at = @At("HEAD"), cancellable = true)
private void noGrab(CallbackInfo ci) {
// Used to be provided by Forge for 1.12.2 and below
if (Boolean.valueOf(System.getProperty("fml.noGrab", "false"))) {
mouseGrabbed = true;
ci.cancel();
}
}
//#endif
@Inject(method = "scrollCallback",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/entity/EntityPlayerSP;isSpectator()Z"),
locals = LocalCapture.CAPTURE_FAILHARD,
cancellable = true)
private void handleReplayModScroll(long _p0, double _p1, double _p2, CallbackInfo ci, double _l1, double yOffsetAccumulated) {
if (ReplayModReplay.instance.getReplayHandler() != null) {
InputReplayTimer.handleScroll((int) yOffsetAccumulated);
ci.cancel();
}
}
}
//#endif

View File

@@ -9,11 +9,17 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//#if MC>=11300
import com.replaymod.core.versions.MCVer;
import com.replaymod.recording.handler.RecordingEventHandler.RecordingEventSender;
import net.minecraft.network.login.server.SPacketCustomPayloadLogin;
//#else
//#if MC>=10800
import net.minecraftforge.fml.common.network.FMLNetworkEvent;
//$$ import net.minecraftforge.fml.common.network.FMLNetworkEvent;
//#else
//$$ import cpw.mods.fml.common.network.FMLNetworkEvent;
//#endif
//#endif
@Mixin(NetHandlerLoginClient.class)
public abstract class MixinNetHandlerLoginClient {
@@ -25,19 +31,33 @@ public abstract class MixinNetHandlerLoginClient {
//$$ private NetworkManager field_147393_d;
//#endif
/**
* 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
//#if MC>=11300
@Inject(method = "func_209521_a", at=@At("HEAD"))
private void replayModRecording_initiateRecording(SPacketCustomPayloadLogin packet, CallbackInfo ci) {
RecordingEventSender eventSender = (RecordingEventSender) MCVer.getMinecraft().renderGlobal;
if (eventSender.getRecordingEventHandler() != null) {
return; // already recording
}
ReplayModRecording.instance.initiateRecording(networkManager);
if (eventSender.getRecordingEventHandler() != null) {
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(networkManager);
//#else
//$$ ReplayModRecording.instance.initiateRecording(field_147393_d);
//#endif
}
//$$ }
//#endif
//#if MC>=11200
@Inject(method = "handleLoginSuccess", at=@At("RETURN"))

View File

@@ -1,5 +1,6 @@
package com.replaymod.recording.mixin;
import com.replaymod.core.versions.MCVer;
import com.replaymod.recording.handler.RecordingEventHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.network.NetHandlerPlayClient;
@@ -30,8 +31,7 @@ import static com.replaymod.core.versions.MCVer.*;
@Mixin(NetHandlerPlayClient.class)
public abstract class MixinNetHandlerPlayClient {
@Shadow
private Minecraft gameController;
private static Minecraft gameController = MCVer.getMinecraft();
//#if MC>=10800
@Shadow

View File

@@ -1,75 +1,77 @@
package com.replaymod.recording.mixin;
import com.replaymod.recording.handler.FMLHandshakeFilter;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.embedded.EmbeddedChannel;
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<11300
//$$ package com.replaymod.recording.mixin;
//$$
//$$ import com.replaymod.recording.handler.FMLHandshakeFilter;
//$$ import io.netty.channel.ChannelPipeline;
//$$ import io.netty.channel.embedded.EmbeddedChannel;
//$$ 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;
//$$ import io.netty.channel.ChannelConfig;
//$$ import net.minecraft.network.EnumConnectionState;
//$$ import net.minecraft.network.NetworkManager;
//$$ import org.spongepowered.asm.mixin.injection.Redirect;
//#endif
//$$
//#if MC>=10800
import net.minecraftforge.fml.common.network.handshake.FMLHandshakeCodec;
import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher;
import net.minecraftforge.fml.relauncher.Side;
//$$ import net.minecraftforge.fml.common.network.handshake.FMLHandshakeCodec;
//$$ import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher;
//$$ import net.minecraftforge.fml.relauncher.Side;
//#else
//$$ import cpw.mods.fml.common.network.handshake.FMLHandshakeCodec;
//$$ import cpw.mods.fml.common.network.handshake.NetworkDispatcher;
//$$ import cpw.mods.fml.relauncher.Side;
//#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());
}
}
//$$
//$$ @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);
}
//$$ @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,32 @@
package com.replaymod.recording.mixin;
//#if MC>=10904
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(player(mc), type, pos, data);
}
}
//#if MC>=10904 && MC<11300
//$$ 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(player(mc), type, pos, data);
//$$ }
//$$ }
//#endif

View File

@@ -1,12 +1,17 @@
package com.replaymod.recording.mixin;
import com.replaymod.recording.handler.RecordingEventHandler;
import net.minecraft.client.renderer.RenderGlobal;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//#if MC>=11300
import net.minecraft.client.renderer.WorldRenderer;
//#else
//$$ import net.minecraft.client.renderer.RenderGlobal;
//#endif
//#if MC>=10904
import net.minecraft.util.math.BlockPos;
//#else
@@ -15,7 +20,11 @@ import net.minecraft.util.math.BlockPos;
//#endif
//#endif
@Mixin(RenderGlobal.class)
//#if MC>=11300
@Mixin(WorldRenderer.class)
//#else
//$$ @Mixin(RenderGlobal.class)
//#endif
public abstract class MixinRenderGlobal implements RecordingEventHandler.RecordingEventSender {
private RecordingEventHandler recordingEventHandler;

View File

@@ -10,7 +10,6 @@ import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.WorldProvider;
import net.minecraft.world.storage.ISaveHandler;
import net.minecraft.world.storage.WorldInfo;
import org.spongepowered.asm.mixin.Mixin;
@@ -19,6 +18,13 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//#if MC>=11300
import net.minecraft.world.dimension.Dimension;
import net.minecraft.world.storage.WorldSavedDataStorage;
//#else
//$$ import net.minecraft.world.WorldProvider;
//#endif
import static com.replaymod.core.versions.MCVer.*;
@Mixin(WorldClient.class)
@@ -26,8 +32,22 @@ public abstract class MixinWorldClient extends World implements RecordingEventHa
@Shadow
private Minecraft mc;
protected MixinWorldClient(ISaveHandler saveHandlerIn, WorldInfo info, WorldProvider providerIn, Profiler profilerIn, boolean client) {
super(saveHandlerIn, info, providerIn, profilerIn, client);
protected MixinWorldClient(ISaveHandler saveHandlerIn,
//#if MC>=11300
WorldSavedDataStorage mapStorage,
//#endif
WorldInfo info,
//#if MC>=11300
Dimension providerIn,
//#else
//$$ WorldProvider providerIn,
//#endif
Profiler profilerIn, boolean client) {
super(saveHandlerIn,
//#if MC>=11300
mapStorage,
//#endif
info, providerIn, profilerIn, client);
}
private RecordingEventHandler replayModRecording_getRecordingEventHandler() {

View File

@@ -1,9 +1,16 @@
package com.replaymod.recording.packet;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.utils.Restrictions;
import com.replaymod.editor.gui.MarkerProcessor;
import com.replaymod.recording.ReplayModRecording;
import com.replaymod.recording.Setting;
import com.replaymod.recording.handler.ConnectionEventHandler;
import com.replaymod.replaystudio.data.Marker;
import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ReplayMetaData;
import de.johni0702.minecraft.gui.element.GuiLabel;
import de.johni0702.minecraft.gui.utils.Colors;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
@@ -17,6 +24,10 @@ import net.minecraft.network.play.server.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
//#if MC>=11300
import net.minecraft.network.login.server.SPacketLoginSuccess;
//#endif
//#if MC>=10904
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.util.text.TextComponentString;
@@ -29,13 +40,16 @@ import net.minecraft.util.text.TextComponentString;
//#if MC>=10800
import net.minecraft.network.EnumPacketDirection;
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;
//#if MC<11300
//$$ import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;
//#endif
//#else
//$$ import cpw.mods.fml.common.network.internal.FMLProxyPacket;
//#endif
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@@ -49,9 +63,11 @@ import static com.replaymod.core.versions.MCVer.*;
public class PacketListener extends ChannelInboundHandlerAdapter {
private static final Minecraft mc = Minecraft.getMinecraft();
private static final Minecraft mc = getMinecraft();
private static final Logger logger = LogManager.getLogger();
private final ReplayMod core;
private final Path outputPath;
private final ReplayFile replayFile;
private final ResourcePackRecorder resourcePackRecorder;
@@ -67,6 +83,11 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
private long lastSentPacket;
private long timePassedWhilePaused;
private volatile boolean serverWasPaused;
//#if MC>=11300
private EnumConnectionState connectionState = EnumConnectionState.LOGIN;
//#else
//$$ private EnumConnectionState connectionState = EnumConnectionState.PLAY;
//#endif
/**
* Used to keep track of the last metadata save job submitted to the save service and
@@ -74,7 +95,9 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
*/
private final AtomicInteger lastSaveMetaDataId = new AtomicInteger();
public PacketListener(ReplayFile replayFile, ReplayMetaData metaData) throws IOException {
public PacketListener(ReplayMod core, Path outputPath, ReplayFile replayFile, ReplayMetaData metaData) throws IOException {
this.core = core;
this.outputPath = outputPath;
this.replayFile = replayFile;
this.metaData = metaData;
this.resourcePackRecorder = new ResourcePackRecorder(replayFile);
@@ -147,6 +170,12 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
throw new RuntimeException(e);
}
});
//#if MC>=11300
if (packet instanceof SPacketLoginSuccess) {
connectionState = EnumConnectionState.PLAY;
}
//#endif
} catch(Exception e) {
logger.error("Writing packet:", e);
}
@@ -157,21 +186,39 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
metaData.setDuration((int) lastSentPacket);
saveMetaData();
saveService.shutdown();
try {
saveService.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
logger.error("Waiting for save service termination:", e);
}
synchronized (replayFile) {
try {
replayFile.save();
replayFile.close();
} catch (IOException e) {
logger.error("Saving replay file:", e);
core.runLater(() -> {
ConnectionEventHandler connectionEventHandler = ReplayModRecording.instance.getConnectionEventHandler();
if (connectionEventHandler.getPacketListener() == this) {
connectionEventHandler.reset();
}
}
});
GuiLabel savingLabel = new GuiLabel().setI18nText("replaymod.gui.replaysaving.title").setColor(Colors.BLACK);
new Thread(() -> {
core.runLater(() -> core.getBackgroundProcesses().addProcess(savingLabel));
saveService.shutdown();
try {
saveService.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
logger.error("Waiting for save service termination:", e);
}
synchronized (replayFile) {
try {
replayFile.save();
replayFile.close();
if (core.getSettingsRegistry().get(Setting.AUTO_POST_PROCESS)) {
MarkerProcessor.apply(outputPath, progress -> {});
}
} catch (IOException e) {
logger.error("Saving replay file:", e);
}
}
core.runLater(() -> core.getBackgroundProcesses().removeProcess(savingLabel));
}).start();
}
@Override
@@ -229,16 +276,18 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
//#endif
//#endif
if (packet instanceof FMLProxyPacket) {
// This packet requires special handling
//#if MC<11300
//$$ if (packet instanceof FMLProxyPacket) {
//$$ // This packet requires special handling
//#if MC>=10800
((FMLProxyPacket) packet).toS3FPackets().forEach(this::save);
//$$ ((FMLProxyPacket) packet).toS3FPackets().forEach(this::save);
//#else
//$$ save(((FMLProxyPacket) packet).toS3FPacket());
//#endif
super.channelRead(ctx, msg);
return;
}
//$$ super.channelRead(ctx, msg);
//$$ return;
//$$ }
//#endif
save(packet);
@@ -337,9 +386,9 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
//#endif
//#if MC>=10800
Integer packetId = EnumConnectionState.PLAY.getPacketId(EnumPacketDirection.CLIENTBOUND, packet);
Integer packetId = connectionState.getPacketId(EnumPacketDirection.CLIENTBOUND, packet);
//#else
//$$ Integer packetId = (Integer) EnumConnectionState.PLAY.func_150755_b().inverse().get(packet.getClass());
//$$ Integer packetId = (Integer) connectionState.func_150755_b().inverse().get(packet.getClass());
//#endif
if (packetId == null) {
throw new IOException("Unknown packet type:" + packet.getClass());
@@ -357,11 +406,15 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
return array;
}
public void addMarker() {
Entity view = getRenderViewEntity(Minecraft.getMinecraft());
int timestamp = (int) (System.currentTimeMillis() - startTime);
public void addMarker(String name) {
addMarker(name, (int) getCurrentDuration());
}
public void addMarker(String name, int timestamp) {
Entity view = getRenderViewEntity(mc);
Marker marker = new Marker();
marker.setName(name);
marker.setTime(timestamp);
marker.setX(view.posX);
marker.setY(view.posY);
@@ -382,6 +435,10 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
});
}
public long getCurrentDuration() {
return lastSentPacket;
}
public void setServerWasPaused() {
this.serverWasPaused = true;
}

View File

@@ -4,16 +4,22 @@ import com.google.common.hash.Hashing;
import com.google.common.io.Files;
import com.replaymod.replaystudio.replay.ReplayFile;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreenWorking;
import net.minecraft.client.gui.GuiYesNo;
import net.minecraft.client.gui.GuiYesNoCallback;
import net.minecraft.client.multiplayer.ServerData;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.resources.ResourcePackRepository;
import net.minecraft.util.HttpUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
//#if MC>=11300
import de.johni0702.minecraft.gui.utils.Consumer;
import net.minecraft.client.resources.DownloadingPackFinder;
//#else
//$$ import net.minecraft.client.gui.GuiScreenWorking;
//$$ import net.minecraft.client.resources.ResourcePackRepository;
//$$ import net.minecraft.util.HttpUtil;
//#endif
//#if MC>=10904
import net.minecraft.network.play.client.CPacketResourcePackStatus;
import net.minecraft.network.play.client.CPacketResourcePackStatus.Action;
@@ -33,11 +39,11 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.network.NetworkManager;
import org.apache.commons.io.FileUtils;
//#if MC<11300
//$$ import org.apache.commons.io.FileUtils;
//#endif
import javax.annotation.Nonnull;
import static com.replaymod.core.versions.MCVer.*;
//#else
//$$ import net.minecraft.client.multiplayer.ServerData.ServerResourceMode;
//$$ import net.minecraft.client.multiplayer.ServerList;
@@ -52,12 +58,14 @@ import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import static com.replaymod.core.versions.MCVer.*;
/**
* Records resource packs and handles incoming resource pack packets during recording.
*/
public class ResourcePackRecorder {
private static final Logger logger = LogManager.getLogger();
private static final Minecraft mc = Minecraft.getMinecraft();
private static final Minecraft mc = getMinecraft();
private final ReplayFile replayFile;
@@ -131,12 +139,12 @@ public class ResourcePackRecorder {
if (url.startsWith("level://")) {
String levelName = url.substring("level://".length());
File savesDir = new File(mc.mcDataDir, "saves");
File savesDir = new File(mcDataDir(mc), "saves");
final File levelDir = new File(savesDir, levelName);
if (levelDir.isFile()) {
netManager.sendPacket(makeStatusPacket(hash, Action.ACCEPTED));
Futures.addCallback(setServerResourcePack(mc.getResourcePackRepository(), levelDir), new FutureCallback<Object>() {
Futures.addCallback(setServerResourcePack(levelDir), new FutureCallback<Object>() {
@Override
public void onSuccess(Object result) {
recordResourcePack(levelDir, requestId);
@@ -163,7 +171,11 @@ public class ResourcePackRecorder {
//noinspection Convert2Lambda
mc.addScheduledTask(() -> mc.displayGuiScreen(new GuiYesNo(new GuiYesNoCallback() {
@Override
public void confirmClicked(boolean result, int id) {
//#if MC>=11300
public void confirmResult(boolean result, int id) {
//#else
//$$ public void confirmClicked(boolean result, int id) {
//#endif
if (serverData != null) {
serverData.setResourceMode(result ? ServerData.ServerResourceMode.ENABLED : ServerData.ServerResourceMode.DISABLED);
}
@@ -202,100 +214,112 @@ public class ResourcePackRecorder {
});
}
//#if MC>=11300
private ListenableFuture downloadResourcePack(final int requestId, String url, String hash) {
final ResourcePackRepository repo = mc.mcResourcePackRepository;
String fileName;
if (hash.matches("^[a-f0-9]{40}$")) {
fileName = hash;
} else {
fileName = url.substring(url.lastIndexOf("/") + 1);
DownloadingPackFinder packFinder = mc.getPackFinder();
((IDownloadingPackFinder) packFinder).setRequestCallback(file -> recordResourcePack(file, requestId));
return packFinder.downloadResourcePack(url, hash);
}
if (fileName.contains("?")) {
fileName = fileName.substring(0, fileName.indexOf("?"));
}
if (!fileName.endsWith(".zip")) {
return Futures.immediateFailedFuture(new IllegalArgumentException("Invalid filename; must end in .zip"));
}
fileName = "legacy_" + fileName.replaceAll("\\W", "");
}
final File file = new File(repo.dirServerResourcepacks, fileName);
public interface IDownloadingPackFinder {
void setRequestCallback(Consumer<File> callback);
}
//#else
//$$ private ListenableFuture downloadResourcePack(final int requestId, String url, String hash) {
//$$ final ResourcePackRepository repo = mc.mcResourcePackRepository;
//$$ String fileName;
//$$ if (hash.matches("^[a-f0-9]{40}$")) {
//$$ fileName = hash;
//$$ } else {
//$$ fileName = url.substring(url.lastIndexOf("/") + 1);
//$$
//$$ if (fileName.contains("?")) {
//$$ fileName = fileName.substring(0, fileName.indexOf("?"));
//$$ }
//$$
//$$ if (!fileName.endsWith(".zip")) {
//$$ return Futures.immediateFailedFuture(new IllegalArgumentException("Invalid filename; must end in .zip"));
//$$ }
//$$
//$$ fileName = "legacy_" + fileName.replaceAll("\\W", "");
//$$ }
//$$
//$$ final File file = new File(repo.dirServerResourcepacks, fileName);
//#if MC>=10809
repo.lock.lock();
//$$ repo.lock.lock();
//#else
//$$ repo.field_177321_h.lock();
//#endif
try {
//$$ try {
//#if MC>=10809
repo.clearResourcePack();
//$$ repo.clearResourcePack();
//#else
//$$ repo.func_148529_f();
//#endif
if (file.exists() && hash.length() == 40) {
try {
String fileHash = Hashing.sha1().hashBytes(Files.toByteArray(file)).toString();
if (fileHash.equals(hash)) {
recordResourcePack(file, requestId);
return setServerResourcePack(repo, file);
}
logger.warn("File " + file + " had wrong hash (expected " + hash + ", found " + fileHash + "). Deleting it.");
FileUtils.deleteQuietly(file);
} catch (IOException ioexception) {
logger.warn("File " + file + " couldn\'t be hashed. Deleting it.", ioexception);
FileUtils.deleteQuietly(file);
}
}
final GuiScreenWorking guiScreen = new GuiScreenWorking();
final Minecraft mc = Minecraft.getMinecraft();
Futures.getUnchecked(mc.addScheduledTask(() -> mc.displayGuiScreen(guiScreen)));
//$$
//$$ if (file.exists() && hash.length() == 40) {
//$$ try {
//$$ String fileHash = Hashing.sha1().hashBytes(Files.toByteArray(file)).toString();
//$$ if (fileHash.equals(hash)) {
//$$ recordResourcePack(file, requestId);
//$$ return setServerResourcePack(file);
//$$ }
//$$
//$$ logger.warn("File " + file + " had wrong hash (expected " + hash + ", found " + fileHash + "). Deleting it.");
//$$ FileUtils.deleteQuietly(file);
//$$ } catch (IOException ioexception) {
//$$ logger.warn("File " + file + " couldn\'t be hashed. Deleting it.", ioexception);
//$$ FileUtils.deleteQuietly(file);
//$$ }
//$$ }
//$$
//$$ final GuiScreenWorking guiScreen = new GuiScreenWorking();
//$$ final Minecraft mc = Minecraft.getMinecraft();
//$$
//$$ Futures.getUnchecked(mc.addScheduledTask(() -> mc.displayGuiScreen(guiScreen)));
//$$
//#if MC>=10809
//#if MC>=11002
//#if MC>=11100
Map<String, String> sessionInfo = ResourcePackRepository.getDownloadHeaders();
//$$ Map<String, String> sessionInfo = ResourcePackRepository.getDownloadHeaders();
//#else
//$$ Map<String, String> sessionInfo = ResourcePackRepository.func_190115_a();
//#endif
//#else
//$$ Map<String, String> sessionInfo = Minecraft.getSessionInfo();
//#endif
repo.downloadingPacks = HttpUtil.downloadResourcePack(file, url, sessionInfo, 50 * 1024 * 1024, guiScreen, mc.getProxy());
Futures.addCallback(repo.downloadingPacks, new FutureCallback<Object>() {
//$$ repo.downloadingPacks = HttpUtil.downloadResourcePack(file, url, sessionInfo, 50 * 1024 * 1024, guiScreen, mc.getProxy());
//$$ Futures.addCallback(repo.downloadingPacks, new FutureCallback<Object>() {
//#else
//$$ Map sessionInfo = Minecraft.getSessionInfo();
//$$ repo.field_177322_i = HttpUtil.func_180192_a(file, url, sessionInfo, 50 * 1024 * 1024, guiScreen, mc.getProxy());
//$$ Futures.addCallback(repo.field_177322_i, new FutureCallback() {
//#endif
@Override
public void onSuccess(Object value) {
recordResourcePack(file, requestId);
setServerResourcePack(repo, file);
}
@Override
public void onFailure(@Nonnull Throwable throwable) {
throwable.printStackTrace();
}
});
//$$ @Override
//$$ public void onSuccess(Object value) {
//$$ recordResourcePack(file, requestId);
//$$ setServerResourcePack(file);
//$$ }
//$$
//$$ @Override
//$$ public void onFailure(@Nonnull Throwable throwable) {
//$$ throwable.printStackTrace();
//$$ }
//$$ });
//#if MC>=10809
return repo.downloadingPacks;
//$$ return repo.downloadingPacks;
//#else
//$$ return repo.field_177322_i;
//#endif
} finally {
//$$ } finally {
//#if MC>=10809
repo.lock.unlock();
//$$ repo.lock.unlock();
//#else
//$$ repo.field_177321_h.unlock();
//#endif
}
}
//$$ }
//$$ }
//#endif
//#else
//$$ public synchronized S3FPacketCustomPayload handleResourcePack(S3FPacketCustomPayload packet) {
//$$ final int requestId = nextRequestId++;

View File

@@ -1,12 +1,29 @@
package com.replaymod.render;
import com.replaymod.core.versions.MCVer;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableColor;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import net.minecraft.client.resources.I18n;
import org.lwjgl.util.ReadableColor;
import net.minecraft.util.Util;
import java.io.File;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Optional;
import static com.replaymod.render.ReplayModRender.LOGGER;
//#if MC>=11300
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
@Data
public class RenderSettings {
@@ -21,6 +38,14 @@ public class RenderSettings {
public String getDescription() {
return I18n.format("replaymod.gui.rendersettings.renderer." + name().toLowerCase() + ".description");
}
public boolean isSpherical() {
return this == EQUIRECTANGULAR || this == ODS;
}
public boolean hasFixedAspectRatio() {
return this == EQUIRECTANGULAR || this == ODS || this == CUBIC;
}
}
public enum EncodingPreset {
@@ -49,7 +74,7 @@ public class RenderSettings {
}
public String getValue() {
return "-y -f rawvideo -pix_fmt rgb24 -s %WIDTH%x%HEIGHT% -r %FPS% -i - %FILTERS%" + preset;
return "-y -f rawvideo -pix_fmt bgra -s %WIDTH%x%HEIGHT% -r %FPS% -i - %FILTERS%" + preset;
}
public String getFileExtension() {
@@ -94,7 +119,9 @@ public class RenderSettings {
private final boolean stabilizePitch;
private final boolean stabilizeRoll;
private final ReadableColor chromaKeyingColor;
private final boolean inject360Metadata;
private final int sphericalFovX;
private final int sphericalFovY;
private final boolean injectSphericalMetadata;
private final AntiAliasing antiAliasing;
private final String exportCommand;
@@ -131,12 +158,66 @@ public class RenderSettings {
}
public String getVideoFilters() {
if (antiAliasing == AntiAliasing.NONE) {
return "";
} else {
StringBuilder filters = new StringBuilder();
if (antiAliasing != AntiAliasing.NONE) {
double factor = 1.0 / antiAliasing.getFactor();
return String.format("-vf scale=iw*%1$s:ih*%1$s ", factor);
filters.append(String.format("-filter:v scale=iw*%1$s:ih*%1$s ", factor));
}
return filters.toString();
}
public String getExportCommandOrDefault() {
return exportCommand.isEmpty() ? findFFmpeg() : exportCommand;
}
private static String findFFmpeg() {
switch (Util.getOSType()) {
case WINDOWS:
// Allow windows users to unpack the ffmpeg archive into a sub-folder of their .minecraft folder
File inDotMinecraft = new File(MCVer.mcDataDir(MCVer.getMinecraft()), "ffmpeg/bin/ffmpeg.exe");
if (inDotMinecraft.exists()) {
LOGGER.debug("FFmpeg found in .minecraft/ffmpeg");
return inDotMinecraft.getAbsolutePath();
}
break;
case OSX:
// The PATH doesn't seem to be set as expected on OSX, therefore we check some common locations ourselves
for (String path : new String[]{"/usr/local/bin/ffmpeg", "/usr/bin/ffmpeg"}) {
File file = new File(path);
if (file.exists()) {
LOGGER.debug("Found FFmpeg at {}", path);
return path;
} else {
LOGGER.debug("FFmpeg not located at {}", path);
}
}
// Homebrew doesn't seem to reliably symlink its installed binaries either
File homebrewFolder = new File("/usr/local/Cellar/ffmpeg");
String[] homebrewVersions = homebrewFolder.list();
if (homebrewVersions != null) {
Optional<File> latestOpt = Arrays.stream(homebrewVersions)
.map(ComparableVersion::new) // Convert file name to comparable version
.sorted(Comparator.reverseOrder()) // Sort for latest version
.map(ComparableVersion::toString) // Convert back to file name
.map(v -> new File(new File(homebrewFolder, v), "bin/ffmpeg")) // Convert to binary files
.filter(File::exists) // Filter invalid installations (missing executable)
.findFirst(); // Take first one
if (latestOpt.isPresent()) {
File latest = latestOpt.get();
LOGGER.debug("Found {} versions of FFmpeg installed with homebrew, chose {}",
homebrewVersions.length, latest);
return latest.getAbsolutePath();
}
}
break;
case LINUX: // Linux users are entrusted to have their PATH configured correctly (most package manager do this)
case SOLARIS: // Never heard of anyone running this mod on Solaris having any problems
case UNKNOWN: // Unknown OS, just try to use "ffmpeg"
}
LOGGER.debug("Using default FFmpeg executable");
return "ffmpeg";
}
}

View File

@@ -1,65 +1,57 @@
package com.replaymod.render;
import com.replaymod.core.Module;
import com.replaymod.core.ReplayMod;
import com.replaymod.render.utils.RenderJob;
import com.replaymod.replay.events.ReplayCloseEvent;
import net.minecraft.crash.CrashReport;
import net.minecraft.util.ReportedException;
import net.minecraftforge.common.config.Configuration;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
//#if MC>=10800
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
//#else
//$$ import cpw.mods.fml.common.Mod;
//$$ import cpw.mods.fml.common.event.FMLPreInitializationEvent;
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//#endif
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import static com.replaymod.core.versions.MCVer.*;
@Mod(modid = ReplayModRender.MOD_ID,
version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*",
//#if MC>=10800
clientSideOnly = true,
//#endif
useMetadata = true)
public class ReplayModRender {
public static final String MOD_ID = "replaymod-render";
@Mod.Instance(MOD_ID)
public class ReplayModRender implements Module {
{ instance = this; }
public static ReplayModRender instance;
private ReplayMod core;
public static Logger LOGGER;
public static Logger LOGGER = LogManager.getLogger();
private Configuration configuration;
private final List<RenderJob> renderQueue = new ArrayList<>();
public ReplayModRender(ReplayMod core) {
this.core = core;
core.getSettingsRegistry().register(Setting.class);
}
public ReplayMod getCore() {
return core;
}
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
LOGGER = event.getModLog();
core = ReplayMod.instance;
configuration = new Configuration(event.getSuggestedConfigurationFile());
@Override
public void initClient() {
FML_BUS.register(this);
core.getSettingsRegistry().register(Setting.class);
}
@SubscribeEvent
@@ -69,17 +61,17 @@ public class ReplayModRender {
public File getVideoFolder() {
String path = core.getSettingsRegistry().get(Setting.RENDER_PATH);
File folder = new File(path.startsWith("./") ? core.getMinecraft().mcDataDir : null, path);
File folder = new File(path.startsWith("./") ? mcDataDir(core.getMinecraft()) : null, path);
try {
FileUtils.forceMkdir(folder);
} catch (IOException e) {
throw new ReportedException(CrashReport.makeCrashReport(e, "Cannot create video folder."));
throw newReportedException(CrashReport.makeCrashReport(e, "Cannot create video folder."));
}
return folder;
}
public Configuration getConfiguration() {
return configuration;
public Path getRenderSettingsPath() {
return mcDataDir(core.getMinecraft()).toPath().resolve("config/replaymod-rendersettings.json");
}
public List<RenderJob> getRenderQueue() {

View File

@@ -1,19 +1,18 @@
package com.replaymod.render;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.frame.RGBFrame;
import com.replaymod.render.rendering.FrameConsumer;
import com.replaymod.render.rendering.VideoRenderer;
import com.replaymod.render.utils.ByteBufferPool;
import com.replaymod.render.utils.StreamPipe;
import net.minecraft.client.Minecraft;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.util.Util;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.TeeOutputStream;
import org.lwjgl.util.ReadableDimension;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -22,17 +21,8 @@ import java.io.IOException;
import java.io.OutputStream;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
//#if MC>=10800
import net.minecraftforge.fml.common.versioning.ComparableVersion;
//#else
//$$ import cpw.mods.fml.common.versioning.ComparableVersion;
//#endif
import static com.replaymod.render.ReplayModRender.LOGGER;
import static org.apache.commons.lang3.Validate.isTrue;
@@ -64,7 +54,7 @@ public class VideoWriter implements FrameConsumer<RGBFrame> {
.replace("%BITRATE%", String.valueOf(settings.getBitRate()))
.replace("%FILTERS%", settings.getVideoFilters());
String executable = settings.getExportCommand().isEmpty() ? findFFmpeg() : settings.getExportCommand();
String executable = settings.getExportCommandOrDefault();
LOGGER.info("Starting {} with args: {}", executable, commandArgs);
String[] cmdline;
try {
@@ -78,7 +68,7 @@ public class VideoWriter implements FrameConsumer<RGBFrame> {
} catch (IOException e) {
throw new NoFFmpegException(e);
}
File exportLogFile = new File(Minecraft.getMinecraft().mcDataDir, "export.log");
File exportLogFile = new File(MCVer.mcDataDir(MCVer.getMinecraft()), "export.log");
OutputStream exportLogOut = new TeeOutputStream(new FileOutputStream(exportLogFile), ffmpegLog);
new StreamPipe(process.getInputStream(), exportLogOut).start();
new StreamPipe(process.getErrorStream(), exportLogOut).start();
@@ -86,54 +76,6 @@ public class VideoWriter implements FrameConsumer<RGBFrame> {
channel = Channels.newChannel(outputStream);
}
private String findFFmpeg() {
switch (Util.getOSType()) {
case WINDOWS:
// Allow windows users to unpack the ffmpeg archive into a sub-folder of their .minecraft folder
File inDotMinecraft = new File(Minecraft.getMinecraft().mcDataDir, "ffmpeg/bin/ffmpeg.exe");
if (inDotMinecraft.exists()) {
LOGGER.debug("FFmpeg found in .minecraft/ffmpeg");
return inDotMinecraft.getAbsolutePath();
}
break;
case OSX:
// The PATH doesn't seem to be set as expected on OSX, therefore we check some common locations ourselves
for (String path : new String[]{"/usr/local/bin/ffmpeg", "/usr/bin/ffmpeg"}) {
File file = new File(path);
if (file.exists()) {
LOGGER.debug("Found FFmpeg at {}", path);
return path;
} else {
LOGGER.debug("FFmpeg not located at {}", path);
}
}
// Homebrew doesn't seem to reliably symlink its installed binaries either
File homebrewFolder = new File("/usr/local/Cellar/ffmpeg");
String[] homebrewVersions = homebrewFolder.list();
if (homebrewVersions != null) {
Optional<File> latestOpt = Arrays.stream(homebrewVersions)
.map(ComparableVersion::new) // Convert file name to comparable version
.sorted(Comparator.reverseOrder()) // Sort for latest version
.map(ComparableVersion::toString) // Convert back to file name
.map(v -> new File(new File(homebrewFolder, v), "bin/ffmpeg")) // Convert to binary files
.filter(File::exists) // Filter invalid installations (missing executable)
.findFirst(); // Take first one
if (latestOpt.isPresent()) {
File latest = latestOpt.get();
LOGGER.debug("Found {} versions of FFmpeg installed with homebrew, chose {}",
homebrewVersions.length, latest);
return latest.getAbsolutePath();
}
}
break;
case LINUX: // Linux users are entrusted to have their PATH configured correctly (most package manager do this)
case SOLARIS: // Never heard of anyone running this mod on Solaris having any problems
case UNKNOWN: // Unknown OS, just try to use "ffmpeg"
}
LOGGER.debug("Using default FFmpeg executable");
return "ffmpeg";
}
@Override
public void close() throws IOException {
IOUtils.closeQuietly(outputStream);
@@ -182,9 +124,9 @@ public class VideoWriter implements FrameConsumer<RGBFrame> {
}
CrashReport report = CrashReport.makeCrashReport(t, "Exporting frame");
CrashReportCategory exportDetails = report.makeCategory("Export details");
exportDetails.addCrashSection("Export command", settings.getExportCommand());
exportDetails.addCrashSection("Export args", commandArgs);
Minecraft.getMinecraft().crashed(report);
MCVer.addDetail(exportDetails, "Export command", settings::getExportCommand);
MCVer.addDetail(exportDetails, "Export args", commandArgs::toString);
MCVer.getMinecraft().crashed(report);
}
}

View File

@@ -5,10 +5,16 @@ import com.replaymod.render.blend.BlendMeshBuilder;
import com.replaymod.render.blend.Exporter;
import com.replaymod.render.blend.data.DMesh;
import com.replaymod.render.blend.data.DObject;
import net.minecraft.client.model.ModelBox;
import net.minecraft.client.model.ModelRenderer;
import org.lwjgl.opengl.GL11;
//#if MC>=11300
import net.minecraft.client.renderer.entity.model.ModelBox;
import net.minecraft.client.renderer.entity.model.ModelRenderer;
//#else
//$$ import net.minecraft.client.model.ModelBox;
//$$ import net.minecraft.client.model.ModelRenderer;
//#endif
import java.io.IOException;
import static com.replaymod.core.versions.MCVer.*;

View File

@@ -4,8 +4,8 @@ import com.replaymod.render.frame.OpenGlFrame;
import com.replaymod.render.rendering.Frame;
import com.replaymod.render.utils.ByteBufferPool;
import com.replaymod.render.utils.PixelBufferObject;
import net.minecraft.client.renderer.OpenGlHelper;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -19,7 +19,7 @@ public abstract class MultiFramePboOpenGlFrameCapturer<F extends Frame, D extend
super(worldRenderer, renderInfo);
data = type.getEnumConstants();
int bufferSize = framePixels * 3 * data.length;
int bufferSize = framePixels * 4 * data.length;
pbo = new PixelBufferObject(bufferSize, PixelBufferObject.Usage.READ);
otherPBO = new PixelBufferObject(bufferSize, PixelBufferObject.Usage.READ);
}
@@ -47,7 +47,7 @@ public abstract class MultiFramePboOpenGlFrameCapturer<F extends Frame, D extend
ByteBuffer pboBuffer = pbo.mapReadOnly();
OpenGlFrame[] frames = new OpenGlFrame[data.length];
int frameBufferSize = getFrameWidth() * getFrameHeight() * 3;
int frameBufferSize = getFrameWidth() * getFrameHeight() * 4;
for (int i = 0; i < frames.length; i++) {
ByteBuffer frameBuffer = ByteBufferPool.allocate(frameBufferSize);
pboBuffer.limit(pboBuffer.position() + frameBufferSize);
@@ -79,17 +79,10 @@ public abstract class MultiFramePboOpenGlFrameCapturer<F extends Frame, D extend
protected OpenGlFrame captureFrame(int frameId, D captureData) {
pbo.bind();
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
int offset = captureData.ordinal() * getFrameWidth() * getFrameHeight() * 3;
if (OpenGlHelper.isFramebufferEnabled()) {
frameBuffer().bindFramebufferTexture();
GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, offset);
frameBuffer().unbindFramebufferTexture();
} else {
GL11.glReadPixels(0, 0, getFrameWidth(), getFrameHeight(), GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, offset);
}
int offset = captureData.ordinal() * getFrameWidth() * getFrameHeight() * 4;
frameBuffer().bindFramebuffer(true);
GL11.glReadPixels(0, 0, getFrameWidth(), getFrameHeight(), GL12.GL_BGRA, GL11.GL_UNSIGNED_BYTE, offset);
frameBuffer().unbindFramebuffer();
pbo.unbind();
return null;

View File

@@ -6,14 +6,11 @@ import com.replaymod.render.frame.ODSOpenGlFrame;
import com.replaymod.render.frame.OpenGlFrame;
import com.replaymod.render.rendering.FrameCapturer;
import com.replaymod.render.shader.Program;
import net.minecraft.client.Minecraft;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.crash.CrashReport;
import net.minecraft.util.ReportedException;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.util.ReadableDimension;
//#if MC>=10800
import net.minecraft.client.renderer.GlStateManager;
import static net.minecraft.client.renderer.GlStateManager.*;
//#else
//$$ import com.replaymod.render.hooks.GLStateTracker.BooleanState;
@@ -36,9 +33,7 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
private final Program.Uniform leftEyeVariable;
private final BooleanState[] previousStates = new BooleanState[3];
private final BooleanState previousFogState;
private final Minecraft mc = Minecraft.getMinecraft();
private BooleanState previousFogState;
public ODSFrameCapturer(WorldRenderer worldRenderer, final RenderInfo renderInfo, int frameSize) {
RenderInfo fakeInfo = new RenderInfo() {
@@ -62,9 +57,9 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
@Override
public float updateForNextFrame() {
if (call++ % 2 == 0) {
shaderProgram.stopUsing();
unbindProgram();
partialTicks = renderInfo.updateForNextFrame();
shaderProgram.use();
bindProgram();
}
return partialTicks;
}
@@ -78,30 +73,43 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
right = new CubicStereoFrameCapturer(worldRenderer, fakeInfo, frameSize);
try {
shaderProgram = new Program(vertexResource, fragmentResource);
shaderProgram.use();
leftEyeVariable = shaderProgram.getUniformVariable("leftEye");
directionVariable = shaderProgram.getUniformVariable("direction");
setTexture("texture", 0);
setTexture("lightMap", 1);
linkState(0, "textureEnabled");
linkState(1, "lightMapEnabled");
linkState(2, "hurtTextureEnabled");
final Program.Uniform uniform = shaderProgram.getUniformVariable("fogEnabled");
previousFogState = fog();
uniform.set(previousFogState.currentState);
fog(new BooleanState(previousFogState.capability) {
@Override
public void setState(boolean state) {
super.setState(state);
uniform.set(state);
}
});
shaderProgram.stopUsing();
} catch (Exception e) {
throw new ReportedException(CrashReport.makeCrashReport(e, "Creating ODS shaders"));
throw newReportedException(CrashReport.makeCrashReport(e, "Creating ODS shaders"));
}
}
private void bindProgram() {
shaderProgram.use();
setTexture("texture", 0);
setTexture("lightMap", 1);
linkState(0, "textureEnabled");
linkState(1, "lightMapEnabled");
linkState(2, "hurtTextureEnabled");
final Program.Uniform uniform = shaderProgram.getUniformVariable("fogEnabled");
previousFogState = fog();
uniform.set(previousFogState.currentState);
fog(new BooleanState(previousFogState.capability) {
{ currentState = previousFogState.currentState; }
@Override
public void setState(boolean state) {
super.setState(state);
uniform.set(state);
}
});
}
private void unbindProgram() {
for (int i = 0; i < previousStates.length; i++) {
previousStates[i].currentState = texture2DState(i).currentState;
texture2DState(i, previousStates[i]);
}
previousFogState.currentState = fog().currentState;
fog(previousFogState);
shaderProgram.stopUsing();
}
private void setTexture(String texture, int i) {
shaderProgram.getUniformVariable(texture).set(i);
}
@@ -111,6 +119,7 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
previousStates[id] = texture2DState(id);
uniform.set(previousStates[id].currentState);
texture2DState(id, new BooleanState(previousStates[id].capability) {
{ currentState = previousStates[id].currentState; }
@Override
public void setState(boolean state) {
super.setState(state);
@@ -126,12 +135,12 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
@Override
public ODSOpenGlFrame process() {
shaderProgram.use();
bindProgram();
leftEyeVariable.set(true);
CubicOpenGlFrame leftFrame = left.process();
leftEyeVariable.set(false);
CubicOpenGlFrame rightFrame = right.process();
shaderProgram.stopUsing();
unbindProgram();
if (leftFrame != null && rightFrame != null) {
return new ODSOpenGlFrame(leftFrame, rightFrame);
@@ -144,10 +153,6 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
left.close();
right.close();
shaderProgram.delete();
for (int i = 0; i < previousStates.length; i++) {
texture2DState(i, previousStates[i]);
}
fog(previousFogState);
}
private class CubicStereoFrameCapturer extends CubicPboOpenGlFrameCapturer {

View File

@@ -1,16 +1,17 @@
package com.replaymod.render.capturer;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.frame.OpenGlFrame;
import com.replaymod.render.rendering.Frame;
import com.replaymod.render.rendering.FrameCapturer;
import com.replaymod.render.utils.ByteBufferPool;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import de.johni0702.minecraft.gui.utils.lwjgl.WritableDimension;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.shader.Framebuffer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
import org.lwjgl.util.WritableDimension;
import org.lwjgl.opengl.GL12;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -30,7 +31,7 @@ public abstract class OpenGlFrameCapturer<F extends Frame, D extends CaptureData
protected int framesDone;
private Framebuffer frameBuffer;
private final Minecraft mc = Minecraft.getMinecraft();
private final Minecraft mc = MCVer.getMinecraft();
public OpenGlFrameCapturer(WorldRenderer worldRenderer, RenderInfo renderInfo) {
this.worldRenderer = worldRenderer;
@@ -64,7 +65,7 @@ public abstract class OpenGlFrameCapturer<F extends Frame, D extends CaptureData
protected Framebuffer frameBuffer() {
if (frameBuffer == null) {
frameBuffer = Minecraft.getMinecraft().getFramebuffer();
frameBuffer = mc.getFramebuffer();
}
return frameBuffer;
}
@@ -96,30 +97,28 @@ public abstract class OpenGlFrameCapturer<F extends Frame, D extends CaptureData
}
protected OpenGlFrame captureFrame(int frameId, D captureData) {
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
ByteBuffer buffer = ByteBufferPool.allocate(getFrameWidth() * getFrameHeight() * 3);
if (OpenGlHelper.isFramebufferEnabled()) {
frameBuffer().bindFramebufferTexture();
GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, buffer);
frameBuffer().unbindFramebufferTexture();
} else {
GL11.glReadPixels(0, 0, getFrameWidth(), getFrameHeight(), GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, buffer);
}
ByteBuffer buffer = ByteBufferPool.allocate(getFrameWidth() * getFrameHeight() * 4);
frameBuffer().bindFramebuffer(true);
GL11.glReadPixels(0, 0, getFrameWidth(), getFrameHeight(), GL12.GL_BGRA, GL11.GL_UNSIGNED_BYTE, buffer);
frameBuffer().unbindFramebuffer();
buffer.rewind();
return new OpenGlFrame(frameId, new Dimension(getFrameWidth(), getFrameHeight()), buffer);
}
protected void resize(int width, int height) {
if (width != mc.displayWidth || height != mc.displayHeight) {
setWindowSize(width, height);
//#if MC>=11300
Framebuffer fb = mc.getFramebuffer();
if (fb.framebufferWidth != width || fb.framebufferHeight != height) {
fb.createFramebuffer(width, height);
}
}
private void setWindowSize(int width, int height) {
mc.resize(width, height);
mc.mainWindow.framebufferWidth = width;
mc.mainWindow.framebufferHeight = height;
//#else
//$$ if (width != mc.displayWidth || height != mc.displayHeight) {
//$$ mc.resize(width, height);
//$$ }
//#endif
}
@Override

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