Zeroth pass on 1.13
This commit is contained in:
parent
6e99f84e91
commit
77c3310711
176 changed files with 603 additions and 16145 deletions
525
build.gradle
525
build.gradle
|
@ -1,477 +1,116 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven { url = 'http://files.minecraftforge.net/maven' }
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven {
|
||||
name = "forge"
|
||||
url = "http://files.minecraftforge.net/maven"
|
||||
}
|
||||
maven {
|
||||
name = "sonatype"
|
||||
url = "https://oss.sonatype.org/content/repositories/snapshots/"
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
|
||||
classpath 'net.minecraftforge.gradle:ForgeGradle:3.+'
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'net.minecrell.licenser' version '0.4'
|
||||
}
|
||||
|
||||
apply plugin: "maven"
|
||||
def patcher_plugin = plugins.apply('net.minecraftforge.gradle.patcher')
|
||||
apply plugin: "net.minecraftforge.gradle.launch4j"
|
||||
|
||||
minecraft.version = "1.12.2"
|
||||
|
||||
minecraft {
|
||||
mappings = 'snapshot_nodoc_20171003'
|
||||
workspaceDir = "projects"
|
||||
versionJson = "jsons/${minecraft.version}-dev.json"
|
||||
buildUserdev = true
|
||||
buildInstaller = true
|
||||
installerVersion = "1.5"
|
||||
|
||||
def common = {
|
||||
patchPrefixOriginal "../src-base/minecraft"
|
||||
patchPrefixChanged "../src-work/minecraft"
|
||||
mainClassClient "net.minecraft.launchwrapper.Launch"
|
||||
tweakClassClient "net.minecraftforge.fml.common.launcher.FMLTweaker"
|
||||
mainClassServer "net.minecraft.launchwrapper.Launch"
|
||||
tweakClassServer "net.minecraftforge.fml.common.launcher.FMLServerTweaker"
|
||||
}
|
||||
|
||||
projects {
|
||||
forge {
|
||||
rootDir "."
|
||||
patchDir "patches/minecraft"
|
||||
patchAfter "clean"
|
||||
genPatchesFrom "clean"
|
||||
genMcpPatches = false
|
||||
applyMcpPatches = false
|
||||
s2sKeepImports = true
|
||||
with common
|
||||
}
|
||||
}
|
||||
}
|
||||
apply plugin: 'eclipse'
|
||||
|
||||
group = 'net.minecraftforge'
|
||||
version = getVersionFromJava(file("src/main/java/net/minecraftforge/common/ForgeVersion.java"))
|
||||
version = '1.0.0'
|
||||
|
||||
extractForgeSources { exclude "**/SideOnly.java", "**/Side.java" }
|
||||
extractForgeResources { exclude "**/log4j2.xml" }
|
||||
|
||||
genGradleProjects {
|
||||
addTestCompileDep "junit:junit:4.12" // TODO update unit tests to junit 5 and remove this
|
||||
addTestCompileDep "org.junit.jupiter:junit-jupiter-api:5.0.0"
|
||||
addTestCompileDep "org.opentest4j:opentest4j:1.0.0" // needed for junit 5
|
||||
addTestCompileDep "org.hamcrest:hamcrest-core:1.3"
|
||||
filter { dep -> !dep.contains("scala") }
|
||||
project(':mcp') {
|
||||
apply plugin: 'net.minecraftforge.gradle.forgedev.mcp'
|
||||
mcp {
|
||||
config = 'de.oceanlabs.mcp:mcp_config:1.13@zip'
|
||||
pipeline = 'joined'
|
||||
}
|
||||
}
|
||||
|
||||
processJson {
|
||||
releaseJson = "jsons/${minecraft.version}-rel.json"
|
||||
addReplacements([
|
||||
"@minecraft_version@": project.minecraft.version,
|
||||
"@version@": project.version,
|
||||
"@project@": "forge",
|
||||
"@artifact@": "net.minecraftforge:forge:${project.version}",
|
||||
"@universal_jar@": { outputJar.archiveName },
|
||||
"@timestamp@": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
|
||||
])
|
||||
project(':clean') {
|
||||
evaluationDependsOn(':mcp')
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'net.minecraftforge.gradle.forgedev.patcher'
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
patcher {
|
||||
parent = project(':mcp')
|
||||
patchedSrc = file('src/main/java')
|
||||
mappings channel: 'snapshot', version: '20180813-1.12'
|
||||
mcVersion = '1.13'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
license {
|
||||
header = project.file('LICENSE-header.txt')
|
||||
|
||||
include 'net/minecraftforge/'
|
||||
exclude 'net/minecraftforge/fml/repackage/'
|
||||
exclude 'net/minecraftforge/server/terminalconsole/'
|
||||
exclude 'net/minecraftforge/fml/common/versioning/ComparableVersion.java'
|
||||
exclude 'net/minecraftforge/fml/common/versioning/InvalidVersionSpecificationException.java'
|
||||
exclude 'net/minecraftforge/fml/common/versioning/Restriction.java'
|
||||
exclude 'net/minecraftforge/fml/common/versioning/VersionRange.java'
|
||||
|
||||
tasks {
|
||||
project(':forge') {
|
||||
evaluationDependsOn(':clean')
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'net.minecraftforge.gradle.forgedev.patcher'
|
||||
sourceSets {
|
||||
main {
|
||||
files = project.files('src/main/java')
|
||||
}
|
||||
test {
|
||||
files = project.files('src/test/java')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task changelog(type: JenkinsChangelog) {
|
||||
|
||||
// skip if there is no forge jenkins pass
|
||||
onlyIf {
|
||||
project.hasProperty('forgeJenkinsPass')
|
||||
}
|
||||
|
||||
outputs.upToDateWhen { false } // never up to date
|
||||
serverRoot = "http://ci.jenkins.minecraftforge.net/"
|
||||
jobName = "minecraftforge"
|
||||
targetBuild = System.env['BUILD_NUMBER'] ?: project.ext.properties.buildNumber ?:0;
|
||||
authName = "console_script"
|
||||
authPassword = project.hasProperty('forgeJenkinsPass') ? project.getProperty('forgeJenkinsPass') : "";
|
||||
output = "build/distributions/${project.name}-${project.version}-changelog.txt"
|
||||
}
|
||||
|
||||
task crowdin(type: CrowdinDownload) {
|
||||
output = "build/crowdin.zip"
|
||||
projectId = 'minecraft-forge'
|
||||
extract = false // we wanna keep it as a zip. not extract it to a folder named "crowdin.zip"
|
||||
|
||||
// task auomatically skips if this is null
|
||||
if (project.hasProperty('crowdinKey'))
|
||||
apiKey = project.crowdinKey
|
||||
}
|
||||
|
||||
def extraTxts = [
|
||||
"CREDITS.txt",
|
||||
"LICENSE.txt",
|
||||
"LICENSE-Paulscode SoundSystem CodecIBXM.txt",
|
||||
"LICENSE-Paulscode IBXM Library.txt"
|
||||
]
|
||||
if (project.hasProperty('forgeJenkinsPass'))
|
||||
extraTxts += changelog
|
||||
|
||||
import groovy.json.JsonSlurper;
|
||||
import groovy.json.JsonBuilder;
|
||||
|
||||
task extractAnnotationsVanilla(type: net.minecraftforge.gradle.tasks.TaskExtractAnnotationsText, dependsOn: deobfuscateJar) {
|
||||
jar = deobfuscateJar.outJar
|
||||
output = 'build/vanilla_annotations_raw.json'
|
||||
doLast { //Re-dump it so it's in groovy's sorted order. Because I like being able to do diffs against things.
|
||||
def json = new JsonSlurper().parseText(file(output).text)
|
||||
file(output).write(new JsonBuilder(json).toPrettyString())
|
||||
}
|
||||
}
|
||||
|
||||
task reobfToSRG(type: net.minecraftforge.gradle.patcher.TaskReobfuscate, dependsOn: reobfuscate) {
|
||||
srg = patcher_plugin.delayedFile('{CACHE_DIR}/de/oceanlabs/mcp/mcp_{MAPPING_CHANNEL}/{MAPPING_VERSION}/{MC_VERSION}/srgs/mcp-srg.srg')
|
||||
exc = reobfuscate.exc
|
||||
preFFJar = reobfuscate.preFFJar
|
||||
methodsCsv = reobfuscate.methodsCsv
|
||||
fieldsCsv = reobfuscate.fieldsCsv
|
||||
addLibs reobfuscate.libs
|
||||
inJar = patcher_plugin.delayedFile('{BUILD_DIR}/localCache/Forge/recompiled.jar')
|
||||
outJar = 'build/forge_srg.jar'
|
||||
}
|
||||
|
||||
task extractAnnotationsForgeSRG(type: net.minecraftforge.gradle.tasks.TaskExtractAnnotationsText, dependsOn: reobfToSRG) {
|
||||
jar = reobfToSRG.outJar
|
||||
output = 'build/forge_annotations.json'
|
||||
doLast { //Re-dump it so it's in groovy's sorted order. Because I like being able to do diffs against things.
|
||||
def json = new JsonSlurper().parseText(file(output).text)
|
||||
json.entrySet().removeIf{e -> (!e.key.startsWith('net/minecraft/') && !e.key.startsWith('net/minecraftforge/')) || e.key.endsWith('/package-info')}
|
||||
file(output).write(new JsonBuilder(json).toPrettyString())
|
||||
}
|
||||
}
|
||||
|
||||
task fixAnnotationsJson(dependsOn: [extractAnnotationsVanilla, extractAnnotationsForgeSRG, genPatches]) {
|
||||
inputs.file(extractAnnotationsVanilla.output)
|
||||
inputs.file(extractAnnotationsForgeSRG.output)
|
||||
outputs.file('build/vanilla_annotations.json')
|
||||
doLast {
|
||||
def json_vanilla = new JsonSlurper().parseText(file(extractAnnotationsVanilla.output).text) as TreeMap
|
||||
def json_forge = new JsonSlurper().parseText(file(extractAnnotationsForgeSRG.output).text) as TreeMap
|
||||
def start = minecraft.projects.forge.patchDir.absolutePath.length()
|
||||
file(minecraft.projects.forge.patchDir).traverse(type: groovy.io.FileType.FILES, nameFilter: {nf -> nf.endsWith('.java.patch')}) { f ->
|
||||
def cls = f.absolutePath.substring(start+1).replace('\\', '/').replace('.java.patch', '')
|
||||
json_vanilla.entrySet().removeIf{e -> e.key == cls || e.key.startsWith(cls + '$')}
|
||||
json_forge.entrySet().stream().filter{e -> e.key == cls || e.key.startsWith(cls + '$')}.forEach{e -> json_vanilla.put(e.key, e.value)}
|
||||
}
|
||||
json_forge.entrySet().stream().filter{e -> e.key.startsWith('net/minecraftforge/')}.forEach{e -> json_vanilla.put(e.key, e.value)}
|
||||
outputs.files.singleFile.write(new JsonBuilder(json_vanilla).toPrettyString())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
outputJar {
|
||||
classifier = 'universal'
|
||||
from extraTxts
|
||||
from(fixAnnotationsJson){
|
||||
into 'META-INF'
|
||||
}
|
||||
dependsOn fixAnnotationsJson
|
||||
|
||||
// add crowdin locales
|
||||
from { crowdin.getDidWork() ? zipTree(crowdin.output) : null}
|
||||
dependsOn 'crowdin'
|
||||
|
||||
manifest.attributes([
|
||||
"Main-Class": "net.minecraftforge.fml.relauncher.ServerLaunchWrapper",
|
||||
"TweakClass": "net.minecraftforge.fml.common.launcher.FMLTweaker",
|
||||
"Class-Path": getServerClasspath(file("jsons/${minecraft.version}-rel.json"))
|
||||
])
|
||||
}
|
||||
|
||||
installer {
|
||||
classifier = 'installer'
|
||||
from extraTxts
|
||||
from "src/main/resources/forge_logo.png"
|
||||
from "src/main/resources/url.png"
|
||||
rename "forge_logo\\.png", "big_logo.png"
|
||||
}
|
||||
|
||||
task signUniversal(type: SignJar, dependsOn: 'outputJar') {
|
||||
onlyIf {
|
||||
project.hasProperty('jarsigner')
|
||||
}
|
||||
|
||||
def jarsigner = [:];
|
||||
|
||||
if (project.hasProperty('jarsigner'))
|
||||
jarsigner = project.jarsigner;
|
||||
|
||||
alias = 'forge'
|
||||
exclude "paulscode/**"
|
||||
storePass = jarsigner.storepass
|
||||
keyPass = jarsigner.keypass
|
||||
keyStore = jarsigner.keystore
|
||||
inputFile = outputJar.archivePath
|
||||
outputFile = outputJar.archivePath
|
||||
}
|
||||
uploadArchives.dependsOn signUniversal
|
||||
build.dependsOn signUniversal
|
||||
installer.dependsOn signUniversal
|
||||
|
||||
// MDK package
|
||||
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
task makeMdk(type: Zip) {
|
||||
baseName = project.name
|
||||
classifier = "mdk"
|
||||
version = project.version
|
||||
destinationDir = file('build/distributions')
|
||||
|
||||
from 'gradlew'
|
||||
from 'gradlew.bat'
|
||||
from extraTxts
|
||||
into ('gradle') {
|
||||
from 'gradle'
|
||||
}
|
||||
into ('eclipse') {
|
||||
from 'mdk/eclipse'
|
||||
}
|
||||
from ('mdk') {
|
||||
filter(ReplaceTokens, tokens: [
|
||||
VERSION: project.version,
|
||||
MAPPINGS: minecraft.mappings.replace('nodoc_', '')
|
||||
])
|
||||
exclude 'eclipse'
|
||||
rename 'gitignore\\.txt', '.gitignore'
|
||||
}
|
||||
}
|
||||
tasks.build.dependsOn makeMdk
|
||||
|
||||
// launch4j
|
||||
|
||||
launch4j {
|
||||
jar = installer.archivePath.canonicalPath
|
||||
outfile = file("build/distributions/${project.name}-${project.version}-installer-win.exe").canonicalPath
|
||||
icon = file('icon.ico').canonicalPath
|
||||
manifest = file('l4jManifest.xml').canonicalPath
|
||||
jreMinVersion = '1.8.0'
|
||||
initialHeapPercent = 5;
|
||||
maxHeapPercent = 100;
|
||||
}
|
||||
tasks.generateXmlConfig.dependsOn installer
|
||||
tasks.build.dependsOn 'launch4j'
|
||||
|
||||
// MAVEN
|
||||
|
||||
artifacts {
|
||||
if (project.hasProperty('forgeJenkinsPass'))
|
||||
archives changelog.output
|
||||
archives file("build/distributions/${project.name}-${project.version}-installer-win.exe")
|
||||
archives makeMdk
|
||||
}
|
||||
|
||||
task ciWriteBuildNumber << {
|
||||
def file = file("src/main/java/net/minecraftforge/common/ForgeVersion.java");
|
||||
def bn = System.getenv("BUILD_NUMBER")?:project.ext.properties.buildNumber?:0;
|
||||
def outfile = "";
|
||||
def ln = "\n"; //Linux line endings because we're on git!
|
||||
|
||||
file.eachLine{ String s ->
|
||||
if (s.matches("^ public static final int buildVersion = [\\d]+;\$"))
|
||||
s = " public static final int buildVersion = ${bn};";
|
||||
if (s.matches('^ public static final String mcVersion = "[^\\"]+";'))
|
||||
s = " public static final String mcVersion = \"${minecraft.version}\";";
|
||||
outfile += (s+ln);
|
||||
}
|
||||
file.write(outfile);
|
||||
}
|
||||
|
||||
uploadArchives {
|
||||
repositories.mavenDeployer {
|
||||
|
||||
dependsOn 'build'
|
||||
|
||||
if (project.hasProperty('forgeMavenPass'))
|
||||
{
|
||||
repository(url: "http://files.minecraftforge.net/maven/manage/upload") {
|
||||
authentication(userName: "forge", password: project.getProperty('forgeMavenPass')) // the elvis operator. look it up.
|
||||
java {
|
||||
srcDir "$rootDir/src/main/java"
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// local repo folder. Might wanna juset use gradle install if you wanans end it to maven-local
|
||||
repository(url: 'file://localhost/' + project.file('repo').getAbsolutePath())
|
||||
}
|
||||
|
||||
pom {
|
||||
groupId = project.group
|
||||
version = project.version
|
||||
artifactId = project.archivesBaseName
|
||||
project {
|
||||
name project.archivesBaseName
|
||||
packaging 'jar'
|
||||
description 'Minecraft Forge API'
|
||||
url 'https://github.com/MinecraftForge/MinecraftForge'
|
||||
|
||||
scm {
|
||||
url 'https://github.com/MinecraftForge/MinecraftForge'
|
||||
connection 'scm:git:git://github.com/MinecraftForge/MinecraftForge.git'
|
||||
developerConnection 'scm:git:git@github.com:MinecraftForge/MinecraftForge.git'
|
||||
}
|
||||
|
||||
issueManagement {
|
||||
system 'github'
|
||||
url 'https://github.com/MinecraftForge/MinecraftForge/issues'
|
||||
}
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name 'Forge Public License'
|
||||
url 'https://raw.github.com/MinecraftForge/MinecraftForge/master/MinecraftForge-License.txt'
|
||||
distribution 'repo'
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id 'cpw'
|
||||
name 'cpw'
|
||||
roles { role 'developer' }
|
||||
}
|
||||
developer {
|
||||
id 'LexManos'
|
||||
name 'Lex Manos'
|
||||
roles { role 'developer' }
|
||||
}
|
||||
developer {
|
||||
id 'AbrarSyed'
|
||||
name 'Abrar Syed'
|
||||
roles { role 'contributor' }
|
||||
}
|
||||
}
|
||||
resources {
|
||||
srcDir "$rootDir/src/main/resources"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
patcher {
|
||||
parent = project(':clean')
|
||||
patches = file("$rootDir/patches/minecraft")
|
||||
patchedSrc = file('src/main/java')
|
||||
accessTransformer = file("$rootDir/src/main/resources/forge_at.cfg")
|
||||
srgPatches = false
|
||||
}
|
||||
applyPatches {
|
||||
canonicalizeAccess true
|
||||
canonicalizeWhitespace true
|
||||
maxFuzz 3
|
||||
}
|
||||
dependencies {
|
||||
implementation project(':clean')
|
||||
implementation 'cpw.mods:modlauncher:0.1+'
|
||||
implementation 'net.minecraftforge:accesstransformers:0.10+:shadowed'
|
||||
implementation 'net.minecraftforge:eventbus:0.1+:service'
|
||||
implementation 'net.minecraftforge:forgespi:0.1+'
|
||||
implementation 'net.minecraftforge:coremods:0.1+'
|
||||
implementation 'com.electronwill.night-config:core:3.4.0'
|
||||
implementation 'com.electronwill.night-config:toml:3.4.0'
|
||||
}
|
||||
|
||||
// HELPER METHODS
|
||||
configurations {
|
||||
ecj
|
||||
}
|
||||
|
||||
dependencies {
|
||||
ecj 'org.eclipse.jdt.core.compiler:ecj:4.6.1'
|
||||
}
|
||||
|
||||
String getServerClasspath(File file)
|
||||
{
|
||||
def node = new JsonSlurper().parse(file);
|
||||
def out = new StringBuilder()
|
||||
node.versionInfo.libraries.each { lib ->
|
||||
if (lib.serverreq)
|
||||
{
|
||||
// group : artifact : version
|
||||
def split = lib.name.split(':')
|
||||
def group = split[0].replace('.', '/')
|
||||
def artifact = split[1]
|
||||
def version = split[2]
|
||||
out += "libraries/$group/$artifact/$version/$artifact-${version}.jar "
|
||||
compileJava {
|
||||
options.fork = true
|
||||
options.failOnError = false
|
||||
options.forkOptions.with {
|
||||
executable = 'java'
|
||||
jvmArgs = ['-classpath', project.configurations.ecj.asPath, 'org.eclipse.jdt.internal.compiler.batch.Main', '-nowarn']
|
||||
}
|
||||
}
|
||||
out += "minecraft_server.${minecraft.version}.jar"
|
||||
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
String getVersionFromJava(File file)
|
||||
{
|
||||
String major = "0";
|
||||
String minor = "0";
|
||||
String revision = "0";
|
||||
String build = "0";
|
||||
|
||||
String prefix = "public static final int";
|
||||
file.eachLine{ String s ->
|
||||
s = s.trim();
|
||||
if (s.startsWith(prefix))
|
||||
{
|
||||
s = s.substring(prefix.length(), s.length() - 1);
|
||||
s = s.replace('=', ' ').replace("Version", "").replaceAll(" +", " ").trim();
|
||||
String[] pts = s.split(" ");
|
||||
|
||||
if (pts[0].equals("major")) major = pts[pts.length - 1];
|
||||
else if (pts[0] == "minor") minor = pts[pts.length - 1];
|
||||
else if (pts[0] == "revision") revision = pts[pts.length - 1];
|
||||
}
|
||||
task runclient(type: JavaExec) {
|
||||
classpath sourceSets.main.runtimeClasspath
|
||||
main 'net.minecraftforge.fml.LaunchTesting'
|
||||
systemProperties target:'fmldevclient'
|
||||
}
|
||||
|
||||
build = System.getenv("BUILD_NUMBER") ?: project.ext.properties.buildNumber ?: 0
|
||||
|
||||
|
||||
String branch = null;
|
||||
if (!System.getenv().containsKey("GIT_BRANCH"))
|
||||
{
|
||||
// TODO: use grgit - Tried to switch 07/07/16 - jgit broken on windows?
|
||||
branch = "git rev-parse --abbrev-ref HEAD".execute().text.trim()
|
||||
task runserver(type: JavaExec) {
|
||||
classpath sourceSets.main.runtimeClasspath
|
||||
main 'net.minecraftforge.fml.LaunchTesting'
|
||||
systemProperties target:'fmldevserver'
|
||||
}
|
||||
else
|
||||
{
|
||||
branch = System.getenv("GIT_BRANCH");
|
||||
branch = branch.substring(branch.lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
def out = "${minecraft.version.replace('-', '_')}-$major.$minor.$revision.$build"
|
||||
|
||||
if (branch && branch != 'master' && branch != 'HEAD' && branch != minecraft.version && branch != minecraft.version + '.0')
|
||||
{
|
||||
if (!(branch.endsWith('.x') && minecraft.version.startsWith(branch.substring(0, branch.length() -2))))
|
||||
out += "-$branch"
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
reobfuscate {
|
||||
extraSrg = [
|
||||
'MD: net/minecraftforge/fml/common/registry/FMLControlledNamespacedRegistry/getKeys ()Ljava/util/Set; net/minecraftforge/fml/common/registry/FMLControlledNamespacedRegistry/getKeys ()Ljava/util/Set;'
|
||||
]
|
||||
//evaluationDependsOnChildren()
|
||||
task setup() {
|
||||
dependsOn ':clean:extractMapped'
|
||||
dependsOn ':forge:extractMapped' //These must be strings so that we can do lazy resolution. Else we need evaluationDependsOnChildren above
|
||||
}
|
||||
|
||||
task resetBuildNumber << {
|
||||
project.ext.properties.buildNumber = 0;
|
||||
ciWriteBuildNumber.execute()
|
||||
}
|
||||
// re-add old tasks for jenkins compat
|
||||
// should be removed, and the jenkins fixed when no longer building with FG 1.2
|
||||
task setupForge { dependsOn 'setup', 'ciWriteBuildNumber' }
|
||||
task buildPackages { dependsOn 'build' }
|
||||
|
||||
//Temporary hack to fix compile errors caused by mappings shading in Bootstrap
|
||||
/*
|
||||
task fixParams << {
|
||||
logger.lifecycle('Fixing param names!')
|
||||
def params = new File(extractMcpMappings.destinationDir, 'params.csv')
|
||||
def text = params.text
|
||||
text = text.replaceAll('p_180276_1_,biome,', 'p_180276_1_,biomeIn,')
|
||||
params.write(text)
|
||||
}
|
||||
fixParams.dependsOn('extractMcpMappings')
|
||||
extractMcpMappings.finalizedBy('fixParams')
|
||||
*/
|
||||
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,5 @@
|
|||
#Sat Mar 10 11:15:39 EST 2018
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
|
||||
|
|
26
gradlew
vendored
26
gradlew
vendored
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
|
@ -33,11 +33,11 @@ DEFAULT_JVM_OPTS=""
|
|||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
|
@ -154,11 +154,19 @@ if $cygwin ; then
|
|||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
# 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"
|
||||
|
||||
# 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")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
|
6
gradlew.bat
vendored
6
gradlew.bat
vendored
|
@ -49,7 +49,6 @@ goto fail
|
|||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
|
@ -60,11 +59,6 @@ set _SKIP=2
|
|||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
|
|
@ -1 +1,9 @@
|
|||
rootProject.name = 'forge'
|
||||
rootProject.name = 'Forge'
|
||||
|
||||
include ':mcp'
|
||||
include ':clean'
|
||||
include ':forge'
|
||||
|
||||
project(":mcp").projectDir = file("projects/mcp")
|
||||
project(":clean").projectDir = file("projects/clean")
|
||||
project(":forge").projectDir = file("projects/forge")
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.advancements.critereon;
|
||||
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.util.JsonUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import net.minecraft.advancements.critereon.ItemPredicate;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
/**
|
||||
* An {@link ItemPredicate} that matches oredicts.
|
||||
*/
|
||||
public class OredictItemPredicate extends ItemPredicate
|
||||
{
|
||||
private final String ore;
|
||||
|
||||
public OredictItemPredicate(String ore)
|
||||
{
|
||||
this.ore = ore;
|
||||
}
|
||||
|
||||
public OredictItemPredicate(JsonObject jsonObject) { this(JsonUtils.getString(jsonObject, "ore")); }
|
||||
|
||||
@Override
|
||||
public boolean test(ItemStack stack)
|
||||
{
|
||||
return !stack.isEmpty() && ArrayUtils.contains(OreDictionary.getOreIDs(stack), OreDictionary.getOreID(ore));
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.classloading;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class FMLForgePlugin
|
||||
{
|
||||
public static boolean RUNTIME_DEOBF = false;
|
||||
}
|
|
@ -46,7 +46,7 @@ import static net.minecraft.util.text.TextFormatting.*;
|
|||
* client, the client takes precedence!
|
||||
*
|
||||
*/
|
||||
public class ClientCommandHandler extends CommandHandler
|
||||
public class ClientCommandHandler {} /*extends CommandHandler
|
||||
{
|
||||
public static final ClientCommandHandler instance = new ClientCommandHandler();
|
||||
|
||||
|
@ -55,7 +55,7 @@ public class ClientCommandHandler extends CommandHandler
|
|||
/**
|
||||
* @return 1 if successfully executed, -1 if no permission or wrong usage,
|
||||
* 0 if it doesn't exist or it was canceled (it's sent to the server)
|
||||
*/
|
||||
* /
|
||||
@Override
|
||||
public int executeCommand(ICommandSender sender, String message)
|
||||
{
|
||||
|
@ -165,3 +165,4 @@ public class ClientCommandHandler extends CommandHandler
|
|||
return Minecraft.getMinecraft().getIntegratedServer();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -26,11 +26,9 @@ import net.minecraft.client.Minecraft;
|
|||
import net.minecraft.client.renderer.InventoryEffectRenderer;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
|
||||
import net.minecraftforge.eventbus.api.Cancelable;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
|
@ -178,6 +176,7 @@ public class GuiScreenEvent extends Event
|
|||
* This event fires at the end of {@link GuiScreen#drawDefaultBackground()} and before the rest of the Gui draws.
|
||||
* This allows drawing next to Guis, above the background but below any tooltips.
|
||||
*/
|
||||
/*
|
||||
public static class BackgroundDrawnEvent extends GuiScreenEvent
|
||||
{
|
||||
private final int mouseX;
|
||||
|
@ -193,22 +192,27 @@ public class GuiScreenEvent extends Event
|
|||
this.mouseY = scaledHeight - Mouse.getY() * scaledHeight / gui.mc.displayHeight - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
/**
|
||||
* The x coordinate of the mouse pointer on the screen.
|
||||
*/
|
||||
*//*
|
||||
|
||||
public int getMouseX()
|
||||
{
|
||||
return mouseX;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
/**
|
||||
* The y coordinate of the mouse pointer on the screen.
|
||||
*/
|
||||
*//*
|
||||
|
||||
public int getMouseY()
|
||||
{
|
||||
return mouseY;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* This event fires in {@link InventoryEffectRenderer#updateActivePotionEffects()}
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.client.event;
|
||||
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
import net.minecraftforge.eventbus.api.Cancelable;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
|
||||
/**
|
||||
* Author: MachineMuse (Claire Semple)
|
||||
* Created: 2:46 PM, 9/4/13
|
||||
*/
|
||||
@net.minecraftforge.eventbus.api.Cancelable
|
||||
public class MouseEvent extends net.minecraftforge.eventbus.api.Event
|
||||
{
|
||||
private final int x;
|
||||
private final int y;
|
||||
private final int dx;
|
||||
private final int dy;
|
||||
private final int dwheel;
|
||||
private final int button;
|
||||
private final boolean buttonstate;
|
||||
private final long nanoseconds;
|
||||
|
||||
public MouseEvent()
|
||||
{
|
||||
this.x = Mouse.getEventX();
|
||||
this.y = Mouse.getEventY();
|
||||
this.dx = Mouse.getEventDX();
|
||||
this.dy = Mouse.getEventDY();
|
||||
this.dwheel = Mouse.getEventDWheel();
|
||||
this.button = Mouse.getEventButton();
|
||||
this.buttonstate = Mouse.getEventButtonState();
|
||||
this.nanoseconds = Mouse.getEventNanoseconds();
|
||||
}
|
||||
|
||||
public int getX() { return x; }
|
||||
public int getY() { return y; }
|
||||
public int getDx() { return dx; }
|
||||
public int getDy() { return dy; }
|
||||
public int getDwheel() { return dwheel; }
|
||||
public int getButton() { return button; }
|
||||
public boolean isButtonstate() { return buttonstate; }
|
||||
public long getNanoseconds() { return nanoseconds; }
|
||||
}
|
|
@ -24,9 +24,8 @@ import java.util.ArrayList;
|
|||
import net.minecraftforge.eventbus.api.Cancelable;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraft.client.gui.BossInfoClient;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
|
||||
@net.minecraftforge.eventbus.api.Cancelable
|
||||
@Cancelable
|
||||
public class RenderGameOverlayEvent extends Event
|
||||
{
|
||||
public float getPartialTicks()
|
||||
|
@ -34,11 +33,6 @@ public class RenderGameOverlayEvent extends Event
|
|||
return partialTicks;
|
||||
}
|
||||
|
||||
public ScaledResolution getResolution()
|
||||
{
|
||||
return resolution;
|
||||
}
|
||||
|
||||
public ElementType getType()
|
||||
{
|
||||
return type;
|
||||
|
@ -71,20 +65,17 @@ public class RenderGameOverlayEvent extends Event
|
|||
}
|
||||
|
||||
private final float partialTicks;
|
||||
private final ScaledResolution resolution;
|
||||
private final ElementType type;
|
||||
|
||||
public RenderGameOverlayEvent(float partialTicks, ScaledResolution resolution)
|
||||
public RenderGameOverlayEvent(float partialTicks, Void resolution)
|
||||
{
|
||||
this.partialTicks = partialTicks;
|
||||
this.resolution = resolution;
|
||||
this.type = null;
|
||||
}
|
||||
|
||||
private RenderGameOverlayEvent(RenderGameOverlayEvent parent, ElementType type)
|
||||
{
|
||||
this.partialTicks = parent.getPartialTicks();
|
||||
this.resolution = parent.getResolution();
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ public class PlaySoundEvent extends SoundEvent
|
|||
{
|
||||
super(manager);
|
||||
this.sound = sound;
|
||||
this.name = sound.getSoundLocation().getResourcePath();
|
||||
this.name = sound.getSoundLocation().getPath();
|
||||
this.setResultSound(sound);
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ public class SoundEvent extends net.minecraftforge.eventbus.api.Event
|
|||
public SoundSourceEvent(SoundManager manager, ISound sound, String uuid)
|
||||
{
|
||||
super(manager);
|
||||
this.name = sound.getSoundLocation().getResourcePath();
|
||||
this.name = sound.getSoundLocation().getPath();
|
||||
this.sound = sound;
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
|
|
@ -223,12 +223,14 @@ public class ForgeGuiFactory implements IModGuiFactory
|
|||
Property global = ForgeMod.getConfig().get(VERSION_CHECK_CAT, "Global", true);
|
||||
|
||||
List<Property> props = new ArrayList<Property>();
|
||||
|
||||
// TODO
|
||||
/*
|
||||
for (ModContainer mod : ForgeVersion.gatherMods().keySet())
|
||||
{
|
||||
values.remove(mod.getModId());
|
||||
props.add(ForgeMod.getConfig().get(VERSION_CHECK_CAT, mod.getModId(), true)); //Get or make the value in the config
|
||||
}
|
||||
*/
|
||||
props.addAll(values.values()); // Add any left overs from the config
|
||||
props.sort(Comparator.comparing(Property::getName));
|
||||
|
||||
|
@ -378,12 +380,15 @@ public class ForgeGuiFactory implements IModGuiFactory
|
|||
private static Map<Object, String> getSelectableValues()
|
||||
{
|
||||
Map<Object, String> selectableValues = new TreeMap<Object, String>();
|
||||
// TODO
|
||||
/*
|
||||
|
||||
for (ModContainer mod : Loader.instance().getActiveModList())
|
||||
// only add mods to the list that have a non-immutable ModContainer
|
||||
if (!mod.isImmutable() && mod.getMod() != null)
|
||||
selectableValues.put(mod.getModId(), mod.getName());
|
||||
|
||||
*/
|
||||
return selectableValues;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.common.ForgeMod;
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.common.ForgeVersion.Status;
|
||||
import net.minecraftforge.fml.VersionChecker;
|
||||
import net.minecraftforge.fml.client.ClientModLoader;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
@ -85,7 +84,7 @@ public class NotificationModUpdateScreen extends GuiScreen
|
|||
public static NotificationModUpdateScreen init(GuiMainMenu guiMainMenu, GuiButton modButton)
|
||||
{
|
||||
NotificationModUpdateScreen notificationModUpdateScreen = new NotificationModUpdateScreen(modButton);
|
||||
notificationModUpdateScreen.setGuiSize(guiMainMenu.width, guiMainMenu.height);
|
||||
notificationModUpdateScreen.setWorldAndResolution(guiMainMenu.mc, guiMainMenu.width, guiMainMenu.height);
|
||||
notificationModUpdateScreen.initGui();
|
||||
return notificationModUpdateScreen;
|
||||
}
|
||||
|
|
|
@ -108,15 +108,17 @@ import com.google.common.collect.Lists;
|
|||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.MODELLOADING;
|
||||
import static net.minecraftforge.fml.Logging.fmlLog;
|
||||
|
||||
public final class ModelLoader extends ModelBakery
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final Map<ModelResourceLocation, IModel> stateModels = Maps.newHashMap();
|
||||
private final Map<ModelResourceLocation, ModelBlockDefinition> multipartDefinitions = Maps.newHashMap();
|
||||
private final Map<ModelBlockDefinition, IModel> multipartModels = Maps.newHashMap();
|
||||
|
@ -939,7 +941,7 @@ public final class ModelLoader extends ModelBakery
|
|||
// ignoring pure ResourceLocation arguments, all things we care about pass ModelResourceLocation
|
||||
if(entry.getKey() instanceof ModelResourceLocation)
|
||||
{
|
||||
fmlLog.debug(MODELLOADING, ()-> new ModelLoaderErrorMessage((ModelResourceLocation)entry.getKey(), entry.getValue(), modelRegistry, this.blockModelShapes, this::getVariantNames));
|
||||
LOGGER.debug(MODELLOADING, ()-> new ModelLoaderErrorMessage((ModelResourceLocation)entry.getKey(), entry.getValue(), modelRegistry, this.blockModelShapes, this::getVariantNames));
|
||||
final ModelResourceLocation location = (ModelResourceLocation)entry.getKey();
|
||||
final IBakedModel model = modelRegistry.getObject(location);
|
||||
if(model == null)
|
||||
|
@ -953,7 +955,7 @@ public final class ModelLoader extends ModelBakery
|
|||
IBakedModel model = modelRegistry.getObject(missing);
|
||||
if(model == null || model == missingModel)
|
||||
{
|
||||
fmlLog.debug(MODELLOADING, ()-> new ModelLoaderErrorMessage(missing, null, modelRegistry, this.blockModelShapes, this::getVariantNames));
|
||||
LOGGER.debug(MODELLOADING, ()-> new ModelLoaderErrorMessage(missing, null, modelRegistry, this.blockModelShapes, this::getVariantNames));
|
||||
}
|
||||
if(model == null)
|
||||
{
|
||||
|
|
|
@ -66,7 +66,7 @@ import javax.annotation.Nullable;
|
|||
|
||||
public class DimensionManager
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger("FML");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Marker DIMMGR = MarkerManager.getMarker("DIMS");
|
||||
private static class Dimension
|
||||
{
|
||||
|
|
|
@ -49,7 +49,7 @@ import net.minecraftforge.common.config.ConfigCategory;
|
|||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
import net.minecraftforge.common.util.Constants;
|
||||
import net.minecraftforge.fml.ServerLifecycleHooks;
|
||||
import net.minecraftforge.fml.server.ServerLifecycleHooks;
|
||||
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import net.minecraftforge.fml.common.Loader;
|
||||
|
|
|
@ -170,7 +170,7 @@ import org.apache.logging.log4j.MarkerManager;
|
|||
|
||||
public class ForgeHooks
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger("FML");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Marker FORGEHOOKS = MarkerManager.getMarker("FORGEHOOKS");
|
||||
//TODO: Loot tables?
|
||||
static class SeedEntry extends WeightedRandom.Item
|
||||
|
|
|
@ -25,22 +25,21 @@ import net.minecraft.world.biome.Biome;
|
|||
import static net.minecraftforge.common.config.Configuration.CATEGORY_CLIENT;
|
||||
import static net.minecraftforge.common.config.Configuration.CATEGORY_GENERAL;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.SidedExecutor;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.fml.VersionChecker;
|
||||
import net.minecraftforge.fml.WorldPersistenceHooks;
|
||||
import net.minecraftforge.fml.javafmlmod.ModLoadingContext;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLModLoadingContext;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.INBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.stats.StatList;
|
||||
import net.minecraft.world.storage.SaveHandler;
|
||||
|
@ -66,9 +65,7 @@ import net.minecraftforge.fml.common.event.FMLLoadCompleteEvent;
|
|||
import net.minecraftforge.fml.common.event.FMLModIdMappingEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLServerStoppingEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
|
||||
import org.apache.logging.log4j.Marker;
|
||||
import org.apache.logging.log4j.MarkerManager;
|
||||
|
@ -76,7 +73,7 @@ import org.apache.logging.log4j.MarkerManager;
|
|||
public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
|
||||
{
|
||||
public static final String VERSION_CHECK_CAT = "version_checking";
|
||||
private static final Logger LOGGER = LogManager.getLogger("FML");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Marker FORGEMOD = MarkerManager.getMarker("FORGEMOD");
|
||||
public static int clumpingThreshold = 64;
|
||||
public static boolean removeErroringEntities = false;
|
||||
|
@ -113,9 +110,9 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
|
|||
public ForgeMod()
|
||||
{
|
||||
INSTANCE = this;
|
||||
ModLoadingContext.get().getModEventBus().addListener(this::preInit);
|
||||
ModLoadingContext.get().getModEventBus().addListener(this::postInit);
|
||||
ModLoadingContext.get().getModEventBus().addListener(this::onAvailable);
|
||||
FMLModLoadingContext.get().getModEventBus().addListener(this::preInit);
|
||||
FMLModLoadingContext.get().getModEventBus().addListener(this::postInit);
|
||||
FMLModLoadingContext.get().getModEventBus().addListener(this::onAvailable);
|
||||
MinecraftForge.EVENT_BUS.addListener(this::serverStarting);
|
||||
MinecraftForge.EVENT_BUS.addListener(this::playerLogin);
|
||||
MinecraftForge.EVENT_BUS.addListener(this::serverStopping);
|
||||
|
@ -336,10 +333,7 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
|
|||
|
||||
if (event.isWorldRunning() && tmpStairs != disableStairSlabCulling)
|
||||
{
|
||||
SidedExecutor.runOn(Dist.CLIENT,()->{
|
||||
Minecraft.getMinecraft().renderGlobal.loadRenderers();
|
||||
return null;
|
||||
});
|
||||
DistExecutor.runWhenOn(Dist.CLIENT,()->()-> Minecraft.getMinecraft().renderGlobal.loadRenderers());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -438,7 +432,7 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
|
|||
}
|
||||
|
||||
@Override
|
||||
public void readData(SaveHandler handler, WorldInfo info, Map<String, NBTBase> propertyMap, NBTTagCompound tag)
|
||||
public void readData(SaveHandler handler, WorldInfo info, Map<String, INBTBase> propertyMap, NBTTagCompound tag)
|
||||
{
|
||||
DimensionManager.loadDimensionDataMap(tag.hasKey("DimensionData") ? tag.getCompoundTag("DimensionData") : null);
|
||||
FluidRegistry.loadFluidDefaults(tag);
|
||||
|
@ -449,10 +443,9 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
|
|||
OreDictionary.rebakeMap();
|
||||
StatList.reinit();
|
||||
Ingredient.invalidateAll();
|
||||
SidedExecutor.runOn(Dist.CLIENT, ()-> {
|
||||
DistExecutor.runWhenOn(Dist.CLIENT, ()-> () -> {
|
||||
Minecraft.getMinecraft().populateSearchTreeManager();
|
||||
Minecraft.getMinecraft().getSearchTreeManager().onResourceManagerReload(Minecraft.getMinecraft().getResourceManager());
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ public class MinecraftForge
|
|||
public static final IEventBus ORE_GEN_BUS = IEventBus.create();
|
||||
|
||||
static final ForgeInternalHandler INTERNAL_HANDLER = new ForgeInternalHandler();
|
||||
private static final Logger LOGGER = LogManager.getLogger("FML");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Marker FORGE = MarkerManager.getMarker("FORGE");
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,7 +22,7 @@ package net.minecraftforge.common.brewing;
|
|||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.potion.PotionHelper;
|
||||
import net.minecraft.potion.PotionBrewing;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
|
@ -49,7 +49,7 @@ public class VanillaBrewingRecipe implements IBrewingRecipe {
|
|||
@Override
|
||||
public boolean isIngredient(@Nonnull ItemStack stack)
|
||||
{
|
||||
return PotionHelper.isReagent(stack);
|
||||
return PotionBrewing.isReagent(stack);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,7 +63,7 @@ public class VanillaBrewingRecipe implements IBrewingRecipe {
|
|||
{
|
||||
if (!input.isEmpty() && !ingredient.isEmpty() && isIngredient(ingredient))
|
||||
{
|
||||
ItemStack result = PotionHelper.doReaction(ingredient, input);
|
||||
ItemStack result = PotionBrewing.doReaction(ingredient, input);
|
||||
if (result != input)
|
||||
{
|
||||
return result;
|
||||
|
|
|
@ -23,7 +23,7 @@ import java.util.concurrent.Callable;
|
|||
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.INBTBase;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -58,7 +58,7 @@ public class Capability<T>
|
|||
* @return a NBT holding the data. Null if no data needs to be stored.
|
||||
*/
|
||||
@Nullable
|
||||
NBTBase writeNBT(Capability<T> capability, T instance, EnumFacing side);
|
||||
INBTBase writeNBT(Capability<T> capability, T instance, EnumFacing side);
|
||||
|
||||
/**
|
||||
* Read the capability instance from a NBT tag.
|
||||
|
@ -79,7 +79,7 @@ public class Capability<T>
|
|||
* @param side The side of the object the instance is associated with.
|
||||
* @param nbt A NBT holding the data. Must not be null, as doesn't make sense to call this function with nothing to read...
|
||||
*/
|
||||
void readNBT(Capability<T> capability, T instance, EnumFacing side, NBTBase nbt);
|
||||
void readNBT(Capability<T> capability, T instance, EnumFacing side, INBTBase nbt);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,7 +97,7 @@ public class Capability<T>
|
|||
* Quick access to the IStorage's readNBT.
|
||||
* See {@link IStorage#readNBT(Capability, Object, EnumFacing, NBTBase)} for documentation.
|
||||
*/
|
||||
public void readNBT(T instance, EnumFacing side, NBTBase nbt)
|
||||
public void readNBT(T instance, EnumFacing side, INBTBase nbt)
|
||||
{
|
||||
storage.readNBT(this, instance, side, nbt);
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ public class Capability<T>
|
|||
* See {@link IStorage#writeNBT(Capability, Object, EnumFacing)} for documentation.
|
||||
*/
|
||||
@Nullable
|
||||
public NBTBase writeNBT(T instance, EnumFacing side)
|
||||
public INBTBase writeNBT(T instance, EnumFacing side)
|
||||
{
|
||||
return storage.writeNBT(this, instance, side);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import java.util.Map;
|
|||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.INBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
@ -45,7 +45,7 @@ import net.minecraftforge.common.util.INBTSerializable;
|
|||
public final class CapabilityDispatcher implements INBTSerializable<NBTTagCompound>, ICapabilityProvider
|
||||
{
|
||||
private ICapabilityProvider[] caps;
|
||||
private INBTSerializable<NBTBase>[] writers;
|
||||
private INBTSerializable<INBTBase>[] writers;
|
||||
private String[] names;
|
||||
|
||||
public CapabilityDispatcher(Map<ResourceLocation, ICapabilityProvider> list)
|
||||
|
@ -57,7 +57,7 @@ public final class CapabilityDispatcher implements INBTSerializable<NBTTagCompou
|
|||
public CapabilityDispatcher(Map<ResourceLocation, ICapabilityProvider> list, @Nullable ICapabilityProvider parent)
|
||||
{
|
||||
List<ICapabilityProvider> lstCaps = Lists.newArrayList();
|
||||
List<INBTSerializable<NBTBase>> lstWriters = Lists.newArrayList();
|
||||
List<INBTSerializable<INBTBase>> lstWriters = Lists.newArrayList();
|
||||
List<String> lstNames = Lists.newArrayList();
|
||||
|
||||
if (parent != null) // Parents go first!
|
||||
|
@ -65,7 +65,7 @@ public final class CapabilityDispatcher implements INBTSerializable<NBTTagCompou
|
|||
lstCaps.add(parent);
|
||||
if (parent instanceof INBTSerializable)
|
||||
{
|
||||
lstWriters.add((INBTSerializable<NBTBase>)parent);
|
||||
lstWriters.add((INBTSerializable<INBTBase>)parent);
|
||||
lstNames.add("Parent");
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ public final class CapabilityDispatcher implements INBTSerializable<NBTTagCompou
|
|||
lstCaps.add(prov);
|
||||
if (prov instanceof INBTSerializable)
|
||||
{
|
||||
lstWriters.add((INBTSerializable<NBTBase>)prov);
|
||||
lstWriters.add((INBTSerializable<INBTBase>)prov);
|
||||
lstNames.add(entry.getKey().toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ import static net.minecraftforge.fml.Logging.CAPABILITIES;
|
|||
public enum CapabilityManager
|
||||
{
|
||||
INSTANCE;
|
||||
private static final Logger LOGGER = LogManager.getLogger("FML");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
/**
|
||||
* Registers a capability to be consumed by others.
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
|
||||
package net.minecraftforge.common.capabilities;
|
||||
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.INBTBase;
|
||||
import net.minecraftforge.common.util.INBTSerializable;
|
||||
|
||||
//Just a mix of the two, useful in patches to lower the size.
|
||||
public interface ICapabilitySerializable<T extends NBTBase> extends ICapabilityProvider, INBTSerializable<T>{}
|
||||
public interface ICapabilitySerializable<T extends INBTBase> extends ICapabilityProvider, INBTSerializable<T>{}
|
||||
|
|
|
@ -37,7 +37,7 @@ import javax.annotation.Nonnull;
|
|||
import net.minecraft.client.util.RecipeBookClient;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import net.minecraftforge.fml.SidedExecutor;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
|
@ -81,7 +81,7 @@ import org.apache.logging.log4j.MarkerManager;
|
|||
public class CraftingHelper {
|
||||
|
||||
private static final boolean DEBUG_LOAD_MINECRAFT = false;
|
||||
private static final Logger LOGGER = LogManager.getLogger("FML");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Marker CRAFTHELPER = MarkerManager.getMarker("CRAFTHELPER");
|
||||
private static Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
|
||||
private static Map<ResourceLocation, IConditionFactory> conditions = new HashMap<>();
|
||||
|
@ -619,10 +619,7 @@ public class CraftingHelper {
|
|||
GameData.fireRegistryEvents(rl -> rl.equals(GameData.RECIPES));
|
||||
|
||||
//reg.freeze();
|
||||
SidedExecutor.runOn(Dist.CLIENT, ()-> {
|
||||
RecipeBookClient.rebuildTable();
|
||||
return null;
|
||||
});
|
||||
DistExecutor.runWhenOn(Dist.CLIENT, ()-> RecipeBookClient::rebuildTable);
|
||||
}
|
||||
|
||||
private static void loadFactories(final ModFile modFile)
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
|
||||
package net.minecraftforge.common.util;
|
||||
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.INBTBase;
|
||||
|
||||
/**
|
||||
* An interface designed to unify various things in the Minecraft
|
||||
* code base that can be serialized to and from a NBT tag.
|
||||
*/
|
||||
public interface INBTSerializable<T extends NBTBase>
|
||||
public interface INBTSerializable<T extends INBTBase>
|
||||
{
|
||||
T serializeNBT();
|
||||
void deserializeNBT(T nbt);
|
||||
|
|
|
@ -58,7 +58,7 @@ import javax.annotation.Nullable;
|
|||
*/
|
||||
public abstract class FluidRegistry
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger("FML");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Marker FLUIDS = MarkerManager.getMarker("FLUIDS");
|
||||
static int maxID = 0;
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ import static net.minecraftforge.fml.Logging.LOADING;
|
|||
*/
|
||||
public class AutomaticEventSubscriber
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger("FML");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
public static void inject(final ModContainer mod, final ModFileScanData scanData, final ClassLoader loader)
|
||||
{
|
||||
if (scanData == null) return;
|
||||
|
|
|
@ -25,9 +25,9 @@ import net.minecraftforge.fml.loading.FMLEnvironment;
|
|||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class SidedExecutor
|
||||
public final class DistExecutor
|
||||
{
|
||||
private SidedExecutor() {}
|
||||
private DistExecutor() {}
|
||||
|
||||
/**
|
||||
* Run the callable in the supplier only on the specified {@link Side}
|
||||
|
@ -37,7 +37,7 @@ public final class SidedExecutor
|
|||
* @param <T> The return type from the callable
|
||||
* @return The callable's result
|
||||
*/
|
||||
public static <T> T runOn(Dist dist, Supplier<Callable<T>> toRun) {
|
||||
public static <T> T callWhenOn(Dist dist, Supplier<Callable<T>> toRun) {
|
||||
if (dist == FMLEnvironment.dist) {
|
||||
try
|
||||
{
|
||||
|
@ -51,7 +51,12 @@ public final class SidedExecutor
|
|||
return null;
|
||||
}
|
||||
|
||||
public static <T> T runSided(Supplier<Supplier<T>> clientTarget, Supplier<Supplier<T>> serverTarget) {
|
||||
public static void runWhenOn(Dist dist, Supplier<Runnable> toRun) {
|
||||
if (dist == FMLEnvironment.dist) {
|
||||
toRun.get().run();
|
||||
}
|
||||
}
|
||||
public static <T> T runForDist(Supplier<Supplier<T>> clientTarget, Supplier<Supplier<T>> serverTarget) {
|
||||
switch (FMLEnvironment.dist)
|
||||
{
|
||||
case CLIENT:
|
|
@ -21,7 +21,7 @@ package net.minecraftforge.fml;
|
|||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.resources.IResourcePack;
|
||||
import net.minecraft.resources.IResourcePack;
|
||||
import net.minecraftforge.fml.client.ModFileResourcePack;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
|
|
@ -25,7 +25,7 @@ import java.util.Map.Entry;
|
|||
import java.util.Optional;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.INBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
@ -47,7 +47,7 @@ import org.apache.logging.log4j.MarkerManager;
|
|||
public final class FMLWorldPersistenceHook implements WorldPersistenceHooks.WorldPersistenceHook
|
||||
{
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger("FML");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Marker WORLDPERSISTENCE = MarkerManager.getMarker("WP");
|
||||
|
||||
@Override
|
||||
|
@ -66,7 +66,7 @@ public final class FMLWorldPersistenceHook implements WorldPersistenceHooks.Worl
|
|||
final NBTTagCompound mod = new NBTTagCompound();
|
||||
mod.setString("ModId", mi.getModId());
|
||||
mod.setString("ModVersion", mi.getVersion().getVersionString());
|
||||
modList.appendTag(mod);
|
||||
modList.add(mod);
|
||||
});
|
||||
fmlData.setTag("LoadingModList", modList);
|
||||
|
||||
|
@ -82,12 +82,12 @@ public final class FMLWorldPersistenceHook implements WorldPersistenceHooks.Worl
|
|||
}
|
||||
|
||||
@Override
|
||||
public void readData(SaveHandler handler, WorldInfo info, Map<String, NBTBase> propertyMap, NBTTagCompound tag)
|
||||
public void readData(SaveHandler handler, WorldInfo info, NBTTagCompound tag)
|
||||
{
|
||||
if (tag.hasKey("LoadingModList"))
|
||||
{
|
||||
NBTTagList modList = tag.getTagList("LoadingModList", (byte)10);
|
||||
for (int i = 0; i < modList.tagCount(); i++)
|
||||
for (int i = 0; i < modList.size(); i++)
|
||||
{
|
||||
NBTTagCompound mod = modList.getCompoundTagAt(i);
|
||||
String modId = mod.getString("ModId");
|
||||
|
|
|
@ -19,33 +19,37 @@
|
|||
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
import static net.minecraftforge.fml.Logging.fmlLog;
|
||||
|
||||
public class FileUtils
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
public static Path getOrCreateDirectory(Path dirPath, String dirLabel) {
|
||||
if (!Files.isDirectory(dirPath))
|
||||
{
|
||||
fmlLog.debug(CORE,"Making {} directory : {}", dirLabel, dirPath);
|
||||
LOGGER.debug(CORE,"Making {} directory : {}", dirLabel, dirPath);
|
||||
try {
|
||||
Files.createDirectory(dirPath);
|
||||
} catch (IOException e) {
|
||||
if (e instanceof FileAlreadyExistsException) {
|
||||
fmlLog.error(CORE,"Failed to create {} directory - there is a file in the way", dirLabel);
|
||||
LOGGER.error(CORE,"Failed to create {} directory - there is a file in the way", dirLabel);
|
||||
} else {
|
||||
fmlLog.error(CORE,"Problem with creating {} directory (Permissions?)", dirLabel, e);
|
||||
LOGGER.error(CORE,"Problem with creating {} directory (Permissions?)", dirLabel, e);
|
||||
}
|
||||
throw new RuntimeException("Problem creating directory", e);
|
||||
}
|
||||
fmlLog.debug(CORE,"Created {} directory : {}", dirLabel, dirPath);
|
||||
LOGGER.debug(CORE,"Created {} directory : {}", dirLabel, dirPath);
|
||||
} else {
|
||||
fmlLog.debug(CORE,"Found existing {} directory : {}", dirLabel, dirPath);
|
||||
LOGGER.debug(CORE,"Found existing {} directory : {}", dirLabel, dirPath);
|
||||
}
|
||||
return dirPath;
|
||||
}
|
||||
|
|
|
@ -21,29 +21,15 @@ package net.minecraftforge.fml;
|
|||
|
||||
import com.google.common.base.Strings;
|
||||
import cpw.mods.modlauncher.Launcher;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.properties.PropertyEnum;
|
||||
import net.minecraft.block.state.BlockStateContainer;
|
||||
import net.minecraft.item.EnumDyeColor;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.MarkerManager;
|
||||
import org.apache.logging.log4j.core.Filter;
|
||||
import org.apache.logging.log4j.core.LoggerContext;
|
||||
import org.apache.logging.log4j.core.config.Configuration;
|
||||
import org.apache.logging.log4j.core.config.ConfigurationFactory;
|
||||
import org.apache.logging.log4j.core.config.Configurator;
|
||||
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
|
||||
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
|
||||
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
|
||||
import org.apache.logging.log4j.core.config.composite.CompositeConfiguration;
|
||||
import org.apache.logging.log4j.core.filter.MarkerFilter;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import static cpw.mods.modlauncher.Logging.CLASSLOADING;
|
||||
import static net.minecraftforge.fml.Logging.fmlLog;
|
||||
|
||||
public class LaunchTesting
|
||||
{
|
||||
public static void main(String... args) throws InterruptedException
|
||||
|
|
|
@ -28,8 +28,6 @@ import org.apache.logging.log4j.core.config.Configurator;
|
|||
|
||||
public class Logging
|
||||
{
|
||||
public static final Logger fmlLog = LogManager.getLogger("FML");
|
||||
|
||||
// Lots of markers
|
||||
public static final Marker CORE = MarkerManager.getMarker("CORE");
|
||||
public static final Marker LOADING = MarkerManager.getMarker("LOADING");
|
||||
|
|
|
@ -34,7 +34,7 @@ import java.util.function.Supplier;
|
|||
* The container that wraps around mods in the system.
|
||||
* <p>
|
||||
* The philosophy is that individual mod implementation technologies should not
|
||||
* impact the actual loading and management of mod code. This interface provides
|
||||
* impact the actual loading and management of mod code. This class provides
|
||||
* a mechanism by which we can wrap actual mod code so that the loader and other
|
||||
* facilities can treat mods at arms length.
|
||||
* </p>
|
||||
|
|
|
@ -20,11 +20,9 @@
|
|||
package net.minecraftforge.fml;
|
||||
|
||||
import com.google.common.collect.Streams;
|
||||
import net.minecraftforge.fml.javafmlmod.ModLoadingContext;
|
||||
import net.minecraftforge.fml.language.ModFileScanData;
|
||||
import net.minecraftforge.fml.loading.DefaultModInfos;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.BackgroundScanHandler;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
|
@ -51,7 +49,7 @@ import static net.minecraftforge.fml.Logging.LOADING;
|
|||
*/
|
||||
public class ModList
|
||||
{
|
||||
private static Logger LOGGER = LogManager.getLogger("FML");
|
||||
private static Logger LOGGER = LogManager.getLogger();
|
||||
private static ModList INSTANCE;
|
||||
private final List<ModFileInfo> modFiles;
|
||||
private final List<ModInfo> sortedList;
|
||||
|
|
|
@ -47,7 +47,7 @@ import static net.minecraftforge.fml.Logging.CORE;
|
|||
|
||||
public class ModLoader
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger("FML");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static ModLoader INSTANCE;
|
||||
private final ClassLoader launchClassLoader;
|
||||
private final LoadingModList loadingModList;
|
||||
|
@ -97,7 +97,7 @@ public class ModLoader
|
|||
CapabilityManager.INSTANCE.injectCapabilities(modList.getAllScanData());
|
||||
LifecycleEventProvider.PREINIT.dispatch();
|
||||
GameData.fireRegistryEvents(rl -> !Objects.equals(rl, GameData.RECIPES));
|
||||
SidedExecutor.runOn(Dist.CLIENT, ModLoader::fireClientEvents);
|
||||
Boolean result = DistExecutor.callWhenOn(Dist.CLIENT, ModLoader::fireClientEvents);
|
||||
LifecycleEventProvider.SIDEDINIT.dispatch();
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ package net.minecraftforge.fml;
|
|||
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
@ -32,6 +33,9 @@ import static net.minecraftforge.fml.Logging.LOADING;
|
|||
|
||||
public class ModLoadingClassLoader extends SecureClassLoader
|
||||
{
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
static {
|
||||
ClassLoader.registerAsParallelCapable();
|
||||
}
|
||||
|
@ -49,7 +53,7 @@ public class ModLoadingClassLoader extends SecureClassLoader
|
|||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
LogManager.getLogger("FML").debug(LOADING, "Loading class {}", name);
|
||||
LOGGER.debug(LOADING, "Loading class {}", name);
|
||||
final String className = name.replace('.','/').concat(".class");
|
||||
final Path classResource = FMLLoader.getLoadingModList().findResource(className);
|
||||
if (classResource != null) {
|
||||
|
|
|
@ -23,7 +23,7 @@ import net.minecraft.client.Minecraft;
|
|||
import net.minecraft.server.dedicated.DedicatedServer;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.client.SplashProgress;
|
||||
import net.minecraftforge.fml.client.ClientHooks;
|
||||
import net.minecraftforge.fml.common.event.FMLClientInitEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLServerInitEvent;
|
||||
import net.minecraftforge.fml.loading.FMLEnvironment;
|
||||
|
@ -34,12 +34,12 @@ import java.util.function.Supplier;
|
|||
public enum SidedProvider
|
||||
{
|
||||
// All of these need to be careful not to directly dereference the client and server elements in their signatures
|
||||
DATAFIXER(c->c.get().getDataFixer(), s->s.get().getDataFixer()),
|
||||
DATAFIXER(c->c.get().getDataFixer(), s->s.get().func_195563_aC()),
|
||||
SIDEDINIT((Function<Supplier<Minecraft>, Function<ModContainer, Event>>)c-> mc->new FMLClientInitEvent(c, mc),
|
||||
(Function<Supplier<DedicatedServer>, Function<ModContainer, Event>>)s-> mc->new FMLServerInitEvent(s, mc)),
|
||||
STRIPCHARS((Function<Supplier<Minecraft>, Function<String, String>>)c-> SplashProgress::stripSpecialChars,
|
||||
STRIPCHARS((Function<Supplier<Minecraft>, Function<String, String>>)c-> ClientHooks::stripSpecialChars,
|
||||
(Function<Supplier<DedicatedServer>, Function<String, String>>)s-> str->str),
|
||||
@SuppressWarnings("Convert2MethodRef") // need to not be methodrefs to avoid classloading all of StartupQuery's data
|
||||
@SuppressWarnings("Convert2MethodRef") // need to not be methodrefs to avoid classloading all of StartupQuery's data (supplier is coming from StartupQuery)
|
||||
STARTUPQUERY(c->StartupQuery.QueryWrapper.clientQuery(c), s->StartupQuery.QueryWrapper.dedicatedServerQuery(s));
|
||||
|
||||
private static Supplier<Minecraft> client;
|
||||
|
|
|
@ -33,6 +33,7 @@ import net.minecraftforge.fml.client.gui.GuiConfirmation;
|
|||
import net.minecraftforge.fml.client.gui.GuiNotification;
|
||||
import net.minecraftforge.fml.common.thread.EffectiveSide;
|
||||
import net.minecraftforge.fml.loading.FMLEnvironment;
|
||||
import net.minecraftforge.fml.server.ServerLifecycleHooks;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.Marker;
|
||||
|
@ -42,7 +43,7 @@ import javax.annotation.Nullable;
|
|||
|
||||
public class StartupQuery {
|
||||
// internal class/functionality, do not use
|
||||
private static final Logger LOGGER = LogManager.getLogger("FML");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Marker SQ = MarkerManager.getMarker("STARTUPQUERY");
|
||||
|
||||
public static boolean confirm(String text)
|
||||
|
@ -236,8 +237,6 @@ public class StartupQuery {
|
|||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
client.loadingScreen.displayLoadingString("");
|
||||
|
||||
try
|
||||
{
|
||||
Thread.sleep(50);
|
||||
|
@ -247,8 +246,6 @@ public class StartupQuery {
|
|||
query.exception = ie;
|
||||
}
|
||||
}
|
||||
|
||||
client.loadingScreen.displayLoadingString(""); // make sure the blank screen is being drawn at the end
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -19,16 +19,13 @@
|
|||
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.storage.SaveHandler;
|
||||
import net.minecraft.world.storage.WorldInfo;
|
||||
import net.minecraftforge.fml.common.thread.EffectiveSide;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class WorldPersistenceHooks
|
||||
{
|
||||
|
@ -47,9 +44,7 @@ public class WorldPersistenceHooks
|
|||
{
|
||||
if (EffectiveSide.get() == LogicalSide.SERVER)
|
||||
{
|
||||
Map<String, NBTBase> additionalProperties = new HashMap<>();
|
||||
worldInfo.setAdditionalProperties(additionalProperties);
|
||||
worldPersistenceHooks.forEach(wac->wac.readData(handler, worldInfo, additionalProperties, tagCompound.getCompoundTag(wac.getModId())));
|
||||
worldPersistenceHooks.forEach(wac->wac.readData(handler, worldInfo, tagCompound.getCompoundTag(wac.getModId())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,6 +71,6 @@ public class WorldPersistenceHooks
|
|||
{
|
||||
String getModId();
|
||||
NBTTagCompound getDataForWriting(SaveHandler handler, WorldInfo info);
|
||||
void readData(SaveHandler handler, WorldInfo info, Map<String, NBTBase> propertyMap, NBTTagCompound tag);
|
||||
void readData(SaveHandler handler, WorldInfo info, NBTTagCompound tag);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package net.minecraftforge.fml.client;
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.JsonArray;
|
||||
|
@ -26,10 +27,10 @@ import com.google.gson.JsonElement;
|
|||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.gui.GuiConnecting;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.GuiWorldSelection;
|
||||
import net.minecraft.client.gui.ServerListEntryNormal;
|
||||
import net.minecraft.client.multiplayer.GuiConnecting;
|
||||
import net.minecraft.client.multiplayer.ServerData;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
|
@ -39,7 +40,6 @@ import net.minecraft.world.storage.WorldSummary;
|
|||
import net.minecraftforge.fml.LogicalSide;
|
||||
import net.minecraftforge.fml.StartupQuery;
|
||||
import net.minecraftforge.fml.client.gui.GuiAccessDenied;
|
||||
import net.minecraftforge.fml.common.network.internal.FMLNetworkHandler;
|
||||
import net.minecraftforge.registries.GameData;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
@ -55,8 +55,11 @@ import java.util.concurrent.CountDownLatch;
|
|||
|
||||
public class ClientHooks
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger("FML");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Marker CLIENTHOOKS = MarkerManager.getMarker("CLIENTHOOKS");
|
||||
// From FontRenderer.renderCharAtPos
|
||||
private static final String ALLOWED_CHARS = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000";
|
||||
private static final CharMatcher DISALLOWED_CHAR_MATCHER = CharMatcher.anyOf(ALLOWED_CHARS).negate();
|
||||
|
||||
private static Map<ServerStatusResponse,JsonObject> extraServerListData;
|
||||
private static Map<ServerData, ExtendedServerListData> serverDataTag;
|
||||
|
@ -77,6 +80,7 @@ public class ClientHooks
|
|||
}
|
||||
public static void bindServerListData(ServerData data, ServerStatusResponse originalResponse)
|
||||
{
|
||||
/*
|
||||
if (extraServerListData.containsKey(originalResponse))
|
||||
{
|
||||
JsonObject jsonData = extraServerListData.get(originalResponse);
|
||||
|
@ -104,6 +108,7 @@ public class ClientHooks
|
|||
}
|
||||
serverDataTag.put(data, new ExtendedServerListData("VANILLA", false, ImmutableMap.of(), !moddedClientAllowed));
|
||||
}
|
||||
*/
|
||||
startupConnectionData.countDown();
|
||||
}
|
||||
|
||||
|
@ -167,7 +172,7 @@ public class ClientHooks
|
|||
|
||||
static File getSavesDir()
|
||||
{
|
||||
return new File(Minecraft.getMinecraft().mcDataDir, "saves");
|
||||
return new File(Minecraft.getMinecraft().gameDir, "saves");
|
||||
}
|
||||
|
||||
public static void tryLoadExistingWorld(GuiWorldSelection selectWorldGUI, WorldSummary comparator)
|
||||
|
@ -210,4 +215,9 @@ public class ClientHooks
|
|||
}
|
||||
}
|
||||
|
||||
public static String stripSpecialChars(String message)
|
||||
{
|
||||
// We can't handle many unicode points in the splash renderer
|
||||
return DISALLOWED_CHAR_MATCHER.removeFrom(net.minecraft.util.StringUtils.stripControlCodes(message));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,10 @@
|
|||
package net.minecraftforge.fml.client;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.resources.IReloadableResourceManager;
|
||||
import net.minecraft.client.resources.IResourcePack;
|
||||
import net.minecraft.client.resources.data.MetadataSerializer;
|
||||
import net.minecraft.resources.IReloadableResourceManager;
|
||||
import net.minecraft.resources.IResourcePack;
|
||||
import net.minecraft.resources.data.IMetadataSectionSerializer;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.LogicalSidedProvider;
|
||||
|
@ -33,7 +32,6 @@ import net.minecraftforge.fml.VersionChecker;
|
|||
import net.minecraftforge.fml.ModLoader;
|
||||
import net.minecraftforge.fml.client.gui.GuiNotification;
|
||||
import net.minecraftforge.fml.client.registry.RenderingRegistry;
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
@ -44,13 +42,12 @@ public class ClientModLoader
|
|||
private static boolean loading;
|
||||
private static Minecraft mc;
|
||||
|
||||
public static void begin(final Minecraft minecraft, final List<IResourcePack> defaultResourcePacks, final IReloadableResourceManager mcResourceManager, MetadataSerializer metadataSerializer_)
|
||||
public static void begin(final Minecraft minecraft, final List<IResourcePack> defaultResourcePacks, final IReloadableResourceManager mcResourceManager, IMetadataSectionSerializer metadataSerializer)
|
||||
{
|
||||
loading = true;
|
||||
ClientModLoader.mc = minecraft;
|
||||
SidedProvider.setClient(()->minecraft);
|
||||
LogicalSidedProvider.setClient(()->minecraft);
|
||||
SplashProgress.start();
|
||||
ModLoader.get().loadMods();
|
||||
ResourcePackLoader.loadResourcePacks(defaultResourcePacks);
|
||||
minecraft.refreshResources();
|
||||
|
@ -61,7 +58,6 @@ public class ClientModLoader
|
|||
ModLoader.get().finishMods();
|
||||
loading = false;
|
||||
mc.gameSettings.loadOptions();
|
||||
SplashProgress.finish();
|
||||
}
|
||||
|
||||
public static VersionChecker.Status checkForUpdates()
|
||||
|
@ -75,27 +71,6 @@ public class ClientModLoader
|
|||
GlStateManager.enableTexture2D();
|
||||
}
|
||||
|
||||
// If the startup screen has a notification on it, render that instead of the loading screen
|
||||
public static boolean drawNotificationOverProgressScreen(final Minecraft client, final ScaledResolution scaledResolution) throws IOException
|
||||
{
|
||||
if (client.currentScreen instanceof GuiNotification)
|
||||
{
|
||||
int width = scaledResolution.getScaledWidth();
|
||||
int height = scaledResolution.getScaledHeight();
|
||||
int mouseX = Mouse.getX() * width / client.displayWidth;
|
||||
int mouseZ = height - Mouse.getY() * height / client.displayHeight - 1;
|
||||
|
||||
client.currentScreen.drawScreen(mouseX, mouseZ, 0);
|
||||
client.currentScreen.handleInput();
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isErrored()
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.client;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraftforge.fml.client.config.GuiConfig;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
|
||||
public class DefaultGuiFactory implements IModGuiFactory
|
||||
{
|
||||
|
||||
protected String modid, title;
|
||||
protected Minecraft minecraft;
|
||||
|
||||
protected DefaultGuiFactory(String modid, String title)
|
||||
{
|
||||
this.modid = modid;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConfigGui()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(Minecraft minecraftInstance)
|
||||
{
|
||||
this.minecraft = minecraftInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuiScreen createConfigGui(GuiScreen parentScreen)
|
||||
{
|
||||
return new GuiConfig(parentScreen, modid, title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RuntimeOptionCategoryElement> runtimeGuiCategories()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IModGuiFactory forMod(ModContainer mod)
|
||||
{
|
||||
return new DefaultGuiFactory(mod.getModId(), mod.getName());
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.client;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import net.minecraft.client.resources.FileResourcePack;
|
||||
import net.minecraftforge.fml.common.FMLContainerHolder;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
|
||||
public class FMLFileResourcePack extends FileResourcePack implements FMLContainerHolder {
|
||||
|
||||
private ModContainer container;
|
||||
|
||||
public FMLFileResourcePack(ModContainer container)
|
||||
{
|
||||
super(container.getSource());
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPackName()
|
||||
{
|
||||
return "FMLFileResourcePack:"+container.getName();
|
||||
}
|
||||
@Override
|
||||
protected InputStream getInputStreamByName(String resourceName) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
return super.getInputStreamByName(resourceName);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
if ("pack.mcmeta".equals(resourceName))
|
||||
{
|
||||
FMLLog.log.debug("Mod {} is missing a pack.mcmeta file, substituting a dummy one", container.getName());
|
||||
return new ByteArrayInputStream(("{\n" +
|
||||
" \"pack\": {\n"+
|
||||
" \"description\": \"dummy FML pack for "+container.getName()+"\",\n"+
|
||||
" \"pack_format\": 2\n"+
|
||||
"}\n" +
|
||||
"}").getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
else throw ioe;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getPackImage() throws IOException
|
||||
{
|
||||
return ImageIO.read(getInputStreamByName(container.getMetadata().logoFile));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModContainer getFMLContainer()
|
||||
{
|
||||
return container;
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.client;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import net.minecraft.client.resources.FolderResourcePack;
|
||||
import net.minecraftforge.fml.common.FMLContainerHolder;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
|
||||
public class FMLFolderResourcePack extends FolderResourcePack implements FMLContainerHolder {
|
||||
|
||||
private ModContainer container;
|
||||
|
||||
public FMLFolderResourcePack(ModContainer container)
|
||||
{
|
||||
super(container.getSource());
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasResourceName(String p_110593_1_)
|
||||
{
|
||||
return super.hasResourceName(p_110593_1_);
|
||||
}
|
||||
@Override
|
||||
public String getPackName()
|
||||
{
|
||||
return "FMLFileResourcePack:"+container.getName();
|
||||
}
|
||||
@Override
|
||||
protected InputStream getInputStreamByName(String resourceName) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
return super.getInputStreamByName(resourceName);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
if ("pack.mcmeta".equals(resourceName))
|
||||
{
|
||||
FMLLog.log.debug("Mod {} is missing a pack.mcmeta file, substituting a dummy one", container.getName());
|
||||
return new ByteArrayInputStream(("{\n" +
|
||||
" \"pack\": {\n"+
|
||||
" \"description\": \"dummy FML pack for "+container.getName()+"\",\n"+
|
||||
" \"pack_format\": 2\n"+
|
||||
"}\n" +
|
||||
"}").getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
else throw ioe;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getPackImage() throws IOException
|
||||
{
|
||||
return ImageIO.read(getInputStreamByName(container.getMetadata().logoFile));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModContainer getFMLContainer()
|
||||
{
|
||||
return container;
|
||||
}
|
||||
|
||||
}
|
|
@ -19,15 +19,19 @@
|
|||
|
||||
package net.minecraftforge.fml.client;
|
||||
|
||||
import net.minecraft.client.resources.AbstractResourcePack;
|
||||
import net.minecraft.resources.AbstractResourcePack;
|
||||
import net.minecraft.resources.ResourcePackType;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ModFileResourcePack extends AbstractResourcePack
|
||||
|
@ -45,32 +49,57 @@ public class ModFileResourcePack extends AbstractResourcePack
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getPackName()
|
||||
public String func_195762_a()
|
||||
{
|
||||
return modFile.getFileName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InputStream getInputStreamByName(String name) throws IOException
|
||||
protected InputStream func_195766_a(String name) throws IOException
|
||||
{
|
||||
return Files.newInputStream(modFile.getLocator().findPath(modFile, name));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasResourceName(String name)
|
||||
protected boolean func_195768_c(String name)
|
||||
{
|
||||
return Files.exists(modFile.getLocator().findPath(modFile, name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getResourceDomains()
|
||||
public Collection<ResourceLocation> func_195758_a(ResourcePackType p_195758_1_, String p_195758_2_, int p_195758_3_, Predicate<String> p_195758_4_)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
return Files.walk(modFile.getLocator().findPath(modFile, p_195758_1_.func_198956_a())).
|
||||
filter(path -> !path.toString().endsWith(".mcmeta")).
|
||||
filter(path -> path.getNameCount() > 2 && p_195758_2_.equals(path.getName(2).toString())).
|
||||
filter(path -> p_195758_4_.test(path.subpath(3, Math.min(p_195758_3_+3, path.getNameCount())).toString())).
|
||||
map(path -> new ResourceLocation(path.getName(1).toString(),path.subpath(3,Math.min(p_195758_3_+3, path.getNameCount())).toString())).
|
||||
collect(Collectors.toList());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> func_195759_a(ResourcePackType p_195759_1_)
|
||||
{
|
||||
try {
|
||||
return Files.walk(modFile.getLocator().findPath(modFile, "assets"),1).map(p->p.getFileName().toString()).collect(Collectors.toSet());
|
||||
return Files.walk(modFile.getLocator().findPath(modFile, p_195759_1_.func_198956_a()),1).map(p->p.getFileName().toString()).collect(Collectors.toSet());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
|
||||
package net.minecraftforge.fml.client;
|
||||
|
||||
import net.minecraft.client.resources.AbstractResourcePack;
|
||||
import net.minecraft.client.resources.FileResourcePack;
|
||||
import net.minecraft.client.resources.FolderResourcePack;
|
||||
import net.minecraft.client.resources.IResourcePack;
|
||||
import net.minecraft.resources.AbstractResourcePack;
|
||||
import net.minecraft.resources.FilePack;
|
||||
import net.minecraft.resources.FolderPack;
|
||||
import net.minecraft.resources.IResourcePack;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
|
@ -48,8 +48,8 @@ public class ResourcePackLoader
|
|||
map(mf -> new ModFileResourcePack(mf.getFile())).
|
||||
collect(Collectors.toMap(ModFileResourcePack::getModFile, Function.identity()));
|
||||
forgePack = Files.isDirectory(FMLLoader.getForgePath()) ?
|
||||
new FolderResourcePack(FMLLoader.getForgePath().toFile()) :
|
||||
new FileResourcePack(FMLLoader.getForgePath().toFile());
|
||||
new FolderPack(FMLLoader.getForgePath().toFile()) :
|
||||
new FilePack(FMLLoader.getForgePath().toFile());
|
||||
resourcePacks.add(forgePack);
|
||||
resourcePacks.addAll(modResourcePacks.values());
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
package net.minecraftforge.fml.client;
|
||||
|
||||
/*
|
||||
import static net.minecraftforge.fml.Logging.SPLASH;
|
||||
import static net.minecraftforge.fml.Logging.fmlLog;
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
@ -86,6 +86,7 @@ import org.lwjgl.util.glu.GLU;
|
|||
@SuppressWarnings("serial")
|
||||
public class SplashProgress
|
||||
{
|
||||
/*
|
||||
private static Drawable d;
|
||||
private static volatile boolean pause = false;
|
||||
private static volatile boolean done = false;
|
||||
|
@ -613,7 +614,7 @@ public class SplashProgress
|
|||
* Resource loading doesn't usually require this call.
|
||||
* Call {@link #resume()} when you're done.
|
||||
* @deprecated not a stable API, will break, don't use this yet
|
||||
*/
|
||||
* /
|
||||
@Deprecated
|
||||
public static void pause()
|
||||
{
|
||||
|
@ -635,7 +636,7 @@ public class SplashProgress
|
|||
|
||||
/**
|
||||
* @deprecated not a stable API, will break, don't use this yet
|
||||
*/
|
||||
* /
|
||||
@Deprecated
|
||||
public static void resume()
|
||||
{
|
||||
|
@ -980,4 +981,5 @@ public class SplashProgress
|
|||
{
|
||||
return (int) (bytes / 1024L / 1024L);
|
||||
}
|
||||
*/
|
||||
}
|
|
@ -20,27 +20,13 @@
|
|||
package net.minecraftforge.fml.client;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Table;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.AbstractResourcePack;
|
||||
import net.minecraft.client.resources.FallbackResourceManager;
|
||||
import net.minecraft.client.resources.IResourcePack;
|
||||
import net.minecraft.client.resources.SimpleReloadableResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.common.FMLContainerHolder;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class TextureTracker
|
||||
|
@ -51,24 +37,25 @@ public class TextureTracker
|
|||
|
||||
public static void trackMissingTexture(ResourceLocation resourceLocation)
|
||||
{
|
||||
badTextureDomains.add(resourceLocation.getResourceDomain());
|
||||
missingTextures.put(resourceLocation.getResourceDomain(),resourceLocation);
|
||||
badTextureDomains.add(resourceLocation.getNamespace());
|
||||
missingTextures.put(resourceLocation.getNamespace(),resourceLocation);
|
||||
}
|
||||
|
||||
public static void trackBrokenTexture(ResourceLocation resourceLocation, String error)
|
||||
{
|
||||
badTextureDomains.add(resourceLocation.getResourceDomain());
|
||||
Set<ResourceLocation> badType = brokenTextures.get(resourceLocation.getResourceDomain(), error);
|
||||
badTextureDomains.add(resourceLocation.getNamespace());
|
||||
Set<ResourceLocation> badType = brokenTextures.get(resourceLocation.getNamespace(), error);
|
||||
if (badType == null)
|
||||
{
|
||||
badType = Sets.newHashSet();
|
||||
brokenTextures.put(resourceLocation.getResourceDomain(), MoreObjects.firstNonNull(error, "Unknown error"), badType);
|
||||
brokenTextures.put(resourceLocation.getNamespace(), MoreObjects.firstNonNull(error, "Unknown error"), badType);
|
||||
}
|
||||
badType.add(resourceLocation);
|
||||
}
|
||||
|
||||
public static void logMissingTextureErrors()
|
||||
{
|
||||
/*
|
||||
if (missingTextures.isEmpty() && brokenTextures.isEmpty())
|
||||
{
|
||||
return;
|
||||
|
@ -141,6 +128,7 @@ public class TextureTracker
|
|||
logger.error(Strings.repeat("=", 50));
|
||||
}
|
||||
logger.error(Strings.repeat("+=", 25));
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -34,8 +34,6 @@ import net.minecraft.client.gui.GuiScreen;
|
|||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.config.ConfigElement;
|
||||
import net.minecraftforge.common.config.ConfigManager;
|
||||
import net.minecraftforge.fml.client.config.GuiConfigEntries.IConfigEntry;
|
||||
import net.minecraftforge.fml.client.event.ConfigChangedEvent;
|
||||
import net.minecraftforge.fml.client.event.ConfigChangedEvent.OnConfigChangedEvent;
|
||||
|
@ -85,51 +83,6 @@ public class GuiConfig extends GuiScreen
|
|||
protected HoverChecker resetHoverChecker;
|
||||
protected HoverChecker checkBoxHoverChecker;
|
||||
|
||||
/**
|
||||
* This constructor handles the {@code @Config} configuration classes
|
||||
* @param parentScreen the parent GuiScreen object
|
||||
* @param mod the mod for which to create a screen
|
||||
*/
|
||||
public GuiConfig(GuiScreen parentScreen, String modid, String title)
|
||||
{
|
||||
this(parentScreen, modid, false, false, title, ConfigManager.getModConfigClasses(modid));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param parentScreen the parrent GuiScreen object
|
||||
* @param modID the mod ID for the mod whose config settings will be editted
|
||||
* @param allRequireWorldRestart whether all config elements on this screen require a world restart
|
||||
* @param allRequireMcRestart whether all config elements on this screen require a game restart
|
||||
* @param title the desired title for this screen. For consistency it is recommended that you pass the path of the config file being
|
||||
* edited.
|
||||
* @param configClasses an array of classes annotated with {@code @Config} providing the configuration
|
||||
*/
|
||||
public GuiConfig(GuiScreen parentScreen, String modID, boolean allRequireWorldRestart, boolean allRequireMcRestart, String title,
|
||||
Class<?>... configClasses)
|
||||
{
|
||||
this(parentScreen, collectConfigElements(configClasses), modID, null, allRequireWorldRestart, allRequireMcRestart, title, null);
|
||||
}
|
||||
|
||||
private static List<IConfigElement> collectConfigElements(Class<?>[] configClasses)
|
||||
{
|
||||
List<IConfigElement> toReturn;
|
||||
if(configClasses.length == 1)
|
||||
{
|
||||
toReturn = ConfigElement.from(configClasses[0]).getChildElements();
|
||||
}
|
||||
else
|
||||
{
|
||||
toReturn = new ArrayList<IConfigElement>();
|
||||
for(Class<?> clazz : configClasses)
|
||||
{
|
||||
toReturn.add(ConfigElement.from(clazz));
|
||||
}
|
||||
}
|
||||
toReturn.sort(Comparator.comparing(e -> I18n.format(e.getLanguageKey())));
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* GuiConfig constructor that will use ConfigChangedEvent when editing is concluded. If a non-null value is passed for configID,
|
||||
* the OnConfigChanged and PostConfigChanged events will be posted when the Done button is pressed if any configElements were changed
|
||||
|
@ -214,7 +167,7 @@ public class GuiConfig extends GuiScreen
|
|||
this.parentScreen = parentScreen;
|
||||
this.configElements = configElements;
|
||||
this.entryList = new GuiConfigEntries(this, mc);
|
||||
this.initEntries = new ArrayList<IConfigEntry>(entryList.listEntries);
|
||||
this.initEntries = new ArrayList<>(entryList.listEntries);
|
||||
this.allRequireWorldRestart = allRequireWorldRestart;
|
||||
IF:if (!allRequireWorldRestart)
|
||||
{
|
||||
|
|
|
@ -27,7 +27,7 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiListExtended;
|
||||
|
@ -35,10 +35,10 @@ import net.minecraft.client.gui.GuiScreen;
|
|||
import net.minecraft.client.gui.GuiTextField;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import net.minecraftforge.fml.common.Loader;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
/**
|
||||
|
@ -150,10 +150,7 @@ public class GuiConfigEntries extends GuiListExtended
|
|||
}
|
||||
else if (configElement.getType() == ConfigGuiType.MOD_ID)
|
||||
{
|
||||
Map<Object, String> values = new TreeMap<Object, String>();
|
||||
for (ModContainer mod : Loader.instance().getActiveModList())
|
||||
values.put(mod.getModId(), mod.getName());
|
||||
values.put("minecraft", "Minecraft");
|
||||
Map<Object, String> values = ModList.get().getMods().stream().collect(Collectors.toMap(ModInfo::getModId, ModInfo::getDisplayName));
|
||||
this.listEntries.add(new SelectValueEntry(this.owningScreen, this, configElement, values));
|
||||
}
|
||||
else if (configElement.getType() == ConfigGuiType.STRING)
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
package net.minecraftforge.fml.client.registry;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
|
||||
import net.minecraft.client.settings.KeyBinding;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraftforge.fml.common.registry.GameRegistry;
|
||||
|
@ -45,13 +45,13 @@ public class ClientRegistry
|
|||
* @param id
|
||||
* @param specialRenderer
|
||||
*/
|
||||
public static <T extends TileEntity> void registerTileEntity(Class<T> tileEntityClass, String id, TileEntitySpecialRenderer<? super T> specialRenderer)
|
||||
public static <T extends TileEntity> void registerTileEntity(Class<T> tileEntityClass, String id, TileEntityRenderer<? super T> specialRenderer)
|
||||
{
|
||||
GameRegistry.registerTileEntity(tileEntityClass, id);
|
||||
bindTileEntitySpecialRenderer(tileEntityClass, specialRenderer);
|
||||
}
|
||||
|
||||
public static <T extends TileEntity> void bindTileEntitySpecialRenderer(Class<T> tileEntityClass, TileEntitySpecialRenderer<? super T> specialRenderer)
|
||||
public static <T extends TileEntity> void bindTileEntitySpecialRenderer(Class<T> tileEntityClass, TileEntityRenderer<? super T> specialRenderer)
|
||||
{
|
||||
TileEntityRendererDispatcher.instance.renderers.put(tileEntityClass, specialRenderer);
|
||||
specialRenderer.setRendererDispatcher(TileEntityRendererDispatcher.instance);
|
||||
|
|
|
@ -1,677 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.EnumConnectionState;
|
||||
import net.minecraft.network.INetHandler;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.network.handshake.client.C00Handshake;
|
||||
import net.minecraft.network.login.server.SPacketDisconnect;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.IThreadListener;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.SaveHandler;
|
||||
import net.minecraft.world.storage.WorldInfo;
|
||||
import net.minecraftforge.client.model.animation.Animation;
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.util.CompoundDataFixer;
|
||||
import net.minecraftforge.fml.LogicalSide;
|
||||
import net.minecraftforge.fml.StartupQuery;
|
||||
import net.minecraftforge.fml.WorldPersistenceHooks;
|
||||
import net.minecraftforge.fml.BrandingControl;
|
||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fml.common.gameevent.InputEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
|
||||
import net.minecraftforge.fml.common.network.FMLNetworkEvent;
|
||||
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||
import net.minecraftforge.fml.common.thread.SidedThreadGroup;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import net.minecraftforge.fml.server.FMLServerHandler;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* The main class for non-obfuscated hook handling code
|
||||
*
|
||||
* Anything that doesn't require obfuscated or client/server specific code should
|
||||
* go in this handler
|
||||
*
|
||||
* It also contains a reference to the sided handler instance that is valid
|
||||
* allowing for common code to access specific properties from the obfuscated world
|
||||
* without a direct dependency
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class FMLCommonHandler
|
||||
{
|
||||
/**
|
||||
* The singleton
|
||||
*/
|
||||
private static final FMLCommonHandler INSTANCE = new FMLCommonHandler();
|
||||
/**
|
||||
* The delegate for side specific data and functions
|
||||
*/
|
||||
private IFMLSidedHandler sidedDelegate;
|
||||
|
||||
private boolean noForge;
|
||||
private List<String> brandings;
|
||||
private List<String> brandingsNoMC;
|
||||
private Set<SaveHandler> handlerSet = Collections.newSetFromMap(new MapMaker().weakKeys().<SaveHandler,Boolean>makeMap());
|
||||
private WeakReference<SaveHandler> handlerToCheck;
|
||||
private IEventBus eventBus = MinecraftForge.EVENT_BUS;
|
||||
private volatile CountDownLatch exitLatch = null;
|
||||
|
||||
private FMLCommonHandler()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* The FML event bus. Subscribe here for FML related events
|
||||
*
|
||||
* @Deprecated Use {@link MinecraftForge#EVENT_BUS} they're the same thing now
|
||||
* @return the event bus
|
||||
*/
|
||||
@Deprecated
|
||||
public IEventBus bus()
|
||||
{
|
||||
return eventBus;
|
||||
}
|
||||
|
||||
public List<String> beginLoading(IFMLSidedHandler handler)
|
||||
{
|
||||
sidedDelegate = handler;
|
||||
MinecraftForge.initialize();
|
||||
// MinecraftForge.registerCrashCallable();
|
||||
return ImmutableList.<String>of();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the instance
|
||||
*/
|
||||
public static FMLCommonHandler instance()
|
||||
{
|
||||
return INSTANCE;
|
||||
}
|
||||
/**
|
||||
* Find the container that associates with the supplied mod object
|
||||
* @param mod
|
||||
*/
|
||||
public ModContainer findContainerFor(Object mod)
|
||||
{
|
||||
if (mod instanceof String)
|
||||
{
|
||||
return Loader.instance().getIndexedModList().get(mod);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Loader.instance().getReversedModObjectList().get(mod);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the forge mod loader logging instance (goes to the forgemodloader log file)
|
||||
* @return The log instance for the FML log file
|
||||
*
|
||||
* @deprecated Not used in FML, Mods use your own logger, see {@link FMLPreInitializationEvent#getModLog()}
|
||||
*/
|
||||
@Deprecated
|
||||
public Logger getFMLLogger()
|
||||
{
|
||||
return FMLLog.log;
|
||||
}
|
||||
|
||||
public Side getSide()
|
||||
{
|
||||
return sidedDelegate.getSide();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the effective side for the context in the game. This is dependent
|
||||
* on thread analysis to try and determine whether the code is running in the
|
||||
* server or not. Use at your own risk
|
||||
*/
|
||||
public Side getEffectiveSide()
|
||||
{
|
||||
final ThreadGroup group = Thread.currentThread().getThreadGroup();
|
||||
return group instanceof SidedThreadGroup ? ((SidedThreadGroup) group).getSide() : Side.CLIENT;
|
||||
}
|
||||
/**
|
||||
* Raise an exception
|
||||
*/
|
||||
public void raiseException(Throwable exception, String message, boolean stopGame)
|
||||
{
|
||||
FMLLog.log.error("Something raised an exception. The message was '{}'. 'stopGame' is {}", stopGame, exception);
|
||||
if (stopGame)
|
||||
{
|
||||
getSidedDelegate().haltGame(message,exception);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<String> getBrandings(boolean includeMC)
|
||||
{
|
||||
if (brandings == null)
|
||||
{
|
||||
BrandingControl.computeBranding();
|
||||
}
|
||||
return includeMC ? ImmutableList.copyOf(brandings) : ImmutableList.copyOf(brandingsNoMC);
|
||||
}
|
||||
|
||||
public IFMLSidedHandler getSidedDelegate()
|
||||
{
|
||||
return sidedDelegate;
|
||||
}
|
||||
|
||||
public void onPostServerTick()
|
||||
{
|
||||
bus().post(new TickEvent.ServerTickEvent(Phase.END));
|
||||
}
|
||||
|
||||
/**
|
||||
* Every tick just after world and other ticks occur
|
||||
*/
|
||||
public void onPostWorldTick(World world)
|
||||
{
|
||||
bus().post(new TickEvent.WorldTickEvent(Side.SERVER, Phase.END, world));
|
||||
}
|
||||
|
||||
public void onPreServerTick()
|
||||
{
|
||||
bus().post(new TickEvent.ServerTickEvent(Phase.START));
|
||||
}
|
||||
|
||||
/**
|
||||
* Every tick just before world and other ticks occur
|
||||
*/
|
||||
public void onPreWorldTick(World world)
|
||||
{
|
||||
bus().post(new TickEvent.WorldTickEvent(Side.SERVER, Phase.START, world));
|
||||
}
|
||||
|
||||
public boolean handleServerAboutToStart(MinecraftServer server)
|
||||
{
|
||||
return Loader.instance().serverAboutToStart(server);
|
||||
}
|
||||
|
||||
public boolean handleServerStarting(MinecraftServer server)
|
||||
{
|
||||
return Loader.instance().serverStarting(server);
|
||||
}
|
||||
|
||||
public void handleServerStarted()
|
||||
{
|
||||
Loader.instance().serverStarted();
|
||||
sidedDelegate.allowLogins();
|
||||
}
|
||||
|
||||
public void handleServerStopping()
|
||||
{
|
||||
Loader.instance().serverStopping();
|
||||
}
|
||||
|
||||
public File getSavesDirectory() {
|
||||
return sidedDelegate.getSavesDirectory();
|
||||
}
|
||||
|
||||
public MinecraftServer getMinecraftServerInstance()
|
||||
{
|
||||
return sidedDelegate.getServer();
|
||||
}
|
||||
|
||||
public void showGuiScreen(Object clientGuiElement)
|
||||
{
|
||||
sidedDelegate.showGuiScreen(clientGuiElement);
|
||||
}
|
||||
|
||||
public void queryUser(StartupQuery query) throws InterruptedException
|
||||
{
|
||||
sidedDelegate.queryUser(query);
|
||||
}
|
||||
|
||||
public void onServerStart(MinecraftServer dedicatedServer)
|
||||
{
|
||||
FMLServerHandler.instance();
|
||||
sidedDelegate.beginServerLoading(dedicatedServer);
|
||||
}
|
||||
|
||||
public void onServerStarted()
|
||||
{
|
||||
sidedDelegate.finishServerLoading();
|
||||
}
|
||||
|
||||
|
||||
public void onPreClientTick()
|
||||
{
|
||||
bus().post(new TickEvent.ClientTickEvent(Phase.START));
|
||||
}
|
||||
|
||||
public void onPostClientTick()
|
||||
{
|
||||
bus().post(new TickEvent.ClientTickEvent(Phase.END));
|
||||
}
|
||||
|
||||
public void onRenderTickStart(float timer)
|
||||
{
|
||||
Animation.setClientPartialTickTime(timer);
|
||||
bus().post(new TickEvent.RenderTickEvent(Phase.START, timer));
|
||||
}
|
||||
|
||||
public void onRenderTickEnd(float timer)
|
||||
{
|
||||
bus().post(new TickEvent.RenderTickEvent(Phase.END, timer));
|
||||
}
|
||||
|
||||
public void onPlayerPreTick(EntityPlayer player)
|
||||
{
|
||||
bus().post(new TickEvent.PlayerTickEvent(Phase.START, player));
|
||||
}
|
||||
|
||||
public void onPlayerPostTick(EntityPlayer player)
|
||||
{
|
||||
bus().post(new TickEvent.PlayerTickEvent(Phase.END, player));
|
||||
}
|
||||
|
||||
public void handleWorldDataSave(SaveHandler handler, WorldInfo worldInfo, NBTTagCompound tagCompound)
|
||||
{
|
||||
for (ModContainer mc : Loader.instance().getModList())
|
||||
{
|
||||
if (mc instanceof InjectedModContainer)
|
||||
{
|
||||
WorldPersistenceHooks.WorldPersistenceHook wac = ((InjectedModContainer)mc).getWrappedWorldAccessContainer();
|
||||
if (wac != null)
|
||||
{
|
||||
NBTTagCompound dataForWriting = wac.getDataForWriting(handler, worldInfo);
|
||||
tagCompound.setTag(mc.getModId(), dataForWriting);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleWorldDataLoad(SaveHandler handler, WorldInfo worldInfo, NBTTagCompound tagCompound)
|
||||
{
|
||||
if (getEffectiveSide()!=LogicalSide.SERVER)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (handlerSet.contains(handler))
|
||||
{
|
||||
return;
|
||||
}
|
||||
handlerSet.add(handler);
|
||||
handlerToCheck = new WeakReference<SaveHandler>(handler); // for confirmBackupLevelDatUse
|
||||
Map<String,NBTBase> additionalProperties = Maps.newHashMap();
|
||||
worldInfo.setAdditionalProperties(additionalProperties);
|
||||
for (ModContainer mc : Loader.instance().getModList())
|
||||
{
|
||||
if (mc instanceof InjectedModContainer)
|
||||
{
|
||||
WorldPersistenceHooks.WorldPersistenceHook wac = ((InjectedModContainer)mc).getWrappedWorldAccessContainer();
|
||||
if (wac != null)
|
||||
{
|
||||
wac.readData(handler, worldInfo, additionalProperties, tagCompound.getCompoundTag(mc.getModId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void confirmBackupLevelDatUse(SaveHandler handler)
|
||||
{
|
||||
if (handlerToCheck == null || handlerToCheck.get() != handler) {
|
||||
// only run if the save has been initially loaded
|
||||
handlerToCheck = null;
|
||||
return;
|
||||
}
|
||||
|
||||
String text = "Forge Mod Loader detected that the backup level.dat is being used.\n\n" +
|
||||
"This may happen due to a bug or corruption, continuing can damage\n" +
|
||||
"your world beyond repair or lose data / progress.\n\n" +
|
||||
"It's recommended to create a world backup before continuing.";
|
||||
|
||||
boolean confirmed = StartupQuery.confirm(text);
|
||||
if (!confirmed) StartupQuery.abort();
|
||||
}
|
||||
|
||||
public boolean isDisplayCloseRequested()
|
||||
{
|
||||
return sidedDelegate != null && sidedDelegate.isDisplayCloseRequested();
|
||||
}
|
||||
|
||||
public boolean shouldServerBeKilledQuietly()
|
||||
{
|
||||
if (sidedDelegate == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return sidedDelegate.shouldServerShouldBeKilledQuietly();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make handleExit() wait for handleServerStopped().
|
||||
*
|
||||
* For internal use only!
|
||||
*/
|
||||
public void expectServerStopped()
|
||||
{
|
||||
exitLatch = new CountDownLatch(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delayed System.exit() until the server is actually stopped/done saving.
|
||||
*
|
||||
* For internal use only!
|
||||
*
|
||||
* @param retVal Exit code for System.exit()
|
||||
*/
|
||||
public void handleExit(int retVal)
|
||||
{
|
||||
CountDownLatch latch = exitLatch;
|
||||
|
||||
if (latch != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
FMLLog.log.info("Waiting for the server to terminate/save.");
|
||||
if (!latch.await(10, TimeUnit.SECONDS))
|
||||
{
|
||||
FMLLog.log.warn("The server didn't stop within 10 seconds, exiting anyway.");
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.log.info("Server terminated.");
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
FMLLog.log.warn("Interrupted wait, exiting.");
|
||||
}
|
||||
}
|
||||
|
||||
System.exit(retVal);
|
||||
}
|
||||
|
||||
public void handleServerStopped()
|
||||
{
|
||||
sidedDelegate.serverStopped();
|
||||
MinecraftServer server = getMinecraftServerInstance();
|
||||
Loader.instance().serverStopped();
|
||||
// FORCE the internal server to stop: hello optifine workaround!
|
||||
if (server!=null) ObfuscationReflectionHelper.setPrivateValue(MinecraftServer.class, server, false, "field_71316"+"_v", "u", "serverStopped");
|
||||
|
||||
// allow any pending exit to continue, clear exitLatch
|
||||
CountDownLatch latch = exitLatch;
|
||||
|
||||
if (latch != null)
|
||||
{
|
||||
latch.countDown();
|
||||
exitLatch = null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getModName()
|
||||
{
|
||||
List<String> modNames = Lists.newArrayListWithExpectedSize(3);
|
||||
modNames.add("fml");
|
||||
if (!noForge)
|
||||
{
|
||||
modNames.add(ForgeVersion.MOD_ID);
|
||||
}
|
||||
|
||||
if (Loader.instance().getFMLBrandingProperties().containsKey("snooperbranding"))
|
||||
{
|
||||
modNames.add(Loader.instance().getFMLBrandingProperties().get("snooperbranding"));
|
||||
}
|
||||
return Joiner.on(',').join(modNames);
|
||||
}
|
||||
|
||||
public void addModToResourcePack(ModContainer container)
|
||||
{
|
||||
sidedDelegate.addModAsResource(container);
|
||||
}
|
||||
|
||||
public String getCurrentLanguage()
|
||||
{
|
||||
|
||||
return sidedDelegate.getCurrentLanguage();
|
||||
}
|
||||
|
||||
public void bootstrap()
|
||||
{
|
||||
}
|
||||
|
||||
public NetworkManager getClientToServerNetworkManager()
|
||||
{
|
||||
return sidedDelegate.getClientToServerNetworkManager();
|
||||
}
|
||||
|
||||
public void fireMouseInput()
|
||||
{
|
||||
bus().post(new InputEvent.MouseInputEvent());
|
||||
}
|
||||
|
||||
public void fireKeyInput()
|
||||
{
|
||||
bus().post(new InputEvent.KeyInputEvent());
|
||||
}
|
||||
|
||||
public void firePlayerChangedDimensionEvent(EntityPlayer player, int fromDim, int toDim)
|
||||
{
|
||||
bus().post(new PlayerEvent.PlayerChangedDimensionEvent(player, fromDim, toDim));
|
||||
}
|
||||
|
||||
public void firePlayerLoggedIn(EntityPlayer player)
|
||||
{
|
||||
bus().post(new PlayerEvent.PlayerLoggedInEvent(player));
|
||||
}
|
||||
|
||||
public void firePlayerLoggedOut(EntityPlayer player)
|
||||
{
|
||||
bus().post(new PlayerEvent.PlayerLoggedOutEvent(player));
|
||||
}
|
||||
|
||||
public void firePlayerRespawnEvent(EntityPlayer player, boolean endConquered)
|
||||
{
|
||||
bus().post(new PlayerEvent.PlayerRespawnEvent(player, endConquered));
|
||||
}
|
||||
|
||||
public void firePlayerItemPickupEvent(EntityPlayer player, EntityItem item, ItemStack clone)
|
||||
{
|
||||
bus().post(new PlayerEvent.ItemPickupEvent(player, item, clone));
|
||||
}
|
||||
|
||||
public void firePlayerCraftingEvent(EntityPlayer player, ItemStack crafted, IInventory craftMatrix)
|
||||
{
|
||||
bus().post(new PlayerEvent.ItemCraftedEvent(player, crafted, craftMatrix));
|
||||
}
|
||||
|
||||
public void firePlayerSmeltedEvent(EntityPlayer player, ItemStack smelted)
|
||||
{
|
||||
bus().post(new PlayerEvent.ItemSmeltedEvent(player, smelted));
|
||||
}
|
||||
|
||||
public INetHandler getClientPlayHandler()
|
||||
{
|
||||
return sidedDelegate.getClientPlayHandler();
|
||||
}
|
||||
|
||||
public void fireNetRegistrationEvent(NetworkManager manager, Set<String> channelSet, String channel, Side side)
|
||||
{
|
||||
sidedDelegate.fireNetRegistrationEvent(bus(), manager, channelSet, channel, side);
|
||||
}
|
||||
|
||||
public boolean shouldAllowPlayerLogins()
|
||||
{
|
||||
return sidedDelegate.shouldAllowPlayerLogins();
|
||||
}
|
||||
|
||||
public void fireServerConnectionEvent(NetworkManager manager)
|
||||
{
|
||||
bus().post(new FMLNetworkEvent.ServerConnectionFromClientEvent(manager));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process initial Handshake packet, kicks players from the server if they are connecting while we are starting up.
|
||||
* Also verifies the client has the FML marker.
|
||||
*
|
||||
* @param packet Handshake Packet
|
||||
* @param manager NetworkDirection connection
|
||||
* @return True to allow connection, otherwise False.
|
||||
*/
|
||||
public boolean handleServerHandshake(C00Handshake packet, NetworkManager manager)
|
||||
{
|
||||
if (!shouldAllowPlayerLogins())
|
||||
{
|
||||
TextComponentString text = new TextComponentString("Server is still starting! Please wait before reconnecting.");
|
||||
LOGGER.info("Disconnecting Player: {}", text.getUnformattedText());
|
||||
manager.sendPacket(new SPacketDisconnect(text));
|
||||
manager.closeChannel(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (packet.getRequestedState() == EnumConnectionState.LOGIN && (!NetworkRegistry.INSTANCE.isVanillaAccepted(Side.CLIENT) && !packet.hasFMLMarker()))
|
||||
{
|
||||
manager.setConnectionState(EnumConnectionState.LOGIN);
|
||||
TextComponentString text = new TextComponentString("This server has mods that require FML/Forge to be installed on the client. Contact your server admin for more details.");
|
||||
Collection<String> modNames = NetworkRegistry.INSTANCE.getRequiredMods(Side.CLIENT);
|
||||
FMLLog.log.info("Disconnecting Player: This server has mods that require FML/Forge to be installed on the client: {}", modNames);
|
||||
manager.sendPacket(new SPacketDisconnect(text));
|
||||
manager.closeChannel(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
manager.channel().attr(net.minecraftforge.fml.network.NetworkRegistry.FML_MARKER).set(packet.hasFMLMarker());
|
||||
return true;
|
||||
}
|
||||
|
||||
public void processWindowMessages()
|
||||
{
|
||||
if (sidedDelegate == null) return;
|
||||
sidedDelegate.processWindowMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to exit from java, with system exit preventions in place. Will be tidy about it and just log a message,
|
||||
* unless debugging is enabled
|
||||
*
|
||||
* @param exitCode The exit code
|
||||
* @param hardExit Perform a halt instead of an exit (only use when the world is unsavable) - read the warnings at {@link Runtime#halt(int)}
|
||||
*/
|
||||
public void exitJava(int exitCode, boolean hardExit)
|
||||
{
|
||||
FMLLog.log.warn("Java has been asked to exit (code {})", exitCode);
|
||||
if (hardExit)
|
||||
{
|
||||
FMLLog.log.warn("This is an abortive exit and could cause world corruption or other things");
|
||||
}
|
||||
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
|
||||
FMLLog.log.warn("Exit trace:");
|
||||
//The first 2 elements are Thread#getStackTrace and FMLCommonHandler#exitJava and aren't relevant
|
||||
for (int i = 2; i < stack.length; i++)
|
||||
{
|
||||
FMLLog.log.warn("\t{}", stack[i]);
|
||||
}
|
||||
if (hardExit)
|
||||
{
|
||||
Runtime.getRuntime().halt(exitCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
Runtime.getRuntime().exit(exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
public IThreadListener getWorldThread(INetHandler net)
|
||||
{
|
||||
return sidedDelegate.getWorldThread(net);
|
||||
}
|
||||
|
||||
public static void callFuture(FutureTask<?> task)
|
||||
{
|
||||
try
|
||||
{
|
||||
task.run();
|
||||
task.get(); // Forces the exception to be thrown if any
|
||||
}
|
||||
catch (InterruptedException | ExecutionException e)
|
||||
{
|
||||
FMLLog.log.fatal("Exception caught executing FutureTask: {}", e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public String stripSpecialChars(String message)
|
||||
{
|
||||
return sidedDelegate != null ? sidedDelegate.stripSpecialChars(message) : message;
|
||||
}
|
||||
|
||||
public void reloadRenderers() {
|
||||
sidedDelegate.reloadRenderers();
|
||||
}
|
||||
|
||||
public void fireSidedRegistryEvents()
|
||||
{
|
||||
sidedDelegate.fireSidedRegistryEvents();
|
||||
}
|
||||
|
||||
public CompoundDataFixer getDataFixer()
|
||||
{
|
||||
return (CompoundDataFixer)sidedDelegate.getDataFixer();
|
||||
}
|
||||
|
||||
public boolean isDisplayVSyncForced() { return sidedDelegate.isDisplayVSyncForced(); }
|
||||
public void resetClientRecipeBook() {
|
||||
this.sidedDelegate.resetClientRecipeBook();
|
||||
}
|
||||
|
||||
public void reloadSearchTrees() {
|
||||
this.sidedDelegate.reloadSearchTrees();
|
||||
}
|
||||
|
||||
public void reloadCreativeSettings()
|
||||
{
|
||||
this.sidedDelegate.reloadCreativeSettings();
|
||||
}
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.ThreadContext;
|
||||
|
||||
/**
|
||||
* FMLs logging class. <b>Internal use only, NOT FOR MOD LOGGING!</b> Mods use your own log, see {@link FMLPreInitializationEvent#getModLog()}.
|
||||
* TODO 1.13 remove all the deprecated methods
|
||||
*/
|
||||
public class FMLLog
|
||||
{
|
||||
|
||||
public static final Logger log = LogManager.getLogger("FML");
|
||||
|
||||
public static void bigWarning(String format, Object... data)
|
||||
{
|
||||
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
|
||||
log.warn("****************************************");
|
||||
log.warn("* "+format, data);
|
||||
for (int i = 2; i < 8 && i < trace.length; i++)
|
||||
{
|
||||
log.warn("* at {}{}", trace[i].toString(), i == 7 ? "..." : "");
|
||||
}
|
||||
log.warn("****************************************");
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void log(String targetLog, Level level, String format, Object... data)
|
||||
{
|
||||
FMLRelaunchLog.log(targetLog, level, format, data);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void log(Level level, String format, Object... data)
|
||||
{
|
||||
FMLRelaunchLog.log(level, format, data);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void log(String targetLog, Level level, Throwable ex, String format, Object... data)
|
||||
{
|
||||
FMLRelaunchLog.log(targetLog, level, ex, format, data);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void log(Level level, Throwable ex, String format, Object... data)
|
||||
{
|
||||
FMLRelaunchLog.log(level, ex, format, data);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void severe(String format, Object... data)
|
||||
{
|
||||
log(Level.ERROR, format, data);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void warning(String format, Object... data)
|
||||
{
|
||||
log(Level.WARN, format, data);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void info(String format, Object... data)
|
||||
{
|
||||
log(Level.INFO, format, data);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void fine(String format, Object... data)
|
||||
{
|
||||
log(Level.DEBUG, format, data);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void finer(String format, Object... data)
|
||||
{
|
||||
log(Level.TRACE, format, data);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Logger getLogger()
|
||||
{
|
||||
return log;
|
||||
}
|
||||
}
|
|
@ -21,22 +21,23 @@ package net.minecraftforge.fml.common;
|
|||
|
||||
import cpw.mods.modlauncher.api.IEnvironment;
|
||||
import net.minecraftforge.fml.FileUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
import static net.minecraftforge.fml.Logging.fmlLog;
|
||||
|
||||
public enum FMLPaths
|
||||
{
|
||||
GAMEDIR(),
|
||||
MODSDIR("mods"),
|
||||
CONFIGDIR("config"),
|
||||
FMLCONFIG(false, CONFIGDIR, "fml.cfg");
|
||||
FMLCONFIG(false, CONFIGDIR, "fml.toml");
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final Path relativePath;
|
||||
private final boolean isDirectory;
|
||||
private Path absolutePath;
|
||||
|
@ -71,7 +72,7 @@ public enum FMLPaths
|
|||
for (FMLPaths path : FMLPaths.values())
|
||||
{
|
||||
path.absolutePath = rootPath.resolve(path.relativePath).toAbsolutePath();
|
||||
fmlLog.debug(CORE,"Path {} is {}", ()-> path, ()-> path.absolutePath);
|
||||
LOGGER.debug(CORE,"Path {} is {}", ()-> path, ()-> path.absolutePath);
|
||||
if (path.isDirectory)
|
||||
{
|
||||
FileUtils.getOrCreateDirectory(path.absolutePath, path.name());
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import net.minecraft.command.EntitySelector;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Allows mods to create custom selectors in commands.
|
||||
* Registered in {@link net.minecraftforge.fml.common.registry.GameRegistry#registerEntitySelector(IEntitySelectorFactory, String...)}
|
||||
* For an example implementation, see CustomEntitySelectorTest
|
||||
*/
|
||||
public interface IEntitySelectorFactory
|
||||
{
|
||||
/**
|
||||
* Called every time a command that contains entity selectors is executed
|
||||
*
|
||||
* @param arguments A map with all arguments and their values
|
||||
* @param mainSelector The main selector string (e.g. 'a' for all players or 'e' for all entities)
|
||||
* @param sender The sender of the command
|
||||
* @param position A position either specified in the selector arguments or by the players position. See {@link EntitySelector#getPosFromArguments(Map, Vec3d)}
|
||||
* @return A list of new predicates, can be empty ({@link Collections#emptyList()} but not null.
|
||||
*/
|
||||
@Nonnull List<Predicate<Entity>> createPredicates(Map<String, String> arguments, String mainSelector, ICommandSender sender, Vec3d position);
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.network.INetHandler;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.IThreadListener;
|
||||
import net.minecraftforge.common.util.CompoundDataFixer;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import net.minecraftforge.fml.StartupQuery;
|
||||
|
||||
public interface IFMLSidedHandler
|
||||
{
|
||||
List<String> getAdditionalBrandingInformation();
|
||||
|
||||
Side getSide();
|
||||
|
||||
void haltGame(String message, Throwable exception);
|
||||
|
||||
void showGuiScreen(Object clientGuiElement);
|
||||
|
||||
void queryUser(StartupQuery query) throws InterruptedException;
|
||||
|
||||
void beginServerLoading(MinecraftServer server);
|
||||
|
||||
void finishServerLoading();
|
||||
|
||||
File getSavesDirectory();
|
||||
|
||||
MinecraftServer getServer();
|
||||
|
||||
boolean isDisplayCloseRequested();
|
||||
|
||||
boolean shouldServerShouldBeKilledQuietly();
|
||||
|
||||
void addModAsResource(ModContainer container);
|
||||
|
||||
String getCurrentLanguage();
|
||||
|
||||
void serverStopped();
|
||||
|
||||
NetworkManager getClientToServerNetworkManager();
|
||||
|
||||
INetHandler getClientPlayHandler();
|
||||
|
||||
void fireNetRegistrationEvent(IEventBus bus, NetworkManager manager, Set<String> channelSet, String channel, Side side);
|
||||
|
||||
boolean shouldAllowPlayerLogins();
|
||||
|
||||
void allowLogins();
|
||||
|
||||
IThreadListener getWorldThread(INetHandler net);
|
||||
|
||||
void processWindowMessages();
|
||||
|
||||
String stripSpecialChars(String message);
|
||||
|
||||
void reloadRenderers();
|
||||
|
||||
void fireSidedRegistryEvents();
|
||||
|
||||
CompoundDataFixer getDataFixer();
|
||||
|
||||
boolean isDisplayVSyncForced();
|
||||
|
||||
default void resetClientRecipeBook(){}
|
||||
|
||||
default void reloadSearchTrees(){}
|
||||
|
||||
default void reloadCreativeSettings(){}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.event.furnace.FurnaceFuelBurnTimeEvent;
|
||||
|
||||
/**
|
||||
* @deprecated set your item's {@link Item#getItemBurnTime(ItemStack)} or subscribe to {@link FurnaceFuelBurnTimeEvent} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface IFuelHandler
|
||||
{
|
||||
int getBurnTime(ItemStack fuel);
|
||||
}
|
|
@ -1,382 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import net.minecraftforge.common.util.TextTable;
|
||||
import net.minecraftforge.fml.common.ProgressManager.ProgressBar;
|
||||
import net.minecraftforge.fml.common.event.ModLifecycleEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLLoadEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLModDisabledEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
import net.minecraftforge.fml.common.versioning.ArtifactVersion;
|
||||
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.ThreadContext;
|
||||
import org.apache.logging.log4j.message.FormattedMessage;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class LoadController
|
||||
{
|
||||
private Loader loader;
|
||||
private EventBus masterChannel;
|
||||
private ImmutableMap<String, EventBus> eventChannels;
|
||||
private LoaderState state;
|
||||
private Multimap<String, ModState> modStates = ArrayListMultimap.create();
|
||||
private List<ModContainer> activeModList = Lists.newArrayList();
|
||||
private ModContainer activeContainer;
|
||||
private BiMap<ModContainer, Object> modObjectList;
|
||||
private ListMultimap<String, ModContainer> packageOwners;
|
||||
|
||||
public LoadController(Loader loader)
|
||||
{
|
||||
this.loader = loader;
|
||||
this.masterChannel = new FMLThrowingEventBus((exception, context) -> {
|
||||
Throwables.throwIfUnchecked(exception);
|
||||
// should not happen, but add some extra context for checked exceptions
|
||||
Method method = context.getSubscriberMethod();
|
||||
String parameterNames = Stream.of(method.getParameterTypes()).map(Class::getName).collect(Collectors.joining(", "));
|
||||
String message = "Exception thrown during LoadController." + method.getName() + '(' + parameterNames + ')';
|
||||
throw new LoaderExceptionModCrash(message, exception);
|
||||
});
|
||||
this.masterChannel.register(this);
|
||||
|
||||
state = LoaderState.NOINIT;
|
||||
packageOwners = ArrayListMultimap.create();
|
||||
|
||||
}
|
||||
|
||||
void disableMod(ModContainer mod)
|
||||
{
|
||||
HashMap<String, EventBus> temporary = Maps.newHashMap(eventChannels);
|
||||
String modId = mod.getModId();
|
||||
EventBus bus = temporary.remove(modId);
|
||||
bus.post(new FMLModDisabledEvent());
|
||||
eventChannels = ImmutableMap.copyOf(temporary);
|
||||
modStates.put(modId, ModState.DISABLED);
|
||||
modObjectList.remove(mod);
|
||||
activeModList.remove(mod);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void buildModList(FMLLoadEvent event)
|
||||
{
|
||||
Builder<String, EventBus> eventBus = ImmutableMap.builder();
|
||||
|
||||
for (final ModContainer mod : loader.getModList())
|
||||
{
|
||||
EventBus bus = new FMLThrowingEventBus((exception, context) -> this.errorOccurred(mod, exception));
|
||||
|
||||
boolean isActive = mod.registerBus(bus, this);
|
||||
if (isActive)
|
||||
{
|
||||
activeModList.add(mod);
|
||||
modStates.put(mod.getModId(), ModState.UNLOADED);
|
||||
eventBus.put(mod.getModId(), bus);
|
||||
FMLCommonHandler.instance().addModToResourcePack(mod);
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.log.warn("Mod {} has been disabled through configuration", mod.getModId());
|
||||
modStates.put(mod.getModId(), ModState.UNLOADED);
|
||||
modStates.put(mod.getModId(), ModState.DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
eventChannels = eventBus.build();
|
||||
}
|
||||
|
||||
public void distributeStateMessage(LoaderState state, Object... eventData)
|
||||
{
|
||||
if (state.hasEvent())
|
||||
{
|
||||
masterChannel.post(state.getEvent(eventData));
|
||||
}
|
||||
}
|
||||
|
||||
public void transition(LoaderState desiredState, boolean forceState)
|
||||
{
|
||||
if (FMLCommonHandler.instance().isDisplayCloseRequested())
|
||||
{
|
||||
FMLLog.log.info("The game window is being closed by the player, exiting.");
|
||||
FMLCommonHandler.instance().exitJava(0, false);
|
||||
}
|
||||
|
||||
LoaderState oldState = state;
|
||||
state = state.transition(false);
|
||||
if (state != desiredState)
|
||||
{
|
||||
if (!forceState)
|
||||
{
|
||||
FormattedMessage message = new FormattedMessage("A fatal error occurred during the state transition from {} to {}. State became {} instead. Loading cannot continue.", oldState, desiredState, state);
|
||||
throw new LoaderException(message.getFormattedMessage());
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.log.info("The state engine was in incorrect state {} and forced into state {}. Errors may have been discarded.", state, desiredState);
|
||||
forceState(desiredState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ModContainer activeContainer()
|
||||
{
|
||||
return activeContainer != null ? activeContainer : findActiveContainerFromStack();
|
||||
}
|
||||
|
||||
void forceActiveContainer(@Nullable ModContainer container)
|
||||
{
|
||||
activeContainer = container;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void propogateStateMessage(ModLifecycleEvent stateEvent)
|
||||
{
|
||||
if (stateEvent instanceof FMLPreInitializationEvent)
|
||||
{
|
||||
modObjectList = buildModObjectList();
|
||||
}
|
||||
ProgressBar bar = ProgressManager.push(stateEvent.description(), activeModList.size(), true);
|
||||
for (ModContainer mc : activeModList)
|
||||
{
|
||||
bar.step(mc.getName());
|
||||
sendEventToModContainer(stateEvent, mc);
|
||||
}
|
||||
ProgressManager.pop(bar);
|
||||
}
|
||||
|
||||
private void sendEventToModContainer(ModLifecycleEvent stateEvent, ModContainer mc)
|
||||
{
|
||||
String modId = mc.getModId();
|
||||
Collection<String> requirements = mc.getRequirements().stream().map(ArtifactVersion::getLabel).collect(Collectors.toCollection(HashSet::new));
|
||||
for (ArtifactVersion av : mc.getDependencies())
|
||||
{
|
||||
if (av.getLabel() != null && requirements.contains(av.getLabel()) && modStates.containsEntry(av.getLabel(), ModState.ERRORED))
|
||||
{
|
||||
LogManager.getLogger(modId).error("Skipping event {} and marking errored mod {} since required dependency {} has errored", stateEvent.getEventType(), modId, av.getLabel());
|
||||
modStates.put(modId, ModState.ERRORED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
activeContainer = mc;
|
||||
stateEvent.applyModContainer(mc);
|
||||
ThreadContext.put("mod", modId);
|
||||
LogManager.getLogger(modId).trace("Sending event {} to mod {}", stateEvent.getEventType(), modId);
|
||||
eventChannels.get(modId).post(stateEvent);
|
||||
LogManager.getLogger(modId).trace("Sent event {} to mod {}", stateEvent.getEventType(), modId);
|
||||
ThreadContext.remove("mod");
|
||||
activeContainer = null;
|
||||
if (stateEvent instanceof FMLStateEvent)
|
||||
{
|
||||
if (!errors.containsKey(modId))
|
||||
{
|
||||
modStates.put(modId, ((FMLStateEvent)stateEvent).getModState());
|
||||
}
|
||||
else
|
||||
{
|
||||
modStates.put(modId, ModState.ERRORED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ImmutableBiMap<ModContainer, Object> buildModObjectList()
|
||||
{
|
||||
ImmutableBiMap.Builder<ModContainer, Object> builder = ImmutableBiMap.builder();
|
||||
for (ModContainer mc : activeModList)
|
||||
{
|
||||
if (!mc.isImmutable() && mc.getMod() != null)
|
||||
{
|
||||
builder.put(mc, mc.getMod());
|
||||
List<String> packages = mc.getOwnedPackages();
|
||||
for (String pkg : packages)
|
||||
{
|
||||
packageOwners.put(pkg, mc);
|
||||
}
|
||||
}
|
||||
if (mc.getMod() == null && !mc.isImmutable() && state != LoaderState.CONSTRUCTING)
|
||||
{
|
||||
FormattedMessage message = new FormattedMessage("There is a severe problem with {} ({}) - it appears not to have constructed correctly", mc.getName(), mc.getModId());
|
||||
this.errorOccurred(mc, new RuntimeException(message.getFormattedMessage()));
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public void errorOccurred(ModContainer modContainer, Throwable exception)
|
||||
{
|
||||
String modId = modContainer.getModId();
|
||||
String modName = modContainer.getName();
|
||||
modStates.put(modId, ModState.ERRORED);
|
||||
if (exception instanceof InvocationTargetException)
|
||||
{
|
||||
exception = exception.getCause();
|
||||
}
|
||||
if (exception instanceof LoaderException) // avoid wrapping loader exceptions multiple times
|
||||
{
|
||||
throw (LoaderException) exception;
|
||||
}
|
||||
FormattedMessage message = new FormattedMessage("Caught exception from {} ({})", modName, modId);
|
||||
throw new LoaderExceptionModCrash(message.getFormattedMessage(), exception);
|
||||
}
|
||||
|
||||
public void printModStates(StringBuilder ret)
|
||||
{
|
||||
ret.append("\n\tStates:");
|
||||
for (ModState state : ModState.values())
|
||||
ret.append(" '").append(state.getMarker()).append("' = ").append(state.toString());
|
||||
|
||||
TextTable table = new TextTable(Lists.newArrayList(
|
||||
TextTable.column("State"),
|
||||
TextTable.column("ID"),
|
||||
TextTable.column("Version"),
|
||||
TextTable.column("Source"),
|
||||
TextTable.column("Signature"))
|
||||
);
|
||||
for (ModContainer mc : loader.getModList())
|
||||
{
|
||||
table.add(
|
||||
modStates.get(mc.getModId()).stream().map(ModState::getMarker).reduce("", (a, b) -> a + b),
|
||||
mc.getModId(),
|
||||
mc.getVersion(),
|
||||
mc.getSource().getName(),
|
||||
mc.getSigningCertificate() != null ? CertificateHelper.getFingerprint(mc.getSigningCertificate()) : "None"
|
||||
);
|
||||
}
|
||||
|
||||
ret.append("\n");
|
||||
ret.append("\n\t");
|
||||
table.append(ret, "\n\t");
|
||||
ret.append("\n");
|
||||
}
|
||||
|
||||
public List<ModContainer> getActiveModList()
|
||||
{
|
||||
return activeModList;
|
||||
}
|
||||
|
||||
public ModState getModState(ModContainer selectedMod)
|
||||
{
|
||||
return Iterables.getLast(modStates.get(selectedMod.getModId()), ModState.AVAILABLE);
|
||||
}
|
||||
|
||||
public void distributeStateMessage(Class<?> customEvent)
|
||||
{
|
||||
Object eventInstance;
|
||||
try
|
||||
{
|
||||
eventInstance = customEvent.newInstance();
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
throw new LoaderException("Failed to create new event instance for " + customEvent.getName(), e);
|
||||
}
|
||||
masterChannel.post(eventInstance);
|
||||
}
|
||||
|
||||
public BiMap<ModContainer, Object> getModObjectList()
|
||||
{
|
||||
if (modObjectList == null)
|
||||
{
|
||||
FMLLog.log.fatal("Detected an attempt by a mod {} to perform game activity during mod construction. This is a serious programming error.", activeContainer);
|
||||
return buildModObjectList();
|
||||
}
|
||||
return ImmutableBiMap.copyOf(modObjectList);
|
||||
}
|
||||
|
||||
public boolean isInState(LoaderState state)
|
||||
{
|
||||
return this.state == state;
|
||||
}
|
||||
|
||||
boolean hasReachedState(LoaderState state)
|
||||
{
|
||||
return this.state.ordinal() >= state.ordinal() && this.state != LoaderState.ERRORED;
|
||||
}
|
||||
|
||||
void forceState(LoaderState newState)
|
||||
{
|
||||
this.state = newState;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ModContainer findActiveContainerFromStack()
|
||||
{
|
||||
for (Class<?> c : getCallingStack())
|
||||
{
|
||||
int idx = c.getName().lastIndexOf('.');
|
||||
if (idx == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
String pkg = c.getName().substring(0, idx);
|
||||
if (packageOwners.containsKey(pkg))
|
||||
{
|
||||
return packageOwners.get(pkg).get(0);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private FMLSecurityManager accessibleManager = new FMLSecurityManager();
|
||||
|
||||
class FMLSecurityManager extends SecurityManager
|
||||
{
|
||||
Class<?>[] getStackClasses()
|
||||
{
|
||||
return getClassContext();
|
||||
}
|
||||
}
|
||||
|
||||
Class<?>[] getCallingStack()
|
||||
{
|
||||
return accessibleManager.getStackClasses();
|
||||
}
|
||||
|
||||
LoaderState getState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraftforge.fml.common.versioning.ArtifactVersion;
|
||||
import net.minecraftforge.fml.common.versioning.VersionParser;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class MetadataCollection
|
||||
{
|
||||
private String modListVersion;
|
||||
private ModMetadata[] modList;
|
||||
private Map<String, ModMetadata> metadatas = Maps.newHashMap();
|
||||
|
||||
public static MetadataCollection from(@Nullable InputStream inputStream, String sourceName)
|
||||
{
|
||||
if (inputStream == null)
|
||||
{
|
||||
return new MetadataCollection();
|
||||
}
|
||||
|
||||
InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
|
||||
try
|
||||
{
|
||||
MetadataCollection collection;
|
||||
Gson gson = new GsonBuilder().registerTypeAdapter(ArtifactVersion.class, new ArtifactVersionAdapter()).create();
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonElement rootElement = parser.parse(reader);
|
||||
if (rootElement.isJsonArray())
|
||||
{
|
||||
collection = new MetadataCollection();
|
||||
JsonArray jsonList = rootElement.getAsJsonArray();
|
||||
collection.modList = new ModMetadata[jsonList.size()];
|
||||
int i = 0;
|
||||
for (JsonElement mod : jsonList)
|
||||
{
|
||||
collection.modList[i++]=gson.fromJson(mod, ModMetadata.class);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
collection = gson.fromJson(rootElement, MetadataCollection.class);
|
||||
}
|
||||
collection.parseModMetadataList();
|
||||
return collection;
|
||||
}
|
||||
catch (JsonParseException e)
|
||||
{
|
||||
FMLLog.log.error("The mcmod.info file in {} cannot be parsed as valid JSON. It will be ignored", sourceName, e);
|
||||
return new MetadataCollection();
|
||||
}
|
||||
}
|
||||
|
||||
private void parseModMetadataList()
|
||||
{
|
||||
for (ModMetadata modMetadata : modList)
|
||||
{
|
||||
metadatas.put(modMetadata.modId, modMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
public ModMetadata getMetadataForId(String modId, Map<String, Object> extraData)
|
||||
{
|
||||
if (!metadatas.containsKey(modId))
|
||||
{
|
||||
ModMetadata dummy = new ModMetadata();
|
||||
dummy.modId = modId;
|
||||
dummy.name = (String) extraData.get("name");
|
||||
dummy.version = (String) extraData.get("version");
|
||||
dummy.autogenerated = true;
|
||||
metadatas.put(modId, dummy);
|
||||
}
|
||||
return metadatas.get(modId);
|
||||
}
|
||||
|
||||
public static class ArtifactVersionAdapter extends TypeAdapter<ArtifactVersion>
|
||||
{
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter out, ArtifactVersion value) throws IOException
|
||||
{
|
||||
// no op - we never write these out
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArtifactVersion read(JsonReader in) throws IOException
|
||||
{
|
||||
return VersionParser.parseVersionReference(in.nextString());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraftforge.fml.client.GuiModsMissing;
|
||||
import net.minecraftforge.fml.client.IDisplayableError;
|
||||
import net.minecraftforge.fml.common.versioning.ArtifactVersion;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class MissingModsException extends EnhancedRuntimeException implements IDisplayableError
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final String id;
|
||||
private final String name;
|
||||
/** @deprecated use {@link #getMissingModInfos()} */
|
||||
@Deprecated // TODO remove in 1.13
|
||||
public final Set<ArtifactVersion> missingMods;
|
||||
private final List<MissingModInfo> missingModsInfos;
|
||||
private final String modName;
|
||||
|
||||
public MissingModsException(String id, String name)
|
||||
{
|
||||
this(new HashSet<>(), id, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #MissingModsException(String, String)}
|
||||
*/
|
||||
@Deprecated // TODO remove in 1.13
|
||||
public MissingModsException(Set<ArtifactVersion> missingMods, String id, String name)
|
||||
{
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.missingMods = missingMods;
|
||||
this.missingModsInfos = new ArrayList<>();
|
||||
for (ArtifactVersion artifactVersion : missingMods)
|
||||
{
|
||||
missingModsInfos.add(new MissingModInfo(artifactVersion, null, true));
|
||||
}
|
||||
this.modName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
Set<ArtifactVersion> missingMods = missingModsInfos.stream().map(MissingModInfo::getAcceptedVersion).collect(Collectors.toSet());
|
||||
return String.format("Mod %s (%s) requires %s", id, name, missingMods);
|
||||
}
|
||||
|
||||
public void addMissingMod(ArtifactVersion acceptedVersion, @Nullable ArtifactVersion currentVersion, boolean required)
|
||||
{
|
||||
MissingModInfo missingModInfo = new MissingModInfo(acceptedVersion, currentVersion, required);
|
||||
this.missingModsInfos.add(missingModInfo);
|
||||
this.missingMods.add(acceptedVersion);
|
||||
}
|
||||
|
||||
public String getModName()
|
||||
{
|
||||
return modName;
|
||||
}
|
||||
|
||||
public List<MissingModInfo> getMissingModInfos()
|
||||
{
|
||||
return Collections.unmodifiableList(this.missingModsInfos);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void printStackTrace(WrappedPrintStream stream)
|
||||
{
|
||||
stream.println("Missing Mods:");
|
||||
for (MissingModInfo info : this.missingModsInfos)
|
||||
{
|
||||
ArtifactVersion acceptedVersion = info.getAcceptedVersion();
|
||||
ArtifactVersion currentVersion = info.getCurrentVersion();
|
||||
String currentString = currentVersion != null ? currentVersion.getVersionString() : "missing";
|
||||
stream.println(String.format("\t%s : need %s: have %s", acceptedVersion.getVersionString(), acceptedVersion.getRangeString(), currentString));
|
||||
}
|
||||
stream.println("");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public GuiScreen createGui()
|
||||
{
|
||||
return new GuiModsMissing(this);
|
||||
}
|
||||
|
||||
public static class MissingModInfo
|
||||
{
|
||||
private final ArtifactVersion acceptedVersion;
|
||||
@Nullable
|
||||
private final ArtifactVersion currentVersion;
|
||||
private final boolean required;
|
||||
|
||||
private MissingModInfo(ArtifactVersion acceptedVersion, @Nullable ArtifactVersion currentVersion, boolean required)
|
||||
{
|
||||
Preconditions.checkNotNull(acceptedVersion, "acceptedVersion");
|
||||
this.acceptedVersion = acceptedVersion;
|
||||
this.currentVersion = currentVersion;
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ArtifactVersion getCurrentVersion()
|
||||
{
|
||||
return currentVersion;
|
||||
}
|
||||
|
||||
public ArtifactVersion getAcceptedVersion()
|
||||
{
|
||||
return acceptedVersion;
|
||||
}
|
||||
|
||||
public boolean isRequired()
|
||||
{
|
||||
return required;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,187 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* A simple delegating class loader used to load mods into the system
|
||||
*
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class ModClassLoader extends URLClassLoader
|
||||
{
|
||||
private static final List<String> STANDARD_LIBRARIES = ImmutableList.of("jinput.jar", "lwjgl.jar", "lwjgl_util.jar", "rt.jar");
|
||||
private LaunchClassLoader mainClassLoader;
|
||||
private List<File> sources;
|
||||
|
||||
public ModClassLoader(ClassLoader parent) {
|
||||
super(new URL[0], null);
|
||||
if (parent instanceof LaunchClassLoader)
|
||||
{
|
||||
this.mainClassLoader = (LaunchClassLoader)parent;
|
||||
}
|
||||
this.sources = Lists.newArrayList();
|
||||
}
|
||||
|
||||
public void addFile(File modFile) throws MalformedURLException
|
||||
{
|
||||
URL url = modFile.toURI().toURL();
|
||||
mainClassLoader.addURL(url);
|
||||
this.sources.add(modFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
return mainClassLoader.loadClass(name);
|
||||
}
|
||||
|
||||
public File[] getParentSources() {
|
||||
try
|
||||
{
|
||||
List<File> files=new ArrayList<File>();
|
||||
for(URL url : mainClassLoader.getSources())
|
||||
{
|
||||
URI uri = url.toURI();
|
||||
if(uri.getScheme().equals("file"))
|
||||
{
|
||||
files.add(new File(uri));
|
||||
}
|
||||
}
|
||||
return files.toArray(new File[]{});
|
||||
}
|
||||
catch (URISyntaxException e)
|
||||
{
|
||||
FMLLog.log.error("Unable to process our input to locate the minecraft code", e);
|
||||
throw new LoaderException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getDefaultLibraries()
|
||||
{
|
||||
return STANDARD_LIBRARIES;
|
||||
}
|
||||
|
||||
public boolean isDefaultLibrary(File file)
|
||||
{
|
||||
String home = System.getProperty("java.home"); // Nullcheck just in case some JVM decides to be stupid
|
||||
if (home != null && file.getAbsolutePath().startsWith(home)) return true;
|
||||
// Should really pull this from the json somehow, but we dont have that at runtime.
|
||||
String name = file.getName();
|
||||
if (!name.endsWith(".jar")) return false;
|
||||
String[] prefixes =
|
||||
{
|
||||
"launchwrapper-",
|
||||
"asm-all-",
|
||||
"akka-actor_2.11-",
|
||||
"config-",
|
||||
"scala-",
|
||||
"jopt-simple-",
|
||||
"lzma-",
|
||||
"realms-",
|
||||
"httpclient-",
|
||||
"httpcore-",
|
||||
"vecmath-",
|
||||
"trove4j-",
|
||||
"icu4j-core-mojang-",
|
||||
"codecjorbis-",
|
||||
"codecwav-",
|
||||
"libraryjavawound-",
|
||||
"librarylwjglopenal-",
|
||||
"soundsystem-",
|
||||
"netty-all-",
|
||||
"guava-",
|
||||
"commons-lang3-",
|
||||
"commons-compress-",
|
||||
"commons-logging-",
|
||||
"commons-io-",
|
||||
"commons-codec-",
|
||||
"jinput-",
|
||||
"jutils-",
|
||||
"gson-",
|
||||
"authlib-",
|
||||
"log4j-api-",
|
||||
"log4j-core-",
|
||||
"lwjgl-",
|
||||
"lwjgl_util-",
|
||||
"twitch-",
|
||||
"jline-",
|
||||
"jna-",
|
||||
"platform-",
|
||||
"oshi-core-",
|
||||
"netty-",
|
||||
"libraryjavasound-",
|
||||
"fastutil-"
|
||||
};
|
||||
for (String s : prefixes)
|
||||
{
|
||||
if (name.startsWith(s)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void clearNegativeCacheFor(Set<String> classList)
|
||||
{
|
||||
mainClassLoader.clearNegativeEntries(classList);
|
||||
}
|
||||
|
||||
public ModAPITransformer addModAPITransformer(ASMDataTable dataTable)
|
||||
{
|
||||
mainClassLoader.registerTransformer("net.minecraftforge.fml.common.asm.transformers.ModAPITransformer");
|
||||
List<IClassTransformer> transformers = mainClassLoader.getTransformers();
|
||||
ModAPITransformer modAPI = (ModAPITransformer) transformers.get(transformers.size()-1);
|
||||
modAPI.initTable(dataTable);
|
||||
return modAPI;
|
||||
}
|
||||
|
||||
List<URL> parentURLs = null;
|
||||
public boolean containsSource(File source)
|
||||
{
|
||||
if (parentURLs == null) {
|
||||
parentURLs = Arrays.asList(mainClassLoader.getURLs());
|
||||
}
|
||||
try
|
||||
{
|
||||
return parentURLs.contains(source.toURI().toURL());
|
||||
} catch (MalformedURLException e)
|
||||
{
|
||||
// shouldn't happen
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Classes annotated with this will have the named interface or method removed from the runtime definition of the class
|
||||
* if the modid specified is missing.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public final class Optional {
|
||||
/**
|
||||
* Not constructable
|
||||
*/
|
||||
private Optional() {}
|
||||
|
||||
/**
|
||||
* Mark a list of interfaces as removable
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface InterfaceList {
|
||||
/**
|
||||
* Mark a list of interfaces for optional removal.
|
||||
* @return
|
||||
*/
|
||||
Interface[] value();
|
||||
}
|
||||
/**
|
||||
* Used to remove optional interfaces
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Repeatable(InterfaceList.class)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface Interface {
|
||||
/**
|
||||
* The fully qualified name of the interface to be stripped
|
||||
* @return the interface name
|
||||
*/
|
||||
String iface();
|
||||
|
||||
/**
|
||||
* The modid that is required to be present for stripping NOT to occur
|
||||
* @return the modid
|
||||
*/
|
||||
String modid();
|
||||
|
||||
/**
|
||||
* Strip references to this interface in method declarations? (Useful to kill synthetic methods from scala f.e.)
|
||||
*
|
||||
* @return if references should be stripped
|
||||
*/
|
||||
boolean striprefs() default false;
|
||||
}
|
||||
/**
|
||||
* Used to remove optional methods
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Method {
|
||||
/**
|
||||
* The modid that is required to be present for stripping NOT to occur
|
||||
* @return the modid
|
||||
*/
|
||||
String modid();
|
||||
}
|
||||
}
|
|
@ -26,14 +26,12 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.SidedExecutor;
|
||||
import net.minecraftforge.fml.SidedProvider;
|
||||
import net.minecraftforge.fml.client.SplashProgress;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.message.MessageFormatMessage;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.SPLASH;
|
||||
import static net.minecraftforge.fml.Logging.fmlLog;
|
||||
|
||||
/**
|
||||
* Not a fully fleshed out API, may change in future MC versions.
|
||||
|
@ -41,7 +39,9 @@ import static net.minecraftforge.fml.Logging.fmlLog;
|
|||
*/
|
||||
public class ProgressManager
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final List<ProgressBar> bars = new CopyOnWriteArrayList<ProgressBar>();
|
||||
|
||||
/**
|
||||
* Not a fully fleshed out API, may change in future MC versions.
|
||||
* However feel free to use and suggest additions.
|
||||
|
@ -62,13 +62,10 @@ public class ProgressManager
|
|||
{
|
||||
bar.timeEachStep();
|
||||
}
|
||||
SidedExecutor.runOn(Dist.CLIENT, ()->SplashProgress::processMessages);
|
||||
// DistExecutor.runWhenOn(Dist.CLIENT, ()->SplashProgress::processMessages);
|
||||
return bar;
|
||||
}
|
||||
|
||||
public static boolean isDisplayVSyncForced() {
|
||||
return FMLCommonHandler.instance().isDisplayVSyncForced();
|
||||
}
|
||||
/**
|
||||
* Not a fully fleshed out API, may change in future MC versions.
|
||||
* However feel free to use and suggest additions.
|
||||
|
@ -81,13 +78,13 @@ public class ProgressManager
|
|||
{
|
||||
long newTime = System.nanoTime();
|
||||
if (bar.timeEachStep)
|
||||
fmlLog.debug(SPLASH, () -> new MessageFormatMessage("Bar Step: {0} - {1} took {2,number,0.000}ms", bar.getTitle(), bar.getMessage(), (newTime - bar.lastTime) / 1.0e6));
|
||||
LOGGER.debug(SPLASH, () -> new MessageFormatMessage("Bar Step: {0} - {1} took {2,number,0.000}ms", bar.getTitle(), bar.getMessage(), (newTime - bar.lastTime) / 1.0e6));
|
||||
if (bar.getSteps() == 1)
|
||||
fmlLog.debug(SPLASH, () -> new MessageFormatMessage("Bar Finished: {0} - {1} took {2,number,0.000}ms", bar.getTitle(), bar.getMessage(), (newTime - bar.lastTime) / 1.0e6));
|
||||
LOGGER.debug(SPLASH, () -> new MessageFormatMessage("Bar Finished: {0} - {1} took {2,number,0.000}ms", bar.getTitle(), bar.getMessage(), (newTime - bar.lastTime) / 1.0e6));
|
||||
else
|
||||
fmlLog.debug(SPLASH, () -> new MessageFormatMessage("Bar Finished: {0} took {1,number,0.000}ms", bar.getTitle(), (newTime - bar.lastTime) / 1.0e6));
|
||||
LOGGER.debug(SPLASH, () -> new MessageFormatMessage("Bar Finished: {0} took {1,number,0.000}ms", bar.getTitle(), (newTime - bar.lastTime) / 1.0e6));
|
||||
}
|
||||
SidedExecutor.runOn(Dist.CLIENT, ()->SplashProgress::processMessages);
|
||||
// DistExecutor.runWhenOn(Dist.CLIENT, ()->SplashProgress::processMessages);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -121,7 +118,7 @@ public class ProgressManager
|
|||
|
||||
public void step(Class<?> classToName, String... extra)
|
||||
{
|
||||
step(ClassNameUtils.shortName(classToName)+ Arrays.stream(extra).collect(Collectors.joining(" ")));
|
||||
step(ClassNameUtils.shortName(classToName)+ String.join(" ", extra));
|
||||
}
|
||||
|
||||
public void step(String message)
|
||||
|
@ -130,7 +127,7 @@ public class ProgressManager
|
|||
if (timeEachStep && step != 0)
|
||||
{
|
||||
long newTime = System.nanoTime();
|
||||
fmlLog.debug(SPLASH,new MessageFormatMessage("Bar Step: {0} - {1} took {2,number,0.000}ms", getTitle(), getMessage(), (newTime - lastTime) / 1.0e6));
|
||||
LOGGER.debug(SPLASH,new MessageFormatMessage("Bar Step: {0} - {1} took {2,number,0.000}ms", getTitle(), getMessage(), (newTime - lastTime) / 1.0e6));
|
||||
lastTime = newTime;
|
||||
}
|
||||
step += 1;
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* A method annotated with this on the {@link Mod} will be called whenever a local save is listed in
|
||||
* the save games list.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface SaveInspectionHandler
|
||||
{
|
||||
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* PrintStream which redirects it's output to a given logger.
|
||||
*
|
||||
* @author Arkan
|
||||
*/
|
||||
public class TracingPrintStream extends PrintStream {
|
||||
|
||||
private Logger logger;
|
||||
private int BASE_DEPTH = 3;
|
||||
|
||||
public TracingPrintStream(Logger logger, PrintStream original) {
|
||||
super(original);
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(Object o) {
|
||||
logger.info("{}{}", getPrefix(), o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(String s) {
|
||||
logger.info("{}{}", getPrefix(), s);
|
||||
}
|
||||
|
||||
private String getPrefix() {
|
||||
StackTraceElement[] elems = Thread.currentThread().getStackTrace();
|
||||
StackTraceElement elem = elems[BASE_DEPTH]; // The caller is always at BASE_DEPTH, including this call.
|
||||
if (elem.getClassName().startsWith("kotlin.io.")) {
|
||||
elem = elems[BASE_DEPTH + 2]; // Kotlins IoPackage masks origins 2 deeper in the stack.
|
||||
} else if (elem.getClassName().startsWith("java.lang.Throwable")) {
|
||||
elem = elems[BASE_DEPTH + 4];
|
||||
}
|
||||
return "[" + elem.getClassName() + ":" + elem.getMethodName() + ":" + elem.getLineNumber() + "]: ";
|
||||
}
|
||||
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common;
|
||||
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraftforge.fml.client.GuiWrongMinecraft;
|
||||
import net.minecraftforge.fml.client.IDisplayableError;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
|
||||
public class WrongMinecraftVersionException extends EnhancedRuntimeException implements IDisplayableError
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
public ModContainer mod;
|
||||
private String mcVersion;
|
||||
|
||||
public WrongMinecraftVersionException(ModContainer mod, String mcver)
|
||||
{
|
||||
super(String.format("Wrong Minecraft version for %s", mod.getModId()));
|
||||
this.mod = mod;
|
||||
this.mcVersion = mcver;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void printStackTrace(WrappedPrintStream stream) {
|
||||
stream.println("Wrong Minecraft Versions!");
|
||||
stream.println("Mod: " + mod.getModId());
|
||||
stream.println("Location: " + mod.getSource().toString());
|
||||
stream.println("Expected: " + mod.acceptableMinecraftVersionRange().toString());
|
||||
stream.println("Current: " + mcVersion);
|
||||
stream.println("");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public GuiScreen createGui()
|
||||
{
|
||||
return new GuiWrongMinecraft(this);
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.apache.logging.log4j.Level;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
|
||||
/**
|
||||
* Copied from http://stackoverflow.com/questions/1399126/java-util-zip-recreating-directory-structure
|
||||
* because the code looked very tidy and neat. Thanks, McDowell!
|
||||
*
|
||||
* @author McDowell
|
||||
*
|
||||
*/
|
||||
public class ZipperUtil {
|
||||
public static void zip(File directory, File zipfile) throws IOException
|
||||
{
|
||||
URI base = directory.toURI();
|
||||
Deque<File> queue = new LinkedList<File>();
|
||||
queue.push(directory);
|
||||
OutputStream out = new FileOutputStream(zipfile);
|
||||
Closeable res = null;
|
||||
try
|
||||
{
|
||||
ZipOutputStream zout = new ZipOutputStream(out);
|
||||
res = zout;
|
||||
while (!queue.isEmpty())
|
||||
{
|
||||
directory = queue.pop();
|
||||
for (File kid : directory.listFiles())
|
||||
{
|
||||
String name = base.relativize(kid.toURI()).getPath();
|
||||
if (kid.isDirectory())
|
||||
{
|
||||
queue.push(kid);
|
||||
name = name.endsWith("/") ? name : name + "/";
|
||||
zout.putNextEntry(new ZipEntry(name));
|
||||
} else
|
||||
{
|
||||
zout.putNextEntry(new ZipEntry(name));
|
||||
Files.copy(kid, zout);
|
||||
zout.closeEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally
|
||||
{
|
||||
res.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void backupWorld() throws IOException
|
||||
{
|
||||
String dirName = FMLCommonHandler.instance().getMinecraftServerInstance().getFolderName();
|
||||
|
||||
backupWorld(dirName);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void backupWorld(String dirName, String saveName) throws IOException
|
||||
{
|
||||
backupWorld(dirName);
|
||||
}
|
||||
|
||||
public static void backupWorld(String dirName) throws IOException
|
||||
{
|
||||
File dstFolder = FMLCommonHandler.instance().getSavesDirectory();
|
||||
File zip = new File(dstFolder, String.format("%s-%2$tY%2$tm%2$td-%2$tH%2$tM%2$tS.zip", dirName, System.currentTimeMillis()));
|
||||
|
||||
try
|
||||
{
|
||||
ZipperUtil.zip(new File(dstFolder, dirName), zip);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
FMLLog.log.warn("World backup failed.", e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
FMLLog.log.info("World backup created at {}.", zip.getCanonicalPath());
|
||||
}
|
||||
}
|
|
@ -1,284 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.asm;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.security.Permission;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.GeneratorAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ASMTransformerWrapper
|
||||
{
|
||||
private static final Map<String, String> wrapperModMap = Maps.newHashMap();
|
||||
private static final Map<String, String> wrapperParentMap = Maps.newHashMap();
|
||||
|
||||
private static final LoadingCache<String, byte[]> wrapperCache = CacheBuilder.newBuilder()
|
||||
.maximumSize(30)
|
||||
.weakValues()
|
||||
.build(new CacheLoader<String, byte[]>()
|
||||
{
|
||||
@Override
|
||||
public byte[] load(String file) throws Exception
|
||||
{
|
||||
return makeWrapper(file);
|
||||
}
|
||||
});
|
||||
|
||||
private static final URL asmGenRoot;
|
||||
private static boolean injected = false;
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
asmGenRoot = new URL("asmgen", null, -1, "/", new ASMGenHandler());
|
||||
}
|
||||
catch(MalformedURLException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ASMGenHandler extends URLStreamHandler
|
||||
{
|
||||
@Override
|
||||
@Nullable
|
||||
protected URLConnection openConnection(URL url) throws IOException
|
||||
{
|
||||
String file = url.getFile();
|
||||
if(file.equals("/"))
|
||||
{
|
||||
return new URLConnection(url)
|
||||
{
|
||||
@Override
|
||||
public void connect() throws IOException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
if(!file.startsWith("/")) throw new RuntimeException("Malformed URL: " + url);
|
||||
file = file.substring(1);
|
||||
if(wrapperModMap.containsKey(file))
|
||||
{
|
||||
return new ASMGenConnection(url, file);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ASMGenConnection extends URLConnection
|
||||
{
|
||||
private final String file;
|
||||
|
||||
protected ASMGenConnection(URL url, String file)
|
||||
{
|
||||
super(url);
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() throws IOException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream()
|
||||
{
|
||||
return new ByteArrayInputStream(wrapperCache.getUnchecked(file));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Permission getPermission()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getTransformerWrapper(LaunchClassLoader launchLoader, String parentClass, String coreMod)
|
||||
{
|
||||
if(!injected)
|
||||
{
|
||||
injected = true;
|
||||
launchLoader.addURL(asmGenRoot);
|
||||
}
|
||||
|
||||
String name = getWrapperName(parentClass);
|
||||
String fileName = name.replace('.', '/') + ".class";
|
||||
wrapperModMap.put(fileName, coreMod);
|
||||
wrapperParentMap.put(fileName, parentClass);
|
||||
return name;
|
||||
}
|
||||
|
||||
private static byte[] makeWrapper(String fileName)
|
||||
{
|
||||
if(!wrapperModMap.containsKey(fileName) || !wrapperParentMap.containsKey(fileName) || !fileName.endsWith(".class"))
|
||||
{
|
||||
throw new IllegalArgumentException("makeWrapper called with strange argument: " + fileName);
|
||||
}
|
||||
String name = fileName.substring(0, fileName.length() - ".class".length());
|
||||
|
||||
try
|
||||
{
|
||||
Type wrapper = Type.getType(TransformerWrapper.class);
|
||||
|
||||
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
|
||||
writer.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, name, null, wrapper.getInternalName(), null);
|
||||
|
||||
Method m = Method.getMethod("void <init> ()");
|
||||
GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, m, null, null, writer);
|
||||
mg.loadThis();
|
||||
mg.invokeConstructor(wrapper, m);
|
||||
mg.returnValue();
|
||||
mg.endMethod();
|
||||
|
||||
m = Method.getMethod("java.lang.String getParentClass ()");
|
||||
mg = new GeneratorAdapter(Opcodes.ACC_PROTECTED, m, null, null, writer);
|
||||
mg.push(wrapperParentMap.get(fileName));
|
||||
mg.returnValue();
|
||||
mg.endMethod();
|
||||
|
||||
m = Method.getMethod("java.lang.String getCoreMod ()");
|
||||
mg = new GeneratorAdapter(Opcodes.ACC_PROTECTED, m, null, null, writer);
|
||||
mg.push(wrapperModMap.get(fileName));
|
||||
mg.returnValue();
|
||||
mg.endMethod();
|
||||
|
||||
writer.visitEnd();
|
||||
|
||||
return writer.toByteArray();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getWrapperName(String parentClass)
|
||||
{
|
||||
return "$wrapper." + parentClass;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class WrapperVisitor extends ClassVisitor
|
||||
{
|
||||
private final String name;
|
||||
private final String parentClass;
|
||||
|
||||
public WrapperVisitor(ClassVisitor cv, String name, String parentClass)
|
||||
{
|
||||
super(Opcodes.ASM5, cv);
|
||||
this.name = name.replace('.', '/');
|
||||
this.parentClass = parentClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
|
||||
{
|
||||
super.visit(version, access, this.name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value)
|
||||
{
|
||||
if(name.equals("parentClass"))
|
||||
{
|
||||
return super.visitField(access, name, desc, signature, parentClass);
|
||||
}
|
||||
return super.visitField(access, name, desc, signature, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class TransformerWrapper implements IClassTransformer
|
||||
{
|
||||
private final IClassTransformer parent;
|
||||
|
||||
public TransformerWrapper()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.parent = (IClassTransformer)this.getClass().getClassLoader().loadClass(getParentClass()).newInstance();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(String name, String transformedName, byte[] basicClass)
|
||||
{
|
||||
try
|
||||
{
|
||||
return parent.transform(name, transformedName, basicClass);
|
||||
}
|
||||
catch(Throwable e)
|
||||
{
|
||||
throw new TransformerException("Exception in class transformer " + parent + " from coremod " + getCoreMod(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "TransformerWrapper(" + getParentClass() + ", " + getCoreMod() + ")";
|
||||
}
|
||||
|
||||
protected abstract String getParentClass();
|
||||
|
||||
protected abstract String getCoreMod();
|
||||
}
|
||||
|
||||
static class TransformerException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = -6616232415696157218L;
|
||||
|
||||
public TransformerException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.asm;
|
||||
|
||||
import net.minecraft.launchwrapper.IClassNameTransformer;
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraftforge.fml.common.asm.deobf.FMLDeobfuscatingRemapper;
|
||||
import net.minecraftforge.fml.common.asm.deobf.FMLRemappingAdapter;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.commons.RemappingClassAdapter;
|
||||
|
||||
public class DeobfuscationTransformer implements IClassTransformer, IClassNameTransformer {
|
||||
|
||||
private static final boolean RECALC_FRAMES = Boolean.parseBoolean(System.getProperty("FORGE_FORCE_FRAME_RECALC", "false"));
|
||||
private static final int WRITER_FLAGS = ClassWriter.COMPUTE_MAXS | (RECALC_FRAMES ? ClassWriter.COMPUTE_FRAMES : 0);
|
||||
private static final int READER_FLAGS = RECALC_FRAMES ? ClassReader.SKIP_FRAMES : ClassReader.EXPAND_FRAMES;
|
||||
// COMPUTE_FRAMES causes classes to be loaded, which could cause issues if the classes do not exist.
|
||||
// However in testing this has not happened. {As we run post RuntimeDistCleaner}
|
||||
// If reported we need to add a custom implementation of ClassWriter.getCommonSuperClass
|
||||
// that does not cause class loading.
|
||||
|
||||
@Override
|
||||
public byte[] transform(String name, String transformedName, byte[] bytes)
|
||||
{
|
||||
if (bytes == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
ClassReader classReader = new ClassReader(bytes);
|
||||
ClassWriter classWriter = new ClassWriter(WRITER_FLAGS);
|
||||
RemappingClassAdapter remapAdapter = new FMLRemappingAdapter(classWriter);
|
||||
classReader.accept(remapAdapter, READER_FLAGS);
|
||||
return classWriter.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String remapClassName(String name)
|
||||
{
|
||||
return FMLDeobfuscatingRemapper.INSTANCE.map(name.replace('.','/')).replace('/', '.');
|
||||
}
|
||||
|
||||
@Override
|
||||
public String unmapClassName(String name)
|
||||
{
|
||||
return FMLDeobfuscatingRemapper.INSTANCE.unmap(name.replace('.', '/')).replace('/','.');
|
||||
}
|
||||
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.asm;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.CodeSource;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
import net.minecraftforge.fml.common.CertificateHelper;
|
||||
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||
import net.minecraftforge.fml.common.asm.deobf.FMLDeobfuscatingRemapper;
|
||||
import net.minecraftforge.fml.common.patcher.ClassPatchManager;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
public class FMLSanityChecker implements IFMLCallHook
|
||||
{
|
||||
private static final String FMLFINGERPRINT = "51:0A:FB:4C:AF:A4:A0:F2:F5:CF:C5:0E:B4:CC:3C:30:24:4A:E3:8E".toLowerCase().replace(":", "");
|
||||
private static final String FORGEFINGERPRINT = "E3:C3:D5:0C:7C:98:6D:F7:4C:64:5C:0A:C5:46:39:74:1C:90:A5:57".toLowerCase().replace(":", "");
|
||||
private static final String MCFINGERPRINT = "CD:99:95:96:56:F7:53:DC:28:D8:63:B4:67:69:F7:F8:FB:AE:FC:FC".toLowerCase().replace(":", "");
|
||||
private LaunchClassLoader cl;
|
||||
private boolean liveEnv;
|
||||
public static File fmlLocation;
|
||||
|
||||
@Override
|
||||
public Void call() throws Exception
|
||||
{
|
||||
CodeSource codeSource = getClass().getProtectionDomain().getCodeSource();
|
||||
boolean goodFML = false;
|
||||
boolean fmlIsJar = false;
|
||||
if (codeSource.getLocation().getProtocol().equals("jar"))
|
||||
{
|
||||
fmlIsJar = true;
|
||||
Certificate[] certificates = codeSource.getCertificates();
|
||||
if (certificates!=null)
|
||||
{
|
||||
|
||||
for (Certificate cert : certificates)
|
||||
{
|
||||
String fingerprint = CertificateHelper.getFingerprint(cert);
|
||||
if (fingerprint.equals(FMLFINGERPRINT))
|
||||
{
|
||||
FMLLog.log.info("Found valid fingerprint for FML. Certificate fingerprint {}", fingerprint);
|
||||
goodFML = true;
|
||||
}
|
||||
else if (fingerprint.equals(FORGEFINGERPRINT))
|
||||
{
|
||||
FMLLog.log.info("Found valid fingerprint for Minecraft Forge. Certificate fingerprint {}", fingerprint);
|
||||
goodFML = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.log.error("Found invalid fingerprint for FML: {}", fingerprint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
goodFML = true;
|
||||
}
|
||||
// Server is not signed, so assume it's good - a deobf env is dev time so it's good too
|
||||
boolean goodMC = FMLLaunchHandler.side() == Side.SERVER || !liveEnv;
|
||||
int certCount = 0;
|
||||
try
|
||||
{
|
||||
Class<?> cbr = Class.forName("net.minecraft.client.ClientBrandRetriever",false, cl);
|
||||
codeSource = cbr.getProtectionDomain().getCodeSource();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Probably a development environment, or the server (the server is not signed)
|
||||
goodMC = true;
|
||||
}
|
||||
JarFile mcJarFile = null;
|
||||
if (fmlIsJar && !goodMC && codeSource.getLocation().getProtocol().equals("jar"))
|
||||
{
|
||||
try
|
||||
{
|
||||
String mcPath = codeSource.getLocation().getPath().substring(5);
|
||||
mcPath = mcPath.substring(0, mcPath.lastIndexOf('!'));
|
||||
mcPath = URLDecoder.decode(mcPath, StandardCharsets.UTF_8.name());
|
||||
mcJarFile = new JarFile(mcPath,true);
|
||||
mcJarFile.getManifest();
|
||||
JarEntry cbrEntry = mcJarFile.getJarEntry("net/minecraft/client/ClientBrandRetriever.class");
|
||||
InputStream mcJarFileInputStream = mcJarFile.getInputStream(cbrEntry);
|
||||
try
|
||||
{
|
||||
ByteStreams.toByteArray(mcJarFileInputStream);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly(mcJarFileInputStream);
|
||||
}
|
||||
Certificate[] certificates = cbrEntry.getCertificates();
|
||||
certCount = certificates != null ? certificates.length : 0;
|
||||
if (certificates!=null)
|
||||
{
|
||||
|
||||
for (Certificate cert : certificates)
|
||||
{
|
||||
String fingerprint = CertificateHelper.getFingerprint(cert);
|
||||
if (fingerprint.equals(MCFINGERPRINT))
|
||||
{
|
||||
FMLLog.log.info("Found valid fingerprint for Minecraft. Certificate fingerprint {}", fingerprint);
|
||||
goodMC = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
FMLLog.log.error("A critical error occurred trying to read the minecraft jar file", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly(mcJarFile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
goodMC = true;
|
||||
}
|
||||
if (!goodMC)
|
||||
{
|
||||
FMLLog.log.error("The minecraft jar {} appears to be corrupt! There has been CRITICAL TAMPERING WITH MINECRAFT, it is highly unlikely minecraft will work! STOP NOW, get a clean copy and try again!", codeSource.getLocation().getFile());
|
||||
if (!Boolean.parseBoolean(System.getProperty("fml.ignoreInvalidMinecraftCertificates","false")))
|
||||
{
|
||||
FMLLog.log.error("For your safety, FML will not launch minecraft. You will need to fetch a clean version of the minecraft jar file");
|
||||
FMLLog.log.error("Technical information: The class net.minecraft.client.ClientBrandRetriever should have been associated with the minecraft jar file, " +
|
||||
"and should have returned us a valid, intact minecraft jar location. This did not work. Either you have modified the minecraft jar file (if so " +
|
||||
"run the forge installer again), or you are using a base editing jar that is changing this class (and likely others too). If you REALLY " +
|
||||
"want to run minecraft in this configuration, add the flag -Dfml.ignoreInvalidMinecraftCertificates=true to the 'JVM settings' in your launcher profile.");
|
||||
FMLCommonHandler.instance().exitJava(1, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
FMLLog.log.error("FML has been ordered to ignore the invalid or missing minecraft certificate. This is very likely to cause a problem!");
|
||||
FMLLog.log.error("Technical information: ClientBrandRetriever was at {}, there were {} certificates for it", codeSource.getLocation(), certCount);
|
||||
}
|
||||
}
|
||||
if (!goodFML)
|
||||
{
|
||||
FMLLog.log.error("FML appears to be missing any signature data. This is not a good thing");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectData(Map<String, Object> data)
|
||||
{
|
||||
liveEnv = (Boolean)data.get("runtimeDeobfuscationEnabled");
|
||||
cl = (LaunchClassLoader) data.get("classLoader");
|
||||
File mcDir = (File)data.get("mcLocation");
|
||||
fmlLocation = (File)data.get("coremodLocation");
|
||||
ClassPatchManager.INSTANCE.setup(FMLLaunchHandler.side());
|
||||
FMLDeobfuscatingRemapper.INSTANCE.setup(mcDir, cl, (String) data.get("deobfuscationFileName"));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.asm;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
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.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
public class FieldRedirectTransformer implements IClassTransformer
|
||||
{
|
||||
private final String clsName;
|
||||
private final String TYPE;
|
||||
private final String DESC;
|
||||
private final String bypass;
|
||||
|
||||
protected FieldRedirectTransformer(String cls, String type, String bypass)
|
||||
{
|
||||
this.clsName = cls;
|
||||
this.TYPE = type;
|
||||
this.DESC = "()" + type;
|
||||
this.bypass = bypass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(String name, String transformedName, byte[] basicClass)
|
||||
{
|
||||
if (!this.clsName.equals(transformedName))
|
||||
return basicClass;
|
||||
|
||||
ClassNode classNode = new ClassNode();
|
||||
ClassReader classReader = new ClassReader(basicClass);
|
||||
classReader.accept(classNode, 0);
|
||||
|
||||
FieldNode fieldRef = null;
|
||||
for (FieldNode f : classNode.fields)
|
||||
{
|
||||
if (this.TYPE.equals(f.desc) && fieldRef == null)
|
||||
{
|
||||
fieldRef = f;
|
||||
}
|
||||
else if (this.TYPE.equals(f.desc))
|
||||
{
|
||||
throw new RuntimeException("Error processing " + clsName + " - found a duplicate holder field");
|
||||
}
|
||||
}
|
||||
if (fieldRef == null)
|
||||
{
|
||||
throw new RuntimeException("Error processing " + clsName + " - no holder field declared (is the code somehow obfuscated?)");
|
||||
}
|
||||
|
||||
MethodNode getMethod = null;
|
||||
for (MethodNode m: classNode.methods)
|
||||
{
|
||||
if (m.name.equals(this.bypass)) continue;
|
||||
if (this.DESC.equals(m.desc) && getMethod == null)
|
||||
{
|
||||
getMethod = m;
|
||||
}
|
||||
else if (this.DESC.equals(m.desc))
|
||||
{
|
||||
throw new RuntimeException("Error processing " + clsName + " - duplicate get method found");
|
||||
}
|
||||
}
|
||||
if (getMethod == null)
|
||||
{
|
||||
throw new RuntimeException("Error processing " + clsName + " - no get method found (is the code somehow obfuscated?)");
|
||||
}
|
||||
|
||||
for (MethodNode m: classNode.methods)
|
||||
{
|
||||
if (m.name.equals(this.bypass)) continue;
|
||||
for (ListIterator<AbstractInsnNode> it = m.instructions.iterator(); it.hasNext(); )
|
||||
{
|
||||
AbstractInsnNode insnNode = it.next();
|
||||
if (insnNode.getType() == AbstractInsnNode.FIELD_INSN)
|
||||
{
|
||||
FieldInsnNode fi = (FieldInsnNode)insnNode;
|
||||
if (fieldRef.name.equals(fi.name) && fi.getOpcode() == Opcodes.GETFIELD)
|
||||
{
|
||||
it.remove();
|
||||
MethodInsnNode replace = new MethodInsnNode(Opcodes.INVOKEVIRTUAL, classNode.name, getMethod.name, getMethod.desc, false);
|
||||
it.add(replace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||
classNode.accept(writer);
|
||||
return writer.toByteArray();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.asm;
|
||||
|
||||
public class ItemBlockSpecialTransformer extends FieldRedirectTransformer
|
||||
{
|
||||
public ItemBlockSpecialTransformer()
|
||||
{
|
||||
super("net.minecraft.item.ItemBlockSpecial", "Lnet/minecraft/block/Block;", "getBlockRaw");
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.asm;
|
||||
|
||||
public class ItemBlockTransformer extends FieldRedirectTransformer
|
||||
{
|
||||
public ItemBlockTransformer()
|
||||
{
|
||||
super("net.minecraft.item.ItemBlock", "Lnet/minecraft/block/Block;", "getBlockRaw");
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.asm;
|
||||
|
||||
public class ItemStackTransformer extends FieldRedirectTransformer
|
||||
{
|
||||
public ItemStackTransformer()
|
||||
{
|
||||
super("net.minecraft.item.ItemStack", "Lnet/minecraft/item/Item;", "getItemRaw");
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.asm;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used to force certain classes to reobfuscate
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
public @interface ReobfuscationMarker {
|
||||
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.asm;
|
||||
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import net.minecraftforge.fml.relauncher.FMLSecurityManager.ExitTrappedException;
|
||||
|
||||
public class TerminalTransformer implements IClassTransformer
|
||||
{
|
||||
@Override
|
||||
public byte[] transform(String name, String transformedName, byte[] basicClass)
|
||||
{
|
||||
if (basicClass == null) return null;
|
||||
ClassReader reader = new ClassReader(basicClass);
|
||||
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||
|
||||
ClassVisitor visitor = writer;
|
||||
visitor = new ExitVisitor(visitor);
|
||||
|
||||
reader.accept(visitor, 0);
|
||||
return writer.toByteArray();
|
||||
}
|
||||
|
||||
public static class ExitVisitor extends ClassVisitor
|
||||
{
|
||||
private String clsName = null;
|
||||
private static final String callbackOwner = org.objectweb.asm.Type.getInternalName(ExitVisitor.class);
|
||||
|
||||
private ExitVisitor(ClassVisitor cv)
|
||||
{
|
||||
super(Opcodes.ASM5, cv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
|
||||
{
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
this.clsName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int mAccess, final String mName, final String mDesc, String mSignature, String[] mExceptions)
|
||||
{
|
||||
final boolean warn = !(clsName.equals("net/minecraft/client/Minecraft") ||
|
||||
clsName.equals("net/minecraft/server/dedicated/DedicatedServer") ||
|
||||
clsName.equals("net/minecraft/server/dedicated/ServerHangWatchdog") ||
|
||||
clsName.equals("net/minecraft/server/dedicated/ServerHangWatchdog$1") ||
|
||||
clsName.equals("net/minecraftforge/fml/common/FMLCommonHandler") ||
|
||||
clsName.startsWith("com/jcraft/jogg/") ||
|
||||
clsName.startsWith("scala/sys/") ||
|
||||
clsName.startsWith("net/minecraft/server/gui/MinecraftServerGui") ||
|
||||
clsName.startsWith("com/sun/jna/")
|
||||
);
|
||||
|
||||
return new MethodVisitor(Opcodes.ASM5, super.visitMethod(mAccess, mName, mDesc, mSignature, mExceptions))
|
||||
{
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isIntf)
|
||||
{
|
||||
if (opcode == Opcodes.INVOKESTATIC && owner.equals("java/lang/System") && name.equals("exit") && desc.equals("(I)V"))
|
||||
{
|
||||
if (warn)
|
||||
{
|
||||
FMLLog.log.warn("=============================================================");
|
||||
FMLLog.log.warn("MOD HAS DIRECT REFERENCE System.exit() THIS IS NOT ALLOWED REROUTING TO FML!");
|
||||
FMLLog.log.warn("Offender: {}.{}{}", ExitVisitor.this.clsName, mName, mDesc);
|
||||
FMLLog.log.warn("Use FMLCommonHandler.exitJava instead");
|
||||
FMLLog.log.warn("=============================================================");
|
||||
}
|
||||
owner = ExitVisitor.callbackOwner;
|
||||
name = "systemExitCalled";
|
||||
}
|
||||
else if (opcode == Opcodes.INVOKEVIRTUAL && owner.equals("java/lang/Runtime") && name.equals("exit") && desc.equals("(I)V"))
|
||||
{
|
||||
if (warn)
|
||||
{
|
||||
FMLLog.log.warn("=============================================================");
|
||||
FMLLog.log.warn("MOD HAS DIRECT REFERENCE Runtime.exit() THIS IS NOT ALLOWED REROUTING TO FML!");
|
||||
FMLLog.log.warn("Offender: {}.{}{}", ExitVisitor.this.clsName, mName, mDesc);
|
||||
FMLLog.log.warn("Use FMLCommonHandler.exitJava instead");
|
||||
FMLLog.log.warn("=============================================================");
|
||||
}
|
||||
opcode = Opcodes.INVOKESTATIC;
|
||||
owner = ExitVisitor.callbackOwner;
|
||||
name = "runtimeExitCalled";
|
||||
desc = "(Ljava/lang/Runtime;I)V";
|
||||
}
|
||||
else if (opcode == Opcodes.INVOKEVIRTUAL && owner.equals("java/lang/Runtime") && name.equals("halt") && desc.equals("(I)V"))
|
||||
{
|
||||
if (warn)
|
||||
{
|
||||
FMLLog.log.warn("=============================================================");
|
||||
FMLLog.log.warn("MOD HAS DIRECT REFERENCE Runtime.halt() THIS IS NOT ALLOWED REROUTING TO FML!");
|
||||
FMLLog.log.warn("Offendor: {}.{}{}", ExitVisitor.this.clsName, mName, mDesc);
|
||||
FMLLog.log.warn("Use FMLCommonHandler.exitJava instead");
|
||||
FMLLog.log.warn("=============================================================");
|
||||
}
|
||||
opcode = Opcodes.INVOKESTATIC;
|
||||
owner = ExitVisitor.callbackOwner;
|
||||
name = "runtimeHaltCalled";
|
||||
desc = "(Ljava/lang/Runtime;I)V";
|
||||
}
|
||||
|
||||
super.visitMethodInsn(opcode, owner, name, desc, isIntf);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Intercept System.exit, and check if the caller is allowed to use it, if not wrap it in a ExitTrappedException
|
||||
public static void systemExitCalled(int status)
|
||||
{
|
||||
ExitVisitor.checkAccess();
|
||||
System.exit(status);
|
||||
}
|
||||
// Intercept Runtime.getRuntime().exit, and check if the caller is allowed to use it, if not wrap it in a ExitTrappedException
|
||||
public static void runtimeExitCalled(Runtime runtime, int status)
|
||||
{
|
||||
ExitVisitor.checkAccess();
|
||||
runtime.exit(status);
|
||||
}
|
||||
|
||||
// Intercept Runtime.getRuntime().halt, and check if the caller is allowed to use it, if not wrap it in a ExitTrappedException
|
||||
public static void runtimeHaltCalled(Runtime runtime, int status)
|
||||
{
|
||||
ExitVisitor.checkAccess();
|
||||
runtime.halt(status);
|
||||
}
|
||||
|
||||
private static void checkAccess()
|
||||
{
|
||||
StackTraceElement[] cause = Thread.currentThread().getStackTrace();
|
||||
|
||||
String callingClass = cause.length > 2 ? cause[3].getClassName() : "none";
|
||||
String callingParent = cause.length > 3 ? cause[4].getClassName() : "none";
|
||||
// FML is allowed to call system exit and the Minecraft applet (from the quit button), and the dedicated server (from itself)
|
||||
boolean allowed = false;
|
||||
allowed |= callingClass.startsWith("net.minecraftforge.fml.");
|
||||
allowed |= callingClass.equals("net.minecraft.client.Minecraft") && callingParent.equals("net.minecraft.client.Minecraft");
|
||||
allowed |= callingClass.equals("net.minecraft.server.gui.MinecraftServerGui$1") && callingParent.equals("java.awt.AWTEventMulticaster");
|
||||
allowed |= callingClass.equals("net.minecraft.server.dedicated.DedicatedServer") && callingParent.equals("net.minecraft.server.MinecraftServer");
|
||||
allowed |= callingClass.equals("net.minecraft.server.dedicated.ServerHangWatchdog");
|
||||
allowed |= callingClass.equals("net.minecraft.server.dedicated.ServerHangWatchdog$1");
|
||||
|
||||
if (!allowed)
|
||||
{
|
||||
throw new ExitTrappedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,501 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.asm.deobf;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import net.minecraftforge.fml.common.patcher.ClassPatchManager;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.common.collect.ImmutableBiMap.Builder;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.io.CharSource;
|
||||
import com.google.common.io.Files;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class FMLDeobfuscatingRemapper extends Remapper {
|
||||
public static final FMLDeobfuscatingRemapper INSTANCE = new FMLDeobfuscatingRemapper();
|
||||
|
||||
private BiMap<String, String> classNameBiMap;
|
||||
|
||||
private Map<String,Map<String,String>> rawFieldMaps;
|
||||
private Map<String,Map<String,String>> rawMethodMaps;
|
||||
|
||||
private Map<String,Map<String,String>> fieldNameMaps;
|
||||
private Map<String,Map<String,String>> methodNameMaps;
|
||||
|
||||
private LaunchClassLoader classLoader;
|
||||
|
||||
|
||||
private static final boolean DEBUG_REMAPPING = Boolean.parseBoolean(System.getProperty("fml.remappingDebug", "false"));
|
||||
private static final boolean DUMP_FIELD_MAPS = Boolean.parseBoolean(System.getProperty("fml.remappingDebug.dumpFieldMaps", "false")) && DEBUG_REMAPPING;
|
||||
private static final boolean DUMP_METHOD_MAPS = Boolean.parseBoolean(System.getProperty("fml.remappingDebug.dumpMethodMaps", "false")) && DEBUG_REMAPPING;
|
||||
|
||||
private FMLDeobfuscatingRemapper()
|
||||
{
|
||||
classNameBiMap=ImmutableBiMap.of();
|
||||
}
|
||||
|
||||
public void setupLoadOnly(String deobfFileName, boolean loadAll)
|
||||
{
|
||||
try
|
||||
{
|
||||
File mapData = new File(deobfFileName);
|
||||
LZMAInputSupplier zis = new LZMAInputSupplier(new FileInputStream(mapData));
|
||||
CharSource srgSource = zis.asCharSource(StandardCharsets.UTF_8);
|
||||
List<String> srgList = srgSource.readLines();
|
||||
rawMethodMaps = Maps.newHashMap();
|
||||
rawFieldMaps = Maps.newHashMap();
|
||||
Builder<String, String> builder = ImmutableBiMap.builder();
|
||||
Splitter splitter = Splitter.on(CharMatcher.anyOf(": ")).omitEmptyStrings().trimResults();
|
||||
for (String line : srgList)
|
||||
{
|
||||
String[] parts = Iterables.toArray(splitter.split(line),String.class);
|
||||
String typ = parts[0];
|
||||
if ("CL".equals(typ))
|
||||
{
|
||||
parseClass(builder, parts);
|
||||
}
|
||||
else if ("MD".equals(typ) && loadAll)
|
||||
{
|
||||
parseMethod(parts);
|
||||
}
|
||||
else if ("FD".equals(typ) && loadAll)
|
||||
{
|
||||
parseField(parts);
|
||||
}
|
||||
}
|
||||
classNameBiMap = builder.build();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
FMLLog.log.error("An error occurred loading the deobfuscation map data", ioe);
|
||||
}
|
||||
methodNameMaps = Maps.newHashMapWithExpectedSize(rawMethodMaps.size());
|
||||
fieldNameMaps = Maps.newHashMapWithExpectedSize(rawFieldMaps.size());
|
||||
|
||||
}
|
||||
public void setup(File mcDir, LaunchClassLoader classLoader, String deobfFileName)
|
||||
{
|
||||
this.classLoader = classLoader;
|
||||
try
|
||||
{
|
||||
List<String> srgList;
|
||||
final String gradleStartProp = System.getProperty("net.minecraftforge.gradle.GradleStart.srg.srg-mcp");
|
||||
|
||||
if (Strings.isNullOrEmpty(gradleStartProp))
|
||||
{
|
||||
// get as a resource
|
||||
InputStream classData = getClass().getResourceAsStream(deobfFileName);
|
||||
LZMAInputSupplier zis = new LZMAInputSupplier(classData);
|
||||
CharSource srgSource = zis.asCharSource(StandardCharsets.UTF_8);
|
||||
srgList = srgSource.readLines();
|
||||
FMLLog.log.debug("Loading deobfuscation resource {} with {} records", deobfFileName, srgList.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
srgList = Files.readLines(new File(gradleStartProp), StandardCharsets.UTF_8);
|
||||
FMLLog.log.debug("Loading deobfuscation resource {} with {} records", gradleStartProp, srgList.size());
|
||||
}
|
||||
|
||||
rawMethodMaps = Maps.newHashMap();
|
||||
rawFieldMaps = Maps.newHashMap();
|
||||
Builder<String, String> builder = ImmutableBiMap.builder();
|
||||
Splitter splitter = Splitter.on(CharMatcher.anyOf(": ")).omitEmptyStrings().trimResults();
|
||||
for (String line : srgList)
|
||||
{
|
||||
String[] parts = Iterables.toArray(splitter.split(line),String.class);
|
||||
String typ = parts[0];
|
||||
if ("CL".equals(typ))
|
||||
{
|
||||
parseClass(builder, parts);
|
||||
}
|
||||
else if ("MD".equals(typ))
|
||||
{
|
||||
parseMethod(parts);
|
||||
}
|
||||
else if ("FD".equals(typ))
|
||||
{
|
||||
parseField(parts);
|
||||
}
|
||||
}
|
||||
classNameBiMap = builder.build();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
FMLLog.log.error("An error occurred loading the deobfuscation map data", ioe);
|
||||
}
|
||||
methodNameMaps = Maps.newHashMapWithExpectedSize(rawMethodMaps.size());
|
||||
fieldNameMaps = Maps.newHashMapWithExpectedSize(rawFieldMaps.size());
|
||||
}
|
||||
|
||||
public boolean isRemappedClass(String className)
|
||||
{
|
||||
return !map(className).equals(className);
|
||||
}
|
||||
|
||||
private void parseField(String[] parts)
|
||||
{
|
||||
String oldSrg = parts[1];
|
||||
int lastOld = oldSrg.lastIndexOf('/');
|
||||
String cl = oldSrg.substring(0,lastOld);
|
||||
String oldName = oldSrg.substring(lastOld+1);
|
||||
String newSrg = parts[2];
|
||||
int lastNew = newSrg.lastIndexOf('/');
|
||||
String newName = newSrg.substring(lastNew+1);
|
||||
if (!rawFieldMaps.containsKey(cl))
|
||||
{
|
||||
rawFieldMaps.put(cl, Maps.<String,String>newHashMap());
|
||||
}
|
||||
String fieldType = getFieldType(cl, oldName);
|
||||
// We might be in mcp named land, where in fact the name is "new"
|
||||
if (fieldType == null) fieldType = getFieldType(cl, newName);
|
||||
rawFieldMaps.get(cl).put(oldName + ":" + fieldType, newName);
|
||||
rawFieldMaps.get(cl).put(oldName + ":null", newName);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache the field descriptions for classes so we don't repeatedly reload the same data again and again
|
||||
*/
|
||||
private final Map<String,Map<String,String>> fieldDescriptions = Maps.newHashMap();
|
||||
|
||||
// Cache null values so we don't waste time trying to recompute classes with no field or method maps
|
||||
private Set<String> negativeCacheMethods = Sets.newHashSet();
|
||||
private Set<String> negativeCacheFields = Sets.newHashSet();
|
||||
|
||||
@Nullable
|
||||
private String getFieldType(String owner, String name)
|
||||
{
|
||||
if (fieldDescriptions.containsKey(owner))
|
||||
{
|
||||
return fieldDescriptions.get(owner).get(name);
|
||||
}
|
||||
synchronized (fieldDescriptions)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] classBytes = ClassPatchManager.INSTANCE.getPatchedResource(owner, map(owner).replace('/', '.'), classLoader);
|
||||
if (classBytes == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
ClassReader cr = new ClassReader(classBytes);
|
||||
ClassNode classNode = new ClassNode();
|
||||
cr.accept(classNode, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||
Map<String,String> resMap = Maps.newHashMap();
|
||||
for (FieldNode fieldNode : classNode.fields) {
|
||||
resMap.put(fieldNode.name, fieldNode.desc);
|
||||
}
|
||||
fieldDescriptions.put(owner, resMap);
|
||||
return resMap.get(name);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
FMLLog.log.error("A critical exception occurred reading a class file {}", owner, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void parseClass(Builder<String, String> builder, String[] parts)
|
||||
{
|
||||
builder.put(parts[1],parts[2]);
|
||||
}
|
||||
|
||||
private void parseMethod(String[] parts)
|
||||
{
|
||||
String oldSrg = parts[1];
|
||||
int lastOld = oldSrg.lastIndexOf('/');
|
||||
String cl = oldSrg.substring(0,lastOld);
|
||||
String oldName = oldSrg.substring(lastOld+1);
|
||||
String sig = parts[2];
|
||||
String newSrg = parts[3];
|
||||
int lastNew = newSrg.lastIndexOf('/');
|
||||
String newName = newSrg.substring(lastNew+1);
|
||||
if (!rawMethodMaps.containsKey(cl))
|
||||
{
|
||||
rawMethodMaps.put(cl, Maps.<String,String>newHashMap());
|
||||
}
|
||||
rawMethodMaps.get(cl).put(oldName+sig, newName);
|
||||
}
|
||||
|
||||
String mapMemberFieldName(String owner, String name, String desc)
|
||||
{
|
||||
String remappedName = mapFieldName(owner, name, desc, true);
|
||||
storeMemberFieldMapping(owner, name, desc, remappedName);
|
||||
return remappedName;
|
||||
}
|
||||
|
||||
private void storeMemberFieldMapping(String owner, String name, String desc, String remappedName) {
|
||||
Map<String, String> fieldMap = getRawFieldMap(owner);
|
||||
|
||||
String key = name + ":" + desc;
|
||||
String altKey = name + ":null";
|
||||
|
||||
if (!fieldMap.containsKey(key)) {
|
||||
fieldMap.put(key, remappedName);
|
||||
fieldMap.put(altKey, remappedName);
|
||||
|
||||
// Alternatively, maps could be made mutable and we could just set the relevant entry, saving
|
||||
// the need to regenerate the super map each time
|
||||
fieldNameMaps.remove(owner);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapFieldName(String owner, String name, @Nullable String desc)
|
||||
{
|
||||
return mapFieldName(owner, name, desc, false);
|
||||
}
|
||||
|
||||
String mapFieldName(String owner, String name, @Nullable String desc, boolean raw)
|
||||
{
|
||||
if (classNameBiMap == null || classNameBiMap.isEmpty())
|
||||
{
|
||||
return name;
|
||||
}
|
||||
Map<String, String> fieldMap = getFieldMap(owner, raw);
|
||||
return fieldMap!=null && fieldMap.containsKey(name+":"+desc) ? fieldMap.get(name+":"+desc) : fieldMap!=null && fieldMap.containsKey(name+":null") ? fieldMap.get(name+":null") :name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String map(String typeName)
|
||||
{
|
||||
if (classNameBiMap == null || classNameBiMap.isEmpty())
|
||||
{
|
||||
return typeName;
|
||||
}
|
||||
if (classNameBiMap.containsKey(typeName))
|
||||
{
|
||||
return classNameBiMap.get(typeName);
|
||||
}
|
||||
int dollarIdx = typeName.lastIndexOf('$');
|
||||
if (dollarIdx > -1)
|
||||
{
|
||||
return map(typeName.substring(0, dollarIdx)) + "$" + typeName.substring(dollarIdx + 1);
|
||||
}
|
||||
return typeName;
|
||||
}
|
||||
|
||||
public String unmap(String typeName)
|
||||
{
|
||||
if (classNameBiMap == null || classNameBiMap.isEmpty())
|
||||
{
|
||||
return typeName;
|
||||
}
|
||||
|
||||
if (classNameBiMap.containsValue(typeName))
|
||||
{
|
||||
return classNameBiMap.inverse().get(typeName);
|
||||
}
|
||||
int dollarIdx = typeName.lastIndexOf('$');
|
||||
if (dollarIdx > -1)
|
||||
{
|
||||
return unmap(typeName.substring(0, dollarIdx)) + "$" + typeName.substring(dollarIdx + 1);
|
||||
}
|
||||
return typeName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String mapMethodName(String owner, String name, String desc)
|
||||
{
|
||||
if (classNameBiMap==null || classNameBiMap.isEmpty())
|
||||
{
|
||||
return name;
|
||||
}
|
||||
Map<String, String> methodMap = getMethodMap(owner);
|
||||
String methodDescriptor = name+desc;
|
||||
return methodMap!=null && methodMap.containsKey(methodDescriptor) ? methodMap.get(methodDescriptor) : name;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String mapSignature(String signature, boolean typeSignature)
|
||||
{
|
||||
// JDT decorates some lambdas with this and SignatureReader chokes on it
|
||||
if (signature != null && signature.contains("!*"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return super.mapSignature(signature, typeSignature);
|
||||
}
|
||||
|
||||
private Map<String,String> getRawFieldMap(String className)
|
||||
{
|
||||
if (!rawFieldMaps.containsKey(className))
|
||||
{
|
||||
rawFieldMaps.put(className, Maps.<String,String>newHashMap());
|
||||
}
|
||||
return rawFieldMaps.get(className);
|
||||
}
|
||||
|
||||
private Map<String,String> getFieldMap(String className, boolean raw)
|
||||
{
|
||||
if (raw)
|
||||
{
|
||||
return getRawFieldMap(className);
|
||||
}
|
||||
|
||||
if (!fieldNameMaps.containsKey(className) && !negativeCacheFields.contains(className))
|
||||
{
|
||||
findAndMergeSuperMaps(className);
|
||||
if (!fieldNameMaps.containsKey(className))
|
||||
{
|
||||
negativeCacheFields.add(className);
|
||||
}
|
||||
|
||||
if (DUMP_FIELD_MAPS)
|
||||
{
|
||||
FMLLog.log.trace("Field map for {} : {}", className, fieldNameMaps.get(className));
|
||||
}
|
||||
}
|
||||
return fieldNameMaps.get(className);
|
||||
}
|
||||
|
||||
private Map<String,String> getMethodMap(String className)
|
||||
{
|
||||
if (!methodNameMaps.containsKey(className) && !negativeCacheMethods.contains(className))
|
||||
{
|
||||
findAndMergeSuperMaps(className);
|
||||
if (!methodNameMaps.containsKey(className))
|
||||
{
|
||||
negativeCacheMethods.add(className);
|
||||
}
|
||||
if (DUMP_METHOD_MAPS)
|
||||
{
|
||||
FMLLog.log.trace("Method map for {} : {}", className, methodNameMaps.get(className));
|
||||
}
|
||||
|
||||
}
|
||||
return methodNameMaps.get(className);
|
||||
}
|
||||
|
||||
private void findAndMergeSuperMaps(String name)
|
||||
{
|
||||
try
|
||||
{
|
||||
String superName = null;
|
||||
String[] interfaces = new String[0];
|
||||
byte[] classBytes = ClassPatchManager.INSTANCE.getPatchedResource(name, map(name), classLoader);
|
||||
if (classBytes != null)
|
||||
{
|
||||
ClassReader cr = new ClassReader(classBytes);
|
||||
superName = cr.getSuperName();
|
||||
interfaces = cr.getInterfaces();
|
||||
}
|
||||
mergeSuperMaps(name, superName, interfaces);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
FMLLog.log.error("Error getting patched resource:", e);
|
||||
}
|
||||
}
|
||||
public void mergeSuperMaps(String name, @Nullable String superName, String[] interfaces)
|
||||
{
|
||||
// System.out.printf("Computing super maps for %s: %s %s\n", name, superName, Arrays.asList(interfaces));
|
||||
if (classNameBiMap == null || classNameBiMap.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Skip Object
|
||||
if (Strings.isNullOrEmpty(superName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> allParents = ImmutableList.<String>builder().add(superName).addAll(Arrays.asList(interfaces)).build();
|
||||
// generate maps for all parent objects
|
||||
for (String parentThing : allParents)
|
||||
{
|
||||
if (!fieldNameMaps.containsKey(parentThing))
|
||||
{
|
||||
findAndMergeSuperMaps(parentThing);
|
||||
}
|
||||
}
|
||||
Map<String, String> methodMap = Maps.newHashMap();
|
||||
Map<String, String> fieldMap = Maps.newHashMap();
|
||||
for (String parentThing : allParents)
|
||||
{
|
||||
if (methodNameMaps.containsKey(parentThing))
|
||||
{
|
||||
methodMap.putAll(methodNameMaps.get(parentThing));
|
||||
}
|
||||
if (fieldNameMaps.containsKey(parentThing))
|
||||
{
|
||||
fieldMap.putAll(fieldNameMaps.get(parentThing));
|
||||
}
|
||||
}
|
||||
if (rawMethodMaps.containsKey(name))
|
||||
{
|
||||
methodMap.putAll(rawMethodMaps.get(name));
|
||||
}
|
||||
if (rawFieldMaps.containsKey(name))
|
||||
{
|
||||
fieldMap.putAll(rawFieldMaps.get(name));
|
||||
}
|
||||
methodNameMaps.put(name, ImmutableMap.copyOf(methodMap));
|
||||
fieldNameMaps.put(name, ImmutableMap.copyOf(fieldMap));
|
||||
// System.out.printf("Maps: %s %s\n", name, methodMap);
|
||||
}
|
||||
|
||||
public Set<String> getObfedClasses()
|
||||
{
|
||||
return ImmutableSet.copyOf(classNameBiMap.keySet());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getStaticFieldType(String oldType, String oldName, String newType, String newName)
|
||||
{
|
||||
String fType = getFieldType(newType, newName);
|
||||
if (oldType.equals(newType))
|
||||
{
|
||||
return fType;
|
||||
}
|
||||
Map<String, String> newClassMap = fieldDescriptions.computeIfAbsent(newType, k -> Maps.newHashMap());
|
||||
newClassMap.put(newName, fType);
|
||||
return fType;
|
||||
}
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.asm.deobf;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
import org.objectweb.asm.commons.RemappingClassAdapter;
|
||||
import org.objectweb.asm.commons.RemappingMethodAdapter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class FMLRemappingAdapter extends RemappingClassAdapter {
|
||||
public FMLRemappingAdapter(ClassVisitor cv)
|
||||
{
|
||||
super(cv, FMLDeobfuscatingRemapper.INSTANCE);
|
||||
}
|
||||
|
||||
private static final List<Handle> META_FACTORIES = Arrays.asList(
|
||||
new Handle(Opcodes.H_INVOKESTATIC, "java/lang/invoke/LambdaMetafactory", "metafactory",
|
||||
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;",
|
||||
false),
|
||||
new Handle(Opcodes.H_INVOKESTATIC, "java/lang/invoke/LambdaMetafactory", "altMetafactory",
|
||||
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;",
|
||||
false)
|
||||
);
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
|
||||
{
|
||||
if (interfaces == null)
|
||||
{
|
||||
interfaces = new String[0];
|
||||
}
|
||||
FMLDeobfuscatingRemapper.INSTANCE.mergeSuperMaps(name, superName, interfaces);
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
|
||||
FMLDeobfuscatingRemapper remapper = FMLDeobfuscatingRemapper.INSTANCE;
|
||||
FieldVisitor fv = cv.visitField(access,
|
||||
remapper.mapMemberFieldName(className, name, desc),
|
||||
remapper.mapDesc(desc), remapper.mapSignature(signature, true),
|
||||
remapper.mapValue(value));
|
||||
return createRemappingFieldAdapter(fv);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MethodVisitor createRemappingMethodAdapter(int access, String newDesc, MethodVisitor mv)
|
||||
{
|
||||
return new StaticFixingMethodVisitor(access, newDesc, mv, remapper);
|
||||
}
|
||||
|
||||
private static class StaticFixingMethodVisitor extends RemappingMethodAdapter
|
||||
{
|
||||
|
||||
public StaticFixingMethodVisitor(int access, String desc, MethodVisitor mv, Remapper remapper)
|
||||
{
|
||||
super(access, desc, mv, remapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(int opcode, String originalType, String originalName, String desc)
|
||||
{
|
||||
// This method solves the problem of a static field reference changing type. In all probability it is a
|
||||
// compatible change, however we need to fix up the desc to point at the new type
|
||||
String type = remapper.mapType(originalType);
|
||||
String fieldName = remapper.mapFieldName(originalType, originalName, desc);
|
||||
String newDesc = remapper.mapDesc(desc);
|
||||
if (opcode == Opcodes.GETSTATIC && type.startsWith("net/minecraft/") && newDesc.startsWith("Lnet/minecraft/"))
|
||||
{
|
||||
String replDesc = FMLDeobfuscatingRemapper.INSTANCE.getStaticFieldType(originalType, originalName, type, fieldName);
|
||||
if (replDesc != null)
|
||||
{
|
||||
newDesc = remapper.mapDesc(replDesc);
|
||||
}
|
||||
}
|
||||
// super.super
|
||||
if (mv != null) {
|
||||
mv.visitFieldInsn(opcode, type, fieldName, newDesc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs)
|
||||
{
|
||||
// Special case lambda metaFactory to get new name
|
||||
if (META_FACTORIES.contains(bsm))
|
||||
{
|
||||
String owner = Type.getReturnType(desc).getInternalName();
|
||||
String odesc = ((Type) bsmArgs[0]).getDescriptor(); // First constant argument is "samMethodType - Signature and return type of method to be implemented by the function object."
|
||||
name = remapper.mapMethodName(owner, name, odesc);
|
||||
}
|
||||
|
||||
super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.asm.deobf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import LZMA.LzmaInputStream;
|
||||
|
||||
import com.google.common.io.ByteSource;
|
||||
|
||||
public class LZMAInputSupplier extends ByteSource {
|
||||
private InputStream compressedData;
|
||||
|
||||
public LZMAInputSupplier(InputStream compressedData)
|
||||
{
|
||||
this.compressedData = compressedData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openStream() throws IOException
|
||||
{
|
||||
return new LzmaInputStream(this.compressedData);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,192 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.discovery.json;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModAnnotation.EnumHolder;
|
||||
|
||||
//Package private, modders shouldn't access this. Do it through ASMDataTable.
|
||||
class ASMInfo
|
||||
{
|
||||
String name;
|
||||
String[] interfaces;
|
||||
List<Annotation> annotations;
|
||||
private Map<Integer, Annotation> byID;
|
||||
|
||||
public Annotation getSubAnnotation(int id)
|
||||
{
|
||||
if (byID == null)
|
||||
{
|
||||
byID = Maps.newHashMap();
|
||||
annotations.forEach(a -> { if (a.id != null) byID.put(a.id, a); });
|
||||
}
|
||||
return byID.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return MoreObjects.toStringHelper("")
|
||||
.add("name", name)
|
||||
.add("itf", interfaces)
|
||||
.add("ann", annotations)
|
||||
.toString();
|
||||
}
|
||||
|
||||
public enum TargetType { CLASS, FIELD, METHOD, SUBTYPE };
|
||||
public enum ValueType
|
||||
{
|
||||
BOOL(Boolean::valueOf, v -> {boolean[] ret = new boolean[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Boolean.parseBoolean(v[x]); return ret; }),
|
||||
BYTE(Byte::valueOf, v -> {byte[] ret = new byte[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Byte.parseByte(v[x]); return ret; }),
|
||||
CHAR(x -> x.charAt(0), v -> {char[] ret = new char[v.length]; for (int x = 0; x < v.length; x++) ret[x] = v[x].charAt(0); return ret; }),
|
||||
SHORT(Short::valueOf, v -> {short[] ret = new short[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Short.parseShort(v[x]); return ret; }),
|
||||
INT(Integer::valueOf, v -> {int[] ret = new int[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Integer.parseInt(v[x]); return ret; }),
|
||||
LONG(Long::valueOf, v -> {long[] ret = new long[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Long.parseLong(v[x]); return ret; }),
|
||||
FLOAT(Float::valueOf, v -> {float[] ret = new float[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Float.parseFloat(v[x]); return ret; }),
|
||||
DOUBLE(Double::valueOf, v -> {double[] ret = new double[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Double.parseDouble(v[x]); return ret; }),
|
||||
STRING(x -> x, x -> x),
|
||||
CLASS(Type::getType, v -> {Type[] ret = new Type[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Type.getType(v[x]); return ret; }),
|
||||
ENUM(ValueType::getEnumHolder, v -> {List<EnumHolder> ret = Lists.newArrayList(); for (int x = 0; x < v.length; x++) ret.add(ValueType.getEnumHolder(v[x])); return ret; }),
|
||||
ANNOTATION(null, null),
|
||||
NULL(x -> null, x -> null);
|
||||
|
||||
public final Function<String, Object> single;
|
||||
public final Function<String[], Object> array;
|
||||
|
||||
private ValueType(Function<String, Object> single, Function<String[], Object> array)
|
||||
{
|
||||
this.single = single;
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
private static EnumHolder getEnumHolder(String value)
|
||||
{
|
||||
int idx = value.lastIndexOf('/');
|
||||
if (idx <= 1)
|
||||
throw new IllegalArgumentException("Can not create a EnumHolder for value: " + value);
|
||||
String field = value.substring(idx + 1);
|
||||
value = value.substring(0, idx);
|
||||
idx = value.indexOf(';'); //Legacy internal name.
|
||||
value = value.substring(1, idx);
|
||||
return new EnumHolder(value, field);
|
||||
}
|
||||
};
|
||||
|
||||
static class Annotation
|
||||
{
|
||||
TargetType type;
|
||||
String name;
|
||||
String target;
|
||||
Integer id;
|
||||
ValueHolder value;
|
||||
Map<String, ValueHolder> values;
|
||||
private Map<String, Object> _values;
|
||||
|
||||
public Map<String, Object> getValues(ASMInfo pool)
|
||||
{
|
||||
if (_values == null)
|
||||
{
|
||||
_values = Maps.newHashMap();
|
||||
if (values != null)
|
||||
values.forEach((k, v) -> _values.put(k, v.get(pool)));
|
||||
else
|
||||
_values.put("value", value == null ? null : value.get(pool));
|
||||
}
|
||||
|
||||
return _values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return MoreObjects.toStringHelper("")
|
||||
.add("type", type)
|
||||
.add("name", name)
|
||||
.add("target", target)
|
||||
.add("id", id)
|
||||
.add("value", value)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
static class ValueHolder
|
||||
{
|
||||
ValueType type;
|
||||
String value;
|
||||
String[] values;
|
||||
|
||||
private Object _value;
|
||||
|
||||
private ValueType getType()
|
||||
{
|
||||
return type == null ? ValueType.STRING : type;
|
||||
}
|
||||
|
||||
public Object get(ASMInfo pool)
|
||||
{
|
||||
if (_value == null)
|
||||
{
|
||||
if (values != null)
|
||||
{
|
||||
if (type == ValueType.ANNOTATION)
|
||||
{
|
||||
List<Map<String, Object>> list = Lists.newArrayList();
|
||||
_value = list;
|
||||
|
||||
for (String s : values)
|
||||
{
|
||||
Annotation sub = pool.getSubAnnotation(Integer.parseInt(s));
|
||||
if (sub == null)
|
||||
FMLLog.log.error("Invalid Sub-Annotation in Annotation JSON: " + s);
|
||||
else
|
||||
list.add(sub.getValues(pool));
|
||||
}
|
||||
}
|
||||
else
|
||||
_value = getType().array.apply(values);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type == ValueType.ANNOTATION)
|
||||
{
|
||||
Annotation sub = pool.getSubAnnotation(Integer.parseInt(value));
|
||||
if (sub == null)
|
||||
FMLLog.log.error("Invalid Sub-Annotation in Annotation JSON: " + value);
|
||||
else
|
||||
_value = sub.getValues(pool);
|
||||
}
|
||||
else
|
||||
_value = getType().single.apply(value);
|
||||
}
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.discovery.json;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import net.minecraftforge.fml.common.discovery.json.ASMInfo.Annotation;
|
||||
import net.minecraftforge.fml.common.discovery.json.ASMInfo.TargetType;
|
||||
|
||||
public class JsonAnnotationLoader
|
||||
{
|
||||
public static final String ANNOTATION_JSON = "META-INF/fml_cache_annotation.json";
|
||||
private static final Gson GSON = new GsonBuilder().create();
|
||||
private static final java.lang.reflect.Type INFO_TABLE = new TypeToken<Map<String, ASMInfo>>(){}.getType();
|
||||
|
||||
public static Multimap<String, ASMData> loadJson(InputStream data, ModCandidate candidate, ASMDataTable table)
|
||||
{
|
||||
Map<String, ASMInfo> map = GSON.fromJson(new InputStreamReader(data, StandardCharsets.UTF_8), INFO_TABLE);
|
||||
Multimap<String, ASMData> ret = HashMultimap.create();
|
||||
|
||||
for (Entry<String, ASMInfo> entry : map.entrySet())
|
||||
{
|
||||
//TODO: Java9 Multi-Release Jars, picking the correct class for the current platform. For now we just ignore them.
|
||||
if (entry.getKey().startsWith("META-INF/"))
|
||||
continue;
|
||||
//TODO: Remove in 1.13, some older mods have these in the entries due to FG issue. Basically filter out scala synthetic class.
|
||||
if (entry.getKey().endsWith("$"))
|
||||
continue;
|
||||
|
||||
ASMInfo asm_info = entry.getValue();
|
||||
if (asm_info.interfaces != null)
|
||||
{
|
||||
for (String type : asm_info.interfaces)
|
||||
{
|
||||
//Interfaces use internal name, but annotations use source names. See ASMModParser.sendToTable
|
||||
table.addASMData(candidate, type, asm_info.name, null, null);
|
||||
ret.put(type, new ASMData(candidate, type, asm_info.name, null, null));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String owner_name = asm_info.name.replace('/', '.');
|
||||
if (asm_info.annotations != null)
|
||||
{
|
||||
for (Annotation anno : asm_info.annotations)
|
||||
{
|
||||
String name = anno.name.indexOf(';') > 0 ? Type.getType(anno.name).getClassName() : anno.name;
|
||||
String target = anno.target != null && (anno.type == TargetType.CLASS || anno.type == TargetType.SUBTYPE) ? anno.target.replace('/', '.') : anno.target;
|
||||
|
||||
table.addASMData(candidate, name, owner_name, target, anno.getValues(asm_info));
|
||||
ret.put(name, new ASMData(candidate, name, owner_name, target, anno.getValues(asm_info)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
|
@ -19,8 +19,6 @@
|
|||
|
||||
package net.minecraftforge.fml.common.event;
|
||||
|
||||
import net.minecraft.command.CommandHandler;
|
||||
import net.minecraft.command.ICommand;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
/**
|
||||
|
@ -36,10 +34,4 @@ public class FMLServerStartingEvent extends ServerLifecycleEvent
|
|||
{
|
||||
super(server);
|
||||
}
|
||||
|
||||
public void registerServerCommand(ICommand command)
|
||||
{
|
||||
CommandHandler ch = (CommandHandler) getServer().getCommandManager();
|
||||
ch.registerCommand(command);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,289 +50,6 @@ import com.google.common.collect.ImmutableList;
|
|||
*
|
||||
*/
|
||||
public class ByteBufUtils {
|
||||
/**
|
||||
* The number of bytes to write the supplied int using the 7 bit varint encoding.
|
||||
*
|
||||
* @param toCount The number to analyse
|
||||
* @return The number of bytes it will take to write it (maximum of 5)
|
||||
*/
|
||||
public static int varIntByteCount(int toCount)
|
||||
{
|
||||
return (toCount & 0xFFFFFF80) == 0 ? 1 : ((toCount & 0xFFFFC000) == 0 ? 2 : ((toCount & 0xFFE00000) == 0 ? 3 : ((toCount & 0xF0000000) == 0 ? 4 : 5)));
|
||||
}
|
||||
/**
|
||||
* Read a varint from the supplied buffer.
|
||||
*
|
||||
* @param buf The buffer to read from
|
||||
* @param maxSize The maximum length of bytes to read
|
||||
* @return The integer
|
||||
*/
|
||||
public static int readVarInt(ByteBuf buf, int maxSize)
|
||||
{
|
||||
Validate.isTrue(maxSize < 6 && maxSize > 0, "Varint length is between 1 and 5, not %d", maxSize);
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
byte b0;
|
||||
|
||||
do
|
||||
{
|
||||
b0 = buf.readByte();
|
||||
i |= (b0 & 127) << j++ * 7;
|
||||
|
||||
if (j > maxSize)
|
||||
{
|
||||
throw new RuntimeException("VarInt too big");
|
||||
}
|
||||
}
|
||||
while ((b0 & 128) == 128);
|
||||
|
||||
return i;
|
||||
}
|
||||
/**
|
||||
* An extended length short. Used by custom payload packets to extend size.
|
||||
*
|
||||
* @param buf
|
||||
* @return
|
||||
*/
|
||||
public static int readVarShort(ByteBuf buf)
|
||||
{
|
||||
int low = buf.readUnsignedShort();
|
||||
int high = 0;
|
||||
if ((low & 0x8000) != 0)
|
||||
{
|
||||
low = low & 0x7FFF;
|
||||
high = buf.readUnsignedByte();
|
||||
}
|
||||
return ((high & 0xFF) << 15) | low;
|
||||
}
|
||||
|
||||
public static void writeVarShort(ByteBuf buf, int toWrite)
|
||||
{
|
||||
int low = toWrite & 0x7FFF;
|
||||
int high = ( toWrite & 0x7F8000 ) >> 15;
|
||||
if (high != 0)
|
||||
{
|
||||
low = low | 0x8000;
|
||||
}
|
||||
buf.writeShort(low);
|
||||
if (high != 0)
|
||||
{
|
||||
buf.writeByte(high);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Write an integer to the buffer using variable length encoding. The maxSize constrains
|
||||
* how many bytes (and therefore the maximum number) that will be written.
|
||||
*
|
||||
* @param to The buffer to write to
|
||||
* @param toWrite The integer to write
|
||||
* @param maxSize The maximum number of bytes to use
|
||||
*/
|
||||
public static void writeVarInt(ByteBuf to, int toWrite, int maxSize)
|
||||
{
|
||||
Validate.isTrue(varIntByteCount(toWrite) <= maxSize, "Integer is too big for %d bytes", maxSize);
|
||||
while ((toWrite & -128) != 0)
|
||||
{
|
||||
to.writeByte(toWrite & 127 | 128);
|
||||
toWrite >>>= 7;
|
||||
}
|
||||
|
||||
to.writeByte(toWrite);
|
||||
}
|
||||
/**
|
||||
* Read a UTF8 string from the byte buffer.
|
||||
* It is encoded as <varint length>[<UTF8 char bytes>]
|
||||
*
|
||||
* @param from The buffer to read from
|
||||
* @return The string
|
||||
*/
|
||||
public static String readUTF8String(ByteBuf from)
|
||||
{
|
||||
int len = readVarInt(from,2);
|
||||
String str = from.toString(from.readerIndex(), len, StandardCharsets.UTF_8);
|
||||
from.readerIndex(from.readerIndex() + len);
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a String with UTF8 byte encoding to the buffer.
|
||||
* It is encoded as <varint length>[<UTF8 char bytes>]
|
||||
* @param to the buffer to write to
|
||||
* @param string The string to write
|
||||
*/
|
||||
public static void writeUTF8String(ByteBuf to, String string)
|
||||
{
|
||||
byte[] utf8Bytes = string.getBytes(StandardCharsets.UTF_8);
|
||||
Validate.isTrue(varIntByteCount(utf8Bytes.length) < 3, "The string is too long for this encoding.");
|
||||
writeVarInt(to, utf8Bytes.length, 2);
|
||||
to.writeBytes(utf8Bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an {@link ItemStack} using minecraft compatible encoding.
|
||||
*
|
||||
* @param to The buffer to write to
|
||||
* @param stack The itemstack to write
|
||||
*/
|
||||
public static void writeItemStack(ByteBuf to, ItemStack stack)
|
||||
{
|
||||
PacketBuffer pb = new PacketBuffer(to);
|
||||
pb.writeItemStack(stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an {@link ItemStack} from the byte buffer provided. It uses the minecraft encoding.
|
||||
*
|
||||
* @param from The buffer to read from
|
||||
* @return The itemstack read
|
||||
*/
|
||||
public static ItemStack readItemStack(ByteBuf from)
|
||||
{
|
||||
PacketBuffer pb = new PacketBuffer(from);
|
||||
try
|
||||
{
|
||||
return pb.readItemStack();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// Unpossible?
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an {@link NBTTagCompound} to the byte buffer. It uses the minecraft encoding.
|
||||
*
|
||||
* @param to The buffer to write to
|
||||
* @param tag The tag to write
|
||||
*/
|
||||
public static void writeTag(ByteBuf to, NBTTagCompound tag)
|
||||
{
|
||||
PacketBuffer pb = new PacketBuffer(to);
|
||||
pb.writeCompoundTag(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an {@link NBTTagCompound} from the byte buffer. It uses the minecraft encoding.
|
||||
*
|
||||
* @param from The buffer to read from
|
||||
* @return The read tag
|
||||
*/
|
||||
@Nullable
|
||||
public static NBTTagCompound readTag(ByteBuf from)
|
||||
{
|
||||
PacketBuffer pb = new PacketBuffer(from);
|
||||
try
|
||||
{
|
||||
return pb.readCompoundTag();
|
||||
} catch (IOException e)
|
||||
{
|
||||
// Unpossible?
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a registry entry to the stream. The serialized format is not specified and must not be relied upon.
|
||||
* Do not use this to write to a file, it is used for client-server communication only.
|
||||
* @param out the buffer to write to
|
||||
* @param entry the registry entry
|
||||
*/
|
||||
public static <T extends IForgeRegistryEntry<T>> void writeRegistryEntry(@Nonnull ByteBuf out, @Nonnull T entry)
|
||||
{
|
||||
ForgeRegistry<T> registry = (ForgeRegistry<T>)GameRegistry.findRegistry(entry.getRegistryType());
|
||||
writeUTF8String(out, RegistryManager.ACTIVE.getName(registry).toString());
|
||||
writeVarInt(out, registry.getID(entry), 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a registry entry from the stream. The same format as in {@link #writeRegistryEntry(ByteBuf, IForgeRegistryEntry)} is used.
|
||||
* @param in the buffer to read from
|
||||
* @param registry the registry the entry belongs to
|
||||
* @return the read registry entry
|
||||
*/
|
||||
@Nonnull
|
||||
public static <T extends IForgeRegistryEntry<T>> T readRegistryEntry(@Nonnull ByteBuf in, @Nonnull IForgeRegistry<T> registry)
|
||||
{
|
||||
String registryName = readUTF8String(in);
|
||||
int id = readVarInt(in, 5);
|
||||
ResourceLocation expectedRegistryName = RegistryManager.ACTIVE.getName(registry);
|
||||
|
||||
if (!expectedRegistryName.toString().equals(registryName))
|
||||
throw new IllegalArgumentException("Registry mismatch: " + registryName + " != " + expectedRegistryName);
|
||||
|
||||
T thing = ((ForgeRegistry<T>)registry).getRaw(id);
|
||||
if (thing == null)
|
||||
throw new IllegalArgumentException("Unknown ID " + id + " for registry " + expectedRegistryName + " received.");
|
||||
|
||||
return thing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write multiple registry entries from the same registry to the stream. The serialized format may be more compact than using
|
||||
* {@link #writeRegistryEntry(ByteBuf, IForgeRegistryEntry)} multiple times.
|
||||
* @param out the buffer to write to
|
||||
* @param entries the entries to write
|
||||
*/
|
||||
public static <T extends IForgeRegistryEntry<T>> void writeRegistryEntries(@Nonnull ByteBuf out, @Nonnull Collection<T> entries)
|
||||
{
|
||||
writeVarInt(out, entries.size(), 5);
|
||||
|
||||
Iterator<T> it = entries.iterator();
|
||||
if (it.hasNext())
|
||||
{
|
||||
T first = it.next();
|
||||
ForgeRegistry<T> registry = (ForgeRegistry<T>)GameRegistry.findRegistry(first.getRegistryType());
|
||||
writeUTF8String(out, RegistryManager.ACTIVE.getName(registry).toString());
|
||||
writeVarInt(out, registry.getID(first), 5);
|
||||
|
||||
while (it.hasNext())
|
||||
{
|
||||
int id = registry.getID(it.next());
|
||||
if (id == -1)
|
||||
throw new IllegalArgumentException("Unregistered IForgeRegistryEntry in collection " + entries + ".");
|
||||
writeVarInt(out, id, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read multiple registry entries from the same registries from the stream. The list of entries must have been written by
|
||||
* {@link #writeRegistryEntries(ByteBuf, Collection)}.
|
||||
* @param in the buffer to read from
|
||||
* @param registry the registry the entries belong to
|
||||
* @return the immutable list of entries
|
||||
*/
|
||||
@Nonnull
|
||||
public static <T extends IForgeRegistryEntry<T>> List<T> readRegistryEntries(@Nonnull ByteBuf in, @Nonnull IForgeRegistry<T> registry)
|
||||
{
|
||||
int size = readVarInt(in, 5);
|
||||
if (size == 0)
|
||||
{
|
||||
return ImmutableList.of();
|
||||
}
|
||||
else
|
||||
{
|
||||
String registryName = readUTF8String(in);
|
||||
ResourceLocation expectedRegistryName = RegistryManager.ACTIVE.getName(registry);
|
||||
if (!expectedRegistryName.toString().equals(registryName))
|
||||
{
|
||||
throw new IllegalArgumentException("Registry mismatch: " + registryName + " != " + expectedRegistryName);
|
||||
}
|
||||
|
||||
ImmutableList.Builder<T> b = ImmutableList.builder();
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
int id = readVarInt(in, 5);
|
||||
T thing = ((ForgeRegistry<T>)registry).getRaw(id);
|
||||
if (thing == null)
|
||||
throw new IllegalArgumentException("Unknown ID " + id + " for registry " + expectedRegistryName + " received.");
|
||||
|
||||
b.add(thing);
|
||||
}
|
||||
return b.build();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getContentDump(ByteBuf buffer)
|
||||
{
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.network;
|
||||
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.LogicalSide;
|
||||
import net.minecraftforge.fml.ModThreadContext;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import net.minecraftforge.fml.common.network.FMLOutboundHandler.OutboundTarget;
|
||||
import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher;
|
||||
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Utility wrapper around {@link EmbeddedChannel}. Provides some convenience methods
|
||||
* associated with the specific needs of FML network handling.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class FMLEmbeddedChannel extends EmbeddedChannel {
|
||||
public FMLEmbeddedChannel(String channelName, LogicalSide source, ChannelHandler... handlers)
|
||||
{
|
||||
this(ModThreadContext.get().getActiveContainer(), channelName, source, handlers);
|
||||
}
|
||||
public FMLEmbeddedChannel(ModContainer container, String channelName, LogicalSide source, ChannelHandler... handlers)
|
||||
{
|
||||
super(handlers);
|
||||
this.attr(NetworkRegistry.FML_CHANNEL).set(channelName);
|
||||
this.attr(NetworkRegistry.CHANNEL_SOURCE).set(source);
|
||||
this.attr(NetworkRegistry.MOD_CONTAINER).setIfAbsent(container);
|
||||
this.pipeline().addFirst("fml:outbound",new FMLOutboundHandler());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Utility method to generate a regular packet from a custom packet. Basically, it writes the packet through the
|
||||
* outbound side which should have a message to message codec present (such as {@link FMLIndexedMessageToMessageCodec},
|
||||
* transforming from mod packets to standard {@link FMLProxyPacket}s.
|
||||
*
|
||||
* This is mostly useful in cases where vanilla expects a packet, such as the TileEntity getDescriptionPacket.
|
||||
*
|
||||
* @param object The inbound packet
|
||||
* @return A Packet suitable for passing to vanilla network code.
|
||||
*/
|
||||
public Packet<?> generatePacketFrom(Object object)
|
||||
{
|
||||
OutboundTarget outboundTarget = attr(FMLOutboundHandler.FML_MESSAGETARGET).getAndSet(OutboundTarget.NOWHERE);
|
||||
writeOutbound(object);
|
||||
Packet<?> pkt = (Packet<?>) outboundMessages().poll();
|
||||
attr(FMLOutboundHandler.FML_MESSAGETARGET).set(outboundTarget);
|
||||
return pkt;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String findChannelHandlerNameForType(Class<? extends ChannelHandler> type)
|
||||
{
|
||||
String targetName = null;
|
||||
for (Entry<String, ChannelHandler> entry : pipeline())
|
||||
{
|
||||
if (type.isInstance(entry.getValue()))
|
||||
{
|
||||
targetName = entry.getKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return targetName;
|
||||
}
|
||||
|
||||
public void cleanAttributes()
|
||||
{
|
||||
this.attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(null);
|
||||
this.attr(NetworkRegistry.NET_HANDLER).set(null);
|
||||
this.attr(NetworkDispatcher.FML_DISPATCHER).set(null);
|
||||
}
|
||||
}
|
|
@ -1,229 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.network;
|
||||
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
import java.util.EnumMap;
|
||||
|
||||
import net.minecraft.client.network.NetHandlerPlayClient;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.network.NetHandlerPlayServer;
|
||||
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An event driven network channel, using {@link FMLNetworkEvent.CustomPacketEvent} and {@link FMLNetworkEvent.CustomNetworkEvent}
|
||||
* to deliver messages to an event listener. There is one "bus" for each channel, due to the
|
||||
* impossibility of filtering a bus for specific events.
|
||||
*
|
||||
* This event driven system completely wraps the netty code. Mod code deals with FMLProxyPackets directly. It is not
|
||||
* possible to enhance the netty pipeline, and I would expect highly unexpected results if it were modified reflectively.
|
||||
* Use a real ChannelHandler if you want to use netty.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class FMLEventChannel {
|
||||
private EnumMap<Side, FMLEmbeddedChannel> channels;
|
||||
private IEventBus eventBus;
|
||||
|
||||
/*
|
||||
* This is done this way so that the CLIENT specific code in the factory only loads on the client
|
||||
*/
|
||||
private enum EventFactory
|
||||
{
|
||||
SERVER()
|
||||
{
|
||||
@Override
|
||||
@Nullable
|
||||
FMLNetworkEvent.CustomPacketEvent<?> make(FMLProxyPacket msg)
|
||||
{
|
||||
FMLNetworkEvent.CustomPacketEvent<?> event = null;
|
||||
if (msg.handler() instanceof NetHandlerPlayServer)
|
||||
{
|
||||
NetHandlerPlayServer server = (NetHandlerPlayServer) msg.handler();
|
||||
event = new FMLNetworkEvent.ServerCustomPacketEvent(server.getNetworkManager(), msg);
|
||||
}
|
||||
return event;
|
||||
}
|
||||
},
|
||||
CLIENT()
|
||||
{
|
||||
@Override
|
||||
@Nullable
|
||||
FMLNetworkEvent.CustomPacketEvent<?> make(FMLProxyPacket msg)
|
||||
{
|
||||
FMLNetworkEvent.CustomPacketEvent<?> event = null;
|
||||
if (msg.handler() instanceof NetHandlerPlayClient)
|
||||
{
|
||||
NetHandlerPlayClient client = (NetHandlerPlayClient) msg.handler();
|
||||
event = new FMLNetworkEvent.ClientCustomPacketEvent(client.getNetworkManager(), msg);
|
||||
}
|
||||
else if (msg.handler() instanceof NetHandlerPlayServer)
|
||||
{
|
||||
NetHandlerPlayServer server = (NetHandlerPlayServer) msg.handler();
|
||||
event = new FMLNetworkEvent.ServerCustomPacketEvent(server.getNetworkManager(), msg);
|
||||
}
|
||||
return event;
|
||||
}
|
||||
};
|
||||
@Nullable
|
||||
abstract FMLNetworkEvent.CustomPacketEvent<?> make(FMLProxyPacket msg);
|
||||
}
|
||||
|
||||
private static EventFactory factory = FMLCommonHandler.instance().getSide() == Side.CLIENT ? EventFactory.CLIENT : EventFactory.SERVER;
|
||||
FMLEventChannel(String name)
|
||||
{
|
||||
this.channels = NetworkRegistry.INSTANCE.newChannel(name, new NetworkEventFiringHandler(this));
|
||||
this.eventBus = IEventBus.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an event listener with this channel and bus. See {@link SubscribeEvent}
|
||||
*
|
||||
* @param object
|
||||
*/
|
||||
public void register(Object object)
|
||||
{
|
||||
this.eventBus.register(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister an event listener from the bus.
|
||||
* @param object
|
||||
*/
|
||||
public void unregister(Object object)
|
||||
{
|
||||
this.eventBus.unregister(object);
|
||||
}
|
||||
|
||||
void fireRead(FMLProxyPacket msg, ChannelHandlerContext ctx)
|
||||
{
|
||||
FMLNetworkEvent.CustomPacketEvent<?> event = factory.make(msg);
|
||||
if (event != null)
|
||||
{
|
||||
this.eventBus.post(event);
|
||||
if (event.getReply() != null)
|
||||
{
|
||||
ctx.channel().attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.REPLY);
|
||||
ctx.writeAndFlush(event.getReply()).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void fireUserEvent(Object evt, ChannelHandlerContext ctx)
|
||||
{
|
||||
FMLNetworkEvent.CustomNetworkEvent event = new FMLNetworkEvent.CustomNetworkEvent(evt);
|
||||
this.eventBus.post(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet to all on the server
|
||||
*
|
||||
* @param pkt
|
||||
*/
|
||||
public void sendToAll(FMLProxyPacket pkt)
|
||||
{
|
||||
channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALL);
|
||||
channels.get(Side.SERVER).writeAndFlush(pkt).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send to a specific player
|
||||
*
|
||||
* @param pkt
|
||||
* @param player
|
||||
*/
|
||||
public void sendTo(FMLProxyPacket pkt, EntityPlayerMP player)
|
||||
{
|
||||
channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.PLAYER);
|
||||
channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(player);
|
||||
channels.get(Side.SERVER).writeAndFlush(pkt).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send to all around a point
|
||||
* @param pkt
|
||||
* @param point
|
||||
*/
|
||||
public void sendToAllAround(FMLProxyPacket pkt, NetworkRegistry.TargetPoint point)
|
||||
{
|
||||
channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALLAROUNDPOINT);
|
||||
channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(point);
|
||||
channels.get(Side.SERVER).writeAndFlush(pkt).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send to all tracking the point
|
||||
* The {@code range} field of the {@link NetworkRegistry.TargetPoint} is ignored.
|
||||
* @param pkt
|
||||
* @param point
|
||||
*/
|
||||
public void sendToAllTracking(FMLProxyPacket pkt, NetworkRegistry.TargetPoint point)
|
||||
{
|
||||
channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.TRACKING_POINT);
|
||||
channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(point);
|
||||
channels.get(Side.SERVER).writeAndFlush(pkt).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send to all tracking the entity
|
||||
* This is not equivalent to {@link #sendToAllTracking(FMLProxyPacket, NetworkRegistry.TargetPoint)}
|
||||
* because entities have different tracking distances based on their type.
|
||||
* @param pkt
|
||||
* @param entity
|
||||
*/
|
||||
public void sendToAllTracking(FMLProxyPacket pkt, Entity entity)
|
||||
{
|
||||
channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.TRACKING_ENTITY);
|
||||
channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(entity);
|
||||
channels.get(Side.SERVER).writeAndFlush(pkt).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send to all in a dimension
|
||||
* @param pkt
|
||||
* @param dimensionId
|
||||
*/
|
||||
public void sendToDimension(FMLProxyPacket pkt, int dimensionId)
|
||||
{
|
||||
channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.DIMENSION);
|
||||
channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(dimensionId);
|
||||
channels.get(Side.SERVER).writeAndFlush(pkt).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send to the server
|
||||
* @param pkt
|
||||
*/
|
||||
public void sendToServer(FMLProxyPacket pkt)
|
||||
{
|
||||
channels.get(Side.CLIENT).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.TOSERVER);
|
||||
channels.get(Side.CLIENT).writeAndFlush(pkt).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.network;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageCodec;
|
||||
import io.netty.util.AttributeKey;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
import it.unimi.dsi.fastutil.bytes.Byte2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.bytes.Byte2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ByteMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap;
|
||||
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;
|
||||
|
||||
@Sharable
|
||||
public abstract class FMLIndexedMessageToMessageCodec<A> extends MessageToMessageCodec<FMLProxyPacket, A>
|
||||
{
|
||||
private final Byte2ObjectMap<Class<? extends A>> discriminators = new Byte2ObjectOpenHashMap<>();
|
||||
private final Object2ByteMap<Class<? extends A>> types = new Object2ByteOpenHashMap<>();
|
||||
|
||||
/**
|
||||
* Make this accessible to subclasses
|
||||
*/
|
||||
|
||||
public static final AttributeKey<ThreadLocal<WeakReference<FMLProxyPacket>>> INBOUNDPACKETTRACKER = AttributeKey.valueOf("fml:inboundpacket");
|
||||
|
||||
@Override
|
||||
public void handlerAdded(ChannelHandlerContext ctx) throws Exception
|
||||
{
|
||||
super.handlerAdded(ctx);
|
||||
ctx.channel().attr(INBOUNDPACKETTRACKER).set(new ThreadLocal<WeakReference<FMLProxyPacket>>());
|
||||
}
|
||||
|
||||
public FMLIndexedMessageToMessageCodec<A> addDiscriminator(int discriminator, Class<? extends A> type)
|
||||
{
|
||||
discriminators.put((byte)discriminator, type);
|
||||
types.put(type, (byte)discriminator);
|
||||
return this;
|
||||
}
|
||||
|
||||
public abstract void encodeInto(ChannelHandlerContext ctx, A msg, ByteBuf target) throws Exception;
|
||||
|
||||
@Override
|
||||
protected final void encode(ChannelHandlerContext ctx, A msg, List<Object> out) throws Exception
|
||||
{
|
||||
String channel = ctx.channel().attr(NetworkRegistry.FML_CHANNEL).get();
|
||||
Class<?> clazz = msg.getClass();
|
||||
if (!types.containsKey(clazz))
|
||||
{
|
||||
throw new RuntimeException("Undefined discriminator for message type " + clazz.getName() + " in channel " + channel);
|
||||
}
|
||||
byte discriminator = types.getByte(clazz);
|
||||
PacketBuffer buffer = new PacketBuffer(Unpooled.buffer());
|
||||
buffer.writeByte(discriminator);
|
||||
encodeInto(ctx, msg, buffer);
|
||||
FMLProxyPacket proxy = new FMLProxyPacket(buffer, channel);
|
||||
WeakReference<FMLProxyPacket> ref = ctx.channel().attr(INBOUNDPACKETTRACKER).get().get();
|
||||
FMLProxyPacket old = ref == null ? null : ref.get();
|
||||
if (old != null)
|
||||
{
|
||||
proxy.setDispatcher(old.getDispatcher());
|
||||
}
|
||||
out.add(proxy);
|
||||
}
|
||||
|
||||
public abstract void decodeInto(ChannelHandlerContext ctx, ByteBuf source, A msg);
|
||||
|
||||
@Override
|
||||
protected final void decode(ChannelHandlerContext ctx, FMLProxyPacket msg, List<Object> out) throws Exception
|
||||
{
|
||||
testMessageValidity(msg);
|
||||
ByteBuf payload = msg.payload().duplicate();
|
||||
if (payload.readableBytes() < 1)
|
||||
{
|
||||
FMLLog.log.error("The FMLIndexedCodec has received an empty buffer on channel {}, likely a result of a LAN server issue. Pipeline parts : {}", ctx.channel().attr(NetworkRegistry.FML_CHANNEL), ctx.pipeline().toString());
|
||||
}
|
||||
byte discriminator = payload.readByte();
|
||||
Class<? extends A> clazz = discriminators.get(discriminator);
|
||||
if(clazz == null)
|
||||
{
|
||||
throw new NullPointerException("Undefined message for discriminator " + discriminator + " in channel " + msg.channel());
|
||||
}
|
||||
A newMsg = clazz.newInstance();
|
||||
ctx.channel().attr(INBOUNDPACKETTRACKER).get().set(new WeakReference<FMLProxyPacket>(msg));
|
||||
decodeInto(ctx, payload.slice(), newMsg);
|
||||
out.add(newMsg);
|
||||
payload.release();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to verify the message received. This can be used to hard disconnect in case of an unexpected packet,
|
||||
* say due to a weird protocol mismatch. Use with caution.
|
||||
* @param msg
|
||||
*/
|
||||
protected void testMessageValidity(FMLProxyPacket msg)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
|
||||
{
|
||||
FMLLog.log.error("FMLIndexedMessageCodec exception caught", cause);
|
||||
super.exceptionCaught(ctx, cause);
|
||||
}
|
||||
}
|
|
@ -1,258 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.network;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import net.minecraft.network.INetHandler;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.network.play.INetHandlerPlayClient;
|
||||
import net.minecraft.network.play.INetHandlerPlayServer;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
public class FMLNetworkEvent<T extends INetHandler> extends Event {
|
||||
private final T handler;
|
||||
private final NetworkManager manager;
|
||||
private final Class<T> type;
|
||||
|
||||
FMLNetworkEvent(T thing, Class<T> type, NetworkManager manager)
|
||||
{
|
||||
this.handler = thing;
|
||||
this.type = type;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public Class<T> getHandlerType()
|
||||
{
|
||||
return getType();
|
||||
}
|
||||
|
||||
public T getHandler()
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
|
||||
public NetworkManager getManager()
|
||||
{
|
||||
return manager;
|
||||
}
|
||||
|
||||
public Class<T> getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired at the client when a client connects to a server
|
||||
*/
|
||||
public static class ClientConnectedToServerEvent extends FMLNetworkEvent<INetHandlerPlayClient> {
|
||||
private final boolean isLocal;
|
||||
private final String connectionType;
|
||||
public ClientConnectedToServerEvent(NetworkManager manager, String connectionType)
|
||||
{
|
||||
super((INetHandlerPlayClient) manager.getNetHandler(), INetHandlerPlayClient.class, manager);
|
||||
this.isLocal = manager.isLocalChannel();
|
||||
this.connectionType = connectionType;
|
||||
}
|
||||
|
||||
public boolean isLocal()
|
||||
{
|
||||
return isLocal;
|
||||
}
|
||||
|
||||
public String getConnectionType()
|
||||
{
|
||||
return connectionType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired at the server when a client connects to the server.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public static class ServerConnectionFromClientEvent extends FMLNetworkEvent<INetHandlerPlayServer> {
|
||||
private final boolean isLocal;
|
||||
public ServerConnectionFromClientEvent(NetworkManager manager)
|
||||
{
|
||||
super((INetHandlerPlayServer) manager.getNetHandler(), INetHandlerPlayServer.class, manager);
|
||||
this.isLocal = manager.isLocalChannel();
|
||||
}
|
||||
|
||||
public boolean isLocal()
|
||||
{
|
||||
return isLocal;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Fired at the server when a client disconnects.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public static class ServerDisconnectionFromClientEvent extends FMLNetworkEvent<INetHandlerPlayServer> {
|
||||
public ServerDisconnectionFromClientEvent(NetworkManager manager)
|
||||
{
|
||||
super((INetHandlerPlayServer) manager.getNetHandler(), INetHandlerPlayServer.class, manager);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Fired at the client when the client is disconnected from the server.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public static class ClientDisconnectionFromServerEvent extends FMLNetworkEvent<INetHandlerPlayClient> {
|
||||
public ClientDisconnectionFromServerEvent(NetworkManager manager)
|
||||
{
|
||||
super((INetHandlerPlayClient) manager.getNetHandler(), INetHandlerPlayClient.class, manager);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when the REGISTER/UNREGISTER for custom channels is received.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
* @param <S> The side
|
||||
*/
|
||||
public static class CustomPacketRegistrationEvent<S extends INetHandler> extends FMLNetworkEvent<S> {
|
||||
private final ImmutableSet<String> registrations;
|
||||
private final String operation;
|
||||
private final Side side;
|
||||
public CustomPacketRegistrationEvent(NetworkManager manager, Set<String> registrations, String operation, Side side, Class<S> type)
|
||||
{
|
||||
super(type.cast(manager.getNetHandler()), type, manager);
|
||||
this.registrations = ImmutableSet.copyOf(registrations);
|
||||
this.side = side;
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
public ImmutableSet<String> getRegistrations()
|
||||
{
|
||||
return registrations;
|
||||
}
|
||||
|
||||
public String getOperation()
|
||||
{
|
||||
return operation;
|
||||
}
|
||||
|
||||
public Side getSide()
|
||||
{
|
||||
return side;
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class CustomPacketEvent<S extends INetHandler> extends FMLNetworkEvent<S> {
|
||||
private final FMLProxyPacket packet;
|
||||
|
||||
private FMLProxyPacket reply;
|
||||
CustomPacketEvent(S thing, Class<S> type, NetworkManager manager, FMLProxyPacket packet)
|
||||
{
|
||||
super(thing, type, manager);
|
||||
this.packet = packet;
|
||||
}
|
||||
|
||||
public abstract Side side();
|
||||
|
||||
/**
|
||||
* The packet that generated the event
|
||||
*/
|
||||
public FMLProxyPacket getPacket()
|
||||
{
|
||||
return packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this packet to reply to the originator
|
||||
*/
|
||||
public FMLProxyPacket getReply()
|
||||
{
|
||||
return reply;
|
||||
}
|
||||
|
||||
public void setReply(FMLProxyPacket reply)
|
||||
{
|
||||
this.reply = reply;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a custom packet is received on the client for the channel
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public static class ClientCustomPacketEvent extends CustomPacketEvent<INetHandlerPlayClient> {
|
||||
public ClientCustomPacketEvent(NetworkManager manager, FMLProxyPacket packet)
|
||||
{
|
||||
super((INetHandlerPlayClient) manager.getNetHandler(), INetHandlerPlayClient.class, manager, packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Side side()
|
||||
{
|
||||
return Side.CLIENT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a custom packet is received at the server for the channel
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public static class ServerCustomPacketEvent extends CustomPacketEvent<INetHandlerPlayServer> {
|
||||
public ServerCustomPacketEvent(NetworkManager manager, FMLProxyPacket packet)
|
||||
{
|
||||
super((INetHandlerPlayServer) manager.getNetHandler(), INetHandlerPlayServer.class, manager, packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Side side()
|
||||
{
|
||||
return Side.SERVER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a custom event, such as {@link NetworkHandshakeEstablished} is fired for the channel
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public static class CustomNetworkEvent extends net.minecraftforge.eventbus.api.Event
|
||||
{
|
||||
private final Object wrappedEvent;
|
||||
public CustomNetworkEvent(Object wrappedEvent)
|
||||
{
|
||||
this.wrappedEvent = wrappedEvent;
|
||||
}
|
||||
|
||||
public Object getWrappedEvent()
|
||||
{
|
||||
return wrappedEvent;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.network;
|
||||
|
||||
public class FMLNetworkException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public FMLNetworkException(Exception e)
|
||||
{
|
||||
super(e);
|
||||
}
|
||||
|
||||
public FMLNetworkException()
|
||||
{
|
||||
}
|
||||
|
||||
public FMLNetworkException(String string)
|
||||
{
|
||||
super(string);
|
||||
}
|
||||
}
|
|
@ -1,394 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.network;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelOutboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.util.AttributeKey;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.server.management.PlayerChunkMap;
|
||||
import net.minecraft.server.management.PlayerChunkMapEntry;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||
import net.minecraftforge.fml.common.network.NetworkRegistry.TargetPoint;
|
||||
import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher;
|
||||
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class FMLOutboundHandler extends ChannelOutboundHandlerAdapter {
|
||||
public static final AttributeKey<OutboundTarget> FML_MESSAGETARGET = AttributeKey.valueOf("fml:outboundTarget");
|
||||
public static final AttributeKey<Object> FML_MESSAGETARGETARGS = AttributeKey.valueOf("fml:outboundTargetArgs");
|
||||
public enum OutboundTarget {
|
||||
/**
|
||||
* The packet is sent nowhere. It will be on the {@link EmbeddedChannel#outboundMessages()} Queue.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
NOWHERE(Sets.immutableEnumSet(Side.CLIENT, Side.SERVER))
|
||||
{
|
||||
@Override
|
||||
public void validateArgs(Object args)
|
||||
{
|
||||
// NOOP
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
},
|
||||
/**
|
||||
* The packet is sent to the {@link NetworkDispatcher} supplied as an argument.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
DISPATCHER(Sets.immutableEnumSet(Side.SERVER))
|
||||
{
|
||||
@Override
|
||||
public void validateArgs(Object args)
|
||||
{
|
||||
if (!(args instanceof NetworkDispatcher))
|
||||
{
|
||||
throw new RuntimeException("DISPATCHER expects a NetworkDispatcher");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
||||
{
|
||||
return ImmutableList.of((NetworkDispatcher)args);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The packet is sent to the originator of the packet. This requires the inbound packet
|
||||
* to have it's originator information set.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
REPLY(Sets.immutableEnumSet(Side.SERVER))
|
||||
{
|
||||
@Override
|
||||
public void validateArgs(Object args)
|
||||
{
|
||||
// NOOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
||||
{
|
||||
return ImmutableList.of(packet.getDispatcher());
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The packet is sent to the {@link EntityPlayerMP} supplied as an argument.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
PLAYER(Sets.immutableEnumSet(Side.SERVER))
|
||||
{
|
||||
@Override
|
||||
public void validateArgs(Object args)
|
||||
{
|
||||
if (!(args instanceof EntityPlayerMP))
|
||||
{
|
||||
throw new RuntimeException("PLAYER target expects a Player arg");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
||||
{
|
||||
EntityPlayerMP player = (EntityPlayerMP) args;
|
||||
NetworkDispatcher dispatcher = (player == null || player instanceof FakePlayer) ? null : player.connection.netManager.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
|
||||
return dispatcher == null ? ImmutableList.<NetworkDispatcher>of() : ImmutableList.of(dispatcher);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The packet is dispatched to all players connected to the server.
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
ALL(Sets.immutableEnumSet(Side.SERVER))
|
||||
{
|
||||
@Override
|
||||
public void validateArgs(Object args)
|
||||
{
|
||||
}
|
||||
@Override
|
||||
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
||||
{
|
||||
ImmutableList.Builder<NetworkDispatcher> builder = ImmutableList.builder();
|
||||
for (EntityPlayerMP player : FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().getPlayers())
|
||||
{
|
||||
NetworkDispatcher dispatcher = player.connection.netManager.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
|
||||
if (dispatcher != null) builder.add(dispatcher);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The packet is sent to all players in the dimension identified by the integer argument.
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
DIMENSION(Sets.immutableEnumSet(Side.SERVER))
|
||||
{
|
||||
@Override
|
||||
public void validateArgs(Object args)
|
||||
{
|
||||
if (!(args instanceof Integer))
|
||||
{
|
||||
throw new RuntimeException("DIMENSION expects an integer argument");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
||||
{
|
||||
int dimension = (Integer)args;
|
||||
ImmutableList.Builder<NetworkDispatcher> builder = ImmutableList.builder();
|
||||
for (EntityPlayerMP player : FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().getPlayers())
|
||||
{
|
||||
if (dimension == player.dimension)
|
||||
{
|
||||
NetworkDispatcher dispatcher = player.connection.netManager.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
|
||||
// Null dispatchers may exist for fake players - skip them
|
||||
if (dispatcher != null) builder.add(dispatcher);
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The packet is sent to all players within range of the {@link TargetPoint} argument supplied.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
ALLAROUNDPOINT(Sets.immutableEnumSet(Side.SERVER))
|
||||
{
|
||||
@Override
|
||||
public void validateArgs(Object args)
|
||||
{
|
||||
if (!(args instanceof TargetPoint))
|
||||
{
|
||||
throw new RuntimeException("ALLAROUNDPOINT expects a TargetPoint argument");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
||||
{
|
||||
TargetPoint tp = (TargetPoint)args;
|
||||
ImmutableList.Builder<NetworkDispatcher> builder = ImmutableList.builder();
|
||||
for (EntityPlayerMP player : FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().getPlayers())
|
||||
{
|
||||
if (player.dimension == tp.dimension)
|
||||
{
|
||||
double d4 = tp.x - player.posX;
|
||||
double d5 = tp.y - player.posY;
|
||||
double d6 = tp.z - player.posZ;
|
||||
|
||||
if (d4 * d4 + d5 * d5 + d6 * d6 < tp.range * tp.range)
|
||||
{
|
||||
NetworkDispatcher dispatcher = player.connection.netManager.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
|
||||
if (dispatcher != null) builder.add(dispatcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The packet is sent to all players that are watching the Chunk containing the supplied {@link TargetPoint}.
|
||||
* The {@code range} field of the {@link TargetPoint} is ignored.
|
||||
*/
|
||||
TRACKING_POINT(Sets.immutableEnumSet(Side.SERVER))
|
||||
{
|
||||
@Override
|
||||
public void validateArgs(Object args)
|
||||
{
|
||||
if (!(args instanceof TargetPoint))
|
||||
{
|
||||
throw new RuntimeException("TRACKING_POINT expects a TargetPoint argument");
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
||||
{
|
||||
TargetPoint tp = (TargetPoint)args;
|
||||
WorldServer world = DimensionManager.getWorld(tp.dimension);
|
||||
if (world == null)
|
||||
{
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
PlayerChunkMapEntry entry = world.getPlayerChunkMap().getEntry(MathHelper.floor(tp.x) >> 4, MathHelper.floor(tp.z) >> 4);
|
||||
if (entry == null)
|
||||
{
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
ImmutableList.Builder<NetworkDispatcher> builder = ImmutableList.builder();
|
||||
for (EntityPlayerMP player : entry.getWatchingPlayers())
|
||||
{
|
||||
NetworkDispatcher dispatcher = player.connection.netManager.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
|
||||
if (dispatcher != null) builder.add(dispatcher);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The packet is sent to all players tracking the supplied {@link Entity}. This is different from {@link #TRACKING_POINT} because Entities
|
||||
* can have different tracking distances depending on their type.
|
||||
*/
|
||||
TRACKING_ENTITY(Sets.immutableEnumSet(Side.SERVER))
|
||||
{
|
||||
@Override
|
||||
public void validateArgs(Object args)
|
||||
{
|
||||
if (!(args instanceof Entity))
|
||||
{
|
||||
throw new RuntimeException("TRACKING_ENTITY expects an Entity argument");
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
||||
{
|
||||
Entity e = (Entity)args;
|
||||
Set<? extends EntityPlayer> players = FMLCommonHandler.instance().getMinecraftServerInstance()
|
||||
.getWorld(e.dimension).getEntityTracker().getTrackingPlayers(e);
|
||||
|
||||
ImmutableList.Builder<NetworkDispatcher> builder = ImmutableList.builder();
|
||||
for (EntityPlayer player : players)
|
||||
{
|
||||
NetworkDispatcher dispatcher = ((EntityPlayerMP) player).connection.netManager.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
|
||||
if (dispatcher != null) builder.add(dispatcher);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The packet is sent to the server this client is currently conversing with.
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
TOSERVER(Sets.immutableEnumSet(Side.CLIENT))
|
||||
{
|
||||
@Override
|
||||
public void validateArgs(Object args)
|
||||
{
|
||||
}
|
||||
@Override
|
||||
public List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet)
|
||||
{
|
||||
NetworkManager clientConnection = FMLCommonHandler.instance().getClientToServerNetworkManager();
|
||||
return clientConnection == null || clientConnection.channel().attr(NetworkDispatcher.FML_DISPATCHER).get() == null ? ImmutableList.<NetworkDispatcher>of() : ImmutableList.of(clientConnection.channel().attr(NetworkDispatcher.FML_DISPATCHER).get());
|
||||
}
|
||||
};
|
||||
|
||||
private OutboundTarget(ImmutableSet<Side> sides)
|
||||
{
|
||||
this.allowed = sides;
|
||||
}
|
||||
public final ImmutableSet<Side> allowed;
|
||||
public abstract void validateArgs(Object args);
|
||||
@Nullable
|
||||
public abstract List<NetworkDispatcher> selectNetworks(Object args, ChannelHandlerContext context, FMLProxyPacket packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception
|
||||
{
|
||||
if (!(msg instanceof FMLProxyPacket))
|
||||
{
|
||||
return;
|
||||
}
|
||||
FMLProxyPacket pkt = (FMLProxyPacket) msg;
|
||||
OutboundTarget outboundTarget;
|
||||
Object args = null;
|
||||
NetworkDispatcher dispatcher = ctx.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();
|
||||
// INTERNAL message callback - let it pass out
|
||||
if (dispatcher != null)
|
||||
{
|
||||
ctx.write(msg, promise);
|
||||
return;
|
||||
}
|
||||
|
||||
outboundTarget = ctx.channel().attr(FML_MESSAGETARGET).get();
|
||||
Side channelSide = ctx.channel().attr(NetworkRegistry.CHANNEL_SOURCE).get();
|
||||
if (outboundTarget != null && outboundTarget.allowed.contains(channelSide))
|
||||
{
|
||||
args = ctx.channel().attr(FML_MESSAGETARGETARGS).get();
|
||||
outboundTarget.validateArgs(args);
|
||||
}
|
||||
else if (channelSide == Side.CLIENT)
|
||||
{
|
||||
outboundTarget = OutboundTarget.TOSERVER;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FMLNetworkException("Packet arrived at the outbound handler without a valid target!");
|
||||
}
|
||||
|
||||
List<NetworkDispatcher> dispatchers = outboundTarget.selectNetworks(args, ctx, pkt);
|
||||
|
||||
// This will drop the messages into the output queue at the embedded channel
|
||||
if (dispatchers == null)
|
||||
{
|
||||
ctx.write(msg, promise);
|
||||
return;
|
||||
}
|
||||
for (NetworkDispatcher targetDispatcher : dispatchers)
|
||||
{
|
||||
pkt.payload().retain();
|
||||
targetDispatcher.sendProxy(pkt);
|
||||
}
|
||||
pkt.payload().release();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.network;
|
||||
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* A method annotated with this will be called when a remote network connection is offered.
|
||||
* The method should have two parameters, of types Map<String,String> and {@link Side}. It should return a boolean
|
||||
* true indicating that the remote party is acceptable, or false if not.
|
||||
*
|
||||
* <p>
|
||||
* When the method is invoked, the map will contain String keys and values listing all mods and their versions present.
|
||||
* The side represents the side of the remote party. So if you're on the server, it'll be CLIENT, and vice versa.
|
||||
*
|
||||
* <p>
|
||||
* This method will be invoked both when querying the status of the remote server, and when connecting to the remote server.
|
||||
*
|
||||
* <p>
|
||||
* <strong>NOTE: the server will not be setup at any point when this method is called. Do not try and interact with the server
|
||||
* or the client in any way, except to accept or reject the list of mods.</strong>
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface NetworkCheckHandler
|
||||
{
|
||||
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.network;
|
||||
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;
|
||||
|
||||
import org.apache.logging.log4j.Level;
|
||||
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
|
||||
/**
|
||||
* Use this handler as the only thing in your channel, to receive network events
|
||||
* whenever your channel receives a message.
|
||||
* Note: it will not forward on to other handlers.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
@Sharable
|
||||
public class NetworkEventFiringHandler extends SimpleChannelInboundHandler<FMLProxyPacket> {
|
||||
private FMLEventChannel eventChannel;
|
||||
|
||||
NetworkEventFiringHandler(FMLEventChannel fmlEventChannel)
|
||||
{
|
||||
this.eventChannel = fmlEventChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, FMLProxyPacket msg) throws Exception
|
||||
{
|
||||
eventChannel.fireRead(msg,ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception
|
||||
{
|
||||
eventChannel.fireUserEvent(evt,ctx);
|
||||
}
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
|
||||
{
|
||||
FMLLog.log.error("NetworkEventFiringHandler exception", cause);
|
||||
super.exceptionCaught(ctx, cause);
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.network;
|
||||
|
||||
import net.minecraft.network.INetHandler;
|
||||
import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
/**
|
||||
* This message is sent through all channels affected by a currently occurring handshake. It is guaranteed to
|
||||
* be able to send a custom payload packet, however, interaction with minecraft and world state is NOT assured
|
||||
* as it is likely this is fired on a netty handler thread, not a world processing thread.
|
||||
*
|
||||
* If you wish to send an outbound message through your channel, bind the {@link FMLOutboundHandler#FML_MESSAGETARGET}
|
||||
* property of your channel to the supplied dispatcher.
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class NetworkHandshakeEstablished {
|
||||
public final NetworkDispatcher dispatcher;
|
||||
public final Side side;
|
||||
public final INetHandler netHandler;
|
||||
|
||||
public NetworkHandshakeEstablished(NetworkDispatcher dispatcher, INetHandler netHandler, Side origin)
|
||||
{
|
||||
this.netHandler = netHandler;
|
||||
this.dispatcher = dispatcher;
|
||||
this.side = origin;
|
||||
}
|
||||
}
|
|
@ -1,358 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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 net.minecraftforge.fml.common.network;
|
||||
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageCodec;
|
||||
import io.netty.util.AttributeKey;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.network.INetHandler;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.LogicalSide;
|
||||
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher;
|
||||
import net.minecraftforge.fml.common.network.internal.FMLProxyPacket;
|
||||
import net.minecraftforge.fml.common.network.internal.NetworkModHolder;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public class NetworkRegistry
|
||||
{
|
||||
public static final NetworkRegistry INSTANCE = new NetworkRegistry();
|
||||
private EnumMap<LogicalSide,Map<String,FMLEmbeddedChannel>> channels = Maps.newEnumMap(LogicalSide.class);
|
||||
private Map<ModContainer, NetworkModHolder> registry = Maps.newHashMap();
|
||||
private Map<ModContainer, IGuiHandler> serverGuiHandlers = Maps.newHashMap();
|
||||
private Map<ModContainer, IGuiHandler> clientGuiHandlers = Maps.newHashMap();
|
||||
|
||||
/**
|
||||
* Set in the {@link ChannelHandlerContext}
|
||||
*/
|
||||
public static final AttributeKey<String> FML_CHANNEL = AttributeKey.valueOf("fml:channelName");
|
||||
public static final AttributeKey<LogicalSide> CHANNEL_SOURCE = AttributeKey.valueOf("fml:channelSource");
|
||||
public static final AttributeKey<ModContainer> MOD_CONTAINER = AttributeKey.valueOf("fml:modContainer");
|
||||
public static final AttributeKey<INetHandler> NET_HANDLER = AttributeKey.valueOf("fml:netHandler");
|
||||
|
||||
// Version 1: ServerHello only contains this value as a byte
|
||||
// Version 2: ServerHello additionally contains a 4 byte (int) dimension for the logging in client
|
||||
public static final byte FML_PROTOCOL = 2;
|
||||
|
||||
private NetworkRegistry()
|
||||
{
|
||||
channels.put(LogicalSide.CLIENT, Maps.<String,FMLEmbeddedChannel>newConcurrentMap());
|
||||
channels.put(LogicalSide.SERVER, Maps.<String,FMLEmbeddedChannel>newConcurrentMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a target point for the ALLROUNDPOINT target.
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public static class TargetPoint {
|
||||
/**
|
||||
* A target point
|
||||
* @param dimension The dimension to target
|
||||
* @param x The X coordinate
|
||||
* @param y The Y coordinate
|
||||
* @param z The Z coordinate
|
||||
* @param range The range
|
||||
*/
|
||||
public TargetPoint(int dimension, double x, double y, double z, double range)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.range = range;
|
||||
this.dimension = dimension;
|
||||
}
|
||||
public final double x;
|
||||
public final double y;
|
||||
public final double z;
|
||||
public final double range;
|
||||
public final int dimension;
|
||||
}
|
||||
/**
|
||||
* Create a new synchronous message channel pair based on netty.
|
||||
*
|
||||
* There are two preconstructed models available:
|
||||
* <ul>
|
||||
* <li> {@link #newSimpleChannel(String)} provides {@link SimpleNetworkWrapper}, a simple implementation of a netty handler, suitable for those who don't
|
||||
* wish to dive too deeply into netty.
|
||||
* <li> {@link #newEventDrivenChannel(String)} (String)} provides {@link FMLEventChannel} an event driven implementation, with lower level
|
||||
* access to the network data stream, for those with advanced bitbanging needs that don't wish to poke netty too hard.
|
||||
* <li> Alternatively, simply use the netty features provided here and implement the full power of the netty stack.
|
||||
* </ul>
|
||||
*
|
||||
* There are two channels created : one for each logical Dist (conDistred as the source of an outbound message)
|
||||
* The returned map will contain a value for each logical Dist, though both will only be working in the
|
||||
* integrated server case.
|
||||
*
|
||||
* The channel expects to read and write using {@link FMLProxyPacket}. All operation is synchronous, as the
|
||||
* asynchronous behaviour occurs at a lower level in netty.
|
||||
*
|
||||
* The first handler in the pipeline is special and should not be removed or moved from the head - it transforms
|
||||
* packets from the outbound of this pipeline into custom packets, based on the current {@link AttributeKey} value
|
||||
* {@link FMLOutboundHandler#FML_MESSAGETARGET} and {@link FMLOutboundHandler#FML_MESSAGETARGETARGS} set on the channel.
|
||||
* For the client to server channel (source Dist : CLIENT) this is fixed as "TOSERVER". For SERVER to CLIENT packets,
|
||||
* several possible values exist.
|
||||
*
|
||||
* Mod Messages should be transformed using a something akin to a {@link MessageToMessageCodec}. FML provides
|
||||
* a utility codec, {@link FMLIndexedMessageToMessageCodec} that transforms from {@link FMLProxyPacket} to a mod
|
||||
* message using a message discriminator byte. This is optional, but highly recommended for use.
|
||||
*
|
||||
* Note also that the handlers supplied need to be {@link ChannelHandler.Sharable} - they are injected into two
|
||||
* channels.
|
||||
*
|
||||
* @param name
|
||||
* @param handlers
|
||||
* @return
|
||||
*/
|
||||
public EnumMap<LogicalSide,FMLEmbeddedChannel> newChannel(String name, ChannelHandler... handlers)
|
||||
{
|
||||
if (channels.get(LogicalSide.CLIENT).containsKey(name) || channels.get(LogicalSide.SERVER).containsKey(name) || name.startsWith("MC|") || name.startsWith("\u0001") || name.startsWith("FML"))
|
||||
{
|
||||
throw new RuntimeException("That channel is already registered");
|
||||
}
|
||||
EnumMap<LogicalSide, FMLEmbeddedChannel> result = Maps.newEnumMap(LogicalSide.class);
|
||||
|
||||
for (LogicalSide side : LogicalSide.values())
|
||||
{
|
||||
FMLEmbeddedChannel channel = new FMLEmbeddedChannel(name, side, handlers);
|
||||
channels.get(side).put(name,channel);
|
||||
result.put(side, channel);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new {@link SimpleNetworkWrapper} for the channel.
|
||||
*
|
||||
* @param name The name of the channel
|
||||
* @return A {@link SimpleNetworkWrapper} for handling this channel
|
||||
*/
|
||||
public SimpleNetworkWrapper newSimpleChannel(String name)
|
||||
{
|
||||
return new SimpleNetworkWrapper(name);
|
||||
}
|
||||
/**
|
||||
* Construct a new {@link FMLEventChannel} for the channel.
|
||||
*
|
||||
* @param name The name of the channel
|
||||
* @return An {@link FMLEventChannel} for handling this channel
|
||||
*/
|
||||
public FMLEventChannel newEventDrivenChannel(String name)
|
||||
{
|
||||
return new FMLEventChannel(name);
|
||||
}
|
||||
/**
|
||||
* INTERNAL Create a new channel pair with the specified name and channel handlers.
|
||||
* This is used internally in forge and FML
|
||||
*
|
||||
* @param container The container to associate the channel with
|
||||
* @param name The name for the channel
|
||||
* @param handlers Some {@link ChannelHandler} for the channel
|
||||
* @return an {@link EnumMap} of the pair of channels. keys are {@link Dist}. There will always be two entries.
|
||||
*/
|
||||
public EnumMap<LogicalSide,FMLEmbeddedChannel> newChannel(ModContainer container, String name, ChannelHandler... handlers)
|
||||
{
|
||||
if (channels.get(Dist.CLIENT).containsKey(name) || channels.get(Dist.DEDICATED_SERVER).containsKey(name) || name.startsWith("MC|") || name.startsWith("\u0001") || (name.startsWith("FML") && !("FML".equals(container.getModId()))))
|
||||
{
|
||||
throw new RuntimeException("That channel is already registered");
|
||||
}
|
||||
EnumMap<LogicalSide,FMLEmbeddedChannel> result = Maps.newEnumMap(LogicalSide.class);
|
||||
|
||||
for (LogicalSide Dist : LogicalSide.values())
|
||||
{
|
||||
FMLEmbeddedChannel channel = new FMLEmbeddedChannel(container, name, Dist, handlers);
|
||||
channels.get(Dist).put(name,channel);
|
||||
result.put(Dist, channel);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public FMLEmbeddedChannel getChannel(String name, Dist source)
|
||||
{
|
||||
return channels.get(source).get(name);
|
||||
}
|
||||
/**
|
||||
* Register an {@link IGuiHandler} for the supplied mod object.
|
||||
*
|
||||
* @param mod The mod to handle GUIs for
|
||||
* @param handler A handler for creating GUI related objects
|
||||
*/
|
||||
public void registerGuiHandler(Object mod, IGuiHandler handler)
|
||||
{
|
||||
ModContainer mc = FMLCommonHandler.instance().findContainerFor(mod);
|
||||
if (mc == null)
|
||||
{
|
||||
FMLLog.log.error("Mod of type {} attempted to register a gui network handler during a construction phase", mod.getClass().getName());
|
||||
throw new RuntimeException("Invalid attempt to create a GUI during mod construction. Use an EventHandler instead");
|
||||
}
|
||||
serverGuiHandlers.put(mc, handler);
|
||||
clientGuiHandlers.put(mc, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL method for accessing the Gui registry
|
||||
* @param mc Mod Container
|
||||
* @param player Player
|
||||
* @param modGuiId guiId
|
||||
* @param world World
|
||||
* @param x X coord
|
||||
* @param y Y coord
|
||||
* @param z Z coord
|
||||
* @return The server Dist GUI object (An instance of {@link Container})
|
||||
*/
|
||||
@Nullable
|
||||
public Container getRemoteGuiContainer(ModContainer mc, EntityPlayerMP player, int modGuiId, World world, int x, int y, int z)
|
||||
{
|
||||
IGuiHandler handler = serverGuiHandlers.get(mc);
|
||||
|
||||
if (handler != null)
|
||||
{
|
||||
return (Container)handler.getServerGuiElement(modGuiId, player, world, x, y, z);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL method for accessing the Gui registry
|
||||
* @param mc Mod Container
|
||||
* @param player Player
|
||||
* @param modGuiId guiId
|
||||
* @param world World
|
||||
* @param x X coord
|
||||
* @param y Y coord
|
||||
* @param z Z coord
|
||||
* @return The client Dist GUI object (An instance of {@link net.minecraft.client.gui.Gui})
|
||||
*/
|
||||
@Nullable
|
||||
public Object getLocalGuiContainer(ModContainer mc, EntityPlayer player, int modGuiId, World world, int x, int y, int z)
|
||||
{
|
||||
IGuiHandler handler = clientGuiHandlers.get(mc);
|
||||
return handler.getClientGuiElement(modGuiId, player, world, x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is there a channel with this name on this Dist?
|
||||
* @param channelName The name
|
||||
* @param source the Dist
|
||||
* @return if there's a channel
|
||||
*/
|
||||
public boolean hasChannel(String channelName, Dist source)
|
||||
{
|
||||
return channels.get(source).containsKey(channelName);
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL method for registering a mod as a network capable thing
|
||||
* @param fmlModContainer The fml mod container
|
||||
* @param clazz a class
|
||||
* @param remoteVersionRange the acceptable remote range
|
||||
* @param asmHarvestedData internal data
|
||||
*/
|
||||
/*
|
||||
public void register(ModContainer fmlModContainer, Class<?> clazz, @Nullable String remoteVersionRange, ASMDataTable asmHarvestedData)
|
||||
{
|
||||
NetworkModHolder networkModHolder = new NetworkModHolder(fmlModContainer, clazz, remoteVersionRange, asmHarvestedData);
|
||||
registry.put(fmlModContainer, networkModHolder);
|
||||
networkModHolder.testVanillaAcceptance();
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
public boolean isVanillaAccepted(Dist from)
|
||||
{
|
||||
return registry.values().stream()
|
||||
.allMatch(mod -> mod.acceptsVanilla(from));
|
||||
}
|
||||
|
||||
public Collection<String> getRequiredMods(Dist from)
|
||||
{
|
||||
return registry.values().stream()
|
||||
.filter(mod -> !mod.acceptsVanilla(from))
|
||||
.map(mod -> mod.getContainer().getModId())
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
*/
|
||||
|
||||
public Map<ModContainer,NetworkModHolder> registry()
|
||||
{
|
||||
return ImmutableMap.copyOf(registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* All the valid channel names for a Dist
|
||||
* @param Dist the Dist
|
||||
* @return the set of channel names
|
||||
*/
|
||||
public Set<String> channelNamesFor(Dist Dist)
|
||||
{
|
||||
return channels.get(Dist).keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL fire a handshake to all channels
|
||||
* @param networkDispatcher The dispatcher firing
|
||||
* @param origin which Dist the dispatcher is on
|
||||
*/
|
||||
public void fireNetworkHandshake(NetworkDispatcher networkDispatcher, Dist origin)
|
||||
{
|
||||
/*
|
||||
NetworkHandshakeEstablished handshake = new NetworkHandshakeEstablished(networkDispatcher, networkDispatcher.getNetHandler(), origin);
|
||||
for (FMLEmbeddedChannel channel : channels.get(origin).values())
|
||||
{
|
||||
channel.attr(FMLOutboundHandler.FML_MESSAGETARGET).set(OutboundTarget.DISPATCHER);
|
||||
channel.attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(networkDispatcher);
|
||||
channel.pipeline().fireUserEventTriggered(handshake);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public void cleanAttributes()
|
||||
{
|
||||
channels.values().forEach(map -> map.values().forEach(FMLEmbeddedChannel::cleanAttributes));
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue