diff --git a/.github/workflows/staging-build.yml b/.github/workflows/staging-build.yml index caa1686d..a0acbe99 100644 --- a/.github/workflows/staging-build.yml +++ b/.github/workflows/staging-build.yml @@ -64,3 +64,4 @@ jobs: This is the most up-to-date build available. files: | build/distributions/* + java9args.txt diff --git a/build.gradle b/build.gradle.bak similarity index 92% rename from build.gradle rename to build.gradle.bak index 464a6257..d0851a8d 100644 --- a/build.gradle +++ b/build.gradle.bak @@ -42,6 +42,10 @@ repositories { name 'minecraft' url 'https://libraries.minecraft.net/' } + maven { + name 'gtnh' + url 'https://nexus.gtnewhorizons.com/repository/public/' + } } minecraft { @@ -57,6 +61,7 @@ minecraft { 'https://github.com/juanmuscaria/maven/raw/master', 'https://maven.minecraftforge.net/', 'https://oss.sonatype.org/content/repositories/snapshots/', + 'https://nexus.gtnewhorizons.com/repository/public/', 'https://libraries.minecraft.net/' ] } @@ -81,13 +86,17 @@ configurations { dependencies { // New java stuff - libraries 'org.apache.commons:commons-lang3:3.12.0' - libraries 'org.apache.commons:commons-compress:1.21' - libraries 'org.ow2.asm:asm:9.5' - libraries 'org.ow2.asm:asm-commons:9.5' - libraries 'org.ow2.asm:asm-tree:9.5' - libraries 'org.ow2.asm:asm-analysis:9.5' - libraries 'org.ow2.asm:asm-util:9.5' + libraries('com.gtnewhorizons.retrofuturabootstrap:RetroFuturaBootstrap:1.0.16') { + exclude group: 'org.apache.logging.log4j' + } + libraries 'com.google.code.gson:gson:2.14.0' + libraries 'org.apache.commons:commons-lang3:3.17.0' + libraries 'org.apache.commons:commons-compress:1.27.1' + libraries 'org.ow2.asm:asm:9.9.1' + libraries 'org.ow2.asm:asm-commons:9.9.1' + libraries 'org.ow2.asm:asm-tree:9.9.1' + libraries 'org.ow2.asm:asm-analysis:9.9.1' + libraries 'org.ow2.asm:asm-util:9.9.1' libraries 'org.ow2.asm:asm-deprecated:7.1' libraries 'jakarta.xml.bind:jakarta.xml.bind-api:3.0.1' libraries "javax.servlet:javax.servlet-api:4.0.1" @@ -96,14 +105,12 @@ dependencies { libraries 'it.unimi.dsi:fastutil:8.5.12' // Other libs - libraries 'pw.prok:Damask:0.1.2@jar' libraries 'commons-cli:commons-cli:1.3@jar' libraries 'org.slf4j:slf4j-simple:1.6.2@jar' libraries 'org.eclipse.jetty:jetty-servlet:9.0.3.v20130506@jar' - libraries 'commons-io:commons-io:2.4@jar' + libraries 'commons-io:commons-io:2.18.0' libraries 'net.sf.opencsv:opencsv:2.0@jar' libraries 'com.beust:jcommander:1.30@jar' - libraries 'io.github.cruciblemc:launchwrapper:1.13@jar' libraries 'com.typesafe.akka:akka-actor_2.11:2.3.3' libraries 'com.typesafe:config:1.2.1' libraries 'org.scala-lang:scala-actors-migration_2.11:1.1.0' @@ -127,7 +134,6 @@ dependencies { libraries 'org.xerial:sqlite-jdbc:3.7.2' libraries 'mysql:mysql-connector-java:5.1.14' libraries 'javax.persistence:persistence-api:1.0.2' - libraries 'pw.prok:KImagine:0.2.0@jar' libraries 'org.apache.httpcomponents:httpclient:4.4.1' libraries 'net.openhft:affinity:3.0.1' libraries 'org.fusesource.jansi:jansi:1.11' diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..98d7154d --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,286 @@ +import org.gradle.api.tasks.bundling.Jar +import org.gradle.api.tasks.bundling.Zip +import org.gradle.api.publish.maven.MavenPublication +import io.github.cruciblemc.forgegradle.tasks.DelayedJar +import java.io.ByteArrayOutputStream + +plugins { + base + id("maven-publish") + id("java-library") + id("crucible") // Assuming this is a custom plugin still available +} + +buildscript { + repositories { + mavenCentral() + // mavenLocal() // for testing plugin pre release + maven { + name = "juanmuscaria" + url = uri("https://github.com/juanmuscaria/maven/raw/master") + } + maven { + name = "forge" + url = uri("https://maven.minecraftforge.net/") + } + } + dependencies { + classpath("com.anatawa12.forge:ForgeGradle:1.2-1.1.0") + } +} + +repositories { + maven { + name = "juanmuscaria" + url = uri("https://github.com/juanmuscaria/maven/raw/master") + } + maven { + name = "thermos" + url = uri("https://github.com/juanmuscaria/maven/raw/master/ThermosLibs") + } + maven { + name = "forge" + url = uri("https://maven.minecraftforge.net/") + } + maven { + name = "minecraft" + url = uri("https://libraries.minecraft.net/") + } + maven { + name = "gtnh" + url = uri("https://nexus.gtnewhorizons.com/repository/public/") + } +} + +configure { + version = "1.7.10" + mcpVersion = "9.08" + mainClass = "cpw.mods.fml.relauncher.ServerLaunchWrapper" + tweakClass = "cpw.mods.fml.common.launcher.FMLTweaker" + installerVersion = "1.4" + + // Repos used on the generated subprojects + repos = listOf("https://github.com/juanmuscaria/maven/raw/master/ThermosLibs", + "https://github.com/juanmuscaria/maven/raw/master", + "https://maven.minecraftforge.net/", + "https://oss.sonatype.org/content/repositories/snapshots/", + "https://nexus.gtnewhorizons.com/repository/public/", + "https://libraries.minecraft.net/") +} + +extensions.configure("ext") { + set("mcVersion", "1.7.10") + set("forgeVersion", "1614") + set("revision", "1.0.7") +} + +group = "io.github.cruciblemc" + +val crucibleVersion = "5.4" // TODO: Not hardcode +version = if (gitInfo("branch") != "master") { + "${extra["mcVersion"]}-${gitInfo("branch")}-${gitInfo("hash")}" +} else { + "${extra["mcVersion"]}-$crucibleVersion" +} + +val libraries by configurations.creating { + isCanBeConsumed = false; isCanBeResolved = true; +} + +configurations["implementation"].extendsFrom(libraries) + +dependencies { + "libraries"("com.gtnewhorizons.retrofuturabootstrap:RetroFuturaBootstrap:1.1.0") { + exclude(group = "org.apache.logging.log4j") + } + "libraries"("com.google.code.gson:gson:2.14.0") + "libraries"("org.apache.commons:commons-lang3:3.17.0") + "libraries"("org.apache.commons:commons-compress:1.27.1") + "libraries"("org.ow2.asm:asm:9.9.1") + "libraries"("org.ow2.asm:asm-commons:9.9.1") + "libraries"("org.ow2.asm:asm-tree:9.9.1") + "libraries"("org.ow2.asm:asm-analysis:9.9.1") + "libraries"("org.ow2.asm:asm-util:9.9.1") + "libraries"("org.ow2.asm:asm-deprecated:7.1") + "libraries"("jakarta.xml.bind:jakarta.xml.bind-api:3.0.1") + "libraries"("javax.servlet:javax.servlet-api:4.0.1") + "libraries"("com.sun.xml.bind:jaxb-impl:3.0.2") + "libraries"("org.openjdk.nashorn:nashorn-core:15.4") + "libraries"("it.unimi.dsi:fastutil:8.5.12") + + // Other libs + "libraries"("commons-cli:commons-cli:1.3@jar") + "libraries"("org.slf4j:slf4j-simple:1.6.2@jar") + "libraries"("org.eclipse.jetty:jetty-servlet:9.0.3.v20130506@jar") + "libraries"("commons-io:commons-io:2.18.0") + "libraries"("net.sf.opencsv:opencsv:2.0@jar") + "libraries"("com.beust:jcommander:1.30@jar") + "libraries"("io.github.cruciblemc:launchwrapper:1.13@jar") + "libraries"("com.typesafe.akka:akka-actor_2.11:2.3.3") + "libraries"("com.typesafe:config:1.2.1") + "libraries"("org.scala-lang:scala-actors-migration_2.11:1.1.0") + "libraries"("org.scala-lang:scala-compiler:2.11.7") + "libraries"("org.scala-lang.plugins:scala-continuations-library_2.11:1.0.2") + "libraries"("org.scala-lang.plugins:scala-continuations-plugin_2.11.2:1.0.2") + "libraries"("org.scala-lang:scala-library:2.11.7") + "libraries"("org.scala-lang:scala-parser-combinators:2.11.0-M4") + "libraries"("org.scala-lang:scala-reflect:2.11.7") + "libraries"("org.scala-lang:scala-swing:2.11.0-M7") + "libraries"("org.scala-lang:scala-xml:2.11.0-M4") + "libraries"("net.sf.jopt-simple:jopt-simple:5.0.1") + "libraries"("lzma:lzma:0.0.1") + "libraries"("org.yaml:snakeyaml:1.9") + "libraries"("commons-lang:commons-lang:2.6") + "libraries"("org.avaje:ebean:2.7.3") + "libraries"("jline:jline:2.6") + "libraries"("net.md-5:SpecialSource:1.10.0") + "libraries"("net.sourceforge.argo:argo:2.25") + "libraries"("com.googlecode.json-simple:json-simple:1.1") + "libraries"("org.xerial:sqlite-jdbc:3.7.2") + "libraries"("mysql:mysql-connector-java:5.1.14") + "libraries"("javax.persistence:persistence-api:1.0.2") + "libraries"("pw.prok:KImagine:0.2.0@jar") + "libraries"("org.apache.httpcomponents:httpclient:4.4.1") + "libraries"("net.openhft:affinity:3.0.1") + "libraries"("org.fusesource.jansi:jansi:1.11") + "libraries"("com.koloboke:koloboke-impl-jdk8:1.0.0") + "libraries"("java3d:vecmath:1.3.1") + "libraries"("net.minecraft:server:1.7.10") +} + +tasks.register("packageJavadoc") { + dependsOn(":eclipse:cauldron:javadoc") + archiveClassifier.set("javadoc") + destinationDirectory.set(layout.buildDirectory.dir("libs")) +} + +tasks.named("jar").configure { + manifest { + attributes( + mapOf( + "Thermos-Git-Branch" to gitInfo("branch"), + "Thermos-Git-Hash" to gitInfo("fullHash"), + "Thermos-Group" to project.group, + "Thermos-Channel" to project.name, + "Thermos-Version" to project.version, + "Thermos-Legacy" to true, + "Implementation-Vendor" to "CrucibleMC Team", + "Implementation-Title" to project.name, + "Implementation-Version" to project.version, + "Specification-Vendor" to "Bukkit Team", + "Specification-Title" to "Bukkit", + "Specification-Version" to "1.7.10-R0.1-SNAPSHOT", + "Forge-Version" to "10.13.4.1614", + "TweakClass" to "cpw.mods.fml.common.launcher.FMLTweaker", + "Main-Class" to "cpw.mods.fml.relauncher.ServerLaunchWrapper", + "Class-Path" to generateClasspath(), + "Crucible-Libs" to generateMavenLibs() + ) + ) + } +} + +tasks.named("packageServer").configure { + doFirst { + manifest { + attributes( + mapOf( + "Thermos-Git-Branch" to gitInfo("branch"), + "Thermos-Git-Hash" to gitInfo("fullHash"), + "Thermos-Group" to project.group, + "Thermos-Channel" to project.name, + "Thermos-Version" to project.version, + "Thermos-Legacy" to true, + "Implementation-Vendor" to "CrucibleMC Team", + "Implementation-Title" to project.name, + "Implementation-Version" to project.version, + "Specification-Vendor" to "Bukkit Team", + "Specification-Title" to "Bukkit", + "Specification-Version" to "1.7.10-R0.1-SNAPSHOT", + "Forge-Version" to "10.13.4.1614", + "TweakClass" to "cpw.mods.fml.common.launcher.FMLTweaker", + "Main-Class" to "cpw.mods.fml.relauncher.ServerLaunchWrapper", + "Class-Path" to generateClasspath(), + "Crucible-Libs" to generateMavenLibs() + ) + ) + } + } +} + +tasks.register("packageLibraries") { + archiveFileName.set("libraries.zip") + destinationDirectory.set(layout.buildDirectory.dir("distributions")) + + outputs.upToDateWhen { false } + + from(configurations.named("libraries").get().resolvedConfiguration.resolvedArtifacts.map { art -> + val id = art.moduleVersion.id + val intoPath = "${id.group.replace('.', '/')}/${id.name}/${id.version}/" + zipTree(art.file).matching { }.let { copySpec -> + //copySpec.into(intoPath) + } + art.file + }) + + group = "crucible" + description = "Package all necessary libraries to run Crucible, in case the server cannot download them at runtime" +} + +publishing { + publications { + create("crucible") { + artifact(tasks.named("packageApi")) + artifact(tasks.named("packageJavadoc")) + } + } + repositories { + maven { + name = "filesystem" + url = uri("${buildDir}/repo") + } + } +} + +// Git helper +fun gitInfo(key: String): String { + val cache = project.extra.properties.getOrPut("gitInfoCached") { + if (file(".git").exists()) { + mapOf( + "hash" to runGit("log", "--format=%h", "-n", "1"), + "fullHash" to runGit("log", "--format=%H", "-n", "1"), + "branch" to runGit("rev-parse", "--abbrev-ref", "HEAD"), + "message" to runGit("log", "--format=%B", "-n", "1") + ) + } else { + mapOf( + "hash" to "NOT_A_GIT", + "fullHash" to "NOT_A_GIT", + "branch" to "NOT_A_GIT", + "message" to "NOT_A_GIT" + ) + } + } as Map<*, *> + return cache[key] as String +} + +fun runGit(vararg args: String): String { + val stdout = ByteArrayOutputStream() + project.exec { + commandLine("git", *args) + standardOutput = stdout + } + return stdout.toString().trim() +} + +fun generateClasspath(): String = + configurations["libraries"].resolvedConfiguration.resolvedArtifacts.joinToString(" ") { art -> + val id = art.moduleVersion.id + "libraries/${id.group.replace('.', '/')}/${id.name}/${id.version}/${id.name}-${id.version}.jar" + } + +fun generateMavenLibs(): String = + configurations["libraries"].resolvedConfiguration.resolvedArtifacts.joinToString(" ") { art -> + val id = art.moduleVersion.id + "${id.group}:${id.name}:${id.version}" + } \ No newline at end of file diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 8f3c8af6..5305ac66 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -16,8 +16,8 @@ repositories { dependencies { // TODO? figure a way to use the runtime dependencies of FG? - implementation("org.ow2.asm:asm:9.6") - implementation("org.ow2.asm:asm-tree:9.6") + implementation("org.ow2.asm:asm:9.8") + implementation("org.ow2.asm:asm-tree:9.8") implementation("com.google.guava:guava:31.1-jre") implementation("com.opencsv:opencsv:5.7.0") implementation("com.cloudbees:diff4j:1.3") @@ -33,7 +33,7 @@ dependencies { implementation("de.oceanlabs.mcp:mcinjector:3.2-SNAPSHOT") implementation("net.minecraftforge:Srg2Source:4.2.7") - api("com.anatawa12.forge:ForgeGradle:1.2-1.1.0") + api("com.anatawa12.forge:ForgeGradle:1.2-1.1.1") testImplementation(platform("org.junit:junit-bom:5.9.1")) testImplementation("org.junit.jupiter:junit-jupiter") diff --git a/buildSrc/src/main/java/io/github/cruciblemc/forgegradle/DevExtension.java b/buildSrc/src/main/java/io/github/cruciblemc/forgegradle/DevExtension.java index 7d6da07b..cc0b92e5 100644 --- a/buildSrc/src/main/java/io/github/cruciblemc/forgegradle/DevExtension.java +++ b/buildSrc/src/main/java/io/github/cruciblemc/forgegradle/DevExtension.java @@ -1,128 +1,84 @@ package io.github.cruciblemc.forgegradle; -import groovy.lang.Closure; +import lombok.Getter; +import lombok.Setter; import net.minecraftforge.gradle.common.BaseExtension; import org.gradle.api.Action; import org.gradle.api.Project; -import org.gradle.util.ClosureBackedAction; -public class DevExtension extends BaseExtension { - private String fmlDir; - private String forgeDir; - private String bukkitDir; - private String mainClass; - private String tweakClass; - private String[] repos = new String[0]; - private boolean makeJavadoc = true; - private String installerVersion = "null"; - private Action subprojects = null; - private Action cleanProject = null; - private Action dirtyProject = null; - - public DevExtension(DevBasePlugin plugin) { - super(plugin); - } - - public String getFmlDir() { - return fmlDir == null ? project.getProjectDir().getPath().replace('\\', '/') : fmlDir.replace('\\', '/'); - } - - public void setFmlDir(String fmlDir) { - this.fmlDir = fmlDir; - } - - public String getForgeDir() { - return forgeDir == null ? project.getProjectDir().getPath().replace('\\', '/') : forgeDir.replace('\\', '/'); - } - - public void setForgeDir(String forgeDir) { - this.forgeDir = forgeDir; - } - - public String getBukkitDir() { - return bukkitDir == null ? project.getProjectDir().getPath().replace('\\', '/') : bukkitDir.replace('\\', '/'); - } - - public void setBukkitDir(String bukkitDir) { - this.bukkitDir = bukkitDir; - } - - public String getMainClass() { - return mainClass == null ? "" : mainClass; - } - - public void setMainClass(String mainClass) { - this.mainClass = mainClass; - } - - public String getInstallerVersion() { - return installerVersion; - } - - public void setInstallerVersion(String installerVersion) { - this.installerVersion = installerVersion; - } - - public String getTweakClass() { - return tweakClass == null ? "" : tweakClass; - } - - public void setTweakClass(String tweakClass) { - this.tweakClass = tweakClass; - } +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; - public Action getSubprojects() { - return subprojects; - } - - public void setSubprojects(Action subprojects) { - this.subprojects = subprojects; - } - - @SuppressWarnings("rawtypes") - public void subprojects(Closure subprojects) { - this.subprojects = new ClosureBackedAction<>(subprojects); - } - - public Action getCleanProject() { - return cleanProject; - } - - public void setCleanProject(Action cleanProject) { - this.cleanProject = cleanProject; - } - - @SuppressWarnings("rawtypes") - public void cleanProject(Closure subprojects) { - this.cleanProject = new ClosureBackedAction(subprojects); - } - - public Action getDirtyProject() { - return dirtyProject; - } - - public void setDirtyProject(Action dirtyProject) { - this.dirtyProject = dirtyProject; - } - - @SuppressWarnings("rawtypes") - public void dirtyProject(Closure subprojects) { - this.dirtyProject = new ClosureBackedAction<>(subprojects); - } - - public boolean getMakeJavadoc() { - return makeJavadoc; - } - - public void setMakeJavadoc(boolean makeJavadoc) { - this.makeJavadoc = makeJavadoc; - } - - public String[] getRepos() { - return repos; - } - - public void setRepos(String[] repos) { - this.repos = repos; - } -} +public class DevExtension extends BaseExtension { + @Setter + private String fmlDir; + @Setter + private String forgeDir; + @Setter + private String bukkitDir; + @Getter + private String mainClass = ""; + @Getter + private String tweakClass = ""; + @Getter + private List repos = new ArrayList<>(); + @Setter + @Getter + private boolean makeJavadoc = true; + @Setter + @Getter + private String installerVersion = "null"; + + @Setter + @Getter + private Action subprojects; + @Setter + @Getter + private Action cleanProject; + @Setter + @Getter + private Action dirtyProject; + + public DevExtension(DevBasePlugin plugin) { + super(plugin); + } + + public String getFmlDir() { + return normalizeOrDefault(fmlDir); + } + + public String getForgeDir() { + return normalizeOrDefault(forgeDir); + } + + public String getBukkitDir() { + return normalizeOrDefault(bukkitDir); + } + + public void setMainClass(String mainClass) { + this.mainClass = mainClass == null ? "" : mainClass; + } + + public void setTweakClass(String tweakClass) { + this.tweakClass = tweakClass == null ? "" : tweakClass; + } + + public void setRepos(List repos) { + this.repos = new ArrayList<>(repos); + } + + public void setRepos(String... repos) { + this.repos = new ArrayList<>(Arrays.asList(repos)); + } + + // --- Helpers --- + + private String normalizeOrDefault(String path) { + if (path == null) { + return project.getProjectDir().getPath().replace('\\', '/'); + } + return path.replace('\\', '/'); + } +} \ No newline at end of file diff --git a/buildSrc/src/main/java/io/github/cruciblemc/forgegradle/tasks/DeterministicDecompileTask.java b/buildSrc/src/main/java/io/github/cruciblemc/forgegradle/tasks/DeterministicDecompileTask.java index 597a4652..1c8fbf08 100644 --- a/buildSrc/src/main/java/io/github/cruciblemc/forgegradle/tasks/DeterministicDecompileTask.java +++ b/buildSrc/src/main/java/io/github/cruciblemc/forgegradle/tasks/DeterministicDecompileTask.java @@ -22,6 +22,7 @@ import net.minecraftforge.gradle.patching.ContextualPatch.PatchReport; import net.minecraftforge.gradle.patching.ContextualPatch.PatchStatus; import net.minecraftforge.gradle.tasks.abstractutil.CachedTask; +import org.gradle.api.Action; import org.gradle.api.file.FileCollection; import org.gradle.api.logging.LogLevel; import org.gradle.api.tasks.*; @@ -156,12 +157,11 @@ private void crucibleFixJar(File patchFiles, File jar) throws Throwable { } private void decompile(final File inJar, final File outJar, final File fernFlower) { - this.getProject().javaexec(new Closure(this) { + this.getProject().javaexec(new Action() { private static final long serialVersionUID = 4608694547855396167L; @Override - public JavaExecSpec call() { - JavaExecSpec exec = (JavaExecSpec) this.getDelegate(); + public void execute(JavaExecSpec exec) { exec.args( fernFlower.getAbsolutePath(), @@ -182,13 +182,6 @@ public JavaExecSpec call() { exec.setStandardOutput(DevConstants.getTaskLogStream(DeterministicDecompileTask.this.getProject(), DeterministicDecompileTask.this.getName() + ".log")); exec.setMaxHeapSize("512M"); - - return exec; - } - - @Override - public JavaExecSpec call(Object obj) { - return this.call(); } }); } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf0..1b33c55b 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index da1db5f0..d4081da4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 83f2acfd..23d15a93 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,80 +15,115 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -97,92 +132,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" fi +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 9618d8d9..db3a6ac2 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,8 +13,10 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,10 +27,14 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -51,48 +57,36 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/patches/cpw/mods/fml/common/discovery/JarDiscoverer.java.patch b/patches/cpw/mods/fml/common/discovery/JarDiscoverer.java.patch index cf0ba2ae..b20b03d7 100644 --- a/patches/cpw/mods/fml/common/discovery/JarDiscoverer.java.patch +++ b/patches/cpw/mods/fml/common/discovery/JarDiscoverer.java.patch @@ -5,7 +5,7 @@ for (ZipEntry ze : Collections.list(jar.entries())) { - if (ze.getName()!=null && ze.getName().startsWith("__MACOSX")) -+ if (ze.getName().startsWith("__MACOSX") || ze.getName().startsWith("META-INF/versions") || ze.getName().contains("org/openjdk/nashorn") || ze.getName().contains("jakarta/servlet/")) ++ if (ze.getName().startsWith("__MACOSX") || ze.getName().contains("module-info.class") || ze.getName().startsWith("META-INF/versions") || ze.getName().contains("org/openjdk/nashorn") || ze.getName().contains("jakarta/servlet/")) { continue; } diff --git a/patches/cpw/mods/fml/common/patcher/ClassPatchManager.java.patch b/patches/cpw/mods/fml/common/patcher/ClassPatchManager.java.patch deleted file mode 100644 index eb3c6262..00000000 --- a/patches/cpw/mods/fml/common/patcher/ClassPatchManager.java.patch +++ /dev/null @@ -1,57 +0,0 @@ ---- ../src-base/minecraft/cpw/mods/fml/common/patcher/ClassPatchManager.java -+++ ../src-work/minecraft/cpw/mods/fml/common/patcher/ClassPatchManager.java -@@ -11,14 +11,15 @@ - import java.util.jar.JarEntry; - import java.util.jar.JarInputStream; - import java.util.jar.JarOutputStream; --import java.util.jar.Pack200; - import java.util.regex.Pattern; - -+import org.apache.commons.compress.harmony.unpack200.Archive; - import org.apache.logging.log4j.Level; - - import net.minecraft.launchwrapper.LaunchClassLoader; - --import LZMA.LzmaInputStream; -+import org.apache.commons.compress.harmony.unpack200.Pack200UnpackerAdapter; -+import org.apache.logging.log4j.Level; - - import com.google.common.base.Joiner; - import com.google.common.base.Throwables; -@@ -30,11 +31,13 @@ - import com.google.common.io.ByteStreams; - import com.google.common.io.Files; - -+import LZMA.LzmaInputStream; - import cpw.mods.fml.relauncher.FMLRelaunchLog; - import cpw.mods.fml.relauncher.Side; - import cpw.mods.fml.repackage.com.nothome.delta.GDiffPatcher; - - public class ClassPatchManager { -+ - public static final ClassPatchManager INSTANCE = new ClassPatchManager(); - - public static final boolean dumpPatched = Boolean.parseBoolean(System.getProperty("fml.dumpPatchedClasses", "false")); -@@ -155,10 +158,20 @@ - FMLRelaunchLog.log(Level.ERROR, "The binary patch set is missing. Either you are in a development environment, or things are not going to work!"); - return; - } -- LzmaInputStream binpatchesDecompressed = new LzmaInputStream(binpatchesCompressed); -+ // Crucible start - apply lwjgl3ify patch -+ // LzmaInputStream binpatchesDecompressed = new LzmaInputStream(binpatchesCompressed); -+ LzmaInputStream binpatchesDecompressedLzma = new LzmaInputStream(binpatchesCompressed); -+ // The Apache pack200 stream chokes on a lzmainputstream for some reason -+ byte[] decompressed = ByteStreams.toByteArray(binpatchesDecompressedLzma); -+ binpatchesDecompressedLzma.close(); -+ ByteArrayInputStream binpatchesDecompressed = new ByteArrayInputStream(decompressed); - ByteArrayOutputStream jarBytes = new ByteArrayOutputStream(); - JarOutputStream jos = new JarOutputStream(jarBytes); -- Pack200.newUnpacker().unpack(binpatchesDecompressed, jos); -+ -+ //Pack200.newUnpacker().unpack(binpatchesDecompressed, jos); -+ new Pack200UnpackerAdapter().unpack(binpatchesDecompressed, jos); -+ // Crucible end -+ - jis = new JarInputStream(new ByteArrayInputStream(jarBytes.toByteArray())); - } - catch (Exception e) diff --git a/patches/cpw/mods/fml/common/registry/ItemStackHolderRef.java.patch b/patches/cpw/mods/fml/common/registry/ItemStackHolderRef.java.patch deleted file mode 100644 index e8e25e7d..00000000 --- a/patches/cpw/mods/fml/common/registry/ItemStackHolderRef.java.patch +++ /dev/null @@ -1,124 +0,0 @@ ---- ../src-base/minecraft/cpw/mods/fml/common/registry/ItemStackHolderRef.java -+++ ../src-work/minecraft/cpw/mods/fml/common/registry/ItemStackHolderRef.java -@@ -1,19 +1,15 @@ - package cpw.mods.fml.common.registry; - --import java.lang.reflect.Field; --import java.lang.reflect.Method; --import java.lang.reflect.Modifier; -- --import net.minecraft.item.ItemStack; -- --import org.apache.logging.log4j.Level; -- - import com.google.common.base.Throwables; -- - import cpw.mods.fml.common.FMLLog; - import cpw.mods.fml.common.registry.GameRegistry.ItemStackHolder; -+import net.minecraft.item.ItemStack; -+import org.apache.logging.log4j.Level; - -+import java.lang.reflect.Field; -+import java.lang.reflect.Method; - -+ - /** - * Internal class used in tracking {@link ItemStackHolder} references - * -@@ -44,16 +40,19 @@ - { - try - { -- if (modifiersField == null) -- { -- Method getReflectionFactory = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("getReflectionFactory"); -- reflectionFactory = getReflectionFactory.invoke(null); -- newFieldAccessor = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("newFieldAccessor", Field.class, boolean.class); -- fieldAccessorSet = Class.forName("sun.reflect.FieldAccessor").getDeclaredMethod("set", Object.class, Object.class); -- modifiersField = Field.class.getDeclaredField("modifiers"); -- modifiersField.setAccessible(true); -- } -- modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL); -+ // Crucible start - implement lwjgl3ify patch directly -+// if (modifiersField == null) -+// { -+// Method getReflectionFactory = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("getReflectionFactory"); -+// reflectionFactory = getReflectionFactory.invoke(null); -+// newFieldAccessor = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("newFieldAccessor", Field.class, boolean.class); -+// fieldAccessorSet = Class.forName("sun.reflect.FieldAccessor").getDeclaredMethod("set", Object.class, Object.class); -+// modifiersField = Field.class.getDeclaredField("modifiers"); -+// modifiersField.setAccessible(true); -+// } -+// modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL); -+ f.setAccessible(true); -+ // Crucible end - } catch (Exception e) - { - throw Throwables.propagate(e); -@@ -62,23 +61,53 @@ - - public void apply() - { -+ // Crucible start - implement lwjgl3ify patch directly -+// ItemStack is; -+// try -+// { -+// is = GameRegistry.makeItemStack(itemName, meta, 1, serializednbt); -+// } catch (RuntimeException e) -+// { -+// FMLLog.getLogger().log(Level.ERROR, "Caught exception processing itemstack {},{},{} in annotation at {}.{}", itemName, meta, serializednbt,field.getClass().getName(),field.getName()); -+// throw e; -+// } -+// try -+// { -+// Object fieldAccessor = newFieldAccessor.invoke(reflectionFactory, field, false); -+// fieldAccessorSet.invoke(fieldAccessor, null, is); -+// } -+// catch (Exception e) -+// { -+// FMLLog.getLogger().log(Level.WARN, "Unable to set {} with value {},{},{}", this.field, this.itemName, this.meta, this.serializednbt); -+// } - ItemStack is; -- try -- { -+ try { - is = GameRegistry.makeItemStack(itemName, meta, 1, serializednbt); -- } catch (RuntimeException e) -- { -- FMLLog.getLogger().log(Level.ERROR, "Caught exception processing itemstack {},{},{} in annotation at {}.{}", itemName, meta, serializednbt,field.getClass().getName(),field.getName()); -+ } catch (RuntimeException e) { -+ FMLLog.getLogger() -+ .log( -+ Level.ERROR, -+ "Caught exception processing itemstack {},{},{} in annotation at {}.{}", -+ itemName, -+ meta, -+ serializednbt, -+ field.getClass() -+ .getName(), -+ field.getName()); - throw e; - } -- try -- { -- Object fieldAccessor = newFieldAccessor.invoke(reflectionFactory, field, false); -- fieldAccessorSet.invoke(fieldAccessor, null, is); -+ try { -+ field.set(null, is); -+ } catch (Throwable e) { -+ FMLLog.getLogger() -+ .log( -+ Level.WARN, -+ "Unable to set {} with value {},{},{}", -+ this.field, -+ this.itemName, -+ this.meta, -+ this.serializednbt); - } -- catch (Exception e) -- { -- FMLLog.getLogger().log(Level.WARN, "Unable to set {} with value {},{},{}", this.field, this.itemName, this.meta, this.serializednbt); -- } -+ // Crucible end - } - } diff --git a/patches/cpw/mods/fml/common/registry/ObjectHolderRef.java.patch b/patches/cpw/mods/fml/common/registry/ObjectHolderRef.java.patch deleted file mode 100644 index a4907437..00000000 --- a/patches/cpw/mods/fml/common/registry/ObjectHolderRef.java.patch +++ /dev/null @@ -1,150 +0,0 @@ ---- ../src-base/minecraft/cpw/mods/fml/common/registry/ObjectHolderRef.java -+++ ../src-work/minecraft/cpw/mods/fml/common/registry/ObjectHolderRef.java -@@ -1,17 +1,18 @@ - package cpw.mods.fml.common.registry; - --import java.lang.reflect.Field; --import java.lang.reflect.Method; --import java.lang.reflect.Modifier; --import org.apache.logging.log4j.Level; - import com.google.common.base.Throwables; - import cpw.mods.fml.common.FMLLog; - import cpw.mods.fml.common.registry.GameRegistry.ObjectHolder; - import net.minecraft.block.Block; - import net.minecraft.init.Blocks; - import net.minecraft.item.Item; -+import net.minecraft.util.RegistryNamespaced; -+import org.apache.logging.log4j.Level; - -+import java.lang.reflect.Field; -+import java.lang.reflect.Method; - -+ - /** - * Internal class used in tracking {@link ObjectHolder} references - * -@@ -74,16 +75,19 @@ - { - try - { -- if (modifiersField == null) -- { -- Method getReflectionFactory = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("getReflectionFactory"); -- reflectionFactory = getReflectionFactory.invoke(null); -- newFieldAccessor = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("newFieldAccessor", Field.class, boolean.class); -- fieldAccessorSet = Class.forName("sun.reflect.FieldAccessor").getDeclaredMethod("set", Object.class, Object.class); -- modifiersField = Field.class.getDeclaredField("modifiers"); -- modifiersField.setAccessible(true); -- } -- modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL); -+ // Crucible start - implement lwjgl3ify patch directly -+// if (modifiersField == null) -+// { -+// Method getReflectionFactory = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("getReflectionFactory"); -+// reflectionFactory = getReflectionFactory.invoke(null); -+// newFieldAccessor = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("newFieldAccessor", Field.class, boolean.class); -+// fieldAccessorSet = Class.forName("sun.reflect.FieldAccessor").getDeclaredMethod("set", Object.class, Object.class); -+// modifiersField = Field.class.getDeclaredField("modifiers"); -+// modifiersField.setAccessible(true); -+// } -+// modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL); -+ f.setAccessible(true); -+ // Crucible end - } catch (Exception e) - { - throw Throwables.propagate(e); -@@ -94,39 +98,72 @@ - { - return isBlock || isItem; - } -+ - public void apply() - { -+ // Crucible start - implement lwjgl3ify patch directly -+// Object thing; -+// if (isBlock) -+// { -+// thing = GameData.getBlockRegistry().getObject(injectedObject); -+// if (thing == Blocks.air) -+// { -+// thing = null; -+// } -+// } -+// else if (isItem) -+// { -+// thing = GameData.getItemRegistry().getObject(injectedObject); -+// } -+// else -+// { -+// thing = null; -+// } -+// -+// if (thing == null) -+// { -+// FMLLog.getLogger().log(Level.DEBUG, "Unable to lookup {} for {}. This means the object wasn't registered. It's likely just mod options.", injectedObject, field); -+// return; -+// } -+// try -+// { -+// Object fieldAccessor = newFieldAccessor.invoke(reflectionFactory, field, false); -+// fieldAccessorSet.invoke(fieldAccessor, null, thing); -+// } -+// catch (Exception e) -+// { -+// FMLLog.log(Level.WARN, e, "Unable to set %s with value %s (%s)", this.field, thing, this.injectedObject); -+// } - Object thing; -- if (isBlock) -- { -- thing = GameData.getBlockRegistry().getObject(injectedObject); -- if (thing == Blocks.air) -- { -+ RegistryNamespaced registry; -+ if (isBlock) { -+ registry = GameData.getBlockRegistry(); -+ thing = registry.getObject(injectedObject); -+ if (thing == Blocks.air) { - thing = null; - } -- } -- else if (isItem) -- { -- thing = GameData.getItemRegistry().getObject(injectedObject); -- } -- else -- { -+ } else if (isItem) { -+ registry = GameData.getItemRegistry(); -+ thing = registry.getObject(injectedObject); -+ } else { - thing = null; - } - -- if (thing == null) -- { -- FMLLog.getLogger().log(Level.DEBUG, "Unable to lookup {} for {}. This means the object wasn't registered. It's likely just mod options.", injectedObject, field); -+ if (thing == null) { -+ FMLLog.getLogger() -+ .log( -+ Level.DEBUG, -+ "Unable to lookup {} for {}. This means the object wasn't registered. It's likely just mod options.", -+ injectedObject, -+ field); - return; - } -- try -- { -- Object fieldAccessor = newFieldAccessor.invoke(reflectionFactory, field, false); -- fieldAccessorSet.invoke(fieldAccessor, null, thing); -- } -- catch (Exception e) -- { -+ try { -+ field.set(null, thing); -+ FMLLog.finer("Set field " + field.toString() + " to " + thing); -+ } catch (Throwable e) { - FMLLog.log(Level.WARN, e, "Unable to set %s with value %s (%s)", this.field, thing, this.injectedObject); - } -+ // Crucible end - } - } diff --git a/patches/cpw/mods/fml/common/registry/ObjectHolderRegistry.java.patch b/patches/cpw/mods/fml/common/registry/ObjectHolderRegistry.java.patch deleted file mode 100644 index 23de36ff..00000000 --- a/patches/cpw/mods/fml/common/registry/ObjectHolderRegistry.java.patch +++ /dev/null @@ -1,22 +0,0 @@ ---- ../src-base/minecraft/cpw/mods/fml/common/registry/ObjectHolderRegistry.java -+++ ../src-work/minecraft/cpw/mods/fml/common/registry/ObjectHolderRegistry.java -@@ -12,6 +12,7 @@ - import cpw.mods.fml.common.discovery.ASMDataTable; - import cpw.mods.fml.common.discovery.ASMDataTable.ASMData; - import cpw.mods.fml.common.registry.GameRegistry.ObjectHolder; -+import me.eigenraven.lwjgl3ify.WasFinalObjectHolder; - - /** - * Internal registry for tracking {@link ObjectHolder} references -@@ -111,6 +112,11 @@ - for (Field f : clazz.getFields()) - { - int mods = f.getModifiers(); -+ // Crucible start - lwjgl3ify patch -+ if (f.isAnnotationPresent(WasFinalObjectHolder.class)) { -+ mods |= Modifier.FINAL; -+ } -+ // Crucible end - boolean isMatch = Modifier.isPublic(mods) && Modifier.isStatic(mods) && Modifier.isFinal(mods); - if (!isMatch || f.isAnnotationPresent(ObjectHolder.class)) - { diff --git a/patches/cpw/mods/fml/relauncher/CoreModManager.java.patch b/patches/cpw/mods/fml/relauncher/CoreModManager.java.patch index 496115d1..43a48556 100644 --- a/patches/cpw/mods/fml/relauncher/CoreModManager.java.patch +++ b/patches/cpw/mods/fml/relauncher/CoreModManager.java.patch @@ -29,7 +29,7 @@ import net.minecraft.launchwrapper.ITweaker; import net.minecraft.launchwrapper.Launch; import net.minecraft.launchwrapper.LaunchClassLoader; -@@ -57,10 +61,11 @@ +@@ -57,6 +61,7 @@ import cpw.mods.fml.relauncher.IFMLLoadingPlugin.TransformerExclusions; public class CoreModManager { @@ -37,11 +37,6 @@ private static final Attributes.Name COREMODCONTAINSFMLMOD = new Attributes.Name("FMLCorePluginContainsFMLMod"); private static final Attributes.Name MODTYPE = new Attributes.Name("ModType"); private static final Attributes.Name MODSIDE = new Attributes.Name("ModSide"); -- private static String[] rootPlugins = { "cpw.mods.fml.relauncher.FMLCorePlugin", "net.minecraftforge.classloading.FMLForgePlugin" }; -+ private static String[] rootPlugins = { "cpw.mods.fml.relauncher.FMLCorePlugin", "net.minecraftforge.classloading.FMLForgePlugin", "pw.prok.imagine.ImagineLoadingPlugin" }; - private static List loadedCoremods = Lists.newArrayList(); - private static List loadPlugins; - private static boolean deobfuscatedEnvironment; @@ -70,6 +75,7 @@ private static List accessTransformers = Lists.newArrayList(); diff --git a/patches/cpw/mods/fml/relauncher/ServerLaunchWrapper.java.patch b/patches/cpw/mods/fml/relauncher/ServerLaunchWrapper.java.patch index 1b058c76..96a78066 100644 --- a/patches/cpw/mods/fml/relauncher/ServerLaunchWrapper.java.patch +++ b/patches/cpw/mods/fml/relauncher/ServerLaunchWrapper.java.patch @@ -19,3 +19,12 @@ new ServerLaunchWrapper().run(args); } +@@ -22,7 +25,7 @@ + Class launchwrapper = null; + try + { +- launchwrapper = Class.forName("net.minecraft.launchwrapper.Launch",true,getClass().getClassLoader()); ++ launchwrapper = Class.forName("com.gtnewhorizons.retrofuturabootstrap.MainStartOnFirstThread",true,getClass().getClassLoader()); + Class.forName("org.objectweb.asm.Type",true,getClass().getClassLoader()); + } + catch (Exception e) diff --git a/patches/net/minecraft/network/NetHandlerPlayServer.java.patch b/patches/net/minecraft/network/NetHandlerPlayServer.java.patch index bafcdcd8..3422e49f 100644 --- a/patches/net/minecraft/network/NetHandlerPlayServer.java.patch +++ b/patches/net/minecraft/network/NetHandlerPlayServer.java.patch @@ -976,7 +976,7 @@ + // Spigot Start + if (org.spigotmc.SpigotConfig.logCommands) + { -+ this.logger.info(event.getPlayer().getName() + " issued server command: " + event.getMessage()); // CraftBukkit ++ this.logger.info("{} issued server command: {}", event.getPlayer().getName(), event.getMessage()); // CraftBukkit + } + + // Spigot end diff --git a/patches/net/minecraft/server/dedicated/DedicatedServer.java.patch b/patches/net/minecraft/server/dedicated/DedicatedServer.java.patch index fb00694a..9bc44167 100644 --- a/patches/net/minecraft/server/dedicated/DedicatedServer.java.patch +++ b/patches/net/minecraft/server/dedicated/DedicatedServer.java.patch @@ -77,7 +77,7 @@ { private static final String __OBFID = "CL_00001787"; { -@@ -82,31 +100,102 @@ +@@ -82,31 +100,54 @@ }; } @@ -111,7 +111,7 @@ - DedicatedServer.this.addPendingCommand(s4, DedicatedServer.this); + if (useJline) + { -+ s = bufferedreader.readLine(">", null); ++ s = bufferedreader.readLine("", null); + } + else + { @@ -135,59 +135,11 @@ }; thread.setDaemon(true); thread.start(); -+ // CraftBukkit start - TODO: handle command-line logging arguments -+ java.util.logging.Logger global = java.util.logging.Logger.getLogger(""); -+ global.setUseParentHandlers(false); -+ -+ for (java.util.logging.Handler handler : global.getHandlers()) -+ { -+ global.removeHandler(handler); -+ } -+ -+ global.addHandler(new ForwardLogHandler()); -+ -+ final org.apache.logging.log4j.core.Logger logger = ((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger()); -+ -+ for (org.apache.logging.log4j.core.Appender appender : logger.getAppenders().values()) -+ { -+ if (appender instanceof org.apache.logging.log4j.core.appender.ConsoleAppender) -+ { -+ logger.removeAppender(appender); -+ } -+ } -+ -+ // Crucible start - go nuclear on all other loggers -+ try { -+ LoggerContext ctx = (LoggerContext) FMLRelaunchLog.log.ctx; -+ Field loggersField = LoggerContext.class.getDeclaredField("loggers"); -+ loggersField.setAccessible(true); -+ @SuppressWarnings("unchecked") -+ ConcurrentMap loggers = -+ (ConcurrentMap) loggersField.get(ctx); -+ for (org.apache.logging.log4j.core.Logger loggerToHack : loggers.values()) { -+ for (org.apache.logging.log4j.core.Appender appender : loggerToHack.getAppenders().values()) -+ { -+ if (appender instanceof org.apache.logging.log4j.core.appender.ConsoleAppender) -+ { -+ loggerToHack.removeAppender(appender); -+ } -+ } -+ } -+ } catch (Throwable e) { -+ System.out.println("[Crucible] Unable to hack other loggers, expect broken and chaotic logs."); -+ e.printStackTrace(); -+ } -+ // Crucible end -+ -+ CrucibleServerMainHook.restoreStreams(); // Crucible - Restores the original streams so System.out does not log to forge logger -+ new Thread(new TerminalConsoleWriterThread(System.out, this.reader)).start(); -+ System.setOut(new PrintStream(new CrucibleTracingLoggerOutputStream(LogManager.getLogger("STDOUT"), Level.INFO), true)); -+ System.setErr(new PrintStream(new CrucibleTracingLoggerOutputStream(LogManager.getLogger("STDERR"), Level.WARN), true)); + // CraftBukkit end field_155771_h.info("Starting minecraft server version 1.7.10"); if (Runtime.getRuntime().maxMemory() / 1024L / 1024L < 512L) -@@ -117,7 +206,7 @@ +@@ -117,7 +158,7 @@ FMLCommonHandler.instance().onServerStart(this); field_155771_h.info("Loading properties"); @@ -196,7 +148,7 @@ this.field_154332_n = new ServerEula(new File("eula.txt")); if (!this.field_154332_n.func_154346_a()) -@@ -172,6 +261,18 @@ +@@ -172,6 +213,18 @@ this.setServerPort(this.settings.getIntProperty("server-port", 25565)); } @@ -215,7 +167,7 @@ field_155771_h.info("Generating keypair"); this.setKeyPair(CryptManager.createNewKeyPair()); field_155771_h.info("Starting Minecraft server on " + (this.getServerHostname().length() == 0 ? "*" : this.getServerHostname()) + ":" + this.getServerPort()); -@@ -180,7 +281,7 @@ +@@ -180,7 +233,7 @@ { this.func_147137_ag().addLanEndpoint(inetaddress, this.getServerPort()); } @@ -224,7 +176,7 @@ { field_155771_h.warn("**** FAILED TO BIND TO PORT!"); field_155771_h.warn("The exception was: {}", new Object[] {ioexception.toString()}); -@@ -196,10 +297,17 @@ +@@ -196,10 +249,17 @@ field_155771_h.warn("To change this, set \"online-mode\" to \"true\" in the server.properties file."); } @@ -244,7 +196,7 @@ if (!PreYggdrasilConverter.func_152714_a(this.settings)) { -@@ -208,7 +316,8 @@ +@@ -208,7 +268,8 @@ else { FMLCommonHandler.instance().onServerStarted(); @@ -254,7 +206,7 @@ long j = System.nanoTime(); if (this.getFolderName() == null) -@@ -274,11 +383,30 @@ +@@ -274,11 +335,30 @@ this.theRConThreadMain.startThread(); } @@ -285,7 +237,7 @@ public boolean canStructuresSpawn() { return this.canSpawnStructures; -@@ -364,11 +492,19 @@ +@@ -364,11 +444,19 @@ public void executePendingCommands() { diff --git a/patches/net/minecraft/world/WorldType.java.patch b/patches/net/minecraft/world/WorldType.java.patch index 3fcd4197..6b94f495 100644 --- a/patches/net/minecraft/world/WorldType.java.patch +++ b/patches/net/minecraft/world/WorldType.java.patch @@ -4,7 +4,7 @@ import net.minecraft.world.gen.layer.GenLayerZoom; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; -+import net.minecraftforge.common.util.EnumHelper; // Cauldron ++import io.github.crucible.util.BukkitEnumHelper; public class WorldType { @@ -15,7 +15,7 @@ + // Cauldron start - add worldtype for bukkit if it does not already exist + if (org.bukkit.WorldType.getByName(p_i1960_2_) == null) + { -+ EnumHelper.addBukkitWorldType(p_i1960_2_); ++ BukkitEnumHelper.addBukkitWorldType(p_i1960_2_); + } + // Cauldron end } diff --git a/patches/net/minecraft/world/chunk/storage/AnvilChunkLoader.java.patch b/patches/net/minecraft/world/chunk/storage/AnvilChunkLoader.java.patch index ac772a00..a80299e7 100644 --- a/patches/net/minecraft/world/chunk/storage/AnvilChunkLoader.java.patch +++ b/patches/net/minecraft/world/chunk/storage/AnvilChunkLoader.java.patch @@ -8,21 +8,27 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; -@@ -33,6 +34,13 @@ +@@ -26,6 +27,7 @@ + import net.minecraft.world.storage.IThreadedFileIO; + import net.minecraft.world.storage.ThreadedFileIOBase; + import net.minecraftforge.common.MinecraftForge; ++import io.github.crucible.util.BukkitEnumHelper; + import net.minecraftforge.event.world.ChunkDataEvent; + + import org.apache.logging.log4j.Level; +@@ -33,6 +35,11 @@ import org.apache.logging.log4j.Logger; import cpw.mods.fml.common.FMLLog; +// Cauldron start -+import java.util.Map; +import net.minecraft.server.MinecraftServer; +import net.minecraftforge.cauldron.CauldronUtils; -+import net.minecraftforge.common.util.EnumHelper; +import cpw.mods.fml.common.asm.transformers.SideTransformer; +// Cauldron end public class AnvilChunkLoader implements IChunkLoader, IThreadedFileIO { -@@ -41,6 +49,7 @@ +@@ -41,6 +48,7 @@ private Set pendingAnvilChunksCoordinates = new HashSet(); private Object syncLockObject = new Object(); public final File chunkSaveLocation; @@ -30,7 +36,7 @@ private static final String __OBFID = "CL_00000384"; public AnvilChunkLoader(File p_i2003_1_) -@@ -68,18 +77,22 @@ +@@ -68,18 +76,22 @@ } } @@ -54,7 +60,7 @@ return chunk; } -@@ -156,8 +169,8 @@ +@@ -156,8 +168,8 @@ if (!chunk.isAtLocation(p_75822_2_, p_75822_3_)) { logger.error("Chunk file at " + p_75822_2_ + "," + p_75822_3_ + " is in the wrong location; relocating. (Expected " + p_75822_2_ + ", " + p_75822_3_ + ", got " + chunk.xPosition + ", " + chunk.zPosition + ")"); @@ -65,7 +71,7 @@ // Have to move tile entities since we don't load them at this stage NBTTagList tileEntities = p_75822_4_.getCompoundTag("Level").getTagList("TileEntities", 10); -@@ -187,8 +200,18 @@ +@@ -187,8 +199,18 @@ public void saveChunk(World p_75816_1_, Chunk p_75816_2_) throws MinecraftException, IOException { @@ -85,7 +91,7 @@ try { NBTTagCompound nbttagcompound = new NBTTagCompound(); -@@ -230,7 +253,7 @@ +@@ -230,7 +252,7 @@ public boolean writeNextIO() { @@ -94,7 +100,7 @@ Object object = this.syncLockObject; synchronized (this.syncLockObject) -@@ -240,15 +263,15 @@ +@@ -240,15 +262,15 @@ return false; } @@ -114,7 +120,7 @@ } catch (Exception exception) { -@@ -259,7 +282,7 @@ +@@ -259,7 +281,7 @@ return true; } @@ -123,7 +129,7 @@ { DataOutputStream dataoutputstream = RegionFileCache.getChunkOutputStream(this.chunkSaveLocation, p_75821_1_.chunkCoordinate.chunkXPos, p_75821_1_.chunkCoordinate.chunkZPos); CompressedStreamTools.write(p_75821_1_.nbtTags, dataoutputstream); -@@ -307,19 +330,19 @@ +@@ -307,19 +329,19 @@ if (extendedblockstorage.getBlockMSBArray() != null) { @@ -148,7 +154,7 @@ } nbttaglist.appendTag(nbttagcompound1); -@@ -379,17 +402,16 @@ +@@ -379,17 +401,16 @@ } p_75820_3_.setTag("TileEntities", nbttaglist3); @@ -172,7 +178,7 @@ NBTTagCompound nbttagcompound2 = new NBTTagCompound(); nbttagcompound2.setInteger("i", Block.getIdFromBlock(nextticklistentry.func_151351_a())); nbttagcompound2.setInteger("x", nextticklistentry.xCoord); -@@ -401,7 +423,6 @@ +@@ -401,7 +422,6 @@ } p_75820_3_.setTag("TileTicks", nbttaglist1); @@ -180,7 +186,7 @@ } private Chunk readChunkFromNBT(World p_75823_1_, NBTTagCompound p_75823_2_) -@@ -455,6 +476,8 @@ +@@ -455,6 +475,8 @@ public void loadEntities(World p_75823_1_, NBTTagCompound p_75823_2_, Chunk chunk) { @@ -189,7 +195,7 @@ NBTTagList nbttaglist1 = p_75823_2_.getTagList("Entities", 10); if (nbttaglist1 != null) -@@ -468,24 +491,31 @@ +@@ -468,24 +490,31 @@ if (entity2 != null) { chunk.addEntity(entity2); @@ -230,7 +236,7 @@ NBTTagList nbttaglist2 = p_75823_2_.getTagList("TileEntities", 10); if (nbttaglist2 != null) -@@ -497,11 +527,35 @@ +@@ -497,11 +526,35 @@ if (tileentity != null) { @@ -252,7 +258,7 @@ + SideTransformer.allowInvalidSide = false; + } + // inject TE into InventoryType to support inventory events -+ EnumHelper.addInventoryType(tileentity); ++ BukkitEnumHelper.addInventoryType(tileentity); + this.checkedTileEntities.add(tileentity.getClass()); + } + // Cauldron end @@ -266,7 +272,7 @@ if (p_75823_2_.hasKey("TileTicks", 9)) { NBTTagList nbttaglist3 = p_75823_2_.getTagList("TileTicks", 10); -@@ -515,6 +569,7 @@ +@@ -515,6 +568,7 @@ } } } diff --git a/patches/net/minecraftforge/common/DimensionManager.java.patch b/patches/net/minecraftforge/common/DimensionManager.java.patch index 6844fd93..188edc5b 100644 --- a/patches/net/minecraftforge/common/DimensionManager.java.patch +++ b/patches/net/minecraftforge/common/DimensionManager.java.patch @@ -1,14 +1,23 @@ --- ../src-base/minecraft/net/minecraftforge/common/DimensionManager.java +++ ../src-work/minecraft/net/minecraftforge/common/DimensionManager.java -@@ -11,6 +11,7 @@ +@@ -11,6 +11,8 @@ import java.util.Map.Entry; import java.util.concurrent.ConcurrentMap; +import io.github.crucible.CrucibleConfigs; ++import io.github.crucible.util.BukkitEnumHelper; import org.apache.logging.log4j.Level; import com.google.common.collect.HashMultiset; -@@ -34,6 +35,15 @@ +@@ -21,7 +23,6 @@ + import cpw.mods.fml.common.FMLLog; + import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.server.MinecraftServer; +-import net.minecraft.world.MinecraftException; + import net.minecraft.world.World; + import net.minecraft.world.WorldManager; + import net.minecraft.world.WorldProvider; +@@ -34,6 +35,14 @@ import net.minecraft.world.storage.ISaveHandler; import net.minecraft.world.storage.SaveHandler; import net.minecraftforge.event.world.WorldEvent; @@ -16,7 +25,6 @@ +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.world.chunk.storage.AnvilSaveHandler; +import net.minecraftforge.cauldron.CauldronUtils; -+import net.minecraftforge.common.util.EnumHelper; +import org.bukkit.World.Environment; +import org.bukkit.WorldCreator; +import org.bukkit.generator.ChunkGenerator; @@ -24,7 +32,7 @@ public class DimensionManager { -@@ -46,6 +56,11 @@ +@@ -46,6 +55,11 @@ private static BitSet dimensionMap = new BitSet(Long.SIZE << 4); private static ConcurrentMap weakWorldMap = new MapMaker().weakKeys().weakValues().makeMap(); private static Multiset leakedWorlds = HashMultiset.create(); @@ -36,7 +44,7 @@ public static boolean registerProviderType(int id, Class provider, boolean keepLoaded) { -@@ -53,7 +68,23 @@ +@@ -53,7 +67,23 @@ { return false; } @@ -60,7 +68,7 @@ spawnSettings.put(id, keepLoaded); return true; } -@@ -157,28 +188,33 @@ +@@ -157,28 +187,33 @@ public static Integer[] getIDs(boolean check) { @@ -108,7 +116,7 @@ return getIDs(); } public static Integer[] getIDs() -@@ -191,12 +227,23 @@ +@@ -191,12 +226,23 @@ if (world != null) { worlds.put(id, world); @@ -133,7 +141,7 @@ worlds.remove(id); MinecraftServer.getServer().worldTickTimes.remove(id); FMLLog.info("Unloading dimension %d", id); -@@ -224,6 +271,7 @@ +@@ -224,6 +270,7 @@ } public static void initDimension(int dim) { @@ -141,7 +149,7 @@ WorldServer overworld = getWorld(0); if (overworld == null) { -@@ -231,6 +279,12 @@ +@@ -231,6 +278,12 @@ } try { @@ -154,7 +162,7 @@ DimensionManager.getProviderType(dim); } catch (Exception e) -@@ -242,9 +296,63 @@ +@@ -242,9 +295,63 @@ ISaveHandler savehandler = overworld.getSaveHandler(); WorldSettings worldSettings = new WorldSettings(overworld.getWorldInfo()); @@ -219,7 +227,7 @@ if (!mcServer.isSinglePlayer()) { world.getWorldInfo().setGameType(mcServer.getGameType()); -@@ -253,6 +361,79 @@ +@@ -253,6 +360,79 @@ mcServer.func_147139_a(mcServer.func_147135_j()); } @@ -299,7 +307,7 @@ public static WorldServer getWorld(int id) { return worlds.get(id); -@@ -266,7 +447,7 @@ +@@ -266,7 +446,7 @@ public static boolean shouldLoadSpawn(int dim) { int id = getProviderType(dim); @@ -308,7 +316,7 @@ } static -@@ -306,7 +487,8 @@ +@@ -306,7 +486,8 @@ } public static void unloadWorld(int id) { @@ -318,7 +326,7 @@ } /* -@@ -315,26 +497,9 @@ +@@ -315,26 +496,9 @@ public static void unloadWorlds(Hashtable worldTickTimes) { for (int id : unloadQueue) { WorldServer w = worlds.get(id); @@ -347,7 +355,7 @@ } } unloadQueue.clear(); -@@ -425,4 +590,45 @@ +@@ -425,4 +589,45 @@ return null; } } @@ -359,7 +367,7 @@ + if (env == null) // Cauldron if environment not found, register one + { + providerName = providerName.replace("WorldProvider", ""); -+ env = EnumHelper.addBukkitEnvironment(dim, providerName.toUpperCase()); ++ env = BukkitEnumHelper.addBukkitEnvironment(dim, providerName.toUpperCase()); + Environment.registerEnvironment(env); + } + return env; diff --git a/patches/net/minecraftforge/common/util/EnumHelper.java.patch b/patches/net/minecraftforge/common/util/EnumHelper.java.patch deleted file mode 100644 index be667f59..00000000 --- a/patches/net/minecraftforge/common/util/EnumHelper.java.patch +++ /dev/null @@ -1,517 +0,0 @@ ---- ../src-base/minecraft/net/minecraftforge/common/util/EnumHelper.java -+++ ../src-work/minecraft/net/minecraftforge/common/util/EnumHelper.java -@@ -1,8 +1,11 @@ - package net.minecraftforge.common.util; - -+import java.lang.invoke.MethodHandle; -+import java.lang.invoke.MethodHandles; - import java.lang.reflect.*; - import java.util.*; - -+import com.google.common.base.Throwables; - import cpw.mods.fml.common.FMLLog; - import net.minecraft.block.BlockPressurePlate.Sensitivity; - import net.minecraft.block.material.Material; -@@ -21,186 +24,120 @@ - import net.minecraft.world.EnumSkyBlock; - import net.minecraft.world.gen.structure.StructureStrongholdPieces.Stronghold.Door; - import net.minecraftforge.classloading.FMLForgePlugin; -+// Cauldron start -+import cpw.mods.fml.relauncher.ReflectionHelper; -+import net.minecraft.inventory.IInventory; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.tileentity.TileEntity; - --public class EnumHelper --{ -- private static Object reflectionFactory = null; -+import org.apache.commons.lang3.ArrayUtils; -+import org.apache.logging.log4j.Level; -+import org.apache.logging.log4j.LogManager; -+import org.apache.logging.log4j.Logger; -+import org.bukkit.World; -+import org.bukkit.WorldType; -+import org.bukkit.block.Biome; -+import org.bukkit.entity.EntityType; -+import org.bukkit.event.inventory.InventoryType; -+// Cauldron end -+ -+public class EnumHelper { -+ private static final Logger logger = LogManager.getLogger(); -+ private static final Map>, Map>> enumConstants = new HashMap<>(); -+ private static Object reflectionFactory = null; - private static Method newConstructorAccessor = null; -- private static Method newInstance = null; -- private static Method newFieldAccessor = null; -- private static Method fieldAccessorSet = null; -- private static boolean isSetup = false; -+ private static Method newInstance = null; -+ private static Method newFieldAccessor = null; -+ private static Method fieldAccessorSet = null; -+ private static boolean isSetup = false; - -- //Some enums are decompiled with extra arguments, so lets check for that -+ // Some enums are decompiled with extra arguments, so lets check for that - @SuppressWarnings("rawtypes") -- private static Class[][] commonTypes = -- { -- {EnumAction.class}, -- {ArmorMaterial.class, int.class, int[].class, int.class}, -- {EnumArt.class, String.class, int.class, int.class, int.class, int.class}, -- {EnumCreatureAttribute.class}, -- {EnumCreatureType.class, Class.class, int.class, Material.class, boolean.class, boolean.class}, -- {Door.class}, -- {EnumEnchantmentType.class}, -- {EnumEntitySize.class}, -- {Sensitivity.class}, -- {MovingObjectType.class}, -- {EnumSkyBlock.class, int.class}, -- {EnumStatus.class}, -- {ToolMaterial.class, int.class, int.class, float.class, float.class, int.class}, -- {EnumRarity.class, EnumChatFormatting.class, String.class} -- }; -+ private static Class[][] commonTypes = {{EnumAction.class}, -+ {ArmorMaterial.class, int.class, int[].class, int.class}, -+ {EnumArt.class, String.class, int.class, int.class, int.class, int.class}, {EnumCreatureAttribute.class}, -+ {EnumCreatureType.class, Class.class, int.class, Material.class, boolean.class, boolean.class}, -+ {Door.class}, {EnumEnchantmentType.class}, {EnumEntitySize.class}, {Sensitivity.class}, -+ {MovingObjectType.class}, {EnumSkyBlock.class, int.class}, {EnumStatus.class}, -+ {ToolMaterial.class, int.class, int.class, float.class, float.class, int.class}, -+ {EnumRarity.class, EnumChatFormatting.class, String.class}}; - -- public static EnumAction addAction(String name) -- { -+ public static EnumAction addAction(String name) { - return addEnum(EnumAction.class, name); - } -- public static ArmorMaterial addArmorMaterial(String name, int durability, int[] reductionAmounts, int enchantability) -- { -+ -+ public static ArmorMaterial addArmorMaterial(String name, int durability, int[] reductionAmounts, int enchantability) { - return addEnum(ArmorMaterial.class, name, durability, reductionAmounts, enchantability); - } -- public static EnumArt addArt(String name, String tile, int sizeX, int sizeY, int offsetX, int offsetY) -- { -+ -+ public static EnumArt addArt(String name, String tile, int sizeX, int sizeY, int offsetX, int offsetY) { - return addEnum(EnumArt.class, name, tile, sizeX, sizeY, offsetX, offsetY); - } -- public static EnumCreatureAttribute addCreatureAttribute(String name) -- { -+ -+ public static EnumCreatureAttribute addCreatureAttribute(String name) { - return addEnum(EnumCreatureAttribute.class, name); - } -+ - @SuppressWarnings("rawtypes") -- public static EnumCreatureType addCreatureType(String name, Class typeClass, int maxNumber, Material material, boolean peaceful, boolean animal) -- { -+ public static EnumCreatureType addCreatureType(String name, Class typeClass, int maxNumber, Material material, boolean peaceful, boolean animal) { - return addEnum(EnumCreatureType.class, name, typeClass, maxNumber, material, peaceful, animal); - } -- public static Door addDoor(String name) -- { -+ -+ public static Door addDoor(String name) { - return addEnum(Door.class, name); - } -- public static EnumEnchantmentType addEnchantmentType(String name) -- { -+ -+ public static EnumEnchantmentType addEnchantmentType(String name) { - return addEnum(EnumEnchantmentType.class, name); - } -- public static EnumEntitySize addEntitySize(String name) -- { -+ -+ public static EnumEntitySize addEntitySize(String name) { - return addEnum(EnumEntitySize.class, name); - } -- public static Sensitivity addSensitivity(String name) -- { -+ -+ public static Sensitivity addSensitivity(String name) { - return addEnum(Sensitivity.class, name); - } -- public static MovingObjectType addMovingObjectType(String name) -- { -+ -+ public static MovingObjectType addMovingObjectType(String name) { - return addEnum(MovingObjectType.class, name); - } -- public static EnumSkyBlock addSkyBlock(String name, int lightValue) -- { -+ -+ public static EnumSkyBlock addSkyBlock(String name, int lightValue) { - return addEnum(EnumSkyBlock.class, name, lightValue); - } -- public static EnumStatus addStatus(String name) -- { -+ -+ public static EnumStatus addStatus(String name) { - return addEnum(EnumStatus.class, name); - } -- public static ToolMaterial addToolMaterial(String name, int harvestLevel, int maxUses, float efficiency, float damage, int enchantability) -- { -+ -+ public static ToolMaterial addToolMaterial(String name, int harvestLevel, int maxUses, float efficiency, float damage, int enchantability) { - return addEnum(ToolMaterial.class, name, harvestLevel, maxUses, efficiency, damage, enchantability); - } -- public static EnumRarity addRarity(String name, EnumChatFormatting color, String displayName) -- { -+ -+ public static EnumRarity addRarity(String name, EnumChatFormatting color, String displayName) { - return addEnum(EnumRarity.class, name, color, displayName); - } - -- private static void setup() -- { -- if (isSetup) -- { -- return; -+ public static void setFailsafeFieldValue(Field field, Object target, Object value) throws Exception { -+ try { -+ setFieldHandle.invokeExact(field, target, value); -+ } catch (Throwable e) { -+ Throwables.propagate(e); - } -- -- try -- { -- Method getReflectionFactory = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("getReflectionFactory"); -- reflectionFactory = getReflectionFactory.invoke(null); -- newConstructorAccessor = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("newConstructorAccessor", Constructor.class); -- newInstance = Class.forName("sun.reflect.ConstructorAccessor").getDeclaredMethod("newInstance", Object[].class); -- newFieldAccessor = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("newFieldAccessor", Field.class, boolean.class); -- fieldAccessorSet = Class.forName("sun.reflect.FieldAccessor").getDeclaredMethod("set", Object.class, Object.class); -- } -- catch (Exception e) -- { -- e.printStackTrace(); -- } -- -- isSetup = true; - } - -- /* -- * Everything below this is found at the site below, and updated to be able to compile in Eclipse/Java 1.6+ -- * Also modified for use in decompiled code. -- * Found at: http://niceideas.ch/roller2/badtrash/entry/java_create_enum_instances_dynamically -- */ -- private static Object getConstructorAccessor(Class enumClass, Class[] additionalParameterTypes) throws Exception -- { -- Class[] parameterTypes = new Class[additionalParameterTypes.length + 2]; -- parameterTypes[0] = String.class; -- parameterTypes[1] = int.class; -- System.arraycopy(additionalParameterTypes, 0, parameterTypes, 2, additionalParameterTypes.length); -- return newConstructorAccessor.invoke(reflectionFactory, enumClass.getDeclaredConstructor(parameterTypes)); -- } -- -- private static < T extends Enum> T makeEnum(Class enumClass, String value, int ordinal, Class[] additionalTypes, Object[] additionalValues) throws Exception -- { -- Object[] parms = new Object[additionalValues.length + 2]; -- parms[0] = value; -- parms[1] = Integer.valueOf(ordinal); -- System.arraycopy(additionalValues, 0, parms, 2, additionalValues.length); -- return enumClass.cast(newInstance.invoke(getConstructorAccessor(enumClass, additionalTypes), new Object[] {parms})); -- } -- -- public static void setFailsafeFieldValue(Field field, Object target, Object value) throws Exception -- { -- field.setAccessible(true); -- Field modifiersField = Field.class.getDeclaredField("modifiers"); -- modifiersField.setAccessible(true); -- modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); -- Object fieldAccessor = newFieldAccessor.invoke(reflectionFactory, field, false); -- fieldAccessorSet.invoke(fieldAccessor, target, value); -- } -- -- private static void blankField(Class enumClass, String fieldName) throws Exception -- { -- for (Field field : Class.class.getDeclaredFields()) -- { -- if (field.getName().contains(fieldName)) -- { -- field.setAccessible(true); -- setFailsafeFieldValue(field, enumClass, null); -- break; -- } -- } -- } -- -- private static void cleanEnumCache(Class enumClass) throws Exception -- { -- blankField(enumClass, "enumConstantDirectory"); -- blankField(enumClass, "enumConstants"); -- } -- -- public static > T addEnum(Class enumType, String enumName, Object... paramValues) -- { -- setup(); -+ public static > T addEnum(Class enumType, String enumName, Object... paramValues) { - return addEnum(commonTypes, enumType, enumName, paramValues); - } - - @SuppressWarnings("rawtypes") -- public static > T addEnum(Class[][] map, Class enumType, String enumName, Object... paramValues) -- { -- for (Class[] lookup : map) -- { -- if (lookup[0] == enumType) -- { -+ public static > T addEnum(Class[][] map, Class enumType, String enumName, -+ Object... paramValues) { -+ for (Class[] lookup : map) { -+ if (lookup[0] == enumType) { - Class[] paramTypes = new Class[lookup.length - 1]; -- if (paramTypes.length > 0) -- { -+ if (paramTypes.length > 0) { - System.arraycopy(lookup, 1, paramTypes, 0, paramTypes.length); - } - return addEnum(enumType, enumName, paramTypes, paramValues); -@@ -210,81 +147,186 @@ - } - - @SuppressWarnings("unchecked") -- public static > T addEnum(Class enumType, String enumName, Class[] paramTypes, Object[] paramValues) -- { -- if (!isSetup) -- { -- setup(); -+ public static > T addEnum(Class enumType, String enumName, Class[] paramTypes, -+ Object[] paramValues) { -+ if (!extensibleEnumIface.isAssignableFrom(enumType)) { -+ throw new RuntimeException( -+ "Enum " + enumType.getName() + " was not made extensible, add it to Crucible.yml"); - } - -- Field valuesField = null; -- Field[] fields = enumType.getDeclaredFields(); -+ synchronized (enumConstants) { -+ Map> enumMap = enumConstants.computeIfAbsent(enumType, k -> new HashMap<>()); -+ if (enumMap.containsKey(enumName.toUpperCase())) { -+ // Inside the addEnum method -+ int suffix = 1; -+ String newName; -+ do { -+ newName = enumName + "$" + suffix; -+ suffix++; -+ } while (enumMap.containsKey(newName.toUpperCase())); - -- for (Field field : fields) -- { -- String name = field.getName(); -- if (name.equals("$VALUES") || name.equals("ENUM$VALUES")) //Added 'ENUM$VALUES' because Eclipse's internal compiler doesn't follow standards -- { -- valuesField = field; -- break; -+ // Log Enum Name Change -+ logger.info("Duplicate Enum found! Remapping {} to {}", enumName, newName); -+ enumName = newName; - } -- } -+ try { -+ paramTypes = ArrayUtils.add(paramTypes, 0, String.class); -+ paramValues = ArrayUtils.add(paramValues, 0, enumName); - -- int flags = (FMLForgePlugin.RUNTIME_DEOBF ? Modifier.PUBLIC : Modifier.PRIVATE) | Modifier.STATIC | Modifier.FINAL | 0x1000 /*SYNTHETIC*/; -- if (valuesField == null) -- { -- String valueType = String.format("[L%s;", enumType.getName().replace('.', '/')); -+ final Method creatorHandle = enumType.getMethod("dynamicCreate", paramTypes); -+ T newValue = (T) creatorHandle.invoke(null, paramValues); - -- for (Field field : fields) -- { -- if ((field.getModifiers() & flags) == flags && -- field.getType().getName().replace('.', '/').equals(valueType)) //Apparently some JVMs return .'s and some don't.. -- { -- valuesField = field; -- break; -- } -+ // Add Enum Name / Class to Map -+ enumMap.put(enumName.toUpperCase(), newValue); -+ return newValue; -+ } catch (Exception e) { -+ throw new RuntimeException("Failed to add enum constant: " + enumName, e); - } - } -+ } - -- if (valuesField == null) -- { -- FMLLog.severe("Could not find $VALUES field for enum: %s", enumType.getName()); -- FMLLog.severe("Runtime Deobf: %s", FMLForgePlugin.RUNTIME_DEOBF); -- FMLLog.severe("Flags: %s", String.format("%16s", Integer.toBinaryString(flags)).replace(' ', '0')); -- FMLLog.severe("Fields:"); -- for (Field field : fields) -- { -- String mods = String.format("%16s", Integer.toBinaryString(field.getModifiers())).replace(' ', '0'); -- FMLLog.severe(" %s %s: %s", mods, field.getName(), field.getType().getName()); -- } -- return null; -+ private static final Class extensibleEnumIface; -+ private static final MethodHandle setFieldHandle; -+ -+ static { -+ try { -+ extensibleEnumIface = Class.forName("me.eigenraven.lwjgl3ify.IExtensibleEnum"); -+ Class unsafeHacks = Class.forName("me.eigenraven.lwjgl3ify.UnsafeHacks"); -+ Method setFieldM = unsafeHacks.getMethod("setField", Field.class, Object.class, Object.class); -+ setFieldHandle = MethodHandles.publicLookup() -+ .unreflect(setFieldM); -+ } catch (ReflectiveOperationException e) { -+ throw new RuntimeException(e); - } -+ } - -- valuesField.setAccessible(true); -+ // Cauldron start -+ public static Biome addBukkitBiome(String name) -+ { -+ return (Biome)addEnum(Biome.class, name, new Class[0], new Object[0]); -+ } - -- try -- { -- T[] previousValues = (T[])valuesField.get(enumType); -- List values = new ArrayList(Arrays.asList(previousValues)); -- T newValue = (T)makeEnum(enumType, enumName, values.size(), paramTypes, paramValues); -- values.add(newValue); -- setFailsafeFieldValue(valuesField, null, values.toArray((T[]) Array.newInstance(enumType, 0))); -- cleanEnumCache(enumType); -+ public static World.Environment addBukkitEnvironment(int id, String name) -+ { -+ return (World.Environment)addEnum(World.Environment.class, name, new Class[] { Integer.TYPE }, new Object[] { Integer.valueOf(id) }); -+ } - -- return newValue; -- } -- catch (Exception e) -- { -- e.printStackTrace(); -- throw new RuntimeException(e.getMessage(), e); -- } -+ public static WorldType addBukkitWorldType(String name) -+ { -+ WorldType worldType = addEnum(WorldType.class, name, new Class [] { String.class }, new Object[] { name }); -+ Map BY_NAME = ReflectionHelper.getPrivateValue(WorldType.class, null, "BY_NAME"); -+ BY_NAME.put(name.toUpperCase(), worldType); -+ -+ return worldType; - } - -- static -+ public static EntityType addBukkitEntityType(String name, Class clazz, int typeId, boolean independent) { -+ String entityType = name.replace("-", "_").toUpperCase(); -+ EntityType bukkitType = addEnum(EntityType.class, entityType, new Class[] { String.class, Class.class, Integer.TYPE, Boolean.TYPE }, new Object[] { name, clazz, typeId, independent }); -+ -+ Map NAME_MAP = ReflectionHelper.getPrivateValue(EntityType.class, null, "NAME_MAP"); -+ Map ID_MAP = ReflectionHelper.getPrivateValue(EntityType.class, null, "ID_MAP"); -+ -+ NAME_MAP.put(name.toLowerCase(), bukkitType); -+ ID_MAP.put((short)typeId, bukkitType); -+ -+ -+ return bukkitType; -+ } -+ -+ public static InventoryType addInventoryType(TileEntity tileentity) - { -- if (!isSetup) -+ if (!IInventory.class.isAssignableFrom(tileentity.getClass())) return null; -+ String id = (String)TileEntity.classToNameMap.get(tileentity.getClass()); -+ -+ try - { -- setup(); -+ IInventory teInv = (IInventory)tileentity; -+ int size = teInv.getSizeInventory(); -+ return addEnum(org.bukkit.event.inventory.InventoryType.class, id, new Class[]{Integer.TYPE, String.class}, new Object[]{size, id}); - } -+ catch (Throwable e) -+ { -+ if (MinecraftServer.getServer().tileEntityConfig.enableTEInventoryWarning.getValue()) -+ { -+ logger.log(Level.WARN, "Could not create inventory type " + tileentity.getClass().getName() + " Exception: " + e.toString()); -+ logger.log(Level.WARN, "Could not determine default inventory size for type " + tileentity.getClass().getName() + " using size of 9"); -+ } -+ return addEnum(org.bukkit.event.inventory.InventoryType.class, id, new Class[]{Integer.TYPE, String.class}, new Object[]{9, id}); -+ } - } -+ -+// @SuppressWarnings("unchecked") -+// public static > T replaceEnum(Class enumType, String enumName, int ordinal, Class[] paramTypes, Object[] paramValues) -+// { -+// -+// Field valuesField = null; -+// Field[] fields = enumType.getDeclaredFields(); -+// -+// for (Field field : fields) -+// { -+// String name = field.getName(); -+// if (name.equals("$VALUES") || name.equals("ENUM$VALUES")) //Added 'ENUM$VALUES' because Eclipse's internal compiler doesn't follow standards -+// { -+// valuesField = field; -+// break; -+// } -+// } -+// -+// int flags = (FMLForgePlugin.RUNTIME_DEOBF ? Modifier.PUBLIC : Modifier.PRIVATE) | Modifier.STATIC | Modifier.FINAL | 0x1000 /*SYNTHETIC*/; -+// if (valuesField == null) -+// { -+// String valueType = String.format("[L%s;", enumType.getName().replace('.', '/')); -+// -+// for (Field field : fields) -+// { -+// if ((field.getModifiers() & flags) == flags && -+// field.getType().getName().replace('.', '/').equals(valueType)) //Apparently some JVMs return .'s and some don't.. -+// { -+// valuesField = field; -+// break; -+// } -+// } -+// } -+// -+// if (valuesField == null) -+// { -+// FMLLog.severe("Could not find $VALUES field for enum: %s", enumType.getName()); -+// FMLLog.severe("Runtime Deobf: %s", FMLForgePlugin.RUNTIME_DEOBF); -+// FMLLog.severe("Flags: %s", String.format("%16s", Integer.toBinaryString(flags)).replace(' ', '0')); -+// FMLLog.severe("Fields:"); -+// for (Field field : fields) -+// { -+// String mods = String.format("%16s", Integer.toBinaryString(field.getModifiers())).replace(' ', '0'); -+// FMLLog.severe(" %s %s: %s", mods, field.getName(), field.getType().getName()); -+// } -+// return null; -+// } -+// -+// valuesField.setAccessible(true); -+// try -+// { -+// Enum[] previousValues = (Enum[])(Enum[])valuesField.get(enumType); -+// Enum[] newValues = new Enum[previousValues.length]; -+// Enum newValue = null; -+// for (Enum enumValue : previousValues) -+// { -+// if (enumValue.ordinal() == ordinal) -+// { -+// newValue = makeEnum(enumType, enumName, ordinal, paramTypes, paramValues); -+// newValues[enumValue.ordinal()] = newValue; -+// } -+// else newValues[enumValue.ordinal()] = enumValue; -+// } -+// List values = new ArrayList(Arrays.asList(newValues)); -+// setFailsafeFieldValue(valuesField, null, values.toArray((Enum[])(Enum[])Array.newInstance(enumType, 0))); -+// return (T) newValue; -+// } -+// catch (Exception e) -+// { -+// e.printStackTrace(); -+// throw new RuntimeException(e.getMessage(), e); -+// } -+// } -+ // Cauldron end - } diff --git a/patches/org/bukkit/plugin/PluginLogger.java.patch b/patches/org/bukkit/plugin/PluginLogger.java.patch index d19b24a9..7d5d34e1 100644 --- a/patches/org/bukkit/plugin/PluginLogger.java.patch +++ b/patches/org/bukkit/plugin/PluginLogger.java.patch @@ -1,25 +1,42 @@ --- ../src-base/minecraft/org/bukkit/plugin/PluginLogger.java +++ ../src-work/minecraft/org/bukkit/plugin/PluginLogger.java -@@ -22,14 +22,20 @@ +@@ -1,5 +1,7 @@ + package org.bukkit.plugin; + ++import io.github.crucible.JulLogManager; ++ + import java.util.logging.Level; + import java.util.logging.LogRecord; + import java.util.logging.Logger; +@@ -11,8 +13,7 @@ + * + * @see Logger + */ +-public class PluginLogger extends Logger { +- private String pluginName; ++public class PluginLogger extends JulLogManager.JulToLog4jLogger { + + /** + * Creates a new PluginLogger that extracts the name from a plugin. +@@ -20,17 +21,12 @@ + * @param context A reference to the plugin + */ public PluginLogger(Plugin context) { - super(context.getClass().getCanonicalName(), null); - String prefix = context.getDescription().getPrefix(); +- super(context.getClass().getCanonicalName(), null); +- String prefix = context.getDescription().getPrefix(); - pluginName = prefix != null ? new StringBuilder().append("[").append(prefix).append("] ").toString() : "[" + context.getDescription().getName() + "] "; -+ // Crucible start - give plugins a proper prefix for log4j -+ //pluginName = prefix != null ? new StringBuilder().append("[").append(prefix).append("] ").toString() : "[" + context.getDescription().getName() + "] "; -+ pluginName = prefix != null ? prefix : context.getDescription().getName(); -+ // Crucible end - setParent(context.getServer().getLogger()); +- setParent(context.getServer().getLogger()); ++ super(getLoggerName(context)); setLevel(Level.ALL); } - @Override - public void log(LogRecord logRecord) { +- @Override +- public void log(LogRecord logRecord) { - logRecord.setMessage(pluginName + logRecord.getMessage()); -+ // Crucible start - fix log4j prefix -+ //logRecord.setMessage(pluginName + logRecord.getMessage()); -+ logRecord.setLoggerName(pluginName); -+ // Crucible end - super.log(logRecord); +- super.log(logRecord); ++ private static String getLoggerName(Plugin context) { ++ String prefix = context.getDescription().getPrefix(); ++ return prefix != null ? prefix : context.getDescription().getName(); } - +- + } diff --git a/patches/org/bukkit/plugin/java/PluginClassLoader.java.patch b/patches/org/bukkit/plugin/java/PluginClassLoader.java.patch index 55da34a0..273f00be 100644 --- a/patches/org/bukkit/plugin/java/PluginClassLoader.java.patch +++ b/patches/org/bukkit/plugin/java/PluginClassLoader.java.patch @@ -1,20 +1,28 @@ --- ../src-base/minecraft/org/bukkit/plugin/java/PluginClassLoader.java +++ ../src-work/minecraft/org/bukkit/plugin/java/PluginClassLoader.java -@@ -1,5 +1,23 @@ +@@ -1,5 +1,31 @@ package org.bukkit.plugin.java; +// Cauldron start ++import com.gtnewhorizons.retrofuturabootstrap.Main; ++import com.gtnewhorizons.retrofuturabootstrap.URLClassLoaderBase; ++import com.gtnewhorizons.retrofuturabootstrap.api.RfbClassTransformer; ++import io.github.crucible.api.CruciblePluginTransform; +import net.md_5.specialsource.provider.ClassLoaderProvider; +import net.md_5.specialsource.transformer.MavenShade; +//import org.bouncycastle.util.io.Streams; +import net.md_5.specialsource.*; +import net.md_5.specialsource.repo.*; ++import net.minecraft.launchwrapper.LaunchClassLoader; +import net.minecraft.server.MinecraftServer; +import net.minecraftforge.cauldron.CauldronUtils; + +import org.bukkit.craftbukkit.v1_7_R4.CraftServer; +import org.bukkit.plugin.PluginDescriptionFile; +import java.io.*; ++import java.lang.invoke.MethodHandle; ++import java.lang.invoke.MethodHandles; ++import java.lang.reflect.Method; +import java.net.JarURLConnection; +import java.security.CodeSigner; +import java.security.CodeSource; @@ -24,7 +32,11 @@ import java.io.File; import java.net.MalformedURLException; import java.net.URL; -@@ -10,21 +28,46 @@ +@@ -7,24 +33,69 @@ + import java.util.HashMap; + import java.util.Map; + import java.util.Set; ++import java.util.jar.Manifest; import org.apache.commons.lang.Validate; import org.bukkit.plugin.InvalidPluginException; @@ -35,6 +47,22 @@ */ -final class PluginClassLoader extends URLClassLoader { +public class PluginClassLoader extends URLClassLoader { ++ private static final LaunchClassLoader launchClassLoader = (LaunchClassLoader) PluginClassLoader.class.getClassLoader(); ++ private static final MethodHandle runTransformersMH; ++ ++ static { ++ MethodHandle runTransformersMHTmp; ++ try { ++ Method method = LaunchClassLoader.class.getDeclaredMethod("runTransformers", String.class, String.class, byte[].class); ++ method.setAccessible(true); ++ runTransformersMHTmp = MethodHandles.lookup().unreflect(method); ++ } catch (NoSuchMethodException | IllegalAccessException e) { ++ e.printStackTrace(); ++ runTransformersMHTmp = null; ++ } ++ runTransformersMH = runTransformersMHTmp; ++ } ++ + public JavaPlugin getPlugin() { return plugin; } // Spigot private final JavaPluginLoader loader; - private final Map> classes = new HashMap>(); @@ -51,6 +79,9 @@ + private RemapperProcessor remapperProcessor; // secondary; for inheritance & remapping reflection + private boolean debug; // classloader debugging + private int remapFlags = -1; ++ private boolean runRfbTransformers; ++ private boolean runLwTransformers; ++ private boolean runPluginTransformers; + private static ConcurrentMap jarMappings = new ConcurrentHashMap(); + private static final int F_GLOBAL_INHERIT = 1 << 1; @@ -75,7 +106,7 @@ PluginClassLoader(final JavaPluginLoader loader, final ClassLoader parent, final PluginDescriptionFile description, final File dataFolder, final File file) throws InvalidPluginException, MalformedURLException { super(new URL[] {file.toURI().toURL()}, parent); Validate.notNull(loader, "Loader cannot be null"); -@@ -34,6 +77,116 @@ +@@ -34,6 +105,121 @@ this.dataFolder = dataFolder; this.file = file; @@ -104,6 +135,9 @@ + boolean reflectClass = MinecraftServer.cauldronConfig.getBoolean("plugin-settings.default.remap-reflect-class", true); + boolean allowFuture = MinecraftServer.cauldronConfig.getBoolean("plugin-settings.default.remap-allow-future", false); + boolean remapGuava = MinecraftServer.cauldronConfig.getBoolean("plugin-settings.default.remap-guava", true); ++ runRfbTransformers = MinecraftServer.cauldronConfig.getBoolean("plugin-settings.default.rfb-transformers", true); ++ runLwTransformers = MinecraftServer.cauldronConfig.getBoolean("plugin-settings.default.lw-transformers", false); ++ runPluginTransformers = MinecraftServer.cauldronConfig.getBoolean("plugin-settings.default.plugin-transformers", true); + + // plugin-specific overrides + useCustomClassLoader = MinecraftServer.cauldronConfig.getBoolean("plugin-settings."+pluginName+".custom-class-loader", useCustomClassLoader, false); @@ -126,73 +160,75 @@ + reflectClass = MinecraftServer.cauldronConfig.getBoolean("plugin-settings."+pluginName+".remap-reflect-class", reflectClass, false); + allowFuture = MinecraftServer.cauldronConfig.getBoolean("plugin-settings."+pluginName+".remap-allow-future", allowFuture, false); + remapGuava = MinecraftServer.cauldronConfig.getBoolean("plugin-settings."+pluginName+".remap-guava", remapGuava, false); ++ runRfbTransformers = MinecraftServer.cauldronConfig.getBoolean("plugin-settings."+pluginName+".rfb-transformers", runRfbTransformers, false); ++ runLwTransformers = MinecraftServer.cauldronConfig.getBoolean("plugin-settings."+pluginName+".lw-transformers", runLwTransformers, false); ++ runPluginTransformers = MinecraftServer.cauldronConfig.getBoolean("plugin-settings."+pluginName+".plugin-transformers", runPluginTransformers, false); + + if (debug) { + System.out.println("PluginClassLoader debugging enabled for "+pluginName); + } + -+ if (!useCustomClassLoader) { -+ remapper = null; -+ return; -+ } -+ -+ int flags = 0; -+ if (remapNMS1710) flags |= F_REMAP_NMS1710; -+ if (remapNMS179) flags |= F_REMAP_NMS179; -+ if (remapNMS172) flags |= F_REMAP_NMS172; -+ if (remapNMS164) flags |= F_REMAP_NMS164; -+ if (remapNMS152) flags |= F_REMAP_NMS152; -+ if (!remapNMSPre.equals("false")) { -+ if (remapNMSPre.equals("1.7.10")) flags |= 0x17100000; -+ else if (remapNMSPre.equals("1.7.9")) flags |= 0x01790000; -+ else if (remapNMSPre.equals("1.7.2")) flags |= 0x01720000; -+ else if (remapNMSPre.equals("1.6.4")) flags |= 0x01640000; -+ else if (remapNMSPre.equals("1.5.2")) flags |= 0x01520000; -+ else { -+ System.out.println("Unsupported nms-remap-pre version '"+remapNMSPre+"', disabling"); ++ if (useCustomClassLoader) { ++ int flags = 0; ++ if (remapNMS1710) flags |= F_REMAP_NMS1710; ++ if (remapNMS179) flags |= F_REMAP_NMS179; ++ if (remapNMS172) flags |= F_REMAP_NMS172; ++ if (remapNMS164) flags |= F_REMAP_NMS164; ++ if (remapNMS152) flags |= F_REMAP_NMS152; ++ if (!remapNMSPre.equals("false")) { ++ if (remapNMSPre.equals("1.7.10")) flags |= 0x17100000; ++ else if (remapNMSPre.equals("1.7.9")) flags |= 0x01790000; ++ else if (remapNMSPre.equals("1.7.2")) flags |= 0x01720000; ++ else if (remapNMSPre.equals("1.6.4")) flags |= 0x01640000; ++ else if (remapNMSPre.equals("1.5.2")) flags |= 0x01520000; ++ else { ++ System.out.println("Unsupported nms-remap-pre version '"+remapNMSPre+"', disabling"); ++ } + } -+ } -+ if (remapOBC1710) flags |= F_REMAP_OBC1710; -+ if (remapOBC179) flags |= F_REMAP_OBC179; -+ if (remapOBC172) flags |= F_REMAP_OBC172; -+ if (remapOBC164) flags |= F_REMAP_OBC164; -+ if (remapOBC152) flags |= F_REMAP_OBC152; -+ if (remapOBCPre) flags |= F_REMAP_OBCPRE; -+ if (remapGuava) flags |= F_REMAP_GUAVA; -+ if (globalInherit) flags |= F_GLOBAL_INHERIT; -+ -+ remapFlags = flags; // used in findClass0 -+ JarMapping jarMapping = getJarMapping(flags); -+ -+ // Load inheritance map -+ if ((flags & F_GLOBAL_INHERIT) != 0) { -+ if (debug) { -+ System.out.println("Enabling global inheritance remapping"); -+ //ClassLoaderProvider.verbose = debug; // TODO: changed in https://github.com/md-5/SpecialSource/commit/132584eda4f0860c9d14f4c142e684a027a128b8#L3L48 ++ if (remapOBC1710) flags |= F_REMAP_OBC1710; ++ if (remapOBC179) flags |= F_REMAP_OBC179; ++ if (remapOBC172) flags |= F_REMAP_OBC172; ++ if (remapOBC164) flags |= F_REMAP_OBC164; ++ if (remapOBC152) flags |= F_REMAP_OBC152; ++ if (remapOBCPre) flags |= F_REMAP_OBCPRE; ++ if (remapGuava) flags |= F_REMAP_GUAVA; ++ if (globalInherit) flags |= F_GLOBAL_INHERIT; ++ ++ remapFlags = flags; // used in findClass0 ++ JarMapping jarMapping = getJarMapping(flags); ++ ++ // Load inheritance map ++ if ((flags & F_GLOBAL_INHERIT) != 0) { ++ if (debug) { ++ System.out.println("Enabling global inheritance remapping"); ++ //ClassLoaderProvider.verbose = debug; // TODO: changed in https://github.com/md-5/SpecialSource/commit/132584eda4f0860c9d14f4c142e684a027a128b8#L3L48 ++ } ++ jarMapping.setInheritanceMap(loader.getGlobalInheritanceMap()); ++ jarMapping.setFallbackInheritanceProvider(new ClassLoaderProvider(this)); + } -+ jarMapping.setInheritanceMap(loader.getGlobalInheritanceMap()); -+ jarMapping.setFallbackInheritanceProvider(new ClassLoaderProvider(this)); -+ } + -+ remapper = new thermos.ThermosRemapper(jarMapping); ++ remapper = new thermos.ThermosRemapper(jarMapping); + -+ if (pluginInherit || reflectFields || reflectClass) { -+ remapperProcessor = new RemapperProcessor( -+ pluginInherit ? loader.getGlobalInheritanceMap() : null, -+ (reflectFields || reflectClass) ? jarMapping : null); ++ if (pluginInherit || reflectFields || reflectClass) { ++ remapperProcessor = new RemapperProcessor( ++ pluginInherit ? loader.getGlobalInheritanceMap() : null, ++ (reflectFields || reflectClass) ? jarMapping : null); + -+ remapperProcessor.setRemapReflectField(reflectFields); -+ remapperProcessor.setRemapReflectClass(reflectClass); -+ remapperProcessor.debug = debug; -+ } else { -+ remapperProcessor = null; ++ remapperProcessor.setRemapReflectField(reflectFields); ++ remapperProcessor.setRemapReflectClass(reflectClass); ++ remapperProcessor.debug = debug; ++ } else { ++ remapperProcessor = null; ++ } + } ++ ++ + // Cauldron end + try { Class jarClass; try { -@@ -58,34 +211,291 @@ +@@ -58,34 +244,333 @@ } @Override @@ -378,12 +414,22 @@ + if (name.startsWith("net.minecraft.")) + { + JarMapping jarMapping = this.getJarMapping(remapFlags); // grab from SpecialSource -+ String remappedClass = jarMapping.classes.get(name.replaceAll("\\.", "\\/")); // get remapped pkgmcp class name -+ if (remappedClass == null){ ++ String remappedClass = jarMapping.classes.get(name.replace('.', '/')); // get remapped pkgmcp class name ++ if(remappedClass == null) { + throw new ClassNotFoundException(name); + } -+ Class clazz = ((net.minecraft.launchwrapper.LaunchClassLoader)MinecraftServer.getServer().getClass().getClassLoader()).findClass(remappedClass); -+ return clazz; ++ try { ++ Class clazz = ((net.minecraft.launchwrapper.LaunchClassLoader)MinecraftServer.getServer().getClass().getClassLoader()).findClass(remappedClass); ++ if(debug) { ++ System.out.printf("Found class %s (remapped to %s, found %s)\n", name, remappedClass, clazz.getName()); ++ } ++ return clazz; ++ } catch (Throwable e) { ++ if(debug) { ++ System.out.printf("Not found class %s (remapped %s)\n", name, remappedClass); ++ } ++ throw e; ++ } + } + if (name.startsWith("org.bukkit.")) { + if (debug) { @@ -402,7 +448,7 @@ + } + if (result == null) { -+ if (remapper == null) { ++ if (remapper == null && !runRfbTransformers && !runLwTransformers && !runPluginTransformers) { + result = super.findClass(name); + } else { + result = remappedFindClass(name); @@ -445,13 +491,31 @@ + bytecode = remapperProcessor.process(stream); + if (bytecode == null) stream = url.openStream(); + } ++ JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection(); // parses only ++ URL jarURL = jarURLConnection.getJarFileURL(); ++ CodeSource codeSource = new CodeSource(jarURL, new CodeSigner[0]); ++ Manifest manifest = jarURLConnection.getManifest(); + -+ /*if (bytecode == null) { -+ bytecode = Streams.readAll(stream); -+ }*/ ++ if (bytecode == null) { ++ bytecode = URLClassLoaderBase.readAllBytes(stream, null); ++ } + + // Remap the classes -+ byte[] remappedBytecode = remapper.remapClassFile(bytecode, RuntimeRepo.getInstance()); ++ byte[] remappedBytecode = bytecode; ++ if(remapper != null) { ++ remappedBytecode = remapper.remapClassFile(bytecode, RuntimeRepo.getInstance()); ++ } ++ if(runLwTransformers) { ++ remappedBytecode = (byte[]) runTransformersMH.invoke(launchClassLoader, name, name, remappedBytecode); ++ } ++ if(runPluginTransformers) { ++ remappedBytecode = CruciblePluginTransform.transform(name, name, remappedBytecode, plugin); ++ } ++ if(runRfbTransformers) { ++ remappedBytecode = launchClassLoader.runRfbTransformers( ++ Main.getRfbTransformers(), runLwTransformers ? RfbClassTransformer.Context.LCL_WITH_TRANSFORMS : RfbClassTransformer.Context.LCL_NO_TRANSFORMS, ++ manifest, name, remappedBytecode); ++ } + + if (debug) { + File file = new File("remapped-plugin-classes/"+name+".class"); @@ -465,15 +529,29 @@ + } + } + ++ ++ // Define the package before defining the class so Class.getPackage() ++ // resolves on Java 8 (it returns null for packages the loader never ++ // defined). URLClassLoader does this for the normal findClass path, ++ // but this remap path calls defineClass directly and must do it itself. ++ int packageDot = name.lastIndexOf('.'); ++ if (packageDot != -1) { ++ String packageName = name.substring(0, packageDot); ++ try { ++ if (manifest != null) { ++ definePackage(packageName, manifest, jarURL); ++ } else { ++ definePackage(packageName, null, null, null, null, null, null, null); ++ } ++ } catch (IllegalArgumentException ignored) { ++ // Already defined by another class in this package or thread. ++ } ++ } + // Define (create) the class using the modified byte code + // The top-child class loader is used for this to prevent access violations + // Set the codesource to the jar, not within the jar, for compatibility with + // plugins that do new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI())) + // instead of using getResourceAsStream - see https://github.com/MinecraftPortCentral/Cauldron-Plus/issues/75 -+ JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection(); // parses only -+ URL jarURL = jarURLConnection.getJarFileURL(); -+ CodeSource codeSource = new CodeSource(jarURL, new CodeSigner[0]); -+ + result = this.defineClass(name, remappedBytecode, 0, remappedBytecode.length, codeSource); + if (result != null) { + // Resolve it - sets the class loader of the class diff --git a/src/main/java/io/github/crucible/JulLogManager.java b/src/main/java/io/github/crucible/JulLogManager.java new file mode 100644 index 00000000..8a61ac4f --- /dev/null +++ b/src/main/java/io/github/crucible/JulLogManager.java @@ -0,0 +1,247 @@ +package io.github.crucible; + +import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.message.MessageFactory; + +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +/** + * Backport and simplify log4j2-jul + */ +public class JulLogManager extends LogManager { + + @Override + public boolean addLogger(Logger logger) { + return false; + } + + @Override + public Logger getLogger(String name) { + try { + return new JulToLog4jLogger(name); + } catch (Throwable e) { + return new JulNoopLogger(name); + } + } + + public static class JulNoopLogger extends Logger { + + protected JulNoopLogger(String name) { + super(name, null); + } + } + + public static class JulToLog4jLogger extends Logger { + private final org.apache.logging.log4j.Logger logger; + + public JulToLog4jLogger(String name) { + super(name, null); + this.logger = org.apache.logging.log4j.LogManager.getLogger(name); + } + + @Override + public void log(LogRecord record) { + final org.apache.logging.log4j.Level level = convertLevel(record.getLevel()); + final Object[] parameters = record.getParameters(); + final MessageFactory messageFactory = logger.getMessageFactory(); + final Message message = parameters == null + ? messageFactory.newMessage(record.getMessage()) + : messageFactory.newMessage(record.getMessage(), parameters); + final Throwable thrown = record.getThrown(); + logger.log(level, null, message, thrown); + } + + @Override + public boolean isLoggable(Level level) { + return logger.isEnabled(convertLevel(level)); + } + + @Override + public String getName() { + return super.getName(); + } + + @Override + public Level getLevel() { + return super.getLevel(); + } + + @Override + public void setLevel(Level newLevel) throws SecurityException { + super.setLevel(newLevel); + } + + public org.apache.logging.log4j.Level convertLevel(Level level) { + if(level == Level.ALL) { + return org.apache.logging.log4j.Level.ALL; + } + if(level == Level.FINEST || level == Level.FINER) { + return org.apache.logging.log4j.Level.TRACE; + } + if(level == Level.FINE) { + return org.apache.logging.log4j.Level.DEBUG; + } + if(level == Level.INFO) { + return org.apache.logging.log4j.Level.INFO; + } + if(level == Level.WARNING) { + return org.apache.logging.log4j.Level.WARN; + } + if(level == Level.SEVERE) { + return org.apache.logging.log4j.Level.ERROR; + } + return org.apache.logging.log4j.Level.TRACE; + } + + @Override + public void setParent(final Logger parent) { + logger.warn("Logger.setParent() not supported by jul-to-log4j LogManager. Logs may be broken"); + } + + @Override + public Logger getParent() { + final org.apache.logging.log4j.core.Logger parent = ((org.apache.logging.log4j.core.Logger)logger).getParent(); + return parent == null ? null : Logger.getLogger(parent.getName()); + } + + @Override + public void log(final Level level, final String msg) { + logger.log(convertLevel(level), msg); + } + + @Override + public void log(final Level level, final String msg, final Object param1) { + logger.log(convertLevel(level), msg, param1); + } + + @Override + public void log(final Level level, final String msg, final Object[] params) { + logger.log(convertLevel(level), msg, params); + } + + @Override + public void log(final Level level, final String msg, final Throwable thrown) { + logger.log(convertLevel(level), msg, thrown); + } + + @Override + public void logp(final Level level, final String sourceClass, final String sourceMethod, final String msg) { + log(level, msg); + } + + @Override + public void logp( + final Level level, + final String sourceClass, + final String sourceMethod, + final String msg, + final Object param1) { + log(level, msg, param1); + } + + @Override + public void logp( + final Level level, + final String sourceClass, + final String sourceMethod, + final String msg, + final Object[] params) { + log(level, msg, params); + } + + @Override + public void logp( + final Level level, + final String sourceClass, + final String sourceMethod, + final String msg, + final Throwable thrown) { + log(level, msg, thrown); + } + + @Override + public void logrb( + final Level level, + final String sourceClass, + final String sourceMethod, + final String bundleName, + final String msg) { + log(level, msg); + } + + @Override + public void logrb( + final Level level, + final String sourceClass, + final String sourceMethod, + final String bundleName, + final String msg, + final Object param1) { + log(level, msg, param1); + } + + @Override + public void logrb( + final Level level, + final String sourceClass, + final String sourceMethod, + final String bundleName, + final String msg, + final Object[] params) { + log(level, msg, params); + } + + @Override + public void logrb( + final Level level, + final String sourceClass, + final String sourceMethod, + final String bundleName, + final String msg, + final Throwable thrown) { + log(level, msg, thrown); + } + + @Override + public void throwing(final String sourceClass, final String sourceMethod, final Throwable thrown) { + logger.throwing(thrown); + } + + @Override + public void severe(final String msg) { + logger.log(org.apache.logging.log4j.Level.ERROR, null, msg); + } + + @Override + public void warning(final String msg) { + logger.log(org.apache.logging.log4j.Level.WARN, null, msg); + } + + @Override + public void info(final String msg) { + logger.log(org.apache.logging.log4j.Level.INFO, null, msg); + } + + @Override + public void config(final String msg) { + logger.log(org.apache.logging.log4j.Level.INFO, null, msg); + } + + @Override + public void fine(final String msg) { + logger.log(org.apache.logging.log4j.Level.DEBUG, null, msg); + } + + @Override + public void finer(final String msg) { + logger.log(org.apache.logging.log4j.Level.TRACE, null, msg); + } + + @Override + public void finest(final String msg) { + logger.log(org.apache.logging.log4j.Level.TRACE, null, msg); + } + } +} diff --git a/src/main/java/io/github/crucible/api/CruciblePluginTransform.java b/src/main/java/io/github/crucible/api/CruciblePluginTransform.java new file mode 100644 index 00000000..488e7702 --- /dev/null +++ b/src/main/java/io/github/crucible/api/CruciblePluginTransform.java @@ -0,0 +1,34 @@ +package io.github.crucible.api; + +import org.bukkit.plugin.Plugin; + +import java.util.ArrayList; +import java.util.List; + +public class CruciblePluginTransform { + private static final List transformers = new ArrayList<>(); + + public static byte[] transform(String name, String transformedName, byte[] basicClass, Plugin plugin) { + byte[] result = basicClass; + for(IPluginClassTransformer transformer : transformers) { + byte[] bytes = transformer.transform(name, transformedName, result, plugin); + if(bytes != null) { + result = bytes; + } + } + return result; + } + + public static void register(IPluginClassTransformer transformer) { + transformers.add(transformer); + } + + public static void unregister(IPluginClassTransformer transformer) { + transformers.remove(transformer); + } + + @FunctionalInterface + public interface IPluginClassTransformer { + byte[] transform(String name, String transformedName, byte[] basicClass, Plugin plugin); + } +} diff --git a/src/main/java/io/github/crucible/bootstrap/CrucibleCoremodHook.java b/src/main/java/io/github/crucible/bootstrap/CrucibleCoremodHook.java index 9621729b..55827275 100644 --- a/src/main/java/io/github/crucible/bootstrap/CrucibleCoremodHook.java +++ b/src/main/java/io/github/crucible/bootstrap/CrucibleCoremodHook.java @@ -15,6 +15,9 @@ public static void coremodHandleLaunch(File mcDir, LaunchClassLoader classLoader } catch (ClassNotFoundException e) { throw new RuntimeException(e); } - Lwjgl3ifyGlue.doCoremodWork(classLoader); + + classLoader.registerTransformer("io.github.crucible.patches.RecurrentComplexTransformer"); + classLoader.registerTransformer("io.github.crucible.patches.StreamsTransformer"); + classLoader.registerTransformer("thermos.ThermosClassTransformer"); } } diff --git a/src/main/java/io/github/crucible/bootstrap/CrucibleServerMainHook.java b/src/main/java/io/github/crucible/bootstrap/CrucibleServerMainHook.java index 05c1fdc9..d1958377 100644 --- a/src/main/java/io/github/crucible/bootstrap/CrucibleServerMainHook.java +++ b/src/main/java/io/github/crucible/bootstrap/CrucibleServerMainHook.java @@ -7,11 +7,16 @@ import java.io.FileReader; import java.io.IOException; import java.io.PrintStream; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.NoSuchAlgorithmException; import java.util.*; +import java.util.jar.Attributes; +import java.util.jar.JarInputStream; +import java.util.jar.Manifest; +import java.util.stream.Collectors; // DO NOT TRY TO LOAD ANY MINECRAFT CLASS FROM HERE, THIS CLASS IS LOADED BEFORE EVERYTHING ON THE SERVER ENTRYPOINT // Also avoid using streams here @@ -21,7 +26,8 @@ public class CrucibleServerMainHook { "https://github.com/juanmuscaria/maven/raw/master/ThermosLibs/", "https://maven.minecraftforge.net/", "https://libraries.minecraft.net/", - "https://repo.maven.apache.org/maven2/" + "https://repo.maven.apache.org/maven2/", + "https://nexus.gtnewhorizons.com/repository/public/" }; private static final Path LIBRARY_ROOT = Paths.get("libraries").toAbsolutePath(); public static final PrintStream originalOut = System.out; @@ -52,7 +58,13 @@ public static void relaunchMain(String[] args) throws Exception { System.setProperty((String) entry.getKey(), (String) entry.getValue()); } - Lwjgl3ifyGlue.checkJava(); + if(System.getProperty("java.class.loader") == null) { + System.setProperty("rfb.skipClassLoaderCheck", "true"); + } + System.setProperty("java.util.logging.manager", "io.github.crucible.JulLogManager"); + if(!Boolean.getBoolean("crucible.skipFixClasspath")) { + fixClasspathProperty(); + } if (!verifyLibraries()) { setupLibraries(); @@ -99,6 +111,31 @@ private static void setupLibraries() throws InterruptedException { LibraryManager.downloadMavenLibraries(LIBRARY_ROOT, list.toArray(new String[0]), CrucibleMetadata.NEEDED_LIBRARIES); } + private static void fixClasspathProperty() { + String[] classpath = System.getProperty("java.class.path").split(File.pathSeparator); + URL location = CrucibleServerMainHook.class.getProtectionDomain().getCodeSource().getLocation(); + if(location == null || !location.toString().endsWith(".jar")) { + return; + } + try(JarInputStream input = new JarInputStream(location.openStream())){ + Manifest manifest = input.getManifest(); + String classPathFromManifest = (String) manifest.getMainAttributes().get(new Attributes.Name("Class-Path")); + String[] internalClasspath = classPathFromManifest.split(" "); + Set set = new HashSet<>(); + Collections.addAll(set, classpath); + List allClasspath = new ArrayList<>(classpath.length + internalClasspath.length); + Collections.addAll(allClasspath, classpath); + for(String s : internalClasspath) { + if(!set.contains(s)) { + allClasspath.add(s); + } + } + System.setProperty("java.class.path", String.join(File.pathSeparator, allClasspath)); + } catch (Throwable e) { + e.printStackTrace(); + } + } + public static void restoreStreams() { System.setOut(originalOut); System.setErr(originalErr); diff --git a/src/main/java/io/github/crucible/bootstrap/LibraryManager.java b/src/main/java/io/github/crucible/bootstrap/LibraryManager.java index 3458b525..d70406eb 100644 --- a/src/main/java/io/github/crucible/bootstrap/LibraryManager.java +++ b/src/main/java/io/github/crucible/bootstrap/LibraryManager.java @@ -22,7 +22,8 @@ import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; -import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicInteger; @@ -38,7 +39,7 @@ public static void downloadMavenLibraries(Path baseDir, String[] repos, String.. reposUri[i] = URI.create(repos[i]); } - ForkJoinPool pool = new ForkJoinPool((Runtime.getRuntime().availableProcessors() * 2) + 1); + ExecutorService pool = Executors.newFixedThreadPool(Math.min(libraries.length, 16)); List> tasks = new ArrayList<>(libraries.length); for (String library : libraries) { tasks.add(makeMavenDownloadTask(baseDir, reposUri, library)); @@ -59,6 +60,8 @@ public static void downloadMavenLibraries(Path baseDir, String[] repos, String.. } } + pool.shutdown(); + if (failed) { throw new RuntimeException("Failed to download one or more essential files for the server, check your logs for more information"); } @@ -126,6 +129,8 @@ public Boolean call() throws Exception { URI uriPath = repo.resolve(jarRelativeName).normalize(); file = uriPath.toURL(); HttpURLConnection connection = (HttpURLConnection) file.openConnection(); + connection.setConnectTimeout(10000); + connection.setReadTimeout(10000); connection.setRequestMethod("GET"); connection.connect(); if (connection.getResponseCode() >= 200 || connection.getResponseCode() <= 399) { diff --git a/src/main/java/io/github/crucible/bootstrap/Lwjgl3ifyGlue.java b/src/main/java/io/github/crucible/bootstrap/Lwjgl3ifyGlue.java index ebc0af3c..4e24df6e 100644 --- a/src/main/java/io/github/crucible/bootstrap/Lwjgl3ifyGlue.java +++ b/src/main/java/io/github/crucible/bootstrap/Lwjgl3ifyGlue.java @@ -23,16 +23,23 @@ public class Lwjgl3ifyGlue { "net.minecraftforge.event.terraingen.InitMapGenEvent$EventType", "net.minecraftforge.event.terraingen.OreGenEvent$GenerateMinable$EventType", "net.minecraftforge.event.terraingen.DecorateBiomeEvent$Decorate$EventType", + "net.minecraftforge.common.BiomeDictionary$Type", // From GTNH crashes "vswe.stevesfactory.Localization", "vswe.stevesfactory.blocks.ClusterMethodRegistration", "vswe.stevesfactory.blocks.ConnectionBlockType", "vswe.stevesfactory.components.ComponentType", "vswe.stevesfactory.components.ConnectionSet", "vswe.stevesfactory.components.ConnectionOption", "ic2.core.init.InternalName", "gregtech.api.enums.Element", "gregtech.api.enums.OrePrefixes", - "net.minecraft.client.audio.MusicTicker$MusicType", - "buildcraft.api.transport.IPipeTile.PipeType", "thaumcraft.common.entities.golems.EnumGolemType", + "net.minecraft.client.audio.MusicTicker$MusicType", "org.bukkit.Material", + "buildcraft.api.transport.IPipeTile$PipeType", "thaumcraft.common.entities.golems.EnumGolemType", // Non-GTNH Mods Compat // The Lord of the Rings Mod: Legacy "net.minecraft.event.HoverEvent$Action", + // LotR Addons + "lotr.common.fac.LOTRFaction", "lotr.common.quest.LOTRMiniQuestFactory", "lotr.common.world.map.LOTRWaypoint", + "lotr.common.world.map.LOTRWaypoint$Region", "lotr.common.world.spawning.LOTRInvasions", + "lotr.common.LOTRShields", "lotr.common.LOTRDimension$DimensionRegion", + "lotr.common.item.LOTRItemBanner$BannerType", "lotr.common.LOTRAchievement$Category", + "lotr.client.gui.LOTRMapLabels", // Reika's mods "net.minecraft.client.audio.SoundCategory", "Reika.RotaryCraft.TileEntities.Processing.TileEntityFuelConverter$Conversions", @@ -42,18 +49,19 @@ public class Lwjgl3ifyGlue { "Reika.DragonAPI.ModInteract.Bees.BeeAlleleRegistry$Territory", "Reika.DragonAPI.ModInteract.Bees.BeeAlleleRegistry$Life", "Reika.DragonAPI.ModInteract.Bees.ButterflyAlleleRegistry$Fertility", - "Reika.DragonAPI.ModInteract.Bees.ButterflyAlleleRegistry$Life", + "Reika.DragonAPI.ModInteract.Bees.ButterflyAlleleRegistry$Life", "Reika.DragonAPI.ModRegistry.ModCropList", // Et Futurum Requiem "net.minecraft.world.WorldSettings$GameType", - // Minechem - "net.minecraftforge.common.BiomeDictionary$Type", + "ganymedes01.etfuturum.tileentities.TileEntityBanner$EnumBannerPattern", + // EnderIO Addons + "crazypants.enderio.ModObject", // Bukkit Enums - "org.bukkit.Material", "org.bukkit.block.Biome", "org.bukkit.World$Environment", "org.bukkit.WorldType", "org.bukkit.entity.EntityType", "org.bukkit.event.inventory.InventoryType", + // }; public static void checkJava() { diff --git a/src/main/java/io/github/crucible/bootstrap/Lwjgl3ifyIntegration.java b/src/main/java/io/github/crucible/bootstrap/Lwjgl3ifyIntegration.java new file mode 100644 index 00000000..270e7d31 --- /dev/null +++ b/src/main/java/io/github/crucible/bootstrap/Lwjgl3ifyIntegration.java @@ -0,0 +1,82 @@ +package io.github.crucible.bootstrap; + +import io.github.crucible.CrucibleConfigs; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Set; + +/** + * Integration with lwjgl3ify mod when present as optional dependency. + * This class uses reflection to avoid hard dependency on lwjgl3ify. + * + * IMPORTANT: This must be called BEFORE any enum classes are loaded, as the + * ExtensibleEnumTransformer checks EarlyConfig.EXTENSIBLE_ENUMS during class transformation. + */ +public class Lwjgl3ifyIntegration { + + private static boolean initialized = false; + private static boolean lwjgl3ifyPresent = false; + + /** + * Attempts to register extensible enums with lwjgl3ify if it's present. + * This method MUST be called early in the initialization process, before any enum classes are loaded. + * + * This directly adds enums to EarlyConfig.EXTENSIBLE_ENUMS set before the transformer runs. + */ + public static void registerExtensibleEnums() { + if (initialized) { + return; + } + initialized = true; + + try { + // Try to load lwjgl3ify's EarlyConfig class + // Note: EarlyConfig is excluded from LaunchClassLoader, so it loads in the system classloader + Class earlyConfigClass = Class.forName("me.eigenraven.lwjgl3ify.rfb.EarlyConfig"); + lwjgl3ifyPresent = true; + + System.out.println("[Crucible] lwjgl3ify detected, registering extensible enums..."); + + // Get the list of extensible enums from Crucible config + List extensibleEnums = CrucibleConfigs.configs.lwjgl3ify_extensibleEnums; + + if (extensibleEnums == null || extensibleEnums.isEmpty()) { + System.out.println("[Crucible] No extensible enums configured, skipping registration."); + return; + } + + // Get the EXTENSIBLE_ENUMS field directly + Field extensibleEnumsField = earlyConfigClass.getDeclaredField("EXTENSIBLE_ENUMS"); + extensibleEnumsField.setAccessible(true); + + @SuppressWarnings("unchecked") + Set lwjgl3ifyEnums = (Set) extensibleEnumsField.get(null); + + // Add all Crucible enums to lwjgl3ify's set + int registered = 0; + for (String enumClass : extensibleEnums) { + if (lwjgl3ifyEnums.add(enumClass)) { + registered++; + } + } + + System.out.println("[Crucible] Successfully registered " + registered + " extensible enums with lwjgl3ify."); + System.out.println("[Crucible] Total extensible enums: " + lwjgl3ifyEnums.size()); + + } catch (ClassNotFoundException e) { + // lwjgl3ify is not present, this is fine + System.out.println("[Crucible] lwjgl3ify not detected, extensible enum registration skipped."); + } catch (Exception e) { + System.err.println("[Crucible] Error while registering extensible enums with lwjgl3ify:"); + e.printStackTrace(); + } + } + + /** + * @return true if lwjgl3ify is present and initialized + */ + public static boolean isLwjgl3ifyPresent() { + return lwjgl3ifyPresent; + } +} diff --git a/src/main/java/io/github/crucible/bootstrap/rfb/CrucibleRfbPlugin.java b/src/main/java/io/github/crucible/bootstrap/rfb/CrucibleRfbPlugin.java new file mode 100644 index 00000000..1976dc89 --- /dev/null +++ b/src/main/java/io/github/crucible/bootstrap/rfb/CrucibleRfbPlugin.java @@ -0,0 +1,13 @@ +package io.github.crucible.bootstrap.rfb; + +import com.gtnewhorizons.retrofuturabootstrap.api.PluginContext; +import com.gtnewhorizons.retrofuturabootstrap.api.RfbPlugin; +import io.github.crucible.bootstrap.Lwjgl3ifyIntegration; +import org.jetbrains.annotations.NotNull; + +public class CrucibleRfbPlugin implements RfbPlugin { + @Override + public void onConstruction(@NotNull PluginContext ctx) { + Lwjgl3ifyIntegration.registerExtensibleEnums(); + } +} diff --git a/src/main/java/io/github/crucible/patches/RecurrentComplexTransformer.java b/src/main/java/io/github/crucible/patches/RecurrentComplexTransformer.java index 5a9ac637..93ffe5aa 100644 --- a/src/main/java/io/github/crucible/patches/RecurrentComplexTransformer.java +++ b/src/main/java/io/github/crucible/patches/RecurrentComplexTransformer.java @@ -1,41 +1,62 @@ package io.github.crucible.patches; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.InsnList; -import org.objectweb.asm.tree.MethodInsnNode; -import pw.prok.imagine.asm.ImagineASM; -import pw.prok.imagine.asm.Transformer; +import cpw.mods.fml.common.FMLLog; +import net.minecraft.launchwrapper.IClassTransformer; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.tree.*; import static org.objectweb.asm.Opcodes.INVOKESTATIC; -@Transformer.RegisterTransformer -public class RecurrentComplexTransformer implements Transformer { +public class RecurrentComplexTransformer implements IClassTransformer { + private static final String TARGET_CLASS = + "ivorius.reccomplex.structures.generic.matchers.BiomeMatcher"; + @Override - public void transform(ImagineASM asm) { - if (asm.is("ivorius.reccomplex.structures.generic.matchers.BiomeMatcher")) { - System.out.println("[Crucible] Found ivorius.reccomplex.structures.generic.matchers.BiomeMatcher, trying to patch it!"); - InsnList instructions = asm.method("ofTypes", "([Lnet/minecraftforge/common/BiomeDictionary$Type;)Ljava/lang/String;").instructions(); - - AbstractInsnNode abstractInsnNode = instructions.getFirst(); - boolean appliedPatch = false; - while (abstractInsnNode != null) { - if (abstractInsnNode.getOpcode() == INVOKESTATIC) { - MethodInsnNode methodInsnNode = (MethodInsnNode) abstractInsnNode; - if ("joptsimple/internal/Strings".equals(methodInsnNode.owner) && - "join".equals(methodInsnNode.name) && - "(Ljava/util/List;Ljava/lang/String;)Ljava/lang/String;" - .equals(methodInsnNode.desc)) { - methodInsnNode.owner = "io/github/crucible/patches/AsmHooks"; - appliedPatch = true; - System.out.println("[Crucible] Patched joptsimple.internal.Strings#join() call!"); + public byte[] transform(String name, String transformedName, byte[] basicClass) { + if (!transformedName.equals(TARGET_CLASS)) { + return basicClass; + } + + FMLLog.info("[Crucible] Found %s, attempting ASM patch", TARGET_CLASS); + + ClassNode classNode = new ClassNode(); + new ClassReader(basicClass).accept(classNode, 0); + + boolean patched = false; + + for (MethodNode method : classNode.methods) { + if (!method.name.equals("ofTypes")) continue; + if (!method.desc.equals("([Lnet/minecraftforge/common/BiomeDictionary$Type;)Ljava/lang/String;")) + continue; + + InsnList insns = method.instructions; + + for (AbstractInsnNode insn = insns.getFirst(); insn != null; insn = insn.getNext()) { + if (insn.getOpcode() == INVOKESTATIC && insn instanceof MethodInsnNode) { + MethodInsnNode m = (MethodInsnNode) insn; + + if (m.owner.equals("joptsimple/internal/Strings") + && m.name.equals("join") + && m.desc.equals("(Ljava/util/List;Ljava/lang/String;)Ljava/lang/String;")) { + + m.owner = "io/github/crucible/patches/AsmHooks"; + patched = true; + + FMLLog.info("[Crucible] Patched Strings.join() call in BiomeMatcher"); + break; } } - abstractInsnNode = abstractInsnNode.getNext(); - } - if (!appliedPatch) { - System.out.println("[Crucible] RecurrentComplexTransformer: " + - "unable to find joptsimple.internal.Strings#join(), skipping it!"); } } + + if (!patched) { + FMLLog.warning("[Crucible] Failed to patch BiomeMatcher: join() call not found"); + return basicClass; + } + + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + classNode.accept(writer); + return writer.toByteArray(); } } diff --git a/src/main/java/io/github/crucible/patches/StreamsTransformer.java b/src/main/java/io/github/crucible/patches/StreamsTransformer.java index fb947bee..2c6f82b7 100644 --- a/src/main/java/io/github/crucible/patches/StreamsTransformer.java +++ b/src/main/java/io/github/crucible/patches/StreamsTransformer.java @@ -1,42 +1,59 @@ package io.github.crucible.patches; +import net.minecraft.launchwrapper.IClassTransformer; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.FieldInsnNode; -import org.objectweb.asm.tree.InsnList; -import org.objectweb.asm.tree.InsnNode; -import pw.prok.imagine.asm.ImagineASM; -import pw.prok.imagine.asm.Transformer; +import org.objectweb.asm.tree.*; import java.util.Iterator; -@Transformer.RegisterTransformer -public class StreamsTransformer implements Transformer { +public class StreamsTransformer implements IClassTransformer { + private static final String TARGET_CLASS = + "streams.world.gen.structure.RiverComponent$"; + @Override - public void transform(ImagineASM asm) { - if (asm.is("streams.world.gen.structure.RiverComponent$")) { - System.out.println("[Crucible] Found streams.world.gen.structure.RiverComponent$, trying to patch it!"); - InsnList instructions = asm.method("", "()V").instructions(); //We just need to replace a number - AbstractInsnNode toReplace = null; - Iterator i = instructions.iterator(); - while (i.hasNext()) { - AbstractInsnNode ins = i.next(); - if (ins.getOpcode() == Opcodes.ICONST_2) { - if (ins.getNext() instanceof FieldInsnNode) { - FieldInsnNode fieldAccess = (FieldInsnNode) ins.getNext(); - if (fieldAccess.name.contains("MinSourceBackWallHeight")) { - toReplace = fieldAccess.getPrevious(); - break; - } - } - } + public byte[] transform(String name, String transformedName, byte[] basicClass) { + if (!transformedName.equals(TARGET_CLASS)) { + return basicClass; + } + + System.out.println("[Crucible] Found " + TARGET_CLASS + ", patching…"); + + ClassNode classNode = new ClassNode(); + ClassReader reader = new ClassReader(basicClass); + reader.accept(classNode, 0); + + for (MethodNode method : classNode.methods) { + if ("".equals(method.name) && "()V".equals(method.desc)) { + patchConstructor(method); } - if (toReplace == null) { - System.out.println("[Crucible] Unable to find MinSourceBackWallHeight, skipping patch!"); - } else { - instructions.set(toReplace, new InsnNode(Opcodes.ICONST_0)); - System.out.println("[Crucible] Patched MinSourceBackWallHeight's previous opcode!"); + } + + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + classNode.accept(writer); + return writer.toByteArray(); + } + + private void patchConstructor(MethodNode method) { + InsnList insns = method.instructions; + + for (Iterator it = insns.iterator(); it.hasNext(); ) { + AbstractInsnNode insn = it.next(); + + if (insn.getOpcode() == Opcodes.ICONST_2 && + insn.getNext() instanceof FieldInsnNode) { + + FieldInsnNode field = (FieldInsnNode) insn.getNext(); + + if (field.name.contains("MinSourceBackWallHeight")) { + insns.set(insn, new InsnNode(Opcodes.ICONST_0)); + System.out.println("[Crucible] Patched MinSourceBackWallHeight"); + return; + } } } + + System.out.println("[Crucible] Failed to find MinSourceBackWallHeight"); } } diff --git a/src/main/java/io/github/crucible/util/BukkitEnumHelper.java b/src/main/java/io/github/crucible/util/BukkitEnumHelper.java new file mode 100644 index 00000000..b22be111 --- /dev/null +++ b/src/main/java/io/github/crucible/util/BukkitEnumHelper.java @@ -0,0 +1,76 @@ +package io.github.crucible.util; + +import cpw.mods.fml.relauncher.ReflectionHelper; +import net.minecraft.inventory.IInventory; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.EnumHelper; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bukkit.World; +import org.bukkit.WorldType; +import org.bukkit.block.Biome; +import org.bukkit.entity.EntityType; +import org.bukkit.event.inventory.InventoryType; + +import java.util.Map; + +public class BukkitEnumHelper { + private static final Logger logger = LogManager.getLogger(); + // Cauldron start + public static Biome addBukkitBiome(String name) + { + return (Biome) EnumHelper.addEnum(Biome.class, name, new Class[0], new Object[0]); + } + + public static World.Environment addBukkitEnvironment(int id, String name) + { + return (World.Environment) EnumHelper.addEnum(World.Environment.class, name, new Class[] { Integer.TYPE }, new Object[] { Integer.valueOf(id) }); + } + + public static WorldType addBukkitWorldType(String name) + { + WorldType worldType = EnumHelper.addEnum(WorldType.class, name, new Class [] { String.class }, new Object[] { name }); + Map BY_NAME = ReflectionHelper.getPrivateValue(WorldType.class, null, "BY_NAME"); + BY_NAME.put(name.toUpperCase(), worldType); + + return worldType; + } + + public static EntityType addBukkitEntityType(String name, Class clazz, int typeId, boolean independent) { + String entityType = name.replace("-", "_").toUpperCase(); + EntityType bukkitType = EnumHelper.addEnum(EntityType.class, entityType, new Class[] { String.class, Class.class, Integer.TYPE, Boolean.TYPE }, new Object[] { name, clazz, typeId, independent }); + + Map NAME_MAP = ReflectionHelper.getPrivateValue(EntityType.class, null, "NAME_MAP"); + Map ID_MAP = ReflectionHelper.getPrivateValue(EntityType.class, null, "ID_MAP"); + + NAME_MAP.put(name.toLowerCase(), bukkitType); + ID_MAP.put((short)typeId, bukkitType); + + + return bukkitType; + } + + public static InventoryType addInventoryType(TileEntity tileentity) + { + if (!IInventory.class.isAssignableFrom(tileentity.getClass())) return null; + String id = (String)TileEntity.classToNameMap.get(tileentity.getClass()); + + try + { + IInventory teInv = (IInventory)tileentity; + int size = teInv.getSizeInventory(); + return EnumHelper.addEnum(InventoryType.class, id, new Class[]{Integer.TYPE, String.class}, new Object[]{size, id}); + } + catch (Throwable e) + { + if (MinecraftServer.getServer().tileEntityConfig.enableTEInventoryWarning.getValue()) + { + logger.log(Level.WARN, "Could not create inventory type " + tileentity.getClass().getName() + " Exception: " + e.toString()); + logger.log(Level.WARN, "Could not determine default inventory size for type " + tileentity.getClass().getName() + " using size of 9"); + } + return EnumHelper.addEnum(InventoryType.class, id, new Class[]{Integer.TYPE, String.class}, new Object[]{9, id}); + } + } +} diff --git a/src/main/java/me/eigenraven/lwjgl3ify/IExtensibleEnum.java b/src/main/java/me/eigenraven/lwjgl3ify/IExtensibleEnum.java deleted file mode 100644 index e1a55261..00000000 --- a/src/main/java/me/eigenraven/lwjgl3ify/IExtensibleEnum.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors SPDX-License-Identifier: LGPL-2.1-only - */ -package me.eigenraven.lwjgl3ify; - -/** - * To be implemented on vanilla enums that should be enhanced with ASM to be extensible. If this is implemented on a - * class, the class must define a static method called "create" which takes a String (enum name), and the rest of the - * parameters matching a constructor. - *

- * For example, an enum with the constructor {@code MyEnum(Object foo)} would require the method: - * - *

- *
- * public static MyEnum create(String name, Object foo) {
- *     throw new IllegalStateException("Enum not extended");
- * }
- * 
- * - * The method contents will be replaced with ASM at runtime. Multiple {@code create} methods can be - * defined as long as each matches a constructor. - */ -public interface IExtensibleEnum { - - /** - * Called by generated factory code to do any post-constructor setup required by the enum. Should not be called - * manually. - */ - @Deprecated - default void init() {} -} \ No newline at end of file diff --git a/src/main/java/me/eigenraven/lwjgl3ify/UnsafeHacks.java b/src/main/java/me/eigenraven/lwjgl3ify/UnsafeHacks.java deleted file mode 100644 index ac8a6711..00000000 --- a/src/main/java/me/eigenraven/lwjgl3ify/UnsafeHacks.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Minecraft Forge Copyright (c) 2016-2019. This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the Free Software Foundation version 2.1 of - * the License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. You should have received a copy of the GNU Lesser General Public License along with this - * library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ -package me.eigenraven.lwjgl3ify; - -import java.lang.reflect.Field; -import java.util.Optional; - -@SuppressWarnings({ "restriction", "sunapi" }) -public class UnsafeHacks { - - private static final sun.misc.Unsafe UNSAFE; - - static { - try { - final Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); - theUnsafe.setAccessible(true); - UNSAFE = (sun.misc.Unsafe) theUnsafe.get(null); - } catch (IllegalAccessException | NoSuchFieldException e) { - throw new RuntimeException("BARF!", e); - } - } - - @SuppressWarnings("unchecked") - public static T newInstance(Class clazz) { - try { - return (T) UNSAFE.allocateInstance(clazz); - } catch (InstantiationException e) { - throw new RuntimeException(e); - } - } - - @SuppressWarnings("unchecked") - public static T getField(Field field, Object object) { - if (object == null) { - long offset = UNSAFE.staticFieldOffset(field); - Object base = UNSAFE.staticFieldBase(field); - return (T) UNSAFE.getObject(base, offset); - } else { - long offset = UNSAFE.objectFieldOffset(field); - return (T) UNSAFE.getObject(object, offset); - } - } - - public static void setField(Field data, Object object, Object value) { - if (object == null) { - long offset = UNSAFE.staticFieldOffset(data); - Object base = UNSAFE.staticFieldBase(data); - UNSAFE.putObject(base, offset, value); - } else { - long offset = UNSAFE.objectFieldOffset(data); - UNSAFE.putObject(object, offset, value); - } - } - - public static int getIntField(Field field, Object object) { - if (object == null) { - long offset = UNSAFE.staticFieldOffset(field); - Object base = UNSAFE.staticFieldBase(field); - return UNSAFE.getInt(base, offset); - } else { - long offset = UNSAFE.objectFieldOffset(field); - return UNSAFE.getInt(object, offset); - } - } - - public static void setIntField(Field data, Object object, int value) { - if (object == null) { - long offset = UNSAFE.staticFieldOffset(data); - Object base = UNSAFE.staticFieldBase(data); - UNSAFE.putInt(base, offset, value); - } else { - long offset = UNSAFE.objectFieldOffset(data); - UNSAFE.putInt(object, offset, value); - } - } - - // Make sure we don't crash if any future versions change field names - private static Optional findField(Class clazz, String name) { - for (Field f : clazz.getDeclaredFields()) { - if (f.getName() - .equals(name)) { - return Optional.of(f); - } - } - return Optional.empty(); - } - - public static void cleanEnumCache(Class> enumClass) throws Exception { - findField(Class.class, "enumConstantDirectory").ifPresent(f -> setField(f, enumClass, null)); - findField(Class.class, "enumConstants").ifPresent(f -> setField(f, enumClass, null)); - } -} \ No newline at end of file diff --git a/src/main/java/me/eigenraven/lwjgl3ify/WasFinalObjectHolder.java b/src/main/java/me/eigenraven/lwjgl3ify/WasFinalObjectHolder.java deleted file mode 100644 index f91c600c..00000000 --- a/src/main/java/me/eigenraven/lwjgl3ify/WasFinalObjectHolder.java +++ /dev/null @@ -1,10 +0,0 @@ -package me.eigenraven.lwjgl3ify; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface WasFinalObjectHolder {} \ No newline at end of file diff --git a/src/main/java/me/eigenraven/lwjgl3ify/api/ConfigUtils.java b/src/main/java/me/eigenraven/lwjgl3ify/api/ConfigUtils.java deleted file mode 100644 index 228854a7..00000000 --- a/src/main/java/me/eigenraven/lwjgl3ify/api/ConfigUtils.java +++ /dev/null @@ -1,34 +0,0 @@ -package me.eigenraven.lwjgl3ify.api; - -import io.github.crucible.CrucibleConfigs; -import org.apache.logging.log4j.Logger; - -import java.util.HashSet; -import java.util.Set; - -/** - * Proxy everything to Crucible - * TODO: perhaps we need to ensure this class is loaded by us? - */ -public class ConfigUtils { - - public ConfigUtils(Logger logger) { - // NO-OP - } - - public boolean isLwjgl3ifyLoaded() { - return true; - } - - public Set getExtensibleEnums() { - return new HashSet<>(CrucibleConfigs.configs.lwjgl3ify_extensibleEnums); - } - - public void addExtensibleEnum(String className) { - CrucibleConfigs.configs.lwjgl3ify_extensibleEnums.add(className); - } - - public boolean isConfigLoaded() { - return true; - } -} diff --git a/src/main/java/me/eigenraven/lwjgl3ify/api/Lwjgl3Aware.java b/src/main/java/me/eigenraven/lwjgl3ify/api/Lwjgl3Aware.java deleted file mode 100644 index 28760fbf..00000000 --- a/src/main/java/me/eigenraven/lwjgl3ify/api/Lwjgl3Aware.java +++ /dev/null @@ -1,13 +0,0 @@ -package me.eigenraven.lwjgl3ify.api; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Mark a class to not be transformed for lwjgl3 compatibility - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface Lwjgl3Aware {} \ No newline at end of file diff --git a/src/main/java/me/eigenraven/lwjgl3ify/api/MakeEnumExtensible.java b/src/main/java/me/eigenraven/lwjgl3ify/api/MakeEnumExtensible.java deleted file mode 100644 index bc1346b0..00000000 --- a/src/main/java/me/eigenraven/lwjgl3ify/api/MakeEnumExtensible.java +++ /dev/null @@ -1,13 +0,0 @@ -package me.eigenraven.lwjgl3ify.api; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Mark an enum for an automatic IExtensibleEnum implementation. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface MakeEnumExtensible {} \ No newline at end of file diff --git a/src/main/java/me/eigenraven/lwjgl3ify/core/ExtensibleEnumTransformerHelper.java b/src/main/java/me/eigenraven/lwjgl3ify/core/ExtensibleEnumTransformerHelper.java deleted file mode 100644 index f98312e5..00000000 --- a/src/main/java/me/eigenraven/lwjgl3ify/core/ExtensibleEnumTransformerHelper.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors SPDX-License-Identifier: LGPL-2.1-only - */ -package me.eigenraven.lwjgl3ify.core; - -import java.util.List; -import java.util.stream.Collectors; - -import io.github.crucible.CrucibleModContainer; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.commons.InstructionAdapter; -import org.objectweb.asm.tree.AnnotationNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldNode; -import org.objectweb.asm.tree.MethodNode; - -import me.eigenraven.lwjgl3ify.IExtensibleEnum; -import me.eigenraven.lwjgl3ify.api.MakeEnumExtensible; - -public class ExtensibleEnumTransformerHelper { - - private final Logger LOGGER = LogManager.getLogger("lwjgl3ify"); - private final Type STRING = Type.getType(String.class); - private final Type ENUM = Type.getType(Enum.class); - public final Type MARKER_IFACE = Type.getType(IExtensibleEnum.class); - public final Type MARKER_ANNOTATION = Type.getType(MakeEnumExtensible.class); - private final Type ARRAY_UTILS = Type.getType("Lorg/apache/commons/lang3/ArrayUtils;"); // Don't directly reference - // this to prevent class - // loading. - private final String ADD_DESC = Type - .getMethodDescriptor(Type.getType(Object[].class), Type.getType(Object[].class), Type.getType(Object.class)); - private final Type UNSAFE_HACKS = Type.getType("Lme/eigenraven/lwjgl3ify/UnsafeHacks;"); // Again, not direct - // reference to prevent - // class loading. - private final String CLEAN_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Class.class)); - private final String NAME_DESC = Type.getMethodDescriptor(STRING); - private final String EQUALS_DESC = Type.getMethodDescriptor(Type.BOOLEAN_TYPE, STRING); - public static final String CREATE_METHOD_NAME = "dynamicCreate"; - - /** - * @return Were changes made? - */ - public boolean processClassWithFlags(final ClassNode classNode, final Type classType) { - if ((classNode.access & Opcodes.ACC_ENUM) == 0) return false; - - Type array = Type.getType("[" + classType.getDescriptor()); - final int flags = Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC; - - FieldNode values = classNode.fields.stream() - .filter(f -> f.desc.contentEquals(array.getDescriptor()) && ((f.access & flags) == flags)) - .findFirst() - .orElse(null); - - boolean process = false; - if (classNode.interfaces.contains(MARKER_IFACE.getInternalName())) { - process = true; - } else if (classNode.visibleAnnotations != null && !classNode.visibleAnnotations.isEmpty()) { - for (AnnotationNode annotation : classNode.visibleAnnotations) { - if (annotation.desc.equals(MARKER_ANNOTATION.getDescriptor())) { - process = true; - } - } - } - if (!process) { - return false; - } - - List constructors = classNode.methods.stream() - .filter(m -> m.name.equals("")) - .collect(Collectors.toList()); - - // Static methods named "create" with first argument as a string - List candidates = constructors.stream() - .map(ctor -> { - final String[] exceptions = ctor.exceptions == null ? null : ctor.exceptions.toArray(new String[0]); - final Type ctorDesc = Type.getMethodType(ctor.desc); - final Type creatorDesc = Type - .getMethodType(classType, ArrayUtils.remove(ctorDesc.getArgumentTypes(), 1)); - final MethodNode creator = new MethodNode( - ctor.access, - CREATE_METHOD_NAME, - creatorDesc.getDescriptor(), - null, - exceptions); - creator.access = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC; - return creator; - }) - .collect(Collectors.toList()); - - if (candidates.isEmpty()) { - throw new IllegalStateException( - "IExtensibleEnum has no candidate factory methods: " + classType.getClassName()); - } - - classNode.methods.addAll(candidates); - - candidates.forEach(mtd -> { - Type[] args = Type.getArgumentTypes(mtd.desc); - if (args.length == 0 || !args[0].equals(STRING)) { - if (LOGGER.isErrorEnabled()) { - String sb = "Enum has create method without String as first parameter:\n" + " Enum: " - + classType.getDescriptor() - + "\n" - + " Target: " - + mtd.name - + mtd.desc - + "\n"; - LOGGER.error(sb); - } - throw new IllegalStateException( - "Enum has create method without String as first parameter: " + mtd.name + mtd.desc); - } - - Type ret = Type.getReturnType(mtd.desc); - if (!ret.equals(classType)) { - if (LOGGER.isErrorEnabled()) { - String sb = "Enum has create method with incorrect return type:\n" + " Enum: " - + classType.getDescriptor() - + "\n" - + " Target: " - + mtd.name - + mtd.desc - + "\n" - + " Found: " - + ret.getClassName() - + ", Expected: " - + classType.getClassName(); - LOGGER.error(sb); - } - throw new IllegalStateException( - "Enum has create method with incorrect return type: " + mtd.name + mtd.desc); - } - - Type[] ctrArgs = new Type[args.length + 1]; - ctrArgs[0] = STRING; - ctrArgs[1] = Type.INT_TYPE; - for (int x = 1; x < args.length; x++) ctrArgs[1 + x] = args[x]; - - String desc = Type.getMethodDescriptor(Type.VOID_TYPE, ctrArgs); - - MethodNode ctr = classNode.methods.stream() - .filter(m -> m.name.equals("") && m.desc.equals(desc)) - .findFirst() - .orElse(null); - if (ctr == null) { - if (LOGGER.isErrorEnabled()) { - StringBuilder sb = new StringBuilder(); - sb.append("Enum has create method with no matching constructor:\n"); - sb.append(" Enum: ") - .append(classType.getDescriptor()) - .append("\n"); - sb.append(" Candidate: ") - .append(mtd.desc) - .append("\n"); - sb.append(" Target: ") - .append(desc) - .append("\n"); - classNode.methods.stream() - .filter(m -> m.name.equals("")) - .forEach( - m -> sb.append(" : ") - .append(m.desc) - .append("\n")); - LOGGER.error(sb.toString()); - } - throw new IllegalStateException("Enum has create method with no matching constructor: " + desc); - } - - if (values == null) { - if (LOGGER.isErrorEnabled()) { - StringBuilder sb = new StringBuilder(); - sb.append("Enum has create method but we could not find $VALUES. Found:\n"); - classNode.fields.stream() - .filter(f -> (f.access & Opcodes.ACC_STATIC) != 0) - .forEach( - m -> sb.append(" ") - .append(m.name) - .append(" ") - .append(m.desc) - .append("\n")); - LOGGER.error(sb.toString()); - } - throw new IllegalStateException("Enum has create method but we could not find $VALUES"); - } - - values.access &= values.access & ~Opcodes.ACC_FINAL; // Strip the final so JITer doesn't inline things. - - mtd.access |= Opcodes.ACC_SYNCHRONIZED; - mtd.instructions.clear(); - mtd.localVariables.clear(); - if (mtd.tryCatchBlocks != null) { - mtd.tryCatchBlocks.clear(); - } - if (mtd.visibleLocalVariableAnnotations != null) { - mtd.visibleLocalVariableAnnotations.clear(); - } - if (mtd.invisibleLocalVariableAnnotations != null) { - mtd.invisibleLocalVariableAnnotations.clear(); - } - InstructionAdapter ins = new InstructionAdapter(mtd); - - int vars = 0; - for (Type arg : args) vars += arg.getSize(); - - { - vars += 1; // int x - Label for_start = new Label(); - Label for_condition = new Label(); - Label for_inc = new Label(); - - ins.iconst(0); - ins.store(vars, Type.INT_TYPE); - ins.goTo(for_condition); - // if (!VALUES[x].name().equalsIgnoreCase(name)) goto for_inc - ins.mark(for_start); - ins.getstatic(classType.getInternalName(), values.name, values.desc); - ins.load(vars, Type.INT_TYPE); - ins.aload(array); - ins.invokevirtual(ENUM.getInternalName(), "name", NAME_DESC, false); - ins.load(0, STRING); - ins.invokevirtual(STRING.getInternalName(), "equalsIgnoreCase", EQUALS_DESC, false); - ins.ifeq(for_inc); - // return VALUES[x]; - ins.getstatic(classType.getInternalName(), values.name, values.desc); - ins.load(vars, Type.INT_TYPE); - ins.aload(array); - ins.areturn(classType); - // x++ - ins.mark(for_inc); - ins.iinc(vars, 1); - // if (x < VALUES.length) goto for_start - ins.mark(for_condition); - ins.load(vars, Type.INT_TYPE); - ins.getstatic(classType.getInternalName(), values.name, values.desc); - ins.arraylength(); - ins.ificmplt(for_start); - } - - { - vars += 1; // enum ret; - // ret = new ThisType(name, VALUES.length, args..) - ins.anew(classType); - ins.dup(); - ins.load(0, STRING); - ins.getstatic(classType.getInternalName(), values.name, values.desc); - ins.arraylength(); - int idx = 1; - for (int x = 1; x < args.length; x++) { - ins.load(idx, args[x]); - idx += args[x].getSize(); - } - ins.invokespecial(classType.getInternalName(), "", desc, false); - ins.store(vars, classType); - // VALUES = ArrayUtils.add(VALUES, ret) - ins.getstatic(classType.getInternalName(), values.name, values.desc); - ins.load(vars, classType); - ins.invokestatic(ARRAY_UTILS.getInternalName(), "add", ADD_DESC, false); - ins.checkcast(array); - ins.putstatic(classType.getInternalName(), values.name, values.desc); - // EnumHelper.cleanEnumCache(ThisType.class) - ins.visitLdcInsn(classType); - ins.invokestatic(UNSAFE_HACKS.getInternalName(), "cleanEnumCache", CLEAN_DESC, false); - // init ret - ins.load(vars, classType); - ins.invokeinterface(MARKER_IFACE.getInternalName(), "init", "()V"); - // return ret - ins.load(vars, classType); - ins.areturn(classType); - } - }); - return true; - } -} \ No newline at end of file diff --git a/src/main/java/me/eigenraven/lwjgl3ify/core/FixConstantPoolInterfaceMethodRefHelper.java b/src/main/java/me/eigenraven/lwjgl3ify/core/FixConstantPoolInterfaceMethodRefHelper.java deleted file mode 100644 index 29b0f363..00000000 --- a/src/main/java/me/eigenraven/lwjgl3ify/core/FixConstantPoolInterfaceMethodRefHelper.java +++ /dev/null @@ -1,95 +0,0 @@ -package me.eigenraven.lwjgl3ify.core; - -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.objectweb.asm.Handle; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.InvokeDynamicInsnNode; -import org.objectweb.asm.tree.MethodNode; - -/** - * Fixes a compilation bug of the java 8 compiler leading to the following exception at runtime: - * cpw.mods.fml.common.LoaderException: java.lang.IncompatibleClassChangeError: Inconsistent constant pool data in - * classfile for class com/gtnewhorizon/structurelib/alignment/IAlignmentLimits. Method 'boolean - * lambda$static$0(net.minecraftforge.common.util.ForgeDirection, - * com.gtnewhorizon.structurelib.alignment.enumerable.Rotation, - * com.gtnewhorizon.structurelib.alignment.enumerable.Flip)' at index 77 is CONSTANT_MethodRef and should be - * CONSTANT_InterfaceMethodRef - */ -public class FixConstantPoolInterfaceMethodRefHelper { - private final Logger LOGGER = LogManager.getLogger("lwjgl3ify"); - - public boolean transform(ClassNode node) { - if (System.getProperty("java.specification.version", "1.8") - .trim() - .startsWith("1.8")) { - return false; - } - final boolean iAmAnInterface = ((node.access & Opcodes.ACC_INTERFACE) != 0); - boolean changesMade = false; - final String internalClassName = node.name; - if (node.methods != null) { - for (MethodNode method : node.methods) { - if (method.instructions != null) { - for (AbstractInsnNode insn : method.instructions) { - changesMade |= validateInstruction(internalClassName, iAmAnInterface, insn); - } - } - } - } - return changesMade; - } - - private boolean validateInstruction(String internalClassName, boolean iAmAnInterface, AbstractInsnNode rawInsn) { - AtomicBoolean changed = new AtomicBoolean(false); - switch (rawInsn.getType()) { - case AbstractInsnNode.INVOKE_DYNAMIC_INSN: - final InvokeDynamicInsnNode insn = (InvokeDynamicInsnNode) rawInsn; - insn.bsm = fixHandle(internalClassName, iAmAnInterface, insn.bsm, changed); - if (insn.bsmArgs != null) { - for (int i = 0; i < insn.bsmArgs.length; i++) { - final Object arg = insn.bsmArgs[i]; - if (arg instanceof Handle) { - Handle handle = (Handle) arg; - insn.bsmArgs[i] = fixHandle(internalClassName, iAmAnInterface, handle, changed); - } - } - } - break; - default: - // no-op - } - return changed.get(); - } - - private Handle fixHandle(String internalClassName, boolean iAmAnInterface, Handle handle, AtomicBoolean changed) { - if (!handle.isInterface()) { - final boolean fixSelfReference = handle.getOwner() - .equals(internalClassName) && iAmAnInterface; - boolean fixJavaReference = false; - if (!fixSelfReference && handle.getOwner() - .startsWith("java/")) { - final String regularName = handle.getOwner() - .replace('/', '.'); - try { - final Class javaClass = Class.forName(regularName); - if (javaClass.isInterface()) { - fixJavaReference = true; - } - } catch (ClassNotFoundException cnfe) { - // no-op - LOGGER.warn("Reference to non-existing java class {} found.", regularName, cnfe); - } - } - if (fixSelfReference || fixJavaReference) { - changed.set(true); - return new Handle(handle.getTag(), handle.getOwner(), handle.getName(), handle.getDesc(), true); - } - } - return handle; - } -} \ No newline at end of file diff --git a/src/main/java/me/eigenraven/lwjgl3ify/core/LwjglRedirectTransformer.java b/src/main/java/me/eigenraven/lwjgl3ify/core/LwjglRedirectTransformer.java deleted file mode 100644 index e0a6b329..00000000 --- a/src/main/java/me/eigenraven/lwjgl3ify/core/LwjglRedirectTransformer.java +++ /dev/null @@ -1,86 +0,0 @@ -package me.eigenraven.lwjgl3ify.core; - -import io.github.crucible.CrucibleModContainer; -import io.github.crucible.bootstrap.CrucibleMetadata; -import me.eigenraven.lwjgl3ify.api.Lwjgl3Aware; -import net.minecraft.launchwrapper.IClassTransformer; -import org.objectweb.asm.*; -import org.objectweb.asm.commons.ClassRemapper; -import org.objectweb.asm.commons.Remapper; - -public class LwjglRedirectTransformer extends Remapper implements IClassTransformer { - - int remaps = 0, calls = 0; - - public static LwjglRedirectTransformer activeInstance = null; - - public LwjglRedirectTransformer() { - // Only use the last constructed transformer - activeInstance = this; - } - - @Override - public byte[] transform(String name, String transformedName, byte[] basicClass) { - if (this != activeInstance) { - return basicClass; - } - if (basicClass == null) { - return null; - } - if (name.contains("lwjgl3ify")) { - return basicClass; - } - ClassReader reader = new ClassReader(basicClass); - ClassWriter writer = new ClassWriter(0); - ClassVisitor visitor = new EscapingClassRemapper(writer); - - try { - reader.accept(visitor, ClassReader.EXPAND_FRAMES); - } catch (Lwjgl3AwareException e) { - return basicClass; - } catch (Exception e) { - CrucibleModContainer.logger.warn("Couldn't remap class {}", transformedName, e); - return basicClass; - } - - return writer.toByteArray(); - } - - final String[] fromPrefixes = new String[] { "org/lwjgl/", "javax/xml/bind/", "javax/servlet/" }; - - final String[] toPrefixes = new String[] { "org/lwjglx/", "jakarta/xml/bind/", "jakarta/servlet/" }; - - @Override - public String map(String typeName) { - if (typeName == null) { - return null; - } - calls++; - for (int pfx = 0; pfx < fromPrefixes.length; pfx++) { - if (typeName.startsWith(fromPrefixes[pfx])) { - remaps++; - return toPrefixes[pfx] + typeName.substring(fromPrefixes[pfx].length()); - } - } - - return typeName; - } - - public static class Lwjgl3AwareException extends RuntimeException { - } - - public class EscapingClassRemapper extends ClassRemapper { - - public EscapingClassRemapper(ClassWriter writer) { - super(writer, LwjglRedirectTransformer.this); - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - if (desc.equals(Type.getDescriptor(Lwjgl3Aware.class))) { - throw new Lwjgl3AwareException(); - } - return super.visitAnnotation(desc, visible); - } - } -} \ No newline at end of file diff --git a/src/main/java/me/eigenraven/lwjgl3ify/core/UnfinalizeObjectHoldersTransformer.java b/src/main/java/me/eigenraven/lwjgl3ify/core/UnfinalizeObjectHoldersTransformer.java deleted file mode 100644 index f184e8ae..00000000 --- a/src/main/java/me/eigenraven/lwjgl3ify/core/UnfinalizeObjectHoldersTransformer.java +++ /dev/null @@ -1,125 +0,0 @@ -package me.eigenraven.lwjgl3ify.core; - -import java.util.ArrayList; -import java.util.List; - -import io.github.crucible.CrucibleConfigs; -import net.minecraft.launchwrapper.IClassTransformer; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.AnnotationNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldNode; - -import me.eigenraven.lwjgl3ify.WasFinalObjectHolder; - -public class UnfinalizeObjectHoldersTransformer implements IClassTransformer { - private final Logger LOGGER = LogManager.getLogger("lwjgl3ify"); - // Keep ClassNode-operating transformers together for efficiency (don't read/write the class multiple times) - final ExtensibleEnumTransformerHelper enumTransformer = new ExtensibleEnumTransformerHelper(); - final FixConstantPoolInterfaceMethodRefHelper cpiMethodRefTransformer = new FixConstantPoolInterfaceMethodRefHelper(); - - private static boolean isHolder(List annotations) { - if (annotations == null) { - return false; - } - for (AnnotationNode annotationNode : annotations) { - // Java 17 uses $ instead of / - final String desc = annotationNode.desc.replace('$', '/'); - if (desc.contains("cpw/mods/fml/common/registry/GameRegistry/ObjectHolder")) { - return true; - } - if (desc.contains("cpw/mods/fml/common/registry/GameRegistry/ItemStackHolder")) { - return true; - } - } - return false; - } - - @Override - public byte[] transform(String name, String transformedName, byte[] basicClass) { - if (basicClass == null) { - return null; - } - - if (transformedName.startsWith("me.eigenraven.lwjgl3ify")) { - return basicClass; - } - try { - final ClassReader reader = new ClassReader(basicClass); - final ClassNode node = new ClassNode(); - reader.accept(node, ClassReader.EXPAND_FRAMES); - final Type classType = Type.getType("L" + name.replace('.', '/') + ";"); - - boolean transformClass = false; - boolean workDone = false; - if (transformedName.equals("net.minecraft.init.Blocks") - || transformedName.equals("net.minecraft.init.Items")) { - transformClass = true; - } - transformClass |= isHolder(node.visibleAnnotations); - if (transformedName.equals("team.chisel.init.ChiselBlocks")) { - LOGGER.debug("chiselblocks"); - } - int fieldsModified = 0; - for (FieldNode field : node.fields) { - boolean transform = transformClass; - if (!transform) { - transform = isHolder(field.visibleAnnotations); - } - if (transform) { - workDone = true; - if ((field.access & Opcodes.ACC_FINAL) != 0) { - if (field.visibleAnnotations == null) { - field.visibleAnnotations = new ArrayList<>(1); - field.visibleAnnotations - .add(new AnnotationNode(Type.getDescriptor(WasFinalObjectHolder.class))); - } - field.access = field.access & (~Opcodes.ACC_FINAL); - } - fieldsModified++; - } - } - if (workDone) { - LOGGER.info("Unfinalized {} Holder fields in {}", fieldsModified, transformedName); - } - - if (CrucibleConfigs.configs.lwjgl3ify_extensibleEnums - .contains(transformedName)) { - if (node.interfaces == null) { - node.interfaces = new ArrayList<>(1); - } - node.interfaces.add(enumTransformer.MARKER_IFACE.getInternalName()); - } - - final boolean enumsTransformed = enumTransformer.processClassWithFlags(node, classType); - - if (enumsTransformed) { - workDone = true; - LOGGER.info("Dynamicized enum {}={}", name, transformedName); - } - - final boolean ifaceMethodRefsTransformed = cpiMethodRefTransformer.transform(node); - - if (ifaceMethodRefsTransformed) { - workDone = true; - LOGGER - .warn("Fixed missing CONSTANT_InterfaceMethodRef miscompilation in {}={}", name, transformedName); - } - - if (workDone) { - final ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); - node.accept(writer); - return writer.toByteArray(); - } - } catch (Exception e) { - LOGGER.error("Error when unfinalizing ObjectHolder transformer", e); - } - return basicClass; - } -} \ No newline at end of file diff --git a/src/main/java/org/bukkit/craftbukkit/v1_7_R4/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/v1_7_R4/block/CraftBlock.java index 8021f905..542adced 100644 --- a/src/main/java/org/bukkit/craftbukkit/v1_7_R4/block/CraftBlock.java +++ b/src/main/java/org/bukkit/craftbukkit/v1_7_R4/block/CraftBlock.java @@ -14,6 +14,7 @@ import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.biome.BiomeGenBase; import net.minecraftforge.cauldron.block.CraftCustomContainer; +import io.github.crucible.util.BukkitEnumHelper; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; @@ -191,7 +192,7 @@ public static BiomeGenBase biomeToBiomeBase(Biome bio) { int id = BiomeGenBase.getBiome(i).biomeID; System.out.println("Adding biome mapping " + BiomeGenBase.getBiome(i).biomeID + " " + name + " at BiomeBase[" + i + "]"); - net.minecraftforge.common.util.EnumHelper.addBukkitBiome(name); // Forge + BukkitEnumHelper.addBukkitBiome(name); // Forge BIOME_MAPPING[BiomeGenBase.getBiome(i).biomeID] = Enum.valueOf(Biome.class, name); // Cauldron end } diff --git a/src/main/java/org/bukkit/craftbukkit/v1_7_R4/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/v1_7_R4/entity/CraftEntity.java index 2ea2aea7..242e8d58 100644 --- a/src/main/java/org/bukkit/craftbukkit/v1_7_R4/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/v1_7_R4/entity/CraftEntity.java @@ -3,7 +3,7 @@ import net.minecraft.entity.Entity; import io.github.crucible.entity.CraftCustomEntity; import net.minecraftforge.common.DimensionManager; -import net.minecraftforge.common.util.EnumHelper; +import io.github.crucible.util.BukkitEnumHelper; import net.minecraftforge.common.util.FakePlayerFactory; import org.bukkit.EntityEffect; import org.bukkit.Location; @@ -501,7 +501,7 @@ public static void initMappings() { int entityId = getEntityTypeIDfromClass(entityClass); Class bukkitEntityClass = CraftEntity.getEntityClass(entityClass); - EnumHelper.addBukkitEntityType(entityName, bukkitEntityClass, entityId, false); + BukkitEnumHelper.addBukkitEntityType(entityName, bukkitEntityClass, entityId, false); } } // Cauldron end diff --git a/src/main/java/org/bukkit/craftbukkit/v1_7_R4/util/TerminalConsoleWriterThread.java b/src/main/java/org/bukkit/craftbukkit/v1_7_R4/util/TerminalConsoleWriterThread.java index bacb52ae..e1e3422a 100644 --- a/src/main/java/org/bukkit/craftbukkit/v1_7_R4/util/TerminalConsoleWriterThread.java +++ b/src/main/java/org/bukkit/craftbukkit/v1_7_R4/util/TerminalConsoleWriterThread.java @@ -26,7 +26,7 @@ public TerminalConsoleWriterThread(OutputStream output, ConsoleReader reader) { @SuppressWarnings("unchecked") Map> instance = (Map>) queues.get(null); instance.get("TerminalConsole").clear(); - } catch (ReflectiveOperationException e) { + } catch (ReflectiveOperationException | NullPointerException e) { e.printStackTrace(); } // Crucible end diff --git a/src/main/java/thermos/Thermos.java b/src/main/java/thermos/Thermos.java new file mode 100644 index 00000000..ccd5dfcc --- /dev/null +++ b/src/main/java/thermos/Thermos.java @@ -0,0 +1,8 @@ +package thermos; + +// EndlessID check this class for thermos compatibility +// https://github.com/GTMEGA/EndlessIDs/blob/a780cde306e2d049d52eca07c444d95ce87f8399/src/main/java/com/falsepattern/endlessids/mixin/plugin/Mixin.java#L629 +public class Thermos { + private Thermos() { + } +} diff --git a/src/main/java/thermos/ThermosClassTransformer.java b/src/main/java/thermos/ThermosClassTransformer.java index 73f9ed24..385fd00f 100644 --- a/src/main/java/thermos/ThermosClassTransformer.java +++ b/src/main/java/thermos/ThermosClassTransformer.java @@ -1,40 +1,82 @@ package thermos; import cpw.mods.fml.common.FMLLog; +import net.minecraft.launchwrapper.IClassTransformer; import org.apache.logging.log4j.Level; -import org.objectweb.asm.tree.FieldInsnNode; -import org.objectweb.asm.tree.InsnList; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.IntInsnNode; -import pw.prok.imagine.asm.ImagineASM; -import pw.prok.imagine.asm.Transformer; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.tree.*; import static org.objectweb.asm.Opcodes.*; -@Transformer.RegisterTransformer -public class ThermosClassTransformer implements Transformer { +public class ThermosClassTransformer implements IClassTransformer { + private static final String TARGET_CLASS = + "climateControl/utils/ChunkGeneratorExtractor"; + @Override - public void transform(final ImagineASM asm) { - if (asm.is("climateControl.utils.ChunkGeneratorExtractor")) { - boolean undergroundBiomesInstalled = false; - try { - Class.forName("exterminatorJeff.undergroundBiomes.worldGen.ChunkProviderWrapper"); - undergroundBiomesInstalled = true; - } catch (Exception ignored) { - } - if (!undergroundBiomesInstalled) { - FMLLog.log(Level.INFO, "Thermos: Patching " + asm.getActualName() + " for compatibility with Climate Control"); - extractFrom(asm, asm.method("extractFrom", - "(Lnet/minecraft/world/WorldServer;)Lnet/minecraft/world/chunk/IChunkProvider;").instructions()); + public byte[] transform(String name, String transformedName, byte[] basicClass) { + if (!TARGET_CLASS.equals(transformedName.replace('.', '/'))) { + return basicClass; + } + + if (isUndergroundBiomesPresent()) { + return basicClass; + } + + FMLLog.log(Level.INFO, + "Thermos: Patching ChunkGeneratorExtractor for Climate Control compatibility"); + + ClassNode cn = new ClassNode(); + ClassReader cr = new ClassReader(basicClass); + cr.accept(cn, 0); + + for (MethodNode mn : cn.methods) { + if (mn.name.equals("extractFrom") + && mn.desc.equals("(Lnet/minecraft/world/WorldServer;)Lnet/minecraft/world/chunk/IChunkProvider;")) { + + patchMethod(mn); + break; } } + + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + cn.accept(cw); + return cw.toByteArray(); + } + + private void patchMethod(MethodNode mn) { + mn.instructions.clear(); + + boolean obf = isObfuscated(); + + String worldClass = obf ? "ahb" : "net/minecraft/world/World"; + String fieldName = obf ? "v" : "chunkProvider"; + String fieldDesc = obf ? "Lapu;" : + "Lnet/minecraft/world/chunk/IChunkProvider;"; + + InsnList insns = new InsnList(); + insns.add(new VarInsnNode(ALOAD, 1)); + insns.add(new FieldInsnNode(GETFIELD, worldClass, fieldName, fieldDesc)); + insns.add(new InsnNode(ARETURN)); + + mn.instructions.add(insns); + } + + private boolean isUndergroundBiomesPresent() { + try { + Class.forName("exterminatorJeff.undergroundBiomes.worldGen.ChunkProviderWrapper"); + return true; + } catch (Throwable ignored) { + return false; + } } - public void extractFrom(ImagineASM asm, InsnList list) { - //Pair fieldChunkProvider = asm.field("net/minecraft/world/World", "chunkProvider"); - list.clear(); - list.add(new IntInsnNode(ALOAD, 1)); - list.add(new FieldInsnNode(GETFIELD, "ahb", "v", "Lapu;")); - list.add(new InsnNode(ARETURN)); + private boolean isObfuscated() { + try { + Class.forName("net.minecraft.world.World"); + return false; + } catch (Throwable t) { + return true; + } } } diff --git a/src/main/resources/META-INF/rfb-plugin/crucible.properties b/src/main/resources/META-INF/rfb-plugin/crucible.properties new file mode 100644 index 00000000..42c4a3ec --- /dev/null +++ b/src/main/resources/META-INF/rfb-plugin/crucible.properties @@ -0,0 +1,9 @@ +name=Crucible +version=0.0.1 +additionalVersions= +className=io.github.crucible.bootstrap.rfb.CrucibleRfbPlugin +transformerExclusions=io.github.crucible.bootstrap.rfb +versionConstraints= +loadBefore= +loadAfter= +loadRequires= diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index ea87a0fa..6e7049b8 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -43,14 +43,14 @@ - + - +