mirror of
https://github.com/GTNewHorizons/CodeChickenCore.git
synced 2026-10-26 22:33:58 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
162de447d5 | ||
|
|
39ed6607a6 | ||
|
|
99b815c12e | ||
|
|
0f37937ada | ||
|
|
c9d29a5c8e | ||
|
|
ea4f68d163 | ||
|
|
549f769747 | ||
|
|
cba2e0f642 | ||
|
|
3740253590 | ||
|
|
183e658bb4 | ||
|
|
acf5b9a2e7 | ||
|
|
7f78ceb921 | ||
|
|
ce1830d7b5 | ||
|
|
4686fe8fa1 | ||
|
|
4e743ba64b | ||
|
|
c5b8594660 | ||
|
|
87168007d7 | ||
|
|
7b0ab21823 | ||
|
|
dd1abf7ac4 | ||
|
|
14983449e8 | ||
|
|
e8dab57101 | ||
|
|
20b1e28074 | ||
|
|
d6e2b946b1 | ||
|
|
52d522f311 | ||
|
|
c841d484ee | ||
|
|
3145cccd70 | ||
|
|
cc15e4cec6 | ||
|
|
fcb9063f2f | ||
|
|
16883088a6 | ||
|
|
f1034f699e | ||
|
|
83f5eac8d8 | ||
|
|
2cf7226306 | ||
|
|
6273a1e71a | ||
|
|
b52d844ed6 | ||
|
|
331a5fcd3f | ||
|
|
955a875d42 | ||
|
|
b45ef7230d | ||
|
|
de334d86f6 | ||
|
|
777235b7fb | ||
|
|
d183e6d9a9 | ||
|
|
a4515fbef8 | ||
|
|
318c107957 | ||
|
|
fabf2af058 | ||
|
|
f6102d56ec | ||
|
|
9b42fa756f | ||
|
|
fa6fea6843 | ||
|
|
8d95baccb5 | ||
|
|
23327451a2 | ||
|
|
b8a70cb09b | ||
|
|
fcd42c8496 | ||
|
|
c84c6875a1 | ||
|
|
1908388ce7 | ||
|
|
5423d96eb7 | ||
|
|
cfd00f33c8 | ||
|
|
6ff72337b7 | ||
|
|
0d678abc10 | ||
|
|
2e1fc1ece0 | ||
|
|
8933d4cf78 | ||
|
|
35e8b9a956 | ||
|
|
2b7476f2e6 | ||
|
|
19dc507599 | ||
|
|
263864ab82 | ||
|
|
94630e0b2b | ||
|
|
53ac3d0ba7 | ||
|
|
8fe333ed86 | ||
|
|
0ac4906338 | ||
|
|
cea80e20a2 | ||
|
|
2987b36bad | ||
|
|
e9f9253875 | ||
|
|
05bd26eb87 | ||
|
|
42b022af2a | ||
|
|
16f0b50920 | ||
|
|
65a89cc92c | ||
|
|
6b5404f1c0 | ||
|
|
d92b0a6a31 | ||
|
|
ccc986f1d7 | ||
|
|
29e4eda53b | ||
|
|
feb8bfd028 | ||
|
|
4a40b215d5 | ||
|
|
e570e12e13 | ||
|
|
05d1e187f8 | ||
|
|
645919daa9 | ||
|
|
f9287f696b | ||
|
|
38744413af | ||
|
|
71f3c55d9d | ||
|
|
f50b326d92 | ||
|
|
3b081ed3cd | ||
|
|
76a6c9e7d5 | ||
|
|
0ba1132ff6 | ||
|
|
9411dd0808 | ||
|
|
4b16ef2776 | ||
|
|
23a58af62a | ||
|
|
f753dcdeb8 | ||
|
|
18461348e3 | ||
|
|
e7c670b1d3 | ||
|
|
ba15e4b116 | ||
|
|
93b1e5dbf0 | ||
|
|
bdb0c8f174 | ||
|
|
1680d74d6d | ||
|
|
09bf91715b | ||
|
|
97cb16586a | ||
|
|
29ef6904f0 | ||
|
|
0529baaf23 | ||
|
|
3bde4ab9ee | ||
|
|
5c54b184ea | ||
|
|
307ca81694 | ||
|
|
66015a13c5 | ||
|
|
6d19cc0079 | ||
|
|
8386a982a2 | ||
|
|
f1153412c1 | ||
|
|
215715f7c5 | ||
|
|
408e45ef25 | ||
|
|
f9fea33b5e | ||
|
|
47d7c667de | ||
|
|
66fd8ad103 | ||
|
|
1f03959a99 | ||
|
|
52f82017e7 | ||
|
|
0a14b64e12 | ||
|
|
32fa471c44 | ||
|
|
c3dcc42a65 | ||
|
|
12e3060669 | ||
|
|
2d9f409c7d | ||
|
|
41997e15e9 | ||
|
|
d910584217 | ||
|
|
4e87c9bfe7 | ||
|
|
91c65cf1dc | ||
|
|
4699a9e86e | ||
|
|
f56ba57d3a | ||
|
|
4babca7004 | ||
|
|
99865de255 | ||
|
|
0a5aee875b | ||
|
|
ca675b5f31 | ||
|
|
34154fc011 | ||
|
|
23b79b7b15 | ||
|
|
e274d1c512 | ||
|
|
eac0727165 | ||
|
|
ae652f51c2 | ||
|
|
7450370d99 | ||
|
|
477b77e7e1 | ||
|
|
5401f3afb0 | ||
|
|
eb6f5e5e7b | ||
|
|
ffc284349e | ||
|
|
3c81313a8c | ||
|
|
3d64337681 | ||
|
|
6a8a453496 | ||
|
|
16d43f287d | ||
|
|
9e6ac47eba | ||
|
|
8a777b265e | ||
|
|
699221214c | ||
|
|
3e65888097 | ||
|
|
6233c2f6ca | ||
|
|
dd297d6e42 | ||
|
|
a7637ca787 | ||
|
|
a315c0059e | ||
|
|
ddadd1f831 | ||
|
|
112c0abc08 | ||
|
|
3b762d300f | ||
|
|
ab0713c129 | ||
|
|
b1057544a7 | ||
|
|
1b71ee5e3d | ||
|
|
bd3234b033 | ||
|
|
cdb52bf72a | ||
|
|
d889cf9cbc | ||
|
|
f5bbe9d2da | ||
|
|
6a29a2428f | ||
|
|
ea515682c1 | ||
|
|
5c5384f79c | ||
|
|
c67c731647 | ||
|
|
c545683025 | ||
|
|
5ef9f6174d | ||
|
|
0941845227 | ||
|
|
9601c27e9d | ||
|
|
a580ca90a9 | ||
|
|
2636721bec | ||
|
|
3d4e112552 | ||
|
|
575ec57050 | ||
|
|
4bd5aab59a | ||
|
|
7f42cd94e0 | ||
|
|
56776c8149 | ||
|
|
5184abc23c | ||
|
|
b16ad2115b | ||
|
|
15d0edcafb | ||
|
|
a1433ba4d4 | ||
|
|
57bcf384d1 | ||
|
|
16704eb601 | ||
|
|
d6f14e9ab1 | ||
|
|
36e6c64b66 | ||
|
|
a003f2638d | ||
|
|
fed626df0b | ||
|
|
8518ed3bb0 | ||
|
|
a2d3051270 | ||
|
|
9341031e7f | ||
|
|
3c5a61e011 | ||
|
|
0f32dd8620 | ||
|
|
397135f687 |
No files matched your search
@@ -0,0 +1,2 @@
|
||||
# Ignore spotlessApply reformat
|
||||
955a875d42bd8f725d389ef8c4f571824f2ae0c8
|
||||
+36
-27
@@ -1,35 +1,44 @@
|
||||
* text eol=lf
|
||||
|
||||
*.jar binary
|
||||
*.[jJ][aA][rR] binary
|
||||
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.tif binary
|
||||
*.tiff binary
|
||||
*.ico binary
|
||||
*.svg text
|
||||
*.eps binary
|
||||
*.[pP][nN][gG] binary
|
||||
*.[jJ][pP][gG] binary
|
||||
*.[jJ][pP][eE][gG] binary
|
||||
*.[gG][iI][fF] binary
|
||||
*.[tT][iI][fF] binary
|
||||
*.[tT][iI][fF][fF] binary
|
||||
*.[iI][cC][oO] binary
|
||||
*.[sS][vV][gG] text
|
||||
*.[eE][pP][sS] binary
|
||||
*.[xX][cC][fF] binary
|
||||
|
||||
*.kar binary
|
||||
*.m4a binary
|
||||
*.mid binary
|
||||
*.midi binary
|
||||
*.mp3 binary
|
||||
*.ogg binary
|
||||
*.ra binary
|
||||
*.[kK][aA][rR] binary
|
||||
*.[mM]4[aA] binary
|
||||
*.[mM][iI][dD] binary
|
||||
*.[mM][iI][dD][iI] binary
|
||||
*.[mM][pP]3 binary
|
||||
*.[oO][gG][gG] binary
|
||||
*.[rR][aA] binary
|
||||
|
||||
*.7z binary
|
||||
*.gz binary
|
||||
*.tar binary
|
||||
*.tgz binary
|
||||
*.zip binary
|
||||
*.7[zZ] binary
|
||||
*.[gG][zZ] binary
|
||||
*.[tT][aA][rR] binary
|
||||
*.[tT][gG][zZ] binary
|
||||
*.[zZ][iI][pP] binary
|
||||
|
||||
*.patch -text
|
||||
*.[tT][cC][nN] binary
|
||||
*.[sS][oO] binary
|
||||
*.[dD][lL][lL] binary
|
||||
*.[dD][yY][lL][iI][bB] binary
|
||||
*.[pP][sS][dD] binary
|
||||
*.[tT][tT][fF] binary
|
||||
*.[oO][tT][fF] binary
|
||||
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
*.ps1 text eol=crlf
|
||||
*.[pP][aA][tT][cC][hH] -text
|
||||
|
||||
*autogenerated binary
|
||||
*.[bB][aA][tT] text eol=crlf
|
||||
*.[cC][mM][dD] text eol=crlf
|
||||
*.[pP][sS]1 text eol=crlf
|
||||
|
||||
*[aA][uU][tT][oO][gG][eE][nN][eE][rR][aA][tT][eE][dD]* binary
|
||||
@@ -26,3 +26,4 @@ whitelist.json
|
||||
*.ipr
|
||||
*.iws
|
||||
src/main/resources/mixins.*.json
|
||||
*.bat
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
minecraft {
|
||||
if (replaceGradleTokenInFile) {
|
||||
replaceIn "CodeChickenCorePlugin.java"
|
||||
tagReplacementFiles.add "CodeChickenCorePlugin.java"
|
||||
if(gradleTokenVersion) {
|
||||
replace gradleTokenVersion, versionDetails().lastTag
|
||||
injectedTags.put gradleTokenVersion, versionDetails().lastTag
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1113
File diff suppressed because it is too large.
Load diff
@@ -1,5 +1,4 @@
|
||||
// Add your dependencies here
|
||||
|
||||
dependencies {
|
||||
compile('com.github.GTNewHorizons:CodeChickenLib:1.1.5.6:dev')
|
||||
}
|
||||
+160
-23
@@ -1,60 +1,197 @@
|
||||
# ExampleMod tag to use as Blowdryer (Spotless, etc.) settings version, leave empty to disable.
|
||||
# LOCAL to test local config updates.
|
||||
gtnh.settings.blowdryerTag = 0.2.0
|
||||
|
||||
# Human-readable mod name, available for mcmod.info population.
|
||||
modName = CodeChicken Core
|
||||
|
||||
# This is a case-sensitive string to identify your mod. Convention is to use lower case.
|
||||
# Case-sensitive identifier string, available for mcmod.info population and used for automatic mixin JSON generation.
|
||||
# Conventionally lowercase.
|
||||
modId = CodeChickenCore
|
||||
|
||||
# Root package of the mod, used to find various classes in other properties,
|
||||
# mcmod.info substitution, enabling assertions in run tasks, etc.
|
||||
modGroup = codechicken
|
||||
|
||||
# WHY is there no version field?
|
||||
# The build script relies on git to provide a version via tags. It is super easy and will enable you to always know the
|
||||
# code base or your binary. Check out this tutorial: https://blog.mattclemente.com/2017/10/13/versioning-with-git-tags/
|
||||
# Whether to use modGroup as the maven publishing group.
|
||||
# Due to a history of using JitPack, the default is com.github.GTNewHorizons for all mods.
|
||||
useModGroupForPublishing = false
|
||||
|
||||
# Will update your build.gradle automatically whenever an update is available
|
||||
# Updates your build.gradle and settings.gradle automatically whenever an update is available.
|
||||
autoUpdateBuildScript = false
|
||||
|
||||
# Version of Minecraft to target
|
||||
minecraftVersion = 1.7.10
|
||||
|
||||
# Version of Minecraft Forge to target
|
||||
forgeVersion = 10.13.4.1614
|
||||
|
||||
# Select a username for testing your mod with breakpoints. You may leave this empty for a random username each time you
|
||||
# restart Minecraft in development. Choose this dependent on your mod:
|
||||
# Do you need consistent player progressing (for example Thaumcraft)? -> Select a name
|
||||
# Do you need to test how your custom blocks interacts with a player that is not the owner? -> leave name empty
|
||||
# Specify an MCP channel for dependency deobfuscation and the deobfParams task.
|
||||
channel = stable
|
||||
|
||||
# Specify an MCP mappings version for dependency deobfuscation and the deobfParams task.
|
||||
mappingsVersion = 12
|
||||
|
||||
# Defines other MCP mappings for dependency deobfuscation.
|
||||
remoteMappings = https\://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/
|
||||
|
||||
# Select a default username for testing your mod. You can always override this per-run by running
|
||||
# `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE.
|
||||
developmentEnvironmentUserName = Developer
|
||||
|
||||
# Define a source file of your project with:
|
||||
# Enables using modern Java syntax (up to version 17) via Jabel, while still targeting JVM 8.
|
||||
# See https://github.com/bsideup/jabel for details on how this works.
|
||||
enableModernJavaSyntax = true
|
||||
|
||||
# Enables injecting missing generics into the decompiled source code for a better coding experience.
|
||||
# Turns most publicly visible List, Map, etc. into proper List<E>, Map<K, V> types.
|
||||
enableGenericInjection = true
|
||||
|
||||
# Generate a class with a String field for the mod version named as defined below.
|
||||
# If generateGradleTokenClass is empty or not missing, no such class will be generated.
|
||||
# If gradleTokenVersion is empty or missing, the field will not be present in the class.
|
||||
generateGradleTokenClass = codechicken.core.asm.Tags
|
||||
|
||||
# Name of the token containing the project's current version to generate/replace.
|
||||
gradleTokenVersion = VERSION
|
||||
|
||||
# [DEPRECATED] Mod Group replacement token.
|
||||
gradleTokenGroupName =
|
||||
|
||||
# [DEPRECATED]
|
||||
# Multiple source files can be defined here by providing a comma-separated list: Class1.java,Class2.java,Class3.java
|
||||
# public static final String VERSION = "GRADLETOKEN_VERSION";
|
||||
# The string's content will be replaced with your mod's version when compiled. You should use this to specify your mod's
|
||||
# version in @Mod([...], version = VERSION, [...])
|
||||
# Leave these properties empty to skip individual token replacements
|
||||
replaceGradleTokenInFile = CodeChickenCoreModContainer.java
|
||||
gradleTokenModId = GRADLETOKEN_MODID
|
||||
gradleTokenModName = GRADLETOKEN_MODNAME
|
||||
gradleTokenVersion = GRADLETOKEN_VERSION
|
||||
gradleTokenGroupName =
|
||||
# version in @Mod([...], version = VERSION, [...]).
|
||||
# Leave these properties empty to skip individual token replacements.
|
||||
replaceGradleTokenInFile =
|
||||
|
||||
# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can
|
||||
# leave this property empty.
|
||||
# Example value: apiPackage = api + modGroup = com.myname.mymodid -> com.myname.mymodid.api
|
||||
# Example value: (apiPackage = api) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.api
|
||||
apiPackage =
|
||||
|
||||
# Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/META-INF/
|
||||
# Example value: mymodid_at.cfg
|
||||
# There can be multiple files in a space-separated list.
|
||||
# Example value: mymodid_at.cfg nei_at.cfg
|
||||
accessTransformersFile =
|
||||
|
||||
# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled!
|
||||
usesMixins = false
|
||||
# Specify the location of your implementation of IMixinPlugin. Leave it empty otherwise.
|
||||
|
||||
# Set to a non-empty string to configure mixins in a separate source set under src/VALUE, instead of src/main.
|
||||
# This can speed up compile times thanks to not running the mixin annotation processor on all input sources.
|
||||
# Mixin classes will have access to "main" classes, but not the other way around.
|
||||
separateMixinSourceSet =
|
||||
|
||||
# Adds some debug arguments like verbose output and class export.
|
||||
usesMixinDebug = false
|
||||
|
||||
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
|
||||
mixinPlugin =
|
||||
|
||||
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
|
||||
mixinsPackage =
|
||||
|
||||
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
|
||||
# This parameter is for legacy compatibility only
|
||||
# Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin
|
||||
# Example value: (coreModClass = asm.FMLPlugin) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.asm.FMLPlugin
|
||||
coreModClass = core.launch.CodeChickenCorePlugin
|
||||
|
||||
# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class
|
||||
# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false!
|
||||
containsMixinsAndOrCoreModOnly = true
|
||||
|
||||
# If enabled, you may use 'shadowImplementation' for dependencies. They will be integrated in your jar. It is your
|
||||
# responsibility check the licence and request permission for distribution, if required.
|
||||
# Enables Mixins even if this mod doesn't use them, useful if one of the dependencies uses mixins.
|
||||
forceEnableMixins = false
|
||||
|
||||
# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated into your jar. It is your
|
||||
# responsibility to check the license and request permission for distribution if required.
|
||||
usesShadowedDependencies = false
|
||||
|
||||
# If disabled, won't remove unused classes from shadowed dependencies. Some libraries use reflection to access
|
||||
# their own classes, making the minimization unreliable.
|
||||
minimizeShadowedDependencies = true
|
||||
|
||||
# If disabled, won't rename the shadowed classes.
|
||||
relocateShadowedDependencies = true
|
||||
|
||||
# Adds CurseMaven, Modrinth, and some more well-known 1.7.10 repositories.
|
||||
includeWellKnownRepositories = true
|
||||
|
||||
# A list of repositories to exclude from the includeWellKnownRepositories setting. Should be a space separated
|
||||
# list of strings, with the acceptable keys being(case does not matter):
|
||||
# cursemaven
|
||||
# modrinth
|
||||
excludeWellKnownRepositories =
|
||||
|
||||
# Change these to your Maven coordinates if you want to publish to a custom Maven repository instead of the default GTNH Maven.
|
||||
# Authenticate with the MAVEN_USER and MAVEN_PASSWORD environment variables.
|
||||
# If you need a more complex setup disable maven publishing here and add a publishing repository to addon.gradle.
|
||||
usesMavenPublishing = true
|
||||
|
||||
# Maven repository to publish the mod to.
|
||||
# mavenPublishUrl = https\://nexus.gtnewhorizons.com/repository/releases/
|
||||
|
||||
# Publishing to Modrinth requires you to set the MODRINTH_TOKEN environment variable to your current Modrinth API token.
|
||||
#
|
||||
# The project's ID on Modrinth. Can be either the slug or the ID.
|
||||
# Leave this empty if you don't want to publish to Modrinth.
|
||||
modrinthProjectId = codechickencore-unofficial
|
||||
|
||||
# The project's relations on Modrinth. You can use this to refer to other projects on Modrinth.
|
||||
# Syntax: scope1-type1:name1;scope2-type2:name2;...
|
||||
# Where scope can be one of [required, optional, incompatible, embedded],
|
||||
# type can be one of [project, version],
|
||||
# and the name is the Modrinth project or version slug/id of the other mod.
|
||||
# Example: required-project:fplib;optional-project:gasstation;incompatible-project:gregtech
|
||||
# Note: GTNH Mixins is automatically set as a required dependency if usesMixins = true
|
||||
modrinthRelations =
|
||||
|
||||
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
|
||||
#
|
||||
# The project's numeric ID on CurseForge. You can find this in the About Project box.
|
||||
# Leave this empty if you don't want to publish on CurseForge.
|
||||
curseForgeProjectId = 746279
|
||||
|
||||
# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge.
|
||||
# Syntax: type1:name1;type2:name2;...
|
||||
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
|
||||
# and the name is the CurseForge project slug of the other mod.
|
||||
# Example: requiredDependency:railcraft;embeddedLibrary:cofhlib;incompatible:buildcraft
|
||||
# Note: UniMixins is automatically set as a required dependency if usesMixins = true.
|
||||
curseForgeRelations =
|
||||
|
||||
# Optional parameter to customize the produced artifacts. Use this to preserve artifact naming when migrating older
|
||||
# projects. New projects should not use this parameter.
|
||||
# customArchiveBaseName =
|
||||
|
||||
# Optional parameter to have the build automatically fail if an illegal version is used.
|
||||
# This can be useful if you e.g. only want to allow versions in the form of '1.1.xxx'.
|
||||
# The check is ONLY performed if the version is a git tag.
|
||||
# Note: the specified string must be escaped, so e.g. 1\\.1\\.\\d+ instead of 1\.1\.\d+
|
||||
# versionPattern =
|
||||
|
||||
# Uncomment to prevent the source code from being published.
|
||||
# noPublishedSources = true
|
||||
|
||||
# Uncomment this to disable Spotless checks.
|
||||
# This should only be uncommented to keep it easier to sync with upstream/other forks.
|
||||
# That is, if there is no other active fork/upstream, NEVER change this.
|
||||
# disableSpotless = true
|
||||
|
||||
# Uncomment this to disable Checkstyle checks (currently wildcard import check).
|
||||
# disableCheckstyle = true
|
||||
|
||||
# Override the IDEA build type. Valid values are: "" (leave blank, do not override), "idea" (force use native IDEA build), "gradle"
|
||||
# (force use delegated build).
|
||||
# This is meant to be set in $HOME/.gradle/gradle.properties.
|
||||
# e.g. add "systemProp.org.gradle.project.ideaOverrideBuildType=idea" will override the build type to be native build.
|
||||
# WARNING: If you do use this option, it will overwrite whatever you have in your existing projects. This might not be what you want!
|
||||
# Usually there is no need to uncomment this here as other developers do not necessarily use the same build type as you.
|
||||
# ideaOverrideBuildType = idea
|
||||
|
||||
# Whether IDEA should run spotless checks when pressing the Build button.
|
||||
# This is meant to be set in $HOME/.gradle/gradle.properties.
|
||||
# ideaCheckSpotlessOnBuild = true
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+3
-1
@@ -1,5 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -15,80 +15,116 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -97,92 +133,120 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# 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"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
# 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")"
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
Vendored
+27
-33
@@ -13,8 +13,10 @@
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,10 +27,14 @@
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@@ -37,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@@ -51,48 +57,36 @@ goto fail
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
// Add any additional repositiroes for your dependencies here
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
name 'GTNH Maven'
|
||||
url 'http://jenkins.usrv.eu:8081/nexus/content/groups/public/'
|
||||
allowInsecureProtocol
|
||||
}
|
||||
maven {
|
||||
url 'https://jitpack.io'
|
||||
}
|
||||
}
|
||||
+19
-6
@@ -1,10 +1,23 @@
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
maven {
|
||||
// RetroFuturaGradle
|
||||
name "GTNH Maven"
|
||||
url "https://nexus.gtnewhorizons.com/repository/public/"
|
||||
mavenContent {
|
||||
includeGroup("com.gtnewhorizons")
|
||||
includeGroupByRegex("com\\.gtnewhorizons\\..+")
|
||||
}
|
||||
}
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'com.diffplug.blowdryerSetup' version '1.6.0'
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.27'
|
||||
}
|
||||
|
||||
apply plugin: 'com.diffplug.blowdryerSetup'
|
||||
|
||||
blowdryerSetup {
|
||||
github('GTNewHorizons/ExampleMod1.7.10', 'tag', '0.1.5')
|
||||
//devLocal '.' // Use this when testing config updates locally
|
||||
}
|
||||
@@ -1,108 +1,22 @@
|
||||
package codechicken.core;
|
||||
|
||||
import codechicken.core.launch.CodeChickenCorePlugin;
|
||||
import com.google.common.base.Function;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.versioning.ComparableVersion;
|
||||
|
||||
import cpw.mods.fml.relauncher.FMLInjectionData;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.ChatComponentText;
|
||||
import net.minecraft.util.StatCollector;
|
||||
|
||||
public class CCUpdateChecker {
|
||||
private static final ArrayList<String> updates = new ArrayList<String>();
|
||||
|
||||
private static class ThreadUpdateCheck extends Thread {
|
||||
private final URL url;
|
||||
private final Function<String, Void> handler;
|
||||
public static void tick() {}
|
||||
|
||||
public ThreadUpdateCheck(URL url, Function<String, Void> handler) {
|
||||
this.url = url;
|
||||
this.handler = handler;
|
||||
|
||||
setName("CodeChicken Update Checker");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestMethod("GET");
|
||||
conn.setConnectTimeout(5000);
|
||||
conn.setReadTimeout(5000);
|
||||
BufferedReader read = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
String ret = read.readLine();
|
||||
read.close();
|
||||
if (ret == null) ret = "";
|
||||
handler.apply(ret);
|
||||
} catch (SocketTimeoutException ignored) {
|
||||
} catch (UnknownHostException ignored) {
|
||||
} catch (IOException iox) {
|
||||
iox.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void tick() {
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
if (!mc.inGameHasFocus) return;
|
||||
|
||||
synchronized (updates) {
|
||||
for (String s : updates) mc.thePlayer.addChatMessage(new ChatComponentText(s));
|
||||
updates.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static void addUpdateMessage(String s) {
|
||||
synchronized (updates) {
|
||||
updates.add(s);
|
||||
}
|
||||
}
|
||||
public static void addUpdateMessage(String s) {}
|
||||
|
||||
public static String mcVersion() {
|
||||
return (String) FMLInjectionData.data()[4];
|
||||
}
|
||||
|
||||
public static void updateCheck(final String mod, final String version) {
|
||||
updateCheck(
|
||||
"http://www.chickenbones.net/Files/notification/version.php?" + "version="
|
||||
+ mcVersion() + "&" + "file="
|
||||
+ mod,
|
||||
new Function<String, Void>() {
|
||||
@Override
|
||||
public Void apply(String ret) {
|
||||
if (!ret.startsWith("Ret: ")) {
|
||||
CodeChickenCorePlugin.logger.error(
|
||||
"Failed to check update for " + mod + " returned: " + ret);
|
||||
return null;
|
||||
}
|
||||
ComparableVersion newversion = new ComparableVersion(ret.substring(5));
|
||||
if (newversion.compareTo(new ComparableVersion(version)) > 0)
|
||||
addUpdateMessage(
|
||||
StatCollector.translateToLocalFormatted("codechickencore.update", newversion, mod));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
public static void updateCheck(final String mod, final String version) {}
|
||||
|
||||
public static void updateCheck(String mod) {
|
||||
updateCheck(mod, Loader.instance().getIndexedModList().get(mod).getVersion());
|
||||
}
|
||||
public static void updateCheck(String mod) {}
|
||||
|
||||
public static void updateCheck(String url, Function<String, Void> handler) {
|
||||
try {
|
||||
new ThreadUpdateCheck(new URL(url), handler).start();
|
||||
} catch (MalformedURLException e) {
|
||||
CodeChickenCorePlugin.logger.error("Malformed URL: " + url, e);
|
||||
}
|
||||
}
|
||||
public static void updateCheck(String url, Function<String, Void> handler) {}
|
||||
}
|
||||
@@ -1,12 +1,5 @@
|
||||
package codechicken.core;
|
||||
|
||||
import codechicken.core.launch.CodeChickenCorePlugin;
|
||||
import codechicken.lib.asm.ASMHelper;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModClassLoader;
|
||||
import cpw.mods.fml.relauncher.CoreModManager;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -15,10 +8,22 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import codechicken.core.launch.CodeChickenCorePlugin;
|
||||
import codechicken.lib.asm.ASMHelper;
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModClassLoader;
|
||||
import cpw.mods.fml.relauncher.CoreModManager;
|
||||
|
||||
public class ClassDiscoverer {
|
||||
|
||||
public IStringMatcher matcher;
|
||||
public String[] superclasses;
|
||||
public ArrayList<Class<?>> classes;
|
||||
@@ -35,13 +40,12 @@ public class ClassDiscoverer {
|
||||
}
|
||||
|
||||
public ClassDiscoverer(Class<?>... superclasses) {
|
||||
this(
|
||||
new IStringMatcher() {
|
||||
public boolean matches(String test) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
superclasses);
|
||||
this(new IStringMatcher() {
|
||||
|
||||
public boolean matches(String test) {
|
||||
return true;
|
||||
}
|
||||
}, superclasses);
|
||||
}
|
||||
|
||||
public ArrayList<Class<?>> findClasses() {
|
||||
@@ -79,10 +83,8 @@ public class ClassDiscoverer {
|
||||
}
|
||||
|
||||
private void findClasspathMods() {
|
||||
List<String> knownLibraries = ImmutableList.<String>builder()
|
||||
.addAll(modClassLoader.getDefaultLibraries())
|
||||
.addAll(CoreModManager.getLoadedCoremods())
|
||||
.build();
|
||||
List<String> knownLibraries = ImmutableList.<String>builder().addAll(modClassLoader.getDefaultLibraries())
|
||||
.addAll(CoreModManager.getLoadedCoremods()).build();
|
||||
File[] minecraftSources = modClassLoader.getParentSources();
|
||||
HashSet<String> searchedSources = new HashSet<String>();
|
||||
for (File minecraftSource : minecraftSources) {
|
||||
@@ -98,7 +100,8 @@ public class ClassDiscoverer {
|
||||
readFromZipFile(minecraftSource);
|
||||
} catch (Exception e) {
|
||||
CodeChickenCorePlugin.logger.error(
|
||||
"Failed to scan " + minecraftSource.getAbsolutePath() + ", the zip file is invalid", e);
|
||||
"Failed to scan " + minecraftSource.getAbsolutePath() + ", the zip file is invalid",
|
||||
e);
|
||||
}
|
||||
}
|
||||
} else if (minecraftSource.isDirectory()) {
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package codechicken.core;
|
||||
|
||||
import codechicken.core.internal.CCCEventHandler;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
@@ -12,7 +7,14 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import codechicken.core.internal.CCCEventHandler;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class ClientUtils extends CommonUtils {
|
||||
|
||||
private static Minecraft mc() {
|
||||
return Minecraft.getMinecraft();
|
||||
}
|
||||
@@ -22,7 +24,7 @@ public class ClientUtils extends CommonUtils {
|
||||
}
|
||||
|
||||
public static boolean inWorld() // TODO unused
|
||||
{
|
||||
{
|
||||
return mc().getNetHandler() != null;
|
||||
}
|
||||
|
||||
@@ -59,8 +61,8 @@ public class ClientUtils extends CommonUtils {
|
||||
|
||||
public static void enhanceSupportersList(Object mod) {
|
||||
ModContainer mc = FMLCommonHandler.instance().findContainerFor(mod);
|
||||
mc.getMetadata().description =
|
||||
mc.getMetadata().description.replace("Supporters:", EnumChatFormatting.AQUA + "Supporters:");
|
||||
mc.getMetadata().description = mc.getMetadata().description
|
||||
.replace("Supporters:", EnumChatFormatting.AQUA + "Supporters:");
|
||||
GuiModListScroll.register(mod);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
package codechicken.core;
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.relauncher.FMLInjectionData;
|
||||
import java.io.File;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityList;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.relauncher.FMLInjectionData;
|
||||
|
||||
public class CommonUtils {
|
||||
|
||||
public static boolean isClient() {
|
||||
return FMLCommonHandler.instance().getSide().isClient();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,39 @@
|
||||
package codechicken.core;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
import static org.lwjgl.opengl.GL11.GL_ALWAYS;
|
||||
import static org.lwjgl.opengl.GL11.GL_EQUAL;
|
||||
import static org.lwjgl.opengl.GL11.GL_KEEP;
|
||||
import static org.lwjgl.opengl.GL11.GL_PACK_ALIGNMENT;
|
||||
import static org.lwjgl.opengl.GL11.GL_REPLACE;
|
||||
import static org.lwjgl.opengl.GL11.GL_STENCIL_INDEX;
|
||||
import static org.lwjgl.opengl.GL11.GL_STENCIL_TEST;
|
||||
import static org.lwjgl.opengl.GL11.GL_UNPACK_ALIGNMENT;
|
||||
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
|
||||
import static org.lwjgl.opengl.GL11.GL_ZERO;
|
||||
import static org.lwjgl.opengl.GL11.glColorMask;
|
||||
import static org.lwjgl.opengl.GL11.glDisable;
|
||||
import static org.lwjgl.opengl.GL11.glEnable;
|
||||
import static org.lwjgl.opengl.GL11.glPixelStorei;
|
||||
import static org.lwjgl.opengl.GL11.glReadPixels;
|
||||
import static org.lwjgl.opengl.GL11.glStencilFunc;
|
||||
import static org.lwjgl.opengl.GL11.glStencilOp;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.MinecraftForgeClient;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.core.launch.CodeChickenCorePlugin;
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
@@ -10,21 +42,9 @@ import cpw.mods.fml.client.GuiModList;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import cpw.mods.fml.common.ModMetadata;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import javax.imageio.ImageIO;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.MinecraftForgeClient;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class GuiModListScroll {
|
||||
|
||||
private static List<ModContainer> scrollMods = new LinkedList<ModContainer>();
|
||||
|
||||
public static void register(Object mod) {
|
||||
@@ -45,9 +65,8 @@ public class GuiModListScroll {
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glReadPixels(0, 0, d.width, d.height, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buf);
|
||||
for (int i = 0; i < d.width; i++)
|
||||
for (int j = 0; j < d.height; j++)
|
||||
img.setRGB(i, d.height - j - 1, buf.get(j * d.width + i) == 0 ? 0 : 0xFFFFFF);
|
||||
for (int i = 0; i < d.width; i++) for (int j = 0; j < d.height; j++)
|
||||
img.setRGB(i, d.height - j - 1, buf.get(j * d.width + i) == 0 ? 0 : 0xFFFFFF);
|
||||
try {
|
||||
ImageIO.write(img, "png", new File("stencil" + x + ".png"));
|
||||
} catch (IOException e) {
|
||||
@@ -109,9 +128,7 @@ public class GuiModListScroll {
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
|
||||
String description = selectedMod.getMetadata().description;
|
||||
int height = GuiDraw.fontRenderer
|
||||
.listFormattedStringToWidth(description, x2 - x1)
|
||||
.size()
|
||||
int height = GuiDraw.fontRenderer.listFormattedStringToWidth(description, x2 - x1).size()
|
||||
* GuiDraw.fontRenderer.FONT_HEIGHT;
|
||||
|
||||
boolean needsScroll = height > y2 - y1draw;
|
||||
@@ -142,8 +159,8 @@ public class GuiModListScroll {
|
||||
}
|
||||
|
||||
/**
|
||||
* Does not add the last 10 px space before the description normally starts
|
||||
* Ignores empty child mods expecting a background draw overwrite
|
||||
* Does not add the last 10 px space before the description normally starts Ignores empty child mods expecting a
|
||||
* background draw overwrite
|
||||
*/
|
||||
private static int calcDescY(GuiModList gui, ModContainer mod) {
|
||||
ModMetadata meta = mod.getMetadata();
|
||||
|
||||
@@ -3,5 +3,6 @@ package codechicken.core;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
|
||||
public interface IGuiPacketSender {
|
||||
|
||||
void sendPacket(EntityPlayerMP player, int windowId);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package codechicken.core;
|
||||
|
||||
public interface IStringMatcher {
|
||||
|
||||
public boolean matches(String test);
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package codechicken.core;
|
||||
import codechicken.core.launch.CodeChickenCorePlugin;
|
||||
|
||||
public class ProfileTimer {
|
||||
|
||||
public double decay;
|
||||
public long startTime;
|
||||
public long nanoTime;
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
package codechicken.core;
|
||||
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
|
||||
public class ReflectionManager {
|
||||
|
||||
public static HashMap<Class<?>, Class<?>> primitiveWrappers = new HashMap<Class<?>, Class<?>>();
|
||||
|
||||
static {
|
||||
@@ -27,12 +29,12 @@ public class ReflectionManager {
|
||||
if (primitive == Long.class && Long.class.isInstance(obj)) return true;
|
||||
if ((primitive == Long.class || primitive == Integer.class) && Integer.class.isInstance(obj)) return true;
|
||||
if ((primitive == Long.class || primitive == Integer.class || primitive == Short.class)
|
||||
&& Short.class.isInstance(obj)) return true;
|
||||
if ((primitive == Long.class
|
||||
|| primitive == Integer.class
|
||||
|| primitive == Short.class
|
||||
|| primitive == Byte.class)
|
||||
&& Integer.class.isInstance(obj)) return true;
|
||||
&& Short.class.isInstance(obj))
|
||||
return true;
|
||||
if ((primitive == Long.class || primitive == Integer.class
|
||||
|| primitive == Short.class
|
||||
|| primitive == Byte.class) && Integer.class.isInstance(obj))
|
||||
return true;
|
||||
|
||||
if (primitive == Double.class && Double.class.isInstance(obj)) return true;
|
||||
if ((primitive == Double.class || primitive == Float.class) && Float.class.isInstance(obj)) return true;
|
||||
@@ -64,7 +66,7 @@ public class ReflectionManager {
|
||||
|
||||
public static void setField(Class<?> class1, Object instance, String name, Object value)
|
||||
throws IllegalArgumentException, IllegalAccessException {
|
||||
setField(class1, instance, new String[] {name}, value);
|
||||
setField(class1, instance, new String[] { name }, value);
|
||||
}
|
||||
|
||||
public static void setField(Class<?> class1, Object instance, String[] names, Object value)
|
||||
@@ -95,19 +97,15 @@ public class ReflectionManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function
|
||||
* void return type
|
||||
* single name
|
||||
* Static function void return type single name
|
||||
*/
|
||||
public static void callMethod(Class<?> class1, String name, Object... params)
|
||||
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
|
||||
callMethod(class1, null, new String[] {name}, params);
|
||||
callMethod(class1, null, new String[] { name }, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function
|
||||
* void return type
|
||||
* single name
|
||||
* Static function void return type single name
|
||||
*/
|
||||
public static void callMethod(Class<?> class1, String[] names, Object... params)
|
||||
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
|
||||
@@ -115,12 +113,11 @@ public class ReflectionManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* void return type
|
||||
* single name
|
||||
* void return type single name
|
||||
*/
|
||||
public static void callMethod(Class<?> class1, Object instance, String name, Object... params)
|
||||
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
|
||||
callMethod(class1, null, instance, new String[] {name}, params);
|
||||
callMethod(class1, null, instance, new String[] { name }, params);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,12 +129,11 @@ public class ReflectionManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method
|
||||
* single name
|
||||
* Static method single name
|
||||
*/
|
||||
public static <R> R callMethod(Class<?> class1, Class<R> returntype, String name, Object... params)
|
||||
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
|
||||
return callMethod(class1, returntype, null, new String[] {name}, params);
|
||||
return callMethod(class1, returntype, null, new String[] { name }, params);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,14 +149,12 @@ public class ReflectionManager {
|
||||
*/
|
||||
public static <R> R callMethod(Class<?> class1, Class<R> returntype, Object instance, String name, Object... params)
|
||||
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
|
||||
return callMethod(class1, returntype, instance, new String[] {name}, params);
|
||||
return callMethod(class1, returntype, instance, new String[] { name }, params);
|
||||
}
|
||||
|
||||
public static <R> R callMethod(
|
||||
Class<?> class1, Class<R> returntype, Object instance, String[] names, Object... params)
|
||||
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
|
||||
nextMethod:
|
||||
for (Method method : class1.getDeclaredMethods()) {
|
||||
public static <R> R callMethod(Class<?> class1, Class<R> returntype, Object instance, String[] names,
|
||||
Object... params) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
|
||||
nextMethod: for (Method method : class1.getDeclaredMethods()) {
|
||||
boolean match = false;
|
||||
for (String name : names) {
|
||||
if (method.getName().equals(name)) {
|
||||
@@ -204,8 +198,7 @@ public class ReflectionManager {
|
||||
|
||||
public static <T> T newInstance(Class<T> class1, Object... params)
|
||||
throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
|
||||
nextMethod:
|
||||
for (Constructor<?> constructor : class1.getDeclaredConstructors()) {
|
||||
nextMethod: for (Constructor<?> constructor : class1.getDeclaredConstructors()) {
|
||||
Class<?>[] paramtypes = constructor.getParameterTypes();
|
||||
if (paramtypes.length != params.length) continue;
|
||||
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
package codechicken.core;
|
||||
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
|
||||
public class ServerUtils extends CommonUtils {
|
||||
|
||||
public static MinecraftServer mc() {
|
||||
return MinecraftServer.getServer();
|
||||
}
|
||||
@@ -49,17 +53,18 @@ public class ServerUtils extends CommonUtils {
|
||||
|
||||
static {
|
||||
try {
|
||||
field_152661_c = ReflectionManager.getField(new ObfMapping(
|
||||
"net/minecraft/server/management/PlayerProfileCache", "field_152661_c", "[Ljava/util/Map;"));
|
||||
c_ProfileEntry = ServerUtils.class
|
||||
.getClassLoader()
|
||||
field_152661_c = ReflectionManager.getField(
|
||||
new ObfMapping(
|
||||
"net/minecraft/server/management/PlayerProfileCache",
|
||||
"field_152661_c",
|
||||
"[Ljava/util/Map;"));
|
||||
c_ProfileEntry = ServerUtils.class.getClassLoader()
|
||||
.loadClass("net.minecraft.server.management.PlayerProfileCache$ProfileEntry");
|
||||
func_152668_a = c_ProfileEntry.getDeclaredMethod(new ObfMapping(
|
||||
func_152668_a = c_ProfileEntry.getDeclaredMethod(
|
||||
new ObfMapping(
|
||||
"net/minecraft/server/management/PlayerProfileCache$ProfileEntry",
|
||||
"func_152668_a",
|
||||
"()Lcom/mojang/authlib/GameProfile;")
|
||||
.toRuntime()
|
||||
.s_name);
|
||||
"()Lcom/mojang/authlib/GameProfile;").toRuntime().s_name);
|
||||
func_152668_a.setAccessible(true);
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -6,7 +6,9 @@ import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class TaskProfiler {
|
||||
|
||||
public static class ProfilerResult {
|
||||
|
||||
public final String name;
|
||||
public final long time;
|
||||
public final double fraction;
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import cpw.mods.fml.common.asm.transformers.AccessTransformer;
|
||||
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
import cpw.mods.fml.common.asm.transformers.AccessTransformer;
|
||||
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;
|
||||
|
||||
public class CodeChickenAccessTransformer extends AccessTransformer {
|
||||
|
||||
private static boolean makeAllPublic;
|
||||
private static Field f_classNameBiMap;
|
||||
private static Object emptyMap = ImmutableBiMap.of();
|
||||
@@ -20,12 +23,10 @@ public class CodeChickenAccessTransformer extends AccessTransformer {
|
||||
private void loadPublicConfig() {
|
||||
if (ObfMapping.obfuscated) return;
|
||||
|
||||
makeAllPublic = CodeChickenCoreModContainer.config
|
||||
.getTag("dev.runtimePublic")
|
||||
.setComment(
|
||||
"Enabling this setting will make all minecraft classes public at runtime in MCP just as they are in modloader."
|
||||
+ "\nYou should ONLY use this when you are testing with a mod that relies on runtime publicity and doesn't include access transformers."
|
||||
+ "\nSuch mods are doing the wrong thing and should be fixed.")
|
||||
makeAllPublic = CodeChickenCoreModContainer.config.getTag("dev.runtimePublic").setComment(
|
||||
"Enabling this setting will make all minecraft classes public at runtime in MCP just as they are in modloader."
|
||||
+ "\nYou should ONLY use this when you are testing with a mod that relies on runtime publicity and doesn't include access transformers."
|
||||
+ "\nSuch mods are doing the wrong thing and should be fixed.")
|
||||
.getBooleanValue(false);
|
||||
|
||||
if (!makeAllPublic) return;
|
||||
|
||||
@@ -1,25 +1,31 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
import codechicken.core.CCUpdateChecker;
|
||||
import java.io.File;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import codechicken.core.ClientUtils;
|
||||
import codechicken.core.featurehack.LiquidTextures;
|
||||
import codechicken.core.internal.CCCEventHandler;
|
||||
import codechicken.core.launch.CodeChickenCorePlugin;
|
||||
import codechicken.lib.config.ConfigFile;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import cpw.mods.fml.common.*;
|
||||
import cpw.mods.fml.common.DummyModContainer;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.LoadController;
|
||||
import cpw.mods.fml.common.ModMetadata;
|
||||
import cpw.mods.fml.common.event.FMLInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.versioning.ArtifactVersion;
|
||||
import cpw.mods.fml.common.versioning.VersionParser;
|
||||
import cpw.mods.fml.common.versioning.VersionRange;
|
||||
import java.io.File;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
public class CodeChickenCoreModContainer extends DummyModContainer {
|
||||
|
||||
public static ConfigFile config;
|
||||
|
||||
public static void loadConfig() {
|
||||
@@ -34,9 +40,9 @@ public class CodeChickenCoreModContainer extends DummyModContainer {
|
||||
|
||||
private static ModMetadata getModMetadata() {
|
||||
final ModMetadata modMetadata = new ModMetadata();
|
||||
modMetadata.name = "GRADLETOKEN_MODNAME";
|
||||
modMetadata.modId = "GRADLETOKEN_MODID";
|
||||
modMetadata.version = "GRADLETOKEN_VERSION";
|
||||
modMetadata.name = "CodeChicken Core";
|
||||
modMetadata.modId = "CodeChickenCore";
|
||||
modMetadata.version = Tags.VERSION;
|
||||
return modMetadata;
|
||||
}
|
||||
|
||||
@@ -68,8 +74,6 @@ public class CodeChickenCoreModContainer extends DummyModContainer {
|
||||
@Subscribe
|
||||
public void init(FMLInitializationEvent event) {
|
||||
if (event.getSide().isClient()) {
|
||||
if (config.getTag("checkUpdates").getBooleanValue(true)) CCUpdateChecker.updateCheck(getModId());
|
||||
|
||||
ClientUtils.enhanceSupportersList("CodeChickenCore");
|
||||
|
||||
FMLCommonHandler.instance().bus().register(new CCCEventHandler());
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
import codechicken.lib.asm.ASMHelper;
|
||||
import codechicken.lib.asm.ClassHeirachyManager;
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import codechicken.lib.asm.ASMHelper;
|
||||
import codechicken.lib.asm.ClassHeirachyManager;
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
|
||||
public class DefaultImplementationTransformer implements IClassTransformer {
|
||||
|
||||
private static LaunchClassLoader cl = (LaunchClassLoader) ClassHeirachyManager.class.getClassLoader();
|
||||
|
||||
private static ClassNode getClassNode(String name) {
|
||||
@@ -25,6 +29,7 @@ public class DefaultImplementationTransformer implements IClassTransformer {
|
||||
}
|
||||
|
||||
static class InterfaceImpl {
|
||||
|
||||
public final String iname;
|
||||
public ArrayList<MethodNode> impls = new ArrayList<MethodNode>();
|
||||
|
||||
@@ -35,11 +40,10 @@ public class DefaultImplementationTransformer implements IClassTransformer {
|
||||
for (MethodNode method : inode.methods) names.add(method.name + method.desc);
|
||||
|
||||
ClassNode cnode = getClassNode(cname);
|
||||
for (MethodNode method : cnode.methods)
|
||||
if (names.contains(method.name + method.desc)) {
|
||||
impls.add(method);
|
||||
method.desc = new ObfMapping(cnode.name, method.name, method.desc).toRuntime().s_desc;
|
||||
}
|
||||
for (MethodNode method : cnode.methods) if (names.contains(method.name + method.desc)) {
|
||||
impls.add(method);
|
||||
method.desc = new ObfMapping(cnode.name, method.name, method.desc).toRuntime().s_desc;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean patch(ClassNode cnode) {
|
||||
|
||||
@@ -13,13 +13,16 @@ import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
public class DelegatedTransformer implements IClassTransformer {
|
||||
|
||||
private static ArrayList<IClassTransformer> delegatedTransformers;
|
||||
private static Method m_defineClass;
|
||||
private static Field f_cachedClasses;
|
||||
@@ -27,8 +30,8 @@ public class DelegatedTransformer implements IClassTransformer {
|
||||
public DelegatedTransformer() {
|
||||
delegatedTransformers = new ArrayList<IClassTransformer>();
|
||||
try {
|
||||
m_defineClass = ClassLoader.class.getDeclaredMethod(
|
||||
"defineClass", String.class, byte[].class, Integer.TYPE, Integer.TYPE);
|
||||
m_defineClass = ClassLoader.class
|
||||
.getDeclaredMethod("defineClass", String.class, byte[].class, Integer.TYPE, Integer.TYPE);
|
||||
m_defineClass.setAccessible(true);
|
||||
f_cachedClasses = LaunchClassLoader.class.getDeclaredField("cachedClasses");
|
||||
f_cachedClasses.setAccessible(true);
|
||||
@@ -53,9 +56,10 @@ public class DelegatedTransformer implements IClassTransformer {
|
||||
if (bytes == null) {
|
||||
String resourceName = transformer.replace('.', '/') + ".class";
|
||||
ZipEntry entry = jar.getEntry(resourceName);
|
||||
if (entry == null)
|
||||
throw new Exception("Failed to add transformer: " + transformer + ". Entry not found in jar file "
|
||||
+ jarFile.getName());
|
||||
if (entry == null) throw new Exception(
|
||||
"Failed to add transformer: " + transformer
|
||||
+ ". Entry not found in jar file "
|
||||
+ jarFile.getName());
|
||||
|
||||
bytes = readFully(jar.getInputStream(entry));
|
||||
}
|
||||
@@ -63,14 +67,12 @@ public class DelegatedTransformer implements IClassTransformer {
|
||||
defineDependancies(bytes, jar, jarFile);
|
||||
Class<?> clazz = defineClass(transformer, bytes);
|
||||
|
||||
if (!IClassTransformer.class.isAssignableFrom(clazz))
|
||||
throw new Exception(
|
||||
"Failed to add transformer: " + transformer + " is not an instance of IClassTransformer");
|
||||
if (!IClassTransformer.class.isAssignableFrom(clazz)) throw new Exception(
|
||||
"Failed to add transformer: " + transformer + " is not an instance of IClassTransformer");
|
||||
|
||||
IClassTransformer classTransformer;
|
||||
try {
|
||||
classTransformer = (IClassTransformer)
|
||||
clazz.getDeclaredConstructor(File.class).newInstance(jarFile);
|
||||
classTransformer = (IClassTransformer) clazz.getDeclaredConstructor(File.class).newInstance(jarFile);
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
classTransformer = (IClassTransformer) clazz.newInstance();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.Label;
|
||||
@@ -12,9 +13,11 @@ import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
public class DependancyLister extends ClassVisitor {
|
||||
|
||||
private static Pattern classdesc = Pattern.compile("L(.+?);");
|
||||
|
||||
private class DependancyMethodLister extends MethodVisitor {
|
||||
|
||||
public DependancyMethodLister(int api) {
|
||||
super(api);
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
@Target({ ElementType.TYPE })
|
||||
public @interface InterfaceDependancies {}
|
||||
@@ -1,5 +1,28 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import codechicken.lib.asm.ASMHelper;
|
||||
import codechicken.lib.asm.ASMInit;
|
||||
import codechicken.lib.asm.CC_ClassWriter;
|
||||
@@ -7,30 +30,17 @@ import codechicken.lib.asm.ObfMapping;
|
||||
import codechicken.obfuscator.IHeirachyEvaluator;
|
||||
import codechicken.obfuscator.ObfuscationMap.ObfuscationEntry;
|
||||
import codechicken.obfuscator.ObfuscationRun;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import cpw.mods.fml.common.asm.transformers.AccessTransformer;
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
public class MCPDeobfuscationTransformer implements IClassTransformer, Opcodes, IHeirachyEvaluator {
|
||||
|
||||
static {
|
||||
ASMInit.init();
|
||||
}
|
||||
|
||||
public static class LoadPlugin implements IFMLLoadingPlugin {
|
||||
|
||||
@Override
|
||||
public String[] getASMTransformerClass() {
|
||||
return new String[0];
|
||||
@@ -72,8 +82,8 @@ public class MCPDeobfuscationTransformer implements IClassTransformer, Opcodes,
|
||||
try {
|
||||
f_transformers = LaunchClassLoader.class.getDeclaredField("transformers");
|
||||
f_modifiers = AccessTransformer.class.getDeclaredField("modifiers");
|
||||
Class<?> c_Modifier =
|
||||
Class.forName(AccessTransformer.class.getName() + "$Modifier", false, Launch.classLoader);
|
||||
Class<?> c_Modifier = Class
|
||||
.forName(AccessTransformer.class.getName() + "$Modifier", false, Launch.classLoader);
|
||||
f_Modifier_name = c_Modifier.getDeclaredField("name");
|
||||
f_Modifier_desc = c_Modifier.getDeclaredField("desc");
|
||||
|
||||
@@ -110,8 +120,7 @@ public class MCPDeobfuscationTransformer implements IClassTransformer, Opcodes,
|
||||
public static void load() {
|
||||
CodeChickenCoreModContainer.loadConfig();
|
||||
|
||||
if (CodeChickenCoreModContainer.config
|
||||
.getTag("dev.deobfuscate")
|
||||
if (CodeChickenCoreModContainer.config.getTag("dev.deobfuscate")
|
||||
.setComment("set to true to completely deobfuscate mcp names")
|
||||
.getBooleanValue(!ObfMapping.obfuscated)) {
|
||||
run = new ObfuscationRun(
|
||||
@@ -120,8 +129,7 @@ public class MCPDeobfuscationTransformer implements IClassTransformer, Opcodes,
|
||||
ObfuscationRun.fillDefaults(new HashMap<String, String>()));
|
||||
run.obf.setHeirachyEvaluator(instance);
|
||||
run.setQuiet().parseMappings();
|
||||
Collections.addAll(
|
||||
excludedPackages, run.config.get("excludedPackages").split(";"));
|
||||
Collections.addAll(excludedPackages, run.config.get("excludedPackages").split(";"));
|
||||
|
||||
if (ObfMapping.obfuscated) {
|
||||
ObfMapping.loadMCPRemapper();
|
||||
@@ -151,8 +159,12 @@ public class MCPDeobfuscationTransformer implements IClassTransformer, Opcodes,
|
||||
private byte[] injectCallback(byte[] bytes) {
|
||||
ClassNode cnode = ASMHelper.createClassNode(bytes);
|
||||
MethodNode mnode = ASMHelper.findMethod(new ObfMapping(cnode.name, "<clinit>", "()V"), cnode);
|
||||
mnode.instructions.insert(new MethodInsnNode(
|
||||
INVOKESTATIC, "codechicken/core/asm/MCPDeobfuscationTransformer", "loadCallback", "()V"));
|
||||
mnode.instructions.insert(
|
||||
new MethodInsnNode(
|
||||
INVOKESTATIC,
|
||||
"codechicken/core/asm/MCPDeobfuscationTransformer",
|
||||
"loadCallback",
|
||||
"()V"));
|
||||
return ASMHelper.createBytes(cnode, 0);
|
||||
}
|
||||
|
||||
@@ -205,8 +217,7 @@ public class MCPDeobfuscationTransformer implements IClassTransformer, Opcodes,
|
||||
try {
|
||||
byte[] bytes = Launch.classLoader.getClassBytes(name);
|
||||
if (bytes != null) return ObfuscationRun.getParents(ASMHelper.createClassNode(bytes));
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
// clear the miss cache because the library containing it might be loaded later
|
||||
Launch.classLoader.clearNegativeEntries(Collections.singleton(name));
|
||||
return null;
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
import static org.objectweb.asm.Opcodes.ASM4;
|
||||
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.util.Printer;
|
||||
import org.objectweb.asm.util.TraceMethodVisitor;
|
||||
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
|
||||
public class MethodASMifier extends ClassVisitor {
|
||||
|
||||
PrintWriter printWriter;
|
||||
ObfMapping method;
|
||||
Printer asmifier;
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
import static codechicken.lib.asm.InsnComparator.*;
|
||||
import static codechicken.lib.asm.InsnComparator.findOnce;
|
||||
|
||||
import codechicken.lib.asm.*;
|
||||
import codechicken.lib.asm.ModularASMTransformer.MethodReplacer;
|
||||
import codechicken.lib.asm.ModularASMTransformer.MethodTransformer;
|
||||
import codechicken.lib.asm.ModularASMTransformer.MethodWriter;
|
||||
import codechicken.lib.config.ConfigTag;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import codechicken.lib.asm.ASMBlock;
|
||||
import codechicken.lib.asm.ASMInit;
|
||||
import codechicken.lib.asm.ASMReader;
|
||||
import codechicken.lib.asm.ModularASMTransformer;
|
||||
import codechicken.lib.asm.ModularASMTransformer.MethodReplacer;
|
||||
import codechicken.lib.asm.ModularASMTransformer.MethodTransformer;
|
||||
import codechicken.lib.asm.ModularASMTransformer.MethodWriter;
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
import codechicken.lib.config.ConfigTag;
|
||||
|
||||
public class TweakTransformer implements IClassTransformer, Opcodes {
|
||||
|
||||
static {
|
||||
ASMInit.init();
|
||||
}
|
||||
@@ -25,43 +33,42 @@ public class TweakTransformer implements IClassTransformer, Opcodes {
|
||||
|
||||
public static void load() {
|
||||
CodeChickenCoreModContainer.loadConfig();
|
||||
tweaks = CodeChickenCoreModContainer.config
|
||||
.getTag("tweaks")
|
||||
.setComment("Various tweaks that can be applied to game mechanics.")
|
||||
.useBraces();
|
||||
tweaks = CodeChickenCoreModContainer.config.getTag("tweaks")
|
||||
.setComment("Various tweaks that can be applied to game mechanics.").useBraces();
|
||||
tweaks.removeTag("persistantLava");
|
||||
|
||||
if (tweaks.getTag("environmentallyFriendlyCreepers")
|
||||
.setComment(
|
||||
"If set to true, creepers will not destroy landscape. (A version of mobGriefing setting just for creepers)")
|
||||
if (tweaks.getTag("environmentallyFriendlyCreepers").setComment(
|
||||
"If set to true, creepers will not destroy landscape. (A version of mobGriefing setting just for creepers)")
|
||||
.getBooleanValue(false)) {
|
||||
transformer.add(new MethodReplacer(
|
||||
new ObfMapping("net/minecraft/entity/monster/EntityCreeper", "func_146077_cc", "()V"),
|
||||
blocks.get("d_environmentallyFriendlyCreepers"),
|
||||
blocks.get("environmentallyFriendlyCreepers")));
|
||||
transformer.add(
|
||||
new MethodReplacer(
|
||||
new ObfMapping("net/minecraft/entity/monster/EntityCreeper", "func_146077_cc", "()V"),
|
||||
blocks.get("d_environmentallyFriendlyCreepers"),
|
||||
blocks.get("environmentallyFriendlyCreepers")));
|
||||
}
|
||||
|
||||
if (!tweaks.getTag("softLeafReplace")
|
||||
.setComment("If set to false, leaves will only replace air when growing")
|
||||
if (!tweaks.getTag("softLeafReplace").setComment("If set to false, leaves will only replace air when growing")
|
||||
.getBooleanValue(false)) {
|
||||
transformer.add(new MethodWriter(
|
||||
ACC_PUBLIC,
|
||||
new ObfMapping(
|
||||
"net/minecraft/block/Block",
|
||||
"canBeReplacedByLeaves",
|
||||
"(Lnet/minecraft/world/IBlockAccess;III)Z"),
|
||||
blocks.get("softLeafReplace")));
|
||||
transformer.add(
|
||||
new MethodWriter(
|
||||
ACC_PUBLIC,
|
||||
new ObfMapping(
|
||||
"net/minecraft/block/Block",
|
||||
"canBeReplacedByLeaves",
|
||||
"(Lnet/minecraft/world/IBlockAccess;III)Z"),
|
||||
blocks.get("softLeafReplace")));
|
||||
}
|
||||
|
||||
if (tweaks.getTag("doFireTickOut")
|
||||
.setComment(
|
||||
"If set to true and doFireTick is disabled in the game rules, fire will still dissipate if it's not over a fire source")
|
||||
if (tweaks.getTag("doFireTickOut").setComment(
|
||||
"If set to true and doFireTick is disabled in the game rules, fire will still dissipate if it's not over a fire source")
|
||||
.getBooleanValue(true)) {
|
||||
transformer.add(
|
||||
new MethodTransformer(new ObfMapping(
|
||||
"net/minecraft/block/BlockFire",
|
||||
"func_149674_a",
|
||||
"(Lnet/minecraft/world/World;IIILjava/util/Random;)V")) {
|
||||
new MethodTransformer(
|
||||
new ObfMapping(
|
||||
"net/minecraft/block/BlockFire",
|
||||
"func_149674_a",
|
||||
"(Lnet/minecraft/world/World;IIILjava/util/Random;)V")) {
|
||||
|
||||
@Override
|
||||
public void transform(MethodNode mv) {
|
||||
ASMBlock needle = blocks.get("n_doFireTick");
|
||||
@@ -79,10 +86,12 @@ public class TweakTransformer implements IClassTransformer, Opcodes {
|
||||
.setComment("If set to true two adjacent water source blocks will not generate a third.")
|
||||
.getBooleanValue(false)) {
|
||||
transformer.add(
|
||||
new MethodTransformer(new ObfMapping(
|
||||
"net/minecraft/block/BlockDynamicLiquid",
|
||||
"func_149674_a",
|
||||
"(Lnet/minecraft/world/World;IIILjava/util/Random;)V")) {
|
||||
new MethodTransformer(
|
||||
new ObfMapping(
|
||||
"net/minecraft/block/BlockDynamicLiquid",
|
||||
"func_149674_a",
|
||||
"(Lnet/minecraft/world/World;IIILjava/util/Random;)V")) {
|
||||
|
||||
@Override
|
||||
public void transform(MethodNode mv) {
|
||||
ASMBlock needle = blocks.get("finiteWater");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package codechicken.core.commands;
|
||||
|
||||
import codechicken.core.ServerUtils;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.command.ICommand;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
@@ -15,8 +15,12 @@ import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
|
||||
import codechicken.core.ServerUtils;
|
||||
|
||||
public abstract class CoreCommand implements ICommand {
|
||||
|
||||
public class WCommandSender implements ICommandSender {
|
||||
|
||||
public ICommandSender wrapped;
|
||||
|
||||
public WCommandSender(ICommandSender sender) {
|
||||
@@ -108,12 +112,12 @@ public abstract class CoreCommand implements ICommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> getCommandAliases() {
|
||||
public List<String> getCommandAliases() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> addTabCompletionOptions(ICommandSender var1, String[] var2) {
|
||||
public List<String> addTabCompletionOptions(ICommandSender var1, String[] var2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -125,10 +129,8 @@ public abstract class CoreCommand implements ICommand {
|
||||
@Override
|
||||
public boolean canCommandSenderUseCommand(ICommandSender var1) {
|
||||
if (OPOnly()) {
|
||||
if (var1 instanceof EntityPlayer)
|
||||
return MinecraftServer.getServer()
|
||||
.getConfigurationManager()
|
||||
.func_152596_g(((EntityPlayer) var1).getGameProfile());
|
||||
if (var1 instanceof EntityPlayer) return MinecraftServer.getServer().getConfigurationManager()
|
||||
.func_152596_g(((EntityPlayer) var1).getGameProfile());
|
||||
else if (var1 instanceof MinecraftServer) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import net.minecraft.world.ChunkPosition;
|
||||
import net.minecraft.world.WorldServer;
|
||||
|
||||
public abstract class PlayerCommand extends CoreCommand {
|
||||
|
||||
@Override
|
||||
public boolean canCommandSenderUseCommand(ICommandSender var1) {
|
||||
if (!super.canCommandSenderUseCommand(var1)) return false;
|
||||
@@ -26,8 +27,8 @@ public abstract class PlayerCommand extends CoreCommand {
|
||||
public abstract void handleCommand(WorldServer world, EntityPlayerMP player, String[] args);
|
||||
|
||||
public ChunkPosition getPlayerLookingAtBlock(EntityPlayerMP player, float reach) {
|
||||
Vec3 vec3d =
|
||||
Vec3.createVectorHelper(player.posX, (player.posY + 1.6200000000000001D) - player.yOffset, player.posZ);
|
||||
Vec3 vec3d = Vec3
|
||||
.createVectorHelper(player.posX, (player.posY + 1.6200000000000001D) - player.yOffset, player.posZ);
|
||||
Vec3 vec3d1 = player.getLook(1.0F);
|
||||
Vec3 vec3d2 = vec3d.addVector(vec3d1.xCoord * reach, vec3d1.yCoord * reach, vec3d1.zCoord * reach);
|
||||
MovingObjectPosition hit = player.worldObj.rayTraceBlocks(vec3d, vec3d2);
|
||||
@@ -39,8 +40,8 @@ public abstract class PlayerCommand extends CoreCommand {
|
||||
}
|
||||
|
||||
public Entity getPlayerLookingAtEntity(EntityPlayerMP player, float reach) {
|
||||
Vec3 vec3d =
|
||||
Vec3.createVectorHelper(player.posX, (player.posY + 1.6200000000000001D) - player.yOffset, player.posZ);
|
||||
Vec3 vec3d = Vec3
|
||||
.createVectorHelper(player.posX, (player.posY + 1.6200000000000001D) - player.yOffset, player.posZ);
|
||||
Vec3 vec3d1 = player.getLook(1.0F);
|
||||
Vec3 vec3d2 = vec3d.addVector(vec3d1.xCoord * reach, vec3d1.yCoord * reach, vec3d1.zCoord * reach);
|
||||
MovingObjectPosition hit = player.worldObj.rayTraceBlocks(vec3d, vec3d2);
|
||||
|
||||
@@ -4,6 +4,7 @@ import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
public abstract class ServerCommand extends CoreCommand {
|
||||
|
||||
@Override
|
||||
public void processCommand(ICommandSender var1, String[] var2) {
|
||||
handleCommand(var2, (MinecraftServer) var1);
|
||||
|
||||
@@ -5,7 +5,9 @@ import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class EntityRenderHook extends Entity {
|
||||
|
||||
public static interface IRenderCallback {
|
||||
|
||||
public void render(float frame, int pass);
|
||||
|
||||
public boolean shouldRenderInPass(int pass);
|
||||
|
||||
@@ -5,7 +5,9 @@ import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class EntityUpdateHook extends Entity {
|
||||
|
||||
public static interface IUpdateCallback {
|
||||
|
||||
public void onUpdate();
|
||||
|
||||
public boolean isValid();
|
||||
|
||||
@@ -6,6 +6,7 @@ import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class FeatureHack {
|
||||
|
||||
private static boolean updateHookEnabled = false;
|
||||
private static boolean renderHookEnabled = false;
|
||||
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
package codechicken.core.featurehack;
|
||||
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.util.ObjectIntIdentityMap;
|
||||
import net.minecraft.util.RegistryNamespaced;
|
||||
import net.minecraft.util.RegistrySimple;
|
||||
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
|
||||
public class GameDataManipulator {
|
||||
|
||||
public static Field f_registryObjects;
|
||||
public static Field f_underlyingIntegerMap;
|
||||
|
||||
@@ -16,15 +19,13 @@ public class GameDataManipulator {
|
||||
try {
|
||||
f_registryObjects = RegistrySimple.class.getDeclaredField(
|
||||
new ObfMapping("net/minecraft/util/RegistrySimple", "field_82596_a", "Ljava/util/Map;")
|
||||
.toRuntime()
|
||||
.s_name);
|
||||
.toRuntime().s_name);
|
||||
f_registryObjects.setAccessible(true);
|
||||
f_underlyingIntegerMap = RegistryNamespaced.class.getDeclaredField(new ObfMapping(
|
||||
f_underlyingIntegerMap = RegistryNamespaced.class.getDeclaredField(
|
||||
new ObfMapping(
|
||||
"net/minecraft/util/RegistryNamespaced",
|
||||
"field_148759_a",
|
||||
"Lnet/minecraft/util/ObjectIntIdentityMap;")
|
||||
.toRuntime()
|
||||
.s_name);
|
||||
"Lnet/minecraft/util/ObjectIntIdentityMap;").toRuntime().s_name);
|
||||
f_underlyingIntegerMap.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
package codechicken.core.featurehack;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
import codechicken.core.ReflectionManager;
|
||||
import codechicken.core.asm.TweakTransformer;
|
||||
import codechicken.core.featurehack.mc.TextureLavaFX;
|
||||
@@ -8,13 +15,9 @@ import codechicken.core.featurehack.mc.TextureWaterFX;
|
||||
import codechicken.core.featurehack.mc.TextureWaterFlowFX;
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import java.lang.reflect.Field;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
public class LiquidTextures {
|
||||
|
||||
public static IIcon[] newTextures = new IIcon[4];
|
||||
|
||||
public static boolean replaceLava;
|
||||
@@ -23,14 +26,10 @@ public class LiquidTextures {
|
||||
private static Field field_tex;
|
||||
|
||||
public static void init() {
|
||||
replaceWater = TweakTransformer.tweaks
|
||||
.getTag("replaceWaterFX")
|
||||
.setComment("Set this to true to use the pre1.5 water textures")
|
||||
.getBooleanValue(false);
|
||||
replaceLava = TweakTransformer.tweaks
|
||||
.getTag("replaceLavaFX")
|
||||
.setComment("Set this to true to use the pre1.5 lava textures")
|
||||
.getBooleanValue(false);
|
||||
replaceWater = TweakTransformer.tweaks.getTag("replaceWaterFX")
|
||||
.setComment("Set this to true to use the pre1.5 water textures").getBooleanValue(false);
|
||||
replaceLava = TweakTransformer.tweaks.getTag("replaceLavaFX")
|
||||
.setComment("Set this to true to use the pre1.5 lava textures").getBooleanValue(false);
|
||||
if (replaceWater) {
|
||||
newTextures[0] = new TextureWaterFX().texture;
|
||||
newTextures[1] = new TextureWaterFlowFX().texture;
|
||||
|
||||
@@ -4,9 +4,11 @@ import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.MinecraftForgeClient;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class RenderEntityRenderHook extends Render {
|
||||
|
||||
@Override
|
||||
public void doRender(Entity entity, double x, double y, double z, float f, float frame) {
|
||||
EntityRenderHook hook = (EntityRenderHook) entity;
|
||||
|
||||
@@ -5,6 +5,7 @@ import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class RenderNull extends Render {
|
||||
|
||||
@Override
|
||||
public void doRender(Entity var1, double var2, double var4, double var6, float var8, float var9) {}
|
||||
|
||||
|
||||
@@ -3,23 +3,23 @@ package codechicken.core.featurehack;
|
||||
import static net.minecraftforge.common.util.ForgeDirection.UP;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class TweakTransformerHelper {
|
||||
|
||||
public static void quenchFireTick(World world, int x, int y, int z, Random rand) {
|
||||
Block base = world.getBlock(x, y - 1, z);
|
||||
boolean supported = (base != null && base.isFireSource(world, x, y - 1, z, UP));
|
||||
|
||||
if (!Blocks.fire.canPlaceBlockAt(world, x, y, z)
|
||||
|| !supported
|
||||
&& world.isRaining()
|
||||
&& (world.canLightningStrikeAt(x, y, z)
|
||||
|| world.canLightningStrikeAt(x - 1, y, z)
|
||||
|| world.canLightningStrikeAt(x + 1, y, z)
|
||||
|| world.canLightningStrikeAt(x, y, z - 1)
|
||||
|| world.canLightningStrikeAt(x, y, z + 1))) world.setBlockToAir(x, y, z);
|
||||
if (!Blocks.fire.canPlaceBlockAt(world, x, y, z) || !supported && world.isRaining()
|
||||
&& (world.canLightningStrikeAt(x, y, z) || world.canLightningStrikeAt(x - 1, y, z)
|
||||
|| world.canLightningStrikeAt(x + 1, y, z)
|
||||
|| world.canLightningStrikeAt(x, y, z - 1)
|
||||
|| world.canLightningStrikeAt(x, y, z + 1)))
|
||||
world.setBlockToAir(x, y, z);
|
||||
else {
|
||||
int meta = world.getBlockMetadata(x, y, z);
|
||||
if (meta < 15) world.setBlockMetadataWithNotify(x, y, z, meta + rand.nextInt(3) / 2, 0);
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
package codechicken.core.featurehack.mc;
|
||||
|
||||
import net.minecraft.util.MathHelper;
|
||||
|
||||
import codechicken.lib.colour.ColourRGBA;
|
||||
import codechicken.lib.render.TextureFX;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.util.MathHelper;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class TextureLavaFX extends TextureFX {
|
||||
|
||||
protected float[] field_76876_g = new float[256];
|
||||
protected float[] field_76878_h = new float[256];
|
||||
protected float[] field_76879_i = new float[256];
|
||||
@@ -52,16 +54,16 @@ public class TextureLavaFX extends TextureFX {
|
||||
|
||||
this.field_76878_h[var1 + var2 * tileSizeBase] = var3 / 10.0F
|
||||
+ (this.field_76879_i[(var1 + 0 & tileSizeMask) + (var2 + 0 & tileSizeMask) * tileSizeBase]
|
||||
+ this.field_76879_i[
|
||||
(var1 + 1 & tileSizeMask) + (var2 + 0 & tileSizeMask) * tileSizeBase]
|
||||
+ this.field_76879_i[
|
||||
(var1 + 1 & tileSizeMask) + (var2 + 1 & tileSizeMask) * tileSizeBase]
|
||||
+ this.field_76879_i[
|
||||
(var1 + 0 & tileSizeMask) + (var2 + 1 & tileSizeMask) * tileSizeBase])
|
||||
+ this.field_76879_i[(var1 + 1 & tileSizeMask)
|
||||
+ (var2 + 0 & tileSizeMask) * tileSizeBase]
|
||||
+ this.field_76879_i[(var1 + 1 & tileSizeMask)
|
||||
+ (var2 + 1 & tileSizeMask) * tileSizeBase]
|
||||
+ this.field_76879_i[(var1 + 0 & tileSizeMask)
|
||||
+ (var2 + 1 & tileSizeMask) * tileSizeBase])
|
||||
/ 4.0F
|
||||
* 0.8F;
|
||||
this.field_76879_i[var1 + var2 * tileSizeBase] +=
|
||||
this.field_76877_j[var1 + var2 * tileSizeBase] * 0.01F;
|
||||
this.field_76879_i[var1 + var2 * tileSizeBase] += this.field_76877_j[var1 + var2 * tileSizeBase]
|
||||
* 0.01F;
|
||||
|
||||
if (this.field_76879_i[var1 + var2 * tileSizeBase] < 0.0F) {
|
||||
this.field_76879_i[var1 + var2 * tileSizeBase] = 0.0F;
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
package codechicken.core.featurehack.mc;
|
||||
|
||||
import net.minecraft.util.MathHelper;
|
||||
|
||||
import codechicken.lib.colour.ColourRGBA;
|
||||
import codechicken.lib.render.TextureFX;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.util.MathHelper;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class TextureLavaFlowFX extends TextureFX {
|
||||
|
||||
protected float[] field_76871_g = new float[256];
|
||||
protected float[] field_76874_h = new float[256];
|
||||
protected float[] field_76875_i = new float[256];
|
||||
@@ -60,16 +62,16 @@ public class TextureLavaFlowFX extends TextureFX {
|
||||
|
||||
this.field_76874_h[var1 + var2 * tileSizeBase] = var3 / 10.0F
|
||||
+ (this.field_76875_i[(var1 + 0 & tileSizeMask) + (var2 + 0 & tileSizeMask) * tileSizeBase]
|
||||
+ this.field_76875_i[
|
||||
(var1 + 1 & tileSizeMask) + (var2 + 0 & tileSizeMask) * tileSizeBase]
|
||||
+ this.field_76875_i[
|
||||
(var1 + 1 & tileSizeMask) + (var2 + 1 & tileSizeMask) * tileSizeBase]
|
||||
+ this.field_76875_i[
|
||||
(var1 + 0 & tileSizeMask) + (var2 + 1 & tileSizeMask) * tileSizeBase])
|
||||
+ this.field_76875_i[(var1 + 1 & tileSizeMask)
|
||||
+ (var2 + 0 & tileSizeMask) * tileSizeBase]
|
||||
+ this.field_76875_i[(var1 + 1 & tileSizeMask)
|
||||
+ (var2 + 1 & tileSizeMask) * tileSizeBase]
|
||||
+ this.field_76875_i[(var1 + 0 & tileSizeMask)
|
||||
+ (var2 + 1 & tileSizeMask) * tileSizeBase])
|
||||
/ 4.0F
|
||||
* 0.8F;
|
||||
this.field_76875_i[var1 + var2 * tileSizeBase] +=
|
||||
this.field_76872_j[var1 + var2 * tileSizeBase] * 0.01F;
|
||||
this.field_76875_i[var1 + var2 * tileSizeBase] += this.field_76872_j[var1 + var2 * tileSizeBase]
|
||||
* 0.01F;
|
||||
|
||||
if (this.field_76875_i[var1 + var2 * tileSizeBase] < 0.0F) {
|
||||
this.field_76875_i[var1 + var2 * tileSizeBase] = 0.0F;
|
||||
|
||||
@@ -7,6 +7,7 @@ import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class TextureWaterFX extends TextureFX {
|
||||
|
||||
/** red RGB value for water texture */
|
||||
protected float[] red = new float[256];
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class TextureWaterFlowFX extends TextureFX {
|
||||
|
||||
protected float[] field_76880_g = new float[256];
|
||||
protected float[] field_76883_h = new float[256];
|
||||
protected float[] field_76884_i = new float[256];
|
||||
@@ -51,15 +52,15 @@ public class TextureWaterFlowFX extends TextureFX {
|
||||
var3 += this.field_76880_g[var5 + var6 * tileSizeBase];
|
||||
}
|
||||
|
||||
this.field_76883_h[var1 + var2 * tileSizeBase] =
|
||||
var3 / 3.2F + this.field_76884_i[var1 + var2 * tileSizeBase] * 0.8F;
|
||||
this.field_76883_h[var1 + var2 * tileSizeBase] = var3 / 3.2F
|
||||
+ this.field_76884_i[var1 + var2 * tileSizeBase] * 0.8F;
|
||||
}
|
||||
}
|
||||
|
||||
for (var1 = 0; var1 < tileSizeBase; ++var1) {
|
||||
for (var2 = 0; var2 < tileSizeBase; ++var2) {
|
||||
this.field_76884_i[var1 + var2 * tileSizeBase] +=
|
||||
this.field_76881_j[var1 + var2 * tileSizeBase] * 0.05F;
|
||||
this.field_76884_i[var1 + var2 * tileSizeBase] += this.field_76881_j[var1 + var2 * tileSizeBase]
|
||||
* 0.05F;
|
||||
|
||||
if (this.field_76884_i[var1 + var2 * tileSizeBase] < 0.0F) {
|
||||
this.field_76884_i[var1 + var2 * tileSizeBase] = 0.0F;
|
||||
|
||||
@@ -6,6 +6,7 @@ import net.minecraftforge.fluids.FluidTankInfo;
|
||||
import net.minecraftforge.fluids.IFluidTank;
|
||||
|
||||
public class ExtendedFluidTank implements IFluidTank {
|
||||
|
||||
private FluidStack fluid;
|
||||
private boolean changeType;
|
||||
private int capacity;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package codechicken.core.fluid;
|
||||
|
||||
import codechicken.lib.inventory.InventoryUtils;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
@@ -11,7 +10,10 @@ import net.minecraftforge.fluids.FluidRegistry;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.IFluidHandler;
|
||||
|
||||
import codechicken.lib.inventory.InventoryUtils;
|
||||
|
||||
public class FluidUtils {
|
||||
|
||||
public static int B = FluidContainerRegistry.BUCKET_VOLUME;
|
||||
public static FluidStack water = new FluidStack(FluidRegistry.WATER, 1000);
|
||||
public static FluidStack lava = new FluidStack(FluidRegistry.LAVA, 1000);
|
||||
@@ -68,8 +70,7 @@ public class FluidUtils {
|
||||
}
|
||||
|
||||
public static NBTTagCompound write(FluidStack fluid, NBTTagCompound tag) {
|
||||
return fluid == null || fluid.getFluid() == null
|
||||
? new NBTTagCompound()
|
||||
return fluid == null || fluid.getFluid() == null ? new NBTTagCompound()
|
||||
: fluid.writeToNBT(new NBTTagCompound());
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.IFluidHandler;
|
||||
|
||||
public class TankAccess {
|
||||
|
||||
public IFluidHandler tank;
|
||||
public ForgeDirection side;
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package codechicken.core.gui;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
public class ClickCounter<T> {
|
||||
|
||||
public class ClickCount {
|
||||
|
||||
public T clicked;
|
||||
public long time;
|
||||
public int count;
|
||||
|
||||
@@ -3,9 +3,11 @@ package codechicken.core.gui;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class GuiCCButton extends GuiWidget {
|
||||
|
||||
public String text;
|
||||
public String actionCommand;
|
||||
private boolean isEnabled = true;
|
||||
@@ -32,8 +34,7 @@ public class GuiCCButton extends GuiWidget {
|
||||
public void mouseClicked(int x, int y, int button) {
|
||||
if (isEnabled && pointInside(x, y) && actionCommand != null) {
|
||||
sendAction(actionCommand, button);
|
||||
Minecraft.getMinecraft()
|
||||
.getSoundHandler()
|
||||
Minecraft.getMinecraft().getSoundHandler()
|
||||
.playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F));
|
||||
}
|
||||
}
|
||||
@@ -52,8 +53,8 @@ public class GuiCCButton extends GuiWidget {
|
||||
int state = getButtonTex(mousex, mousey);
|
||||
drawTexturedModalRect(x, y, 0, 46 + state * 20, width / 2, height / 2); // top left
|
||||
drawTexturedModalRect(x + width / 2, y, 200 - width / 2, 46 + state * 20, width / 2, height / 2); // top right
|
||||
drawTexturedModalRect(
|
||||
x, y + height / 2, 0, 46 + state * 20 + 20 - height / 2, width / 2, height / 2); // bottom left
|
||||
drawTexturedModalRect(x, y + height / 2, 0, 46 + state * 20 + 20 - height / 2, width / 2, height / 2); // bottom
|
||||
// left
|
||||
drawTexturedModalRect(
|
||||
x + width / 2,
|
||||
y + height / 2,
|
||||
|
||||
@@ -2,9 +2,11 @@ package codechicken.core.gui;
|
||||
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.util.ChatAllowedCharacters;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
public class GuiCCTextField extends GuiWidget {
|
||||
|
||||
private String text;
|
||||
private boolean isFocused;
|
||||
private boolean isEnabled;
|
||||
@@ -63,10 +65,9 @@ public class GuiCCTextField extends GuiWidget {
|
||||
public void keyTyped(char c, int keycode) {
|
||||
if (!isEnabled || !isFocused) return;
|
||||
|
||||
/*if(c == '\t')//tab
|
||||
{
|
||||
parentGuiScreen.selectNextField();
|
||||
}*/
|
||||
/*
|
||||
* if(c == '\t')//tab { parentGuiScreen.selectNextField(); }
|
||||
*/
|
||||
if (c == '\026') // paste
|
||||
{
|
||||
String s = GuiScreen.getClipboardString();
|
||||
@@ -90,8 +91,7 @@ public class GuiCCTextField extends GuiWidget {
|
||||
}
|
||||
|
||||
public boolean canAddChar(char c) {
|
||||
return allowedCharacters == null
|
||||
? ChatAllowedCharacters.isAllowedCharacter(c)
|
||||
return allowedCharacters == null ? ChatAllowedCharacters.isAllowedCharacter(c)
|
||||
: allowedCharacters.indexOf(c) >= 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
package codechicken.core.gui;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
|
||||
public class GuiScreenWidget extends GuiScreen implements IGuiActionListener {
|
||||
|
||||
public ArrayList<GuiWidget> widgets = new ArrayList<GuiWidget>();
|
||||
public int xSize, ySize, guiTop, guiLeft;
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package codechicken.core.gui;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import codechicken.lib.math.MathHelper;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import java.awt.*;
|
||||
|
||||
public abstract class GuiScrollPane extends GuiWidget {
|
||||
|
||||
protected int scrollclicky = -1;
|
||||
protected float scrollpercent;
|
||||
protected int scrollmousey;
|
||||
@@ -28,7 +31,10 @@ public abstract class GuiScrollPane extends GuiWidget {
|
||||
|
||||
public Rectangle windowBounds() {
|
||||
return new Rectangle(
|
||||
x + marginleft, y + margintop, width - marginleft - marginright, height - margintop - marginbottom);
|
||||
x + marginleft,
|
||||
y + margintop,
|
||||
width - marginleft - marginright,
|
||||
height - margintop - marginbottom);
|
||||
}
|
||||
|
||||
public abstract int contentHeight();
|
||||
@@ -103,13 +109,8 @@ public abstract class GuiScrollPane extends GuiWidget {
|
||||
Rectangle w = windowBounds();
|
||||
int barempty = height - sbar.height;
|
||||
|
||||
if (button == 0
|
||||
&& sbar.height < height
|
||||
&& // the scroll bar can move (not full length)
|
||||
mx >= sbar.x
|
||||
&& mx <= sbar.x + sbar.width
|
||||
&& my >= y
|
||||
&& my <= y + height) // in the scroll pane
|
||||
if (button == 0 && sbar.height < height && // the scroll bar can move (not full length)
|
||||
mx >= sbar.x && mx <= sbar.x + sbar.width && my >= y && my <= y + height) // in the scroll pane
|
||||
{
|
||||
if (my < sbar.y) {
|
||||
percentscrolled = (my - y) / (float) barempty;
|
||||
@@ -126,14 +127,12 @@ public abstract class GuiScrollPane extends GuiWidget {
|
||||
}
|
||||
|
||||
/**
|
||||
* Mouse down on slot area
|
||||
* Coordinates relative to slot content area
|
||||
* Mouse down on slot area Coordinates relative to slot content area
|
||||
*/
|
||||
public void slotDown(int mx, int my, int button) {}
|
||||
|
||||
/**
|
||||
* Mouse up on slot area
|
||||
* Coordinates relative to slot content area
|
||||
* Mouse up on slot area Coordinates relative to slot content area
|
||||
*/
|
||||
public void slotUp(int mx, int my, int button) {}
|
||||
|
||||
@@ -141,7 +140,7 @@ public abstract class GuiScrollPane extends GuiWidget {
|
||||
public void mouseMovedOrUp(int mx, int my, int button) {
|
||||
Rectangle w = windowBounds();
|
||||
if (isScrolling() && button == 0) // we were scrolling and we released mouse
|
||||
scrollclicky = -1;
|
||||
scrollclicky = -1;
|
||||
else if (w.contains(mx, my)) slotUp(mx - w.x, my - w.y + scrolledPixels(), button);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package codechicken.core.gui;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
public abstract class GuiScrollSlot extends GuiScrollPane {
|
||||
|
||||
protected String actionCommand;
|
||||
public boolean focused;
|
||||
protected ClickCounter<Integer> click = new ClickCounter<Integer>();
|
||||
|
||||
@@ -8,6 +8,7 @@ import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class GuiWidget extends Gui {
|
||||
|
||||
protected static final ResourceLocation guiTex = new ResourceLocation("textures/gui/widgets.png");
|
||||
|
||||
public GuiScreen parentScreen;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package codechicken.core.gui;
|
||||
|
||||
public interface IGuiActionListener {
|
||||
|
||||
public void actionPerformed(String actionCommand, Object... params);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package codechicken.core.internal;
|
||||
|
||||
import codechicken.core.CCUpdateChecker;
|
||||
import net.minecraftforge.client.event.GuiScreenEvent;
|
||||
|
||||
import codechicken.core.GuiModListScroll;
|
||||
import cpw.mods.fml.client.GuiModList;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
@@ -8,16 +9,15 @@ import cpw.mods.fml.common.gameevent.TickEvent;
|
||||
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraftforge.client.event.GuiScreenEvent;
|
||||
|
||||
public class CCCEventHandler {
|
||||
|
||||
public static int renderTime;
|
||||
public static float renderFrame;
|
||||
|
||||
@SubscribeEvent
|
||||
public void clientTick(TickEvent.ClientTickEvent event) {
|
||||
if (event.phase == Phase.END) {
|
||||
CCUpdateChecker.tick();
|
||||
renderTime++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
package codechicken.core.inventory;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.inventory.Container;
|
||||
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.core.gui.GuiWidget;
|
||||
import codechicken.core.gui.IGuiActionListener;
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.inventory.Container;
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class GuiContainerWidget extends GuiContainer implements IGuiActionListener {
|
||||
|
||||
public ArrayList<GuiWidget> widgets = new ArrayList<GuiWidget>();
|
||||
|
||||
public GuiContainerWidget(Container inventorySlots) {
|
||||
|
||||
@@ -1,17 +1,7 @@
|
||||
package codechicken.core.launch;
|
||||
|
||||
import codechicken.core.asm.*;
|
||||
import codechicken.lib.config.ConfigTag;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
|
||||
import cpw.mods.fml.common.versioning.VersionParser;
|
||||
import cpw.mods.fml.relauncher.CoreModManager;
|
||||
import cpw.mods.fml.relauncher.FMLInjectionData;
|
||||
import cpw.mods.fml.relauncher.IFMLCallHook;
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.MCVersion;
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.TransformerExclusions;
|
||||
import java.awt.*;
|
||||
import java.awt.Desktop;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -22,20 +12,39 @@ import java.util.Map;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import javax.swing.event.HyperlinkListener;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@TransformerExclusions(value = {"codechicken.core.asm", "codechicken.obfuscator"})
|
||||
import codechicken.core.asm.CodeChickenCoreModContainer;
|
||||
import codechicken.core.asm.DelegatedTransformer;
|
||||
import codechicken.core.asm.MCPDeobfuscationTransformer;
|
||||
import codechicken.core.asm.Tags;
|
||||
import codechicken.core.asm.TweakTransformer;
|
||||
import codechicken.lib.config.ConfigTag;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
|
||||
import cpw.mods.fml.common.versioning.VersionParser;
|
||||
import cpw.mods.fml.relauncher.CoreModManager;
|
||||
import cpw.mods.fml.relauncher.FMLInjectionData;
|
||||
import cpw.mods.fml.relauncher.IFMLCallHook;
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.MCVersion;
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.TransformerExclusions;
|
||||
|
||||
@TransformerExclusions(value = { "codechicken.core.asm", "codechicken.obfuscator" })
|
||||
@MCVersion("1.7.10")
|
||||
public class CodeChickenCorePlugin implements IFMLLoadingPlugin, IFMLCallHook {
|
||||
|
||||
public static final String mcVersion = "[1.7.10]";
|
||||
|
||||
@Deprecated
|
||||
public static final String version = "1.1.3-unused";
|
||||
public static final String version = Tags.VERSION;
|
||||
|
||||
public static File minecraftDir;
|
||||
public static String currentMcVersion;
|
||||
@@ -47,27 +56,25 @@ public class CodeChickenCorePlugin implements IFMLLoadingPlugin, IFMLCallHook {
|
||||
minecraftDir = (File) FMLInjectionData.data()[6];
|
||||
currentMcVersion = (String) FMLInjectionData.data()[4];
|
||||
|
||||
DepLoader.load();
|
||||
injectDeobfPlugin();
|
||||
}
|
||||
|
||||
private void injectDeobfPlugin() {
|
||||
try {
|
||||
Class<?> wrapperClass = Class.forName("cpw.mods.fml.relauncher.CoreModManager$FMLPluginWrapper");
|
||||
Constructor wrapperConstructor = wrapperClass.getConstructor(
|
||||
String.class, IFMLLoadingPlugin.class, File.class, Integer.TYPE, String[].class);
|
||||
Constructor wrapperConstructor = wrapperClass
|
||||
.getConstructor(String.class, IFMLLoadingPlugin.class, File.class, Integer.TYPE, String[].class);
|
||||
Field f_loadPlugins = CoreModManager.class.getDeclaredField("loadPlugins");
|
||||
wrapperConstructor.setAccessible(true);
|
||||
f_loadPlugins.setAccessible(true);
|
||||
((List) f_loadPlugins.get(null))
|
||||
.add(
|
||||
2,
|
||||
wrapperConstructor.newInstance(
|
||||
"CCCDeobfPlugin",
|
||||
new MCPDeobfuscationTransformer.LoadPlugin(),
|
||||
null,
|
||||
0,
|
||||
new String[0]));
|
||||
((List) f_loadPlugins.get(null)).add(
|
||||
2,
|
||||
wrapperConstructor.newInstance(
|
||||
"CCCDeobfPlugin",
|
||||
new MCPDeobfuscationTransformer.LoadPlugin(),
|
||||
null,
|
||||
0,
|
||||
new String[0]));
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to inject MCPDeobfuscation Transformer", e);
|
||||
}
|
||||
@@ -88,13 +95,13 @@ public class CodeChickenCorePlugin implements IFMLLoadingPlugin, IFMLCallHook {
|
||||
ep.setEditable(false);
|
||||
ep.setOpaque(false);
|
||||
ep.addHyperlinkListener(new HyperlinkListener() {
|
||||
|
||||
@Override
|
||||
public void hyperlinkUpdate(HyperlinkEvent event) {
|
||||
try {
|
||||
if (event.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED))
|
||||
Desktop.getDesktop().browse(event.getURL().toURI());
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -134,45 +141,43 @@ public class CodeChickenCorePlugin implements IFMLLoadingPlugin, IFMLCallHook {
|
||||
}
|
||||
|
||||
public static void systemCheck(ConfigTag checkRAM) {
|
||||
long minBytes = parseSize(checkRAM.getTag("minRAM")
|
||||
.setComment("Amount of RAM minimum this modpack needs to load")
|
||||
.getValue("3GB"));
|
||||
long minBytes = parseSize(
|
||||
checkRAM.getTag("minRAM").setComment("Amount of RAM minimum this modpack needs to load")
|
||||
.getValue("3GB"));
|
||||
if (Runtime.getRuntime().maxMemory() < minBytes) {
|
||||
String err = "You should have at least " + humanReadableByteCountBin(minBytes)
|
||||
+ " of RAM but you have only allocated "
|
||||
+ humanReadableByteCountBin(Runtime.getRuntime().maxMemory()) + ".";
|
||||
+ humanReadableByteCountBin(Runtime.getRuntime().maxMemory())
|
||||
+ ".";
|
||||
logger.error(err);
|
||||
|
||||
JEditorPane ep = new JEditorPane(
|
||||
"text/html",
|
||||
"<html>" + err + "<br>"
|
||||
+ checkRAM.getTag("modPack")
|
||||
.setComment("Name of the modpack")
|
||||
"<html>" + err
|
||||
+ "<br>"
|
||||
+ checkRAM.getTag("modPack").setComment("Name of the modpack")
|
||||
.getValue("Unidentified ModPack")
|
||||
+ " seriously won't run without enough RAM. "
|
||||
+ checkRAM.getTag("wiki")
|
||||
.setComment("Webpage describing RAM settings")
|
||||
.getValue(
|
||||
"See <a href=\"https://downloadmoreram.com\">DownloadMoreRam.com</a> for details.")
|
||||
+ checkRAM.getTag("wiki").setComment("Webpage describing RAM settings").getValue(
|
||||
"See <a href=\"https://downloadmoreram.com\">DownloadMoreRam.com</a> for details.")
|
||||
+ "<br>Recommended values are between "
|
||||
+ checkRAM.getTag("recRAM")
|
||||
.setComment("Lower bound of recommended RAM")
|
||||
.getValue("4GB") + " and "
|
||||
+ checkRAM.getTag("recRAMUpper")
|
||||
.setComment("Upper bound of recommended RAM")
|
||||
+ checkRAM.getTag("recRAM").setComment("Lower bound of recommended RAM").getValue("4GB")
|
||||
+ " and "
|
||||
+ checkRAM.getTag("recRAMUpper").setComment("Upper bound of recommended RAM")
|
||||
.getValue("6GB")
|
||||
+ ". Check your launcher's JVM arguments." + "</html>");
|
||||
+ ". Check your launcher's JVM arguments."
|
||||
+ "</html>");
|
||||
|
||||
ep.setEditable(false);
|
||||
ep.setOpaque(false);
|
||||
ep.addHyperlinkListener(new HyperlinkListener() {
|
||||
|
||||
@Override
|
||||
public void hyperlinkUpdate(HyperlinkEvent event) {
|
||||
try {
|
||||
if (event.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED))
|
||||
Desktop.getDesktop().browse(event.getURL().toURI());
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -185,12 +190,9 @@ public class CodeChickenCorePlugin implements IFMLLoadingPlugin, IFMLCallHook {
|
||||
@Override
|
||||
public String[] getASMTransformerClass() {
|
||||
versionCheck(mcVersion, "CodeChickenCore");
|
||||
return new String[] {
|
||||
"codechicken.lib.asm.ClassHeirachyManager",
|
||||
"codechicken.core.asm.TweakTransformer",
|
||||
"codechicken.core.asm.DelegatedTransformer",
|
||||
"codechicken.core.asm.DefaultImplementationTransformer"
|
||||
};
|
||||
return new String[] { "codechicken.lib.asm.ClassHeirachyManager", "codechicken.core.asm.TweakTransformer",
|
||||
"codechicken.core.asm.DelegatedTransformer", "codechicken.core.asm.DefaultImplementationTransformer",
|
||||
"codechicken.lib.asm.RedirectorTransformer" };
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -215,13 +217,12 @@ public class CodeChickenCorePlugin implements IFMLLoadingPlugin, IFMLCallHook {
|
||||
public Void call() {
|
||||
CodeChickenCoreModContainer.loadConfig();
|
||||
ConfigTag checkRAM;
|
||||
checkRAM = CodeChickenCoreModContainer.config
|
||||
.getTag("checks")
|
||||
.setComment("Configuration options for checking various requirements for a modpack.")
|
||||
.useBraces();
|
||||
checkRAM = CodeChickenCoreModContainer.config.getTag("checks")
|
||||
.setComment("Configuration options for checking various requirements for a modpack.").useBraces();
|
||||
if (checkRAM.getTag("checkRAM")
|
||||
.setComment("If set to true, check RAM available for Minecraft before continuing to load")
|
||||
.getBooleanValue(false)) systemCheck(checkRAM);
|
||||
.getBooleanValue(false))
|
||||
systemCheck(checkRAM);
|
||||
TweakTransformer.load();
|
||||
scanCodeChickenMods();
|
||||
|
||||
|
||||
@@ -1,52 +1,26 @@
|
||||
package codechicken.core.launch;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.swing.Box;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import cpw.mods.fml.common.versioning.ComparableVersion;
|
||||
import cpw.mods.fml.relauncher.FMLInjectionData;
|
||||
import cpw.mods.fml.relauncher.FMLLaunchHandler;
|
||||
import cpw.mods.fml.relauncher.IFMLCallHook;
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.MCVersion;
|
||||
import java.awt.*;
|
||||
import java.awt.Dialog.ModalityType;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import javax.swing.event.HyperlinkListener;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
import sun.misc.URLClassPath;
|
||||
import sun.net.util.URLUtil;
|
||||
|
||||
/**
|
||||
* For autodownloading stuff.
|
||||
* This is really unoriginal, mostly ripped off FML, credits to cpw.
|
||||
* For autodownloading stuff. This is really unoriginal, mostly ripped off FML, credits to cpw.
|
||||
*/
|
||||
@MCVersion("1.7.10")
|
||||
public class DepLoader implements IFMLLoadingPlugin, IFMLCallHook {
|
||||
private static ByteBuffer downloadBuffer = ByteBuffer.allocateDirect(1 << 23);
|
||||
private static final String owner = "CB's DepLoader";
|
||||
private static DepLoadInst inst;
|
||||
|
||||
public interface IDownloadDisplay {
|
||||
|
||||
void resetProgress(int sizeGuess);
|
||||
|
||||
void setPokeThread(Thread currentThread);
|
||||
@@ -64,135 +38,44 @@ public class DepLoader implements IFMLLoadingPlugin, IFMLCallHook {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class Downloader extends JOptionPane implements IDownloadDisplay {
|
||||
private JDialog container;
|
||||
private JLabel currentActivity;
|
||||
private JProgressBar progress;
|
||||
|
||||
boolean stopIt;
|
||||
Thread pokeThread;
|
||||
|
||||
private Box makeProgressPanel() {
|
||||
Box box = Box.createVerticalBox();
|
||||
box.add(Box.createRigidArea(new Dimension(0, 10)));
|
||||
JLabel welcomeLabel = new JLabel("<html><b><font size='+1'>" + owner
|
||||
+ " is setting up your minecraft environment</font></b></html>");
|
||||
box.add(welcomeLabel);
|
||||
welcomeLabel.setAlignmentY(LEFT_ALIGNMENT);
|
||||
welcomeLabel =
|
||||
new JLabel("<html>Please wait, " + owner + " has some tasks to do before you can play</html>");
|
||||
welcomeLabel.setAlignmentY(LEFT_ALIGNMENT);
|
||||
box.add(welcomeLabel);
|
||||
box.add(Box.createRigidArea(new Dimension(0, 10)));
|
||||
currentActivity = new JLabel("Currently doing ...");
|
||||
box.add(currentActivity);
|
||||
box.add(Box.createRigidArea(new Dimension(0, 10)));
|
||||
progress = new JProgressBar(0, 100);
|
||||
progress.setStringPainted(true);
|
||||
box.add(progress);
|
||||
box.add(Box.createRigidArea(new Dimension(0, 30)));
|
||||
return box;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JDialog makeDialog() {
|
||||
if (container != null) return container;
|
||||
|
||||
setMessageType(JOptionPane.INFORMATION_MESSAGE);
|
||||
setMessage(makeProgressPanel());
|
||||
setOptions(new Object[] {"Stop"});
|
||||
addPropertyChangeListener(new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (evt.getSource() == Downloader.this && evt.getPropertyName() == VALUE_PROPERTY) {
|
||||
requestClose("This will stop minecraft from launching\nAre you sure you want to do this?");
|
||||
}
|
||||
}
|
||||
});
|
||||
container = new JDialog(null, "Hello", ModalityType.MODELESS);
|
||||
container.setResizable(false);
|
||||
container.setLocationRelativeTo(null);
|
||||
container.add(this);
|
||||
this.updateUI();
|
||||
container.pack();
|
||||
container.setMinimumSize(container.getPreferredSize());
|
||||
container.setVisible(true);
|
||||
container.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
|
||||
container.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
requestClose(
|
||||
"Closing this window will stop minecraft from launching\nAre you sure you wish to do this?");
|
||||
}
|
||||
});
|
||||
return container;
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void requestClose(String message) {
|
||||
int shouldClose = JOptionPane.showConfirmDialog(
|
||||
container,
|
||||
message,
|
||||
"Are you sure you want to stop?",
|
||||
JOptionPane.YES_NO_OPTION,
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
if (shouldClose == JOptionPane.YES_OPTION) container.dispose();
|
||||
|
||||
stopIt = true;
|
||||
if (pokeThread != null) pokeThread.interrupt();
|
||||
}
|
||||
protected void requestClose(String message) {}
|
||||
|
||||
@Override
|
||||
public void updateProgressString(String progressUpdate, Object... data) {
|
||||
// FMLLog.finest(progressUpdate, data);
|
||||
if (currentActivity != null) currentActivity.setText(String.format(progressUpdate, data));
|
||||
}
|
||||
public void updateProgressString(String progressUpdate, Object... data) {}
|
||||
|
||||
@Override
|
||||
public void resetProgress(int sizeGuess) {
|
||||
if (progress != null) progress.getModel().setRangeProperties(0, 0, 0, sizeGuess, false);
|
||||
}
|
||||
public void resetProgress(int sizeGuess) {}
|
||||
|
||||
@Override
|
||||
public void updateProgress(int fullLength) {
|
||||
if (progress != null) progress.getModel().setValue(fullLength);
|
||||
}
|
||||
public void updateProgress(int fullLength) {}
|
||||
|
||||
@Override
|
||||
public void setPokeThread(Thread currentThread) {
|
||||
this.pokeThread = currentThread;
|
||||
}
|
||||
public void setPokeThread(Thread currentThread) {}
|
||||
|
||||
@Override
|
||||
public boolean shouldStopIt() {
|
||||
return stopIt;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showErrorDialog(String name, String url) {
|
||||
JEditorPane ep = new JEditorPane(
|
||||
"text/html",
|
||||
"<html>" + owner
|
||||
+ " was unable to download required library " + name
|
||||
+ "<br>Check your internet connection and try restarting or download it manually from"
|
||||
+ "<br><a href=\""
|
||||
+ url + "\">" + url + "</a> and put it in your mods folder" + "</html>");
|
||||
|
||||
ep.setEditable(false);
|
||||
ep.setOpaque(false);
|
||||
ep.addHyperlinkListener(new HyperlinkListener() {
|
||||
@Override
|
||||
public void hyperlinkUpdate(HyperlinkEvent event) {
|
||||
try {
|
||||
if (event.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED))
|
||||
Desktop.getDesktop().browse(event.getURL().toURI());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
JOptionPane.showMessageDialog(null, ep, "A download error has occurred", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
public void showErrorDialog(String name, String url) {}
|
||||
}
|
||||
|
||||
public static class DummyDownloader implements IDownloadDisplay {
|
||||
|
||||
@Override
|
||||
public void resetProgress(int sizeGuess) {}
|
||||
|
||||
@@ -220,6 +103,7 @@ public class DepLoader implements IFMLLoadingPlugin, IFMLCallHook {
|
||||
}
|
||||
|
||||
public static class VersionedFile {
|
||||
|
||||
public final Pattern pattern;
|
||||
public final String filename;
|
||||
public final ComparableVersion version;
|
||||
@@ -244,6 +128,7 @@ public class DepLoader implements IFMLLoadingPlugin, IFMLCallHook {
|
||||
}
|
||||
|
||||
public static class Dependency {
|
||||
|
||||
public String url;
|
||||
public VersionedFile file;
|
||||
|
||||
@@ -261,313 +146,13 @@ public class DepLoader implements IFMLLoadingPlugin, IFMLCallHook {
|
||||
}
|
||||
|
||||
public static class DepLoadInst {
|
||||
private File modsDir;
|
||||
private File v_modsDir;
|
||||
private IDownloadDisplay downloadMonitor;
|
||||
private JDialog popupWindow;
|
||||
|
||||
private Map<String, Dependency> depMap = new HashMap<String, Dependency>();
|
||||
private HashSet<String> depSet = new HashSet<String>();
|
||||
public DepLoadInst() {}
|
||||
|
||||
public DepLoadInst() {
|
||||
String mcVer = (String) FMLInjectionData.data()[4];
|
||||
File mcDir = (File) FMLInjectionData.data()[6];
|
||||
|
||||
modsDir = new File(mcDir, "mods");
|
||||
v_modsDir = new File(mcDir, "mods/" + mcVer);
|
||||
if (!v_modsDir.exists()) v_modsDir.mkdirs();
|
||||
}
|
||||
|
||||
private void addClasspath(String name) {
|
||||
try {
|
||||
((LaunchClassLoader) DepLoader.class.getClassLoader())
|
||||
.addURL(new File(v_modsDir, name).toURI().toURL());
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteMod(File mod) {
|
||||
if (mod.delete()) return;
|
||||
|
||||
try {
|
||||
ClassLoader cl = DepLoader.class.getClassLoader();
|
||||
URL url = mod.toURI().toURL();
|
||||
Field f_ucp = URLClassLoader.class.getDeclaredField("ucp");
|
||||
Field f_loaders = URLClassPath.class.getDeclaredField("loaders");
|
||||
Field f_lmap = URLClassPath.class.getDeclaredField("lmap");
|
||||
f_ucp.setAccessible(true);
|
||||
f_loaders.setAccessible(true);
|
||||
f_lmap.setAccessible(true);
|
||||
|
||||
URLClassPath ucp = (URLClassPath) f_ucp.get(cl);
|
||||
Closeable loader = ((Map<String, Closeable>) f_lmap.get(ucp)).remove(URLUtil.urlNoFragString(url));
|
||||
if (loader != null) {
|
||||
loader.close();
|
||||
((List<?>) f_loaders.get(ucp)).remove(loader);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (!mod.delete()) {
|
||||
mod.deleteOnExit();
|
||||
String msg = owner + " was unable to delete file " + mod.getPath()
|
||||
+ " the game will now try to delete it on exit. If this dialog appears again, delete it manually.";
|
||||
CodeChickenCorePlugin.logger.error(msg);
|
||||
if (!GraphicsEnvironment.isHeadless())
|
||||
JOptionPane.showMessageDialog(null, msg, "An update error has occurred", JOptionPane.ERROR_MESSAGE);
|
||||
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private void download(Dependency dep) {
|
||||
popupWindow = (JDialog) downloadMonitor.makeDialog();
|
||||
File libFile = new File(v_modsDir, dep.file.filename);
|
||||
try {
|
||||
URL libDownload = new URL(dep.url + '/' + dep.file.filename);
|
||||
downloadMonitor.updateProgressString("Downloading file %s", libDownload.toString());
|
||||
CodeChickenCorePlugin.logger.debug("Downloading file " + libDownload);
|
||||
URLConnection connection = libDownload.openConnection();
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setReadTimeout(5000);
|
||||
connection.setRequestProperty("User-Agent", "" + owner + " Downloader");
|
||||
int sizeGuess = connection.getContentLength();
|
||||
download(connection.getInputStream(), sizeGuess, libFile);
|
||||
downloadMonitor.updateProgressString("Download complete");
|
||||
CodeChickenCorePlugin.logger.trace("Download complete");
|
||||
|
||||
scanDepInfo(libFile);
|
||||
} catch (Exception e) {
|
||||
libFile.delete();
|
||||
if (downloadMonitor.shouldStopIt()) {
|
||||
CodeChickenCorePlugin.logger.error(
|
||||
"You have stopped the downloading operation before it could complete");
|
||||
System.exit(1);
|
||||
return;
|
||||
}
|
||||
downloadMonitor.showErrorDialog(dep.file.filename, dep.url + '/' + dep.file.filename);
|
||||
throw new RuntimeException("A download error occured", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void download(InputStream is, int sizeGuess, File target) throws Exception {
|
||||
if (sizeGuess > downloadBuffer.capacity())
|
||||
throw new Exception(String.format(
|
||||
"The file %s is too large to be downloaded by " + owner + " - the download is invalid",
|
||||
target.getName()));
|
||||
|
||||
downloadBuffer.clear();
|
||||
|
||||
int bytesRead, fullLength = 0;
|
||||
|
||||
downloadMonitor.resetProgress(sizeGuess);
|
||||
try {
|
||||
downloadMonitor.setPokeThread(Thread.currentThread());
|
||||
byte[] smallBuffer = new byte[1024];
|
||||
while ((bytesRead = is.read(smallBuffer)) >= 0) {
|
||||
downloadBuffer.put(smallBuffer, 0, bytesRead);
|
||||
fullLength += bytesRead;
|
||||
if (downloadMonitor.shouldStopIt()) {
|
||||
break;
|
||||
}
|
||||
downloadMonitor.updateProgress(fullLength);
|
||||
}
|
||||
is.close();
|
||||
downloadMonitor.setPokeThread(null);
|
||||
downloadBuffer.limit(fullLength);
|
||||
downloadBuffer.position(0);
|
||||
} catch (InterruptedIOException e) {
|
||||
// We were interrupted by the stop button. We're stopping now.. clear interruption flag.
|
||||
Thread.interrupted();
|
||||
throw new Exception("Stop");
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
try {
|
||||
/*String cksum = generateChecksum(downloadBuffer);
|
||||
if (cksum.equals(validationHash))
|
||||
{*/
|
||||
if (!target.exists()) target.createNewFile();
|
||||
|
||||
downloadBuffer.position(0);
|
||||
FileOutputStream fos = new FileOutputStream(target);
|
||||
fos.getChannel().write(downloadBuffer);
|
||||
fos.close();
|
||||
/*}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException(String.format("The downloaded file %s has an invalid checksum %s (expecting %s). The download did not succeed correctly and the file has been deleted. Please try launching again.", target.getName(), cksum, validationHash));
|
||||
}*/
|
||||
} catch (Exception e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private String checkExisting(Dependency dep) {
|
||||
for (File f : modsDir.listFiles()) {
|
||||
VersionedFile vfile = new VersionedFile(f.getName(), dep.file.pattern);
|
||||
if (!vfile.matches() || !vfile.name.equals(dep.file.name)) continue;
|
||||
|
||||
if (f.renameTo(new File(v_modsDir, f.getName()))) continue;
|
||||
|
||||
deleteMod(f);
|
||||
}
|
||||
|
||||
for (File f : v_modsDir.listFiles()) {
|
||||
VersionedFile vfile = new VersionedFile(f.getName(), dep.file.pattern);
|
||||
if (!vfile.matches() || !vfile.name.equals(dep.file.name)) continue;
|
||||
|
||||
int cmp = vfile.version.compareTo(dep.file.version);
|
||||
if (cmp < 0) {
|
||||
CodeChickenCorePlugin.logger.warn("Deleted old version " + f.getName());
|
||||
deleteMod(f);
|
||||
return null;
|
||||
}
|
||||
if (cmp > 0) {
|
||||
CodeChickenCorePlugin.logger.warn("Warning: version of " + dep.file.name + ", " + vfile.version
|
||||
+ " is newer than request " + dep.file.version);
|
||||
return f.getName();
|
||||
}
|
||||
return f.getName(); // found dependency
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void load() {
|
||||
scanDepInfos();
|
||||
if (depMap.isEmpty()) return;
|
||||
|
||||
loadDeps();
|
||||
activateDeps();
|
||||
}
|
||||
|
||||
private void activateDeps() {
|
||||
for (Dependency dep : depMap.values()) if (dep.coreLib) addClasspath(dep.existing);
|
||||
}
|
||||
|
||||
private void loadDeps() {
|
||||
downloadMonitor = FMLLaunchHandler.side().isClient() ? new Downloader() : new DummyDownloader();
|
||||
try {
|
||||
while (!depSet.isEmpty()) {
|
||||
Iterator<String> it = depSet.iterator();
|
||||
Dependency dep = depMap.get(it.next());
|
||||
it.remove();
|
||||
load(dep);
|
||||
}
|
||||
} finally {
|
||||
if (popupWindow != null) {
|
||||
popupWindow.setVisible(false);
|
||||
popupWindow.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void load(Dependency dep) {
|
||||
dep.existing = checkExisting(dep);
|
||||
if (dep.existing == null) // download dep
|
||||
{
|
||||
download(dep);
|
||||
dep.existing = dep.file.filename;
|
||||
}
|
||||
}
|
||||
|
||||
private List<File> modFiles() {
|
||||
List<File> list = new LinkedList<File>();
|
||||
list.addAll(Arrays.asList(modsDir.listFiles()));
|
||||
list.addAll(Arrays.asList(v_modsDir.listFiles()));
|
||||
return list;
|
||||
}
|
||||
|
||||
private void scanDepInfos() {
|
||||
for (File file : modFiles()) {
|
||||
if (!file.getName().endsWith(".jar") && !file.getName().endsWith(".zip")) continue;
|
||||
|
||||
scanDepInfo(file);
|
||||
}
|
||||
}
|
||||
|
||||
private void scanDepInfo(File file) {
|
||||
try {
|
||||
ZipFile zip = new ZipFile(file);
|
||||
ZipEntry e = zip.getEntry("dependancies.info");
|
||||
if (e == null) e = zip.getEntry("dependencies.info");
|
||||
if (e != null) loadJSon(zip.getInputStream(e));
|
||||
zip.close();
|
||||
} catch (Exception e) {
|
||||
CodeChickenCorePlugin.logger.error(
|
||||
"Failed to load dependencies.info from " + file.getName() + " as JSON");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadJSon(InputStream input) throws IOException {
|
||||
InputStreamReader reader = new InputStreamReader(input);
|
||||
JsonElement root = new JsonParser().parse(reader);
|
||||
if (root.isJsonArray()) loadJSonArr(root);
|
||||
else loadJson(root.getAsJsonObject());
|
||||
reader.close();
|
||||
}
|
||||
|
||||
private void loadJSonArr(JsonElement root) throws IOException {
|
||||
for (JsonElement node : root.getAsJsonArray()) loadJson(node.getAsJsonObject());
|
||||
}
|
||||
|
||||
private void loadJson(JsonObject node) throws IOException {
|
||||
boolean obfuscated =
|
||||
((LaunchClassLoader) DepLoader.class.getClassLoader()).getClassBytes("net.minecraft.world.World")
|
||||
== null;
|
||||
|
||||
String testClass = node.get("class").getAsString();
|
||||
if (DepLoader.class.getResource("/" + testClass.replace('.', '/') + ".class") != null) return;
|
||||
|
||||
String repo = node.get("repo").getAsString();
|
||||
String filename = node.get("file").getAsString();
|
||||
if (!obfuscated && node.has("dev")) filename = node.get("dev").getAsString();
|
||||
|
||||
boolean coreLib = node.has("coreLib") && node.get("coreLib").getAsBoolean();
|
||||
|
||||
Pattern pattern = null;
|
||||
try {
|
||||
if (node.has("pattern"))
|
||||
pattern = Pattern.compile(node.get("pattern").getAsString());
|
||||
} catch (PatternSyntaxException e) {
|
||||
CodeChickenCorePlugin.logger.error("Invalid filename pattern: " + node.get("pattern"));
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (pattern == null) pattern = Pattern.compile("(\\w+).*?([\\d\\.]+)[-\\w]*\\.[^\\d]+");
|
||||
|
||||
VersionedFile file = new VersionedFile(filename, pattern);
|
||||
if (!file.matches()) throw new RuntimeException("Invalid filename format for dependency: " + filename);
|
||||
|
||||
addDep(new Dependency(repo, file, coreLib));
|
||||
}
|
||||
|
||||
private void addDep(Dependency newDep) {
|
||||
if (mergeNew(depMap.get(newDep.file.name), newDep)) {
|
||||
depMap.put(newDep.file.name, newDep);
|
||||
depSet.add(newDep.file.name);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean mergeNew(Dependency oldDep, Dependency newDep) {
|
||||
if (oldDep == null) return true;
|
||||
|
||||
Dependency newest = newDep.file.version.compareTo(oldDep.file.version) > 0 ? newDep : oldDep;
|
||||
newest.coreLib = newDep.coreLib || oldDep.coreLib;
|
||||
|
||||
return newest == newDep;
|
||||
}
|
||||
public void load() {}
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
if (inst == null) {
|
||||
inst = new DepLoadInst();
|
||||
inst.load();
|
||||
}
|
||||
}
|
||||
public static void load() {}
|
||||
|
||||
@Override
|
||||
public String[] getASMTransformerClass() {
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.FRAME;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.JUMP_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.LABEL;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.LOOKUPSWITCH_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.TABLESWITCH_INSN;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
public class ASMBlock {
|
||||
|
||||
public InsnListSection list;
|
||||
private BiMap<String, LabelNode> labels;
|
||||
|
||||
public ASMBlock(InsnListSection list, BiMap<String, LabelNode> labels) {
|
||||
this.list = list;
|
||||
this.labels = labels;
|
||||
}
|
||||
|
||||
public ASMBlock(InsnListSection list) {
|
||||
this(list, HashBiMap.<String, LabelNode>create());
|
||||
}
|
||||
|
||||
public ASMBlock(InsnList list) {
|
||||
this(new InsnListSection(list));
|
||||
}
|
||||
|
||||
public ASMBlock() {
|
||||
this(new InsnListSection());
|
||||
}
|
||||
|
||||
public LabelNode getOrAdd(String s) {
|
||||
LabelNode l = get(s);
|
||||
if (l == null) labels.put(s, l = new LabelNode());
|
||||
return l;
|
||||
}
|
||||
|
||||
public LabelNode get(String s) {
|
||||
return labels.get(s);
|
||||
}
|
||||
|
||||
public void replaceLabels(Map<LabelNode, LabelNode> labelMap, Set<LabelNode> usedLabels) {
|
||||
for (AbstractInsnNode insn : list) switch (insn.getType()) {
|
||||
case LABEL:
|
||||
AbstractInsnNode insn2 = insn.clone(labelMap);
|
||||
if (insn2 == insn) // identity mapping
|
||||
continue;
|
||||
if (usedLabels.contains(insn2))
|
||||
throw new IllegalStateException("LabelNode cannot be a part of two InsnLists");
|
||||
list.replace(insn, insn2);
|
||||
break;
|
||||
case JUMP_INSN:
|
||||
case FRAME:
|
||||
case LOOKUPSWITCH_INSN:
|
||||
case TABLESWITCH_INSN:
|
||||
list.replace(insn, insn.clone(labelMap));
|
||||
}
|
||||
|
||||
for (Entry<LabelNode, LabelNode> entry : labelMap.entrySet()) {
|
||||
String key = labels.inverse().get(entry.getKey());
|
||||
if (key != null) labels.put(key, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public void replaceLabels(Map<LabelNode, LabelNode> labelMap) {
|
||||
replaceLabels(labelMap, Collections.EMPTY_SET);
|
||||
}
|
||||
|
||||
public void replaceLabel(String s, LabelNode l) {
|
||||
LabelNode old = get(s);
|
||||
if (old != null) replaceLabels(ImmutableMap.of(old, l));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulls all common labels from other into this
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public ASMBlock mergeLabels(ASMBlock other) {
|
||||
if (labels.isEmpty() || other.labels.isEmpty()) return this;
|
||||
|
||||
// common labels, give them our nodes
|
||||
HashMap<LabelNode, LabelNode> labelMap = list.identityLabelMap();
|
||||
for (Entry<String, LabelNode> entry : other.labels.entrySet()) {
|
||||
LabelNode old = labels.get(entry.getKey());
|
||||
if (old != null) labelMap.put(old, entry.getValue());
|
||||
}
|
||||
HashSet<LabelNode> usedLabels = new HashSet<LabelNode>();
|
||||
for (AbstractInsnNode insn = other.list.list.getFirst(); insn != null; insn = insn.getNext())
|
||||
if (insn.getType() == LABEL) usedLabels.add((LabelNode) insn);
|
||||
|
||||
replaceLabels(labelMap, usedLabels);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like mergeLabels but pulls insns from other list into this so LabelNodes can be transferred
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public ASMBlock pullLabels(ASMBlock other) {
|
||||
other.list.remove();
|
||||
return mergeLabels(other);
|
||||
}
|
||||
|
||||
public ASMBlock copy() {
|
||||
BiMap<String, LabelNode> labels = HashBiMap.create();
|
||||
Map<LabelNode, LabelNode> labelMap = list.cloneLabels();
|
||||
|
||||
for (Entry<String, LabelNode> entry : this.labels.entrySet())
|
||||
labels.put(entry.getKey(), labelMap.get(entry.getValue()));
|
||||
|
||||
return new ASMBlock(list.copy(labelMap), labels);
|
||||
}
|
||||
|
||||
public ASMBlock applyLabels(InsnListSection list2) {
|
||||
if (labels.isEmpty()) return new ASMBlock(list2);
|
||||
|
||||
Set<LabelNode> cFlowLabels1 = labels.values();
|
||||
Set<LabelNode> cFlowLabels2 = InsnComparator.getControlFlowLabels(list2);
|
||||
ASMBlock block = new ASMBlock(list2);
|
||||
|
||||
HashMap<LabelNode, LabelNode> labelMap = new HashMap<LabelNode, LabelNode>();
|
||||
|
||||
for (int i = 0, k = 0; i < list.size() && k < list2.size();) {
|
||||
AbstractInsnNode insn1 = list.get(i);
|
||||
if (!InsnComparator.insnImportant(insn1, cFlowLabels1)) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
AbstractInsnNode insn2 = list2.get(k);
|
||||
if (!InsnComparator.insnImportant(insn2, cFlowLabels2)) {
|
||||
k++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (insn1.getOpcode() != insn2.getOpcode())
|
||||
throw new IllegalArgumentException("Lists do not match:\n" + list + "\n\n" + list2);
|
||||
|
||||
switch (insn1.getType()) {
|
||||
case LABEL:
|
||||
labelMap.put((LabelNode) insn1, (LabelNode) insn2);
|
||||
break;
|
||||
case JUMP_INSN:
|
||||
labelMap.put(((JumpInsnNode) insn1).label, ((JumpInsnNode) insn2).label);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
k++;
|
||||
}
|
||||
|
||||
for (Entry<String, LabelNode> entry : labels.entrySet())
|
||||
block.labels.put(entry.getKey(), labelMap.get(entry.getValue()));
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
public InsnList rawListCopy() {
|
||||
return list.copy().list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
import org.objectweb.asm.tree.LocalVariableNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.TryCatchBlockNode;
|
||||
import org.objectweb.asm.util.ASMifier;
|
||||
import org.objectweb.asm.util.Textifier;
|
||||
import org.objectweb.asm.util.TraceClassVisitor;
|
||||
|
||||
import codechicken.lib.config.ConfigFile;
|
||||
import codechicken.lib.config.DefaultingConfigFile;
|
||||
|
||||
public class ASMHelper {
|
||||
|
||||
public static ConfigFile config = loadConfig();
|
||||
public static Logger logger = LogManager.getLogger("CCL ASM");
|
||||
|
||||
private static ConfigFile loadConfig() {
|
||||
try { // weak reference for environments without FML
|
||||
File mcDir = (File) ((Object[]) Class.forName("cpw.mods.fml.relauncher.FMLInjectionData").getMethod("data")
|
||||
.invoke(null))[6];
|
||||
File file = new File(mcDir, "config/CodeChickenLib.cfg");
|
||||
if (ObfMapping.obfuscated) return new DefaultingConfigFile(file);
|
||||
else return new ConfigFile(file).setComment("CodeChickenLib development configuration file.");
|
||||
} catch (Exception ignored) {
|
||||
return null; // no config for these systems
|
||||
}
|
||||
}
|
||||
|
||||
public static interface Acceptor {
|
||||
|
||||
public void accept(ClassVisitor cv) throws IOException;
|
||||
}
|
||||
|
||||
public static MethodNode findMethod(ObfMapping methodmap, ClassNode cnode) {
|
||||
for (MethodNode mnode : cnode.methods) if (methodmap.matches(mnode)) return mnode;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static FieldNode findField(ObfMapping fieldmap, ClassNode cnode) {
|
||||
for (FieldNode fnode : cnode.fields) if (fieldmap.matches(fnode)) return fnode;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ClassNode createClassNode(byte[] bytes) {
|
||||
return createClassNode(bytes, 0);
|
||||
}
|
||||
|
||||
public static ClassNode createClassNode(byte[] bytes, int flags) {
|
||||
ClassNode cnode = new ClassNode();
|
||||
ClassReader reader = new ClassReader(bytes);
|
||||
reader.accept(cnode, flags);
|
||||
return cnode;
|
||||
}
|
||||
|
||||
public static byte[] createBytes(ClassNode cnode, int flags) {
|
||||
ClassWriter cw = new CC_ClassWriter(flags);
|
||||
cnode.accept(cw);
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
public static Map<LabelNode, LabelNode> cloneLabels(InsnList list) {
|
||||
return new InsnListSection(list).cloneLabels();
|
||||
}
|
||||
|
||||
public static InsnList cloneInsnList(InsnList list) {
|
||||
return new InsnListSection(list).copy().list;
|
||||
}
|
||||
|
||||
public static InsnList cloneInsnList(Map<LabelNode, LabelNode> labelMap, InsnList list) {
|
||||
return new InsnListSection(list).copy(labelMap).list;
|
||||
}
|
||||
|
||||
public static List<TryCatchBlockNode> cloneTryCatchBlocks(Map<LabelNode, LabelNode> labelMap,
|
||||
List<TryCatchBlockNode> tcblocks) {
|
||||
ArrayList<TryCatchBlockNode> clone = new ArrayList<TryCatchBlockNode>();
|
||||
for (TryCatchBlockNode node : tcblocks) clone.add(
|
||||
new TryCatchBlockNode(
|
||||
labelMap.get(node.start),
|
||||
labelMap.get(node.end),
|
||||
labelMap.get(node.handler),
|
||||
node.type));
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
public static List<LocalVariableNode> cloneLocals(Map<LabelNode, LabelNode> labelMap,
|
||||
List<LocalVariableNode> locals) {
|
||||
ArrayList<LocalVariableNode> clone = new ArrayList<LocalVariableNode>(locals.size());
|
||||
for (LocalVariableNode node : locals) clone.add(
|
||||
new LocalVariableNode(
|
||||
node.name,
|
||||
node.desc,
|
||||
node.signature,
|
||||
labelMap.get(node.start),
|
||||
labelMap.get(node.end),
|
||||
node.index));
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
public static void copy(MethodNode src, MethodNode dst) {
|
||||
Map<LabelNode, LabelNode> labelMap = cloneLabels(src.instructions);
|
||||
dst.instructions = cloneInsnList(labelMap, src.instructions);
|
||||
dst.tryCatchBlocks = cloneTryCatchBlocks(labelMap, src.tryCatchBlocks);
|
||||
if (src.localVariables != null) dst.localVariables = cloneLocals(labelMap, src.localVariables);
|
||||
dst.visibleAnnotations = src.visibleAnnotations;
|
||||
dst.invisibleAnnotations = src.invisibleAnnotations;
|
||||
dst.visitMaxs(src.maxStack, src.maxLocals);
|
||||
}
|
||||
|
||||
public static String toString(InsnList list) {
|
||||
return new InsnListSection(list).toString();
|
||||
}
|
||||
|
||||
public static int getLocal(List<LocalVariableNode> list, String name) {
|
||||
int found = -1;
|
||||
for (LocalVariableNode node : list) {
|
||||
if (node.name.equals(name)) {
|
||||
if (found >= 0) throw new RuntimeException(
|
||||
"Duplicate local variable: " + name + " not coded to handle this scenario.");
|
||||
|
||||
found = node.index;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
public static void replaceMethod(MethodNode original, MethodNode replacement) {
|
||||
original.instructions.clear();
|
||||
if (original.localVariables != null) original.localVariables.clear();
|
||||
if (original.tryCatchBlocks != null) original.tryCatchBlocks.clear();
|
||||
replacement.accept(original);
|
||||
}
|
||||
|
||||
public static void dump(Acceptor acceptor, File file, boolean filterImportant, boolean sortLocals,
|
||||
boolean textify) {
|
||||
try {
|
||||
if (!file.getParentFile().exists()) file.getParentFile().mkdirs();
|
||||
if (!file.exists()) file.createNewFile();
|
||||
|
||||
PrintWriter pout = new PrintWriter(file);
|
||||
ClassVisitor cv = new TraceClassVisitor(null, textify ? new Textifier() : new ASMifier(), pout);
|
||||
if (filterImportant) cv = new ImportantInsnVisitor(cv);
|
||||
if (sortLocals) cv = new LocalVariablesSorterVisitor(cv);
|
||||
acceptor.accept(cv);
|
||||
pout.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void dump(Acceptor acceptor, File file, boolean filterImportant, boolean sortLocals) {
|
||||
dump(acceptor, file, filterImportant, sortLocals, config.getTag("textify").getBooleanValue(true));
|
||||
}
|
||||
|
||||
public static void dump(final byte[] bytes, File file, boolean filterImportant, boolean sortLocals) {
|
||||
dump(new Acceptor() {
|
||||
|
||||
@Override
|
||||
public void accept(ClassVisitor cv) {
|
||||
new ClassReader(bytes).accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
}
|
||||
}, file, filterImportant, sortLocals);
|
||||
}
|
||||
|
||||
public static void dump(final InputStream is, File file, boolean filterImportant, boolean sortLocals) {
|
||||
dump(new Acceptor() {
|
||||
|
||||
@Override
|
||||
public void accept(ClassVisitor cv) throws IOException {
|
||||
new ClassReader(is).accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
}
|
||||
}, file, filterImportant, sortLocals);
|
||||
}
|
||||
|
||||
public static void dump(final ClassNode cnode, File file, boolean filterImportant, boolean sortLocals) {
|
||||
dump(new Acceptor() {
|
||||
|
||||
@Override
|
||||
public void accept(ClassVisitor cv) {
|
||||
cnode.accept(cv);
|
||||
}
|
||||
}, file, filterImportant, sortLocals);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
|
||||
/**
|
||||
* Initialisation class for using this package. Call this on coremod load
|
||||
*/
|
||||
public class ASMInit {
|
||||
|
||||
private static boolean initialised = false;
|
||||
|
||||
public static void init() {
|
||||
if (!initialised) {
|
||||
Launch.classLoader.addTransformerExclusion("codechicken.lib.asm");
|
||||
Launch.classLoader.addTransformerExclusion("codechicken.lib.config");
|
||||
initialised = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,469 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.AALOAD;
|
||||
import static org.objectweb.asm.Opcodes.AASTORE;
|
||||
import static org.objectweb.asm.Opcodes.ACONST_NULL;
|
||||
import static org.objectweb.asm.Opcodes.ALOAD;
|
||||
import static org.objectweb.asm.Opcodes.ANEWARRAY;
|
||||
import static org.objectweb.asm.Opcodes.ARETURN;
|
||||
import static org.objectweb.asm.Opcodes.ARRAYLENGTH;
|
||||
import static org.objectweb.asm.Opcodes.ASTORE;
|
||||
import static org.objectweb.asm.Opcodes.ATHROW;
|
||||
import static org.objectweb.asm.Opcodes.BALOAD;
|
||||
import static org.objectweb.asm.Opcodes.BASTORE;
|
||||
import static org.objectweb.asm.Opcodes.BIPUSH;
|
||||
import static org.objectweb.asm.Opcodes.CALOAD;
|
||||
import static org.objectweb.asm.Opcodes.CASTORE;
|
||||
import static org.objectweb.asm.Opcodes.CHECKCAST;
|
||||
import static org.objectweb.asm.Opcodes.D2F;
|
||||
import static org.objectweb.asm.Opcodes.D2I;
|
||||
import static org.objectweb.asm.Opcodes.D2L;
|
||||
import static org.objectweb.asm.Opcodes.DADD;
|
||||
import static org.objectweb.asm.Opcodes.DALOAD;
|
||||
import static org.objectweb.asm.Opcodes.DASTORE;
|
||||
import static org.objectweb.asm.Opcodes.DCMPG;
|
||||
import static org.objectweb.asm.Opcodes.DCMPL;
|
||||
import static org.objectweb.asm.Opcodes.DCONST_0;
|
||||
import static org.objectweb.asm.Opcodes.DCONST_1;
|
||||
import static org.objectweb.asm.Opcodes.DDIV;
|
||||
import static org.objectweb.asm.Opcodes.DLOAD;
|
||||
import static org.objectweb.asm.Opcodes.DMUL;
|
||||
import static org.objectweb.asm.Opcodes.DNEG;
|
||||
import static org.objectweb.asm.Opcodes.DREM;
|
||||
import static org.objectweb.asm.Opcodes.DRETURN;
|
||||
import static org.objectweb.asm.Opcodes.DSTORE;
|
||||
import static org.objectweb.asm.Opcodes.DSUB;
|
||||
import static org.objectweb.asm.Opcodes.DUP;
|
||||
import static org.objectweb.asm.Opcodes.DUP2;
|
||||
import static org.objectweb.asm.Opcodes.DUP2_X1;
|
||||
import static org.objectweb.asm.Opcodes.DUP2_X2;
|
||||
import static org.objectweb.asm.Opcodes.DUP_X1;
|
||||
import static org.objectweb.asm.Opcodes.DUP_X2;
|
||||
import static org.objectweb.asm.Opcodes.F2D;
|
||||
import static org.objectweb.asm.Opcodes.F2I;
|
||||
import static org.objectweb.asm.Opcodes.F2L;
|
||||
import static org.objectweb.asm.Opcodes.FADD;
|
||||
import static org.objectweb.asm.Opcodes.FALOAD;
|
||||
import static org.objectweb.asm.Opcodes.FASTORE;
|
||||
import static org.objectweb.asm.Opcodes.FCMPG;
|
||||
import static org.objectweb.asm.Opcodes.FCMPL;
|
||||
import static org.objectweb.asm.Opcodes.FCONST_0;
|
||||
import static org.objectweb.asm.Opcodes.FCONST_1;
|
||||
import static org.objectweb.asm.Opcodes.FCONST_2;
|
||||
import static org.objectweb.asm.Opcodes.FDIV;
|
||||
import static org.objectweb.asm.Opcodes.FLOAD;
|
||||
import static org.objectweb.asm.Opcodes.FMUL;
|
||||
import static org.objectweb.asm.Opcodes.FNEG;
|
||||
import static org.objectweb.asm.Opcodes.FREM;
|
||||
import static org.objectweb.asm.Opcodes.FRETURN;
|
||||
import static org.objectweb.asm.Opcodes.FSTORE;
|
||||
import static org.objectweb.asm.Opcodes.FSUB;
|
||||
import static org.objectweb.asm.Opcodes.GETFIELD;
|
||||
import static org.objectweb.asm.Opcodes.GETSTATIC;
|
||||
import static org.objectweb.asm.Opcodes.GOTO;
|
||||
import static org.objectweb.asm.Opcodes.I2B;
|
||||
import static org.objectweb.asm.Opcodes.I2C;
|
||||
import static org.objectweb.asm.Opcodes.I2D;
|
||||
import static org.objectweb.asm.Opcodes.I2F;
|
||||
import static org.objectweb.asm.Opcodes.I2L;
|
||||
import static org.objectweb.asm.Opcodes.I2S;
|
||||
import static org.objectweb.asm.Opcodes.IADD;
|
||||
import static org.objectweb.asm.Opcodes.IALOAD;
|
||||
import static org.objectweb.asm.Opcodes.IAND;
|
||||
import static org.objectweb.asm.Opcodes.IASTORE;
|
||||
import static org.objectweb.asm.Opcodes.ICONST_0;
|
||||
import static org.objectweb.asm.Opcodes.ICONST_1;
|
||||
import static org.objectweb.asm.Opcodes.ICONST_2;
|
||||
import static org.objectweb.asm.Opcodes.ICONST_3;
|
||||
import static org.objectweb.asm.Opcodes.ICONST_4;
|
||||
import static org.objectweb.asm.Opcodes.ICONST_5;
|
||||
import static org.objectweb.asm.Opcodes.ICONST_M1;
|
||||
import static org.objectweb.asm.Opcodes.IDIV;
|
||||
import static org.objectweb.asm.Opcodes.IFEQ;
|
||||
import static org.objectweb.asm.Opcodes.IFGE;
|
||||
import static org.objectweb.asm.Opcodes.IFGT;
|
||||
import static org.objectweb.asm.Opcodes.IFLE;
|
||||
import static org.objectweb.asm.Opcodes.IFLT;
|
||||
import static org.objectweb.asm.Opcodes.IFNE;
|
||||
import static org.objectweb.asm.Opcodes.IFNONNULL;
|
||||
import static org.objectweb.asm.Opcodes.IFNULL;
|
||||
import static org.objectweb.asm.Opcodes.IF_ACMPEQ;
|
||||
import static org.objectweb.asm.Opcodes.IF_ACMPNE;
|
||||
import static org.objectweb.asm.Opcodes.IF_ICMPEQ;
|
||||
import static org.objectweb.asm.Opcodes.IF_ICMPGE;
|
||||
import static org.objectweb.asm.Opcodes.IF_ICMPGT;
|
||||
import static org.objectweb.asm.Opcodes.IF_ICMPLE;
|
||||
import static org.objectweb.asm.Opcodes.IF_ICMPLT;
|
||||
import static org.objectweb.asm.Opcodes.IF_ICMPNE;
|
||||
import static org.objectweb.asm.Opcodes.IINC;
|
||||
import static org.objectweb.asm.Opcodes.ILOAD;
|
||||
import static org.objectweb.asm.Opcodes.IMUL;
|
||||
import static org.objectweb.asm.Opcodes.INEG;
|
||||
import static org.objectweb.asm.Opcodes.INSTANCEOF;
|
||||
import static org.objectweb.asm.Opcodes.INVOKEDYNAMIC;
|
||||
import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
|
||||
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
|
||||
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
|
||||
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
|
||||
import static org.objectweb.asm.Opcodes.IOR;
|
||||
import static org.objectweb.asm.Opcodes.IREM;
|
||||
import static org.objectweb.asm.Opcodes.IRETURN;
|
||||
import static org.objectweb.asm.Opcodes.ISHL;
|
||||
import static org.objectweb.asm.Opcodes.ISHR;
|
||||
import static org.objectweb.asm.Opcodes.ISTORE;
|
||||
import static org.objectweb.asm.Opcodes.ISUB;
|
||||
import static org.objectweb.asm.Opcodes.IUSHR;
|
||||
import static org.objectweb.asm.Opcodes.IXOR;
|
||||
import static org.objectweb.asm.Opcodes.JSR;
|
||||
import static org.objectweb.asm.Opcodes.L2D;
|
||||
import static org.objectweb.asm.Opcodes.L2F;
|
||||
import static org.objectweb.asm.Opcodes.L2I;
|
||||
import static org.objectweb.asm.Opcodes.LADD;
|
||||
import static org.objectweb.asm.Opcodes.LALOAD;
|
||||
import static org.objectweb.asm.Opcodes.LAND;
|
||||
import static org.objectweb.asm.Opcodes.LASTORE;
|
||||
import static org.objectweb.asm.Opcodes.LCMP;
|
||||
import static org.objectweb.asm.Opcodes.LCONST_0;
|
||||
import static org.objectweb.asm.Opcodes.LCONST_1;
|
||||
import static org.objectweb.asm.Opcodes.LDC;
|
||||
import static org.objectweb.asm.Opcodes.LDIV;
|
||||
import static org.objectweb.asm.Opcodes.LLOAD;
|
||||
import static org.objectweb.asm.Opcodes.LMUL;
|
||||
import static org.objectweb.asm.Opcodes.LNEG;
|
||||
import static org.objectweb.asm.Opcodes.LOOKUPSWITCH;
|
||||
import static org.objectweb.asm.Opcodes.LOR;
|
||||
import static org.objectweb.asm.Opcodes.LREM;
|
||||
import static org.objectweb.asm.Opcodes.LRETURN;
|
||||
import static org.objectweb.asm.Opcodes.LSHL;
|
||||
import static org.objectweb.asm.Opcodes.LSHR;
|
||||
import static org.objectweb.asm.Opcodes.LSTORE;
|
||||
import static org.objectweb.asm.Opcodes.LSUB;
|
||||
import static org.objectweb.asm.Opcodes.LUSHR;
|
||||
import static org.objectweb.asm.Opcodes.LXOR;
|
||||
import static org.objectweb.asm.Opcodes.MONITORENTER;
|
||||
import static org.objectweb.asm.Opcodes.MONITOREXIT;
|
||||
import static org.objectweb.asm.Opcodes.MULTIANEWARRAY;
|
||||
import static org.objectweb.asm.Opcodes.NEW;
|
||||
import static org.objectweb.asm.Opcodes.NEWARRAY;
|
||||
import static org.objectweb.asm.Opcodes.NOP;
|
||||
import static org.objectweb.asm.Opcodes.POP;
|
||||
import static org.objectweb.asm.Opcodes.POP2;
|
||||
import static org.objectweb.asm.Opcodes.PUTFIELD;
|
||||
import static org.objectweb.asm.Opcodes.PUTSTATIC;
|
||||
import static org.objectweb.asm.Opcodes.RET;
|
||||
import static org.objectweb.asm.Opcodes.RETURN;
|
||||
import static org.objectweb.asm.Opcodes.SALOAD;
|
||||
import static org.objectweb.asm.Opcodes.SASTORE;
|
||||
import static org.objectweb.asm.Opcodes.SIPUSH;
|
||||
import static org.objectweb.asm.Opcodes.SWAP;
|
||||
import static org.objectweb.asm.Opcodes.TABLESWITCH;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.FIELD_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.FRAME;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.IINC_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.INT_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.INVOKE_DYNAMIC_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.JUMP_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.LABEL;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.LDC_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.LOOKUPSWITCH_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.METHOD_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.MULTIANEWARRAY_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.TABLESWITCH_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.TYPE_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.VAR_INSN;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.IincInsnNode;
|
||||
import org.objectweb.asm.tree.InsnNode;
|
||||
import org.objectweb.asm.tree.IntInsnNode;
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.LineNumberNode;
|
||||
import org.objectweb.asm.tree.MultiANewArrayInsnNode;
|
||||
import org.objectweb.asm.tree.VarInsnNode;
|
||||
|
||||
public class ASMReader {
|
||||
|
||||
public static Map<String, Integer> opCodes = new HashMap<String, Integer>();
|
||||
public static byte[] TYPE;
|
||||
|
||||
static {
|
||||
opCodes.put("NOP", NOP);
|
||||
opCodes.put("ACONST_NULL", ACONST_NULL);
|
||||
opCodes.put("ICONST_M1", ICONST_M1);
|
||||
opCodes.put("ICONST_0", ICONST_0);
|
||||
opCodes.put("ICONST_1", ICONST_1);
|
||||
opCodes.put("ICONST_2", ICONST_2);
|
||||
opCodes.put("ICONST_3", ICONST_3);
|
||||
opCodes.put("ICONST_4", ICONST_4);
|
||||
opCodes.put("ICONST_5", ICONST_5);
|
||||
opCodes.put("LCONST_0", LCONST_0);
|
||||
opCodes.put("LCONST_1", LCONST_1);
|
||||
opCodes.put("FCONST_0", FCONST_0);
|
||||
opCodes.put("FCONST_1", FCONST_1);
|
||||
opCodes.put("FCONST_2", FCONST_2);
|
||||
opCodes.put("DCONST_0", DCONST_0);
|
||||
opCodes.put("DCONST_1", DCONST_1);
|
||||
opCodes.put("BIPUSH", BIPUSH);
|
||||
opCodes.put("SIPUSH", SIPUSH);
|
||||
opCodes.put("LDC", LDC);
|
||||
opCodes.put("ILOAD", ILOAD);
|
||||
opCodes.put("LLOAD", LLOAD);
|
||||
opCodes.put("FLOAD", FLOAD);
|
||||
opCodes.put("DLOAD", DLOAD);
|
||||
opCodes.put("ALOAD", ALOAD);
|
||||
opCodes.put("IALOAD", IALOAD);
|
||||
opCodes.put("LALOAD", LALOAD);
|
||||
opCodes.put("FALOAD", FALOAD);
|
||||
opCodes.put("DALOAD", DALOAD);
|
||||
opCodes.put("AALOAD", AALOAD);
|
||||
opCodes.put("BALOAD", BALOAD);
|
||||
opCodes.put("CALOAD", CALOAD);
|
||||
opCodes.put("SALOAD", SALOAD);
|
||||
opCodes.put("ISTORE", ISTORE);
|
||||
opCodes.put("LSTORE", LSTORE);
|
||||
opCodes.put("FSTORE", FSTORE);
|
||||
opCodes.put("DSTORE", DSTORE);
|
||||
opCodes.put("ASTORE", ASTORE);
|
||||
opCodes.put("IASTORE", IASTORE);
|
||||
opCodes.put("LASTORE", LASTORE);
|
||||
opCodes.put("FASTORE", FASTORE);
|
||||
opCodes.put("DASTORE", DASTORE);
|
||||
opCodes.put("AASTORE", AASTORE);
|
||||
opCodes.put("BASTORE", BASTORE);
|
||||
opCodes.put("CASTORE", CASTORE);
|
||||
opCodes.put("SASTORE", SASTORE);
|
||||
opCodes.put("POP", POP);
|
||||
opCodes.put("POP2", POP2);
|
||||
opCodes.put("DUP", DUP);
|
||||
opCodes.put("DUP_X1", DUP_X1);
|
||||
opCodes.put("DUP_X2", DUP_X2);
|
||||
opCodes.put("DUP2", DUP2);
|
||||
opCodes.put("DUP2_X1", DUP2_X1);
|
||||
opCodes.put("DUP2_X2", DUP2_X2);
|
||||
opCodes.put("SWAP", SWAP);
|
||||
opCodes.put("IADD", IADD);
|
||||
opCodes.put("LADD", LADD);
|
||||
opCodes.put("FADD", FADD);
|
||||
opCodes.put("DADD", DADD);
|
||||
opCodes.put("ISUB", ISUB);
|
||||
opCodes.put("LSUB", LSUB);
|
||||
opCodes.put("FSUB", FSUB);
|
||||
opCodes.put("DSUB", DSUB);
|
||||
opCodes.put("IMUL", IMUL);
|
||||
opCodes.put("LMUL", LMUL);
|
||||
opCodes.put("FMUL", FMUL);
|
||||
opCodes.put("DMUL", DMUL);
|
||||
opCodes.put("IDIV", IDIV);
|
||||
opCodes.put("LDIV", LDIV);
|
||||
opCodes.put("FDIV", FDIV);
|
||||
opCodes.put("DDIV", DDIV);
|
||||
opCodes.put("IREM", IREM);
|
||||
opCodes.put("LREM", LREM);
|
||||
opCodes.put("FREM", FREM);
|
||||
opCodes.put("DREM", DREM);
|
||||
opCodes.put("INEG", INEG);
|
||||
opCodes.put("LNEG", LNEG);
|
||||
opCodes.put("FNEG", FNEG);
|
||||
opCodes.put("DNEG", DNEG);
|
||||
opCodes.put("ISHL", ISHL);
|
||||
opCodes.put("LSHL", LSHL);
|
||||
opCodes.put("ISHR", ISHR);
|
||||
opCodes.put("LSHR", LSHR);
|
||||
opCodes.put("IUSHR", IUSHR);
|
||||
opCodes.put("LUSHR", LUSHR);
|
||||
opCodes.put("IAND", IAND);
|
||||
opCodes.put("LAND", LAND);
|
||||
opCodes.put("IOR", IOR);
|
||||
opCodes.put("LOR", LOR);
|
||||
opCodes.put("IXOR", IXOR);
|
||||
opCodes.put("LXOR", LXOR);
|
||||
opCodes.put("IINC", IINC);
|
||||
opCodes.put("I2L", I2L);
|
||||
opCodes.put("I2F", I2F);
|
||||
opCodes.put("I2D", I2D);
|
||||
opCodes.put("L2I", L2I);
|
||||
opCodes.put("L2F", L2F);
|
||||
opCodes.put("L2D", L2D);
|
||||
opCodes.put("F2I", F2I);
|
||||
opCodes.put("F2L", F2L);
|
||||
opCodes.put("F2D", F2D);
|
||||
opCodes.put("D2I", D2I);
|
||||
opCodes.put("D2L", D2L);
|
||||
opCodes.put("D2F", D2F);
|
||||
opCodes.put("I2B", I2B);
|
||||
opCodes.put("I2C", I2C);
|
||||
opCodes.put("I2S", I2S);
|
||||
opCodes.put("LCMP", LCMP);
|
||||
opCodes.put("FCMPL", FCMPL);
|
||||
opCodes.put("FCMPG", FCMPG);
|
||||
opCodes.put("DCMPL", DCMPL);
|
||||
opCodes.put("DCMPG", DCMPG);
|
||||
opCodes.put("IFEQ", IFEQ);
|
||||
opCodes.put("IFNE", IFNE);
|
||||
opCodes.put("IFLT", IFLT);
|
||||
opCodes.put("IFGE", IFGE);
|
||||
opCodes.put("IFGT", IFGT);
|
||||
opCodes.put("IFLE", IFLE);
|
||||
opCodes.put("IF_ICMPEQ", IF_ICMPEQ);
|
||||
opCodes.put("IF_ICMPNE", IF_ICMPNE);
|
||||
opCodes.put("IF_ICMPLT", IF_ICMPLT);
|
||||
opCodes.put("IF_ICMPGE", IF_ICMPGE);
|
||||
opCodes.put("IF_ICMPGT", IF_ICMPGT);
|
||||
opCodes.put("IF_ICMPLE", IF_ICMPLE);
|
||||
opCodes.put("IF_ACMPEQ", IF_ACMPEQ);
|
||||
opCodes.put("IF_ACMPNE", IF_ACMPNE);
|
||||
opCodes.put("GOTO", GOTO);
|
||||
opCodes.put("JSR", JSR);
|
||||
opCodes.put("RET", RET);
|
||||
opCodes.put("TABLESWITCH", TABLESWITCH);
|
||||
opCodes.put("LOOKUPSWITCH", LOOKUPSWITCH);
|
||||
opCodes.put("IRETURN", IRETURN);
|
||||
opCodes.put("LRETURN", LRETURN);
|
||||
opCodes.put("FRETURN", FRETURN);
|
||||
opCodes.put("DRETURN", DRETURN);
|
||||
opCodes.put("ARETURN", ARETURN);
|
||||
opCodes.put("RETURN", RETURN);
|
||||
opCodes.put("GETSTATIC", GETSTATIC);
|
||||
opCodes.put("PUTSTATIC", PUTSTATIC);
|
||||
opCodes.put("GETFIELD", GETFIELD);
|
||||
opCodes.put("PUTFIELD", PUTFIELD);
|
||||
opCodes.put("INVOKEVIRTUAL", INVOKEVIRTUAL);
|
||||
opCodes.put("INVOKESPECIAL", INVOKESPECIAL);
|
||||
opCodes.put("INVOKESTATIC", INVOKESTATIC);
|
||||
opCodes.put("INVOKEINTERFACE", INVOKEINTERFACE);
|
||||
opCodes.put("INVOKEDYNAMIC", INVOKEDYNAMIC);
|
||||
opCodes.put("NEW", NEW);
|
||||
opCodes.put("NEWARRAY", NEWARRAY);
|
||||
opCodes.put("ANEWARRAY", ANEWARRAY);
|
||||
opCodes.put("ARRAYLENGTH", ARRAYLENGTH);
|
||||
opCodes.put("ATHROW", ATHROW);
|
||||
opCodes.put("CHECKCAST", CHECKCAST);
|
||||
opCodes.put("INSTANCEOF", INSTANCEOF);
|
||||
opCodes.put("MONITORENTER", MONITORENTER);
|
||||
opCodes.put("MONITOREXIT", MONITOREXIT);
|
||||
opCodes.put("MULTIANEWARRAY", MULTIANEWARRAY);
|
||||
opCodes.put("IFNULL", IFNULL);
|
||||
opCodes.put("IFNONNULL", IFNONNULL);
|
||||
|
||||
// derived from classWriter, mapped to AbstractInsnNode
|
||||
TYPE = new byte[200];
|
||||
String s = "AAAAAAAAAAAAAAAABBJ__CCCCC____________________AAAAAAAACC"
|
||||
+ "CCC____________________AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
+ "AAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAHHHHHHHHHHHHHHHHCLMAA"
|
||||
+ "AAAAEEEEFFFFGDBDAADDAA_NHH";
|
||||
for (int i = 0; i < s.length(); i++) TYPE[i] = (byte) (s.charAt(i) - 'A');
|
||||
}
|
||||
|
||||
public static Map<String, ASMBlock> loadResource(String res) {
|
||||
return loadResource(ASMHelper.class.getResourceAsStream(res), res);
|
||||
}
|
||||
|
||||
public static Map<String, ASMBlock> loadResource(InputStream in, String res) {
|
||||
HashMap<String, ASMBlock> blocks = new HashMap<String, ASMBlock>();
|
||||
String current = "unnamed";
|
||||
ASMBlock block = new ASMBlock();
|
||||
try {
|
||||
BufferedReader r = new BufferedReader(new InputStreamReader(in));
|
||||
String line;
|
||||
while ((line = r.readLine()) != null) {
|
||||
{
|
||||
int hpos = line.indexOf('#');
|
||||
if (hpos >= 0) line = line.substring(0, hpos);
|
||||
}
|
||||
line = line.trim();
|
||||
if (line.length() == 0) continue;
|
||||
if (line.startsWith("list ")) {
|
||||
if (block.list.size() > 0) blocks.put(current, block);
|
||||
current = line.substring(5);
|
||||
block = new ASMBlock();
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
AbstractInsnNode insn = null;
|
||||
String[] split = line.replace(" : ", ":").split(" ");
|
||||
Integer i_opcode = opCodes.get(split[0]);
|
||||
if (i_opcode == null) {
|
||||
if (split[0].equals("LINENUMBER"))
|
||||
insn = new LineNumberNode(Integer.parseInt(split[1]), block.getOrAdd(split[2]));
|
||||
else if (split[0].startsWith("L")) insn = block.getOrAdd(split[0]);
|
||||
else throw new Exception("Unknown opcode " + split[0]);
|
||||
} else {
|
||||
int opcode = i_opcode;
|
||||
switch (TYPE[opcode]) {
|
||||
case INSN:
|
||||
insn = new InsnNode(opcode);
|
||||
break;
|
||||
case INT_INSN:
|
||||
insn = new IntInsnNode(opcode, Integer.parseInt(split[1]));
|
||||
break;
|
||||
case VAR_INSN:
|
||||
insn = new VarInsnNode(opcode, Integer.parseInt(split[1]));
|
||||
break;
|
||||
case TYPE_INSN:
|
||||
insn = new ObfMapping(split[1]).toClassloading().toInsn(opcode);
|
||||
break;
|
||||
case FIELD_INSN:
|
||||
case METHOD_INSN:
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 1; i < split.length; i++) sb.append(split[i]);
|
||||
insn = ObfMapping.fromDesc(sb.toString()).toClassloading().toInsn(opcode);
|
||||
break;
|
||||
case INVOKE_DYNAMIC_INSN:
|
||||
throw new Exception("Found INVOKEDYNAMIC while reading");
|
||||
case JUMP_INSN:
|
||||
insn = new JumpInsnNode(opcode, block.getOrAdd(split[1]));
|
||||
break;
|
||||
case LDC_INSN:
|
||||
String cst = split[1];
|
||||
if (cst.equals("*")) insn = new LdcInsnNode(null);
|
||||
else if (cst.endsWith("\"")) insn = new LdcInsnNode(cst.substring(1, cst.length() - 1));
|
||||
else if (cst.endsWith("L"))
|
||||
insn = new LdcInsnNode(Long.valueOf(cst.substring(0, cst.length() - 1)));
|
||||
else if (cst.endsWith("F"))
|
||||
insn = new LdcInsnNode(Float.valueOf(cst.substring(0, cst.length() - 1)));
|
||||
else if (cst.endsWith("D"))
|
||||
insn = new LdcInsnNode(Double.valueOf(cst.substring(0, cst.length() - 1)));
|
||||
else if (cst.contains(".")) insn = new LdcInsnNode(Double.valueOf(cst));
|
||||
else insn = new LdcInsnNode(Integer.valueOf(cst));
|
||||
break;
|
||||
case IINC_INSN:
|
||||
insn = new IincInsnNode(opcode, Integer.parseInt(split[1]));
|
||||
break;
|
||||
case LABEL:
|
||||
throw new Exception("Use L# for labels");
|
||||
case TABLESWITCH_INSN:
|
||||
case LOOKUPSWITCH_INSN:
|
||||
throw new Exception("I don't know how to deal with this insn type");
|
||||
case MULTIANEWARRAY_INSN:
|
||||
insn = new MultiANewArrayInsnNode(split[1], Integer.parseInt(split[2]));
|
||||
break;
|
||||
case FRAME:
|
||||
throw new Exception("Use ClassWriter.COMPUTE_FRAMES");
|
||||
}
|
||||
}
|
||||
|
||||
if (insn != null) block.list.add(insn);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error while reading ASM Block " + current + " from " + res + ", line: " + line);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
r.close();
|
||||
if (block.list.size() > 0) blocks.put(current, block);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to read ASM resource: " + res, e);
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
|
||||
public class CC_ClassWriter extends ClassWriter {
|
||||
|
||||
private final boolean runtime;
|
||||
|
||||
public CC_ClassWriter(int flags) {
|
||||
this(flags, false);
|
||||
}
|
||||
|
||||
public CC_ClassWriter(int flags, boolean runtime) {
|
||||
super(flags);
|
||||
this.runtime = runtime;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCommonSuperClass(String type1, String type2) {
|
||||
String c = type1.replace('/', '.');
|
||||
String d = type2.replace('/', '.');
|
||||
if (ClassHeirachyManager.classExtends(d, c)) return type1;
|
||||
if (ClassHeirachyManager.classExtends(c, d)) return type2;
|
||||
do {
|
||||
c = ClassHeirachyManager.getSuperClass(c, runtime);
|
||||
} while (!ClassHeirachyManager.classExtends(d, c));
|
||||
return c.replace('.', '/');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
/***
|
||||
* This Class is derived from the ASM ClassReader
|
||||
* <p>
|
||||
* ASM: a very small and fast Java bytecode manipulation framework Copyright (c) 2000-2011 INRIA, France Telecom All
|
||||
* rights reserved.
|
||||
* <p>
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation and/or other materials provided with the
|
||||
* distribution. 3. Neither the name of the copyright holders nor the names of its contributors may be used to endorse
|
||||
* or promote products derived from this software without specific prior written permission.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* Using this class to search for a (single) String reference is > 40 times faster than parsing a class with a
|
||||
* ClassReader + ClassNode while using way less RAM
|
||||
*/
|
||||
public class ClassConstantPoolParser {
|
||||
|
||||
private static final int UTF8 = 1;
|
||||
private static final int INT = 3;
|
||||
private static final int FLOAT = 4;
|
||||
private static final int LONG = 5;
|
||||
private static final int DOUBLE = 6;
|
||||
private static final int FIELD = 9;
|
||||
private static final int METH = 10;
|
||||
private static final int IMETH = 11;
|
||||
private static final int NAME_TYPE = 12;
|
||||
private static final int HANDLE = 15;
|
||||
private static final int INDY = 18;
|
||||
|
||||
private final byte[][] BYTES_TO_SEARCH;
|
||||
|
||||
public ClassConstantPoolParser(String... strings) {
|
||||
BYTES_TO_SEARCH = new byte[strings.length][];
|
||||
for (int i = 0; i < BYTES_TO_SEARCH.length; i++) {
|
||||
BYTES_TO_SEARCH[i] = strings[i].getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the constant pool of the class represented by this byte array contains one of the Strings we are
|
||||
* looking for
|
||||
*/
|
||||
public boolean find(byte[] basicClass) {
|
||||
if (basicClass == null || basicClass.length == 0) {
|
||||
return false;
|
||||
}
|
||||
// checks the class version
|
||||
if (readShort(6, basicClass) > Opcodes.V1_8) {
|
||||
return false;
|
||||
}
|
||||
// parses the constant pool
|
||||
int n = readUnsignedShort(8, basicClass);
|
||||
int index = 10;
|
||||
for (int i = 1; i < n; ++i) {
|
||||
int size;
|
||||
switch (basicClass[index]) {
|
||||
case FIELD, METH, IMETH, INT, FLOAT, NAME_TYPE, INDY -> size = 5;
|
||||
case LONG, DOUBLE -> {
|
||||
size = 9;
|
||||
++i;
|
||||
}
|
||||
case UTF8 -> {
|
||||
final int strLen = readUnsignedShort(index + 1, basicClass);
|
||||
size = 3 + strLen;
|
||||
label: for (byte[] bytes : BYTES_TO_SEARCH) {
|
||||
if (strLen == bytes.length) {
|
||||
for (int j = index + 3; j < index + 3 + strLen; j++) {
|
||||
if (basicClass[j] != bytes[j - (index + 3)]) {
|
||||
continue label;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
case HANDLE -> size = 4;
|
||||
default -> size = 3;
|
||||
}
|
||||
index += size;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static short readShort(final int index, byte[] basicClass) {
|
||||
return (short) (((basicClass[index] & 0xFF) << 8) | (basicClass[index + 1] & 0xFF));
|
||||
}
|
||||
|
||||
private static int readUnsignedShort(final int index, byte[] basicClass) {
|
||||
return ((basicClass[index] & 0xFF) << 8) | (basicClass[index + 1] & 0xFF);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;
|
||||
|
||||
/**
|
||||
* This is added as a class transformer if CodeChickenCore is installed. Adding it as a class transformer will speed
|
||||
* evaluation up slightly by automatically caching superclasses when they are first loaded.
|
||||
*/
|
||||
public class ClassHeirachyManager implements IClassTransformer {
|
||||
|
||||
static {
|
||||
ASMInit.init();
|
||||
}
|
||||
|
||||
public static class SuperCache {
|
||||
|
||||
String superclass;
|
||||
public HashSet<String> parents = new HashSet<String>();
|
||||
private boolean flattened;
|
||||
|
||||
public void add(String parent) {
|
||||
parents.add(parent);
|
||||
}
|
||||
|
||||
public void flatten() {
|
||||
if (flattened) return;
|
||||
|
||||
for (String s : new ArrayList<String>(parents)) {
|
||||
SuperCache c = declareClass(s);
|
||||
if (c != null) {
|
||||
c.flatten();
|
||||
parents.addAll(c.parents);
|
||||
}
|
||||
}
|
||||
flattened = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static HashMap<String, SuperCache> superclasses = new HashMap<String, SuperCache>();
|
||||
private static LaunchClassLoader cl = Launch.classLoader;
|
||||
|
||||
public static String toKey(String name) {
|
||||
if (ObfMapping.obfuscated)
|
||||
name = FMLDeobfuscatingRemapper.INSTANCE.map(name.replace('.', '/')).replace('/', '.');
|
||||
return name;
|
||||
}
|
||||
|
||||
public static String unKey(String name) {
|
||||
if (ObfMapping.obfuscated)
|
||||
name = FMLDeobfuscatingRemapper.INSTANCE.unmap(name.replace('.', '/')).replace('/', '.');
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name The class in question
|
||||
* @param superclass The class being extended
|
||||
* @return true if clazz extends, either directly or indirectly, superclass.
|
||||
*/
|
||||
public static boolean classExtends(String name, String superclass) {
|
||||
name = toKey(name);
|
||||
superclass = toKey(superclass);
|
||||
|
||||
if (name.equals(superclass)) return true;
|
||||
|
||||
SuperCache cache = declareClass(name);
|
||||
if (cache == null) // just can't handle this
|
||||
return false;
|
||||
|
||||
cache.flatten();
|
||||
return cache.parents.contains(superclass);
|
||||
}
|
||||
|
||||
private static SuperCache declareClass(String name) {
|
||||
name = toKey(name);
|
||||
SuperCache cache = superclasses.get(name);
|
||||
|
||||
if (cache != null) return cache;
|
||||
|
||||
try {
|
||||
byte[] bytes = cl.getClassBytes(unKey(name));
|
||||
if (bytes != null) cache = declareASM(bytes);
|
||||
} catch (Exception e) {}
|
||||
|
||||
if (cache != null) return cache;
|
||||
|
||||
try {
|
||||
cache = declareReflection(name);
|
||||
} catch (ClassNotFoundException e) {}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
private static SuperCache declareReflection(String name) throws ClassNotFoundException {
|
||||
Class<?> aclass = Class.forName(name);
|
||||
|
||||
SuperCache cache = getOrCreateCache(name);
|
||||
if (aclass.isInterface()) cache.superclass = "java.lang.Object";
|
||||
else if (name.equals("java.lang.Object")) return cache;
|
||||
else cache.superclass = toKey(aclass.getSuperclass().getName());
|
||||
|
||||
cache.add(cache.superclass);
|
||||
for (Class<?> iclass : aclass.getInterfaces()) cache.add(toKey(iclass.getName()));
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
private static SuperCache declareASM(byte[] bytes) {
|
||||
ClassNode node = ASMHelper.createClassNode(bytes);
|
||||
String name = toKey(node.name);
|
||||
|
||||
SuperCache cache = getOrCreateCache(name);
|
||||
cache.superclass = toKey(node.superName.replace('/', '.'));
|
||||
cache.add(cache.superclass);
|
||||
for (String iclass : node.interfaces) cache.add(toKey(iclass.replace('/', '.')));
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(String name, String tname, byte[] bytes) {
|
||||
if (bytes == null) return null;
|
||||
|
||||
if (!superclasses.containsKey(tname)) declareASM(bytes);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static SuperCache getOrCreateCache(String name) {
|
||||
SuperCache cache = superclasses.get(name);
|
||||
if (cache == null) superclasses.put(name, cache = new SuperCache());
|
||||
return cache;
|
||||
}
|
||||
|
||||
public static String getSuperClass(String name, boolean runtime) {
|
||||
name = toKey(name);
|
||||
SuperCache cache = declareClass(name);
|
||||
if (cache == null) return "java.lang.Object";
|
||||
|
||||
cache.flatten();
|
||||
String s = cache.superclass;
|
||||
if (!runtime) s = FMLDeobfuscatingRemapper.INSTANCE.unmap(s);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
public class ImportantInsnVisitor extends ClassVisitor {
|
||||
|
||||
public class ImportantInsnMethodVisitor extends MethodVisitor {
|
||||
|
||||
MethodVisitor delegate;
|
||||
|
||||
public ImportantInsnMethodVisitor(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
super(Opcodes.ASM4, new MethodNode(access, name, desc, signature, exceptions));
|
||||
delegate = cv.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
super.visitEnd();
|
||||
MethodNode mnode = (MethodNode) mv;
|
||||
mnode.instructions = InsnComparator.getImportantList(mnode.instructions);
|
||||
mnode.accept(delegate);
|
||||
}
|
||||
}
|
||||
|
||||
public ImportantInsnVisitor(ClassVisitor cv) {
|
||||
super(Opcodes.ASM4, cv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
return new ImportantInsnMethodVisitor(access, name, desc, signature, exceptions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.FIELD_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.FRAME;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.IINC_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.INT_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.JUMP_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.LABEL;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.LDC_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.LINE;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.LOOKUPSWITCH_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.METHOD_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.TABLESWITCH_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.TYPE_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.VAR_INSN;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.IincInsnNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.IntInsnNode;
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.LookupSwitchInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.TableSwitchInsnNode;
|
||||
import org.objectweb.asm.tree.TypeInsnNode;
|
||||
import org.objectweb.asm.tree.VarInsnNode;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
public class InsnComparator {
|
||||
|
||||
public static boolean varInsnEqual(VarInsnNode insn1, VarInsnNode insn2) {
|
||||
return insn1.var == -1 || insn2.var == -1 || insn1.var == insn2.var;
|
||||
}
|
||||
|
||||
public static boolean methodInsnEqual(MethodInsnNode insn1, MethodInsnNode insn2) {
|
||||
return insn1.owner.equals(insn2.owner) && insn1.name.equals(insn2.name) && insn1.desc.equals(insn2.desc);
|
||||
}
|
||||
|
||||
public static boolean fieldInsnEqual(FieldInsnNode insn1, FieldInsnNode insn2) {
|
||||
return insn1.owner.equals(insn2.owner) && insn1.name.equals(insn2.name) && insn1.desc.equals(insn2.desc);
|
||||
}
|
||||
|
||||
public static boolean ldcInsnEqual(LdcInsnNode insn1, LdcInsnNode insn2) {
|
||||
return insn1.cst == null || insn2.cst == null || insn1.cst.equals(insn2.cst);
|
||||
}
|
||||
|
||||
public static boolean typeInsnEqual(TypeInsnNode insn1, TypeInsnNode insn2) {
|
||||
return insn1.desc.equals("*") || insn2.desc.equals("*") || insn1.desc.equals(insn2.desc);
|
||||
}
|
||||
|
||||
public static boolean iincInsnEqual(IincInsnNode node1, IincInsnNode node2) {
|
||||
return node1.var == node2.var && node1.incr == node2.incr;
|
||||
}
|
||||
|
||||
public static boolean intInsnEqual(IntInsnNode node1, IntInsnNode node2) {
|
||||
return node1.operand == -1 || node2.operand == -1 || node1.operand == node2.operand;
|
||||
}
|
||||
|
||||
public static boolean insnEqual(AbstractInsnNode node1, AbstractInsnNode node2) {
|
||||
if (node1.getOpcode() != node2.getOpcode()) return false;
|
||||
|
||||
switch (node2.getType()) {
|
||||
case VAR_INSN:
|
||||
return varInsnEqual((VarInsnNode) node1, (VarInsnNode) node2);
|
||||
case TYPE_INSN:
|
||||
return typeInsnEqual((TypeInsnNode) node1, (TypeInsnNode) node2);
|
||||
case FIELD_INSN:
|
||||
return fieldInsnEqual((FieldInsnNode) node1, (FieldInsnNode) node2);
|
||||
case METHOD_INSN:
|
||||
return methodInsnEqual((MethodInsnNode) node1, (MethodInsnNode) node2);
|
||||
case LDC_INSN:
|
||||
return ldcInsnEqual((LdcInsnNode) node1, (LdcInsnNode) node2);
|
||||
case IINC_INSN:
|
||||
return iincInsnEqual((IincInsnNode) node1, (IincInsnNode) node2);
|
||||
case INT_INSN:
|
||||
return intInsnEqual((IntInsnNode) node1, (IntInsnNode) node2);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean insnImportant(AbstractInsnNode insn, Set<LabelNode> controlFlowLabels) {
|
||||
switch (insn.getType()) {
|
||||
case LINE:
|
||||
case FRAME:
|
||||
return false;
|
||||
case LABEL:
|
||||
return controlFlowLabels.contains(insn);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<LabelNode> getControlFlowLabels(InsnListSection list) {
|
||||
return getControlFlowLabels(list.list);
|
||||
}
|
||||
|
||||
public static Set<LabelNode> getControlFlowLabels(InsnList list) {
|
||||
HashSet<LabelNode> controlFlowLabels = new HashSet<LabelNode>();
|
||||
for (AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) {
|
||||
switch (insn.getType()) {
|
||||
case JUMP_INSN:
|
||||
JumpInsnNode jinsn = (JumpInsnNode) insn;
|
||||
controlFlowLabels.add(jinsn.label);
|
||||
break;
|
||||
case TABLESWITCH_INSN:
|
||||
TableSwitchInsnNode tsinsn = (TableSwitchInsnNode) insn;
|
||||
controlFlowLabels.add(tsinsn.dflt);
|
||||
for (LabelNode label : tsinsn.labels) controlFlowLabels.add(label);
|
||||
break;
|
||||
case LOOKUPSWITCH_INSN:
|
||||
LookupSwitchInsnNode lsinsn = (LookupSwitchInsnNode) insn;
|
||||
controlFlowLabels.add(lsinsn.dflt);
|
||||
for (LabelNode label : lsinsn.labels) controlFlowLabels.add(label);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return controlFlowLabels;
|
||||
}
|
||||
|
||||
public static InsnList getImportantList(InsnList list) {
|
||||
return getImportantList(new InsnListSection(list)).list;
|
||||
}
|
||||
|
||||
public static InsnListSection getImportantList(InsnListSection list) {
|
||||
if (list.size() == 0) return list;
|
||||
|
||||
Set<LabelNode> controlFlowLabels = getControlFlowLabels(list);
|
||||
Map<LabelNode, LabelNode> labelMap = Maps.asMap(controlFlowLabels, new Function<LabelNode, LabelNode>() {
|
||||
|
||||
@Override
|
||||
public LabelNode apply(LabelNode input) {
|
||||
return input;
|
||||
}
|
||||
});
|
||||
|
||||
InsnListSection importantNodeList = new InsnListSection();
|
||||
for (AbstractInsnNode insn : list)
|
||||
if (insnImportant(insn, controlFlowLabels)) importantNodeList.add(insn.clone(labelMap));
|
||||
|
||||
return importantNodeList;
|
||||
}
|
||||
|
||||
public static List<InsnListSection> find(InsnListSection haystack, InsnListSection needle) {
|
||||
Set<LabelNode> controlFlowLabels = getControlFlowLabels(haystack);
|
||||
LinkedList<InsnListSection> list = new LinkedList<InsnListSection>();
|
||||
for (int start = 0; start <= haystack.size() - needle.size(); start++) {
|
||||
InsnListSection section = matches(haystack.drop(start), needle, controlFlowLabels);
|
||||
if (section != null) {
|
||||
list.add(section);
|
||||
start = section.end - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<InsnListSection> find(InsnList haystack, InsnListSection needle) {
|
||||
return find(new InsnListSection(haystack), needle);
|
||||
}
|
||||
|
||||
public static InsnListSection matches(InsnListSection haystack, InsnListSection needle,
|
||||
Set<LabelNode> controlFlowLabels) {
|
||||
int h = 0, n = 0;
|
||||
for (; h < haystack.size() && n < needle.size(); h++) {
|
||||
AbstractInsnNode insn = haystack.get(h);
|
||||
if (!insnImportant(insn, controlFlowLabels)) continue;
|
||||
|
||||
if (!insnEqual(haystack.get(h), needle.get(n))) return null;
|
||||
n++;
|
||||
}
|
||||
if (n != needle.size()) return null;
|
||||
|
||||
return haystack.take(h);
|
||||
}
|
||||
|
||||
public static InsnListSection findOnce(InsnListSection haystack, InsnListSection needle) {
|
||||
List<InsnListSection> list = find(haystack, needle);
|
||||
if (list.size() != 1) throw new RuntimeException(
|
||||
"Needle found " + list.size() + " times in Haystack:\n" + haystack + "\n\n" + needle);
|
||||
|
||||
return list.get(0);
|
||||
}
|
||||
|
||||
public static InsnListSection findOnce(InsnList haystack, InsnListSection needle) {
|
||||
return findOnce(new InsnListSection(haystack), needle);
|
||||
}
|
||||
|
||||
public static List<InsnListSection> findN(InsnListSection haystack, InsnListSection needle) {
|
||||
List<InsnListSection> list = find(haystack, needle);
|
||||
if (list.isEmpty()) throw new RuntimeException("Needle not found in Haystack:\n" + haystack + "\n\n" + needle);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<InsnListSection> findN(InsnList haystack, InsnListSection needle) {
|
||||
return findN(new InsnListSection(haystack), needle);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.FRAME;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.JUMP_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.LABEL;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.LOOKUPSWITCH_INSN;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.TABLESWITCH_INSN;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.FrameNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
import org.objectweb.asm.tree.LookupSwitchInsnNode;
|
||||
import org.objectweb.asm.tree.TableSwitchInsnNode;
|
||||
import org.objectweb.asm.util.Textifier;
|
||||
import org.objectweb.asm.util.TraceMethodVisitor;
|
||||
|
||||
/**
|
||||
* A section of an InsnList, may become invalid if the insn list is modified
|
||||
*/
|
||||
public class InsnListSection implements Iterable<AbstractInsnNode> {
|
||||
|
||||
private class InsnListSectionIterator implements Iterator<AbstractInsnNode> {
|
||||
|
||||
int i = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return i < size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractInsnNode next() {
|
||||
return get(i++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
InsnListSection.this.remove(--i);
|
||||
}
|
||||
}
|
||||
|
||||
public InsnList list;
|
||||
public int start;
|
||||
public int end;
|
||||
|
||||
public InsnListSection(InsnList list, int start, int end) {
|
||||
this.list = list;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public InsnListSection(InsnList list, AbstractInsnNode first, AbstractInsnNode last) {
|
||||
this(list, list.indexOf(first), list.indexOf(last) + 1);
|
||||
}
|
||||
|
||||
public InsnListSection(InsnList list) {
|
||||
this(list, 0, list.size());
|
||||
}
|
||||
|
||||
public InsnListSection() {
|
||||
this(new InsnList());
|
||||
}
|
||||
|
||||
public void accept(MethodVisitor mv) {
|
||||
for (AbstractInsnNode insn : this) insn.accept(mv);
|
||||
}
|
||||
|
||||
public AbstractInsnNode getFirst() {
|
||||
return size() == 0 ? null : list.get(start);
|
||||
}
|
||||
|
||||
public AbstractInsnNode getLast() {
|
||||
return size() == 0 ? null : list.get(end - 1);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return end - start;
|
||||
}
|
||||
|
||||
public AbstractInsnNode get(int i) {
|
||||
return list.get(start + i);
|
||||
}
|
||||
|
||||
public void set(int i, AbstractInsnNode insn) {
|
||||
list.set(get(i), insn);
|
||||
}
|
||||
|
||||
public void remove(int i) {
|
||||
list.remove(get(i));
|
||||
end--;
|
||||
}
|
||||
|
||||
public void replace(AbstractInsnNode location, AbstractInsnNode insn) {
|
||||
list.set(location, insn);
|
||||
}
|
||||
|
||||
public void add(AbstractInsnNode insn) {
|
||||
list.add(insn);
|
||||
end++;
|
||||
}
|
||||
|
||||
public void insertBefore(InsnList insns) {
|
||||
int s = insns.size();
|
||||
if (this.list.size() == 0) list.insert(insns);
|
||||
else list.insertBefore(list.get(start), insns);
|
||||
start += s;
|
||||
end += s;
|
||||
}
|
||||
|
||||
public void insert(InsnList insns) {
|
||||
if (end == 0) list.insert(insns);
|
||||
else list.insert(list.get(end - 1), insns);
|
||||
}
|
||||
|
||||
public void replace(InsnList insns) {
|
||||
int s = insns.size();
|
||||
remove();
|
||||
insert(insns);
|
||||
end = start + s;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
while (end != start) remove(0);
|
||||
}
|
||||
|
||||
public void setLast(AbstractInsnNode last) {
|
||||
end = list.indexOf(last) + 1;
|
||||
}
|
||||
|
||||
public void setFirst(AbstractInsnNode first) {
|
||||
start = list.indexOf(first);
|
||||
}
|
||||
|
||||
public InsnListSection drop(int n) {
|
||||
return slice(n, size());
|
||||
}
|
||||
|
||||
public InsnListSection take(int n) {
|
||||
return slice(0, n);
|
||||
}
|
||||
|
||||
public InsnListSection slice(int start, int end) {
|
||||
return new InsnListSection(list, this.start + start, this.start + end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes leading and trailing labels and line number nodes that don't affect control flow
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public InsnListSection trim(Set<LabelNode> controlFlowLabels) {
|
||||
while (start < end && !InsnComparator.insnImportant(getFirst(), controlFlowLabels)) start++;
|
||||
|
||||
while (start < end && !InsnComparator.insnImportant(getLast(), controlFlowLabels)) end--;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
Textifier t = new Textifier();
|
||||
accept(new TraceMethodVisitor(t));
|
||||
StringWriter sw = new StringWriter();
|
||||
t.print(new PrintWriter(sw));
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
public void println() {
|
||||
System.out.println(toString());
|
||||
}
|
||||
|
||||
public HashMap<LabelNode, LabelNode> identityLabelMap() {
|
||||
HashMap<LabelNode, LabelNode> labelMap = new HashMap<LabelNode, LabelNode>();
|
||||
for (AbstractInsnNode insn : this) switch (insn.getType()) {
|
||||
case LABEL:
|
||||
labelMap.put((LabelNode) insn, (LabelNode) insn);
|
||||
break;
|
||||
case JUMP_INSN:
|
||||
labelMap.put(((JumpInsnNode) insn).label, ((JumpInsnNode) insn).label);
|
||||
break;
|
||||
case LOOKUPSWITCH_INSN:
|
||||
LookupSwitchInsnNode linsn = (LookupSwitchInsnNode) insn;
|
||||
labelMap.put(linsn.dflt, linsn.dflt);
|
||||
for (LabelNode label : linsn.labels) labelMap.put(label, label);
|
||||
break;
|
||||
case TABLESWITCH_INSN:
|
||||
TableSwitchInsnNode tinsn = (TableSwitchInsnNode) insn;
|
||||
labelMap.put(tinsn.dflt, tinsn.dflt);
|
||||
for (LabelNode label : tinsn.labels) labelMap.put(label, label);
|
||||
break;
|
||||
case FRAME:
|
||||
FrameNode fnode = (FrameNode) insn;
|
||||
if (fnode.local != null)
|
||||
for (Object o : fnode.local) if (o instanceof LabelNode) labelMap.put((LabelNode) o, (LabelNode) o);
|
||||
if (fnode.stack != null)
|
||||
for (Object o : fnode.stack) if (o instanceof LabelNode) labelMap.put((LabelNode) o, (LabelNode) o);
|
||||
break;
|
||||
}
|
||||
|
||||
return labelMap;
|
||||
}
|
||||
|
||||
public Map<LabelNode, LabelNode> cloneLabels() {
|
||||
Map<LabelNode, LabelNode> labelMap = identityLabelMap();
|
||||
for (Entry<LabelNode, LabelNode> entry : labelMap.entrySet()) entry.setValue(new LabelNode());
|
||||
|
||||
return labelMap;
|
||||
}
|
||||
|
||||
public InsnListSection copy() {
|
||||
return copy(cloneLabels());
|
||||
}
|
||||
|
||||
public InsnListSection copy(Map<LabelNode, LabelNode> labelMap) {
|
||||
InsnListSection copy = new InsnListSection();
|
||||
for (AbstractInsnNode insn : this) copy.add(insn.clone(labelMap));
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<AbstractInsnNode> iterator() {
|
||||
return new InsnListSectionIterator();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.commons.LocalVariablesSorter;
|
||||
|
||||
public class LocalVariablesSorterVisitor extends ClassVisitor {
|
||||
|
||||
public Set<ObfMapping> methods;
|
||||
public String owner;
|
||||
|
||||
public LocalVariablesSorterVisitor(Set<ObfMapping> methods, ClassVisitor cv) {
|
||||
super(Opcodes.ASM4, cv);
|
||||
this.methods = methods;
|
||||
}
|
||||
|
||||
public LocalVariablesSorterVisitor(ClassVisitor cv) {
|
||||
this(null, 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);
|
||||
owner = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
|
||||
return methods == null || methods.contains(new ObfMapping(owner, name, desc))
|
||||
? new LocalVariablesSorter(access, desc, mv)
|
||||
: mv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
import static codechicken.lib.asm.ASMHelper.config;
|
||||
import static codechicken.lib.asm.ASMHelper.createBytes;
|
||||
import static codechicken.lib.asm.ASMHelper.dump;
|
||||
import static codechicken.lib.asm.ASMHelper.findMethod;
|
||||
import static codechicken.lib.asm.ASMHelper.logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
public class ModularASMTransformer {
|
||||
|
||||
public static class ClassNodeTransformerList {
|
||||
|
||||
List<ClassNodeTransformer> transformers = new LinkedList<ClassNodeTransformer>();
|
||||
HashSet<ObfMapping> methodsToSort = new HashSet<ObfMapping>();
|
||||
|
||||
public void add(ClassNodeTransformer t) {
|
||||
transformers.add(t);
|
||||
t.addMethodsToSort(methodsToSort);
|
||||
}
|
||||
|
||||
public byte[] transform(byte[] bytes) {
|
||||
ClassNode cnode = new ClassNode();
|
||||
ClassReader reader = new ClassReader(bytes);
|
||||
ClassVisitor cv = cnode;
|
||||
if (!methodsToSort.isEmpty()) cv = new LocalVariablesSorterVisitor(methodsToSort, cv);
|
||||
reader.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
|
||||
try {
|
||||
int writeFlags = 0;
|
||||
for (ClassNodeTransformer t : transformers) {
|
||||
t.transform(cnode);
|
||||
writeFlags |= t.writeFlags;
|
||||
}
|
||||
|
||||
bytes = createBytes(cnode, writeFlags);
|
||||
if (config.getTag("dump_asm").getBooleanValue(false))
|
||||
dump(bytes, new File("asm/ccl_modular/" + cnode.name.replace('/', '#') + ".txt"), false, false);
|
||||
return bytes;
|
||||
} catch (RuntimeException e) {
|
||||
dump(bytes, new File("asm/ccl_modular/" + cnode.name.replace('/', '#') + ".txt"), false, false);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class ClassNodeTransformer {
|
||||
|
||||
public int writeFlags;
|
||||
|
||||
public ClassNodeTransformer(int writeFlags) {
|
||||
this.writeFlags = writeFlags;
|
||||
}
|
||||
|
||||
public ClassNodeTransformer() {
|
||||
this(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
}
|
||||
|
||||
public abstract String className();
|
||||
|
||||
public abstract void transform(ClassNode cnode);
|
||||
|
||||
public void addMethodsToSort(Set<ObfMapping> set) {}
|
||||
}
|
||||
|
||||
public abstract static class MethodTransformer extends ClassNodeTransformer {
|
||||
|
||||
public final ObfMapping method;
|
||||
|
||||
public MethodTransformer(ObfMapping method) {
|
||||
this.method = method.toClassloading();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String className() {
|
||||
return method.javaClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(ClassNode cnode) {
|
||||
MethodNode mv = findMethod(method, cnode);
|
||||
if (mv == null) throw new RuntimeException("Method not found: " + method);
|
||||
|
||||
try {
|
||||
transform(mv);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error transforming method: " + method, e);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void transform(MethodNode mv);
|
||||
}
|
||||
|
||||
public static class MethodWriter extends ClassNodeTransformer {
|
||||
|
||||
public final int access;
|
||||
public final ObfMapping method;
|
||||
public final String[] exceptions;
|
||||
public InsnList list;
|
||||
|
||||
public MethodWriter(int access, ObfMapping method) {
|
||||
this(access, method, null, (InsnList) null);
|
||||
}
|
||||
|
||||
public MethodWriter(int access, ObfMapping method, InsnList list) {
|
||||
this(access, method, null, list);
|
||||
}
|
||||
|
||||
public MethodWriter(int access, ObfMapping method, ASMBlock block) {
|
||||
this(access, method, null, block);
|
||||
}
|
||||
|
||||
public MethodWriter(int access, ObfMapping method, String[] exceptions) {
|
||||
this(access, method, exceptions, (InsnList) null);
|
||||
}
|
||||
|
||||
public MethodWriter(int access, ObfMapping method, String[] exceptions, InsnList list) {
|
||||
this.access = access;
|
||||
this.method = method.toClassloading();
|
||||
this.exceptions = exceptions;
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
public MethodWriter(int access, ObfMapping method, String[] exceptions, ASMBlock block) {
|
||||
this(access, method, exceptions, block.rawListCopy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String className() {
|
||||
return method.javaClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(ClassNode cnode) {
|
||||
MethodNode mv = findMethod(method, cnode);
|
||||
if (mv == null) mv = (MethodNode) method.visitMethod(cnode, access, exceptions);
|
||||
else {
|
||||
mv.access = access;
|
||||
mv.instructions.clear();
|
||||
if (mv.localVariables != null) mv.localVariables.clear();
|
||||
if (mv.tryCatchBlocks != null) mv.tryCatchBlocks.clear();
|
||||
}
|
||||
|
||||
write(mv);
|
||||
}
|
||||
|
||||
public void write(MethodNode mv) {
|
||||
logger.debug("Writing method " + method);
|
||||
list.accept(mv);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MethodInjector extends MethodTransformer {
|
||||
|
||||
public ASMBlock needle;
|
||||
public ASMBlock injection;
|
||||
public boolean before;
|
||||
|
||||
public MethodInjector(ObfMapping method, ASMBlock needle, ASMBlock injection, boolean before) {
|
||||
super(method);
|
||||
this.needle = needle;
|
||||
this.injection = injection;
|
||||
this.before = before;
|
||||
}
|
||||
|
||||
public MethodInjector(ObfMapping method, ASMBlock injection, boolean before) {
|
||||
this(method, null, injection, before);
|
||||
}
|
||||
|
||||
public MethodInjector(ObfMapping method, InsnList needle, InsnList injection, boolean before) {
|
||||
this(method, new ASMBlock(needle), new ASMBlock(injection), before);
|
||||
}
|
||||
|
||||
public MethodInjector(ObfMapping method, InsnList injection, boolean before) {
|
||||
this(method, null, new ASMBlock(injection), before);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMethodsToSort(Set<ObfMapping> set) {
|
||||
set.add(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(MethodNode mv) {
|
||||
if (needle == null) {
|
||||
logger.debug("Injecting " + (before ? "before" : "after") + " method " + method);
|
||||
if (before) mv.instructions.insert(injection.rawListCopy());
|
||||
else mv.instructions.add(injection.rawListCopy());
|
||||
} else {
|
||||
for (InsnListSection key : InsnComparator.findN(mv.instructions, needle.list)) {
|
||||
logger.debug(
|
||||
"Injecting " + (before ? "before" : "after")
|
||||
+ " method "
|
||||
+ method
|
||||
+ " @ "
|
||||
+ key.start
|
||||
+ " - "
|
||||
+ key.end);
|
||||
ASMBlock injectBlock = injection.copy().mergeLabels(needle.applyLabels(key));
|
||||
|
||||
if (before) key.insertBefore(injectBlock.list.list);
|
||||
else key.insert(injectBlock.list.list);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class MethodReplacer extends MethodTransformer {
|
||||
|
||||
public ASMBlock needle;
|
||||
public ASMBlock replacement;
|
||||
|
||||
public MethodReplacer(ObfMapping method, ASMBlock needle, ASMBlock replacement) {
|
||||
super(method);
|
||||
this.needle = needle;
|
||||
this.replacement = replacement;
|
||||
}
|
||||
|
||||
public MethodReplacer(ObfMapping method, InsnList needle, InsnList replacement) {
|
||||
this(method, new ASMBlock(needle), new ASMBlock(replacement));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMethodsToSort(Set<ObfMapping> set) {
|
||||
set.add(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(MethodNode mv) {
|
||||
for (InsnListSection key : InsnComparator.findN(mv.instructions, needle.list)) {
|
||||
logger.debug("Replacing method " + method + " @ " + key.start + " - " + key.end);
|
||||
ASMBlock replaceBlock = replacement.copy().pullLabels(needle.applyLabels(key));
|
||||
key.insert(replaceBlock.list.list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class FieldWriter extends ClassNodeTransformer {
|
||||
|
||||
public final ObfMapping field;
|
||||
public final int access;
|
||||
public final Object value;
|
||||
|
||||
public FieldWriter(int access, ObfMapping field, Object value) {
|
||||
this.field = field.toClassloading();
|
||||
this.access = access;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public FieldWriter(int access, ObfMapping field) {
|
||||
this(access, field, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String className() {
|
||||
return field.javaClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(ClassNode cnode) {
|
||||
field.visitField(cnode, access, value);
|
||||
}
|
||||
}
|
||||
|
||||
public HashMap<String, ClassNodeTransformerList> transformers = new HashMap<String, ClassNodeTransformerList>();
|
||||
|
||||
public void add(ClassNodeTransformer t) {
|
||||
ClassNodeTransformerList list = transformers.get(t.className());
|
||||
if (list == null) transformers.put(t.className(), list = new ClassNodeTransformerList());
|
||||
list.add(t);
|
||||
}
|
||||
|
||||
public byte[] transform(String name, byte[] bytes) {
|
||||
if (bytes == null) return null;
|
||||
|
||||
ClassNodeTransformerList list = transformers.get(name);
|
||||
return list == null ? bytes : list.transform(bytes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,401 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.swing.JFileChooser;
|
||||
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import net.minecraftforge.common.ForgeVersion;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.TypeInsnNode;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.io.LineProcessor;
|
||||
import com.google.common.io.Resources;
|
||||
|
||||
import codechicken.lib.config.ConfigTag;
|
||||
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;
|
||||
import cpw.mods.fml.relauncher.FMLInjectionData;
|
||||
|
||||
public class ObfMapping {
|
||||
|
||||
public static class ObfRemapper extends Remapper {
|
||||
|
||||
private final HashMap<String, String> fields = new HashMap<>();
|
||||
private final HashMap<String, String> funcs = new HashMap<>();
|
||||
|
||||
public ObfRemapper() {
|
||||
try {
|
||||
Field rawFieldMapsField = FMLDeobfuscatingRemapper.class.getDeclaredField("rawFieldMaps");
|
||||
Field rawMethodMapsField = FMLDeobfuscatingRemapper.class.getDeclaredField("rawMethodMaps");
|
||||
rawFieldMapsField.setAccessible(true);
|
||||
rawMethodMapsField.setAccessible(true);
|
||||
Map<String, Map<String, String>> rawFieldMaps = (Map<String, Map<String, String>>) rawFieldMapsField
|
||||
.get(FMLDeobfuscatingRemapper.INSTANCE);
|
||||
Map<String, Map<String, String>> rawMethodMaps = (Map<String, Map<String, String>>) rawMethodMapsField
|
||||
.get(FMLDeobfuscatingRemapper.INSTANCE);
|
||||
|
||||
if (rawFieldMaps == null) throw new IllegalStateException(
|
||||
"codechicken.lib.asm.ObfMapping loaded too early. Make sure all references are in or after the asm transformer load stage");
|
||||
|
||||
for (Map<String, String> map : rawFieldMaps.values())
|
||||
for (Entry<String, String> entry : map.entrySet()) if (entry.getValue().startsWith("field"))
|
||||
fields.put(entry.getValue(), entry.getKey().substring(0, entry.getKey().indexOf(':')));
|
||||
for (Map<String, String> map : rawMethodMaps.values())
|
||||
for (Entry<String, String> entry : map.entrySet()) if (entry.getValue().startsWith("func"))
|
||||
funcs.put(entry.getValue(), entry.getKey().substring(0, entry.getKey().indexOf('(')));
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapMethodName(String owner, String name, String desc) {
|
||||
String s = funcs.get(name);
|
||||
return s == null ? name : s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapFieldName(String owner, String name, String desc) {
|
||||
String s = fields.get(name);
|
||||
return s == null ? name : s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String map(String typeName) {
|
||||
return FMLDeobfuscatingRemapper.INSTANCE.unmap(typeName);
|
||||
}
|
||||
|
||||
public String unmap(String typeName) {
|
||||
return FMLDeobfuscatingRemapper.INSTANCE.map(typeName);
|
||||
}
|
||||
|
||||
public boolean isObf(String typeName) {
|
||||
return !map(typeName).equals(typeName) || !unmap(typeName).equals(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MCPRemapper extends Remapper implements LineProcessor<Void> {
|
||||
|
||||
public static File[] getConfFiles() {
|
||||
ConfigTag tag = ASMHelper.config.getTag("mappingDir")
|
||||
.setComment("Path to directory holding packaged.srg, fields.csv and methods.csv for mcp remapping");
|
||||
for (int i = 0; i < DIR_GUESSES + DIR_ASKS; i++) {
|
||||
File dir = confDirectoryGuess(i, tag);
|
||||
if (dir == null || dir.isFile()) continue;
|
||||
|
||||
File[] mappings;
|
||||
try {
|
||||
mappings = parseConfDir(dir);
|
||||
} catch (Exception e) {
|
||||
if (i >= DIR_GUESSES) e.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
|
||||
tag.setValue(dir.getPath());
|
||||
return mappings;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Failed to select mappings directory, set it manually in the config");
|
||||
}
|
||||
|
||||
private static final int DIR_GUESSES = 6;
|
||||
private static final int DIR_ASKS = 3;
|
||||
|
||||
public static File confDirectoryGuess(int i, ConfigTag tag) {
|
||||
File mcDir = (File) FMLInjectionData.data()[6];
|
||||
switch (i) {
|
||||
case 0:
|
||||
return tag.value != null ? new File(tag.getValue()) : null;
|
||||
case 1:
|
||||
return new File(mcDir, "../conf");
|
||||
case 2:
|
||||
return new File(mcDir, "../build/unpacked/conf");
|
||||
case 3:
|
||||
return new File(
|
||||
System.getProperty("user.home"),
|
||||
".gradle/caches/minecraft/net/minecraftforge/forge/" + FMLInjectionData.data()[4]
|
||||
+ "-"
|
||||
+ ForgeVersion.getVersion()
|
||||
+ "/unpacked/conf");
|
||||
case 4:
|
||||
return new File(
|
||||
System.getProperty("user.home"),
|
||||
".gradle/caches/minecraft/net/minecraftforge/forge/" + FMLInjectionData.data()[4]
|
||||
+ "-"
|
||||
+ ForgeVersion.getVersion()
|
||||
+ "-"
|
||||
+ FMLInjectionData.data()[4]
|
||||
+ "/unpacked/conf");
|
||||
case 5:
|
||||
final String gradleCsvDir = System.getProperty("net.minecraftforge.gradle.GradleStart.csvDir");
|
||||
return gradleCsvDir != null ? new File(gradleCsvDir) : null;
|
||||
default:
|
||||
JFileChooser fc = new JFileChooser(mcDir);
|
||||
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
fc.setDialogTitle("Select an mcp conf dir for the deobfuscator.");
|
||||
int ret = fc.showDialog(null, "Select");
|
||||
return ret == JFileChooser.APPROVE_OPTION ? fc.getSelectedFile() : null;
|
||||
}
|
||||
}
|
||||
|
||||
public static File[] parseConfDir(File confDir) {
|
||||
File srgDir = new File(confDir, "conf");
|
||||
if (!srgDir.exists()) srgDir = confDir;
|
||||
|
||||
File srgs = new File(srgDir, "packaged.srg");
|
||||
if (!srgs.exists()) srgs = new File(srgDir, "joined.srg");
|
||||
if (!srgs.exists()) throw new RuntimeException("Could not find packaged.srg or joined.srg");
|
||||
|
||||
File mapDir = new File(confDir, "mappings");
|
||||
if (!mapDir.exists()) mapDir = confDir;
|
||||
|
||||
File methods = new File(mapDir, "methods.csv");
|
||||
if (!methods.exists()) throw new RuntimeException("Could not find methods.csv");
|
||||
File fields = new File(mapDir, "fields.csv");
|
||||
if (!fields.exists()) throw new RuntimeException("Could not find fields.csv");
|
||||
|
||||
return new File[] { srgs, methods, fields };
|
||||
}
|
||||
|
||||
private final HashMap<String, String> fields = new HashMap<>();
|
||||
private final HashMap<String, String> funcs = new HashMap<>();
|
||||
|
||||
public MCPRemapper() {
|
||||
File[] mappings = getConfFiles();
|
||||
try {
|
||||
Resources.readLines(mappings[1].toURI().toURL(), Charsets.UTF_8, this);
|
||||
Resources.readLines(mappings[2].toURI().toURL(), Charsets.UTF_8, this);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapMethodName(String owner, String name, String desc) {
|
||||
String s = funcs.get(name);
|
||||
return s == null ? name : s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapFieldName(String owner, String name, String desc) {
|
||||
String s = fields.get(name);
|
||||
return s == null ? name : s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processLine(String line) throws IOException {
|
||||
int i = line.indexOf(',');
|
||||
String srg = line.substring(0, i);
|
||||
int i2 = i + 1;
|
||||
i = line.indexOf(',', i2);
|
||||
String mcp = line.substring(i2, i);
|
||||
(srg.startsWith("func") ? funcs : fields).put(srg, mcp);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void getResult() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static ObfRemapper obfMapper = new ObfRemapper();
|
||||
public static Remapper mcpMapper = null;
|
||||
|
||||
public static void loadMCPRemapper() {
|
||||
if (mcpMapper == null) mcpMapper = new MCPRemapper();
|
||||
}
|
||||
|
||||
public static final boolean obfuscated;
|
||||
|
||||
static {
|
||||
boolean obf = true;
|
||||
try {
|
||||
obf = Launch.classLoader.getClassBytes("net.minecraft.world.World") == null;
|
||||
} catch (IOException ignored) {}
|
||||
obfuscated = obf;
|
||||
if (!obf) loadMCPRemapper();
|
||||
}
|
||||
|
||||
public String s_owner;
|
||||
public String s_name;
|
||||
public String s_desc;
|
||||
|
||||
public ObfMapping(String owner) {
|
||||
this(owner, "", "");
|
||||
}
|
||||
|
||||
public ObfMapping(String owner, String name, String desc) {
|
||||
this.s_owner = owner;
|
||||
this.s_name = name;
|
||||
this.s_desc = desc;
|
||||
|
||||
if (s_owner.contains(".")) throw new IllegalArgumentException(s_owner);
|
||||
}
|
||||
|
||||
public ObfMapping(ObfMapping descmap, String subclass) {
|
||||
this(subclass, descmap.s_name, descmap.s_desc);
|
||||
}
|
||||
|
||||
public static ObfMapping fromDesc(String s) {
|
||||
int lastDot = s.lastIndexOf('.');
|
||||
if (lastDot < 0) return new ObfMapping(s, "", "");
|
||||
int sep = s.indexOf('('); // methods
|
||||
int sep_end = sep;
|
||||
if (sep < 0) {
|
||||
sep = s.indexOf(' '); // some stuffs
|
||||
sep_end = sep + 1;
|
||||
}
|
||||
if (sep < 0) {
|
||||
sep = s.indexOf(':'); // fields
|
||||
sep_end = sep + 1;
|
||||
}
|
||||
if (sep < 0) return new ObfMapping(s.substring(0, lastDot), s.substring(lastDot + 1), "");
|
||||
|
||||
return new ObfMapping(s.substring(0, lastDot), s.substring(lastDot + 1, sep), s.substring(sep_end));
|
||||
}
|
||||
|
||||
public ObfMapping subclass(String subclass) {
|
||||
return new ObfMapping(this, subclass);
|
||||
}
|
||||
|
||||
public boolean matches(MethodNode node) {
|
||||
return s_name.equals(node.name) && s_desc.equals(node.desc);
|
||||
}
|
||||
|
||||
public boolean matches(MethodInsnNode node) {
|
||||
return s_owner.equals(node.owner) && s_name.equals(node.name) && s_desc.equals(node.desc);
|
||||
}
|
||||
|
||||
public AbstractInsnNode toInsn(int opcode) {
|
||||
if (isClass()) return new TypeInsnNode(opcode, s_owner);
|
||||
else if (isMethod()) return new MethodInsnNode(opcode, s_owner, s_name, s_desc);
|
||||
else return new FieldInsnNode(opcode, s_owner, s_name, s_desc);
|
||||
}
|
||||
|
||||
public void visitTypeInsn(MethodVisitor mv, int opcode) {
|
||||
mv.visitTypeInsn(opcode, s_owner);
|
||||
}
|
||||
|
||||
public void visitMethodInsn(MethodVisitor mv, int opcode) {
|
||||
mv.visitMethodInsn(opcode, s_owner, s_name, s_desc);
|
||||
}
|
||||
|
||||
public void visitFieldInsn(MethodVisitor mv, int opcode) {
|
||||
mv.visitFieldInsn(opcode, s_owner, s_name, s_desc);
|
||||
}
|
||||
|
||||
public MethodVisitor visitMethod(ClassVisitor visitor, int access, String[] exceptions) {
|
||||
return visitor.visitMethod(access, s_name, s_desc, null, exceptions);
|
||||
}
|
||||
|
||||
public FieldVisitor visitField(ClassVisitor visitor, int access, Object value) {
|
||||
return visitor.visitField(access, s_name, s_desc, null, value);
|
||||
}
|
||||
|
||||
public boolean isClass(String name) {
|
||||
return name.replace('.', '/').equals(s_owner);
|
||||
}
|
||||
|
||||
public boolean matches(String name, String desc) {
|
||||
return s_name.equals(name) && s_desc.equals(desc);
|
||||
}
|
||||
|
||||
public boolean matches(FieldNode node) {
|
||||
return s_name.equals(node.name) && s_desc.equals(node.desc);
|
||||
}
|
||||
|
||||
public boolean matches(FieldInsnNode node) {
|
||||
return s_owner.equals(node.owner) && s_name.equals(node.name) && s_desc.equals(node.desc);
|
||||
}
|
||||
|
||||
public String javaClass() {
|
||||
return s_owner.replace('/', '.');
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ObfMapping)) return false;
|
||||
|
||||
ObfMapping desc = (ObfMapping) obj;
|
||||
return s_owner.equals(desc.s_owner) && s_name.equals(desc.s_name) && s_desc.equals(desc.s_desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(s_desc, s_name, s_owner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (s_name.length() == 0) return "[" + s_owner + "]";
|
||||
if (s_desc.length() == 0) return "[" + s_owner + "." + s_name + "]";
|
||||
return "[" + (isMethod() ? methodDesc() : fieldDesc()) + "]";
|
||||
}
|
||||
|
||||
public String methodDesc() {
|
||||
return s_owner + "." + s_name + s_desc;
|
||||
}
|
||||
|
||||
public String fieldDesc() {
|
||||
return s_owner + "." + s_name + ":" + s_desc;
|
||||
}
|
||||
|
||||
public boolean isClass() {
|
||||
return s_name.length() == 0;
|
||||
}
|
||||
|
||||
public boolean isMethod() {
|
||||
return s_desc.contains("(");
|
||||
}
|
||||
|
||||
public boolean isField() {
|
||||
return !isClass() && !isMethod();
|
||||
}
|
||||
|
||||
public ObfMapping map(Remapper mapper) {
|
||||
if (mapper == null) return this;
|
||||
|
||||
if (isMethod()) s_name = mapper.mapMethodName(s_owner, s_name, s_desc);
|
||||
else if (isField()) s_name = mapper.mapFieldName(s_owner, s_name, s_desc);
|
||||
|
||||
s_owner = mapper.mapType(s_owner);
|
||||
|
||||
if (isMethod()) s_desc = mapper.mapMethodDesc(s_desc);
|
||||
else if (s_desc.length() > 0) s_desc = mapper.mapDesc(s_desc);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObfMapping toRuntime() {
|
||||
map(mcpMapper);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObfMapping toClassloading() {
|
||||
if (!obfuscated) map(mcpMapper);
|
||||
else if (obfMapper.isObf(s_owner)) map(obfMapper);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObfMapping copy() {
|
||||
return new ObfMapping(s_owner, s_name, s_desc);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
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.InsnList;
|
||||
import org.objectweb.asm.tree.InsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.util.Textifier;
|
||||
import org.objectweb.asm.util.TraceClassVisitor;
|
||||
|
||||
import codechicken.core.launch.CodeChickenCorePlugin;
|
||||
|
||||
public class RedirectorTransformer implements IClassTransformer, Opcodes {
|
||||
|
||||
private static final boolean DUMP_CLASSES = Boolean.parseBoolean(System.getProperty("ccl.dumpClass", "false"));
|
||||
private static final String RenderStateClass = "codechicken/lib/render/CCRenderState";
|
||||
private static final Set<String> redirectedFields = new HashSet<>();
|
||||
private static final Set<String> redirectedSimpleMethods = new HashSet<>();
|
||||
private static final Set<String> redirectedMethods = new HashSet<>();
|
||||
private static final ClassConstantPoolParser cstPoolParser;
|
||||
|
||||
static {
|
||||
Collections.addAll(
|
||||
redirectedFields,
|
||||
"pipeline",
|
||||
"model",
|
||||
"firstVertexIndex",
|
||||
"lastVertexIndex",
|
||||
"vertexIndex",
|
||||
"baseColour",
|
||||
"alphaOverride",
|
||||
"useNormals",
|
||||
"computeLighting",
|
||||
"useColour",
|
||||
"lightMatrix",
|
||||
"vert",
|
||||
"hasNormal",
|
||||
"normal",
|
||||
"hasColour",
|
||||
"colour",
|
||||
"hasBrightness",
|
||||
"brightness",
|
||||
"side",
|
||||
"lc"
|
||||
|
||||
);
|
||||
Collections.addAll(redirectedSimpleMethods, "reset", "pullLightmap", "pushLightmap", "setDynamic", "draw");
|
||||
Collections.addAll(
|
||||
redirectedMethods,
|
||||
"setPipeline",
|
||||
"bindModel",
|
||||
"setModel",
|
||||
"setVertexRange",
|
||||
"render",
|
||||
"runPipeline",
|
||||
"writeVert",
|
||||
"setNormal",
|
||||
"setColour",
|
||||
"setBrightness",
|
||||
"startDrawing");
|
||||
|
||||
cstPoolParser = new ClassConstantPoolParser(RenderStateClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(String name, String transformedName, byte[] basicClass) {
|
||||
if (!cstPoolParser.find(basicClass)) {
|
||||
return basicClass;
|
||||
}
|
||||
|
||||
final ClassReader cr = new ClassReader(basicClass);
|
||||
final ClassNode cn = new ClassNode();
|
||||
cr.accept(cn, 0);
|
||||
boolean changed = false;
|
||||
|
||||
// spotless:off
|
||||
for (MethodNode mn : cn.methods) {
|
||||
for (AbstractInsnNode node : mn.instructions.toArray()) {
|
||||
if (node instanceof FieldInsnNode fNode) {
|
||||
if (node.getOpcode() == GETSTATIC && RenderStateClass.equals(fNode.owner) && redirectedFields.contains(fNode.name)) {
|
||||
mn.instructions.insertBefore(fNode,
|
||||
new MethodInsnNode(
|
||||
INVOKESTATIC,
|
||||
fNode.owner,
|
||||
"instance",
|
||||
"()Lcodechicken/lib/render/CCRenderState;",
|
||||
false));
|
||||
fNode.setOpcode(GETFIELD);
|
||||
changed = true;
|
||||
} else if (node.getOpcode() == PUTSTATIC && RenderStateClass.equals(fNode.owner) && redirectedFields.contains(fNode.name)) {
|
||||
InsnList list = new InsnList();
|
||||
list.add(new MethodInsnNode(
|
||||
INVOKESTATIC,
|
||||
fNode.owner,
|
||||
"instance",
|
||||
"()Lcodechicken/lib/render/CCRenderState;",
|
||||
false));
|
||||
list.add(new InsnNode(SWAP));
|
||||
mn.instructions.insertBefore(fNode, list);
|
||||
fNode.setOpcode(PUTFIELD);
|
||||
changed = true;
|
||||
}
|
||||
} else if (node instanceof MethodInsnNode mNode) {
|
||||
if (node.getOpcode() == INVOKESTATIC && RenderStateClass.equals(mNode.owner) && redirectedSimpleMethods.contains(mNode.name)) {
|
||||
mn.instructions.insertBefore(mNode,
|
||||
new MethodInsnNode(
|
||||
INVOKESTATIC,
|
||||
mNode.owner,
|
||||
"instance",
|
||||
"()Lcodechicken/lib/render/CCRenderState;",
|
||||
false));
|
||||
mNode.setOpcode(INVOKEVIRTUAL);
|
||||
mNode.name = mNode.name + "Instance";
|
||||
changed = true;
|
||||
} else if (node.getOpcode() == INVOKEVIRTUAL && RenderStateClass.equals(mNode.owner)
|
||||
&& (redirectedSimpleMethods.contains(mNode.name) || redirectedMethods.contains(mNode.name))) {
|
||||
// Handle mods that updated to previously new API
|
||||
mNode.name = mNode.name + "Instance";
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// spotless:on
|
||||
|
||||
if (changed) {
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||
cn.accept(cw);
|
||||
final byte[] bytes = cw.toByteArray();
|
||||
if (DUMP_CLASSES) {
|
||||
saveTransformedClass(basicClass, transformedName + "_PRE");
|
||||
saveTransformedClass(bytes, transformedName + "_POST");
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
return basicClass;
|
||||
}
|
||||
|
||||
private File outputDir = null;
|
||||
|
||||
private void saveTransformedClass(final byte[] data, final String classname) {
|
||||
if (outputDir == null) {
|
||||
outputDir = new File(Launch.minecraftHome, "ASM_CCL" + File.separatorChar + "REDIRECTOR");
|
||||
try {
|
||||
FileUtils.deleteDirectory(outputDir);
|
||||
} catch (IOException ignored) {}
|
||||
if (!outputDir.exists()) {
|
||||
// noinspection ResultOfMethodCallIgnored
|
||||
outputDir.mkdirs();
|
||||
}
|
||||
}
|
||||
final String fileName = classname.replace('.', File.separatorChar);
|
||||
final File classFile = new File(outputDir, fileName + ".class");
|
||||
final File bytecodeFile = new File(outputDir, fileName + "_BYTE.txt");
|
||||
final File outDir = classFile.getParentFile();
|
||||
if (!outDir.exists()) {
|
||||
// noinspection ResultOfMethodCallIgnored
|
||||
outDir.mkdirs();
|
||||
}
|
||||
if (classFile.exists()) {
|
||||
// noinspection ResultOfMethodCallIgnored
|
||||
classFile.delete();
|
||||
}
|
||||
try (final OutputStream output = Files.newOutputStream(classFile.toPath())) {
|
||||
output.write(data);
|
||||
CodeChickenCorePlugin.logger.info("Saved class (byte[]) to " + classFile.toPath());
|
||||
} catch (IOException e) {
|
||||
CodeChickenCorePlugin.logger.error("Could not save class (byte[]) " + classname);
|
||||
}
|
||||
if (bytecodeFile.exists()) {
|
||||
// noinspection ResultOfMethodCallIgnored
|
||||
bytecodeFile.delete();
|
||||
}
|
||||
try (final OutputStream output = Files.newOutputStream(bytecodeFile.toPath())) {
|
||||
final ClassReader classReader = new ClassReader(data);
|
||||
classReader.accept(new TraceClassVisitor(null, new Textifier(), new PrintWriter(output)), 0);
|
||||
CodeChickenCorePlugin.logger.info("Saved class (bytecode) to " + bytecodeFile.toPath());
|
||||
} catch (IOException e) {
|
||||
CodeChickenCorePlugin.logger.error("Could not save class (bytecode) " + classname);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package codechicken.lib.colour;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.config.ConfigTag.IConfigType;
|
||||
import codechicken.lib.math.MathHelper;
|
||||
import codechicken.lib.util.Copyable;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public abstract class Colour implements Copyable<Colour> {
|
||||
|
||||
public static IConfigType<Colour> configRGB = new IConfigType<Colour>() {
|
||||
|
||||
@Override
|
||||
public String configValue(Colour entry) {
|
||||
String s = Long.toString(((long) entry.rgb()) << 32 >>> 32, 16);
|
||||
while (s.length() < 6) s = "0" + s;
|
||||
return "0x" + s.toUpperCase();
|
||||
}
|
||||
|
||||
private final Pattern patternRGB = Pattern.compile("(\\d+),(\\d+),(\\d+)");
|
||||
|
||||
@Override
|
||||
public Colour valueOf(String text) throws Exception {
|
||||
Matcher matcherRGB = patternRGB.matcher(text.replaceAll("\\s", ""));
|
||||
if (matcherRGB.matches()) return new ColourRGBA(
|
||||
Integer.parseInt(matcherRGB.group(1)),
|
||||
Integer.parseInt(matcherRGB.group(2)),
|
||||
Integer.parseInt(matcherRGB.group(3)),
|
||||
0xFF);
|
||||
|
||||
int hex = (int) Long.parseLong(text.replace("0x", ""), 16);
|
||||
return new ColourRGBA(hex << 8 | 0xFF);
|
||||
}
|
||||
};
|
||||
|
||||
public byte r;
|
||||
public byte g;
|
||||
public byte b;
|
||||
public byte a;
|
||||
|
||||
public Colour(int r, int g, int b, int a) {
|
||||
this.r = (byte) r;
|
||||
this.g = (byte) g;
|
||||
this.b = (byte) b;
|
||||
this.a = (byte) a;
|
||||
}
|
||||
|
||||
public Colour(Colour colour) {
|
||||
r = colour.r;
|
||||
g = colour.g;
|
||||
b = colour.b;
|
||||
a = colour.a;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void glColour() {
|
||||
GL11.glColor4ub(r, g, b, a);
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void glColour(int a) {
|
||||
GL11.glColor4ub(r, g, b, (byte) a);
|
||||
}
|
||||
|
||||
public abstract int pack();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "[0x" + Integer.toHexString(pack()).toUpperCase() + "]";
|
||||
}
|
||||
|
||||
public Colour add(Colour colour2) {
|
||||
a += colour2.a;
|
||||
r += colour2.r;
|
||||
g += colour2.g;
|
||||
b += colour2.b;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Colour sub(Colour colour2) {
|
||||
int ia = (a & 0xFF) - (colour2.a & 0xFF);
|
||||
int ir = (r & 0xFF) - (colour2.r & 0xFF);
|
||||
int ig = (g & 0xFF) - (colour2.g & 0xFF);
|
||||
int ib = (b & 0xFF) - (colour2.b & 0xFF);
|
||||
a = (byte) (ia < 0 ? 0 : ia);
|
||||
r = (byte) (ir < 0 ? 0 : ir);
|
||||
g = (byte) (ig < 0 ? 0 : ig);
|
||||
b = (byte) (ib < 0 ? 0 : ib);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Colour invert() {
|
||||
a = (byte) (0xFF - (a & 0xFF));
|
||||
r = (byte) (0xFF - (r & 0xFF));
|
||||
g = (byte) (0xFF - (g & 0xFF));
|
||||
b = (byte) (0xFF - (b & 0xFF));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Colour multiply(Colour colour2) {
|
||||
a = (byte) ((a & 0xFF) * ((colour2.a & 0xFF) / 255D));
|
||||
r = (byte) ((r & 0xFF) * ((colour2.r & 0xFF) / 255D));
|
||||
g = (byte) ((g & 0xFF) * ((colour2.g & 0xFF) / 255D));
|
||||
b = (byte) ((b & 0xFF) * ((colour2.b & 0xFF) / 255D));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Colour scale(double d) {
|
||||
a = (byte) ((a & 0xFF) * d);
|
||||
r = (byte) ((r & 0xFF) * d);
|
||||
g = (byte) ((g & 0xFF) * d);
|
||||
b = (byte) ((b & 0xFF) * d);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Colour interpolate(Colour colour2, double d) {
|
||||
return this.add(colour2.copy().sub(this).scale(d));
|
||||
}
|
||||
|
||||
public Colour multiplyC(double d) {
|
||||
r = (byte) MathHelper.clip((r & 0xFF) * d, 0, 255);
|
||||
g = (byte) MathHelper.clip((g & 0xFF) * d, 0, 255);
|
||||
b = (byte) MathHelper.clip((b & 0xFF) * d, 0, 255);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public abstract Colour copy();
|
||||
|
||||
public int rgb() {
|
||||
return (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF);
|
||||
}
|
||||
|
||||
public int argb() {
|
||||
return (a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF);
|
||||
}
|
||||
|
||||
public int rgba() {
|
||||
return (r & 0xFF) << 24 | (g & 0xFF) << 16 | (b & 0xFF) << 8 | (a & 0xFF);
|
||||
}
|
||||
|
||||
public Colour set(Colour colour) {
|
||||
r = colour.r;
|
||||
g = colour.g;
|
||||
b = colour.b;
|
||||
a = colour.a;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean equals(Colour colour) {
|
||||
return colour != null && rgba() == colour.rgba();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package codechicken.lib.colour;
|
||||
|
||||
public class ColourARGB extends Colour {
|
||||
|
||||
public ColourARGB(int colour) {
|
||||
super((colour >> 16) & 0xFF, (colour >> 8) & 0xFF, colour & 0xFF, (colour >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
public ColourARGB(int a, int r, int g, int b) {
|
||||
super(r, g, b, a);
|
||||
}
|
||||
|
||||
public ColourARGB(ColourARGB colour) {
|
||||
super(colour);
|
||||
}
|
||||
|
||||
public ColourARGB copy() {
|
||||
return new ColourARGB(this);
|
||||
}
|
||||
|
||||
public int pack() {
|
||||
return pack(this);
|
||||
}
|
||||
|
||||
public static int pack(Colour colour) {
|
||||
return (colour.a & 0xFF) << 24 | (colour.r & 0xFF) << 16 | (colour.g & 0xFF) << 8 | (colour.b & 0xFF);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package codechicken.lib.colour;
|
||||
|
||||
public class ColourRGBA extends Colour {
|
||||
|
||||
public ColourRGBA(int colour) {
|
||||
super((colour >> 24) & 0xFF, (colour >> 16) & 0xFF, (colour >> 8) & 0xFF, colour & 0xFF);
|
||||
}
|
||||
|
||||
public ColourRGBA(double r, double g, double b, double a) {
|
||||
super((int) (255 * r), (int) (255 * g), (int) (255 * b), (int) (255 * a));
|
||||
}
|
||||
|
||||
public ColourRGBA(int r, int g, int b, int a) {
|
||||
super(r, g, b, a);
|
||||
}
|
||||
|
||||
public ColourRGBA(ColourRGBA colour) {
|
||||
super(colour);
|
||||
}
|
||||
|
||||
public int pack() {
|
||||
return pack(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Colour copy() {
|
||||
return new ColourRGBA(this);
|
||||
}
|
||||
|
||||
public static int pack(Colour colour) {
|
||||
return (colour.r & 0xFF) << 24 | (colour.g & 0xFF) << 16 | (colour.b & 0xFF) << 8 | (colour.a & 0xFF);
|
||||
}
|
||||
|
||||
public static int multiply(int c1, int c2) {
|
||||
if (c1 == -1) return c2;
|
||||
if (c2 == -1) return c1;
|
||||
int r = (((c1 >>> 24) * (c2 >>> 24)) & 0xFF00) << 16;
|
||||
int g = (((c1 >> 16 & 0xFF) * (c2 >> 16 & 0xFF)) & 0xFF00) << 8;
|
||||
int b = ((c1 >> 8 & 0xFF) * (c2 >> 8 & 0xFF)) & 0xFF00;
|
||||
int a = ((c1 & 0xFF) * (c2 & 0xFF)) >> 8;
|
||||
return r | g | b | a;
|
||||
}
|
||||
|
||||
public static int multiplyC(int c, float f) {
|
||||
int r = (int) ((c >>> 24) * f);
|
||||
int g = (int) ((c >> 16 & 0xFF) * f);
|
||||
int b = (int) ((c >> 8 & 0xFF) * f);
|
||||
return r << 24 | g << 16 | b << 8 | c & 0xFF;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package codechicken.lib.colour;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import codechicken.lib.math.MathHelper;
|
||||
import codechicken.lib.render.TextureUtils;
|
||||
|
||||
public class CustomGradient {
|
||||
|
||||
public int[] gradient;
|
||||
|
||||
public CustomGradient(ResourceLocation textureFile) {
|
||||
BufferedImage img = TextureUtils.loadBufferedImage(textureFile);
|
||||
if (img == null) throw new RuntimeException("File not found: " + textureFile.toString());
|
||||
|
||||
int[] data = new int[img.getWidth()];
|
||||
img.getRGB(0, 0, img.getWidth(), 1, data, 0, img.getWidth());
|
||||
gradient = new int[img.getWidth()];
|
||||
for (int i = 0; i < data.length; i++) gradient[i] = (data[i] << 8) | (((data[i]) >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
public ColourRGBA getColour(double position) {
|
||||
return new ColourRGBA(getColourI(position));
|
||||
}
|
||||
|
||||
public int getColourI(double position) {
|
||||
int off = (int) MathHelper.clip(gradient.length * position, 0, gradient.length - 1);
|
||||
return gradient[off];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package codechicken.lib.config;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
public class ConfigFile extends ConfigTagParent {
|
||||
|
||||
public static final byte[] crlf = new byte[] { 0xD, 0xA };
|
||||
|
||||
public File file;
|
||||
private boolean loading;
|
||||
|
||||
public ConfigFile(File file) {
|
||||
newlinemode = 2;
|
||||
load(file);
|
||||
}
|
||||
|
||||
protected ConfigFile() {}
|
||||
|
||||
protected void load(File file) {
|
||||
try {
|
||||
if (!file.getParentFile().exists()) file.getParentFile().mkdirs();
|
||||
if (!file.exists()) file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.file = file;
|
||||
loadConfig();
|
||||
}
|
||||
|
||||
protected void loadConfig() {
|
||||
loading = true;
|
||||
BufferedReader reader;
|
||||
try {
|
||||
reader = new BufferedReader(new FileReader(file));
|
||||
|
||||
while (true) {
|
||||
reader.mark(2000);
|
||||
String line = reader.readLine();
|
||||
if (line != null && line.startsWith("#")) {
|
||||
if (comment == null || comment.equals("")) comment = line.substring(1);
|
||||
else comment = comment + "\n" + line.substring(1);
|
||||
} else {
|
||||
reader.reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
loadChildren(reader);
|
||||
reader.close();
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigFile setComment(String header) {
|
||||
super.setComment(header);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigFile setSortMode(int mode) {
|
||||
super.setSortMode(mode);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameQualifier() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String readLine(BufferedReader reader) throws IOException {
|
||||
String line = reader.readLine();
|
||||
return line == null ? null : line.replace("\t", "");
|
||||
}
|
||||
|
||||
public static void writeLine(PrintWriter writer, String line, int tabs) {
|
||||
for (int i = 0; i < tabs; i++) writer.print('\t');
|
||||
|
||||
writer.println(line);
|
||||
}
|
||||
|
||||
public void saveConfig() {
|
||||
if (loading) return;
|
||||
|
||||
PrintWriter writer;
|
||||
try {
|
||||
writer = new PrintWriter(file);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
writeComment(writer, 0);
|
||||
ConfigFile.writeLine(writer, "", 0);
|
||||
saveTagTree(writer, 0, "");
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
|
||||
public boolean isLoading() {
|
||||
return loading;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
package codechicken.lib.config;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
public class ConfigTag extends ConfigTagParent {
|
||||
|
||||
public interface IConfigType<T> {
|
||||
|
||||
public String configValue(T entry);
|
||||
|
||||
public T valueOf(String text) throws Exception;
|
||||
}
|
||||
|
||||
public ConfigTag(ConfigTagParent parent, String name) {
|
||||
this.parent = parent;
|
||||
this.name = name;
|
||||
qualifiedname = parent.getNameQualifier() + name;
|
||||
newline = parent.newlinemode == 2;
|
||||
parent.addChild(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameQualifier() {
|
||||
return qualifiedname + ".";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveConfig() {
|
||||
parent.saveConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the tag is loaded from a config file as opposed to constructed by a mod
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public ConfigTag onLoaded() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
public void setDefaultValue(String defaultValue) {
|
||||
if (value == null) {
|
||||
value = defaultValue;
|
||||
saveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
public void setIntValue(int i) {
|
||||
setValue(Integer.toString(i));
|
||||
}
|
||||
|
||||
public void setBooleanValue(boolean b) {
|
||||
setValue(Boolean.toString(b));
|
||||
}
|
||||
|
||||
public void setHexValue(int i) {
|
||||
setValue("0x" + Long.toString(((long) i) << 32 >>> 32, 16));
|
||||
}
|
||||
|
||||
public <T> void set(IConfigType<T> type, T entry) {
|
||||
setValue(type.configValue(entry));
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getValue(String defaultValue) {
|
||||
setDefaultValue(defaultValue);
|
||||
return value;
|
||||
}
|
||||
|
||||
public int getIntValue() {
|
||||
return Integer.parseInt(getValue());
|
||||
}
|
||||
|
||||
public int getIntValue(int defaultValue) {
|
||||
try {
|
||||
if (value != null) return getIntValue();
|
||||
} catch (NumberFormatException ignored) {}
|
||||
|
||||
setIntValue(defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public boolean getBooleanValue() {
|
||||
String value = getValue();
|
||||
if (value != null && (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes"))) return true;
|
||||
else if (value != null && (value.equalsIgnoreCase("false") || value.equalsIgnoreCase("no"))) return false;
|
||||
|
||||
throw new NumberFormatException(qualifiedname + ".value=" + value);
|
||||
}
|
||||
|
||||
public boolean getBooleanValue(boolean defaultValue) {
|
||||
try {
|
||||
if (value != null) return getBooleanValue();
|
||||
} catch (NumberFormatException ignored) {}
|
||||
|
||||
setBooleanValue(defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public int getHexValue() {
|
||||
return (int) Long.parseLong(getValue().replace("0x", ""), 16);
|
||||
}
|
||||
|
||||
public int getHexValue(int defaultValue) {
|
||||
try {
|
||||
if (value != null) return getHexValue();
|
||||
} catch (NumberFormatException ignored) {}
|
||||
|
||||
setHexValue(defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public <T> T get(IConfigType<T> type) {
|
||||
try {
|
||||
return type.valueOf(getValue());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> T get(IConfigType<T> type, T defaultValue) {
|
||||
try {
|
||||
if (value != null) return get(type);
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
set(type, defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public void save(PrintWriter writer, int tabs, String bracequalifier, boolean first) {
|
||||
String vname;
|
||||
if (qualifiedname.contains(".") && bracequalifier.length() > 0)
|
||||
vname = qualifiedname.substring(bracequalifier.length() + 1);
|
||||
else vname = qualifiedname;
|
||||
|
||||
if (newline && !first) ConfigFile.writeLine(writer, "", tabs);
|
||||
|
||||
writeComment(writer, tabs);
|
||||
if (value != null) ConfigFile.writeLine(writer, vname + "=" + value, tabs);
|
||||
|
||||
if (!hasChildTags()) return;
|
||||
|
||||
if (brace) {
|
||||
if (value == null) ConfigFile.writeLine(writer, vname, tabs);
|
||||
ConfigFile.writeLine(writer, "{", tabs);
|
||||
saveTagTree(writer, tabs + 1, qualifiedname);
|
||||
ConfigFile.writeLine(writer, "}", tabs);
|
||||
} else {
|
||||
saveTagTree(writer, tabs, bracequalifier);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigTag setComment(String comment) {
|
||||
super.setComment(comment);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigTag setSortMode(int mode) {
|
||||
super.setSortMode(mode);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfigTag setNewLine(boolean b) {
|
||||
newline = b;
|
||||
saveConfig();
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfigTag useBraces() {
|
||||
brace = true;
|
||||
if (parent.newlinemode == 1) newline = true;
|
||||
|
||||
saveConfig();
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfigTag setPosition(int pos) {
|
||||
position = pos;
|
||||
saveConfig();
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean containsTag(String tagname) {
|
||||
return getTag(tagname, false) != null;
|
||||
}
|
||||
|
||||
public int getId(String name, int defaultValue) {
|
||||
return getTag(name).getIntValue(defaultValue);
|
||||
}
|
||||
|
||||
public int getId(String name) {
|
||||
int ret = getId(name, IDBase);
|
||||
IDBase = ret + 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int getAcheivementId(String name, int defaultValue) {
|
||||
return getTag(name).getIntValue(defaultValue);
|
||||
}
|
||||
|
||||
public ConfigTag setBaseID(int i) {
|
||||
IDBase = i;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfigTagParent parent;
|
||||
public String name;
|
||||
public String qualifiedname;
|
||||
public String value;
|
||||
public boolean brace;
|
||||
public boolean newline;
|
||||
public int position = Integer.MAX_VALUE;
|
||||
|
||||
private int IDBase;
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
package codechicken.lib.config;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public abstract class ConfigTagParent {
|
||||
|
||||
public static class TagOrderComparator implements Comparator<ConfigTag> {
|
||||
|
||||
int sortMode;
|
||||
|
||||
public TagOrderComparator(int sortMode) {
|
||||
this.sortMode = sortMode;
|
||||
}
|
||||
|
||||
public int compare(ConfigTag o1, ConfigTag o2) {
|
||||
if (o1.position != o2.position) return Integer.compare(o1.position, o2.position);
|
||||
if (o1.brace != o2.brace) return o1.brace ? 1 : -1; // braced one goes after
|
||||
|
||||
if (sortMode == 1) {
|
||||
if (Objects.equals(o1.value, o2.value)) return 0;
|
||||
if (o1.value == null) return 1;
|
||||
if (o2.value == null) return -1;
|
||||
return o1.value.compareTo(o2.value);
|
||||
} else {
|
||||
return o1.name.compareTo(o2.name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The immediate child tags of this tag
|
||||
*/
|
||||
private final TreeMap<String, ConfigTag> childtags = new TreeMap<>();
|
||||
/**
|
||||
* A map of all tags in the tree, meaning all tags in this tag and all tags in child tags (recursively). Allows for
|
||||
* quick access to any tag in the tree, without the need to traverse the tree part by part.
|
||||
*/
|
||||
private final Map<String, ConfigTag> allTagsInTree = new HashMap<>();
|
||||
public String comment;
|
||||
/**
|
||||
* 0 = name, 1 = value
|
||||
*/
|
||||
public int sortMode = 0;
|
||||
/**
|
||||
* The mode for determining when child tags should leave a blank line between them and the one above 0 = never, 1 =
|
||||
* when braced, 2 = always
|
||||
*/
|
||||
public int newlinemode = 1;
|
||||
|
||||
public abstract void saveConfig();
|
||||
|
||||
public abstract String getNameQualifier();
|
||||
|
||||
public ConfigTagParent setComment(String comment) {
|
||||
this.comment = comment;
|
||||
saveConfig();
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfigTagParent setSortMode(int mode) {
|
||||
sortMode = mode;
|
||||
saveConfig();
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfigTagParent setNewLineMode(int mode) {
|
||||
newlinemode = mode;
|
||||
for (Entry<String, ConfigTag> entry : childtags.entrySet()) {
|
||||
ConfigTag tag = entry.getValue();
|
||||
if (newlinemode == 0) tag.newline = false;
|
||||
else if (newlinemode == 1) tag.newline = tag.brace;
|
||||
else if (newlinemode == 2) tag.newline = true;
|
||||
}
|
||||
saveConfig();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, ConfigTag> childTagMap() {
|
||||
return childtags;
|
||||
}
|
||||
|
||||
public boolean hasChildTags() {
|
||||
return !childtags.isEmpty();
|
||||
}
|
||||
|
||||
public boolean containsTag(String tagname) {
|
||||
return allTagsInTree.get(tagname) != null;
|
||||
}
|
||||
|
||||
public ConfigTag getNewTag(String tagname) {
|
||||
return new ConfigTag(this, tagname);
|
||||
}
|
||||
|
||||
public ConfigTag getTag(String tagname, boolean create) {
|
||||
ConfigTag tag = allTagsInTree.get(tagname);
|
||||
if (tag == null && create) return getTagRecursive(tagname, create);
|
||||
return tag;
|
||||
}
|
||||
|
||||
public ConfigTag getTagRecursive(String tagname, boolean create) {
|
||||
int dotpos = tagname.indexOf(".");
|
||||
String basetagname = dotpos == -1 ? tagname : tagname.substring(0, dotpos);
|
||||
ConfigTag basetag = childtags.get(basetagname);
|
||||
if (basetag == null) {
|
||||
if (!create) return null;
|
||||
|
||||
basetag = getNewTag(basetagname);
|
||||
saveConfig();
|
||||
}
|
||||
if (dotpos == -1) return basetag;
|
||||
|
||||
return basetag.getTag(tagname.substring(dotpos + 1), create);
|
||||
}
|
||||
|
||||
public ConfigTag getTag(String tagname) {
|
||||
return getTag(tagname, true);
|
||||
}
|
||||
|
||||
public boolean removeTag(String tagname) {
|
||||
removeChildFromFlatMap(tagname);
|
||||
|
||||
ConfigTag tag = getTag(tagname, false);
|
||||
if (tag == null) return false;
|
||||
|
||||
int dotpos = tagname.lastIndexOf(".");
|
||||
String lastpart = dotpos == -1 ? tagname : tagname.substring(dotpos + 1, tagname.length());
|
||||
if (tag.parent != null) {
|
||||
boolean ret = tag.parent.childtags.remove(lastpart) != null;
|
||||
if (ret) saveConfig();
|
||||
return ret;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addChild(ConfigTag tag) {
|
||||
childtags.put(tag.name, tag);
|
||||
|
||||
addChildToFlatMap(tag.name, tag);
|
||||
}
|
||||
|
||||
private void addChildToFlatMap(String path, ConfigTag tag) {
|
||||
allTagsInTree.put(path, tag);
|
||||
|
||||
// Stupid cast but these two garbage classes are interlinked anyway
|
||||
if ((this instanceof ConfigTag t) && t.parent != null) t.parent.addChildToFlatMap(t.name + "." + path, tag);
|
||||
}
|
||||
|
||||
private void removeChildFromFlatMap(String path) {
|
||||
allTagsInTree.remove(path);
|
||||
|
||||
// Stupid cast but these two garbage classes are interlinked anyway
|
||||
if ((this instanceof ConfigTag t) && t.parent != null) t.parent.removeChildFromFlatMap(t.name + "." + path);
|
||||
}
|
||||
|
||||
public <T extends ConfigTag> ArrayList<T> getSortedTagList() {
|
||||
ArrayList<T> taglist = new ArrayList<T>(childtags.size());
|
||||
for (Entry<String, ConfigTag> tag : childtags.entrySet()) taglist.add((T) tag.getValue());
|
||||
|
||||
Collections.sort(taglist, new TagOrderComparator(sortMode));
|
||||
return taglist;
|
||||
}
|
||||
|
||||
public void loadChildren(BufferedReader reader) {
|
||||
String comment = "";
|
||||
String bracequalifier = "";
|
||||
try {
|
||||
while (true) {
|
||||
String line = ConfigFile.readLine(reader);
|
||||
if (line == null) break;
|
||||
if (line.startsWith("#")) {
|
||||
if (comment.equals("")) comment = line.substring(1);
|
||||
else comment = comment + "\n" + line.substring(1);
|
||||
} else if (line.contains("=")) {
|
||||
String qualifiedname = line.substring(0, line.indexOf("="));
|
||||
getTag(qualifiedname).onLoaded().setComment(comment)
|
||||
.setValue(line.substring(line.indexOf("=") + 1));
|
||||
comment = "";
|
||||
bracequalifier = qualifiedname;
|
||||
} else if (line.equals("{")) {
|
||||
getTag(bracequalifier).setComment(comment).useBraces().loadChildren(reader);
|
||||
comment = "";
|
||||
bracequalifier = "";
|
||||
} else if (line.equals("}")) {
|
||||
break;
|
||||
} else {
|
||||
bracequalifier = line;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveTagTree(PrintWriter writer, int tabs, String bracequalifier) {
|
||||
boolean first = true;
|
||||
for (ConfigTag tag : getSortedTagList()) {
|
||||
tag.save(writer, tabs, bracequalifier, first);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeComment(PrintWriter writer, int tabs) {
|
||||
if (comment != null && !comment.equals("")) {
|
||||
String[] comments = comment.split("\n");
|
||||
for (int i = 0; i < comments.length; i++) ConfigFile.writeLine(writer, "#" + comments[i], tabs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package codechicken.lib.config;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class DefaultingConfigFile extends ConfigFile {
|
||||
|
||||
public DefaultingConfigFile(File file) {
|
||||
super();
|
||||
if (file.exists()) load(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveConfig() {
|
||||
if (file != null) super.saveConfig();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package codechicken.lib.config;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class SimpleProperties {
|
||||
|
||||
public HashMap<String, String> propertyMap = new HashMap<String, String>();
|
||||
public File propertyFile;
|
||||
public boolean saveOnChange = false;
|
||||
public String encoding;
|
||||
|
||||
private boolean loading = false;
|
||||
|
||||
public SimpleProperties(File file, boolean saveOnChange, String encoding) {
|
||||
propertyFile = file;
|
||||
this.saveOnChange = saveOnChange;
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
public SimpleProperties(File file, boolean saveOnChange) {
|
||||
this(file, saveOnChange, Charset.defaultCharset().name());
|
||||
}
|
||||
|
||||
public SimpleProperties(File file) {
|
||||
this(file, true);
|
||||
}
|
||||
|
||||
public void load() {
|
||||
clear();
|
||||
loading = true;
|
||||
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(new FileInputStream(propertyFile), encoding));
|
||||
while (true) {
|
||||
String read = reader.readLine();
|
||||
if (read == null) break;
|
||||
|
||||
int equalIndex = read.indexOf('=');
|
||||
if (equalIndex == -1) continue;
|
||||
|
||||
setProperty(read.substring(0, equalIndex), read.substring(equalIndex + 1));
|
||||
}
|
||||
reader.close();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
loading = false;
|
||||
}
|
||||
|
||||
public void save() {
|
||||
try {
|
||||
PrintStream writer = new PrintStream(propertyFile);
|
||||
|
||||
for (Entry<String, String> entry : propertyMap.entrySet()) {
|
||||
writer.println(entry.getKey() + "=" + entry.getValue());
|
||||
}
|
||||
|
||||
writer.close();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
propertyMap.clear();
|
||||
}
|
||||
|
||||
public boolean hasProperty(String key) {
|
||||
return propertyMap.containsKey(key);
|
||||
}
|
||||
|
||||
public void removeProperty(String key) {
|
||||
if (propertyMap.remove(key) != null && saveOnChange && !loading) save();
|
||||
}
|
||||
|
||||
public void setProperty(String key, int value) {
|
||||
setProperty(key, Integer.toString(value));
|
||||
}
|
||||
|
||||
public void setProperty(String key, boolean value) {
|
||||
setProperty(key, Boolean.toString(value));
|
||||
}
|
||||
|
||||
public void setProperty(String key, String value) {
|
||||
propertyMap.put(key, value);
|
||||
if (saveOnChange && !loading) save();
|
||||
}
|
||||
|
||||
public int getProperty(String property, int defaultvalue) {
|
||||
try {
|
||||
return Integer.parseInt(getProperty(property, Integer.toString(defaultvalue)));
|
||||
} catch (NumberFormatException nfe) {
|
||||
return defaultvalue;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getProperty(String property, boolean defaultvalue) {
|
||||
try {
|
||||
return Boolean.parseBoolean(getProperty(property, Boolean.toString(defaultvalue)));
|
||||
} catch (NumberFormatException nfe) {
|
||||
return defaultvalue;
|
||||
}
|
||||
}
|
||||
|
||||
public String getProperty(String property, String defaultvalue) {
|
||||
String value = propertyMap.get(property);
|
||||
if (value == null) {
|
||||
setProperty(property, defaultvalue);
|
||||
return defaultvalue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getProperty(String property) {
|
||||
return propertyMap.get(property);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package codechicken.lib.data;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
|
||||
import codechicken.lib.vec.BlockCoord;
|
||||
|
||||
public interface MCDataInput {
|
||||
|
||||
public long readLong();
|
||||
|
||||
public int readInt();
|
||||
|
||||
public short readShort();
|
||||
|
||||
public int readUShort();
|
||||
|
||||
public byte readByte();
|
||||
|
||||
public short readUByte();
|
||||
|
||||
public double readDouble();
|
||||
|
||||
public float readFloat();
|
||||
|
||||
public boolean readBoolean();
|
||||
|
||||
public char readChar();
|
||||
|
||||
public int readVarShort();
|
||||
|
||||
public int readVarInt();
|
||||
|
||||
public byte[] readByteArray(int length);
|
||||
|
||||
public String readString();
|
||||
|
||||
public BlockCoord readCoord();
|
||||
|
||||
public NBTTagCompound readNBTTagCompound();
|
||||
|
||||
public ItemStack readItemStack();
|
||||
|
||||
public FluidStack readFluidStack();
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package codechicken.lib.data;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public class MCDataInputStream extends InputStream {
|
||||
|
||||
private MCDataInput in;
|
||||
|
||||
public MCDataInputStream(MCDataInput in) {
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
return in.readByte() & 0xFF;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package codechicken.lib.data;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
|
||||
import codechicken.lib.vec.BlockCoord;
|
||||
|
||||
public interface MCDataOutput {
|
||||
|
||||
public MCDataOutput writeLong(long l);
|
||||
|
||||
public MCDataOutput writeInt(int i);
|
||||
|
||||
public MCDataOutput writeShort(int s);
|
||||
|
||||
public MCDataOutput writeByte(int b);
|
||||
|
||||
public MCDataOutput writeDouble(double d);
|
||||
|
||||
public MCDataOutput writeFloat(float f);
|
||||
|
||||
public MCDataOutput writeBoolean(boolean b);
|
||||
|
||||
public MCDataOutput writeChar(char c);
|
||||
|
||||
public MCDataOutput writeVarInt(int i);
|
||||
|
||||
public MCDataOutput writeVarShort(int s);
|
||||
|
||||
public MCDataOutput writeByteArray(byte[] array);
|
||||
|
||||
public MCDataOutput writeString(String s);
|
||||
|
||||
public MCDataOutput writeCoord(int x, int y, int z);
|
||||
|
||||
public MCDataOutput writeCoord(BlockCoord coord);
|
||||
|
||||
public MCDataOutput writeNBTTagCompound(NBTTagCompound tag);
|
||||
|
||||
public MCDataOutput writeItemStack(ItemStack stack);
|
||||
|
||||
public MCDataOutput writeFluidStack(FluidStack liquid);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package codechicken.lib.data;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class MCDataOutputStream extends OutputStream {
|
||||
|
||||
private MCDataOutput out;
|
||||
|
||||
public MCDataOutputStream(MCDataOutput out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) {
|
||||
out.writeByte(b);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
package codechicken.lib.data;
|
||||
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompressedStreamTools;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import codechicken.lib.vec.BlockCoord;
|
||||
import cpw.mods.fml.common.network.ByteBufUtils;
|
||||
|
||||
public class MCDataOutputWrapper implements MCDataOutput {
|
||||
|
||||
/**
|
||||
* Mimics ByteBufUtils Write an integer using variable length encoding.
|
||||
*
|
||||
* @param to The buffer to write to
|
||||
* @param i The integer to write
|
||||
*/
|
||||
public static void writeVarInt(DataOutput to, int i) throws IOException {
|
||||
while ((i & 0x80) != 0) {
|
||||
to.writeByte(i & 0x7F | 0x80);
|
||||
i >>>= 7;
|
||||
}
|
||||
|
||||
to.writeByte(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mimics ByteBufUtils Write an extended short using a short and a byte if necessary
|
||||
*
|
||||
* @param to The buffer to write to
|
||||
* @param s The short to write, less than 0x7FFFFF
|
||||
*/
|
||||
public static void writeVarShort(DataOutput to, int s) throws IOException {
|
||||
int low = s & 0x7FFF;
|
||||
int high = (s & 0x7F8000) >> 15;
|
||||
if (high != 0) low |= 0x8000;
|
||||
to.writeShort(low);
|
||||
if (high != 0) to.writeByte(high);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mimics ByteBufUtils Write a String with UTF8 byte encoding to the buffer. It is encoded as <varint length>[<UTF8
|
||||
* char bytes>]
|
||||
*
|
||||
* @param to the data output to write to
|
||||
* @param string The string to write
|
||||
*/
|
||||
public static void writeUTF8String(DataOutput to, String string) throws IOException {
|
||||
byte[] utf8Bytes = string.getBytes(Charsets.UTF_8);
|
||||
Validate.isTrue(
|
||||
ByteBufUtils.varIntByteCount(utf8Bytes.length) < 3,
|
||||
"The string is too long for this encoding.");
|
||||
writeVarInt(to, utf8Bytes.length);
|
||||
to.write(utf8Bytes);
|
||||
}
|
||||
|
||||
public DataOutput dataout;
|
||||
|
||||
public MCDataOutputWrapper(DataOutput out) {
|
||||
dataout = out;
|
||||
}
|
||||
|
||||
public MCDataOutputWrapper writeBoolean(boolean b) {
|
||||
try {
|
||||
dataout.writeBoolean(b);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCDataOutputWrapper writeByte(int b) {
|
||||
try {
|
||||
dataout.writeByte(b);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCDataOutputWrapper writeShort(int s) {
|
||||
try {
|
||||
dataout.writeShort(s);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCDataOutputWrapper writeInt(int i) {
|
||||
try {
|
||||
dataout.writeInt(i);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCDataOutputWrapper writeFloat(float f) {
|
||||
try {
|
||||
dataout.writeFloat(f);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCDataOutputWrapper writeDouble(double d) {
|
||||
try {
|
||||
dataout.writeDouble(d);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCDataOutputWrapper writeLong(long l) {
|
||||
try {
|
||||
dataout.writeLong(l);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MCDataOutputWrapper writeChar(char c) {
|
||||
try {
|
||||
dataout.writeChar(c);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MCDataOutput writeVarInt(int i) {
|
||||
try {
|
||||
writeVarInt(dataout, i);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MCDataOutput writeVarShort(int s) {
|
||||
try {
|
||||
writeVarShort(dataout, s);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCDataOutputWrapper writeByteArray(byte[] barray) {
|
||||
try {
|
||||
dataout.write(barray);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCDataOutputWrapper writeCoord(int x, int y, int z) {
|
||||
writeInt(x);
|
||||
writeInt(y);
|
||||
writeInt(z);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCDataOutputWrapper writeCoord(BlockCoord coord) {
|
||||
writeInt(coord.x);
|
||||
writeInt(coord.y);
|
||||
writeInt(coord.z);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCDataOutputWrapper writeString(String s) {
|
||||
try {
|
||||
writeUTF8String(dataout, s);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCDataOutputWrapper writeItemStack(ItemStack stack) {
|
||||
writeItemStack(stack, false);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCDataOutputWrapper writeItemStack(ItemStack stack, boolean large) {
|
||||
if (stack == null) {
|
||||
writeInt(-1);
|
||||
} else {
|
||||
writeInt(Item.getIdFromItem(stack.getItem()));
|
||||
if (large) writeInt(stack.stackSize);
|
||||
else writeByte(stack.stackSize);
|
||||
writeShort(stack.getItemDamage());
|
||||
writeNBTTagCompound(stack.stackTagCompound);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCDataOutputWrapper writeNBTTagCompound(NBTTagCompound compound) {
|
||||
try {
|
||||
if (compound == null) {
|
||||
writeShort(-1);
|
||||
} else {
|
||||
byte[] bytes = CompressedStreamTools.compress(compound);
|
||||
writeShort((short) bytes.length);
|
||||
writeByteArray(bytes);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCDataOutputWrapper writeFluidStack(FluidStack fluid) {
|
||||
if (fluid == null) {
|
||||
writeShort(-1);
|
||||
} else {
|
||||
writeShort(fluid.getFluidID());
|
||||
writeVarInt(fluid.amount);
|
||||
writeNBTTagCompound(fluid.tag);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package codechicken.lib.gui;
|
||||
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import codechicken.lib.render.CCRenderState;
|
||||
import codechicken.lib.render.TextureDataHolder;
|
||||
import codechicken.lib.render.TextureUtils;
|
||||
|
||||
public class Canvas9Seg {
|
||||
|
||||
public final ResourceLocation tex;
|
||||
public float[] seg_u = new float[4];
|
||||
public float[] seg_v = new float[4];
|
||||
public int[] seg_w = new int[3];
|
||||
public int[] seg_h = new int[3];
|
||||
|
||||
public Canvas9Seg(ResourceLocation tex) {
|
||||
this.tex = tex;
|
||||
load();
|
||||
}
|
||||
|
||||
private int[] readMarkers(TextureDataHolder data, int stride, int size) {
|
||||
int[] markers = new int[4];
|
||||
|
||||
int marker = 1;
|
||||
int prev_col = data.data[0];
|
||||
for (int i = 1; i < size; i++) {
|
||||
if (data.data[i * stride] != prev_col) {
|
||||
markers[marker] = i;
|
||||
prev_col = data.data[i * stride];
|
||||
if (++marker == 4) break;
|
||||
}
|
||||
}
|
||||
|
||||
markers[0] += 1;
|
||||
markers[3] -= 1;
|
||||
return markers;
|
||||
}
|
||||
|
||||
private void parseMarkers(TextureDataHolder data, int stride, int size, int[] sizes, float[] texcoords) {
|
||||
int[] markers = readMarkers(data, stride, size);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
texcoords[i] = markers[i] / (float) size;
|
||||
if (i > 0) sizes[i - 1] = markers[i] - markers[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
private void load() {
|
||||
TextureDataHolder data = TextureUtils.loadTexture(tex);
|
||||
parseMarkers(data, 1, data.width, seg_w, seg_u);
|
||||
parseMarkers(data, data.width, data.height, seg_h, seg_v);
|
||||
}
|
||||
|
||||
private void drawSeg(int[] sw, int[] sh, int seg) {
|
||||
Tessellator t = Tessellator.instance;
|
||||
int u = seg % 3;
|
||||
int v = seg / 3;
|
||||
t.addVertexWithUV(sw[u], sh[v], 0, seg_u[u], seg_v[v]);
|
||||
t.addVertexWithUV(sw[u], sh[v + 1], 0, seg_u[u], seg_v[v + 1]);
|
||||
t.addVertexWithUV(sw[u + 1], sh[v + 1], 0, seg_u[u + 1], seg_v[v + 1]);
|
||||
t.addVertexWithUV(sw[u + 1], sh[v], 0, seg_u[u + 1], seg_v[v]);
|
||||
}
|
||||
|
||||
public void draw(CCRenderState state, int x, int y, int w, int h) {
|
||||
CCRenderState.changeTexture(tex);
|
||||
state.resetInstance();
|
||||
state.startDrawingInstance();
|
||||
|
||||
int[] sw = new int[] { x, x + seg_w[0], x + w - seg_w[2], x + w };
|
||||
int[] sh = new int[] { y, y + seg_h[0], y + h - seg_h[2], y + h };
|
||||
|
||||
for (int seg = 0; seg < 9; seg++) drawSeg(sw, sh, seg);
|
||||
|
||||
state.drawInstance();
|
||||
}
|
||||
|
||||
public void draw(int x, int y, int w, int h) {
|
||||
draw(CCRenderState.instance(), x, y, w, h);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
package codechicken.lib.gui;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
|
||||
import codechicken.lib.math.MathHelper;
|
||||
import codechicken.lib.render.CCRenderState;
|
||||
|
||||
public class GuiDraw {
|
||||
|
||||
public static class GuiHook extends Gui {
|
||||
|
||||
public void setZLevel(float f) {
|
||||
zLevel = f;
|
||||
}
|
||||
|
||||
public float getZLevel() {
|
||||
return zLevel;
|
||||
}
|
||||
|
||||
public void incZLevel(float f) {
|
||||
zLevel += f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawGradientRect(int par1, int par2, int par3, int par4, int par5, int par6) {
|
||||
super.drawGradientRect(par1, par2, par3, par4, par5, par6);
|
||||
}
|
||||
}
|
||||
|
||||
public static final GuiHook gui = new GuiHook();
|
||||
public static FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer;
|
||||
public static TextureManager renderEngine = Minecraft.getMinecraft().renderEngine;
|
||||
|
||||
public static void drawRect(int x, int y, int w, int h, int colour) {
|
||||
drawGradientRect(x, y, w, h, colour, colour);
|
||||
}
|
||||
|
||||
public static void drawGradientRect(int x, int y, int w, int h, int colour1, int colour2) {
|
||||
gui.drawGradientRect(x, y, x + w, y + h, colour1, colour2);
|
||||
}
|
||||
|
||||
public static void drawTexturedModalRect(int x, int y, int tx, int ty, int w, int h) {
|
||||
gui.drawTexturedModalRect(x, y, tx, ty, w, h);
|
||||
}
|
||||
|
||||
public static void drawString(String text, int x, int y, int colour, boolean shadow) {
|
||||
if (shadow) fontRenderer.drawStringWithShadow(text, x, y, colour);
|
||||
else fontRenderer.drawString(text, x, y, colour);
|
||||
}
|
||||
|
||||
public static void drawString(String text, int x, int y, int colour) {
|
||||
drawString(text, x, y, colour, true);
|
||||
}
|
||||
|
||||
public static void drawStringC(String text, int x, int y, int w, int h, int colour, boolean shadow) {
|
||||
drawString(text, x + (w - getStringWidth(text)) / 2, y + (h - 8) / 2, colour, shadow);
|
||||
}
|
||||
|
||||
public static void drawStringC(String text, int x, int y, int w, int h, int colour) {
|
||||
drawStringC(text, x, y, w, h, colour, true);
|
||||
}
|
||||
|
||||
public static void drawStringC(String text, int x, int y, int colour, boolean shadow) {
|
||||
drawString(text, x - getStringWidth(text) / 2, y, colour, shadow);
|
||||
}
|
||||
|
||||
public static void drawStringC(String text, int x, int y, int colour) {
|
||||
drawStringC(text, x, y, colour, true);
|
||||
}
|
||||
|
||||
public static void drawStringR(String text, int x, int y, int colour, boolean shadow) {
|
||||
drawString(text, x - getStringWidth(text), y, colour, shadow);
|
||||
}
|
||||
|
||||
public static void drawStringR(String text, int x, int y, int colour) {
|
||||
drawStringR(text, x, y, colour, true);
|
||||
}
|
||||
|
||||
public static int getStringWidth(String s) {
|
||||
return fontRenderer.getStringWidth(s);
|
||||
}
|
||||
|
||||
public static Dimension displaySize() {
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
ScaledResolution res = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight);
|
||||
return new Dimension(res.getScaledWidth(), res.getScaledHeight());
|
||||
}
|
||||
|
||||
public static Dimension displayRes() {
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
return new Dimension(mc.displayWidth, mc.displayHeight);
|
||||
}
|
||||
|
||||
public static Point getMousePosition(int eventX, int eventY) {
|
||||
Dimension size = displaySize();
|
||||
Dimension res = displayRes();
|
||||
return new Point(eventX * size.width / res.width, size.height - eventY * size.height / res.height - 1);
|
||||
}
|
||||
|
||||
public static Point getMousePosition() {
|
||||
return getMousePosition(Mouse.getX(), Mouse.getY());
|
||||
}
|
||||
|
||||
public static void changeTexture(String s) {
|
||||
CCRenderState.changeTexture(s);
|
||||
}
|
||||
|
||||
public static void changeTexture(ResourceLocation r) {
|
||||
CCRenderState.changeTexture(r);
|
||||
}
|
||||
|
||||
public static void drawTip(int x, int y, String text) {
|
||||
drawMultilineTip(x, y, Arrays.asList(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a string in the tooltip list with TOOLTIP_LINESPACE to have a small gap between it and the next line
|
||||
*/
|
||||
public static final String TOOLTIP_LINESPACE = "\u00A7h";
|
||||
/**
|
||||
* Have a string in the tooltip list with TOOLTIP_HANDLER + getTipLineId(handler) for a custom handler
|
||||
*/
|
||||
public static final String TOOLTIP_HANDLER = "\u00A7x";
|
||||
|
||||
private static List<ITooltipLineHandler> tipLineHandlers = new ArrayList<ITooltipLineHandler>();
|
||||
|
||||
public static interface ITooltipLineHandler {
|
||||
|
||||
public Dimension getSize();
|
||||
|
||||
public void draw(int x, int y);
|
||||
}
|
||||
|
||||
public static int getTipLineId(ITooltipLineHandler handler) {
|
||||
tipLineHandlers.add(handler);
|
||||
return tipLineHandlers.size() - 1;
|
||||
}
|
||||
|
||||
public static ITooltipLineHandler getTipLine(String line) {
|
||||
if (!line.startsWith(TOOLTIP_HANDLER)) return null;
|
||||
return tipLineHandlers.get(Integer.parseInt(line.substring(2)));
|
||||
}
|
||||
|
||||
public static void drawMultilineTip(int x, int y, List<String> list) {
|
||||
drawMultilineTip(fontRenderer, x, y, list);
|
||||
}
|
||||
|
||||
public static void drawMultilineTip(FontRenderer font, int x, int y, List<String> list) {
|
||||
if (list.isEmpty()) return;
|
||||
|
||||
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
|
||||
GL11.glDisable(GL11.GL_DEPTH_TEST);
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
|
||||
int w = 0;
|
||||
int h = -2;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
String s = list.get(i);
|
||||
ITooltipLineHandler line = getTipLine(s);
|
||||
Dimension d = line != null ? line.getSize()
|
||||
: new Dimension(
|
||||
font.getStringWidth(s),
|
||||
list.get(i).endsWith(TOOLTIP_LINESPACE) && i + 1 < list.size() ? 12 : 10);
|
||||
w = Math.max(w, d.width);
|
||||
h += d.height;
|
||||
}
|
||||
|
||||
if (x < 8) x = 8;
|
||||
else if (x > displaySize().width - w - 8) {
|
||||
x -= 24 + w; // flip side of cursor
|
||||
if (x < 8) x = 8;
|
||||
}
|
||||
y = (int) MathHelper.clip(y, 8, displaySize().height - 8 - h);
|
||||
|
||||
gui.incZLevel(300);
|
||||
drawTooltipBox(x - 4, y - 4, w + 7, h + 7);
|
||||
for (String s : list) {
|
||||
ITooltipLineHandler line = getTipLine(s);
|
||||
if (line != null) {
|
||||
line.draw(x, y);
|
||||
y += line.getSize().height;
|
||||
} else {
|
||||
font.drawStringWithShadow(s, x, y, -1);
|
||||
y += s.endsWith(TOOLTIP_LINESPACE) ? 12 : 10;
|
||||
}
|
||||
}
|
||||
|
||||
tipLineHandlers.clear();
|
||||
gui.incZLevel(-300);
|
||||
|
||||
GL11.glEnable(GL11.GL_DEPTH_TEST);
|
||||
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
}
|
||||
|
||||
public static void drawTooltipBox(int x, int y, int w, int h) {
|
||||
int bg = 0xf0100010;
|
||||
drawGradientRect(x + 1, y, w - 1, 1, bg, bg);
|
||||
drawGradientRect(x + 1, y + h, w - 1, 1, bg, bg);
|
||||
drawGradientRect(x + 1, y + 1, w - 1, h - 1, bg, bg); // center
|
||||
drawGradientRect(x, y + 1, 1, h - 1, bg, bg);
|
||||
drawGradientRect(x + w, y + 1, 1, h - 1, bg, bg);
|
||||
int grad1 = 0x505000ff;
|
||||
int grad2 = 0x5028007F;
|
||||
drawGradientRect(x + 1, y + 2, 1, h - 3, grad1, grad2);
|
||||
drawGradientRect(x + w - 1, y + 2, 1, h - 3, grad1, grad2);
|
||||
|
||||
drawGradientRect(x + 1, y + 1, w - 1, 1, grad1, grad1);
|
||||
drawGradientRect(x + 1, y + h - 1, w - 1, 1, grad2, grad2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
package codechicken.lib.inventory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.inventory.ICrafting;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.play.INetHandlerPlayClient;
|
||||
import net.minecraft.network.play.INetHandlerPlayServer;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import codechicken.lib.packet.PacketCustom;
|
||||
import codechicken.lib.packet.PacketCustom.IClientPacketHandler;
|
||||
import codechicken.lib.packet.PacketCustom.IServerPacketHandler;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
|
||||
/**
|
||||
* Clean container implementation with a few extra features. Easy shift-click handling. Hooks for slot clicks, large
|
||||
* stack sizes and some networking.
|
||||
*/
|
||||
public abstract class ContainerExtended extends Container implements ICrafting {
|
||||
|
||||
private static final String netChannel = "CCL:Container";
|
||||
private static int nextNetworkID = 0;
|
||||
|
||||
static {
|
||||
PacketCustom.assignHandler(netChannel, new IClientPacketHandler() {
|
||||
|
||||
@Override
|
||||
public void handlePacket(PacketCustom packet, Minecraft mc, INetHandlerPlayClient handler) {
|
||||
Container cont = mc.thePlayer.openContainer;
|
||||
if (!(cont instanceof ContainerExtended)) return;
|
||||
|
||||
ContainerExtended c = (ContainerExtended) cont;
|
||||
if (packet.getType() == 1) c.netID = packet.readInt();
|
||||
else if (c.netID == packet.readInt()) c.handleClientPacket(packet);
|
||||
}
|
||||
});
|
||||
PacketCustom.assignHandler(netChannel, new IServerPacketHandler() {
|
||||
|
||||
@Override
|
||||
public void handlePacket(PacketCustom packet, EntityPlayerMP sender, INetHandlerPlayServer handler) {
|
||||
Container cont = sender.openContainer;
|
||||
if (!(cont instanceof ContainerExtended)) return;
|
||||
|
||||
ContainerExtended c = (ContainerExtended) cont;
|
||||
if (c.netID == packet.readInt()) c.handleServerPacket(packet);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public LinkedList<EntityPlayerMP> playerCrafters = new LinkedList<EntityPlayerMP>();
|
||||
private int netID;
|
||||
|
||||
public ContainerExtended() {
|
||||
crafters.add(this);
|
||||
if (FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER) netID = ++nextNetworkID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCraftingToCrafters(ICrafting icrafting) {
|
||||
if (icrafting instanceof EntityPlayerMP) {
|
||||
playerCrafters.add((EntityPlayerMP) icrafting);
|
||||
sendNetID((EntityPlayerMP) icrafting);
|
||||
sendContainerAndContentsToPlayer(this, getInventory(), Arrays.asList((EntityPlayerMP) icrafting));
|
||||
detectAndSendChanges();
|
||||
} else super.addCraftingToCrafters(icrafting);
|
||||
}
|
||||
|
||||
private void sendNetID(EntityPlayerMP player) {
|
||||
if (netID == 0) LogManager.getLogger("CodeChickenLib").error("Player added to container with 0 network ID");
|
||||
else new PacketCustom(netChannel, 1).writeInt(netID).sendToPlayer(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCraftingFromCrafters(ICrafting icrafting) {
|
||||
if (icrafting instanceof EntityPlayerMP) playerCrafters.remove(icrafting);
|
||||
else super.removeCraftingFromCrafters(icrafting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendContainerAndContentsToPlayer(Container container, List list) {
|
||||
sendContainerAndContentsToPlayer(container, list, playerCrafters);
|
||||
}
|
||||
|
||||
public void sendContainerAndContentsToPlayer(Container container, List<ItemStack> list,
|
||||
List<EntityPlayerMP> playerCrafters) {
|
||||
LinkedList<ItemStack> largeStacks = new LinkedList<ItemStack>();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
ItemStack stack = list.get(i);
|
||||
if (stack != null && stack.stackSize > Byte.MAX_VALUE) {
|
||||
list.set(i, null);
|
||||
largeStacks.add(stack);
|
||||
} else largeStacks.add(null);
|
||||
}
|
||||
|
||||
for (EntityPlayerMP player : playerCrafters) player.sendContainerAndContentsToPlayer(container, list);
|
||||
|
||||
for (int i = 0; i < largeStacks.size(); i++) {
|
||||
ItemStack stack = largeStacks.get(i);
|
||||
if (stack != null) sendLargeStack(stack, i, playerCrafters);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendLargeStack(ItemStack stack, int slot, List<EntityPlayerMP> players) {}
|
||||
|
||||
@Override
|
||||
public void sendProgressBarUpdate(Container container, int i, int j) {
|
||||
for (EntityPlayerMP player : playerCrafters) player.sendProgressBarUpdate(container, i, j);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSlotContents(Container container, int slot, ItemStack stack) {
|
||||
if (stack != null && stack.stackSize > Byte.MAX_VALUE) sendLargeStack(stack, slot, playerCrafters);
|
||||
else for (EntityPlayerMP player : playerCrafters) player.sendSlotContents(container, slot, stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack slotClick(int par1, int par2, int par3, EntityPlayer player) {
|
||||
if (par1 >= 0 && par1 < inventorySlots.size()) {
|
||||
Slot slot = getSlot(par1);
|
||||
if (slot instanceof SlotHandleClicks) return ((SlotHandleClicks) slot).slotClick(this, player, par2, par3);
|
||||
}
|
||||
return super.slotClick(par1, par2, par3, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack transferStackInSlot(EntityPlayer par1EntityPlayer, int slotIndex) {
|
||||
ItemStack transferredStack = null;
|
||||
Slot slot = (Slot) inventorySlots.get(slotIndex);
|
||||
|
||||
if (slot != null && slot.getHasStack()) {
|
||||
ItemStack stack = slot.getStack();
|
||||
transferredStack = stack.copy();
|
||||
|
||||
if (!doMergeStackAreas(slotIndex, stack)) return null;
|
||||
|
||||
if (stack.stackSize == 0) slot.putStack(null);
|
||||
else slot.onSlotChanged();
|
||||
}
|
||||
|
||||
return transferredStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mergeItemStack(ItemStack stack, int startIndex, int endIndex, boolean reverse) {
|
||||
boolean merged = false;
|
||||
int slotIndex = reverse ? endIndex - 1 : startIndex;
|
||||
|
||||
if (stack == null) return false;
|
||||
|
||||
if (stack.isStackable()) // search for stacks to increase
|
||||
{
|
||||
while (stack.stackSize > 0 && (reverse ? slotIndex >= startIndex : slotIndex < endIndex)) {
|
||||
Slot slot = (Slot) inventorySlots.get(slotIndex);
|
||||
ItemStack slotStack = slot.getStack();
|
||||
|
||||
if (slotStack != null && slotStack.getItem() == stack.getItem()
|
||||
&& (!stack.getHasSubtypes() || stack.getItemDamage() == slotStack.getItemDamage())
|
||||
&& ItemStack.areItemStackTagsEqual(stack, slotStack)) {
|
||||
int totalStackSize = slotStack.stackSize + stack.stackSize;
|
||||
int maxStackSize = Math.min(stack.getMaxStackSize(), slot.getSlotStackLimit());
|
||||
if (totalStackSize <= maxStackSize) {
|
||||
stack.stackSize = 0;
|
||||
slotStack.stackSize = totalStackSize;
|
||||
slot.onSlotChanged();
|
||||
merged = true;
|
||||
} else if (slotStack.stackSize < maxStackSize) {
|
||||
stack.stackSize -= maxStackSize - slotStack.stackSize;
|
||||
slotStack.stackSize = maxStackSize;
|
||||
slot.onSlotChanged();
|
||||
merged = true;
|
||||
}
|
||||
}
|
||||
|
||||
slotIndex += reverse ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (stack.stackSize > 0) // normal transfer :)
|
||||
{
|
||||
slotIndex = reverse ? endIndex - 1 : startIndex;
|
||||
|
||||
while (stack.stackSize > 0 && (reverse ? slotIndex >= startIndex : slotIndex < endIndex)) {
|
||||
Slot slot = (Slot) this.inventorySlots.get(slotIndex);
|
||||
|
||||
if (!slot.getHasStack() && slot.isItemValid(stack)) {
|
||||
int maxStackSize = Math.min(stack.getMaxStackSize(), slot.getSlotStackLimit());
|
||||
if (stack.stackSize <= maxStackSize) {
|
||||
slot.putStack(stack.copy());
|
||||
slot.onSlotChanged();
|
||||
stack.stackSize = 0;
|
||||
merged = true;
|
||||
} else {
|
||||
slot.putStack(stack.splitStack(maxStackSize));
|
||||
slot.onSlotChanged();
|
||||
merged = true;
|
||||
}
|
||||
}
|
||||
|
||||
slotIndex += reverse ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when slotIndex is shift clicked on. Recommended implementation is to call mergeItemStack based on
|
||||
* slotIndex
|
||||
*
|
||||
* @param stack The stack in the clicked slot
|
||||
* @return True if one or more items were moved from this slots into other slots
|
||||
*/
|
||||
public boolean doMergeStackAreas(int slotIndex, ItemStack stack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void bindPlayerInventory(InventoryPlayer inventoryPlayer) {
|
||||
bindPlayerInventory(inventoryPlayer, 8, 84);
|
||||
}
|
||||
|
||||
protected void bindPlayerInventory(InventoryPlayer inventoryPlayer, int x, int y) {
|
||||
for (int row = 0; row < 3; row++) for (int col = 0; col < 9; col++)
|
||||
addSlotToContainer(new Slot(inventoryPlayer, col + row * 9 + 9, x + col * 18, y + row * 18));
|
||||
for (int slot = 0; slot < 9; slot++) addSlotToContainer(new Slot(inventoryPlayer, slot, x + slot * 18, y + 58));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInteractWith(EntityPlayer var1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void sendContainerPacket(PacketCustom packet) {
|
||||
for (EntityPlayerMP player : playerCrafters) packet.sendToPlayer(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type An identifying number for the packet type between 2 and 0x79 inclusive. 1 is reserved for
|
||||
* synchronising networkIDs
|
||||
* @return A packet on the CCL inventory channel that will be recieved by this container on the other network side
|
||||
*/
|
||||
public PacketCustom getPacket(int type) {
|
||||
if (netID == 0)
|
||||
LogManager.getLogger("CodeChickenLib").error("Tried to get packet for container with 0 network ID");
|
||||
if (type == 1) throw new IllegalArgumentException(
|
||||
"Packet type 1 is reserved for network synchronisation in ContainerExtended");
|
||||
|
||||
return new PacketCustom(netChannel, type).writeInt(netID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a packet from the server obtained by getPacket.
|
||||
*/
|
||||
public void handleClientPacket(PacketCustom packet) {}
|
||||
|
||||
/**
|
||||
* Handle a packet from the client obtained by getPacket.
|
||||
*/
|
||||
public void handleServerPacket(PacketCustom packet) {}
|
||||
|
||||
public void sendProgressBarUpdate(int barID, int value) {
|
||||
for (ICrafting crafting : (List<ICrafting>) crafters) crafting.sendProgressBarUpdate(this, barID, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package codechicken.lib.inventory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.lib.packet.PacketCustom;
|
||||
|
||||
public abstract class ContainerSynchronised extends ContainerExtended {
|
||||
|
||||
private ArrayList<IContainerSyncVar> syncVars = new ArrayList<IContainerSyncVar>();
|
||||
|
||||
/**
|
||||
* Create a packet to be used to send a synced variable update. Calls getPacket. Can be overriden to add extra
|
||||
* identifying data or change the type (default 2)
|
||||
*/
|
||||
public PacketCustom createSyncPacket() {
|
||||
return getPacket(2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void detectAndSendChanges() {
|
||||
super.detectAndSendChanges();
|
||||
|
||||
for (int i = 0; i < syncVars.size(); i++) {
|
||||
IContainerSyncVar var = syncVars.get(i);
|
||||
if (var.changed()) {
|
||||
PacketCustom packet = createSyncPacket();
|
||||
packet.writeByte(i);
|
||||
var.writeChange(packet);
|
||||
sendContainerPacket(packet);
|
||||
var.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendContainerAndContentsToPlayer(Container container, List<ItemStack> list,
|
||||
List<EntityPlayerMP> playerCrafters) {
|
||||
super.sendContainerAndContentsToPlayer(container, list, playerCrafters);
|
||||
for (int i = 0; i < syncVars.size(); i++) {
|
||||
IContainerSyncVar var = syncVars.get(i);
|
||||
PacketCustom packet = createSyncPacket();
|
||||
packet.writeByte(i);
|
||||
var.writeChange(packet);
|
||||
var.reset();
|
||||
for (EntityPlayerMP player : playerCrafters) packet.sendToPlayer(player);
|
||||
}
|
||||
}
|
||||
|
||||
public void addSyncVar(IContainerSyncVar var) {
|
||||
syncVars.add(var);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleClientPacket(PacketCustom packet) {
|
||||
syncVars.get(packet.readUByte()).readChange(packet);
|
||||
}
|
||||
|
||||
public List<IContainerSyncVar> getSyncedVars() {
|
||||
return Collections.unmodifiableList(syncVars);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package codechicken.lib.inventory;
|
||||
|
||||
import codechicken.lib.packet.PacketCustom;
|
||||
|
||||
public interface IContainerSyncVar {
|
||||
|
||||
public boolean changed();
|
||||
|
||||
public void reset();
|
||||
|
||||
public void writeChange(PacketCustom packet);
|
||||
|
||||
public void readChange(PacketCustom packet);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package codechicken.lib.inventory;
|
||||
|
||||
import codechicken.lib.packet.PacketCustom;
|
||||
|
||||
public abstract class IntegerSync implements IContainerSyncVar {
|
||||
|
||||
public int c_value;
|
||||
|
||||
@Override
|
||||
public boolean changed() {
|
||||
return getValue() != c_value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
c_value = getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeChange(PacketCustom packet) {
|
||||
packet.writeInt(getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readChange(PacketCustom packet) {
|
||||
c_value = packet.readInt();
|
||||
}
|
||||
|
||||
public abstract int getValue();
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package codechicken.lib.inventory;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
/**
|
||||
* Creates a copy of an IInventory for extended simulation
|
||||
*/
|
||||
public class InventoryCopy implements IInventory {
|
||||
|
||||
public boolean[] accessible;
|
||||
public ItemStack[] items;
|
||||
public IInventory inv;
|
||||
|
||||
public InventoryCopy(IInventory inv) {
|
||||
items = new ItemStack[inv.getSizeInventory()];
|
||||
accessible = new boolean[inv.getSizeInventory()];
|
||||
this.inv = inv;
|
||||
update();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
ItemStack stack = inv.getStackInSlot(i);
|
||||
if (stack != null) items[i] = stack.copy();
|
||||
}
|
||||
}
|
||||
|
||||
public InventoryCopy open(InventoryRange access) {
|
||||
int lslot = access.lastSlot();
|
||||
if (lslot > accessible.length) {
|
||||
boolean[] l_accessible = new boolean[lslot];
|
||||
ItemStack[] l_items = new ItemStack[lslot];
|
||||
System.arraycopy(accessible, 0, l_accessible, 0, accessible.length);
|
||||
System.arraycopy(items, 0, l_items, 0, items.length);
|
||||
accessible = l_accessible;
|
||||
items = l_items;
|
||||
}
|
||||
|
||||
for (int slot : access.slots) accessible[slot] = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSizeInventory() {
|
||||
return items.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackInSlot(int slot) {
|
||||
return items[slot];
|
||||
}
|
||||
|
||||
public ItemStack decrStackSize(int slot, int amount) {
|
||||
return InventoryUtils.decrStackSize(this, slot, amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackInSlotOnClosing(int slot) {
|
||||
return InventoryUtils.getStackInSlotOnClosing(this, slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInventorySlotContents(int slot, ItemStack stack) {
|
||||
items[slot] = stack;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInventoryName() {
|
||||
return "copy";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseableByPlayer(EntityPlayer player) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory() {}
|
||||
|
||||
@Override
|
||||
public void closeInventory() {}
|
||||
|
||||
@Override
|
||||
public int getInventoryStackLimit() {
|
||||
return 64;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDirty() {}
|
||||
|
||||
@Override
|
||||
public boolean isItemValidForSlot(int i, ItemStack itemstack) {
|
||||
return inv.isItemValidForSlot(i, itemstack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomInventoryName() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package codechicken.lib.inventory;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
/**
|
||||
* IInventory implementation which saves and loads from an NBT tag
|
||||
*/
|
||||
public class InventoryNBT implements IInventory {
|
||||
|
||||
protected ItemStack[] items;
|
||||
protected NBTTagCompound tag;
|
||||
|
||||
public InventoryNBT(int size, NBTTagCompound tag) {
|
||||
this.tag = tag;
|
||||
items = new ItemStack[size];
|
||||
readNBT();
|
||||
}
|
||||
|
||||
private void writeNBT() {
|
||||
tag.setTag("items", InventoryUtils.writeItemStacksToTag(items, getInventoryStackLimit()));
|
||||
}
|
||||
|
||||
private void readNBT() {
|
||||
if (tag.hasKey("items")) InventoryUtils.readItemStacksFromTag(items, tag.getTagList("items", 10));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSizeInventory() {
|
||||
return items.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackInSlot(int slot) {
|
||||
return items[slot];
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack decrStackSize(int slot, int amount) {
|
||||
return InventoryUtils.decrStackSize(this, slot, amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackInSlotOnClosing(int slot) {
|
||||
return InventoryUtils.getStackInSlotOnClosing(this, slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInventorySlotContents(int slot, ItemStack stack) {
|
||||
items[slot] = stack;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInventoryName() {
|
||||
return "NBT";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInventoryStackLimit() {
|
||||
return 64;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDirty() {
|
||||
writeNBT();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseableByPlayer(EntityPlayer var1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory() {}
|
||||
|
||||
@Override
|
||||
public void closeInventory() {}
|
||||
|
||||
@Override
|
||||
public boolean isItemValidForSlot(int i, ItemStack itemstack) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomInventoryName() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package codechicken.lib.inventory;
|
||||
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.ISidedInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
/**
|
||||
* Inventory wrapper for unified ISided/IInventory access
|
||||
*/
|
||||
public class InventoryRange {
|
||||
|
||||
public IInventory inv;
|
||||
public int side;
|
||||
public ISidedInventory sidedInv;
|
||||
public int[] slots;
|
||||
|
||||
public InventoryRange(IInventory inv, int side) {
|
||||
this.inv = inv;
|
||||
this.side = side;
|
||||
if (inv instanceof ISidedInventory) {
|
||||
sidedInv = (ISidedInventory) inv;
|
||||
slots = sidedInv.getAccessibleSlotsFromSide(side);
|
||||
} else {
|
||||
slots = new int[inv.getSizeInventory()];
|
||||
for (int i = 0; i < slots.length; i++) slots[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
public InventoryRange(IInventory inv) {
|
||||
this(inv, 0);
|
||||
}
|
||||
|
||||
public InventoryRange(IInventory inv, int fslot, int size) {
|
||||
this.inv = inv;
|
||||
slots = new int[size];
|
||||
for (int i = 0; i < slots.length; i++) slots[i] = fslot + i;
|
||||
}
|
||||
|
||||
public InventoryRange(IInventory inv, InventoryRange access) {
|
||||
this.inv = inv;
|
||||
this.slots = access.slots;
|
||||
this.side = access.side;
|
||||
if (inv instanceof ISidedInventory) sidedInv = (ISidedInventory) inv;
|
||||
}
|
||||
|
||||
public boolean canInsertItem(int slot, ItemStack item) {
|
||||
return sidedInv == null ? inv.isItemValidForSlot(slot, item) : sidedInv.canInsertItem(slot, item, side);
|
||||
}
|
||||
|
||||
public boolean canExtractItem(int slot, ItemStack item) {
|
||||
return sidedInv == null ? inv.isItemValidForSlot(slot, item) : sidedInv.canExtractItem(slot, item, side);
|
||||
}
|
||||
|
||||
public int lastSlot() {
|
||||
int last = 0;
|
||||
for (int slot : slots) if (slot > last) last = slot;
|
||||
return last;
|
||||
}
|
||||
}
|
||||
Loaded 100 of 190 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user