Merge branch 'johni/1.13-pre' into johni/blend
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -1 +1 @@
|
||||
eyJhbGciOiJIUzI1NiJ9.cGlwZWxpbmU6CiAgY2xvbmU6CiAgICBpbWFnZTogcGx1Z2lucy9naXQKICAgIHRhZ3M6IHRydWUKICAgIHJlY3Vyc2l2ZTogdHJ1ZQogIGJ1aWxkOgogICAgaW1hZ2U6IG1hdmVuOjMuMy45LWpkay04CiAgICBjb21tYW5kczoKICAgICAgLSBjdXJsIC0tZmFpbCAtLWNyZWF0ZS1kaXJzIC1vICRIT01FLy5ncmFkbGUvaW5pdC5kL21pcnJvci5ncmFkbGUgaHR0cHM6Ly9tYXZlbi5qb2huaTA3MDIuZGUvY29uZmlnL2dyYWRsZQogICAgICAtIGdpdCBjb25maWcgLS1nbG9iYWwgdXNlci5lbWFpbCAicmVwbGF5bW9kQGRyb25lIiAmJiBnaXQgY29uZmlnIC0tZ2xvYmFsIHVzZXIubmFtZSAiRHJvbmUiCiAgICAgIC0gUkVQUk9EVUNJQkxFX0JVSUxEPTEgLi9ncmFkbGV3IDoxLjcuMTA6c2V0dXBDSVdvcmtzcGFjZSA6akd1aToxLjcuMTA6c2V0dXBDSVdvcmtzcGFjZQogICAgICAtIFNJR05FRF9KQVI9JCghIGdpdCBkZXNjcmliZSAtLWV4YWN0IDI-JjEgPiAvZGV2L251bGw7IGVjaG8gJD8pIFJFUFJPRFVDSUJMRV9CVUlMRD0xIC4vZ3JhZGxldyAkKGJhc2ggLWMgImVjaG8gOnsxLjcuMTAsMS44LDEuOC45LDEuOS40LDEuMTAuMiwxLjExLDEuMTEuMiwxLjEyLDEuMTIuMSwxLjEyLjJ9OnJlb2JmSmFyIikgLS1wYXJhbGxlbAogICAgICAtIG1rZGlyIC1wIGJ1aWxkL2xpYnMgJiYgbXYgdmVyc2lvbnMvKi9idWlsZC9saWJzLyogYnVpbGQvbGlicy8KICBhcmNoaXZlOgogICAgaW1hZ2U6IHBsdWdpbnMvczMKICAgIGFjbDogcHVibGljLXJlYWQKICAgIHJlZ2lvbjogInVzLWVhc3QtMSIKICAgIGJ1Y2tldDogInJlcGxheW1vZCIKICAgIHBhdGhfc3R5bGU6IHRydWUKICAgIHNvdXJjZTogYnVpbGQvbGlicy8qCiAgICBzdHJpcF9wcmVmaXg6IGJ1aWxkL2xpYnMvCiAgICB0YXJnZXQ6IC8K.2bNe9Pd4FUTIP9VTrFR4YuHJkgCmjIbfBCUu-Wrvap8
|
||||
eyJhbGciOiJIUzI1NiJ9.cGlwZWxpbmU6CiAgY2xvbmU6CiAgICBpbWFnZTogcGx1Z2lucy9naXQKICAgIHRhZ3M6IHRydWUKICAgIHJlY3Vyc2l2ZTogdHJ1ZQogIGJ1aWxkOgogICAgaW1hZ2U6IG1hdmVuOjMuMy45LWpkay04CiAgICBjb21tYW5kczoKICAgICAgLSBjdXJsIC0tZmFpbCAtLWNyZWF0ZS1kaXJzIC1vICRIT01FLy5ncmFkbGUvaW5pdC5kL21pcnJvci5ncmFkbGUgaHR0cHM6Ly9tYXZlbi5qb2huaTA3MDIuZGUvY29uZmlnL2dyYWRsZQogICAgICAtIGdpdCBjb25maWcgLS1nbG9iYWwgdXNlci5lbWFpbCAicmVwbGF5bW9kQGRyb25lIiAmJiBnaXQgY29uZmlnIC0tZ2xvYmFsIHVzZXIubmFtZSAiRHJvbmUiCiAgICAgIC0gLi9ncmFkbGV3IC0tb2xkLWdyYWRsZSA6MS43LjEwOnNldHVwQ0lXb3Jrc3BhY2UgOmpHdWk6MS43LjEwOnNldHVwQ0lXb3Jrc3BhY2UKICAgICAgLSAuL2dyYWRsZXcgLS1vbGQtZ3JhZGxlIDoxLjcuMTA6cmVvYmZKYXIKICAgICAgLSAuL2dyYWRsZXcgJChiYXNoIC1jICJlY2hvIDp7MS44LDEuOC45LDEuOS40LDEuMTAuMiwxLjExLDEuMTEuMiwxLjEyLDEuMTIuMSwxLjEyLjIsMS4xMy4yfTpyZW9iZkphciIpIC0tcGFyYWxsZWwKICAgICAgLSBta2RpciAtcCBidWlsZC9saWJzICYmIG12IHZlcnNpb25zLyovYnVpbGQvbGlicy8qIGJ1aWxkL2xpYnMvCiAgYXJjaGl2ZToKICAgIGltYWdlOiBwbHVnaW5zL3MzCiAgICBhY2w6IHB1YmxpYy1yZWFkCiAgICByZWdpb246ICJ1cy1lYXN0LTEiCiAgICBidWNrZXQ6ICJyZXBsYXltb2QiCiAgICBwYXRoX3N0eWxlOiB0cnVlCiAgICBzb3VyY2U6IGJ1aWxkL2xpYnMvKgogICAgc3RyaXBfcHJlZml4OiBidWlsZC9saWJzLwogICAgdGFyZ2V0OiAvCg.xvkvCrkXlWrSXghw1bLwsewIfd0vJZyz-Wk15airj_s
|
||||
BIN
.gitignore
vendored
BIN
.gitignore
vendored
Binary file not shown.
@@ -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).
|
||||
|
||||
17
build.gradle
17
build.gradle
@@ -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
5
gradle.properties
Normal 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=
|
||||
0
gradle/reprod/checksums.empty.txt
Normal file
0
gradle/reprod/checksums.empty.txt
Normal 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
|
||||
|
||||
@@ -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
BIN
gradle/wrapper/gradle-wrapper-old.jar
vendored
Executable file
Binary file not shown.
6
gradle/wrapper/gradle-wrapper-old.properties
vendored
Executable file
6
gradle/wrapper/gradle-wrapper-old.properties
vendored
Executable 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
|
||||
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -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
7
gradlew
vendored
@@ -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
2
jGui
Submodule jGui updated: 097131041b...79b0aaf3e9
@@ -1,22 +1,32 @@
|
||||
include ':jGui'
|
||||
[
|
||||
'core',
|
||||
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'
|
||||
].each { version ->
|
||||
include ":jGui:$version"
|
||||
project(":jGui:$version").with {
|
||||
projectDir = file("jGui/versions/$version")
|
||||
buildFileName = '../common.gradle'
|
||||
}
|
||||
}
|
||||
|
||||
def versions = [
|
||||
'core',
|
||||
'1.7.10',
|
||||
'1.12',
|
||||
'1.13.2'
|
||||
]
|
||||
replayModVersions += [
|
||||
'1.8',
|
||||
'1.8.9',
|
||||
'1.9.4',
|
||||
@@ -25,9 +35,21 @@ def versions = [
|
||||
'1.11.2',
|
||||
'1.12',
|
||||
'1.12.1',
|
||||
'1.12.2'
|
||||
]
|
||||
versions.each { version ->
|
||||
'1.12.2',
|
||||
'1.13.2'
|
||||
]
|
||||
}
|
||||
|
||||
include ':jGui'
|
||||
jGuiVersions.each { version ->
|
||||
include ":jGui:$version"
|
||||
project(":jGui:$version").with {
|
||||
projectDir = file("jGui/versions/$version")
|
||||
buildFileName = '../common.gradle'
|
||||
}
|
||||
}
|
||||
|
||||
replayModVersions.each { version ->
|
||||
include ":$version"
|
||||
project(":$version").with {
|
||||
projectDir = file("versions/$version")
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
10
src/main/java/com/replaymod/core/Module.java
Normal file
10
src/main/java/com/replaymod/core/Module.java
Normal 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) {}
|
||||
}
|
||||
@@ -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,29 +257,42 @@ 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())
|
||||
//if(!FMLClientHandler.instance().hasOptifine()) FIXME 1.13 update
|
||||
GameSettings.Options.RENDER_DISTANCE.setValueMax(64f);
|
||||
//#endif
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.");
|
||||
//#if MC>=11300
|
||||
if (spec != null) {
|
||||
throw new IllegalStateException("Cannot register more settings are spec has been built.");
|
||||
}
|
||||
} else {
|
||||
value = NULL_OBJECT;
|
||||
}
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
135
src/main/java/com/replaymod/core/gui/GuiBackgroundProcesses.java
Normal file
135
src/main/java/com/replaymod/core/gui/GuiBackgroundProcesses.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
146
src/main/java/com/replaymod/core/versions/LangResourcePack.java
Normal file
146
src/main/java/com/replaymod/core/versions/LangResourcePack.java
Normal 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
|
||||
@@ -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>=11300
|
||||
public static MainWindow newScaledResolution(Minecraft mc) {
|
||||
return mc.mainWindow;
|
||||
}
|
||||
//#else
|
||||
//$$ public static ScaledResolution newScaledResolution(Minecraft mc) {
|
||||
//#if MC>=10809
|
||||
return new ScaledResolution(mc);
|
||||
//$$ return new ScaledResolution(mc);
|
||||
//#else
|
||||
//$$ return new ScaledResolution(mc, mc.displayWidth, mc.displayHeight);
|
||||
//#endif
|
||||
}
|
||||
//$$ }
|
||||
//#endif
|
||||
|
||||
public static ListenableFuture setServerResourcePack(ResourcePackRepository repo, File file) {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
262
src/main/java/com/replaymod/editor/gui/GuiEditReplay.java
Normal file
262
src/main/java/com/replaymod/editor/gui/GuiEditReplay.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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,25 +107,32 @@ public class GuiTrimPanel extends GuiPanel {
|
||||
endMarker.setToString(toString).setMinSize(new Dimension(100, 20)).onSelection(i ->
|
||||
onSelectedMarkerChanged(endMarker, endHour, endMin, endSec, endMilli));
|
||||
|
||||
File[] files = null;
|
||||
inputReplayButton.onClick(() -> {
|
||||
File folder;
|
||||
try {
|
||||
File folder = gui.getMod().getReplayFolder();
|
||||
files = folder.listFiles((FileFilter) new SuffixFileFilter(".mcpr", IOCase.INSENSITIVE));
|
||||
folder = gui.getMod().getReplayFolder();
|
||||
} catch (IOException e) {
|
||||
Utils.error(LOGGER, gui, CrashReport.makeCrashReport(e, "Listing available replays"), gui.backButton::onClick);
|
||||
Utils.error(LOGGER, gui, CrashReport.makeCrashReport(e, "Getting replay folder"), gui.backButton::onClick);
|
||||
return;
|
||||
}
|
||||
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);
|
||||
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();
|
||||
}
|
||||
if (files.length == 0) {
|
||||
inputReplays.setValues(NO_REPLAY);
|
||||
} else {
|
||||
inputReplays.setValues(files);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
180
src/main/java/com/replaymod/editor/gui/MarkerProcessor.java
Normal file
180
src/main/java/com/replaymod/editor/gui/MarkerProcessor.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" +
|
||||
|
||||
@@ -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?");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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\\\"\"");
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,16 +132,24 @@ 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());
|
||||
boolean isMp4 = Files.getFileExtension(outputFile.getName()).equalsIgnoreCase("mp4");
|
||||
|
||||
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 ODS with {} {}", settings.getExportCommand(), args);
|
||||
Process process = new ProcessBuilder(commandLine.toStrings()).directory(videoFile.getParentFile()).start();
|
||||
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();
|
||||
@@ -180,19 +189,16 @@ public class YoutubeUploader {
|
||||
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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
69
src/main/java/com/replaymod/online/PlainFileAuthData.java
Normal file
69
src/main/java/com/replaymod/online/PlainFileAuthData.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.*;
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,11 +74,7 @@ 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() {
|
||||
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()) {
|
||||
@@ -69,10 +82,7 @@ public class GuiHandler {
|
||||
} else {
|
||||
new GuiLoginPrompt(mod.getApiClient(), replayViewer, uploadGui, true);
|
||||
}
|
||||
}
|
||||
}).setSize(73, 20).setI18nLabel("replaymod.gui.upload").setDisabled();
|
||||
}
|
||||
}
|
||||
}).setSize(73, 20).setI18nLabel("replaymod.gui.upload").setDisabled());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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,6 +186,17 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
|
||||
metaData.setDuration((int) lastSentPacket);
|
||||
saveMetaData();
|
||||
|
||||
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);
|
||||
@@ -168,10 +208,17 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
if (fileName.contains("?")) {
|
||||
fileName = fileName.substring(0, fileName.indexOf("?"));
|
||||
DownloadingPackFinder packFinder = mc.getPackFinder();
|
||||
((IDownloadingPackFinder) packFinder).setRequestCallback(file -> recordResourcePack(file, requestId));
|
||||
return packFinder.downloadResourcePack(url, hash);
|
||||
}
|
||||
|
||||
if (!fileName.endsWith(".zip")) {
|
||||
return Futures.immediateFailedFuture(new IllegalArgumentException("Invalid filename; must end in .zip"));
|
||||
public interface IDownloadingPackFinder {
|
||||
void setRequestCallback(Consumer<File> callback);
|
||||
}
|
||||
|
||||
fileName = "legacy_" + fileName.replaceAll("\\W", "");
|
||||
}
|
||||
|
||||
final File file = new File(repo.dirServerResourcepacks, fileName);
|
||||
//#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++;
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.*;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,9 +73,15 @@ 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");
|
||||
} catch (Exception e) {
|
||||
throw newReportedException(CrashReport.makeCrashReport(e, "Creating ODS shaders"));
|
||||
}
|
||||
}
|
||||
|
||||
private void bindProgram() {
|
||||
shaderProgram.use();
|
||||
setTexture("texture", 0);
|
||||
setTexture("lightMap", 1);
|
||||
linkState(0, "textureEnabled");
|
||||
@@ -90,16 +91,23 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
|
||||
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);
|
||||
}
|
||||
});
|
||||
shaderProgram.stopUsing();
|
||||
} catch (Exception e) {
|
||||
throw new ReportedException(CrashReport.makeCrashReport(e, "Creating ODS shaders"));
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user