Update build (#1)

* Switch to GTNH ForgeGradle

* spotlessApply

* Switch to Sponge Mixin, reformat file names, drop Grimoire dependency

* Fix mapping

* Workflows

* CODEOWNERS

* .editorconfig

* Update README

* updateBuildScript

* address review

* remove spotless.gradle
This commit is contained in:
miozune authored and GitHub committed 2022-07-18 11:37:13 +07:00
1 parent 9b900985a4
commit 96dbab660d
32 files changed
+1580 -266

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
# This is the universal Text Editor Configuration
# for all GTNewHorizons projects
# See: https://editorconfig.org/
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.{bat,ini}]
end_of_line = crlf
[*.{dtd,json,info,mcmeta,md,sh,svg,xml,xsd,xsl,yaml,yml}]
indent_size = 2
+13
View File
@@ -0,0 +1,13 @@
name: Build and test
on:
pull_request:
branches: [ master, main ]
push:
branches: [ master, main ]
jobs:
build-and-test:
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/build-and-test.yml@master
secrets: inherit
+14
View File
@@ -0,0 +1,14 @@
name: Release tagged build
on:
push:
tags: [ '*' ]
permissions:
contents: write
jobs:
release-tags:
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/release-tags.yml@master
secrets: inherit
+25 -17
View File
@@ -1,24 +1,32 @@
.git
.gradle
.idea
.settings
.metadata
bin
build
run
minecraft
eclipse
/.idea/
/.vscode/
/run/
/build/
/eclipse/
.classpath
.project
.apt_generated
.apt_generated_tests
*.bat
*.sh
/bin/
/config/
/crash-reports/
/logs/
options.txt
/saves/
usernamecache.json
banned-ips.json
banned-players.json
eula.txt
ops.json
server.properties
servers.dat
usercache.json
whitelist.json
/out/
*.iml
*.ipr
*.iws
*.launch
.factorypath
forge*changelog.txt
src/main/resources/mixins.*.json
*.bat
*.DS_Store
!gradlew.bat
+2
View File
@@ -0,0 +1,2 @@
# Any Github changes require admin approval
/.github/** @GTNewHorizons/admin
+2 -6
View File
@@ -7,11 +7,7 @@ BetterCrashes makes Minecraft return you to the main menu when it crashes,and it
Most of the code comes from VanillaFix, I just make them work on Minecraft 1.7.10.
Requires [Grimoire](https://github.com/CrucibleMC/Grimoire) mod to work
## Known Issues
Not compatible with hodgepodge mod,you need go to hodgepodge mod's config file to turn off fixGuiGameOver,if you don't do this, it may cause a crash.
Requires [SpongeMixins](https://github.com/GTNewHorizons/SpongeMixins) mod to work
## Credits
Thanks VanillaFix and Grimoire
Thanks to VanillaFix and original author, vfyjxf
+884 -42
View File
@@ -1,81 +1,923 @@
//version: 1658080040
/*
DO NOT CHANGE THIS FILE!
Also, you may replace this file at any time if there is an update available.
Please check https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/build.gradle for updates.
*/
import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.internal.logging.text.StyledTextOutput.Style
import org.gradle.internal.logging.text.StyledTextOutputFactory
import java.nio.file.Files
import java.nio.file.Paths
import java.util.concurrent.TimeUnit
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream
buildscript {
repositories {
mavenCentral()
jcenter()
maven {
name = "github"
url = "https://github.com/juanmuscaria/maven/raw/master"
name 'forge'
url 'https://maven.minecraftforge.net'
}
maven {
name 'sonatype'
url 'https://oss.sonatype.org/content/repositories/snapshots/'
}
maven {
name 'Scala CI dependencies'
url 'https://repo1.maven.org/maven2/'
}
maven {
name 'jitpack'
url 'https://jitpack.io'
}
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:1.2-1.4.0-SNAPSHOT'
classpath 'com.integral.grimoire:GrimoireShenanigans:[1.3.0,)'
classpath 'com.github.GTNewHorizons:ForgeGradle:1.2.7'
}
}
plugins {
id 'java-library'
id 'idea'
id 'eclipse'
id 'scala'
id 'maven-publish'
id 'org.jetbrains.kotlin.jvm' version '1.5.30' apply false
id 'org.jetbrains.kotlin.kapt' version '1.5.30' apply false
id 'com.google.devtools.ksp' version '1.5.30-1.0.0' apply false
id 'org.ajoberstar.grgit' version '4.1.1'
id 'com.github.johnrengelman.shadow' version '4.0.4'
id 'com.palantir.git-version' version '0.13.0' apply false
id 'de.undercouch.download' version '5.0.1'
id 'com.github.gmazzo.buildconfig' version '3.0.3' apply false
id "com.diffplug.spotless" version "6.7.2"
}
dependencies {
implementation 'com.diffplug:blowdryer:1.6.0'
}
apply plugin: 'com.diffplug.blowdryer'
if (project.file('.git/HEAD').isFile()) {
apply plugin: 'com.palantir.git-version'
}
def out = services.get(StyledTextOutputFactory).create('an-output')
apply plugin: 'java'
apply plugin: 'forge'
apply plugin: 'grimoire-shenanigans'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8'
def projectJavaVersion = JavaLanguageVersion.of(8)
version = mod_version
group = mod_group
archivesBaseName = mod_archives_name
java {
toolchain {
languageVersion.set(projectJavaVersion)
}
}
idea {
module {
inheritOutputDirs = true
downloadJavadoc = true
downloadSources = true
}
}
apply from: Blowdryer.file('spotless.gradle')
if(JavaVersion.current() != JavaVersion.VERSION_1_8) {
throw new GradleException("This project requires Java 8, but it's running on " + JavaVersion.current())
}
checkPropertyExists("modName")
checkPropertyExists("modId")
checkPropertyExists("modGroup")
checkPropertyExists("autoUpdateBuildScript")
checkPropertyExists("minecraftVersion")
checkPropertyExists("forgeVersion")
checkPropertyExists("replaceGradleTokenInFile")
checkPropertyExists("gradleTokenModId")
checkPropertyExists("gradleTokenModName")
checkPropertyExists("gradleTokenVersion")
checkPropertyExists("gradleTokenGroupName")
checkPropertyExists("apiPackage")
checkPropertyExists("accessTransformersFile")
checkPropertyExists("usesMixins")
checkPropertyExists("mixinPlugin")
checkPropertyExists("mixinsPackage")
checkPropertyExists("coreModClass")
checkPropertyExists("containsMixinsAndOrCoreModOnly")
checkPropertyExists("usesShadowedDependencies")
checkPropertyExists("developmentEnvironmentUserName")
boolean noPublishedSources = project.findProperty("noPublishedSources") ? project.noPublishedSources.toBoolean() : false
boolean usesMixinDebug = project.findProperty('usesMixinDebug') ?: project.usesMixins.toBoolean()
boolean forceEnableMixins = project.findProperty('forceEnableMixins') ? project.forceEnableMixins.toBoolean() : false
String channel = project.findProperty('channel') ? project.channel : 'stable'
String mappingsVersion = project.findProperty('mappingsVersion') ? project.mappingsVersion : '12'
String remoteMappings = project.findProperty('remoteMappings') ? project.remoteMappings : 'https://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/'
String javaSourceDir = "src/main/java/"
String scalaSourceDir = "src/main/scala/"
String kotlinSourceDir = "src/main/kotlin/"
String targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/")
String targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/")
String targetPackageKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/")
if(!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) {
throw new GradleException("Could not resolve \"modGroup\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin)
}
if(apiPackage) {
targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/")
targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/")
targetPackageKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/")
if(!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) {
throw new GradleException("Could not resolve \"apiPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin)
}
}
if(accessTransformersFile) {
String targetFile = "src/main/resources/META-INF/" + accessTransformersFile
if(!getFile(targetFile).exists()) {
throw new GradleException("Could not resolve \"accessTransformersFile\"! Could not find " + targetFile)
}
}
if(usesMixins.toBoolean()) {
if(mixinsPackage.isEmpty() || mixinPlugin.isEmpty()) {
throw new GradleException("\"mixinPlugin\" requires \"mixinsPackage\" and \"mixinPlugin\" to be set!")
}
targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/")
targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/")
targetPackageKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/")
if(!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) {
throw new GradleException("Could not resolve \"mixinsPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin)
}
String targetFileJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".java"
String targetFileScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".scala"
String targetFileScalaJava = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".java"
String targetFileKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".kt"
if(!(getFile(targetFileJava).exists() || getFile(targetFileScala).exists() || getFile(targetFileScalaJava).exists() || getFile(targetFileKotlin).exists())) {
throw new GradleException("Could not resolve \"mixinPlugin\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava + " or " + targetFileKotlin)
}
}
if(coreModClass) {
String targetFileJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".java"
String targetFileScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".scala"
String targetFileScalaJava = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".java"
String targetFileKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".kt"
if(!(getFile(targetFileJava).exists() || getFile(targetFileScala).exists() || getFile(targetFileScalaJava).exists() || getFile(targetFileKotlin).exists())) {
throw new GradleException("Could not resolve \"coreModClass\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava + " or " + targetFileKotlin)
}
}
configurations.all {
resolutionStrategy.cacheChangingModulesFor(0, TimeUnit.SECONDS)
// Make sure GregTech build won't time out
System.setProperty("org.gradle.internal.http.connectionTimeout", 120000 as String)
System.setProperty("org.gradle.internal.http.socketTimeout", 120000 as String)
}
// Fix Jenkins' Git: chmod a file should not be detected as a change and append a '.dirty' to the version
try {
'git config core.fileMode false'.execute()
}
catch (Exception ignored) {
out.style(Style.Failure).println("git isn't installed at all")
}
// Pulls version first from the VERSION env and then git tag
String identifiedVersion
String versionOverride = System.getenv("VERSION") ?: null
try {
identifiedVersion = versionOverride == null ? gitVersion() : versionOverride
}
catch (Exception ignored) {
out.style(Style.Failure).text(
'This mod must be version controlled by Git AND the repository must provide at least one tag,\n' +
'or the VERSION override must be set! ').style(Style.SuccessHeader).text('(Do NOT download from GitHub using the ZIP option, instead\n' +
'clone the repository, see ').style(Style.Info).text('https://gtnh.miraheze.org/wiki/Development').style(Style.SuccessHeader).println(' for details.)'
)
versionOverride = 'NO-GIT-TAG-SET'
identifiedVersion = versionOverride
}
version = minecraftVersion + '-' + identifiedVersion
ext {
modVersion = identifiedVersion
}
if(identifiedVersion == versionOverride) {
out.style(Style.Failure).text('Override version to ').style(Style.Identifier).text(modVersion).style(Style.Failure).println('!\7')
}
group = modGroup
if(project.hasProperty("customArchiveBaseName") && customArchiveBaseName) {
archivesBaseName = customArchiveBaseName
}
else {
archivesBaseName = modId
}
def arguments = []
def jvmArguments = []
if (usesMixins.toBoolean() || forceEnableMixins) {
arguments += [
"--tweakClass org.spongepowered.asm.launch.MixinTweaker"
]
if (usesMixinDebug.toBoolean()) {
jvmArguments += [
"-Dmixin.debug.countInjections=true",
"-Dmixin.debug.verbose=true",
"-Dmixin.debug.export=true"
]
}
}
minecraft {
version = "1.7.10-10.13.4.1614-1.7.10"
runDir = "eclipse"
replace "@VERSION@", project.version
version = minecraftVersion + '-' + forgeVersion + '-' + minecraftVersion
runDir = 'run'
if (replaceGradleTokenInFile) {
replaceIn replaceGradleTokenInFile
if(gradleTokenModId) {
replace gradleTokenModId, modId
}
if(gradleTokenModName) {
replace gradleTokenModName, modName
}
if(gradleTokenVersion) {
replace gradleTokenVersion, modVersion
}
if(gradleTokenGroupName) {
replace gradleTokenGroupName, modGroup
}
}
clientIntellijRun {
args(arguments)
jvmArgs(jvmArguments)
if(developmentEnvironmentUserName) {
args("--username", developmentEnvironmentUserName)
}
}
serverIntellijRun {
args(arguments)
jvmArgs(jvmArguments)
}
}
if(file('addon.gradle').exists()) {
apply from: 'addon.gradle'
}
apply from: 'repositories.gradle'
configurations {
implementation.extendsFrom(shadowImplementation) // TODO: remove after all uses are refactored
implementation.extendsFrom(shadowCompile)
implementation.extendsFrom(shadeCompile)
}
repositories {
flatDir {
dirs 'libs'
maven {
name 'Overmind forge repo mirror'
url 'https://gregtech.overminddl1.com/'
}
if(usesMixins.toBoolean() || forceEnableMixins) {
maven {
name 'sponge'
url 'https://repo.spongepowered.org/repository/maven-public'
}
maven {
url 'https://jitpack.io'
}
}
}
processResources {
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
expand 'version': project.version,
'mod_id': mod_id,
'mod_name': mod_name,
'mod_author': mod_author,
'mod_description': mod_description,
'mc_version': mc_version,
'mod_version': mod_version,
'mod_icon': mod_icon
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('org.spongepowered:mixin:0.8-SNAPSHOT')
}
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
if(usesMixins.toBoolean() || forceEnableMixins) {
// using 0.8 to workaround a issue in 0.7 which fails mixin application
compile('com.github.GTNewHorizons:SpongePoweredMixin:0.7.12-GTNH') {
// Mixin includes a lot of dependencies that are too up-to-date
exclude module: 'launchwrapper'
exclude module: 'guava'
exclude module: 'gson'
exclude module: 'commons-io'
exclude module: 'log4j-core'
}
compile('com.github.GTNewHorizons:SpongeMixins:1.5.0')
}
}
task devJar(type: Jar) {
classifier = 'dev'
from sourceSets.main.output
apply from: 'dependencies.gradle'
def mixingConfigRefMap = 'mixins.' + modId + '.refmap.json'
def refMap = "${tasks.compileJava.temporaryDir}" + File.separator + mixingConfigRefMap
def mixinSrg = "${tasks.reobf.temporaryDir}" + File.separator + "mixins.srg"
task generateAssets {
if (usesMixins.toBoolean()) {
def mixinConfigFile = getFile("/src/main/resources/mixins." + modId + ".json");
if (!mixinConfigFile.exists()) {
mixinConfigFile.text = """{
"required": true,
"minVersion": "0.7.11",
"package": "${modGroup}.${mixinsPackage}",
"plugin": "${modGroup}.${mixinPlugin}",
"refmap": "${mixingConfigRefMap}",
"target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_8",
"mixins": [],
"client": [],
"server": []
}
"""
}
}
}
task sourcesJar(type: Jar) {
classifier = 'sources'
from sourceSets.main.allSource
task relocateShadowJar(type: ConfigureShadowRelocation) {
target = tasks.shadowJar
prefix = modGroup + ".shadow"
}
shadowJar {
project.configurations.shadeCompile.each { dep ->
from(project.zipTree(dep)) {
exclude 'META-INF', 'META-INF/**'
}
}
reobf {
addExtraSrgFile project.mixinSrg
manifest {
attributes(getManifestAttributes())
}
minimize() // This will only allow shading for actually used classes
configurations = [
project.configurations.shadowImplementation,
project.configurations.shadowCompile
]
dependsOn(relocateShadowJar)
}
jar {
appendix project.minecraft.version
project.configurations.shadeCompile.each { dep ->
from(project.zipTree(dep)) {
exclude 'META-INF', 'META-INF/**'
}
}
manifest {
attributes(getManifestAttributes())
}
if(usesShadowedDependencies.toBoolean()) {
dependsOn(shadowJar)
enabled = false
}
}
reobf {
if(usesMixins.toBoolean()) {
addExtraSrgFile mixinSrg
}
}
afterEvaluate {
if(usesMixins.toBoolean()) {
tasks.compileJava {
options.compilerArgs += [
"-AreobfSrgFile=${tasks.reobf.srg}",
"-AoutSrgFile=${mixinSrg}",
"-AoutRefMapFile=${refMap}",
// Elan: from what I understand they are just some linter configs so you get some warning on how to properly code
"-XDenableSunApiLintControl",
"-XDignore.symbol.file"
]
}
}
}
runClient {
if(developmentEnvironmentUserName) {
arguments += [
"--username",
developmentEnvironmentUserName
]
}
args(arguments)
jvmArgs(jvmArguments)
}
runServer {
args(arguments)
jvmArgs(jvmArguments)
}
tasks.withType(JavaExec).configureEach {
javaLauncher.set(
javaToolchains.launcherFor {
languageVersion = projectJavaVersion
}
)
}
processResources {
// this will ensure that this task is redone when the versions change.
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version
exclude("spotless.gradle")
// replace stuff in mcmod.info, nothing else
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
// replace modVersion and minecraftVersion
expand "minecraftVersion": project.minecraft.version,
"modVersion": modVersion,
"modId": modId,
"modName": modName
}
if(usesMixins.toBoolean()) {
from refMap
}
// copy everything else that's not the mcmod.info
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
exclude 'spotless.gradle'
}
}
def getManifestAttributes() {
def manifestAttributes = [:]
if(!containsMixinsAndOrCoreModOnly.toBoolean() && (usesMixins.toBoolean() || coreModClass)) {
manifestAttributes += ["FMLCorePluginContainsFMLMod": true]
}
if(accessTransformersFile) {
manifestAttributes += ["FMLAT" : accessTransformersFile.toString()]
}
if(coreModClass) {
manifestAttributes += ["FMLCorePlugin": modGroup + "." + coreModClass]
}
if(usesMixins.toBoolean()) {
manifestAttributes += [
"TweakClass" : "org.spongepowered.asm.launch.MixinTweaker",
"MixinConfigs" : "mixins." + modId + ".json",
"ForceLoadAsMod" : !containsMixinsAndOrCoreModOnly.toBoolean()
]
}
return manifestAttributes
}
task sourcesJar(type: Jar) {
from (sourceSets.main.allSource)
from (file("$projectDir/LICENSE"))
getArchiveClassifier().set('sources')
}
task shadowDevJar(type: ShadowJar) {
project.configurations.shadeCompile.each { dep ->
from(project.zipTree(dep)) {
exclude 'META-INF', 'META-INF/**'
}
}
from sourceSets.main.output
getArchiveClassifier().set("dev")
manifest {
attributes(getManifestAttributes())
}
minimize() // This will only allow shading for actually used classes
configurations = [
project.configurations.shadowImplementation,
project.configurations.shadowCompile
]
}
task relocateShadowDevJar(type: ConfigureShadowRelocation) {
target = tasks.shadowDevJar
prefix = modGroup + ".shadow"
}
task circularResolverJar(type: Jar) {
dependsOn(relocateShadowDevJar)
dependsOn(shadowDevJar)
enabled = false
}
task devJar(type: Jar) {
project.configurations.shadeCompile.each { dep ->
from(project.zipTree(dep)) {
exclude 'META-INF', 'META-INF/**'
}
}
from sourceSets.main.output
getArchiveClassifier().set("dev")
manifest {
attributes(getManifestAttributes())
}
if(usesShadowedDependencies.toBoolean()) {
dependsOn(circularResolverJar)
enabled = false
}
}
task apiJar(type: Jar) {
from (sourceSets.main.allSource) {
include modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") + '/**'
}
from (sourceSets.main.output) {
include modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") + '/**'
}
from (sourceSets.main.resources.srcDirs) {
include("LICENSE")
}
getArchiveClassifier().set('api')
}
artifacts {
if(!noPublishedSources) {
archives sourcesJar
}
archives devJar
archives sourcesJar
if(apiPackage) {
archives apiJar
}
}
// The gradle metadata includes all of the additional deps that we disabled from POM generation (including forgeBin with no groupID),
// and isn't strictly needed with the POM so just disable it.
tasks.withType(GenerateModuleMetadata) {
enabled = false
}
// workaround variable hiding in pom processing
def projectConfigs = project.configurations
publishing {
publications {
maven(MavenPublication) {
from components.java
if(usesShadowedDependencies.toBoolean()) {
artifact source: shadowJar, classifier: ""
}
if(!noPublishedSources) {
artifact source: sourcesJar, classifier: "sources"
}
artifact source: usesShadowedDependencies.toBoolean() ? shadowDevJar : devJar, classifier: "dev"
if (apiPackage) {
artifact source: apiJar, classifier: "api"
}
groupId = System.getenv("ARTIFACT_GROUP_ID") ?: "com.github.GTNewHorizons"
artifactId = System.getenv("ARTIFACT_ID") ?: project.name
// Using the identified version, not project.version as it has the prepended 1.7.10
version = System.getenv("RELEASE_VERSION") ?: identifiedVersion
// remove extra garbage from minecraft and minecraftDeps configuration
pom.withXml {
def badArtifacts = [:].withDefault {[] as Set<String>}
for (configuration in [
projectConfigs.minecraft,
projectConfigs.minecraftDeps
]) {
for (dependency in configuration.allDependencies) {
badArtifacts[dependency.group == null ? "" : dependency.group] += dependency.name
}
}
// example for specifying extra stuff to ignore
// badArtifacts["org.example.group"] += "artifactName"
Node pomNode = asNode()
pomNode.dependencies.'*'.findAll() {
badArtifacts[it.groupId.text()].contains(it.artifactId.text())
}.each() {
it.parent().remove(it)
}
}
}
}
repositories {
maven {
url = "http://jenkins.usrv.eu:8081/nexus/content/repositories/releases"
credentials {
username = System.getenv("MAVEN_USER") ?: "NONE"
password = System.getenv("MAVEN_PASSWORD") ?: "NONE"
}
}
}
}
// Updating
task updateBuildScript {
doLast {
if (performBuildScriptUpdate(projectDir.toString())) return
print("Build script already up-to-date!")
}
}
if (isNewBuildScriptVersionAvailable(projectDir.toString())) {
if (autoUpdateBuildScript.toBoolean()) {
performBuildScriptUpdate(projectDir.toString())
} else {
out.style(Style.SuccessHeader).println("Build script update available! Run 'gradle updateBuildScript'")
}
}
static URL availableBuildScriptUrl() {
new URL("https://raw.githubusercontent.com/GTNewHorizons/ExampleMod1.7.10/main/build.gradle")
}
boolean performBuildScriptUpdate(String projectDir) {
if (isNewBuildScriptVersionAvailable(projectDir)) {
def buildscriptFile = getFile("build.gradle")
availableBuildScriptUrl().withInputStream { i -> buildscriptFile.withOutputStream { it << i } }
out.style(Style.Success).print("Build script updated. Please REIMPORT the project or RESTART your IDE!")
return true
}
return false
}
boolean isNewBuildScriptVersionAvailable(String projectDir) {
Map parameters = ["connectTimeout": 2000, "readTimeout": 2000]
String currentBuildScript = getFile("build.gradle").getText()
String currentBuildScriptHash = getVersionHash(currentBuildScript)
String availableBuildScript = availableBuildScriptUrl().newInputStream(parameters).getText()
String availableBuildScriptHash = getVersionHash(availableBuildScript)
boolean isUpToDate = currentBuildScriptHash.empty || availableBuildScriptHash.empty || currentBuildScriptHash == availableBuildScriptHash
return !isUpToDate
}
static String getVersionHash(String buildScriptContent) {
String versionLine = buildScriptContent.find("^//version: [a-z0-9]*")
if(versionLine != null) {
return versionLine.split(": ").last()
}
return ""
}
configure(updateBuildScript) {
group = 'forgegradle'
description = 'Updates the build script to the latest version'
}
// Parameter Deobfuscation
task deobfParams {
doLast {
String mcpDir = "$project.gradle.gradleUserHomeDir/caches/minecraft/de/oceanlabs/mcp/mcp_$channel/$mappingsVersion"
String mcpZIP = "$mcpDir/mcp_$channel-$mappingsVersion-${minecraftVersion}.zip"
String paramsCSV = "$mcpDir/params.csv"
download.run {
src "https://maven.minecraftforge.net/de/oceanlabs/mcp/mcp_$channel/$mappingsVersion-$minecraftVersion/mcp_$channel-$mappingsVersion-${minecraftVersion}.zip"
dest mcpZIP
overwrite false
}
if(!file(paramsCSV).exists()) {
println("Extracting MCP archive ...")
unzip(mcpZIP, mcpDir)
}
println("Parsing params.csv ...")
Map<String, String> params = new HashMap<>()
Files.lines(Paths.get(paramsCSV)).forEach{line ->
String[] cells = line.split(",")
if(cells.length > 2 && cells[0].matches("p_i?\\d+_\\d+_")) {
params.put(cells[0], cells[1])
}
}
out.style(Style.Success).println("Modified ${replaceParams(file("$projectDir/src/main/java"), params)} files!")
out.style(Style.Failure).println("Don't forget to verify that the code still works as before!\n It could be broken due to duplicate variables existing now\n or parameters taking priority over other variables.")
}
}
static int replaceParams(File file, Map<String, String> params) {
int fileCount = 0
if(file.isDirectory()) {
for(File f : file.listFiles()) {
fileCount += replaceParams(f, params)
}
return fileCount
}
println("Visiting ${file.getName()} ...")
try {
String content = new String(Files.readAllBytes(file.toPath()))
int hash = content.hashCode()
params.forEach{key, value ->
content = content.replaceAll(key, value)
}
if(hash != content.hashCode()) {
Files.write(file.toPath(), content.getBytes("UTF-8"))
return 1
}
} catch(Exception e) {
e.printStackTrace()
}
return 0
}
// Credit: bitsnaps (https://gist.github.com/bitsnaps/00947f2dce66f4bbdabc67d7e7b33681)
static unzip(String zipFileName, String outputDir) {
byte[] buffer = new byte[16384]
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFileName))
ZipEntry zipEntry = zis.getNextEntry()
while (zipEntry != null) {
File newFile = new File(outputDir + File.separator, zipEntry.name)
if (zipEntry.isDirectory()) {
if (!newFile.isDirectory() && !newFile.mkdirs()) {
throw new IOException("Failed to create directory $newFile")
}
} else {
// fix for Windows-created archives
File parent = newFile.parentFile
if (!parent.isDirectory() && !parent.mkdirs()) {
throw new IOException("Failed to create directory $parent")
}
// write file content
FileOutputStream fos = new FileOutputStream(newFile)
int len = 0
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len)
}
fos.close()
}
zipEntry = zis.getNextEntry()
}
zis.closeEntry()
zis.close()
}
configure(deobfParams) {
group = 'forgegradle'
description = 'Rename all obfuscated parameter names inherited from Minecraft classes'
}
// Dependency Deobfuscation
def deobf(String sourceURL) {
try {
URL url = new URL(sourceURL)
String fileName = url.getFile()
//get rid of directories:
int lastSlash = fileName.lastIndexOf("/")
if(lastSlash > 0) {
fileName = fileName.substring(lastSlash + 1)
}
//get rid of extension:
if(fileName.endsWith(".jar") || fileName.endsWith(".litemod")) {
fileName = fileName.substring(0, fileName.lastIndexOf("."))
}
String hostName = url.getHost()
if(hostName.startsWith("www.")) {
hostName = hostName.substring(4)
}
List parts = Arrays.asList(hostName.split("\\."))
Collections.reverse(parts)
hostName = String.join(".", parts)
return deobf(sourceURL, "$hostName/$fileName")
} catch(Exception e) {
return deobf(sourceURL, "deobf/${sourceURL.hashCode()}")
}
}
// The method above is to be preferred. Use this method if the filename is not at the end of the URL.
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
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
dest obfFile
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)
}
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) {
if (!project.hasProperty(propertyName)) {
throw new GradleException("This project requires a property \"" + propertyName + "\"! Please add it your \"gradle.properties\". You can find all properties and their description here: https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/gradle.properties")
}
}
def getFile(String relativePath) {
return new File(projectDir, relativePath)
}
+5
View File
@@ -0,0 +1,5 @@
// Add your dependencies here
dependencies {
}
+77 -17
View File
@@ -1,19 +1,79 @@
# Gradle Specifications
org.gradle.jvmargs=-Xmx2G -Xms2G
org.gradle.daemon=false
modName = BetterCrashes
# General Specifications
mc_version=1.7.10
mod_version=1.1.2
forge_version=10.13.4.1614
mod_group=vfyjxf.bettercrashes
mod_id=bettercrashes
mod_name=BetterCrashes
mod_archives_name=BetterCrashes
mod_author=vfyjxf
mod_icon=TEM_logo.png
mod_description=Some generic mod description
mod_credits=Me, for making this amazing mod.
# This is a case-sensitive string to identify your mod. Convention is to use lower case.
modId = bettercrashes
# Grimoire Shenanigans
mixinRefmapName=mixins.bettercrashes.refmap.json
modGroup = vfyjxf.bettercrashes
# WHY is there no version field?
# The build script relies on git to provide a version via tags. It is super easy and will enable you to always know the
# code base or your binary. Check out this tutorial: https://blog.mattclemente.com/2017/10/13/versioning-with-git-tags/
# Will update your build.gradle automatically whenever an update is available
autoUpdateBuildScript = false
minecraftVersion = 1.7.10
forgeVersion = 10.13.4.1614
# Specify a MCP channel and mappings version for dependency deobfuscation and the deobfParams task.
channel = stable
mappingsVersion = 12
# Define other MCP mappings for dependency deobfuscation
remoteMappings = https://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/
# Select a username for testing your mod with breakpoints. You may leave this empty for a random username each time you
# restart Minecraft in development. Choose this dependent on your mod:
# Do you need consistent player progressing (for example Thaumcraft)? -> Select a name
# Do you need to test how your custom blocks interacts with a player that is not the owner? -> leave name empty
developmentEnvironmentUserName = Developer
# Define a source file of your project with:
# public static final String VERSION = "GRADLETOKEN_VERSION";
# The string's content will be replaced with your mod's version when compiled. You should use this to specify your mod's
# version in @Mod([...], version = VERSION, [...])
# Leave these properties empty to skip individual token replacements
replaceGradleTokenInFile = Tags.java
gradleTokenModId = GRADLETOKEN_MODID
gradleTokenModName = GRADLETOKEN_MODNAME
gradleTokenVersion = GRADLETOKEN_VERSION
gradleTokenGroupName = GRADLETOKEN_GROUPNAME
# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can
# leave this property empty.
# Example value: apiPackage = api + modGroup = com.myname.mymodid -> com.myname.mymodid.api
apiPackage =
# Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/META-INF/
# Example value: mymodid_at.cfg
accessTransformersFile =
# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled!
usesMixins = true
# Adds some debug arguments like verbose output and export
usesMixinDebug = false
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
mixinPlugin = mixinplugin.MixinPlugin
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
mixinsPackage = mixins
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
# This parameter is for legacy compatibility only
# Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin
coreModClass =
# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class
# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false!
containsMixinsAndOrCoreModOnly = false
# Enables Mixins even if this mod doesn't use them, useful if one of the dependencies uses mixins.
forceEnableMixins = false
# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated in your jar. It is your
# responsibility check the licence and request permission for distribution, if required.
usesShadowedDependencies = false
# Optional parameter to customize the produced artifacts. Use this to preserver artifact naming when migrating older
# projects. New projects should not use this parameter.
#customArchiveBaseName =
# Optional parameter to prevent the source code from being published
# noPublishedSources =
Binary file not shown.
+1 -2
View File
@@ -1,6 +1,5 @@
#Wed Jul 02 15:54:47 CDT 2014
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
+5
View File
@@ -0,0 +1,5 @@
// Add any additional repositories for your dependencies here
repositories {
}
+10
View File
@@ -0,0 +1,10 @@
plugins {
id 'com.diffplug.blowdryerSetup' version '1.6.0'
}
apply plugin: 'com.diffplug.blowdryerSetup'
blowdryerSetup {
github('GTNewHorizons/ExampleMod1.7.10', 'tag', '0.1.4')
//devLocal '.' // Use this when testing config updates locally
}
@@ -1,17 +1,18 @@
package vfyjxf.bettercrashes;
import cpw.mods.fml.common.Mod;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@Mod(modid = BetterCrashes.MODID, version = BetterCrashes.VERSION, name = BetterCrashes.NAME,dependencies = BetterCrashes.DEPENDENCIES)
@Mod(
modid = BetterCrashes.MODID,
version = BetterCrashes.VERSION,
name = BetterCrashes.NAME,
dependencies = BetterCrashes.DEPENDENCIES)
public class BetterCrashes {
public static final String MODID = "bettercrashes";
public static final String NAME = "BetterCrashes";
public static final String VERSION = "@VERSION@";
public static final String DEPENDENCIES = "required-after:grimoire";
public static final String DEPENDENCIES = "";
public static final Logger logger = LogManager.getLogger("BetterCrashes");
}
@@ -1,19 +1,21 @@
package vfyjxf.bettercrashes;
import net.minecraftforge.common.config.Configuration;
import java.io.File;
import net.minecraftforge.common.config.Configuration;
public class BetterCrashesConfig {
public static boolean enableUploadCrash = false;
public static boolean enableUploadCrash = false;
public static void loadConfig(File configFile){
public static void loadConfig(File configFile) {
Configuration config = new Configuration(configFile);
config.load();
enableUploadCrash = config.get("upload","enableUploadCrash",false,
"if true,we will use \"https://paste.ubuntu.com\" to upload crash report.").getBoolean();
enableUploadCrash = config.get(
"upload",
"enableUploadCrash",
false,
"if true,we will use \"https://paste.ubuntu.com\" to upload crash report.")
.getBoolean();
config.save();
}
}
@@ -1,23 +0,0 @@
package vfyjxf.bettercrashes;
import io.github.crucible.grimoire.common.api.grimmix.Grimmix;
import io.github.crucible.grimoire.common.api.grimmix.GrimmixController;
import io.github.crucible.grimoire.common.api.grimmix.lifecycle.IConfigBuildingEvent;
@Grimmix(id = "bettercrashesgrimmix", name = "Better Crashes Grimmix")
public class BetterCrashesGrimmix extends GrimmixController {
@Override
public void buildMixinConfigs(IConfigBuildingEvent event) {
event.createBuilder("bettercrashes/mixins.bettercrashes.json")
.mixinPackage("vfyjxf.bettercrashes.mixins")
.clientMixins("client.MixinMinecraft")
.commonMixins("MixinCrashReport")
.refmap("@MIXIN_REFMAP@")
.verbose(true)
.required(true)
.build();
}
}
@@ -0,0 +1,49 @@
package vfyjxf.bettercrashes.mixinplugin;
import static vfyjxf.bettercrashes.mixinplugin.TargetedMod.VANILLA;
import cpw.mods.fml.relauncher.FMLLaunchHandler;
import java.util.Arrays;
import java.util.List;
public enum Mixin {
//
// IMPORTANT: Do not make any references to any mod from this file. This file is loaded quite early on and if
// you refer to other mods you load them as well. The consequence is: You can't inject any previously loaded
// classes!
// Exception: Tags.java, as long as it is used for Strings only!
//
MinecraftMixin("minecraft.MinecraftMixin", Side.BOTH, VANILLA),
CrashReportMixin("minecraft.CrashReportMixin", Side.BOTH, VANILLA);
public final String mixinClass;
public final List<TargetedMod> targetedMods;
private final Side side;
Mixin(String mixinClass, Side side, TargetedMod... targetedMods) {
this.mixinClass = mixinClass;
this.targetedMods = Arrays.asList(targetedMods);
this.side = side;
}
Mixin(String mixinClass, TargetedMod... targetedMods) {
this.mixinClass = mixinClass;
this.targetedMods = Arrays.asList(targetedMods);
this.side = Side.BOTH;
}
public boolean shouldLoad(List<TargetedMod> loadedMods) {
return (side == Side.BOTH
|| side == Side.SERVER && FMLLaunchHandler.side().isServer()
|| side == Side.CLIENT && FMLLaunchHandler.side().isClient())
&& loadedMods.containsAll(targetedMods);
}
}
enum Side {
BOTH,
CLIENT,
SERVER;
}
@@ -0,0 +1,109 @@
package vfyjxf.bettercrashes.mixinplugin;
import static java.nio.file.Files.walk;
import static vfyjxf.bettercrashes.mixinplugin.TargetedMod.VANILLA;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
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 ru.timeconqueror.spongemixins.MinecraftURLClassPath;
public class MixinPlugin implements IMixinConfigPlugin {
private static final Logger LOG = LogManager.getLogger("BetterCrashes mixins");
private static final Path MODS_DIRECTORY_PATH = new File(Launch.minecraftHome, "mods/").toPath();
@Override
public void onLoad(String mixinPackage) {}
@Override
public String getRefMapperConfig() {
return null;
}
@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
return true;
}
@Override
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {}
// This method return a List<String> of mixins. Every mixins in this list will be loaded.
@Override
public List<String> getMixins() {
final boolean isDevelopmentEnvironment = (boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment");
List<TargetedMod> loadedMods = Arrays.stream(TargetedMod.values())
.filter(mod -> mod == VANILLA || (mod.loadInDevelopment && isDevelopmentEnvironment) || loadJarOf(mod))
.collect(Collectors.toList());
for (TargetedMod mod : TargetedMod.values()) {
if (loadedMods.contains(mod)) {
LOG.info("Found " + mod.modName + "! Integrating now...");
} else {
LOG.info("Could not find " + mod.modName + "! Skipping integration....");
}
}
List<String> mixins = new ArrayList<>();
for (Mixin mixin : Mixin.values()) {
if (mixin.shouldLoad(loadedMods)) {
mixins.add(mixin.mixinClass);
LOG.debug("Loading mixin: " + mixin.mixinClass);
}
}
return mixins;
}
private boolean loadJarOf(final TargetedMod mod) {
try {
File jar = findJarOf(mod);
if (jar == null) {
LOG.info("Jar not found for " + mod);
return false;
}
LOG.info("Attempting to add " + jar + " to the URL Class Path");
if (!jar.exists()) {
throw new FileNotFoundException(jar.toString());
}
MinecraftURLClassPath.addJar(jar);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public static File findJarOf(final TargetedMod mod) {
try {
return walk(MODS_DIRECTORY_PATH)
.filter(mod::isMatchingJar)
.map(Path::toFile)
.findFirst()
.orElse(null);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
@Override
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {}
@Override
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {}
}
@@ -0,0 +1,44 @@
package vfyjxf.bettercrashes.mixinplugin;
import com.google.common.io.Files;
import java.nio.file.Path;
public enum TargetedMod {
//
// IMPORTANT: Do not make any references to any mod from this file. This file is loaded quite early on and if
// you refer to other mods you load them as well. The consequence is: You can't inject any previously loaded
// classes!
// Exception: Tags.java, as long as it is used for Strings only!
//
// Replace with your injected mods here, but always keep VANILLA:
VANILLA("Minecraft", "unused", true);
public final String modName;
public final String jarNamePrefixLowercase;
// Optional dependencies can be omitted in development. Especially skipping GT5U will drastically speed up your game
// start!
public final boolean loadInDevelopment;
TargetedMod(String modName, String jarNamePrefix, boolean loadInDevelopment) {
this.modName = modName;
this.jarNamePrefixLowercase = jarNamePrefix.toLowerCase();
this.loadInDevelopment = loadInDevelopment;
}
public boolean isMatchingJar(Path path) {
final String pathString = path.toString();
final String nameLowerCase = Files.getNameWithoutExtension(pathString).toLowerCase();
final String fileExtension = Files.getFileExtension(pathString);
return nameLowerCase.startsWith(jarNamePrefixLowercase) && "jar".equals(fileExtension);
}
@Override
public String toString() {
return "TargetedMod{" + "modName='"
+ modName + '\'' + ", jarNamePrefixLowercase='"
+ jarNamePrefixLowercase + '\'' + '}';
}
}
@@ -4,9 +4,16 @@
*The source file uses the MIT License.
*/
package vfyjxf.bettercrashes.mixins;
package vfyjxf.bettercrashes.mixins.minecraft;
import cpw.mods.fml.common.ModContainer;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import org.apache.commons.lang3.StringUtils;
@@ -22,24 +29,31 @@ import vfyjxf.bettercrashes.utils.IPatchedCrashReport;
import vfyjxf.bettercrashes.utils.ModIdentifier;
import vfyjxf.bettercrashes.utils.StacktraceDeobfuscator;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
@Mixin(value = CrashReport.class, priority = 500)
public class CrashReportMixin implements IPatchedCrashReport {
@Shadow
@Final
private CrashReportCategory theReportCategory;
@Mixin(value = CrashReport.class,priority = 500)
public class MixinCrashReport implements IPatchedCrashReport {
@Shadow @Final private CrashReportCategory theReportCategory;
@Shadow @Final private Throwable cause;
@Shadow @Final private List<CrashReportCategory> crashReportSections;
@Shadow @Final private String description;
@Shadow
@Final
private Throwable cause;
@Shadow private static String getWittyComment() { return null; }
@Shadow
@Final
private List<CrashReportCategory> crashReportSections;
@Shadow
@Final
private String description;
@Shadow
private static String getWittyComment() {
return null;
}
private Set<ModContainer> suspectedMods;
@Override
public Set<ModContainer> getSuspectedMods() {
return suspectedMods;
@@ -82,13 +96,22 @@ public class MixinCrashReport implements IPatchedCrashReport {
StringBuilder builder = new StringBuilder();
builder.append("---- Minecraft Crash Report ----\n")
.append("// ").append(getVanillaFixComment())
.append("// ")
.append(getVanillaFixComment())
.append("\n\n")
.append("Time: ").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format(new Date())).append("\n")
.append("Description: ").append(description)
.append("Time: ")
.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format(new Date()))
.append("\n")
.append("Description: ")
.append(description)
.append("\n\n")
.append(stacktraceToString(cause).replace("\t", " ")) // Vanilla's getCauseStackTraceOrString doesn't print causes and suppressed exceptions
.append("\n\nA detailed walkthrough of the error, its code path and all known details is as follows:\n");
.append(stacktraceToString(cause)
.replace(
"\t",
" ")) // Vanilla's getCauseStackTraceOrString doesn't print causes and suppressed
// exceptions
.append(
"\n\nA detailed walkthrough of the error, its code path and all known details is as follows:\n");
for (int i = 0; i < 87; i++) {
builder.append("-");
@@ -126,7 +149,8 @@ public class MixinCrashReport implements IPatchedCrashReport {
String author = mod.getMetadata().authorList.get(0);
return "I blame " + author + ".";
}
} catch (Throwable ignored) {}
} catch (Throwable ignored) {
}
return getWittyComment();
}
@@ -4,10 +4,13 @@
*The source file uses the MIT License.
*/
package vfyjxf.bettercrashes.mixins.client;
package vfyjxf.bettercrashes.mixins.minecraft;
import cpw.mods.fml.client.SplashProgress;
import cpw.mods.fml.common.Loader;
import java.io.IOException;
import java.util.List;
import java.util.Queue;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.SoundHandler;
import net.minecraft.client.gui.*;
@@ -40,58 +43,114 @@ import vfyjxf.bettercrashes.utils.GuiCrashScreen;
import vfyjxf.bettercrashes.utils.GuiInitErrorScreen;
import vfyjxf.bettercrashes.utils.StateManager;
import java.io.IOException;
import java.util.List;
import java.util.Queue;
/**
* @author Runemoro
*/
@Mixin(Minecraft.class)
public abstract class MixinMinecraft{
public abstract class MinecraftMixin {
@Shadow @Final private static Logger logger;
@Shadow volatile boolean running;
@Shadow private boolean hasCrashed;
@Shadow private CrashReport crashReporter;
@Shadow public static byte[] memoryReserve;
@Shadow @Final private Queue field_152351_aB;// field_152351_aB --> scheduledTasks
@Shadow public EntityRenderer entityRenderer;
@Shadow private long field_83002_am;//field_83002_am-->debugCrashKeyPressTime
@Shadow public GameSettings gameSettings;
@Shadow public GuiIngame ingameGUI;
@Shadow private List defaultResourcePacks;
@Shadow private IReloadableResourceManager mcResourceManager;
@Shadow public FontRenderer fontRenderer;
@Shadow public TextureManager renderEngine;
@Shadow private LanguageManager mcLanguageManager;
@Shadow private SoundHandler mcSoundHandler;
@Shadow @Final private IMetadataSerializer metadataSerializer_;
@Shadow private Framebuffer framebufferMc;
@Shadow public GuiScreen currentScreen;
@Shadow private int leftClickCounter;
@Shadow public int displayWidth;
@Shadow public int displayHeight;
@Shadow
@Final
private static Logger logger;
@Shadow protected abstract void startGame() throws LWJGLException;
@Shadow public abstract void displayGuiScreen(GuiScreen guiScreenIn);
@Shadow public abstract CrashReport addGraphicsAndWorldToCrashReport(CrashReport theCrash);
@Shadow
volatile boolean running;
@Shadow protected abstract void runGameLoop();
@Shadow
private boolean hasCrashed;
@Shadow public abstract NetHandlerPlayClient getNetHandler();
@Shadow
private CrashReport crashReporter;
@Shadow public abstract void loadWorld(WorldClient worldClientIn);
@Shadow
public static byte[] memoryReserve;
@Shadow public abstract void freeMemory();
@Shadow
@Final
private Queue field_152351_aB; // field_152351_aB --> scheduledTasks
@Shadow public abstract void shutdownMinecraftApplet();
@Shadow
public EntityRenderer entityRenderer;
@Shadow public abstract void refreshResources();
@Shadow
private long field_83002_am; // field_83002_am-->debugCrashKeyPressTime
@Shadow protected abstract void checkGLError(String message);
@Shadow
public GameSettings gameSettings;
@Shadow public abstract void func_147120_f();// func_147120_f --> resetSize
@Shadow
public GuiIngame ingameGUI;
@Shadow
private List defaultResourcePacks;
@Shadow
private IReloadableResourceManager mcResourceManager;
@Shadow
public FontRenderer fontRenderer;
@Shadow
public TextureManager renderEngine;
@Shadow
private LanguageManager mcLanguageManager;
@Shadow
private SoundHandler mcSoundHandler;
@Shadow
@Final
private IMetadataSerializer metadataSerializer_;
@Shadow
private Framebuffer framebufferMc;
@Shadow
public GuiScreen currentScreen;
@Shadow
private int leftClickCounter;
@Shadow
public int displayWidth;
@Shadow
public int displayHeight;
@SuppressWarnings("MixinAnnotationTarget")
@Shadow
protected abstract void func_71384_a() throws LWJGLException; // func_71384_a --> startGame
@Shadow
public abstract void displayGuiScreen(GuiScreen guiScreenIn);
@Shadow
public abstract CrashReport addGraphicsAndWorldToCrashReport(CrashReport theCrash);
@Shadow
protected abstract void runGameLoop();
@Shadow
public abstract NetHandlerPlayClient getNetHandler();
@Shadow
public abstract void loadWorld(WorldClient worldClientIn);
@Shadow
public abstract void freeMemory();
@Shadow
public abstract void shutdownMinecraftApplet();
@Shadow
public abstract void refreshResources();
@Shadow
protected abstract void checkGLError(String message);
@Shadow
public abstract void func_147120_f(); // func_147120_f --> resetSize
private int clientCrashCount = 0;
private int serverCrashCount = 0;
@@ -101,10 +160,10 @@ public abstract class MixinMinecraft{
* @reason Overwrite Minecraft.run()
*/
@Overwrite
public void run(){
public void run() {
running = true;
try {
startGame();
func_71384_a();
} catch (Throwable throwable) {
CrashReport crashReport = CrashReport.makeCrashReport(throwable, "Initializing game");
crashReport.makeCategory("Initialization");
@@ -145,7 +204,6 @@ public abstract class MixinMinecraft{
} finally {
shutdownMinecraftApplet();
}
}
/**
@@ -159,7 +217,7 @@ public abstract class MixinMinecraft{
// Reset hasCrashed, debugCrashKeyPressTime, and crashIntegratedServerNextTick
hasCrashed = false;
field_83002_am = -1;
// crashIntegratedServerNextTick = false;
// crashIntegratedServerNextTick = false;
// Vanilla does this when switching to main menu but not our custom crash screen
// nor the out of memory screen (see https://bugs.mojang.com/browse/MC-128953)
@@ -167,19 +225,25 @@ public abstract class MixinMinecraft{
ingameGUI.getChatGUI().clearChatMessages();
// Display the crash screen
// runGUILoop(new GuiCrashScreen(report));
// runGUILoop(new GuiCrashScreen(report));
displayGuiScreen(new GuiCrashScreen(report));
} 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", t);
logger.error(
"An uncaught exception occured while displaying the crash screen, making normal report instead", t);
displayCrashReport(report);
System.exit(report.getFile() != null ? -1 : -2);
}
}
private void addInfoToCrash(CrashReport crashReport){
crashReport.getCategory().addCrashSectionCallable("Client Crashes Since Restart",() -> String.valueOf(clientCrashCount));
crashReport.getCategory().addCrashSectionCallable("Integrated Server Crashes Since Restart", () -> String.valueOf(serverCrashCount));
private void addInfoToCrash(CrashReport crashReport) {
crashReport
.getCategory()
.addCrashSectionCallable("Client Crashes Since Restart", () -> String.valueOf(clientCrashCount));
crashReport
.getCategory()
.addCrashSectionCallable(
"Integrated Server Crashes Since Restart", () -> String.valueOf(serverCrashCount));
}
/**
@@ -194,12 +258,15 @@ public abstract class MixinMinecraft{
originalMemoryReserveSize = memoryReserve.length;
memoryReserve = new byte[0];
}
} catch (Throwable ignored) {}
} catch (Throwable ignored) {
}
StateManager.resetStates();
if (getNetHandler() != null) {
getNetHandler().getNetworkManager().closeChannel(new ChatComponentText("[BetterCrashes] Client crashed"));
getNetHandler()
.getNetworkManager()
.closeChannel(new ChatComponentText("[BetterCrashes] Client crashed"));
}
loadWorld(null);
if (entityRenderer.isShaderActive()) {
@@ -210,14 +277,16 @@ public abstract class MixinMinecraft{
if (originalMemoryReserveSize != -1) {
try {
memoryReserve = new byte[originalMemoryReserveSize];
} catch (Throwable ignored) {}
} catch (Throwable ignored) {
}
}
System.gc();
} catch (Throwable t) {
logger.error("Failed to reset state after a crash", t);
try {
StateManager.resetStates();
} catch (Throwable ignored) {}
} catch (Throwable ignored) {
}
}
}
@@ -236,7 +305,8 @@ public abstract class MixinMinecraft{
mcResourceManager.registerReloadListener(mcLanguageManager);
refreshResources(); // TODO: Why is this necessary?
fontRenderer = new FontRenderer(gameSettings, new ResourceLocation("textures/font/ascii.png"), renderEngine, false);
fontRenderer = new FontRenderer(
gameSettings, new ResourceLocation("textures/font/ascii.png"), renderEngine, false);
mcResourceManager.registerReloadListener(fontRenderer);
mcSoundHandler = new SoundHandler(mcResourceManager, gameSettings);
@@ -245,11 +315,14 @@ public abstract class MixinMinecraft{
running = true;
try {
//noinspection deprecation
SplashProgress.pause();// Disable the forge splash progress screen
} catch (Throwable ignored) {}
SplashProgress.pause(); // Disable the forge splash progress screen
} catch (Throwable ignored) {
}
runGUILoop(new GuiInitErrorScreen(report));
} catch (Throwable t) {
logger.error("An uncaught exception occured while displaying the init error screen, making normal report instead", t);
logger.error(
"An uncaught exception occured while displaying the init error screen, making normal report instead",
t);
displayCrashReport(report);
System.exit(report.getFile() != null ? -1 : -2);
}
@@ -261,7 +334,10 @@ public abstract class MixinMinecraft{
*/
private void runGUILoop(GuiScreen screen) throws IOException {
displayGuiScreen(screen);
while (running && currentScreen != null && !(currentScreen instanceof GuiMainMenu) && !(Loader.isModLoaded("custommainmenu"))) {
while (running
&& currentScreen != null
&& !(currentScreen instanceof GuiMainMenu)
&& !(Loader.isModLoaded("custommainmenu"))) {
if (Display.isCreated() && Display.isCloseRequested()) {
System.exit(0);
}
@@ -277,11 +353,18 @@ public abstract class MixinMinecraft{
GL11.glViewport(0, 0, displayWidth, displayHeight);
// EntityRenderer.setupOverlayRendering
ScaledResolution scaledResolution = new ScaledResolution((Minecraft) (Object) this,displayWidth,displayHeight);
ScaledResolution scaledResolution =
new ScaledResolution((Minecraft) (Object) this, displayWidth, displayHeight);
GL11.glClear(256);
GL11.glMatrixMode(5889);
GL11.glLoadIdentity();
GL11.glOrtho(0.0D, scaledResolution.getScaledWidth_double(), scaledResolution.getScaledHeight_double(), 0, 1000, 3000);
GL11.glOrtho(
0.0D,
scaledResolution.getScaledWidth_double(),
scaledResolution.getScaledHeight_double(),
0,
1000,
3000);
GL11.glMatrixMode(5888);
GL11.glLoadIdentity();
GL11.glTranslatef(0, 0, -2000);
@@ -307,7 +390,6 @@ public abstract class MixinMinecraft{
}
}
/**
* @author Runemoro
* @reason
@@ -317,8 +399,4 @@ public abstract class MixinMinecraft{
public void displayCrashReport(CrashReport report) {
CrashUtils.outputReport(report);
}
}
@@ -1,6 +1,5 @@
package vfyjxf.bettercrashes.utils;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
@@ -9,7 +8,6 @@ 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();
@@ -32,5 +30,4 @@ public class CrashReportUpload {
}
return url + resultUrl;
}
}
@@ -6,15 +6,14 @@
package vfyjxf.bettercrashes.utils;
import net.minecraft.client.Minecraft;
import net.minecraft.crash.CrashReport;
import vfyjxf.bettercrashes.BetterCrashes;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import net.minecraft.client.Minecraft;
import net.minecraft.crash.CrashReport;
import vfyjxf.bettercrashes.BetterCrashes;
/**
* @author Runemoro
@@ -33,7 +32,9 @@ public class CrashUtils {
reportName += Minecraft.getMinecraft().func_152345_ab() ? "-client" : "-server";
reportName += ".txt";
File reportsDir = isClient() ? new File(Minecraft.getMinecraft().mcDataDir, "crash-reports") : new File("crash-reports");
File reportsDir = isClient()
? new File(Minecraft.getMinecraft().mcDataDir, "crash-reports")
: new File("crash-reports");
File reportFile = new File(reportsDir, reportName);
report.saveToFile(reportFile);
@@ -42,7 +43,10 @@ public class CrashUtils {
BetterCrashes.logger.fatal("Failed saving report", e);
}
BetterCrashes.logger.fatal("Minecraft ran into a problem! " + (report.getFile() != null ? "Report saved to: " + report.getFile() : "Crash report could not be saved.")
BetterCrashes.logger.fatal("Minecraft ran into a problem! "
+ (report.getFile() != null
? "Report saved to: " + report.getFile()
: "Crash report could not be saved.")
+ "\n" + report.getCompleteReport());
}
@@ -64,14 +68,13 @@ public class CrashUtils {
*/
public static void openCrashReport(CrashReport crashReport) throws IOException {
if(!Desktop.isDesktopSupported()){
if (!Desktop.isDesktopSupported()) {
BetterCrashes.logger.error("Desktop is not supported");
return;
}
File report = crashReport.getFile();
if(report.exists()){
if (report.exists()) {
Desktop.getDesktop().open(report);
}
}
}
@@ -14,7 +14,6 @@ import net.minecraft.client.gui.GuiOptionButton;
import net.minecraft.client.resources.I18n;
import net.minecraft.crash.CrashReport;
@SideOnly(Side.CLIENT)
public class GuiCrashScreen extends GuiProblemScreen {
public GuiCrashScreen(CrashReport report) {
@@ -24,7 +23,8 @@ public class GuiCrashScreen extends GuiProblemScreen {
@Override
public void initGui() {
super.initGui();
GuiOptionButton mainMenuButton = new GuiOptionButton(0, width / 2 - 50 - 115, height / 4 + 120 + 12, 110, 20, I18n.format("bettercrashes.gui.toTitle"));
GuiOptionButton mainMenuButton = new GuiOptionButton(
0, width / 2 - 50 - 115, height / 4 + 120 + 12, 110, 20, I18n.format("bettercrashes.gui.toTitle"));
buttonList.add(mainMenuButton);
}
@@ -39,7 +39,8 @@ public class GuiCrashScreen extends GuiProblemScreen {
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) { // TODO: localize number of lines
drawDefaultBackground();
drawCenteredString(fontRendererObj, I18n.format("bettercrashes.crashscreen.title"), width / 2, height / 4 - 40, 0xFFFFFF);
drawCenteredString(
fontRendererObj, I18n.format("bettercrashes.crashscreen.title"), width / 2, height / 4 - 40, 0xFFFFFF);
int textColor = 0xD0D0D0;
int x = width / 2 - 155;
@@ -52,7 +53,14 @@ public class GuiCrashScreen extends GuiProblemScreen {
drawString(fontRendererObj, I18n.format("bettercrashes.crashscreen.paragraph2.line1"), x, y += 11, textColor);
drawCenteredString(fontRendererObj, report.getFile() != null ? "\u00A7n" + report.getFile().getName() : I18n.format("vanillafix.crashscreen.reportSaveFailed"), width / 2, y += 11, 0x00FF00);
drawCenteredString(
fontRendererObj,
report.getFile() != null
? "\u00A7n" + report.getFile().getName()
: I18n.format("vanillafix.crashscreen.reportSaveFailed"),
width / 2,
y += 11,
0x00FF00);
drawString(fontRendererObj, I18n.format("bettercrashes.crashscreen.paragraph3.line1"), x, y += 12, textColor);
drawString(fontRendererObj, I18n.format("bettercrashes.crashscreen.paragraph3.line2"), x, y += 9, textColor);
@@ -4,7 +4,6 @@
*The source file uses the MIT License.
*/
package vfyjxf.bettercrashes.utils;
import cpw.mods.fml.relauncher.Side;
@@ -14,7 +13,7 @@ import net.minecraft.client.resources.I18n;
import net.minecraft.crash.CrashReport;
@SideOnly(Side.CLIENT)
public class GuiInitErrorScreen extends GuiProblemScreen{
public class GuiInitErrorScreen extends GuiProblemScreen {
public GuiInitErrorScreen(CrashReport report) {
super(report);
@@ -24,8 +23,15 @@ public class GuiInitErrorScreen extends GuiProblemScreen{
public void initGui() {
mc.setIngameNotInFocus();
buttonList.clear();
buttonList.add(new GuiButton(1,width / 2 - 155, height / 4 + 120 + 12, 150, 20, I18n.format("bettercrashes.gui.openCrashReport")));
buttonList.add(new GuiButton(2, width / 2 - 155 + 160, height / 4 + 120 + 12, 150, 20, I18n.format("bettercrashes.gui.uploadReportAndCopyLink")));
buttonList.add(new GuiButton(
1, width / 2 - 155, height / 4 + 120 + 12, 150, 20, I18n.format("bettercrashes.gui.openCrashReport")));
buttonList.add(new GuiButton(
2,
width / 2 - 155 + 160,
height / 4 + 120 + 12,
150,
20,
I18n.format("bettercrashes.gui.uploadReportAndCopyLink")));
}
@Override
@@ -36,7 +42,12 @@ public class GuiInitErrorScreen extends GuiProblemScreen{
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) { // TODO: localize number of lines
drawDefaultBackground();
drawCenteredString(fontRendererObj, I18n.format("bettercrashes.initerrorscreen.title"), width / 2, height / 4 - 40, 0xFFFFFF);
drawCenteredString(
fontRendererObj,
I18n.format("bettercrashes.initerrorscreen.title"),
width / 2,
height / 4 - 40,
0xFFFFFF);
int textColor = 0xD0D0D0;
int x = width / 2 - 155;
@@ -49,12 +60,23 @@ public class GuiInitErrorScreen extends GuiProblemScreen{
drawString(fontRendererObj, I18n.format("bettercrashes.crashscreen.paragraph2.line1"), x, y += 11, textColor);
drawCenteredString(fontRendererObj, report.getFile() != null ? "\u00A7n" + report.getFile().getName() : I18n.format("vanillafix.crashscreen.reportSaveFailed"), width / 2, y += 11, 0x00FF00);
drawCenteredString(
fontRendererObj,
report.getFile() != null
? "\u00A7n" + report.getFile().getName()
: I18n.format("vanillafix.crashscreen.reportSaveFailed"),
width / 2,
y += 11,
0x00FF00);
drawString(fontRendererObj, I18n.format("bettercrashes.initerrorscreen.paragraph3.line1"), x, y += 12, textColor);
drawString(fontRendererObj, I18n.format("bettercrashes.initerrorscreen.paragraph3.line2"), x, y += 9, textColor);
drawString(fontRendererObj, I18n.format("bettercrashes.initerrorscreen.paragraph3.line3"), x, y += 9, textColor);
drawString(fontRendererObj, I18n.format("bettercrashes.initerrorscreen.paragraph3.line4"), x, y += 9, textColor);
drawString(
fontRendererObj, I18n.format("bettercrashes.initerrorscreen.paragraph3.line1"), x, y += 12, textColor);
drawString(
fontRendererObj, I18n.format("bettercrashes.initerrorscreen.paragraph3.line2"), x, y += 9, textColor);
drawString(
fontRendererObj, I18n.format("bettercrashes.initerrorscreen.paragraph3.line3"), x, y += 9, textColor);
drawString(
fontRendererObj, I18n.format("bettercrashes.initerrorscreen.paragraph3.line4"), x, y += 9, textColor);
super.drawScreen(mouseX, mouseY, partialTicks);
}
}
@@ -9,20 +9,18 @@ package vfyjxf.bettercrashes.utils;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
import net.minecraft.crash.CrashReport;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@SideOnly(Side.CLIENT)
public abstract class GuiProblemScreen extends GuiScreen{
public abstract class GuiProblemScreen extends GuiScreen {
protected final CrashReport report;
private String hasteLink = null;
@@ -36,13 +34,20 @@ public abstract class GuiProblemScreen extends GuiScreen{
public void initGui() {
mc.setIngameNotInFocus();
buttonList.clear();
buttonList.add(new GuiButton(1, width / 2 - 50, height / 4 + 120 + 12, 110, 20, I18n.format("bettercrashes.gui.openCrashReport")));
buttonList.add(new GuiButton(2, width / 2 - 50 + 115, height / 4 + 120 + 12, 110, 20, I18n.format("bettercrashes.gui.uploadReportAndCopyLink")));
buttonList.add(new GuiButton(
1, width / 2 - 50, height / 4 + 120 + 12, 110, 20, I18n.format("bettercrashes.gui.openCrashReport")));
buttonList.add(new GuiButton(
2,
width / 2 - 50 + 115,
height / 4 + 120 + 12,
110,
20,
I18n.format("bettercrashes.gui.uploadReportAndCopyLink")));
}
@Override
protected void actionPerformed(GuiButton button) {
if (button.id == 1){
if (button.id == 1) {
try {
CrashUtils.openCrashReport(report);
} catch (IOException e) {
@@ -51,10 +56,11 @@ public abstract class GuiProblemScreen extends GuiScreen{
e.printStackTrace();
}
}
if(button.id == 2){
if(hasteLink == null){
if (button.id == 2) {
if (hasteLink == null) {
try {
hasteLink = CrashReportUpload.uploadToUbuntuPastebin("https://paste.ubuntu.com",report.getCompleteReport());
hasteLink = CrashReportUpload.uploadToUbuntuPastebin(
"https://paste.ubuntu.com", report.getCompleteReport());
} catch (IOException e) {
button.displayString = I18n.format("bettercrashes.gui.failed");
button.enabled = false;
@@ -63,7 +69,6 @@ public abstract class GuiProblemScreen extends GuiScreen{
}
setClipboardString(hasteLink);
}
}
@Override
@@ -7,7 +7,6 @@
package vfyjxf.bettercrashes.utils;
import cpw.mods.fml.common.ModContainer;
import java.util.Set;
/**
@@ -4,6 +4,8 @@ import net.minecraft.crash.CrashReport;
public interface IPatchedMinecraft {
boolean shouldCrashIntegratedServerNextTick();
void showWarningScreen(CrashReport report);
void makeErrorNotification(CrashReport report);
}
@@ -8,17 +8,16 @@ package vfyjxf.bettercrashes.utils;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModContainer;
import net.minecraft.launchwrapper.Launch;
import net.minecraft.launchwrapper.LaunchClassLoader;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
import net.minecraft.launchwrapper.Launch;
import net.minecraft.launchwrapper.LaunchClassLoader;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* @author Runemoro
@@ -65,7 +64,8 @@ public final class ModIdentifier {
// Get the mod containing that class
try {
if (url.getProtocol().equals("jar")) url = new URL(url.getFile().substring(0, url.getFile().indexOf('!')));
if (url.getProtocol().equals("jar"))
url = new URL(url.getFile().substring(0, url.getFile().indexOf('!')));
return modMap.get(new File(url.toURI()).getCanonicalFile());
} catch (URISyntaxException | IOException e) {
throw new RuntimeException(e);
@@ -86,7 +86,8 @@ public final class ModIdentifier {
try {
modMap.remove(Loader.instance().getMinecraftModContainer().getSource()); // Ignore minecraft jar (minecraft)
modMap.remove(Loader.instance().getIndexedModList().get("FML").getSource()); // Ignore forge jar (FML, forge)
modMap.remove(
Loader.instance().getIndexedModList().get("FML").getSource()); // Ignore forge jar (FML, forge)
} catch (NullPointerException ignored) {
// Workaround for https://github.com/MinecraftForge/MinecraftForge/issues/4919
}
@@ -20,7 +20,8 @@ import java.util.zip.ZipInputStream;
* @author Runemoro
*/
public final class StacktraceDeobfuscator {
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 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;
/**
@@ -34,7 +35,8 @@ public final class StacktraceDeobfuscator {
if (!mappings.exists()) {
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");
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();
connection.setDoInput(true);
connection.connect();
@@ -72,9 +74,11 @@ public final class StacktraceDeobfuscator {
String mappingLine = scanner.nextLine();
int commaIndex = mappingLine.indexOf(',');
String srgName = mappingLine.substring(0, commaIndex);
String mcpName = mappingLine.substring(commaIndex + 1, commaIndex + 1 + mappingLine.substring(commaIndex + 1).indexOf(','));
String mcpName = mappingLine.substring(
commaIndex + 1,
commaIndex + 1 + mappingLine.substring(commaIndex + 1).indexOf(','));
//System.out.println(srgName + " <=> " + mcpName);
// System.out.println(srgName + " <=> " + mcpName);
if (!DEBUG_IN_DEV) {
srgMcpMethodMap.put(srgName, mcpName);
} else {
@@ -103,7 +107,8 @@ public final class StacktraceDeobfuscator {
public static StackTraceElement[] deobfuscateStacktrace(StackTraceElement[] stackTrace) {
int index = 0;
for (StackTraceElement el : stackTrace) {
stackTrace[index++] = new StackTraceElement(el.getClassName(), deobfuscateMethodName(el.getMethodName()), el.getFileName(), el.getLineNumber());
stackTrace[index++] = new StackTraceElement(
el.getClassName(), deobfuscateMethodName(el.getMethodName()), el.getFileName(), el.getLineNumber());
}
return stackTrace;
}
@@ -114,7 +119,8 @@ public final class StacktraceDeobfuscator {
}
String mcpName = srgMcpMethodMap.get(srgName);
// log.debug(srgName + " <=> " + mcpName != null ? mcpName : "?"); // Can't do this, it would be a recursive call to log appender
// log.debug(srgName + " <=> " + mcpName != null ? mcpName : "?"); // Can't do this, it would be a recursive
// call to log appender
return mcpName != null ? mcpName : srgName;
}
+10 -8
View File
@@ -1,14 +1,16 @@
[{
"modid": "${mod_id}",
"name": "${mod_name}",
"description": "${mod_description}",
"version": "${mod_version}",
"mcversion": "${mc_version}",
"url": "",
"modid": "${modId}",
"name": "${modName}",
"description": "BetterCrashes makes Minecraft return you to the main menu when it crashes.",
"version": "${modVersion}",
"mcversion": "${minecraftVersion}",
"url": "https://github.com/GTNewHorizons/BetterCrashes",
"updateUrl": "",
"authorList": ["${mod_author}"],
"authorList": [
"vfyjxf"
],
"credits": "",
"logoFile": "${mod_icon}",
"logoFile": "",
"screenshots": [],
"dependencies": []
}]
@@ -0,0 +1,12 @@
{
"required": true,
"minVersion": "0.7.11",
"package": "vfyjxf.bettercrashes.mixins",
"plugin": "vfyjxf.bettercrashes.mixinplugin.MixinPlugin",
"refmap": "mixins.bettercrashes.refmap.json",
"target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_8",
"mixins": [],
"client": [],
"server": []
}