mirror of
https://github.com/GTNewHorizons/BetterCrashes.git
synced 2026-10-25 20:22:28 +00:00
Switch to mclo.gs crash report upload, replace GTNH-specific code with configuration, and fix stacktrace deobfuscator (#11)
* Update buildscript * spotlessApply * Switch from paste.ubuntu.com to mclo.gs paste.ubuntu.com requires a login for viewing the paste and that is annoying. mclo.gs is made for Minecraft logs. It does some special highlighting and censors certain information that is not relevant. Drawback is that logs are only valid for 90 days after last viewing. * Replace GTNH-specific code with configuration parameters * Update MCP link for stacktrace deobfuscation * Make stacktrace deobfuscation actually functional * Create HttpUtils#createConnection to reuse HTTP connection parameters in various parts of the mod * Address review feedback * Change deobfuscation mapping source This removes the necessity to extract a zip archive.
This commit is contained in:
1 parent
e31bd1c209
commit
4466f68afc
17 files changed
+345
-245
No files matched your search
@@ -2,12 +2,13 @@
|
||||
|
||||
BetterCrashes is a port of VanillaFix's crash improvement features to Minecraft 1.7.10.
|
||||
|
||||
BetterCrashes makes Minecraft return you to the main menu when it crashes,and it can upload your Crash-Report to
|
||||
[Ubuntu Pastebin](http://paste.ubuntu.com/) for send the link easier.
|
||||
BetterCrashes makes Minecraft return you to the main menu when it crashes, and it can upload your crash report to
|
||||
[mclo.gs](https://mclo.gs/) for easy sharing.
|
||||
|
||||
Most of the code comes from VanillaFix, I just make them work on Minecraft 1.7.10.
|
||||
Most of the code comes from VanillaFix, I just made it work on Minecraft 1.7.10.
|
||||
|
||||
Requires [SpongeMixins](https://github.com/GTNewHorizons/SpongeMixins) mod to work
|
||||
|
||||
## Credits
|
||||
|
||||
Thanks to VanillaFix and original author, vfyjxf
|
||||
+101
-125
@@ -1,4 +1,4 @@
|
||||
//version: 1678003329
|
||||
//version: 1684218858
|
||||
/*
|
||||
DO NOT CHANGE THIS FILE!
|
||||
Also, you may replace this file at any time if there is an update available.
|
||||
@@ -6,29 +6,25 @@
|
||||
*/
|
||||
|
||||
|
||||
import com.diffplug.blowdryer.Blowdryer
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import com.gtnewhorizons.retrofuturagradle.ObfuscationAttribute
|
||||
import com.gtnewhorizons.retrofuturagradle.mcp.ReobfuscatedJar
|
||||
import com.gtnewhorizons.retrofuturagradle.minecraft.RunMinecraftTask
|
||||
import com.gtnewhorizons.retrofuturagradle.util.Distribution
|
||||
import com.matthewprenger.cursegradle.CurseArtifact
|
||||
import com.matthewprenger.cursegradle.CurseRelation
|
||||
import com.modrinth.minotaur.dependencies.ModDependency
|
||||
import com.modrinth.minotaur.dependencies.VersionDependency
|
||||
import cpw.mods.fml.relauncher.Side
|
||||
import org.gradle.api.tasks.options.Option;
|
||||
import org.gradle.internal.logging.text.StyledTextOutput.Style
|
||||
import org.gradle.internal.logging.text.StyledTextOutputFactory
|
||||
import org.gradle.internal.xml.XmlTransformer
|
||||
import org.jetbrains.gradle.ext.*
|
||||
import org.jetbrains.gradle.ext.Application
|
||||
import org.jetbrains.gradle.ext.Gradle
|
||||
|
||||
import javax.inject.Inject
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
import javax.inject.Inject
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
@@ -65,22 +61,26 @@ plugins {
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.8.0' apply false
|
||||
id 'org.jetbrains.kotlin.kapt' version '1.8.0' apply false
|
||||
id 'com.google.devtools.ksp' version '1.8.0-1.0.9' apply false
|
||||
id 'org.ajoberstar.grgit' version '4.1.1' // 4.1.1 is the last jvm8 supporting version ,unused, available for addon.gradle
|
||||
id 'com.github.johnrengelman.shadow' version '7.1.2' apply false
|
||||
id 'com.palantir.git-version' version '0.13.0' apply false // 0.13.0 is the last jvm8 supporting version
|
||||
id 'de.undercouch.download' version '5.3.0'
|
||||
id 'org.ajoberstar.grgit' version '4.1.1' // 4.1.1 is the last jvm8 supporting version, unused, available for addon.gradle
|
||||
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
|
||||
id 'com.palantir.git-version' version '3.0.0' apply false
|
||||
id 'de.undercouch.download' version '5.4.0'
|
||||
id 'com.github.gmazzo.buildconfig' version '3.1.0' apply false // Unused, available for addon.gradle
|
||||
id 'com.diffplug.spotless' version '6.7.2' apply false
|
||||
id 'com.diffplug.spotless' version '6.13.0' apply false // 6.13.0 is the last jvm8 supporting version
|
||||
id 'com.modrinth.minotaur' version '2.+' apply false
|
||||
id 'com.matthewprenger.cursegradle' version '1.4.0' apply false
|
||||
id 'com.gtnewhorizons.retrofuturagradle' version '1.2.3'
|
||||
id 'com.gtnewhorizons.retrofuturagradle' version '1.3.14'
|
||||
}
|
||||
|
||||
print("You might want to check out './gradlew :faq' if your build fails.\n")
|
||||
|
||||
boolean settingsupdated = verifySettingsGradle()
|
||||
settingsupdated = verifyGitAttributes() || settingsupdated
|
||||
if (settingsupdated)
|
||||
throw new GradleException("Settings has been updated, please re-run task.")
|
||||
|
||||
if (project.file('.git/HEAD').isFile()) {
|
||||
// In submodules, .git is a file pointing to the real git dir
|
||||
if (project.file('.git/HEAD').isFile() || project.file('.git').isFile()) {
|
||||
apply plugin: 'com.palantir.git-version'
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ propertyDefaultIfUnset("enableGenericInjection", false) // On by default for new
|
||||
// this is meant to be set using the user wide property file. by default we do nothing.
|
||||
propertyDefaultIfUnset("ideaOverrideBuildType", "") // Can be nothing, "gradle" or "idea"
|
||||
|
||||
project.extensions.add(Blowdryer, "Blowdryer", Blowdryer) // Make blowdryer available in "apply from:" scripts
|
||||
project.extensions.add(com.diffplug.blowdryer.Blowdryer, "Blowdryer", com.diffplug.blowdryer.Blowdryer) // Make blowdryer available in "apply from:" scripts
|
||||
if (!disableSpotless) {
|
||||
apply plugin: 'com.diffplug.spotless'
|
||||
apply from: Blowdryer.file('spotless.gradle')
|
||||
@@ -160,6 +160,14 @@ java {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
tasks.withType(ScalaCompile).configureEach {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
pluginManager.withPlugin('org.jetbrains.kotlin.jvm') {
|
||||
// If Kotlin is enabled in the project
|
||||
kotlin {
|
||||
@@ -193,6 +201,14 @@ configurations {
|
||||
canBeConsumed = false
|
||||
canBeResolved = false
|
||||
}
|
||||
|
||||
create("devOnlyNonPublishable") {
|
||||
description = "Runtime and compiletime dependencies that are not published alongside the jar (compileOnly + runtimeOnlyNonPublishable)"
|
||||
canBeConsumed = false
|
||||
canBeResolved = false
|
||||
}
|
||||
compileOnly.extendsFrom(devOnlyNonPublishable)
|
||||
runtimeOnlyNonPublishable.extendsFrom(devOnlyNonPublishable)
|
||||
}
|
||||
|
||||
if (enableModernJavaSyntax.toBoolean()) {
|
||||
@@ -206,6 +222,8 @@ if (enableModernJavaSyntax.toBoolean()) {
|
||||
|
||||
dependencies {
|
||||
annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:1.0.0'
|
||||
// workaround for https://github.com/bsideup/jabel/issues/174
|
||||
annotationProcessor 'net.java.dev.jna:jna-platform:5.13.0'
|
||||
compileOnly('com.github.bsideup.jabel:jabel-javac-plugin:1.0.0') {
|
||||
transitive = false // We only care about the 1 annotation class
|
||||
}
|
||||
@@ -391,14 +409,12 @@ minecraft {
|
||||
|
||||
username = developmentEnvironmentUserName.toString()
|
||||
|
||||
lwjgl3Version = "3.3.2-SNAPSHOT"
|
||||
lwjgl3Version = "3.3.2"
|
||||
|
||||
// Enable assertions in the current mod
|
||||
extraRunJvmArguments.add("-ea:${modGroup}")
|
||||
|
||||
if (usesMixins.toBoolean() || forceEnableMixins.toBoolean()) {
|
||||
extraTweakClasses.add("org.spongepowered.asm.launch.MixinTweaker")
|
||||
|
||||
if (usesMixinDebug.toBoolean()) {
|
||||
extraRunJvmArguments.addAll([
|
||||
"-Dmixin.debug.countInjections=true",
|
||||
@@ -513,14 +529,6 @@ repositories {
|
||||
url = "http://jenkins.usrv.eu:8081/nexus/content/groups/public/"
|
||||
allowInsecureProtocol = true
|
||||
}
|
||||
if (usesMixins.toBoolean() || forceEnableMixins.toBoolean()) {
|
||||
if (usesMixinDebug.toBoolean()) {
|
||||
maven {
|
||||
name = "Fabric Maven"
|
||||
url = "https://maven.fabricmc.net/"
|
||||
}
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name 'sonatype'
|
||||
url 'https://oss.sonatype.org/content/repositories/snapshots/'
|
||||
@@ -559,29 +567,50 @@ repositories {
|
||||
}
|
||||
}
|
||||
|
||||
def mixinProviderGroup = "io.github.legacymoddingmc"
|
||||
def mixinProviderModule = "unimixins"
|
||||
def mixinProviderVersion = "0.1.7.1"
|
||||
def mixinProviderSpecNoClassifer = "${mixinProviderGroup}:${mixinProviderModule}:${mixinProviderVersion}"
|
||||
def mixinProviderSpec = "${mixinProviderSpecNoClassifer}:dev"
|
||||
ext.mixinProviderSpec = mixinProviderSpec
|
||||
|
||||
dependencies {
|
||||
if (usesMixins.toBoolean()) {
|
||||
annotationProcessor('org.ow2.asm:asm-debug-all:5.0.3')
|
||||
annotationProcessor('com.google.guava:guava:24.1.1-jre')
|
||||
annotationProcessor('com.google.code.gson:gson:2.8.6')
|
||||
annotationProcessor('com.gtnewhorizon:gtnhmixins:2.1.13:processor')
|
||||
annotationProcessor(mixinProviderSpec)
|
||||
if (usesMixinDebug.toBoolean()) {
|
||||
runtimeOnlyNonPublishable('org.jetbrains:intellij-fernflower:1.2.1.16')
|
||||
}
|
||||
}
|
||||
if (usesMixins.toBoolean() || forceEnableMixins.toBoolean()) {
|
||||
implementation('com.gtnewhorizon:gtnhmixins:2.1.13')
|
||||
if (usesMixins.toBoolean()) {
|
||||
implementation(mixinProviderSpec)
|
||||
} else if (forceEnableMixins.toBoolean()) {
|
||||
runtimeOnlyNonPublishable(mixinProviderSpec)
|
||||
}
|
||||
}
|
||||
|
||||
pluginManager.withPlugin('org.jetbrains.kotlin.kapt') {
|
||||
if (usesMixins.toBoolean()) {
|
||||
dependencies {
|
||||
kapt('com.gtnewhorizon:gtnhmixins:2.1.13:processor')
|
||||
kapt(mixinProviderSpec)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replace old mixin mods with unimixins
|
||||
// https://docs.gradle.org/8.0.2/userguide/resolution_rules.html#sec:substitution_with_classifier
|
||||
configurations.all {
|
||||
resolutionStrategy.dependencySubstitution {
|
||||
substitute module('com.gtnewhorizon:gtnhmixins') using module(mixinProviderSpecNoClassifer) withClassifier("dev") because("Unimixins replaces other mixin mods")
|
||||
substitute module('com.github.GTNewHorizons:Mixingasm') using module(mixinProviderSpecNoClassifer) withClassifier("dev") because("Unimixins replaces other mixin mods")
|
||||
substitute module('com.github.GTNewHorizons:SpongePoweredMixin') using module(mixinProviderSpecNoClassifer) withClassifier("dev") because("Unimixins replaces other mixin mods")
|
||||
substitute module('com.github.GTNewHorizons:SpongeMixins') using module(mixinProviderSpecNoClassifer) withClassifier("dev") because("Unimixins replaces other mixin mods")
|
||||
substitute module('io.github.legacymoddingmc:unimixins') using module(mixinProviderSpecNoClassifer) withClassifier("dev") because("Our previous unimixins upload was missing the dev classifier")
|
||||
}
|
||||
}
|
||||
|
||||
apply from: 'dependencies.gradle'
|
||||
|
||||
def mixingConfigRefMap = 'mixins.' + modId + '.refmap.json'
|
||||
@@ -695,13 +724,13 @@ ext.java17PatchDependenciesCfg = configurations.create("java17PatchDependencies"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
def lwjgl3ifyVersion = '1.1.35'
|
||||
def lwjgl3ifyVersion = '1.3.5'
|
||||
def asmVersion = '9.4'
|
||||
if (modId != 'lwjgl3ify') {
|
||||
java17Dependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}")
|
||||
}
|
||||
if (modId != 'hodgepodge') {
|
||||
java17Dependencies('com.github.GTNewHorizons:Hodgepodge:2.0.40')
|
||||
java17Dependencies('com.github.GTNewHorizons:Hodgepodge:2.2.13')
|
||||
}
|
||||
|
||||
java17PatchDependencies('net.minecraft:launchwrapper:1.15') {transitive = false}
|
||||
@@ -775,7 +804,7 @@ public abstract class RunHotswappableMinecraftTask extends RunMinecraftTask {
|
||||
public boolean setEnableHotswap(boolean enable) { enableHotswap = enable }
|
||||
|
||||
@Inject
|
||||
public RunHotswappableMinecraftTask(Side side, String superTask, org.gradle.api.invocation.Gradle gradle) {
|
||||
public RunHotswappableMinecraftTask(Distribution side, String superTask, org.gradle.api.invocation.Gradle gradle) {
|
||||
super(side, gradle)
|
||||
|
||||
this.lwjglVersion = 3
|
||||
@@ -784,7 +813,7 @@ public abstract class RunHotswappableMinecraftTask extends RunMinecraftTask {
|
||||
this.extraJvmArgs.addAll(project.provider(() -> enableHotswap ? project.hotswapJvmArgs : []))
|
||||
|
||||
this.classpath(project.java17PatchDependenciesCfg)
|
||||
if (side == Side.CLIENT) {
|
||||
if (side == Distribution.CLIENT) {
|
||||
this.classpath(project.minecraftTasks.lwjgl3Configuration)
|
||||
}
|
||||
// Use a raw provider instead of map to not create a dependency on the task
|
||||
@@ -793,14 +822,22 @@ public abstract class RunHotswappableMinecraftTask extends RunMinecraftTask {
|
||||
!file.path.contains("2.9.4-nightly-20150209") // Remove lwjgl2
|
||||
}
|
||||
this.classpath(project.java17DependenciesCfg)
|
||||
}
|
||||
|
||||
if (!(project.usesMixins.toBoolean() || project.forceEnableMixins.toBoolean())) {
|
||||
this.extraArgs.addAll("--tweakClass", "org.spongepowered.asm.launch.MixinTweaker")
|
||||
public void setup(Project project) {
|
||||
super.setup(project)
|
||||
if (project.usesMixins.toBoolean()) {
|
||||
this.extraJvmArgs.addAll(project.provider(() -> {
|
||||
def mixinCfg = project.configurations.detachedConfiguration(project.dependencies.create(project.mixinProviderSpec))
|
||||
mixinCfg.canBeConsumed = false
|
||||
mixinCfg.transitive = false
|
||||
enableHotswap ? ["-javaagent:" + mixinCfg.singleFile.absolutePath] : []
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def runClient17Task = tasks.register("runClient17", RunHotswappableMinecraftTask, Side.CLIENT, "runClient")
|
||||
def runClient17Task = tasks.register("runClient17", RunHotswappableMinecraftTask, Distribution.CLIENT, "runClient")
|
||||
runClient17Task.configure {
|
||||
setup(project)
|
||||
group = "Modded Minecraft"
|
||||
@@ -811,7 +848,7 @@ runClient17Task.configure {
|
||||
userUUID = minecraft.userUUID
|
||||
}
|
||||
|
||||
def runServer17Task = tasks.register("runServer17", RunHotswappableMinecraftTask, Side.SERVER, "runServer")
|
||||
def runServer17Task = tasks.register("runServer17", RunHotswappableMinecraftTask, Distribution.DEDICATED_SERVER, "runServer")
|
||||
runServer17Task.configure {
|
||||
setup(project)
|
||||
group = "Modded Minecraft"
|
||||
@@ -852,11 +889,6 @@ tasks.named("jar", Jar).configure {
|
||||
}
|
||||
|
||||
if (usesShadowedDependencies.toBoolean()) {
|
||||
tasks.register('relocateShadowJar', ConfigureShadowRelocation) {
|
||||
target = tasks.shadowJar
|
||||
prefix = modGroup + ".shadow"
|
||||
enabled = relocateShadowedDependencies.toBoolean()
|
||||
}
|
||||
tasks.named("shadowJar", ShadowJar).configure {
|
||||
manifest {
|
||||
attributes(getManifestAttributes())
|
||||
@@ -872,7 +904,8 @@ if (usesShadowedDependencies.toBoolean()) {
|
||||
]
|
||||
archiveClassifier.set('dev')
|
||||
if (relocateShadowedDependencies.toBoolean()) {
|
||||
dependsOn(relocateShadowJar)
|
||||
relocationPrefix = modGroup + ".shadow"
|
||||
enableRelocation = true
|
||||
}
|
||||
}
|
||||
configurations.runtimeElements.outgoing.artifacts.clear()
|
||||
@@ -1006,6 +1039,7 @@ idea {
|
||||
}
|
||||
compiler.javac {
|
||||
afterEvaluate {
|
||||
javacAdditionalOptions = "-encoding utf8"
|
||||
moduleJavacAdditionalOptions = [
|
||||
(project.name + ".main"): tasks.compileJava.options.compilerArgs.collect { '"' + it + '"' }.join(' ')
|
||||
]
|
||||
@@ -1125,7 +1159,7 @@ if (modrinthProjectId.size() != 0 && System.getenv("MODRINTH_TOKEN") != null) {
|
||||
}
|
||||
}
|
||||
if (usesMixins.toBoolean()) {
|
||||
addModrinthDep("required", "project", "gtnhmixins")
|
||||
addModrinthDep("required", "project", "unimixins")
|
||||
}
|
||||
tasks.modrinth.dependsOn(build)
|
||||
tasks.publish.dependsOn(tasks.modrinth)
|
||||
@@ -1169,7 +1203,7 @@ if (curseForgeProjectId.size() != 0 && System.getenv("CURSEFORGE_TOKEN") != null
|
||||
}
|
||||
}
|
||||
if (usesMixins.toBoolean()) {
|
||||
addCurseForgeRelation("requiredDependency", "gtnhmixins")
|
||||
addCurseForgeRelation("requiredDependency", "unimixins")
|
||||
}
|
||||
tasks.curseforge.dependsOn(build)
|
||||
tasks.publish.dependsOn(tasks.curseforge)
|
||||
@@ -1204,7 +1238,7 @@ def addCurseForgeRelation(String type, String name) {
|
||||
|
||||
// Updating
|
||||
|
||||
def buildscriptGradleVersion = "8.0.1"
|
||||
def buildscriptGradleVersion = "8.1.1"
|
||||
|
||||
tasks.named('wrapper', Wrapper).configure {
|
||||
gradleVersion = buildscriptGradleVersion
|
||||
@@ -1236,6 +1270,21 @@ if (!project.getGradle().startParameter.isOffline() && !Boolean.getBoolean('DISA
|
||||
}
|
||||
}
|
||||
|
||||
// If you want to add more cases to this task, implement them as arguments if total amount to print gets too large
|
||||
tasks.register('faq') {
|
||||
group = 'GTNH Buildscript'
|
||||
description = 'Prints frequently asked questions about building a project'
|
||||
|
||||
doLast {
|
||||
print("If your build fails to fetch dependencies, they might have been deleted and replaced by newer " +
|
||||
"versions.\nCheck if the versions you try to fetch are still on the distributing sites.\n" +
|
||||
"The links can be found in repositories.gradle and build.gradle:repositories, " +
|
||||
"not build.gradle:buildscript.repositories - this one is for gradle plugin metadata.\n\n" +
|
||||
"If your build fails to recognize the syntax of new Java versions, enable Jabel in your " +
|
||||
"gradle.properties. See how it's done in GTNH ExampleMod/gradle.properties.")
|
||||
}
|
||||
}
|
||||
|
||||
static URL availableBuildScriptUrl() {
|
||||
new URL("https://raw.githubusercontent.com/GTNewHorizons/ExampleMod1.7.10/master/build.gradle")
|
||||
}
|
||||
@@ -1373,7 +1422,7 @@ static int replaceParams(File file, Map<String, String> params) {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Dependency Deobfuscation
|
||||
// Dependency Deobfuscation (Deprecated, use the new RFG API documented in dependencies.gradle)
|
||||
|
||||
def deobf(String sourceURL) {
|
||||
try {
|
||||
@@ -1415,11 +1464,7 @@ def deobfMaven(String repoURL, String mavenDep) {
|
||||
}
|
||||
|
||||
def deobfCurse(String curseDep) {
|
||||
try {
|
||||
return deobfMaven("https://www.cursemaven.com/", "curse.maven:$curseDep")
|
||||
} catch (Exception ignored) {
|
||||
out.style(Style.Failure).println("Failed to get $curseDep from cursemaven.")
|
||||
}
|
||||
return dependencies.rfg.deobf("curse.maven:$curseDep")
|
||||
}
|
||||
|
||||
// The method above is to be preferred. Use this method if the filename is not at the end of the URL.
|
||||
@@ -1427,34 +1472,7 @@ def deobf(String sourceURL, String rawFileName) {
|
||||
String bon2Version = "2.5.1"
|
||||
String fileName = URLDecoder.decode(rawFileName, "UTF-8")
|
||||
String cacheDir = "$project.gradle.gradleUserHomeDir/caches"
|
||||
String bon2Dir = "$cacheDir/forge_gradle/deobf"
|
||||
String bon2File = "$bon2Dir/BON2-${bon2Version}.jar"
|
||||
String obfFile = "$cacheDir/modules-2/files-2.1/${fileName}.jar"
|
||||
String deobfFile = "$cacheDir/modules-2/files-2.1/${fileName}-deobf.jar"
|
||||
|
||||
if (file(deobfFile).exists()) {
|
||||
return files(deobfFile)
|
||||
}
|
||||
|
||||
String mappingsVer
|
||||
String remoteMappings = project.hasProperty('remoteMappings') ? project.remoteMappings : 'https://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/'
|
||||
if (remoteMappings) {
|
||||
String id = "${forgeVersion.split("\\.")[3]}-$minecraftVersion"
|
||||
String mappingsZIP = "$cacheDir/forge_gradle/maven_downloader/de/oceanlabs/mcp/mcp_snapshot_nodoc/$id/mcp_snapshot_nodoc-${id}.zip"
|
||||
|
||||
zipMappings(mappingsZIP, remoteMappings, bon2Dir)
|
||||
|
||||
mappingsVer = "snapshot_$id"
|
||||
} else {
|
||||
mappingsVer = "${channel}_$mappingsVersion"
|
||||
}
|
||||
|
||||
download.run {
|
||||
src "http://jenkins.usrv.eu:8081/nexus/content/repositories/releases/com/github/parker8283/BON2/$bon2Version-CUSTOM/BON2-$bon2Version-CUSTOM-all.jar"
|
||||
dest bon2File
|
||||
quiet true
|
||||
overwrite false
|
||||
}
|
||||
|
||||
download.run {
|
||||
src sourceURL
|
||||
@@ -1462,50 +1480,8 @@ def deobf(String sourceURL, String rawFileName) {
|
||||
quiet true
|
||||
overwrite false
|
||||
}
|
||||
|
||||
exec {
|
||||
commandLine 'java', '-jar', bon2File, '--inputJar', obfFile, '--outputJar', deobfFile, '--mcVer', minecraftVersion, '--mappingsVer', mappingsVer, '--notch'
|
||||
workingDir bon2Dir
|
||||
standardOutput = new FileOutputStream("${deobfFile}.log")
|
||||
}
|
||||
|
||||
return files(deobfFile)
|
||||
return dependencies.rfg.deobf(files(obfFile))
|
||||
}
|
||||
|
||||
def zipMappings(String zipPath, String url, String bon2Dir) {
|
||||
File zipFile = new File(zipPath)
|
||||
if (zipFile.exists()) {
|
||||
return
|
||||
}
|
||||
|
||||
String fieldsCache = "$bon2Dir/data/fields.csv"
|
||||
String methodsCache = "$bon2Dir/data/methods.csv"
|
||||
|
||||
download.run {
|
||||
src "${url}fields.csv"
|
||||
dest fieldsCache
|
||||
quiet true
|
||||
}
|
||||
download.run {
|
||||
src "${url}methods.csv"
|
||||
dest methodsCache
|
||||
quiet true
|
||||
}
|
||||
|
||||
zipFile.getParentFile().mkdirs()
|
||||
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))
|
||||
|
||||
zos.putNextEntry(new ZipEntry("fields.csv"))
|
||||
Files.copy(Paths.get(fieldsCache), zos)
|
||||
zos.closeEntry()
|
||||
|
||||
zos.putNextEntry(new ZipEntry("methods.csv"))
|
||||
Files.copy(Paths.get(methodsCache), zos)
|
||||
zos.closeEntry()
|
||||
|
||||
zos.close()
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
|
||||
def checkPropertyExists(String propertyName) {
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
package vfyjxf.bettercrashes;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
|
||||
import cpw.mods.fml.common.Loader;
|
||||
|
||||
public class BetterCrashesConfig {
|
||||
|
||||
public static Configuration config;
|
||||
|
||||
public static final String GENERAL = "General";
|
||||
|
||||
public static boolean isGTNH = Loader.isModLoaded("dreamcraft");
|
||||
public static int crashLogLimitClient = 30;
|
||||
public static int crashLogLimitServer = 30;
|
||||
public static String crashLogPasteService;
|
||||
public static String issueTrackerURL;
|
||||
public static List<String> unsupportedMods;
|
||||
public static boolean stacktraceDeobfuscation = false;
|
||||
|
||||
public static void init(File file) {
|
||||
config = new Configuration(file);
|
||||
@@ -38,6 +41,23 @@ public class BetterCrashesConfig {
|
||||
0,
|
||||
Integer.MAX_VALUE,
|
||||
"Maximum number of crash logs generated per restart for server. Suppresses too many logs generated by continuous crashes.");
|
||||
crashLogPasteService = config.getString(
|
||||
"crashLogPasteService",
|
||||
GENERAL,
|
||||
"mclo.gs",
|
||||
"Service to use for uploading crashlogs. Currently, only mclo.gs is currently supported.");
|
||||
issueTrackerURL = config.getString("issueTrackerURL", GENERAL, "", "Link to a bug tracker.");
|
||||
unsupportedMods = Arrays.asList(
|
||||
config.getStringList(
|
||||
"unsupportedMods",
|
||||
GENERAL,
|
||||
new String[] {},
|
||||
"List of modids of mods that are not supported by the modpack. BetterCrashes will encourage the player to mention those specifically in their bug report. Optifine will always be detected."));
|
||||
stacktraceDeobfuscation = config.getBoolean(
|
||||
"stacktraceDeobfuscation",
|
||||
GENERAL,
|
||||
true,
|
||||
"Enables clearer stacktraces by deobfuscating vanilla methods using MCP.");
|
||||
|
||||
if (config.hasChanged()) {
|
||||
config.save();
|
||||
|
||||
@@ -17,9 +17,9 @@ import net.minecraft.launchwrapper.Launch;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.spongepowered.asm.lib.tree.ClassNode;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||
import org.spongepowered.libraries.org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import ru.timeconqueror.spongemixins.MinecraftURLClassPath;
|
||||
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
package vfyjxf.bettercrashes.mixins.minecraft;
|
||||
|
||||
import static vfyjxf.bettercrashes.BetterCrashes.MODID;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
@@ -27,10 +30,11 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import vfyjxf.bettercrashes.BetterCrashesConfig;
|
||||
import vfyjxf.bettercrashes.utils.IPatchedCrashReport;
|
||||
import vfyjxf.bettercrashes.utils.ModIdentifier;
|
||||
import vfyjxf.bettercrashes.utils.StacktraceDeobfuscator;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
|
||||
@Mixin(value = CrashReport.class, priority = 500)
|
||||
public class CrashReportMixin implements IPatchedCrashReport {
|
||||
@@ -89,6 +93,9 @@ public class CrashReportMixin implements IPatchedCrashReport {
|
||||
/** @reason Deobfuscates the stacktrace using MCP mappings */
|
||||
@Inject(method = "populateEnvironment", at = @At("HEAD"))
|
||||
private void beforePopulateEnvironment(CallbackInfo ci) {
|
||||
if (BetterCrashesConfig.stacktraceDeobfuscation) {
|
||||
StacktraceDeobfuscator.init(new File(String.format("%s-stackdeobfuscator-methods.csv", MODID)));
|
||||
}
|
||||
StacktraceDeobfuscator.deobfuscateThrowable(cause);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,13 +39,13 @@ import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import cpw.mods.fml.client.SplashProgress;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import vfyjxf.bettercrashes.BetterCrashesConfig;
|
||||
import vfyjxf.bettercrashes.utils.CrashUtils;
|
||||
import vfyjxf.bettercrashes.utils.GuiCrashScreen;
|
||||
import vfyjxf.bettercrashes.utils.GuiInitErrorScreen;
|
||||
import vfyjxf.bettercrashes.utils.StateManager;
|
||||
import cpw.mods.fml.client.SplashProgress;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
|
||||
/**
|
||||
* @author Runemoro
|
||||
@@ -122,9 +122,8 @@ public abstract class MinecraftMixin {
|
||||
@Shadow
|
||||
public int displayHeight;
|
||||
|
||||
@SuppressWarnings("MixinAnnotationTarget")
|
||||
@Shadow
|
||||
protected abstract void func_71384_a() throws LWJGLException; // func_71384_a --> startGame
|
||||
protected abstract void startGame() throws LWJGLException;
|
||||
|
||||
@Shadow
|
||||
public abstract void displayGuiScreen(GuiScreen guiScreenIn);
|
||||
@@ -167,7 +166,7 @@ public abstract class MinecraftMixin {
|
||||
public void run() {
|
||||
running = true;
|
||||
try {
|
||||
func_71384_a();
|
||||
startGame();
|
||||
} catch (Throwable throwable) {
|
||||
CrashReport crashReport = CrashReport.makeCrashReport(throwable, "Initializing game");
|
||||
crashReport.makeCategory("Initialization");
|
||||
@@ -235,7 +234,7 @@ public abstract class MinecraftMixin {
|
||||
} catch (Throwable t) {
|
||||
// The crash screen has crashed. Report it normally instead.
|
||||
logger.error(
|
||||
"An uncaught exception occured while displaying the crash screen, making normal report instead",
|
||||
"An uncaught exception occurred while displaying the crash screen, making normal report instead",
|
||||
t);
|
||||
displayCrashReport(report);
|
||||
System.exit(report.getFile() != null ? -1 : -2);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package vfyjxf.bettercrashes.upload;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import vfyjxf.bettercrashes.BetterCrashes;
|
||||
import vfyjxf.bettercrashes.BetterCrashesConfig;
|
||||
|
||||
public class CrashReportUpload {
|
||||
|
||||
private static final Map<String, IUploadService> services = new HashMap<>();
|
||||
private static final String DEFAULT_SERVICE = "mclo.gs";
|
||||
|
||||
static {
|
||||
services.put("mclo.gs", new MclogsUploadService());
|
||||
}
|
||||
|
||||
public static URL uploadCrashReport(String crashReport) throws IOException {
|
||||
String service = BetterCrashesConfig.crashLogPasteService;
|
||||
IUploadService selectedService = services.get(service);
|
||||
if (selectedService == null) {
|
||||
BetterCrashes.logger.warn(
|
||||
String.format("Unknown upload service \"%s\", falling back to \"%s\"", service, DEFAULT_SERVICE));
|
||||
selectedService = services.get(DEFAULT_SERVICE);
|
||||
}
|
||||
|
||||
return selectedService.upload(crashReport);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package vfyjxf.bettercrashes.upload;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
public interface IUploadService {
|
||||
|
||||
/**
|
||||
* Upload crash report to pastebin service
|
||||
*
|
||||
* @param contents crash report
|
||||
* @return URL pointing to the uploaded crash report
|
||||
* @throws IOException
|
||||
*/
|
||||
URL upload(String contents) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package vfyjxf.bettercrashes.upload;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import vfyjxf.bettercrashes.utils.HttpUtils;
|
||||
|
||||
public class MclogsUploadService implements IUploadService {
|
||||
|
||||
private static final String MCLOGS_UPLOAD_URL = "https://api.mclo.gs/1/log";
|
||||
|
||||
@Override
|
||||
public URL upload(String contents) throws IOException {
|
||||
URL resultURL = null;
|
||||
|
||||
URL pasteURL = new URL(MCLOGS_UPLOAD_URL);
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
connection = HttpUtils.createConnection(pasteURL);
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
|
||||
try (PrintWriter out = new PrintWriter(connection.getOutputStream())) {
|
||||
String params = "content=" + URLEncoder.encode(contents, StandardCharsets.UTF_8.name());
|
||||
out.write(params);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
try (BufferedReader in = new BufferedReader(
|
||||
new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
||||
Gson gson = new Gson();
|
||||
JsonObject response = gson.fromJson(in, JsonObject.class);
|
||||
if (response.has("success") && response.get("success").getAsBoolean()) {
|
||||
resultURL = new URL(response.get("url").getAsString());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (connection != null) connection.disconnect();
|
||||
}
|
||||
|
||||
return resultURL;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package vfyjxf.bettercrashes.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
public class CrashReportUpload {
|
||||
|
||||
public static String uploadToUbuntuPastebin(String url, String crashReport) throws IOException {
|
||||
URL pasteUrl = new URL(url);
|
||||
HttpURLConnection connection = (HttpURLConnection) pasteUrl.openConnection();
|
||||
connection.setInstanceFollowRedirects(false);
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setUseCaches(false);
|
||||
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
connection.setReadTimeout(1000000);
|
||||
connection.setConnectTimeout(500000);
|
||||
PrintWriter out = new PrintWriter(connection.getOutputStream());
|
||||
String params = "poster=CrashReport&syntax=text&content=" + URLEncoder.encode(crashReport, "UTF-8");
|
||||
out.write(params);
|
||||
out.flush();
|
||||
String resultUrl = null;
|
||||
resultUrl = connection.getHeaderField("Location");
|
||||
if (resultUrl == null) {
|
||||
resultUrl = connection.getHeaderField("location");
|
||||
}
|
||||
return url + resultUrl;
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ public class CrashUtils {
|
||||
|
||||
public static void openBrowser(URI uri) {
|
||||
if (!Desktop.isDesktopSupported()) {
|
||||
BetterCrashes.logger.error("Desktop is not supported");
|
||||
BetterCrashes.logger.error("Desktop is not supported. Cannot open link in browser.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -6,13 +6,10 @@
|
||||
|
||||
package vfyjxf.bettercrashes.utils;
|
||||
|
||||
import static vfyjxf.bettercrashes.BetterCrashesConfig.isGTNH;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -25,12 +22,13 @@ import net.minecraft.crash.CrashReport;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import vfyjxf.bettercrashes.BetterCrashesConfig;
|
||||
import cpw.mods.fml.client.FMLClientHandler;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import vfyjxf.bettercrashes.BetterCrashesConfig;
|
||||
import vfyjxf.bettercrashes.upload.CrashReportUpload;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public abstract class GuiProblemScreen extends GuiScreen {
|
||||
@@ -51,11 +49,9 @@ public abstract class GuiProblemScreen extends GuiScreen {
|
||||
}
|
||||
|
||||
protected final CrashReport report;
|
||||
private volatile String hasteLink = null;
|
||||
private volatile URL pasteLink = null;
|
||||
private String modListString;
|
||||
protected static final List<String> UNSUPPORTED_MOD_IDS = Arrays.asList();
|
||||
protected List<String> detectedUnsupportedModNames;
|
||||
private static final String GTNH_ISSUE_TRACKER = "https://github.com/GTNewHorizons/GT-New-Horizons-Modpack/issues?q=label%3A%22Type%3A+Crash%22";
|
||||
|
||||
public GuiProblemScreen(CrashReport report) {
|
||||
this.report = report;
|
||||
@@ -81,7 +77,7 @@ public abstract class GuiProblemScreen extends GuiScreen {
|
||||
110,
|
||||
20,
|
||||
I18n.format("bettercrashes.gui.common.uploadReportAndCopyLink")));
|
||||
if (BetterCrashesConfig.isGTNH) {
|
||||
if (StringUtils.isNotEmpty(BetterCrashesConfig.issueTrackerURL)) {
|
||||
buttonList.add(
|
||||
new GuiButton(
|
||||
3,
|
||||
@@ -89,7 +85,7 @@ public abstract class GuiProblemScreen extends GuiScreen {
|
||||
height / 4 + 120 + 12 + 25,
|
||||
140,
|
||||
20,
|
||||
I18n.format("bettercrashes.gui.common.gtnhIssueTracker")));
|
||||
I18n.format("bettercrashes.gui.common.issueTracker")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +101,7 @@ public abstract class GuiProblemScreen extends GuiScreen {
|
||||
}
|
||||
}
|
||||
if (button.id == 2) {
|
||||
if (hasteLink == null) {
|
||||
if (pasteLink == null) {
|
||||
button.enabled = false;
|
||||
button.displayString = I18n.format("bettercrashes.gui.common.uploading");
|
||||
Thread thread = new Thread("BetterCrashes report uploading") {
|
||||
@@ -113,8 +109,10 @@ public abstract class GuiProblemScreen extends GuiScreen {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
hasteLink = CrashReportUpload
|
||||
.uploadToUbuntuPastebin("https://paste.ubuntu.com", report.getCompleteReport());
|
||||
pasteLink = CrashReportUpload.uploadCrashReport(report.getCompleteReport());
|
||||
if (pasteLink != null) {
|
||||
setClipboardString(pasteLink.toString());
|
||||
}
|
||||
synchronized (button) {
|
||||
button.enabled = true;
|
||||
button.displayString = I18n.format("bettercrashes.gui.common.success");
|
||||
@@ -130,15 +128,12 @@ public abstract class GuiProblemScreen extends GuiScreen {
|
||||
};
|
||||
thread.start();
|
||||
} else {
|
||||
CrashUtils.openBrowser(hasteLink);
|
||||
CrashUtils.openBrowser(pasteLink.toString());
|
||||
}
|
||||
|
||||
if (hasteLink != null) {
|
||||
setClipboardString(hasteLink);
|
||||
}
|
||||
}
|
||||
if (button.id == 3) {
|
||||
CrashUtils.openBrowser(GTNH_ISSUE_TRACKER);
|
||||
CrashUtils.openBrowser(BetterCrashesConfig.issueTrackerURL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +176,7 @@ public abstract class GuiProblemScreen extends GuiScreen {
|
||||
|
||||
drawCenteredString(
|
||||
fontRendererObj,
|
||||
report.getFile() != null ? "\u00A7n" + report.getFile().getName()
|
||||
report.getFile() != null ? "§n" + report.getFile().getName()
|
||||
: I18n.format("bettercrashes.gui.common.reportSaveFailed"),
|
||||
width / 2,
|
||||
y += 11,
|
||||
@@ -192,23 +187,17 @@ public abstract class GuiProblemScreen extends GuiScreen {
|
||||
}
|
||||
|
||||
y += 12;
|
||||
y += drawLongString(
|
||||
fontRendererObj,
|
||||
I18n.format("bettercrashes.gui.common.paragraph3" + (isGTNH ? "_gtnh" : "")),
|
||||
x,
|
||||
y,
|
||||
340,
|
||||
textColor);
|
||||
y += drawLongString(fontRendererObj, I18n.format("bettercrashes.gui.common.paragraph3"), x, y, 340, textColor);
|
||||
|
||||
if (hasUnsupportedMods) {
|
||||
drawString(fontRendererObj, I18n.format("bettercrashes.gui.common.paragraph4_gtnh"), x, y += 10, textColor);
|
||||
drawString(fontRendererObj, I18n.format("bettercrashes.gui.common.paragraph4"), x, y += 10, textColor);
|
||||
drawCenteredString(
|
||||
fontRendererObj,
|
||||
StringUtils.join(detectedUnsupportedModNames, ", "),
|
||||
width / 2,
|
||||
y += 11,
|
||||
0xE0E000);
|
||||
drawString(fontRendererObj, I18n.format("bettercrashes.gui.common.paragraph5_gtnh"), x, y += 12, textColor);
|
||||
drawString(fontRendererObj, I18n.format("bettercrashes.gui.common.paragraph5"), x, y += 12, textColor);
|
||||
}
|
||||
|
||||
super.drawScreen(mouseX, mouseY, partialTicks);
|
||||
@@ -243,19 +232,20 @@ public abstract class GuiProblemScreen extends GuiScreen {
|
||||
}
|
||||
|
||||
protected List<String> getUnsupportedMods() {
|
||||
if (!BetterCrashesConfig.isGTNH) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> list = new ArrayList<>();
|
||||
List<String> installedUnsupportedMods = new ArrayList<>();
|
||||
for (ModContainer mod : Loader.instance().getModList()) {
|
||||
if (UNSUPPORTED_MOD_IDS.contains(mod.getModId())) {
|
||||
list.add(mod.getName());
|
||||
if (BetterCrashesConfig.unsupportedMods.contains(mod.getModId())) {
|
||||
installedUnsupportedMods.add(mod.getName());
|
||||
}
|
||||
}
|
||||
|
||||
// Due to the nature of Optifine, it will very often need special
|
||||
// consideration in bug reports.
|
||||
if (FMLClientHandler.instance().hasOptifine()) {
|
||||
list.add("Optifine");
|
||||
installedUnsupportedMods.add("Optifine");
|
||||
}
|
||||
return list;
|
||||
|
||||
return installedUnsupportedMods;
|
||||
}
|
||||
|
||||
private int getClientCrashCount() {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package vfyjxf.bettercrashes.utils;
|
||||
|
||||
import static vfyjxf.bettercrashes.BetterCrashes.NAME;
|
||||
import static vfyjxf.bettercrashes.BetterCrashes.VERSION;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
public class HttpUtils {
|
||||
|
||||
private static final int HTTP_READ_TIMEOUT = 20000;
|
||||
private static final int HTTP_CONNECT_TIMEOUT = 50000;
|
||||
|
||||
/**
|
||||
* Create an HTTP connection with BetterCrashes-specific options for use in other parts of the mod.
|
||||
*/
|
||||
public static HttpURLConnection createConnection(URL url) throws IOException {
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setInstanceFollowRedirects(true);
|
||||
connection.setUseCaches(false);
|
||||
connection.setRequestProperty("User-Agent", String.format("%s/%s", NAME, VERSION));
|
||||
connection.setReadTimeout(HTTP_READ_TIMEOUT);
|
||||
connection.setConnectTimeout(HTTP_CONNECT_TIMEOUT);
|
||||
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
@@ -20,9 +20,9 @@ import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import vfyjxf.bettercrashes.BetterCrashes;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import vfyjxf.bettercrashes.BetterCrashes;
|
||||
|
||||
/**
|
||||
* @author Runemoro
|
||||
|
||||
@@ -13,20 +13,26 @@ import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import com.google.common.hash.Hasher;
|
||||
import com.google.common.hash.Hashing;
|
||||
|
||||
import vfyjxf.bettercrashes.BetterCrashes;
|
||||
|
||||
/**
|
||||
* @author Runemoro
|
||||
*/
|
||||
public final class StacktraceDeobfuscator {
|
||||
|
||||
private static final String MAPPING_METHODS_CSV_URL = "https://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/methods.csv";
|
||||
private static final String MAPPING_METHODS_CSV_HASH = "63de115ead3e848e529de81e81ada9dff694e50fb5c6d92ec1e9037fe50ca191"; // sha256
|
||||
|
||||
private static final boolean DEBUG_IN_DEV = false; // Makes this MCP -> SRG for testing in dev. Don't forget to set
|
||||
// to false when done!
|
||||
private static HashMap<String, String> srgMcpMethodMap = null;
|
||||
|
||||
/**
|
||||
* If the file does not exits, downloads latest method mappings and saves them to it. Initializes a HashMap between
|
||||
* If the file does not exist, downloads method mappings and saves them to it. Initializes a HashMap between
|
||||
* obfuscated and deobfuscated names from that file.
|
||||
*/
|
||||
public static void init(File mappings) {
|
||||
@@ -34,34 +40,40 @@ public final class StacktraceDeobfuscator {
|
||||
|
||||
// Download the file if necessary
|
||||
if (!mappings.exists()) {
|
||||
BetterCrashes.logger.info("Downloading MCP method mappings to deobfuscate stacktrace");
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
URL mappingsURL = new URL(
|
||||
"http://export.mcpbot.bspk.rs/mcp_stable_nodoc/39-1.12/mcp_stable_nodoc-39-1.12.zip");
|
||||
connection = (HttpURLConnection) mappingsURL.openConnection();
|
||||
URL mappingsURL = new URL(MAPPING_METHODS_CSV_URL);
|
||||
connection = HttpUtils.createConnection(mappingsURL);
|
||||
connection.setDoInput(true);
|
||||
connection.connect();
|
||||
try (InputStream inputStream = connection.getInputStream()) {
|
||||
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
|
||||
ZipEntry entry;
|
||||
while ((entry = zipInputStream.getNextEntry()) != null) {
|
||||
if (entry.getName().equals("methods.csv")) {
|
||||
try (FileOutputStream out = new FileOutputStream(mappings)) {
|
||||
byte[] buffer = new byte[2048];
|
||||
int len;
|
||||
while ((len = zipInputStream.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
break;
|
||||
boolean downloadInvalid = false;
|
||||
|
||||
try (FileOutputStream out = new FileOutputStream(mappings)) {
|
||||
Hasher hasher = Hashing.sha256().newHasher();
|
||||
byte[] buffer = new byte[1024 * 8];
|
||||
int len;
|
||||
while ((len = inputStream.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, len);
|
||||
hasher.putBytes(buffer, 0, len);
|
||||
}
|
||||
|
||||
if (!hasher.hash().toString().equals(MAPPING_METHODS_CSV_HASH)) {
|
||||
downloadInvalid = true;
|
||||
BetterCrashes.logger.warn(
|
||||
"Downloaded MCP mapping method.csv does not match expected hash. Skipping deobfuscation...");
|
||||
}
|
||||
}
|
||||
if (entry == null) {
|
||||
throw new RuntimeException("Downloaded zip did not contain methods.csv");
|
||||
|
||||
if (downloadInvalid) {
|
||||
mappings.delete();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
BetterCrashes.logger.warn("Failed downloading MCP mappings. Skipping deobfuscation...");
|
||||
return;
|
||||
} finally {
|
||||
if (connection != null) connection.disconnect();
|
||||
}
|
||||
@@ -85,8 +97,11 @@ public final class StacktraceDeobfuscator {
|
||||
srgMcpMethodMap.put(mcpName, srgName);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException | IndexOutOfBoundsException e) {
|
||||
BetterCrashes.logger.warn(
|
||||
"Failed to parse {}. Possible corruption. Please delete to trigger redownload.",
|
||||
mappings.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the map only if it's successful, to make sure that it's complete
|
||||
|
||||
@@ -4,17 +4,16 @@ bettercrashes.gui.common.openCrashReport=Open Crash Report
|
||||
bettercrashes.gui.common.failed=[Failed]
|
||||
bettercrashes.gui.common.uploading=Uploading...
|
||||
bettercrashes.gui.common.success=Success
|
||||
bettercrashes.gui.common.gtnhIssueTracker=Open GTNH issue tracker
|
||||
bettercrashes.gui.common.issueTracker=Open bug tracker
|
||||
|
||||
bettercrashes.gui.common.paragraph1=The following mod(s) have been identified as potential causes:
|
||||
bettercrashes.gui.common.identificationErrored=[Error identifying]
|
||||
bettercrashes.gui.common.identificationErrored=[Error identifying mod]
|
||||
bettercrashes.gui.common.unknownCause=Unknown
|
||||
bettercrashes.gui.common.paragraph2=report has been generated, and click the button below to open:
|
||||
bettercrashes.gui.common.paragraph2=report has been generated, click the button below to open:
|
||||
bettercrashes.gui.common.reportSaveFailed=[Error saving report, see log]
|
||||
bettercrashes.gui.common.paragraph3=You're encouraged to send this report's link to the mod's author to help them fix the issue. Clicking the "Upload and Copy link" button can upload report and copy its link to clipboard. Since BetterCrashes is installed, you can keep playing despite the crash.
|
||||
bettercrashes.gui.common.paragraph3_gtnh=You're encouraged to send this report's link to the GTNH issue tracker to help us fix the issue, AFTER searching the tracker for similar issue already reported. Clicking the "Upload and Copy link" button can upload report and copy its link to clipboard. Since BetterCrashes is installed, you can keep playing despite the crash.
|
||||
bettercrashes.gui.common.paragraph4_gtnh=GTNH does not support the following mod(s):
|
||||
bettercrashes.gui.common.paragraph5_gtnh=When sending report, add mention to these as well.
|
||||
bettercrashes.gui.common.paragraph3=You're encouraged to send this report's link to the modpack or mod's author to help them fix the issue. Make sure to search the tracker for similar issues already reported. Clicking the "Upload and Copy link" button can upload report and copy its link to clipboard. Since BetterCrashes is installed, you can keep playing despite the crash.
|
||||
bettercrashes.gui.common.paragraph4=This modpack does not officially support the following mod(s):
|
||||
bettercrashes.gui.common.paragraph5=When sending report, add mention of these as well.
|
||||
bettercrashes.gui.common.paragraph6=Number of crash logs exceeded limit and log was not generated.
|
||||
bettercrashes.gui.common.paragraph7=Limit can be changed via config.
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ bettercrashes.gui.common.openCrashReport=打开崩溃报告
|
||||
bettercrashes.gui.common.failed=[失败]
|
||||
bettercrashes.gui.common.uploading=上传中...
|
||||
bettercrashes.gui.common.success=成功
|
||||
bettercrashes.gui.common.gtnhIssueTracker=打开GTNH的issue跟踪器
|
||||
|
||||
bettercrashes.gui.common.paragraph1=下列模组被认为可能是导致崩溃的原因:
|
||||
bettercrashes.gui.common.identificationErrored=[鉴别错误]
|
||||
@@ -12,9 +11,6 @@ bettercrashes.gui.common.unknownCause=未知
|
||||
bettercrashes.gui.common.paragraph2=一份报告已经生成,点击下方的按钮可以打开它:
|
||||
bettercrashes.gui.common.reportSaveFailed=[保存报告出错,请查看日志]
|
||||
bettercrashes.gui.common.paragraph3=我们建议您将此报告的链接发送给模组的作者以帮助他们修复问题,点击"上传并复制链接"即可上传报告并将其链接复制到剪贴板。由于安装了BetterCrashes,尽管发生了崩溃,你仍然可以继续进行游戏。
|
||||
bettercrashes.gui.common.paragraph3_gtnh=我们非常欢迎你在搜索过仓库issue,未发现类似issue后,将此报告链接发送给我们,这可以帮助我们修复这些问题。点击"上传并复制链接"即可上传报告并将其链接复制到剪贴板。由于安装了BetterCrashes,尽管发生了崩溃,你仍然可以继续进行游戏。
|
||||
bettercrashes.gui.common.paragraph4_gtnh=GTNH不支持以下模组:
|
||||
bettercrashes.gui.common.paragraph5_gtnh=请在发送崩溃报告时,同时提及这些.
|
||||
bettercrashes.gui.common.paragraph6=崩溃日志超出了数量限制,未生成日志。
|
||||
bettercrashes.gui.common.paragraph7=数量限制可以通过配置更改.
|
||||
|
||||
@@ -22,4 +18,4 @@ bettercrashes.gui.crash.title=Minecraft崩溃啦!
|
||||
bettercrashes.gui.crash.summary=Minecraft遇到了一个问题并崩溃了。
|
||||
|
||||
bettercrashes.gui.init_error.title=Minecraft未能启动!
|
||||
bettercrashes.gui.init_error.summary=启动过程中的一个错误阻止了Minecraft的启动
|
||||
bettercrashes.gui.init_error.summary=启动过程中的一个错误阻止了Minecraft的启动
|
||||
Reference in new issue
Block a user