mirror of
https://github.com/GTNewHorizons/CodeChickenCore.git
synced 2026-11-15 17:44:42 +00:00
Initial commit
This commit is contained in:
commit
0d94e9ac7f
78 files changed
+7045
No files matched your search
@@ -0,0 +1,2 @@
|
||||
/build/build
|
||||
/build/.gradle
|
||||
@@ -0,0 +1,173 @@
|
||||
// This sets us up for building a forge project - you need all of these
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
name = "forge"
|
||||
url = "http://files.minecraftforge.net/maven"
|
||||
}
|
||||
maven {
|
||||
name = "sonatype"
|
||||
url = "https://oss.sonatype.org/content/repositories/snapshots/"
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT'
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the forge plugin - this adds all the magic for automatically obfuscating, deobfuscating etc
|
||||
apply plugin: 'forge'
|
||||
|
||||
// This is our group
|
||||
group = "codechicken" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||
// This is our actual project within the group.
|
||||
archivesBaseName = "CodeChickenCore"
|
||||
|
||||
// Define properties file
|
||||
ext.configFile = file "build.properties"
|
||||
|
||||
configFile.withReader {
|
||||
// Load config. It shall from now be referenced as simply config or project.config
|
||||
def prop = new Properties()
|
||||
prop.load(it)
|
||||
project.ext.config = new ConfigSlurper().parse prop
|
||||
}
|
||||
dependencies {
|
||||
compile "codechicken:CodeChickenLib:${config.mc_version}-${config.ccl_version}:dev"
|
||||
}
|
||||
|
||||
version = "${project.config.mod_version}." + System.getenv("BUILD_NUMBER") ?: "1"
|
||||
|
||||
println config.mc_version + "-" + config.forge_version
|
||||
// Setup the forge minecraft plugin data. Specify the preferred forge/minecraft version here
|
||||
minecraft {
|
||||
version = config.mc_version + "-" + config.forge_version
|
||||
}
|
||||
|
||||
// this sets our output jar to have a 'tag' of 'universal' on it
|
||||
// It also adds the minecraft version in a custom version name
|
||||
// The result is files named <projectname>-<mcversion>-<version>-universal.jar
|
||||
jar {
|
||||
classifier = 'universal'
|
||||
version = "${project.minecraft.version}-${project.version}"
|
||||
manifest {
|
||||
attributes 'FMLCorePlugin': 'codechicken.core.launch.CodeChickenCorePlugin'
|
||||
}
|
||||
|
||||
}
|
||||
sourceSets {
|
||||
main {
|
||||
def root = project.projectDir.parentFile
|
||||
java {
|
||||
srcDir new File(root, "src")
|
||||
}
|
||||
resources {
|
||||
srcDir new File(root, "resources")
|
||||
}
|
||||
}
|
||||
}
|
||||
processResources {
|
||||
//redo task if any of these properties change
|
||||
inputs.property "version", project.version
|
||||
inputs.property "mc_version", config.mc_version
|
||||
inputs.property "ccl_version", config.ccl_version
|
||||
|
||||
// Replace properties in info files
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
include '*.info'
|
||||
expand 'version':project.version,'mc_version':config.mc_version,'ccl_version':config.ccl_version
|
||||
}
|
||||
// Copy everything else
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
include 'assets/**/*.*'
|
||||
}
|
||||
}
|
||||
|
||||
// Add in a source jar for people, should they desire to download such a thing
|
||||
task sourceJar(type: Jar) {
|
||||
from sourceSets.main.allSource
|
||||
classifier = 'src'
|
||||
version = "${project.minecraft.version}-${project.version}"
|
||||
}
|
||||
|
||||
// Add in an mcp named jar, for those who wish to run in a development environment (assuming mcp naming matches)
|
||||
task deobfJar(type: Jar) {
|
||||
from sourceSets.main.output
|
||||
classifier = 'dev'
|
||||
version = "${project.minecraft.version}-${project.version}"
|
||||
manifest {
|
||||
attributes 'FMLCorePlugin': 'codechicken.core.launch.CodeChickenCorePlugin'
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the artifact system about our extra jars
|
||||
artifacts {
|
||||
archives sourceJar, deobfJar
|
||||
}
|
||||
|
||||
// Configure an upload task. this is setup for uploading to files.minecraftforge.net. There are other examples around
|
||||
uploadArchives {
|
||||
dependsOn 'reobf'
|
||||
repositories {
|
||||
if (project.hasProperty("filesmaven")) {
|
||||
logger.info('Publishing to files server')
|
||||
|
||||
mavenDeployer {
|
||||
configuration = configurations.deployJars
|
||||
|
||||
repository(url: project.filesmaven.url) {
|
||||
authentication(userName: project.filesmaven.username, privateKey: project.filesmaven.key)
|
||||
}
|
||||
|
||||
// This is just the pom data for the maven repo
|
||||
pom {
|
||||
groupId = project.group
|
||||
// Force the maven upload to use the <mcversion>-<version> syntax preferred at files
|
||||
version = "${project.minecraft.version}-${project.version}"
|
||||
artifactId = project.archivesBaseName
|
||||
project {
|
||||
name project.archivesBaseName
|
||||
packaging 'jar'
|
||||
description 'CodeChickenCore'
|
||||
url 'https://github.com/Chicken-Bones/CodeChickenCore'
|
||||
|
||||
scm {
|
||||
url 'https://github.com/Chicken-Bones/CodeChickenCore'
|
||||
connection 'scm:git:git://github.com/Chicken-Bones/CodeChickenCore.git'
|
||||
developerConnection 'scm:git:[email protected]:Chicken-Bones/CodeChickenCore.git'
|
||||
}
|
||||
|
||||
issueManagement {
|
||||
system 'github'
|
||||
url 'https://github.com/Chicken-Bones/CodeChickenCore/issues'
|
||||
}
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name 'GNU Lesser Public License (GPL), Version 2.1'
|
||||
url 'https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt'
|
||||
distribution 'repo'
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id 'chicken-bones'
|
||||
name 'chicken-bones'
|
||||
roles { role 'developer' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.info('Publishing to repo folder')
|
||||
|
||||
mavenDeployer {
|
||||
pom.version = "${project.minecraft.version}-${project.version}"
|
||||
repository(url: 'file://localhost/' + project.file('repo').getAbsolutePath())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
mc_version=1.7.2
|
||||
forge_version=10.12.0.1054
|
||||
ccl_version=1.1.0.74
|
||||
mod_version=1.0
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,6 @@
|
||||
#Wed Mar 26 13:33:58 CDT 2014
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-bin.zip
|
||||
Vendored
+164
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# 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
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
|
||||
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"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
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.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "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, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
# 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" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
Vendored
+90
@@ -0,0 +1,90 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@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=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
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.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
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.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
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%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="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
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* This settings file was auto generated by the Gradle buildInit task
|
||||
* by 'sunstrike' at '21/11/13 14:14' with Gradle 1.9
|
||||
*
|
||||
* The settings file is used to specify which projects to include in your build.
|
||||
* In a single project build this file can be empty or even removed.
|
||||
*
|
||||
* Detailed information about configuring a multi-project build in Gradle can be found
|
||||
* in the user guide at http://gradle.org/docs/1.9/userguide/multi_project_builds.html
|
||||
*/
|
||||
|
||||
/*
|
||||
// To declare projects as part of a multi-project build use the 'include' method
|
||||
include 'shared'
|
||||
include 'api'
|
||||
include 'services:webservice'
|
||||
*/
|
||||
|
||||
rootProject.name = 'CodeChickenLib'
|
||||
@@ -0,0 +1,40 @@
|
||||
#A bunch of vanilla tweaks
|
||||
|
||||
list d_environmentallyFriendlyCreepers
|
||||
ALOAD 0
|
||||
GETFIELD net/minecraft/entity/monster/EntityCreeper.field_70170_p:Lnet/minecraft/world/World; #worldObj
|
||||
INVOKEVIRTUAL net/minecraft/world/World.func_82736_K()Lnet/minecraft/world/GameRules; #getGameRules
|
||||
LDC "mobGriefing"
|
||||
INVOKEVIRTUAL net/minecraft/world/GameRules.func_82766_b(Ljava/lang/String;)Z #getGameRuleBooleanValue
|
||||
|
||||
list environmentallyFriendlyCreepers
|
||||
ICONST_0
|
||||
|
||||
list softLeafReplace
|
||||
ALOAD 0
|
||||
ALOAD 1
|
||||
ILOAD 2
|
||||
ILOAD 3
|
||||
ILOAD 4
|
||||
INVOKEVIRTUAL net/minecraft/block/Block.isAir(Lnet/minecraft/world/IBlockAccess;III)Z #forge method
|
||||
IRETURN
|
||||
|
||||
list n_doFireTick
|
||||
LDC "doFireTick"
|
||||
INVOKEVIRTUAL net/minecraft/world/GameRules.func_82766_b(Ljava/lang/String;)Z #getGameRuleBooleanValue
|
||||
IFEQ LRET
|
||||
|
||||
list doFireTick
|
||||
ALOAD 1
|
||||
ILOAD 2
|
||||
ILOAD 3
|
||||
ILOAD 4
|
||||
ALOAD 5
|
||||
INVOKESTATIC codechicken/core/featurehack/TweakTransformerHelper.quenchFireTick(Lnet/minecraft/world/World;IIILjava/util/Random;)V
|
||||
LSKIP
|
||||
|
||||
list finiteWater
|
||||
ALOAD 0
|
||||
GETFIELD net/minecraft/block/BlockDynamicLiquid.field_149815_a:I
|
||||
ICONST_2
|
||||
IF_ICMPLT LEND
|
||||
@@ -0,0 +1,11 @@
|
||||
[
|
||||
{
|
||||
"modid": "CodeChickenCore",
|
||||
"name": "CodeChicken Core",
|
||||
"description": "Base common code for all chickenbones mods.",
|
||||
"version": "0",
|
||||
"mcversion": "1.7.2",
|
||||
"url": "http://www.minecraftforum.net/topic/909223",
|
||||
"authors": [ "ChickenBones" ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"repo": "http://files.minecraftforge.net/CodeChickenLib/",
|
||||
"file": "CodeChickenLib-universal-@MCVERSION@-@[email protected]",
|
||||
"dev": "CodeChickenLib-dev-@MCVERSION@-@[email protected]",
|
||||
"class": "codechicken.lib.asm.ASMHelper",
|
||||
"version": "1.0.0.62",
|
||||
"mcversion": "1.6.4",
|
||||
"coreLib": true
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package codechicken.core;
|
||||
|
||||
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 cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.versioning.ComparableVersion;
|
||||
import cpw.mods.fml.relauncher.FMLInjectionData;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.ChatComponentText;
|
||||
|
||||
public class CCUpdateChecker
|
||||
{
|
||||
private static final ArrayList<String> updates = new ArrayList<String>();
|
||||
|
||||
private static class ThreadUpdateCheck extends Thread
|
||||
{
|
||||
private final URL url;
|
||||
private final String mod;
|
||||
private final ComparableVersion version;
|
||||
|
||||
public ThreadUpdateCheck(URL url, String mod, ComparableVersion version)
|
||||
{
|
||||
this.url = url;
|
||||
this.mod = mod;
|
||||
this.version = version;
|
||||
|
||||
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.startsWith("Ret: "))
|
||||
{
|
||||
System.err.println("Failed to check update for "+mod+" returned: "+ret);
|
||||
return;
|
||||
}
|
||||
ComparableVersion newversion = new ComparableVersion(ret.substring(5));
|
||||
if(newversion.compareTo(version) > 0)
|
||||
{
|
||||
addUpdateMessage("Version "+newversion+" of "+mod+" is available");
|
||||
}
|
||||
}
|
||||
catch(SocketTimeoutException ste)
|
||||
{}
|
||||
catch(UnknownHostException uhe)
|
||||
{}
|
||||
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 String mcVersion()
|
||||
{
|
||||
return (String) FMLInjectionData.data()[4];
|
||||
}
|
||||
|
||||
public static void updateCheck(String mod, String version)
|
||||
{
|
||||
try
|
||||
{
|
||||
new ThreadUpdateCheck(
|
||||
new URL("http://www.chickenbones.craftsaddle.org/Files/New_Versions/version.php?"+
|
||||
"version="+mcVersion()+"&"+
|
||||
"file="+mod),
|
||||
mod, new ComparableVersion(version)).start();
|
||||
}
|
||||
catch(MalformedURLException e)
|
||||
{}
|
||||
}
|
||||
|
||||
public static void updateCheck(String mod)
|
||||
{
|
||||
updateCheck(mod, Loader.instance().getIndexedModList().get(mod).getVersion());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package codechicken.core;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
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 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;
|
||||
|
||||
public class ClassDiscoverer
|
||||
{
|
||||
public IStringMatcher matcher;
|
||||
public String[] superclasses;
|
||||
public ArrayList<Class<?>> classes;
|
||||
public ModClassLoader modClassLoader;
|
||||
|
||||
public ClassDiscoverer(IStringMatcher matcher, Class<?>... superclasses) {
|
||||
this.matcher = matcher;
|
||||
this.superclasses = new String[superclasses.length];
|
||||
for (int i = 0; i < superclasses.length; i++)
|
||||
this.superclasses[i] = superclasses[i].getName().replace('.', '/');
|
||||
|
||||
classes = new ArrayList<Class<?>>();
|
||||
modClassLoader = (ModClassLoader) Loader.instance().getModClassLoader();
|
||||
}
|
||||
|
||||
public ClassDiscoverer(Class<?>... superclasses) {
|
||||
this(new IStringMatcher()
|
||||
{
|
||||
public boolean matches(String test) {return true;}
|
||||
}, superclasses);
|
||||
}
|
||||
|
||||
public ArrayList<Class<?>> findClasses() {
|
||||
try {
|
||||
findClasspathMods();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
private void checkAddClass(String resource) {
|
||||
try {
|
||||
String classname = resource.replace(".class", "").replace("\\", ".").replace("/", ".");
|
||||
byte[] bytes = Launch.classLoader.getClassBytes(classname);
|
||||
if (bytes == null)
|
||||
return;
|
||||
|
||||
ClassNode cnode = ASMHelper.createClassNode(bytes);
|
||||
for (String superclass : superclasses)
|
||||
if (!cnode.interfaces.contains(superclass) && !cnode.superName.equals(superclass))
|
||||
return;
|
||||
|
||||
addClass(classname);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Unable to load class: " + resource);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void addClass(String classname) {
|
||||
try {
|
||||
Class<?> class1 = Class.forName(classname, true, modClassLoader);
|
||||
classes.add(class1);
|
||||
} catch (Exception cnfe) {
|
||||
System.err.println("Unable to load class: " + classname);
|
||||
cnfe.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void findClasspathMods() {
|
||||
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) {
|
||||
if (searchedSources.contains(minecraftSource.getAbsolutePath()))
|
||||
continue;
|
||||
searchedSources.add(minecraftSource.getAbsolutePath());
|
||||
|
||||
if (minecraftSource.isFile()) {
|
||||
if (!knownLibraries.contains(minecraftSource.getName())) {
|
||||
FMLLog.fine("Found a minecraft related file at %s, examining for codechicken classes", minecraftSource.getAbsolutePath());
|
||||
try {
|
||||
readFromZipFile(minecraftSource);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Failed to scan " + minecraftSource.getAbsolutePath() + ", the zip file is invalid");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} else if (minecraftSource.isDirectory()) {
|
||||
FMLLog.fine("Found a minecraft related directory at %s, examining for codechicken classes", minecraftSource.getAbsolutePath());
|
||||
readFromDirectory(minecraftSource, minecraftSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readFromZipFile(File file) throws IOException {
|
||||
FileInputStream fileinputstream = new FileInputStream(file);
|
||||
ZipInputStream zipinputstream = new ZipInputStream(fileinputstream);
|
||||
do {
|
||||
ZipEntry zipentry = zipinputstream.getNextEntry();
|
||||
if (zipentry == null) {
|
||||
break;
|
||||
}
|
||||
String fullname = zipentry.getName().replace('\\', '/');
|
||||
int pos = fullname.lastIndexOf('/');
|
||||
String name = pos == -1 ? fullname : fullname.substring(pos + 1);
|
||||
if (!zipentry.isDirectory() && matcher.matches(name)) {
|
||||
checkAddClass(fullname);
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
fileinputstream.close();
|
||||
}
|
||||
|
||||
private void readFromDirectory(File directory, File basedirectory) {
|
||||
for (File child : directory.listFiles()) {
|
||||
if (child.isDirectory()) {
|
||||
readFromDirectory(child, basedirectory);
|
||||
} else if (child.isFile() && matcher.matches(child.getName())) {
|
||||
String fullname = CommonUtils.getRelativePath(basedirectory, child);
|
||||
checkAddClass(fullname);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package codechicken.core;
|
||||
|
||||
import codechicken.core.internal.CCCEventHandler;
|
||||
|
||||
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;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class ClientUtils extends CommonUtils
|
||||
{
|
||||
private static Minecraft mc() {
|
||||
return Minecraft.getMinecraft();
|
||||
}
|
||||
|
||||
public static World getWorld() {
|
||||
return mc().theWorld;
|
||||
}
|
||||
|
||||
public static boolean inWorld()//TODO unused
|
||||
{
|
||||
return mc().getNetHandler() != null;
|
||||
}
|
||||
|
||||
public static void openSMPGui(int windowId, GuiScreen gui) {
|
||||
mc().displayGuiScreen(gui);
|
||||
if (windowId != 0)
|
||||
mc().thePlayer.openContainer.windowId = windowId;
|
||||
}
|
||||
|
||||
public static float getRenderFrame() {
|
||||
return CCCEventHandler.renderFrame;
|
||||
}
|
||||
|
||||
public static double getRenderTime() {
|
||||
return CCCEventHandler.renderTime + getRenderFrame();
|
||||
}
|
||||
|
||||
public static String getServerIP() {
|
||||
try {
|
||||
NetworkManager networkManager = mc().getNetHandler().getNetworkManager();
|
||||
String s = networkManager.getSocketAddress().toString();
|
||||
s = s.substring(s.indexOf("/") + 1);
|
||||
return s;
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static String getWorldSaveName() {
|
||||
return mc().isSingleplayer() ? MinecraftServer.getServer().getFolderName() : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package codechicken.core;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ChatAllowedCharacters;
|
||||
import net.minecraft.util.ChatComponentText;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
|
||||
public class CommonUtils
|
||||
{
|
||||
public static boolean isClient() {
|
||||
return FMLCommonHandler.instance().getSide().isClient();
|
||||
}
|
||||
|
||||
public static File getSaveLocation(int dim) {
|
||||
File basesave = DimensionManager.getCurrentSaveRootDirectory();
|
||||
if (dim != 0)
|
||||
return new File(basesave, DimensionManager.getWorld(dim).provider.getSaveFolder());
|
||||
|
||||
return basesave;
|
||||
}
|
||||
|
||||
public static String getWorldName(World world) {
|
||||
return world.getWorldInfo().getWorldName();
|
||||
}
|
||||
|
||||
public static int getDimension(World world) {
|
||||
return world.provider.dimensionId;
|
||||
}
|
||||
|
||||
public static File getModsFolder() {
|
||||
return new File(getMinecraftDir(), "mods");
|
||||
}
|
||||
|
||||
public static File getMinecraftDir() {
|
||||
return Minecraft.getMinecraft().mcDataDir;
|
||||
}
|
||||
|
||||
public static String getRelativePath(File parent, File child) {
|
||||
if (parent.isFile() || !child.getPath().startsWith(parent.getPath()))
|
||||
return null;
|
||||
|
||||
return child.getPath().substring(parent.getPath().length() + 1);
|
||||
}
|
||||
|
||||
public static ModContainer findModContainer(String modID) {
|
||||
for (ModContainer mc : Loader.instance().getModList())
|
||||
if (modID.equals(mc.getModId()))
|
||||
return mc;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package codechicken.core;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
|
||||
public interface IGuiPacketSender
|
||||
{
|
||||
void sendPacket(EntityPlayerMP player, int windowId);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package codechicken.core;
|
||||
|
||||
public interface IStringMatcher
|
||||
{
|
||||
public boolean matches(String test);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package codechicken.core;
|
||||
|
||||
public class ProfileTimer
|
||||
{
|
||||
public double decay;
|
||||
public long startTime;
|
||||
public long nanoTime;
|
||||
public int scanCount;
|
||||
public int logScans;
|
||||
public String logName;
|
||||
|
||||
public ProfileTimer() {
|
||||
this(0.98);
|
||||
}
|
||||
|
||||
public ProfileTimer(double decay) {
|
||||
this.decay = decay;
|
||||
}
|
||||
|
||||
public ProfileTimer log(String logName, int scans) {
|
||||
this.logScans = scans;
|
||||
this.logName = logName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
startTime = System.nanoTime();
|
||||
}
|
||||
|
||||
public void end() {
|
||||
long t = System.nanoTime()-startTime;
|
||||
nanoTime = (long)(nanoTime*decay+t*(1-decay));
|
||||
|
||||
scanCount++;
|
||||
if(logScans > 0 && scanCount % logScans == 0)
|
||||
System.out.println("Profiled " + logName + " " + nanoTime + "ns");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package codechicken.core;
|
||||
|
||||
public class ReentrantCheck
|
||||
{
|
||||
private boolean entered;
|
||||
|
||||
public ReentrantCheck()
|
||||
{
|
||||
entered = false;
|
||||
}
|
||||
|
||||
public boolean entered()
|
||||
{
|
||||
return entered;
|
||||
}
|
||||
|
||||
public void enter()
|
||||
{
|
||||
entered = true;
|
||||
}
|
||||
|
||||
public void exit()
|
||||
{
|
||||
entered = false;
|
||||
}
|
||||
|
||||
public static ThreadLocal<ReentrantCheck> threadLocal()
|
||||
{
|
||||
return new ThreadLocal<ReentrantCheck>()
|
||||
{
|
||||
@Override
|
||||
protected ReentrantCheck initialValue()
|
||||
{
|
||||
return new ReentrantCheck();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
package codechicken.core;
|
||||
|
||||
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
|
||||
{
|
||||
primitiveWrappers.put(Integer.TYPE, Integer.class);
|
||||
primitiveWrappers.put(Short.TYPE, Short.class);
|
||||
primitiveWrappers.put(Byte.TYPE, Byte.class);
|
||||
primitiveWrappers.put(Long.TYPE, Long.class);
|
||||
primitiveWrappers.put(Double.TYPE, Double.class);
|
||||
primitiveWrappers.put(Float.TYPE, Float.class);
|
||||
primitiveWrappers.put(Boolean.TYPE, Boolean.class);
|
||||
primitiveWrappers.put(Character.TYPE, Character.class);
|
||||
}
|
||||
|
||||
public static boolean isInstance(Class<?> class1, Object obj)
|
||||
{
|
||||
Class<?> primitive = primitiveWrappers.get(class1);
|
||||
if(primitive != null)
|
||||
{
|
||||
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;
|
||||
|
||||
if(primitive == Double.class && Double.class.isInstance(obj))
|
||||
return true;
|
||||
if((primitive == Double.class || primitive == Float.class) && Float.class.isInstance(obj))
|
||||
return true;
|
||||
|
||||
return primitive.isInstance(obj);
|
||||
}
|
||||
return class1.isInstance(obj);
|
||||
}
|
||||
|
||||
public static Class<?> findClass(String name)
|
||||
{
|
||||
return findClass(name, true);
|
||||
}
|
||||
|
||||
public static boolean classExists(String name)
|
||||
{
|
||||
return findClass(name, false) != null;
|
||||
}
|
||||
|
||||
public static Class<?> findClass(String name, boolean init)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Class.forName(name, init, ReflectionManager.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException cnfe)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Class.forName("net.minecraft.src."+name, init, ReflectionManager.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException cnfe2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setField(Class<?> class1, Object instance, String name, Object value) throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
setField(class1, instance, new String[]{name}, value);
|
||||
}
|
||||
|
||||
public static void setField(Class<?> class1, Object instance, String[] names, Object value) throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
for(Field field : class1.getDeclaredFields())
|
||||
{
|
||||
boolean match = false;
|
||||
for(String name : names)
|
||||
{
|
||||
if(field.getName().equals(name))
|
||||
{
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!match)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
field.setAccessible(true);
|
||||
field.set(instance, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public static void setField(Class<?> class1, Object instance, int fieldindex, Object value) throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
Field field = class1.getDeclaredFields()[fieldindex];
|
||||
field.setAccessible(true);
|
||||
field.set(instance, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function
|
||||
* void return type
|
||||
* single name
|
||||
*/
|
||||
public static void callMethod(Class<?> class1, String[] names, Object... params) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException
|
||||
{
|
||||
callMethod(class1, null, names, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* void return type
|
||||
*/
|
||||
public static void callMethod(Class<?> class1, Object instance, String[] names, Object... params) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException
|
||||
{
|
||||
callMethod(class1, null, instance, names, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method
|
||||
*/
|
||||
public static <R> R callMethod(Class<?> class1, Class<R> returntype, String[] names, Object... params) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException
|
||||
{
|
||||
return callMethod(class1, returntype, null, names, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* sinlge name
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!match)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Class<?>[] paramtypes = method.getParameterTypes();
|
||||
if(paramtypes.length != params.length)
|
||||
continue;
|
||||
|
||||
for(int i = 0; i < params.length; i++)
|
||||
{
|
||||
if(!isInstance(paramtypes[i], params[i]))
|
||||
continue nextMethod;
|
||||
}
|
||||
|
||||
method.setAccessible(true);
|
||||
return (R)method.invoke(instance, params);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T> T getField(Class<?> class1, Class<T> fieldType, Object instance, int fieldIndex) throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
Field field = class1.getDeclaredFields()[fieldIndex];
|
||||
field.setAccessible(true);
|
||||
return (T) field.get(instance);
|
||||
}
|
||||
|
||||
public static <T> T getField(Class<?> class1, Class<T> fieldType, Object instance, String fieldName)
|
||||
{
|
||||
try
|
||||
{
|
||||
Field field = class1.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return (T) field.get(instance);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T newInstance(Class<T> class1, Object... params) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException
|
||||
{
|
||||
nextMethod: for(Constructor<?> constructor : class1.getDeclaredConstructors())
|
||||
{
|
||||
Class<?>[] paramtypes = constructor.getParameterTypes();
|
||||
if(paramtypes.length != params.length)
|
||||
continue;
|
||||
|
||||
for(int i = 0; i < params.length; i++)
|
||||
{
|
||||
if(!isInstance(paramtypes[i], params[i]))
|
||||
continue nextMethod;
|
||||
}
|
||||
|
||||
constructor.setAccessible(true);
|
||||
return (T)constructor.newInstance(params);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean hasField(Class<?> class1, String fieldName)
|
||||
{
|
||||
try
|
||||
{
|
||||
class1.getDeclaredField(fieldName);
|
||||
return true;
|
||||
}
|
||||
catch(NoSuchFieldException nfe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T get(Field field, Class<T> class1)
|
||||
{
|
||||
return get(field, class1, null);
|
||||
}
|
||||
|
||||
public static <T> T get(Field field, Class<T> class1, Object instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (T)field.get(instance);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void set(Field field, Object value)
|
||||
{
|
||||
set(field, null, value);
|
||||
}
|
||||
|
||||
public static void set(Field field, Object instance, Object value)
|
||||
{
|
||||
try
|
||||
{
|
||||
field.set(instance, value);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Field getField(ObfMapping mapping)
|
||||
{
|
||||
mapping.toRuntime();
|
||||
|
||||
try
|
||||
{
|
||||
Class<?> clazz = ReflectionManager.class.getClassLoader().loadClass(mapping.javaClass());
|
||||
Field field = clazz.getDeclaredField(mapping.s_name);
|
||||
field.setAccessible(true);
|
||||
return field;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package codechicken.core;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityList;
|
||||
|
||||
public class RegistrationHelper
|
||||
{
|
||||
public static void registerHandledEntity(Class<? extends Entity> entityClass, String identifier)
|
||||
{
|
||||
EntityList.classToStringMapping.put(entityClass, identifier);
|
||||
EntityList.stringToClassMapping.put(identifier, entityClass);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package codechicken.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.command.CommandHandler;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.command.ICommand;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
|
||||
public class ServerUtils extends CommonUtils
|
||||
{
|
||||
public static MinecraftServer mc() {
|
||||
return MinecraftServer.getServer();
|
||||
}
|
||||
|
||||
public static EntityPlayerMP getPlayer(String playername) {
|
||||
return mc().getConfigurationManager().getPlayerForUsername(playername);
|
||||
}
|
||||
|
||||
public static List<EntityPlayerMP> getPlayers() {
|
||||
return mc().getConfigurationManager().playerEntityList;
|
||||
}
|
||||
|
||||
public static ArrayList<EntityPlayer> getPlayersInDimension(int dimension) {
|
||||
ArrayList<EntityPlayer> players = new ArrayList<EntityPlayer>();
|
||||
for (EntityPlayer p : getPlayers())
|
||||
if(p.dimension == dimension)
|
||||
players.add(p);
|
||||
|
||||
return players;
|
||||
}
|
||||
|
||||
public static void openSMPContainer(EntityPlayerMP player, Container container, IGuiPacketSender packetSender) {
|
||||
player.getNextWindowId();
|
||||
player.closeContainer();
|
||||
packetSender.sendPacket(player, player.currentWindowId);
|
||||
player.openContainer = container;
|
||||
player.openContainer.windowId = player.currentWindowId;
|
||||
player.openContainer.addCraftingToCrafters(player);
|
||||
}
|
||||
|
||||
public static boolean isPlayerOP(String username) {
|
||||
return mc().getConfigurationManager().isPlayerOpped(username);
|
||||
}
|
||||
|
||||
public static boolean isPlayerOwner(String username) {
|
||||
return mc().isSinglePlayer() && mc().getServerOwner().equalsIgnoreCase(username);
|
||||
}
|
||||
|
||||
public static void registerCommand(ICommand command) {
|
||||
((CommandHandler) mc().getCommandManager()).registerCommand(command);
|
||||
}
|
||||
|
||||
public static void sendChatToAll(IChatComponent msg) {
|
||||
for(EntityPlayer p : getPlayers())
|
||||
p.addChatComponentMessage(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package codechicken.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
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;
|
||||
|
||||
public ProfilerResult(String name, long time, long totalTime)
|
||||
{
|
||||
this.name = name;
|
||||
this.time = time;
|
||||
fraction = time/(double)totalTime;
|
||||
}
|
||||
}
|
||||
|
||||
public HashMap<String, Long> times = new HashMap<String, Long>();
|
||||
|
||||
public String currentSection;
|
||||
private long startTime;
|
||||
private long totalTime;
|
||||
|
||||
public void start(String section)
|
||||
{
|
||||
if(currentSection != null)
|
||||
end();
|
||||
|
||||
currentSection = section;
|
||||
startTime = System.nanoTime();
|
||||
}
|
||||
|
||||
public void end()
|
||||
{
|
||||
long time = System.nanoTime()-startTime;
|
||||
totalTime+=time;
|
||||
|
||||
Long prev = times.get(currentSection);
|
||||
if(prev == null)
|
||||
prev = 0L;
|
||||
times.put(currentSection, prev+time);
|
||||
currentSection = null;
|
||||
}
|
||||
|
||||
public List<ProfilerResult> getResults()
|
||||
{
|
||||
ArrayList<ProfilerResult> results = new ArrayList<ProfilerResult>(times.size());
|
||||
for(Entry<String, Long> e : times.entrySet())
|
||||
results.add(new ProfilerResult(e.getKey(), e.getValue(), totalTime));
|
||||
return results;
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
if(currentSection != null)
|
||||
end();
|
||||
times.clear();
|
||||
totalTime = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import codechicken.core.launch.CodeChickenCorePlugin;
|
||||
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 CodeChickenAccessTransformer instance;
|
||||
private static List<String> mapFileList = new LinkedList<String>();
|
||||
|
||||
private static boolean makeAllPublic;
|
||||
private static Field f_classNameBiMap;
|
||||
private static Object emptyMap = ImmutableBiMap.of();
|
||||
|
||||
public CodeChickenAccessTransformer() throws IOException
|
||||
{
|
||||
super();
|
||||
instance = this;
|
||||
for(String file : mapFileList)
|
||||
readMapFile(file);
|
||||
mapFileList = null;
|
||||
loadPublicConfig();
|
||||
}
|
||||
|
||||
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.")
|
||||
.getBooleanValue(false);
|
||||
|
||||
if(!makeAllPublic)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
f_classNameBiMap = FMLDeobfuscatingRemapper.class.getDeclaredField("classNameBiMap");
|
||||
f_classNameBiMap.setAccessible(true);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addTransformerMap(String mapFile)
|
||||
{
|
||||
if(instance == null)
|
||||
mapFileList.add(mapFile);
|
||||
else
|
||||
instance.readMapFile(mapFile);
|
||||
}
|
||||
|
||||
private void readMapFile(String mapFile)
|
||||
{
|
||||
CodeChickenCorePlugin.logger.debug("Adding Accesstransformer map: " + mapFile);
|
||||
try
|
||||
{
|
||||
Method parentMapFile = AccessTransformer.class.getDeclaredMethod("readMapFile", String.class);
|
||||
parentMapFile.setAccessible(true);
|
||||
parentMapFile.invoke(this, mapFile);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(String name, String transformedName, byte[] bytes) {
|
||||
boolean setPublic = makeAllPublic && name.startsWith("net.minecraft.");
|
||||
if(setPublic)
|
||||
setClassMap(name);
|
||||
bytes = super.transform(name, transformedName, bytes);
|
||||
if(setPublic)
|
||||
restoreClassMap();
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private void restoreClassMap() {
|
||||
try
|
||||
{
|
||||
f_classNameBiMap.set(FMLDeobfuscatingRemapper.INSTANCE, emptyMap);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setClassMap(String name) {
|
||||
try
|
||||
{
|
||||
f_classNameBiMap.set(FMLDeobfuscatingRemapper.INSTANCE, ImmutableBiMap.of(name.replace('.', '/'), ""));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import codechicken.core.CCUpdateChecker;
|
||||
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.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;
|
||||
|
||||
public class CodeChickenCoreModContainer extends DummyModContainer
|
||||
{
|
||||
public static ConfigFile config;
|
||||
|
||||
public static void loadConfig() {
|
||||
if(config == null)
|
||||
config = new ConfigFile(new File(CodeChickenCorePlugin.minecraftDir, "config/CodeChickenCore.cfg")).setComment("CodeChickenCore configuration file.");
|
||||
}
|
||||
|
||||
public CodeChickenCoreModContainer() {
|
||||
super(MetadataCollection.from(MetadataCollection.class.getResourceAsStream("/cccmod.info"), "CodeChickenCore").getMetadataForId("CodeChickenCore", null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ArtifactVersion> getDependants() {
|
||||
LinkedList<ArtifactVersion> deps = new LinkedList<ArtifactVersion>();
|
||||
deps.add(VersionParser.parseVersionReference("NotEnoughItems@[0,)"));
|
||||
deps.add(VersionParser.parseVersionReference("EnderStorage@[1.4.3.6,)"));
|
||||
deps.add(VersionParser.parseVersionReference("ChickenChunks@[1.3.3.4,)"));
|
||||
deps.add(VersionParser.parseVersionReference("Translocator@[1.1.0.15,)"));
|
||||
deps.add(VersionParser.parseVersionReference("WR-CBE|Core@[1.4.0.7,)"));
|
||||
return deps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerBus(EventBus bus, LoadController controller) {
|
||||
bus.register(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void preInit(FMLPreInitializationEvent event) {
|
||||
if (event.getSide().isClient())
|
||||
LiquidTextures.init();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void init(FMLInitializationEvent event) {
|
||||
if (event.getSide().isClient()) {
|
||||
if (config.getTag("checkUpdates").getBooleanValue(true))
|
||||
CCUpdateChecker.updateCheck(getModId());
|
||||
FMLCommonHandler.instance().bus().register(new CCCEventHandler());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VersionRange acceptableMinecraftVersionRange() {
|
||||
return VersionParser.parseRange(CodeChickenCorePlugin.mcVersion);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
|
||||
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;
|
||||
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
|
||||
public class DefaultImplementationTransformer implements IClassTransformer
|
||||
{
|
||||
private static LaunchClassLoader cl = (LaunchClassLoader)ClassHeirachyManager.class.getClassLoader();
|
||||
private static ClassNode getClassNode(String name) {
|
||||
try {
|
||||
return ASMHelper.createClassNode(cl.getClassBytes(name.replace('/', '.')));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static class InterfaceImpl
|
||||
{
|
||||
public final String iname;
|
||||
public ArrayList<MethodNode> impls = new ArrayList<MethodNode>();
|
||||
|
||||
public InterfaceImpl(String iname, String cname)
|
||||
{
|
||||
this.iname = iname;
|
||||
HashSet<String> names = new HashSet<String>();
|
||||
ClassNode inode = getClassNode(iname);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean patch(ClassNode cnode) {
|
||||
LinkedList<String> names = new LinkedList<String>();
|
||||
for(MethodNode method : cnode.methods) {
|
||||
ObfMapping m = new ObfMapping(cnode.name, method.name, method.desc).toRuntime();
|
||||
names.add(m.s_name+m.s_desc);
|
||||
}
|
||||
|
||||
boolean changed = false;
|
||||
for(MethodNode impl : impls) {
|
||||
if(names.contains(impl.name+impl.desc))
|
||||
continue;
|
||||
|
||||
MethodNode copy = new MethodNode(impl.access, impl.name, impl.desc,
|
||||
impl.signature, impl.exceptions == null ? null : impl.exceptions.toArray(new String[0]));
|
||||
ASMHelper.copy(impl, copy);
|
||||
cnode.methods.add(impl);
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
||||
private static HashMap<String, InterfaceImpl> impls = new HashMap<String, InterfaceImpl>();
|
||||
|
||||
public static void registerDefaultImpl(String iname, String cname) {
|
||||
impls.put(iname.replace('.', '/'), new InterfaceImpl(iname, cname));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(String name, String transformedName, byte[] bytes) {
|
||||
if(transformedName.startsWith("net.minecraft") || impls.isEmpty())
|
||||
return bytes;
|
||||
|
||||
ClassNode cnode = ASMHelper.createClassNode(bytes);
|
||||
boolean changed = false;
|
||||
for(String iname : cnode.interfaces) {
|
||||
InterfaceImpl impl = impls.get(iname);
|
||||
if(impl != null)
|
||||
changed |= impl.patch(cnode);
|
||||
}
|
||||
|
||||
return changed ? ASMHelper.createBytes(cnode, 0) : bytes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
|
||||
import static codechicken.core.launch.CodeChickenCorePlugin.logger;
|
||||
|
||||
public class DelegatedTransformer implements IClassTransformer
|
||||
{
|
||||
private static ArrayList<IClassTransformer> delegatedTransformers;
|
||||
private static Method m_defineClass;
|
||||
private static Field f_cachedClasses;
|
||||
|
||||
public DelegatedTransformer()
|
||||
{
|
||||
delegatedTransformers = new ArrayList<IClassTransformer>();
|
||||
try
|
||||
{
|
||||
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);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(String name, String tname, byte[] bytes)
|
||||
{
|
||||
if (bytes == null) return null;
|
||||
for(IClassTransformer trans : delegatedTransformers)
|
||||
bytes = trans.transform(name, tname, bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static void addTransformer(String transformer, JarFile jar, File jarFile)
|
||||
{
|
||||
logger.debug("Adding CCTransformer: " + transformer);
|
||||
try
|
||||
{
|
||||
byte[] bytes;
|
||||
bytes = Launch.classLoader.getClassBytes(transformer);
|
||||
|
||||
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());
|
||||
|
||||
bytes = readFully(jar.getInputStream(entry));
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
IClassTransformer classTransformer;
|
||||
try
|
||||
{
|
||||
classTransformer = (IClassTransformer) clazz.getDeclaredConstructor(File.class).newInstance(jarFile);
|
||||
}
|
||||
catch(NoSuchMethodException nsme)
|
||||
{
|
||||
classTransformer = (IClassTransformer) clazz.newInstance();
|
||||
}
|
||||
delegatedTransformers.add(classTransformer);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void defineDependancies(byte[] bytes, JarFile jar, File jarFile) throws Exception
|
||||
{
|
||||
defineDependancies(bytes, jar, jarFile, new Stack<String>());
|
||||
}
|
||||
|
||||
private static void defineDependancies(byte[] bytes, JarFile jar, File jarFile, Stack<String> depStack) throws Exception
|
||||
{
|
||||
ClassReader reader = new ClassReader(bytes);
|
||||
DependancyLister lister = new DependancyLister(Opcodes.ASM4);
|
||||
reader.accept(lister, 0);
|
||||
|
||||
depStack.push(reader.getClassName());
|
||||
|
||||
for(String dependancy : lister.getDependancies())
|
||||
{
|
||||
if(depStack.contains(dependancy))
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
Launch.classLoader.loadClass(dependancy.replace('/', '.'));
|
||||
}
|
||||
catch(ClassNotFoundException cnfe)
|
||||
{
|
||||
ZipEntry entry = jar.getEntry(dependancy+".class");
|
||||
if(entry == null)
|
||||
throw new Exception("Dependancy "+dependancy+" not found in jar file "+jarFile.getName());
|
||||
|
||||
byte[] depbytes = readFully(jar.getInputStream(entry));
|
||||
defineDependancies(depbytes, jar, jarFile, depStack);
|
||||
|
||||
logger.debug("Defining dependancy: "+dependancy);
|
||||
|
||||
defineClass(dependancy.replace('/', '.'), depbytes);
|
||||
}
|
||||
}
|
||||
|
||||
depStack.pop();
|
||||
}
|
||||
|
||||
private static Class<?> defineClass(String classname, byte[] bytes) throws Exception
|
||||
{
|
||||
Class<?> clazz = (Class<?>) m_defineClass.invoke(Launch.classLoader, classname, bytes, 0, bytes.length);
|
||||
((Map<String, Class<?>>)f_cachedClasses.get(Launch.classLoader)).put(classname, clazz);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public static byte[] readFully(InputStream stream) throws IOException
|
||||
{
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(stream.available());
|
||||
int r;
|
||||
while ((r = stream.read()) != -1)
|
||||
{
|
||||
bos.write(r);
|
||||
}
|
||||
|
||||
return bos.toByteArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(int opcode, String owner, String name, String desc)
|
||||
{
|
||||
dependDesc(desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index)
|
||||
{
|
||||
dependDesc(desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc)
|
||||
{
|
||||
depend(owner);
|
||||
dependDesc(desc);
|
||||
}
|
||||
}
|
||||
|
||||
private HashSet<String> dependancies = new HashSet<String>();
|
||||
|
||||
public DependancyLister(int api)
|
||||
{
|
||||
super(api);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value)
|
||||
{
|
||||
dependDesc(desc);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void dependDesc(String desc)
|
||||
{
|
||||
Matcher match = classdesc.matcher(desc);
|
||||
while(match.find())
|
||||
{
|
||||
String s = match.group();
|
||||
depend(s.substring(1, s.length()-1));
|
||||
}
|
||||
}
|
||||
|
||||
private void depend(String classname)
|
||||
{
|
||||
dependancies.add(classname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
|
||||
{
|
||||
dependDesc(desc);
|
||||
return new DependancyMethodLister(Opcodes.ASM4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
|
||||
{
|
||||
depend(superName);
|
||||
if(interfaces != null)
|
||||
for(String interfacename : interfaces)
|
||||
depend(interfacename);
|
||||
}
|
||||
|
||||
public List<String> getDependancies()
|
||||
{
|
||||
return new ArrayList<String>(dependancies);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
public @interface InterfaceDependancies
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AnnotationNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import codechicken.core.launch.CodeChickenCorePlugin;
|
||||
import codechicken.lib.asm.ASMHelper;
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
|
||||
public class InterfaceDependancyTransformer implements IClassTransformer
|
||||
{
|
||||
@Override
|
||||
public byte[] transform(String name, String tname, byte[] bytes) {
|
||||
if (bytes == null) return null;
|
||||
ClassNode cnode = ASMHelper.createClassNode(bytes);
|
||||
|
||||
boolean hasDependancyInterfaces = false;
|
||||
if (cnode.visibleAnnotations != null)
|
||||
for (AnnotationNode ann : cnode.visibleAnnotations)
|
||||
if (ann.desc.equals(Type.getDescriptor(InterfaceDependancies.class))) {
|
||||
hasDependancyInterfaces = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hasDependancyInterfaces)
|
||||
return bytes;
|
||||
|
||||
hasDependancyInterfaces = false;
|
||||
for (Iterator<String> iterator = cnode.interfaces.iterator(); iterator.hasNext(); ) {
|
||||
try {
|
||||
Launch.classLoader.findClass(new ObfMapping(iterator.next()).toRuntime().javaClass());
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
iterator.remove();
|
||||
hasDependancyInterfaces = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasDependancyInterfaces)
|
||||
return bytes;
|
||||
|
||||
return ASMHelper.createBytes(cnode, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.swing.JFileChooser;
|
||||
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
||||
import net.minecraft.launchwrapper.ITweaker;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
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.core.launch.CodeChickenCorePlugin;
|
||||
import codechicken.lib.asm.ASMHelper;
|
||||
import codechicken.lib.asm.CC_ClassWriter;
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
import codechicken.lib.config.ConfigFile;
|
||||
import codechicken.lib.config.ConfigTag;
|
||||
import codechicken.obfuscator.IHeirachyEvaluator;
|
||||
import codechicken.obfuscator.ObfuscationRun;
|
||||
import codechicken.obfuscator.ObfuscationMap.ObfuscationEntry;
|
||||
import cpw.mods.fml.common.asm.transformers.AccessTransformer;
|
||||
import cpw.mods.fml.common.asm.transformers.DeobfuscationTransformer;
|
||||
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
|
||||
public class MCPDeobfuscationTransformer implements IClassTransformer, Opcodes, IHeirachyEvaluator
|
||||
{
|
||||
public static class LoadPlugin implements IFMLLoadingPlugin
|
||||
{
|
||||
@Override
|
||||
public String[] getASMTransformerClass() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModContainerClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSetupClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectData(Map<String, Object> data) {
|
||||
load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessTransformerClass() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static ObfuscationRun run;
|
||||
private static List<String> excludedPackages = new LinkedList<String>();
|
||||
private static MCPDeobfuscationTransformer instance = new MCPDeobfuscationTransformer();
|
||||
|
||||
private static boolean activated;
|
||||
|
||||
private static Field f_transformers;
|
||||
private static Field f_modifiers;
|
||||
private static Field f_Modifier_name;
|
||||
private static Field f_Modifier_desc;
|
||||
|
||||
static {
|
||||
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);
|
||||
f_Modifier_name = c_Modifier.getDeclaredField("name");
|
||||
f_Modifier_desc = c_Modifier.getDeclaredField("desc");
|
||||
|
||||
f_transformers.setAccessible(true);
|
||||
f_modifiers.setAccessible(true);
|
||||
f_Modifier_name.setAccessible(true);
|
||||
f_Modifier_desc.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object get(Field f, Object inst) {
|
||||
try {
|
||||
return f.get(inst);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void set(Field f, Object inst, Object value) {
|
||||
try {
|
||||
f.set(inst, value);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static List<IClassTransformer> getTransformers() {
|
||||
return (List<IClassTransformer>) get(f_transformers, Launch.classLoader);
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
CodeChickenCoreModContainer.loadConfig();
|
||||
ConfigFile config = CodeChickenCoreModContainer.config;
|
||||
File mcDir = CodeChickenCorePlugin.minecraftDir;
|
||||
|
||||
if (config.getTag("dev.deobfuscate")
|
||||
.setComment("set to true to completely deobfuscate mcp names")
|
||||
.getBooleanValue(!ObfMapping.obfuscated)) {
|
||||
run = new ObfuscationRun(false, ObfMapping.MCPRemapper.getConfFiles(),
|
||||
ObfuscationRun.fillDefaults(new HashMap<String, String>()));
|
||||
run.obf.setHeirachyEvaluator(instance);
|
||||
run.setQuiet().parseMappings();
|
||||
for (String pkg : run.config.get("excludedPackages").split(";"))
|
||||
excludedPackages.add(pkg);
|
||||
|
||||
if (ObfMapping.obfuscated) {
|
||||
ObfMapping.loadMCPRemapper();
|
||||
run.setSeargeConstants();
|
||||
getTransformers().add(instance);
|
||||
} else {
|
||||
getTransformers().add(0, instance);//insert transformer as first.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(String name, String transformedName, byte[] bytes) {
|
||||
if (name.equals("cpw.mods.fml.common.Loader")) {
|
||||
bytes = injectCallback(bytes);
|
||||
activated = true;
|
||||
}
|
||||
|
||||
if (!activated || bytes == null)
|
||||
return bytes;
|
||||
|
||||
ClassNode cnode = ASMHelper.createClassNode(bytes, ClassReader.EXPAND_FRAMES);
|
||||
ClassWriter cw = new CC_ClassWriter(0, true);
|
||||
run.remap(cnode, cw);
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
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"));
|
||||
return ASMHelper.createBytes(cnode, 0);
|
||||
}
|
||||
|
||||
public static void loadCallback() {
|
||||
if (ObfMapping.obfuscated) {
|
||||
//move ourselves to the end
|
||||
List<IClassTransformer> transformers = getTransformers();
|
||||
for (Iterator<IClassTransformer> iterator = transformers.iterator(); iterator.hasNext(); ) {
|
||||
IClassTransformer t = iterator.next();
|
||||
if (t == instance || t instanceof DeobfuscationTransformer)
|
||||
iterator.remove();
|
||||
}
|
||||
transformers.add(instance);
|
||||
} else {
|
||||
//remap access transformers
|
||||
for (IClassTransformer t : getTransformers())
|
||||
if (t instanceof AccessTransformer)
|
||||
remapAccessTransformer(t);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void remapAccessTransformer(IClassTransformer t) {
|
||||
Multimap<String, ?> modifiers = (Multimap<String, ?>) get(f_modifiers, t);
|
||||
Multimap<String, Object> t_modifiers = HashMultimap.create();
|
||||
for (Entry<String, ?> entry : modifiers.entries()) {
|
||||
Object mod = entry.getValue();
|
||||
String m_owner = entry.getKey().replace('.', '/');
|
||||
String m_name = (String) get(f_Modifier_name, mod);
|
||||
String m_desc = ((String) get(f_Modifier_desc, mod)).replace('.', '/');
|
||||
ObfMapping map;
|
||||
if (m_name.equals("*")) {
|
||||
map = new ObfMapping(m_owner);
|
||||
map.s_name = m_name;
|
||||
map.s_desc = m_desc;
|
||||
} else {
|
||||
try {
|
||||
map = new ObfMapping(m_owner, m_name, m_desc).toClassloading();
|
||||
} catch (Exception e) {
|
||||
new Object();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
set(f_Modifier_name, mod, map.s_name);
|
||||
set(f_Modifier_desc, mod, map.s_desc);
|
||||
t_modifiers.put(map.javaClass(), mod);
|
||||
}
|
||||
set(f_modifiers, t, t_modifiers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getParents(ObfuscationEntry desc) {
|
||||
try {
|
||||
String name = ObfMapping.obfuscated ? desc.obf.s_owner : desc.mcp.s_owner;
|
||||
name = name.replace('/', '.');
|
||||
byte[] bytes = Launch.classLoader.getClassBytes(name);
|
||||
if (bytes != null)
|
||||
return ObfuscationRun.getParents(ASMHelper.createClassNode(bytes));
|
||||
} catch (IOException e) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLibClass(ObfuscationEntry desc) {
|
||||
String name = desc.srg.s_owner;
|
||||
for (String p : excludedPackages)
|
||||
if (name.startsWith(p))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String unmap(String name) {
|
||||
if (run == null)
|
||||
return null;
|
||||
ObfuscationEntry e = run.obf.lookupMcpClass(name);
|
||||
if (e == null)
|
||||
return null;
|
||||
return e.obf.s_owner;
|
||||
}
|
||||
|
||||
public static MCPDeobfuscationTransformer instance() {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
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.core.launch.CodeChickenCorePlugin;
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class MethodASMifier extends ClassVisitor
|
||||
{
|
||||
PrintWriter printWriter;
|
||||
ObfMapping method;
|
||||
Printer asmifier;
|
||||
|
||||
public MethodASMifier(ObfMapping method, Printer printer, PrintWriter printWriter) {
|
||||
super(ASM4);
|
||||
this.method = method;
|
||||
this.printWriter = printWriter;
|
||||
asmifier = printer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
if (method.matches(name, desc)) {
|
||||
Printer localPrinter = asmifier.visitMethod(access, name, desc, signature, exceptions);
|
||||
return new TraceMethodVisitor(null, localPrinter);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
asmifier.visitClassEnd();
|
||||
asmifier.print(printWriter);
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
public static void printMethod(ObfMapping method, Printer printer, File toFile) {
|
||||
try {
|
||||
printMethod(method, Launch.classLoader.getClassBytes(method.javaClass()), printer, toFile);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void printMethod(ObfMapping method, byte[] bytes, Printer printer, File toFile) {
|
||||
try {
|
||||
if (!toFile.getParentFile().exists())
|
||||
toFile.getParentFile().mkdirs();
|
||||
if (!toFile.exists())
|
||||
toFile.createNewFile();
|
||||
|
||||
PrintWriter printWriter = new PrintWriter(toFile);
|
||||
|
||||
ClassVisitor cv = new MethodASMifier(method, printer, printWriter);
|
||||
ClassReader cr = new ClassReader(bytes);
|
||||
cr.accept(cv, 0);
|
||||
|
||||
printWriter.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package codechicken.core.asm;
|
||||
|
||||
import codechicken.lib.asm.*;
|
||||
import codechicken.lib.asm.ModularASMTransformer.MethodReplacer;
|
||||
import codechicken.lib.asm.ModularASMTransformer.MethodTransformer;
|
||||
import codechicken.lib.asm.ModularASMTransformer.MethodWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.InsnNode;
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import codechicken.lib.config.ConfigTag;
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static codechicken.lib.asm.InsnComparator.*;
|
||||
|
||||
public class TweakTransformer implements IClassTransformer, Opcodes
|
||||
{
|
||||
private static ModularASMTransformer transformer = new ModularASMTransformer();
|
||||
private static Map<String, ASMBlock> blocks = ASMReader.loadResource("/assets/codechickencore/asm/tweaks.asm");
|
||||
public static ConfigTag tweaks;
|
||||
|
||||
public static void load() {
|
||||
CodeChickenCoreModContainer.loadConfig();
|
||||
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)")
|
||||
.getBooleanValue(false)) {
|
||||
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")
|
||||
.getBooleanValue(false)) {
|
||||
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")
|
||||
.getBooleanValue(true)) {
|
||||
transformer.add(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");
|
||||
ASMBlock inject = blocks.get("doFireTick");
|
||||
|
||||
ASMBlock key = needle.applyLabels(findOnce(mv.instructions, needle.list));
|
||||
LabelNode jlabel = key.get("LRET");
|
||||
mv.instructions.insertBefore(jlabel, new JumpInsnNode(GOTO, inject.get("LSKIP")));
|
||||
mv.instructions.insert(jlabel, inject.list.list);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (tweaks.getTag("finiteWater")
|
||||
.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"))
|
||||
{
|
||||
@Override
|
||||
public void transform(MethodNode mv) {
|
||||
InsnListSection key = findOnce(mv.instructions, blocks.get("finiteWater").list);
|
||||
key.setLast(((JumpInsnNode) key.getLast()).label);
|
||||
key.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(String name, String tname, byte[] bytes) {
|
||||
return transformer.transform(name, bytes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package codechicken.core.commands;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import codechicken.core.ServerUtils;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.ChatComponentText;
|
||||
import net.minecraft.util.ChunkCoordinates;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.command.ICommand;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
|
||||
public abstract class CoreCommand implements ICommand
|
||||
{
|
||||
public class WCommandSender implements ICommandSender
|
||||
{
|
||||
public ICommandSender wrapped;
|
||||
|
||||
public WCommandSender(ICommandSender sender) {
|
||||
wrapped = sender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandSenderName() {
|
||||
return wrapped.getCommandSenderName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChatMessage(IChatComponent string) {
|
||||
wrapped.addChatMessage(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCommandSenderUseCommand(int i, String s) {
|
||||
return wrapped.canCommandSenderUseCommand(i, s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkCoordinates getPlayerCoordinates() {
|
||||
return wrapped.getPlayerCoordinates();
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getEntityWorld() {
|
||||
return wrapped.getEntityWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChatComponent func_145748_c_() {
|
||||
return new ChatComponentText(getCommandSenderName());
|
||||
}
|
||||
}
|
||||
|
||||
public abstract boolean OPOnly();
|
||||
|
||||
@Override
|
||||
public String getCommandUsage(ICommandSender var1)
|
||||
{
|
||||
return "/" + getCommandName() + " help";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processCommand(ICommandSender listener, String[] args)
|
||||
{
|
||||
WCommandSender wsender = new WCommandSender(listener);
|
||||
|
||||
if(args.length < minimumParameters() ||
|
||||
args.length == 1 && args[0].equals("help"))
|
||||
{
|
||||
printHelp(wsender);
|
||||
return;
|
||||
}
|
||||
|
||||
String command = getCommandName();
|
||||
for(String arg : args)
|
||||
command+=" "+arg;
|
||||
|
||||
handleCommand(command, wsender.getCommandSenderName(), args, wsender);
|
||||
}
|
||||
|
||||
public abstract void handleCommand(String command, String playername, String[] args, WCommandSender listener);
|
||||
|
||||
public abstract void printHelp(WCommandSender listener);
|
||||
|
||||
public final EntityPlayerMP getPlayer(String name)
|
||||
{
|
||||
return ServerUtils.getPlayer(name);
|
||||
}
|
||||
|
||||
public WorldServer getWorld(int dimension)
|
||||
{
|
||||
return DimensionManager.getWorld(dimension);
|
||||
}
|
||||
|
||||
public WorldServer getWorld(EntityPlayer player)
|
||||
{
|
||||
return (WorldServer) player.worldObj;
|
||||
}
|
||||
|
||||
public Integer parseInteger(String parse)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Integer.parseInt(parse);
|
||||
}
|
||||
catch(NumberFormatException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Object arg0)
|
||||
{
|
||||
return getCommandName().compareTo(((ICommand)arg0).getCommandName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> getCommandAliases()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> addTabCompletionOptions(ICommandSender var1, String[] var2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsernameIndex(String[] astring, int i)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCommandSenderUseCommand(ICommandSender var1)
|
||||
{
|
||||
if(OPOnly())
|
||||
{
|
||||
if(var1 instanceof EntityPlayer)
|
||||
return ServerUtils.isPlayerOP(var1.getCommandSenderName());
|
||||
else if(var1 instanceof MinecraftServer)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public abstract int minimumParameters();
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package codechicken.core.commands;
|
||||
|
||||
import net.minecraft.util.MovingObjectPosition.MovingObjectType;
|
||||
import net.minecraft.world.ChunkPosition;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.WorldServer;
|
||||
|
||||
public abstract class PlayerCommand extends CoreCommand
|
||||
{
|
||||
@Override
|
||||
public boolean canCommandSenderUseCommand(ICommandSender var1)
|
||||
{
|
||||
if(!super.canCommandSenderUseCommand(var1))
|
||||
return false;
|
||||
return var1 instanceof EntityPlayer;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleCommand(String command, String playername, String[] args, WCommandSender listener)
|
||||
{
|
||||
EntityPlayerMP player = (EntityPlayerMP)listener.wrapped;
|
||||
handleCommand(getWorld(player), player, args);
|
||||
}
|
||||
|
||||
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 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);
|
||||
if(hit == null || hit.typeOfHit != MovingObjectType.BLOCK)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ChunkPosition(hit.blockX, hit.blockY, hit.blockZ);
|
||||
}
|
||||
|
||||
public Entity getPlayerLookingAtEntity(EntityPlayerMP player, float reach)
|
||||
{
|
||||
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);
|
||||
if(hit == null || hit.typeOfHit != MovingObjectType.ENTITY)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return hit.entityHit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package codechicken.core.commands;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
|
||||
public abstract class ServerCommand extends CoreCommand
|
||||
{
|
||||
@Override
|
||||
public void processCommand(ICommandSender var1, String[] var2)
|
||||
{
|
||||
handleCommand(var2, (MinecraftServer)var1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCommandSenderUseCommand(ICommandSender var1)
|
||||
{
|
||||
if(!super.canCommandSenderUseCommand(var1))
|
||||
return false;
|
||||
return var1 instanceof MinecraftServer;
|
||||
}
|
||||
|
||||
public abstract void handleCommand(String[] args, MinecraftServer listener);
|
||||
|
||||
public final boolean OPOnly()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package codechicken.core.featurehack;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
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);
|
||||
|
||||
public boolean isValid();
|
||||
}
|
||||
|
||||
public final IRenderCallback callback;
|
||||
|
||||
public EntityRenderHook(World world, double x, double y, double z, IRenderCallback callback) {
|
||||
super(world);
|
||||
setPosition(x, y, z);
|
||||
ignoreFrustumCheck = true;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate() {
|
||||
if (!callback.isValid())
|
||||
setDead();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void entityInit() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readEntityFromNBT(NBTTagCompound var1) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeEntityToNBT(NBTTagCompound var1) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRenderInPass(int pass) {
|
||||
return callback.shouldRenderInPass(pass);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package codechicken.core.featurehack;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
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();
|
||||
}
|
||||
|
||||
public final IUpdateCallback callback;
|
||||
public EntityUpdateHook(World world, int x, int y, int z, IUpdateCallback callback)
|
||||
{
|
||||
super(world);
|
||||
setPosition(x, y, z);
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate()
|
||||
{
|
||||
if(!callback.isValid())
|
||||
setDead();
|
||||
else
|
||||
callback.onUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void entityInit()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readEntityFromNBT(NBTTagCompound var1)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeEntityToNBT(NBTTagCompound var1)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package codechicken.core.featurehack;
|
||||
|
||||
import cpw.mods.fml.client.registry.RenderingRegistry;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
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;
|
||||
|
||||
public static void enableUpdateHook()
|
||||
{
|
||||
if(updateHookEnabled)
|
||||
return;
|
||||
|
||||
updateHookEnabled = true;
|
||||
if(FMLCommonHandler.instance().getSide().isClient())
|
||||
enableClientUpdateHook();
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static void enableRenderHook()
|
||||
{
|
||||
if(renderHookEnabled)
|
||||
return;
|
||||
|
||||
renderHookEnabled = true;
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityUpdateHook.class, new RenderNull());
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
private static void enableClientUpdateHook()
|
||||
{
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityRenderHook.class, new RenderEntityRenderHook());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package codechicken.core.featurehack;
|
||||
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.util.ObjectIntIdentityMap;
|
||||
import net.minecraft.util.RegistryNamespaced;
|
||||
import net.minecraft.util.RegistrySimple;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
|
||||
public class GameDataManipulator
|
||||
{
|
||||
public static Field f_registryObjects;
|
||||
public static Field f_underlyingIntegerMap;
|
||||
|
||||
static
|
||||
{
|
||||
try {
|
||||
f_registryObjects = RegistrySimple.class.getDeclaredField(
|
||||
new ObfMapping("net/minecraft/util/RegistrySimple", "registryObjects", "Ljava/util/Map;").toRuntime().s_name);
|
||||
f_registryObjects.setAccessible(true);
|
||||
f_underlyingIntegerMap = RegistryNamespaced.class.getDeclaredField(
|
||||
new ObfMapping("net/minecraft/util/RegistryNamespaced", "underlyingIntegerMap", "Lnet/minecraft/util/ObjectIntIdentityMap;").toRuntime().s_name);
|
||||
f_underlyingIntegerMap.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void replaceItem(int id, Item item) {
|
||||
try {
|
||||
String name = Item.itemRegistry.getNameForObject(Item.getItemById(id));
|
||||
((Map)f_registryObjects.get(Item.itemRegistry)).put(name, item);
|
||||
((ObjectIntIdentityMap)f_underlyingIntegerMap.get(Item.itemRegistry)).func_148746_a(item, id);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package codechicken.core.featurehack;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import codechicken.core.ReflectionManager;
|
||||
import codechicken.core.featurehack.mc.TextureLavaFX;
|
||||
import codechicken.core.featurehack.mc.TextureLavaFlowFX;
|
||||
import codechicken.core.featurehack.mc.TextureWaterFX;
|
||||
import codechicken.core.featurehack.mc.TextureWaterFlowFX;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
import codechicken.core.asm.TweakTransformer;
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
|
||||
public class LiquidTextures
|
||||
{
|
||||
public static IIcon[] newTextures = new IIcon[4];
|
||||
|
||||
public static boolean replaceLava;
|
||||
public static boolean replaceWater;
|
||||
|
||||
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);
|
||||
if(replaceWater)
|
||||
{
|
||||
newTextures[0] = new TextureWaterFX().texture;
|
||||
newTextures[1] = new TextureWaterFlowFX().texture;
|
||||
}
|
||||
if(replaceLava)
|
||||
{
|
||||
newTextures[2] = new TextureLavaFX().texture;
|
||||
newTextures[3] = new TextureLavaFlowFX().texture;
|
||||
}
|
||||
|
||||
if(replaceWater || replaceLava)
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.register(new LiquidTextures());
|
||||
field_tex = ReflectionManager.getField(new ObfMapping("net/minecraft/block/BlockLiquid", "field_149806_a", "[Lnet/minecraft/util/IIcon;"));
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void postStitch(TextureStitchEvent.Post event)
|
||||
{
|
||||
IIcon[] icons;
|
||||
if(replaceLava)
|
||||
{
|
||||
icons = ReflectionManager.get(field_tex, IIcon[].class, Blocks.flowing_lava);
|
||||
icons[0] = newTextures[2];
|
||||
icons[1] = newTextures[3];
|
||||
icons = ReflectionManager.get(field_tex, IIcon[].class, Blocks.lava);
|
||||
icons[0] = newTextures[2];
|
||||
icons[1] = newTextures[3];
|
||||
}
|
||||
if(replaceWater)
|
||||
{
|
||||
icons = ReflectionManager.get(field_tex, IIcon[].class, Blocks.flowing_water);
|
||||
icons[0] = newTextures[0];
|
||||
icons[1] = newTextures[1];
|
||||
icons = ReflectionManager.get(field_tex, IIcon[].class, Blocks.water);
|
||||
icons[0] = newTextures[0];
|
||||
icons[1] = newTextures[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package codechicken.core.featurehack;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraftforge.client.MinecraftForgeClient;
|
||||
|
||||
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;
|
||||
GL11.glTranslated(x-hook.posX, y-hook.posY, z-hook.posZ);
|
||||
((EntityRenderHook)entity).callback.render(frame, MinecraftForgeClient.getRenderPass());
|
||||
GL11.glTranslated(hook.posX-x, hook.posY-y, hook.posZ-z);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceLocation getEntityTexture(Entity entity)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package codechicken.core.featurehack;
|
||||
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceLocation getEntityTexture(Entity entity)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package codechicken.core.featurehack;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import static net.minecraftforge.common.util.ForgeDirection.UP;
|
||||
|
||||
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);
|
||||
else
|
||||
{
|
||||
int meta = world.getBlockMetadata(x, y, z);
|
||||
if(meta < 15)
|
||||
world.setBlockMetadataWithNotify(x, y, z, meta+rand.nextInt(3)/2, 0);
|
||||
|
||||
world.scheduleBlockUpdate(x, y, z, Blocks.fire, Blocks.fire.tickRate(world) + rand.nextInt(10));
|
||||
|
||||
if(!supported && !Blocks.fire.canCatchFire(world, x, y - 1, z, UP) && meta == 15 && rand.nextInt(4) == 0)
|
||||
world.setBlockToAir(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean canPlaceBlockAt(World world, int x, int y, int z)
|
||||
{
|
||||
Block block = world.getBlock(x, y, z);
|
||||
return block.isAir(world, x, y, z) || block.isReplaceable(world, x, y, z);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package codechicken.core.featurehack.mc;
|
||||
|
||||
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];
|
||||
protected float[] field_76877_j = new float[256];
|
||||
|
||||
public TextureLavaFX()
|
||||
{
|
||||
super(16, "lava_still_fx");
|
||||
setup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup()
|
||||
{
|
||||
super.setup();
|
||||
field_76876_g = new float[tileSizeSquare];
|
||||
field_76878_h = new float[tileSizeSquare];
|
||||
field_76879_i = new float[tileSizeSquare];
|
||||
field_76877_j = new float[tileSizeSquare];
|
||||
}
|
||||
|
||||
public void onTick()
|
||||
{
|
||||
int var2;
|
||||
float var3;
|
||||
int var5;
|
||||
int var6;
|
||||
int var7;
|
||||
int var8;
|
||||
int var9;
|
||||
|
||||
for (int var1 = 0; var1 < tileSizeBase; ++var1)
|
||||
{
|
||||
for (var2 = 0; var2 < tileSizeBase; ++var2)
|
||||
{
|
||||
var3 = 0.0F;
|
||||
int var4 = (int)(MathHelper.sin(var2 * (float)Math.PI * 2.0F / 16.0F) * 1.2F);
|
||||
var5 = (int)(MathHelper.sin(var1 * (float)Math.PI * 2.0F / 16.0F) * 1.2F);
|
||||
|
||||
for (var6 = var1 - 1; var6 <= var1 + 1; ++var6)
|
||||
{
|
||||
for (var7 = var2 - 1; var7 <= var2 + 1; ++var7)
|
||||
{
|
||||
var8 = var6 + var4 & tileSizeMask;
|
||||
var9 = var7 + var5 & tileSizeMask;
|
||||
var3 += this.field_76876_g[var8 + var9 * tileSizeBase];
|
||||
}
|
||||
}
|
||||
|
||||
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]) / 4.0F * 0.8F;
|
||||
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;
|
||||
}
|
||||
|
||||
this.field_76877_j[var1 + var2 * tileSizeBase] -= 0.06F;
|
||||
|
||||
if (Math.random() < 0.005D)
|
||||
{
|
||||
this.field_76877_j[var1 + var2 * tileSizeBase] = 1.5F;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float[] var11 = this.field_76878_h;
|
||||
this.field_76878_h = this.field_76876_g;
|
||||
this.field_76876_g = var11;
|
||||
|
||||
for (var2 = 0; var2 < tileSizeSquare; ++var2)
|
||||
{
|
||||
var3 = this.field_76876_g[var2] * 2.0F;
|
||||
|
||||
if (var3 > 1.0F)
|
||||
{
|
||||
var3 = 1.0F;
|
||||
}
|
||||
|
||||
if (var3 < 0.0F)
|
||||
{
|
||||
var3 = 0.0F;
|
||||
}
|
||||
|
||||
var5 = (int)(var3 * 100.0F + 155.0F);
|
||||
var6 = (int)(var3 * var3 * 255.0F);
|
||||
var7 = (int)(var3 * var3 * var3 * var3 * 128.0F);
|
||||
|
||||
if (this.anaglyphEnabled)
|
||||
{
|
||||
var8 = (var5 * 30 + var6 * 59 + var7 * 11) / 100;
|
||||
var9 = (var5 * 30 + var6 * 70) / 100;
|
||||
int var10 = (var5 * 30 + var7 * 70) / 100;
|
||||
var5 = var8;
|
||||
var6 = var9;
|
||||
var7 = var10;
|
||||
}
|
||||
|
||||
imageData[var2] = new ColourRGBA(var5, var6, var7, -1).argb();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package codechicken.core.featurehack.mc;
|
||||
|
||||
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];
|
||||
protected float[] field_76872_j = new float[256];
|
||||
int field_76873_k = 0;
|
||||
|
||||
//shadow
|
||||
public int tileSizeBase = 16;
|
||||
public int tileSizeSquare = 256;
|
||||
public int tileSizeMask = 15;
|
||||
public int tileSizeSquareMask = 255;
|
||||
|
||||
public TextureLavaFlowFX()
|
||||
{
|
||||
super(32, "lava_flow_fx");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup()
|
||||
{
|
||||
super.setup();
|
||||
field_76871_g = new float[tileSizeSquare];
|
||||
field_76874_h = new float[tileSizeSquare];
|
||||
field_76875_i = new float[tileSizeSquare];
|
||||
field_76872_j = new float[tileSizeSquare];
|
||||
field_76873_k = 0;
|
||||
}
|
||||
|
||||
public void onTick()
|
||||
{
|
||||
++this.field_76873_k;
|
||||
int var2;
|
||||
float var3;
|
||||
int var5;
|
||||
int var6;
|
||||
int var7;
|
||||
int var8;
|
||||
int var9;
|
||||
|
||||
for (int var1 = 0; var1 < tileSizeBase; ++var1)
|
||||
{
|
||||
for (var2 = 0; var2 < tileSizeBase; ++var2)
|
||||
{
|
||||
var3 = 0.0F;
|
||||
int var4 = (int)(MathHelper.sin(var2 * (float)Math.PI * 2.0F / 16.0F) * 1.2F);
|
||||
var5 = (int)(MathHelper.sin(var1 * (float)Math.PI * 2.0F / 16.0F) * 1.2F);
|
||||
|
||||
for (var6 = var1 - 1; var6 <= var1 + 1; ++var6)
|
||||
{
|
||||
for (var7 = var2 - 1; var7 <= var2 + 1; ++var7)
|
||||
{
|
||||
var8 = var6 + var4 & tileSizeMask;
|
||||
var9 = var7 + var5 & tileSizeMask;
|
||||
var3 += this.field_76871_g[var8 + var9 * tileSizeBase];
|
||||
}
|
||||
}
|
||||
|
||||
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]) / 4.0F * 0.8F;
|
||||
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;
|
||||
}
|
||||
|
||||
this.field_76872_j[var1 + var2 * tileSizeBase] -= 0.06F;
|
||||
|
||||
if (Math.random() < 0.005D)
|
||||
{
|
||||
this.field_76872_j[var1 + var2 * tileSizeBase] = 1.5F;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float[] var11 = this.field_76874_h;
|
||||
this.field_76874_h = this.field_76871_g;
|
||||
this.field_76871_g = var11;
|
||||
|
||||
for (var2 = 0; var2 < tileSizeSquare; ++var2)
|
||||
{
|
||||
var3 = this.field_76871_g[(var2 - this.field_76873_k / 3 * tileSizeBase) & tileSizeSquareMask] * 2.0F;
|
||||
|
||||
if (var3 > 1.0F)
|
||||
{
|
||||
var3 = 1.0F;
|
||||
}
|
||||
|
||||
if (var3 < 0.0F)
|
||||
{
|
||||
var3 = 0.0F;
|
||||
}
|
||||
|
||||
var5 = (int)(var3 * 100.0F + 155.0F);
|
||||
var6 = (int)(var3 * var3 * 255.0F);
|
||||
var7 = (int)(var3 * var3 * var3 * var3 * 128.0F);
|
||||
|
||||
if (this.anaglyphEnabled)
|
||||
{
|
||||
var8 = (var5 * 30 + var6 * 59 + var7 * 11) / 100;
|
||||
var9 = (var5 * 30 + var6 * 70) / 100;
|
||||
int var10 = (var5 * 30 + var7 * 70) / 100;
|
||||
var5 = var8;
|
||||
var6 = var9;
|
||||
var7 = var10;
|
||||
}
|
||||
|
||||
int px = var2&tileSizeMask;
|
||||
int py = var2/tileSizeBase;
|
||||
writeColour(px, py, var5, var6, var7, -1);
|
||||
writeColour(px+16, py, var5, var6, var7, -1);
|
||||
writeColour(px, py+16, var5, var6, var7, -1);
|
||||
writeColour(px+16, py+16, var5, var6, var7, -1);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeColour(int px, int py, int var5, int var6, int var7, int var8)
|
||||
{
|
||||
imageData[py*32+px] = new ColourRGBA(var5, var6, var7, var8).argb();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package codechicken.core.featurehack.mc;
|
||||
|
||||
import codechicken.lib.colour.ColourRGBA;
|
||||
import codechicken.lib.render.TextureFX;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
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];
|
||||
|
||||
/** green RGB value for water texture */
|
||||
protected float[] green = new float[256];
|
||||
|
||||
/** blue RGB value for water texture */
|
||||
protected float[] blue = new float[256];
|
||||
|
||||
/** alpha RGB value for water texture */
|
||||
protected float[] alpha = new float[256];
|
||||
public TextureWaterFX()
|
||||
{
|
||||
super(16, "water_still_fx");
|
||||
setup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup()
|
||||
{
|
||||
super.setup();
|
||||
red = new float[tileSizeSquare];
|
||||
green = new float[tileSizeSquare];
|
||||
blue = new float[tileSizeSquare];
|
||||
alpha = new float[tileSizeSquare];
|
||||
}
|
||||
|
||||
public void onTick()
|
||||
{
|
||||
int var1;
|
||||
int var2;
|
||||
float var3;
|
||||
int var5;
|
||||
int var6;
|
||||
|
||||
for (var1 = 0; var1 < tileSizeBase; ++var1)
|
||||
{
|
||||
for (var2 = 0; var2 < tileSizeBase; ++var2)
|
||||
{
|
||||
var3 = 0.0F;
|
||||
|
||||
for (int var4 = var1 - 1; var4 <= var1 + 1; ++var4)
|
||||
{
|
||||
var5 = var4 & tileSizeMask;
|
||||
var6 = var2 & tileSizeMask;
|
||||
var3 += this.red[var5 + var6 * tileSizeBase];
|
||||
}
|
||||
|
||||
this.green[var1 + var2 * tileSizeBase] = var3 / 3.3F + this.blue[var1 + var2 * tileSizeBase] * 0.8F;
|
||||
}
|
||||
}
|
||||
|
||||
for (var1 = 0; var1 < tileSizeBase; ++var1)
|
||||
{
|
||||
for (var2 = 0; var2 < tileSizeBase; ++var2)
|
||||
{
|
||||
this.blue[var1 + var2 * tileSizeBase] += this.alpha[var1 + var2 * tileSizeBase] * 0.05F;
|
||||
|
||||
if (this.blue[var1 + var2 * tileSizeBase] < 0.0F)
|
||||
{
|
||||
this.blue[var1 + var2 * tileSizeBase] = 0.0F;
|
||||
}
|
||||
|
||||
this.alpha[var1 + var2 * tileSizeBase] -= 0.1F;
|
||||
|
||||
if (Math.random() < 0.05D)
|
||||
{
|
||||
this.alpha[var1 + var2 * tileSizeBase] = 0.5F;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float[] var12 = this.green;
|
||||
this.green = this.red;
|
||||
this.red = var12;
|
||||
|
||||
for (var2 = 0; var2 < tileSizeSquare; ++var2)
|
||||
{
|
||||
var3 = this.red[var2];
|
||||
|
||||
if (var3 > 1.0F)
|
||||
{
|
||||
var3 = 1.0F;
|
||||
}
|
||||
|
||||
if (var3 < 0.0F)
|
||||
{
|
||||
var3 = 0.0F;
|
||||
}
|
||||
|
||||
float var13 = var3 * var3;
|
||||
var5 = (int)(32.0F + var13 * 32.0F);
|
||||
var6 = (int)(50.0F + var13 * 64.0F);
|
||||
int var7 = 255;
|
||||
int var8 = (int)(146.0F + var13 * 50.0F);
|
||||
|
||||
if (this.anaglyphEnabled)
|
||||
{
|
||||
int var9 = (var5 * 30 + var6 * 59 + var7 * 11) / 100;
|
||||
int var10 = (var5 * 30 + var6 * 70) / 100;
|
||||
int var11 = (var5 * 30 + var7 * 70) / 100;
|
||||
var5 = var9;
|
||||
var6 = var10;
|
||||
var7 = var11;
|
||||
}
|
||||
|
||||
imageData[var2] = new ColourRGBA(var5, var6, var7, var8).argb();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package codechicken.core.featurehack.mc;
|
||||
|
||||
import codechicken.lib.colour.ColourRGBA;
|
||||
import codechicken.lib.render.TextureFX;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
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];
|
||||
protected float[] field_76881_j = new float[256];
|
||||
private int tickCounter = 0;
|
||||
|
||||
//shadow
|
||||
public int tileSizeBase = 16;
|
||||
public int tileSizeSquare = 256;
|
||||
public int tileSizeMask = 15;
|
||||
public int tileSizeSquareMask = 255;
|
||||
|
||||
public TextureWaterFlowFX()
|
||||
{
|
||||
super(32, "water_flow_fx");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup()
|
||||
{
|
||||
super.setup();
|
||||
field_76880_g = new float[tileSizeSquare];
|
||||
field_76883_h = new float[tileSizeSquare];
|
||||
field_76884_i = new float[tileSizeSquare];
|
||||
field_76881_j = new float[tileSizeSquare];
|
||||
tickCounter = 0;
|
||||
}
|
||||
|
||||
public void onTick()
|
||||
{
|
||||
++this.tickCounter;
|
||||
int var1;
|
||||
int var2;
|
||||
float var3;
|
||||
int var5;
|
||||
int var6;
|
||||
|
||||
for (var1 = 0; var1 < tileSizeBase; ++var1)
|
||||
{
|
||||
for (var2 = 0; var2 < tileSizeBase; ++var2)
|
||||
{
|
||||
var3 = 0.0F;
|
||||
|
||||
for (int var4 = var2 - 2; var4 <= var2; ++var4)
|
||||
{
|
||||
var5 = var1 & tileSizeMask;
|
||||
var6 = var4 & tileSizeMask;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (this.field_76884_i[var1 + var2 * tileSizeBase] < 0.0F)
|
||||
{
|
||||
this.field_76884_i[var1 + var2 * tileSizeBase] = 0.0F;
|
||||
}
|
||||
|
||||
this.field_76881_j[var1 + var2 * tileSizeBase] -= 0.3F;
|
||||
|
||||
if (Math.random() < 0.2D)
|
||||
{
|
||||
this.field_76881_j[var1 + var2 * tileSizeBase] = 0.5F;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float[] var12 = this.field_76883_h;
|
||||
this.field_76883_h = this.field_76880_g;
|
||||
this.field_76880_g = var12;
|
||||
|
||||
for (var2 = 0; var2 < tileSizeSquare; ++var2)
|
||||
{
|
||||
var3 = this.field_76880_g[var2 - this.tickCounter * tileSizeBase & tileSizeSquareMask];
|
||||
|
||||
if (var3 > 1.0F)
|
||||
{
|
||||
var3 = 1.0F;
|
||||
}
|
||||
|
||||
if (var3 < 0.0F)
|
||||
{
|
||||
var3 = 0.0F;
|
||||
}
|
||||
|
||||
float var13 = var3 * var3;
|
||||
var5 = (int)(32.0F + var13 * 32.0F);
|
||||
var6 = (int)(50.0F + var13 * 64.0F);
|
||||
int var7 = 255;
|
||||
int var8 = (int)(146.0F + var13 * 50.0F);
|
||||
|
||||
if (this.anaglyphEnabled)
|
||||
{
|
||||
int var9 = (var5 * 30 + var6 * 59 + var7 * 11) / 100;
|
||||
int var10 = (var5 * 30 + var6 * 70) / 100;
|
||||
int var11 = (var5 * 30 + var7 * 70) / 100;
|
||||
var5 = var9;
|
||||
var6 = var10;
|
||||
var7 = var11;
|
||||
}
|
||||
|
||||
|
||||
int px = var2&tileSizeMask;
|
||||
int py = var2/tileSizeBase;
|
||||
writeColour(px, py, var5, var6, var7, var8);
|
||||
writeColour(px+16, py, var5, var6, var7, var8);
|
||||
writeColour(px, py+16, var5, var6, var7, var8);
|
||||
writeColour(px+16, py+16, var5, var6, var7, var8);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeColour(int px, int py, int var5, int var6, int var7, int var8)
|
||||
{
|
||||
imageData[py*32+px] = new ColourRGBA(var5, var6, var7, var8).argb();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package codechicken.core.fluid;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.FluidTankInfo;
|
||||
import net.minecraftforge.fluids.IFluidTank;
|
||||
|
||||
public class ExtendedFluidTank implements IFluidTank
|
||||
{
|
||||
private FluidStack fluid;
|
||||
private boolean changeType;
|
||||
private int capacity;
|
||||
|
||||
public ExtendedFluidTank(FluidStack type, int capacity)
|
||||
{
|
||||
if(type == null)
|
||||
{
|
||||
fluid = new FluidStack(0, 0);
|
||||
changeType = true;
|
||||
}
|
||||
else
|
||||
fluid = FluidUtils.copy(type, 0);
|
||||
this.capacity = capacity;
|
||||
}
|
||||
|
||||
public ExtendedFluidTank(int capacity)
|
||||
{
|
||||
this(null, capacity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStack getFluid()
|
||||
{
|
||||
return fluid.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCapacity()
|
||||
{
|
||||
return capacity;
|
||||
}
|
||||
|
||||
public boolean canAccept(FluidStack type)
|
||||
{
|
||||
return type == null || type.fluidID <= 0 || (fluid.amount == 0 && changeType) || fluid.isFluidEqual(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int fill(FluidStack resource, boolean doFill)
|
||||
{
|
||||
if(resource == null || resource.fluidID <= 0)
|
||||
return 0;
|
||||
|
||||
if(!canAccept(resource))
|
||||
return 0;
|
||||
|
||||
int tofill = Math.min(getCapacity()-fluid.amount, resource.amount);
|
||||
if(doFill && tofill > 0)
|
||||
{
|
||||
if(!fluid.isFluidEqual(resource))
|
||||
fluid = FluidUtils.copy(resource, fluid.amount+tofill);
|
||||
else
|
||||
fluid.amount+=tofill;
|
||||
onLiquidChanged();
|
||||
}
|
||||
|
||||
return tofill;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStack drain(int maxDrain, boolean doDrain)
|
||||
{
|
||||
if(fluid.amount == 0 || maxDrain <= 0)
|
||||
return null;
|
||||
|
||||
int todrain = Math.min(maxDrain, fluid.amount);
|
||||
if(doDrain && todrain > 0)
|
||||
{
|
||||
fluid.amount-=todrain;
|
||||
onLiquidChanged();
|
||||
}
|
||||
return FluidUtils.copy(fluid, todrain);
|
||||
}
|
||||
|
||||
public FluidStack drain(FluidStack resource, boolean doDrain)
|
||||
{
|
||||
if (resource == null || !resource.isFluidEqual(fluid))
|
||||
return null;
|
||||
|
||||
return drain(resource.amount, doDrain);
|
||||
}
|
||||
|
||||
public void onLiquidChanged()
|
||||
{
|
||||
}
|
||||
|
||||
public void fromTag(NBTTagCompound tag)
|
||||
{
|
||||
fluid = FluidUtils.read(tag);
|
||||
}
|
||||
|
||||
public NBTTagCompound toTag()
|
||||
{
|
||||
return FluidUtils.write(fluid, new NBTTagCompound());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFluidAmount()
|
||||
{
|
||||
return fluid.amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidTankInfo getInfo()
|
||||
{
|
||||
return new FluidTankInfo(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package codechicken.core.fluid;
|
||||
|
||||
import codechicken.core.CommonUtils;
|
||||
import codechicken.lib.inventory.InventoryUtils;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
import net.minecraftforge.fluids.Fluid;
|
||||
import net.minecraftforge.fluids.FluidContainerRegistry;
|
||||
import net.minecraftforge.fluids.FluidRegistry;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.IFluidHandler;
|
||||
|
||||
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);
|
||||
|
||||
public static boolean fillTankWithContainer(IFluidHandler tank, EntityPlayer player)
|
||||
{
|
||||
ItemStack stack = player.getCurrentEquippedItem();
|
||||
FluidStack liquid = FluidContainerRegistry.getFluidForFilledItem(stack);
|
||||
|
||||
if(liquid == null)
|
||||
return false;
|
||||
|
||||
if(tank.fill(ForgeDirection.UNKNOWN, liquid, false) != liquid.amount && !player.capabilities.isCreativeMode)
|
||||
return false;
|
||||
|
||||
tank.fill(ForgeDirection.UNKNOWN, liquid, true);
|
||||
|
||||
if(!player.capabilities.isCreativeMode)
|
||||
InventoryUtils.consumeItem(player.inventory, player.inventory.currentItem);
|
||||
|
||||
player.inventoryContainer.detectAndSendChanges();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean emptyTankIntoContainer(IFluidHandler tank, EntityPlayer player, FluidStack tankLiquid)
|
||||
{
|
||||
ItemStack stack = player.getCurrentEquippedItem();
|
||||
|
||||
if(!FluidContainerRegistry.isEmptyContainer(stack))
|
||||
return false;
|
||||
|
||||
ItemStack filled = FluidContainerRegistry.fillFluidContainer(tankLiquid, stack);
|
||||
FluidStack liquid = FluidContainerRegistry.getFluidForFilledItem(filled);
|
||||
|
||||
if(liquid == null || filled == null)
|
||||
return false;
|
||||
|
||||
tank.drain(ForgeDirection.UNKNOWN, liquid.amount, true);
|
||||
|
||||
if(!player.capabilities.isCreativeMode)
|
||||
{
|
||||
if(stack.stackSize == 1)
|
||||
player.inventory.setInventorySlotContents(player.inventory.currentItem, filled);
|
||||
else if(player.inventory.addItemStackToInventory(filled))
|
||||
stack.stackSize--;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
player.inventoryContainer.detectAndSendChanges();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static FluidStack copy(FluidStack liquid, int quantity)
|
||||
{
|
||||
liquid = liquid.copy();
|
||||
liquid.amount = quantity;
|
||||
return liquid;
|
||||
}
|
||||
|
||||
public static FluidStack read(NBTTagCompound tag)
|
||||
{
|
||||
FluidStack stack = FluidStack.loadFluidStackFromNBT(tag);
|
||||
return stack != null ? stack : new FluidStack(0, 0);
|
||||
}
|
||||
|
||||
public static NBTTagCompound write(FluidStack fluid, NBTTagCompound tag)
|
||||
{
|
||||
return fluid == null || fluid.getFluid() == null ? new NBTTagCompound() : fluid.writeToNBT(new NBTTagCompound());
|
||||
}
|
||||
|
||||
public static int getLuminosity(FluidStack stack, double density)
|
||||
{
|
||||
Fluid fluid = stack.getFluid();
|
||||
if(fluid == null)
|
||||
return 0;
|
||||
int light = fluid.getLuminosity(stack);
|
||||
if(fluid.isGaseous())
|
||||
light=(int)(light*density);
|
||||
return light;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package codechicken.core.fluid;
|
||||
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.IFluidHandler;
|
||||
|
||||
public class TankAccess
|
||||
{
|
||||
public IFluidHandler tank;
|
||||
public ForgeDirection side;
|
||||
|
||||
public TankAccess(IFluidHandler tank, ForgeDirection side)
|
||||
{
|
||||
this.tank = tank;
|
||||
this.side = side;
|
||||
}
|
||||
|
||||
public TankAccess(IFluidHandler tank, int side)
|
||||
{
|
||||
this(tank, ForgeDirection.getOrientation(side));
|
||||
}
|
||||
|
||||
public int fill(FluidStack resource, boolean doFill)
|
||||
{
|
||||
return tank.fill(side, resource, doFill);
|
||||
}
|
||||
|
||||
public FluidStack drain(int maxDrain, boolean doDrain)
|
||||
{
|
||||
return tank.drain(side, maxDrain, doDrain);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
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;
|
||||
public boolean visible = true;
|
||||
|
||||
public GuiCCButton(int x, int y, int width, int height, String text)
|
||||
{
|
||||
super(x, y, width, height);
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public void setText(String s)
|
||||
{
|
||||
text = s;
|
||||
}
|
||||
|
||||
public boolean isEnabled()
|
||||
{
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean b)
|
||||
{
|
||||
isEnabled = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(int x, int y, int button)
|
||||
{
|
||||
if(isEnabled && pointInside(x, y) && actionCommand != null)
|
||||
{
|
||||
sendAction(actionCommand, button);
|
||||
Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mousex, int mousey, float frame)
|
||||
{
|
||||
if(!visible)
|
||||
return;
|
||||
|
||||
renderEngine.bindTexture(guiTex);
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
boolean mouseover = pointInside(mousex, mousey);
|
||||
int state = !isEnabled ? 0 : mouseover ? 2 : 1;
|
||||
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 + width / 2, y + height / 2, 200 - width / 2, 46 + state * 20 + 20 - height / 2, width / 2, height / 2);//bottom right
|
||||
|
||||
drawCenteredString(fontRenderer, text, x + width / 2, y + (height - 8) / 2, getTextColour(mousex, mousey));
|
||||
}
|
||||
|
||||
public int getTextColour(int mousex, int mousey)
|
||||
{
|
||||
return !isEnabled ? 0xFFA0A0A0 : pointInside(mousex, mousey) ? 0xFFFFFFA0 : 0xFFE0E0E0;
|
||||
}
|
||||
|
||||
public GuiCCButton setActionCommand(String string)
|
||||
{
|
||||
actionCommand = string;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
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;
|
||||
|
||||
public int maxStringLength;
|
||||
public int cursorCounter;
|
||||
public String actionCommand;
|
||||
|
||||
private String allowedCharacters;
|
||||
|
||||
public GuiCCTextField(int x, int y, int width, int height, String text)
|
||||
{
|
||||
super(x, y, width, height);
|
||||
isFocused = false;
|
||||
isEnabled = true;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public GuiCCTextField setActionCommand(String s)
|
||||
{
|
||||
actionCommand = s;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setText(String s)
|
||||
{
|
||||
if(s.equals(text))
|
||||
return;
|
||||
|
||||
String oldText = text;
|
||||
text = s;
|
||||
onTextChanged(oldText);
|
||||
}
|
||||
|
||||
public void onTextChanged(String oldText)
|
||||
{
|
||||
}
|
||||
|
||||
public final String getText()
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
public final boolean isEnabled()
|
||||
{
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean b)
|
||||
{
|
||||
isEnabled = b;
|
||||
if(!isEnabled && isFocused)
|
||||
setFocused(false);
|
||||
}
|
||||
|
||||
public final boolean isFocused()
|
||||
{
|
||||
return isFocused;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update()
|
||||
{
|
||||
cursorCounter++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(char c, int keycode)
|
||||
{
|
||||
if(!isEnabled || !isFocused)
|
||||
return;
|
||||
|
||||
/*if(c == '\t')//tab
|
||||
{
|
||||
parentGuiScreen.selectNextField();
|
||||
}*/
|
||||
if(c == '\026')//paste
|
||||
{
|
||||
String s = GuiScreen.getClipboardString();
|
||||
if(s == null || s.equals(""))
|
||||
return;
|
||||
|
||||
for(int i = 0; i < s.length(); i++)
|
||||
{
|
||||
if(text.length() == maxStringLength)
|
||||
return;
|
||||
|
||||
char tc = s.charAt(i);
|
||||
if(canAddChar(tc))
|
||||
setText(text + tc);
|
||||
}
|
||||
}
|
||||
if(keycode == Keyboard.KEY_RETURN)
|
||||
{
|
||||
setFocused(false);
|
||||
sendAction(actionCommand, getText());
|
||||
}
|
||||
|
||||
if(keycode == Keyboard.KEY_BACK && text.length() > 0)
|
||||
setText(text.substring(0, text.length() - 1));
|
||||
|
||||
if((text.length() < maxStringLength || maxStringLength == 0) && canAddChar(c))
|
||||
setText(text + c);
|
||||
}
|
||||
|
||||
public boolean canAddChar(char c)
|
||||
{
|
||||
return allowedCharacters == null ? ChatAllowedCharacters.isAllowedCharacter(c) : allowedCharacters.indexOf(c) >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(int x, int y, int button)
|
||||
{
|
||||
if(isEnabled && pointInside(x, y))
|
||||
{
|
||||
setFocused(true);
|
||||
if(button == 1)
|
||||
setText("");
|
||||
}
|
||||
else
|
||||
setFocused(false);
|
||||
}
|
||||
|
||||
public void setFocused(boolean focus)
|
||||
{
|
||||
if(focus == isFocused)
|
||||
return;
|
||||
isFocused = focus;
|
||||
onFocusChanged();
|
||||
}
|
||||
|
||||
public void onFocusChanged()
|
||||
{
|
||||
if(isFocused)
|
||||
cursorCounter = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int i, int j, float f)
|
||||
{
|
||||
drawBackground();
|
||||
drawText();
|
||||
}
|
||||
|
||||
public void drawBackground()
|
||||
{
|
||||
drawRect(x - 1, y - 1, x + width + 1, y + height + 1, 0xffa0a0a0);
|
||||
drawRect(x, y, x + width, y + height, 0xff000000);
|
||||
}
|
||||
|
||||
public String getDrawText()
|
||||
{
|
||||
String s = getText();
|
||||
if(isEnabled && isFocused && (cursorCounter / 6) % 2 == 0)
|
||||
s+="_";
|
||||
return s;
|
||||
}
|
||||
|
||||
public void drawText()
|
||||
{
|
||||
drawString(fontRenderer, getDrawText(), x + 4, y + height/2 - 4, getTextColour());
|
||||
}
|
||||
|
||||
public int getTextColour()
|
||||
{
|
||||
return isEnabled ? 0xe0e0e0 : 0x707070;
|
||||
}
|
||||
|
||||
public GuiCCTextField setMaxStringLength(int i)
|
||||
{
|
||||
maxStringLength = i;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GuiCCTextField setAllowedCharacters(String s)
|
||||
{
|
||||
allowedCharacters = s;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package codechicken.core.gui;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
|
||||
public class GuiScreenWidget extends GuiScreen implements IGuiActionListener
|
||||
{
|
||||
public ArrayList<GuiWidget> widgets = new ArrayList<GuiWidget>();
|
||||
public int xSize, ySize, guiTop, guiLeft;
|
||||
|
||||
public GuiScreenWidget()
|
||||
{
|
||||
this(176, 166);
|
||||
}
|
||||
|
||||
public GuiScreenWidget(int xSize, int ySize)
|
||||
{
|
||||
super();
|
||||
this.xSize = xSize;
|
||||
this.ySize = ySize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui()
|
||||
{
|
||||
guiTop = (height - ySize) / 2;
|
||||
guiLeft = (width - xSize) / 2;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
initGui();
|
||||
widgets.clear();
|
||||
addWidgets();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWorldAndResolution(Minecraft mc, int i, int j)
|
||||
{
|
||||
boolean init = this.mc == null;
|
||||
super.setWorldAndResolution(mc, i, j);
|
||||
if(init)
|
||||
addWidgets();
|
||||
}
|
||||
|
||||
public void add(GuiWidget widget)
|
||||
{
|
||||
widgets.add(widget);
|
||||
widget.onAdded(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mousex, int mousey, float f)
|
||||
{
|
||||
GL11.glTranslated(guiLeft, guiTop, 0);
|
||||
drawBackground();
|
||||
for(GuiWidget widget : widgets)
|
||||
widget.draw(mousex-guiLeft, mousey-guiTop, f);
|
||||
drawForeground();
|
||||
GL11.glTranslated(-guiLeft, -guiTop, 0);
|
||||
}
|
||||
|
||||
public void drawBackground()
|
||||
{
|
||||
}
|
||||
|
||||
public void drawForeground()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClicked(int x, int y, int button)
|
||||
{
|
||||
super.mouseClicked(x, y, button);
|
||||
for(GuiWidget widget : widgets)
|
||||
widget.mouseClicked(x-guiLeft, y-guiTop, button);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseMovedOrUp(int x, int y, int button)
|
||||
{
|
||||
super.mouseMovedOrUp(x, y, button);
|
||||
for(GuiWidget widget : widgets)
|
||||
widget.mouseMovedOrUp(x-guiLeft, y-guiTop, button);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClickMove(int x, int y, int button, long time)
|
||||
{
|
||||
super.mouseClickMove(x, y, button, time);
|
||||
for(GuiWidget widget : widgets)
|
||||
widget.mouseDragged(x-guiLeft, y-guiTop, button, time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateScreen()
|
||||
{
|
||||
super.updateScreen();
|
||||
if(mc.currentScreen == this)
|
||||
for(GuiWidget widget : widgets)
|
||||
widget.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(char c, int keycode)
|
||||
{
|
||||
super.keyTyped(c, keycode);
|
||||
for(GuiWidget widget : widgets)
|
||||
widget.keyTyped(c, keycode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMouseInput()
|
||||
{
|
||||
super.handleMouseInput();
|
||||
int i = Mouse.getEventDWheel();
|
||||
if(i != 0)
|
||||
{
|
||||
Point p = GuiDraw.getMousePosition();
|
||||
int scroll = i > 0 ? 1 : -1;
|
||||
for(GuiWidget widget : widgets)
|
||||
widget.mouseScrolled(p.x, p.y, scroll);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(String ident, Object... params)
|
||||
{
|
||||
}
|
||||
|
||||
public void addWidgets()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
package codechicken.core.gui;
|
||||
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import codechicken.lib.math.MathHelper;
|
||||
|
||||
public abstract class GuiScrollSlot extends GuiWidget
|
||||
{
|
||||
protected GuiButton scrollupbutton;
|
||||
protected GuiButton scrolldownbutton;
|
||||
protected String actionCommand;
|
||||
|
||||
protected int scrollclicky = -1;
|
||||
protected float scrollpercent;
|
||||
protected int scrollmousey;
|
||||
protected float percentscrolled;
|
||||
|
||||
protected int lastslotclicked = -1;
|
||||
protected int lastbuttonclicked = -1;
|
||||
protected long lastslotclicktime;
|
||||
|
||||
public boolean focused;
|
||||
|
||||
public int contentx;
|
||||
public int contenty;
|
||||
public int contentheight;
|
||||
public boolean smoothScroll = true;
|
||||
|
||||
public GuiScrollSlot(int x, int y, int width, int height)
|
||||
{
|
||||
super(x, y, width, height);
|
||||
setContentSize(x+3, y+2, height-2);
|
||||
}
|
||||
|
||||
public GuiScrollSlot setActionCommand(String s)
|
||||
{
|
||||
actionCommand = s;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setSmoothScroll(boolean b)
|
||||
{
|
||||
smoothScroll = b;
|
||||
}
|
||||
|
||||
public void setSize(int x, int y, int width, int height)
|
||||
{
|
||||
int cx = contentx-this.x;
|
||||
int cy = contenty-this.y;
|
||||
int ch = height-contentheight;
|
||||
super.setSize(x, y, width, height);
|
||||
|
||||
setContentSize(x+cx, y+cy, height-ch);
|
||||
}
|
||||
|
||||
public void setContentSize(int x, int y, int h)
|
||||
{
|
||||
this.contentx = x;
|
||||
this.contenty = y;
|
||||
this.contentheight = h;
|
||||
}
|
||||
|
||||
public void registerButtons(GuiButton up, GuiButton down, String selectionCommand)
|
||||
{
|
||||
scrollupbutton = up;
|
||||
scrolldownbutton = down;
|
||||
actionCommand = selectionCommand;
|
||||
}
|
||||
|
||||
public abstract int getSlotHeight();
|
||||
|
||||
protected abstract int getNumSlots();
|
||||
|
||||
public abstract void selectNext();
|
||||
|
||||
public abstract void selectPrev();
|
||||
|
||||
protected abstract void slotClicked(int slot, int button, int mousex, int mousey, boolean doubleclick);
|
||||
|
||||
protected abstract boolean isSlotSelected(int slot);
|
||||
|
||||
protected abstract void drawSlot(int slot, int x, int y, int mousex, int mousey, boolean selected, float frame);
|
||||
|
||||
protected void unfocus()
|
||||
{
|
||||
}
|
||||
|
||||
public void setFocused(boolean focus)
|
||||
{
|
||||
focused = focus;
|
||||
if(!focused)
|
||||
unfocus();
|
||||
}
|
||||
|
||||
public void scrollUp()
|
||||
{
|
||||
scroll(-5);
|
||||
}
|
||||
|
||||
public void scrollDown()
|
||||
{
|
||||
scroll(5);
|
||||
}
|
||||
|
||||
public void scroll(int i)
|
||||
{
|
||||
percentscrolled += i/(float)contentheight * 100;
|
||||
calculatePercentScrolled();
|
||||
}
|
||||
|
||||
public int totalContentHeight()
|
||||
{
|
||||
return getNumSlots() * getSlotHeight();
|
||||
}
|
||||
|
||||
public int getSlotY(int slot)
|
||||
{
|
||||
int scrolledPixels = (int)((totalContentHeight() - contentheight) * percentscrolled + 0.5);
|
||||
if(!smoothScroll)
|
||||
scrolledPixels = (int)(scrolledPixels/(double)getSlotHeight()+0.5)*getSlotHeight();
|
||||
return contenty-scrolledPixels+slot*getSlotHeight();
|
||||
}
|
||||
|
||||
public int getClickedSlot(int mousey)
|
||||
{
|
||||
if(mousey < contenty || mousey >= contenty+contentheight)
|
||||
return -1;
|
||||
|
||||
for(int slot = 0; slot < getNumSlots(); slot++)
|
||||
{
|
||||
int sloty = getSlotY(slot);
|
||||
if(mousey >= sloty && mousey < sloty + getSlotHeight())
|
||||
return slot;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getScrollBarWidth()
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
public int getScrollBarHeight()
|
||||
{
|
||||
int sbarh = (int)((contentheight / (float)totalContentHeight()) * height);
|
||||
if(sbarh > height)
|
||||
{
|
||||
return height;
|
||||
}
|
||||
else if(sbarh < height / 15)
|
||||
{
|
||||
return height / 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
return sbarh;
|
||||
}
|
||||
}
|
||||
|
||||
public void calculatePercentScrolled()
|
||||
{
|
||||
int barempty = height - getScrollBarHeight();
|
||||
if(scrollclicky >= 0)
|
||||
{
|
||||
int scrolldiff = scrollmousey - scrollclicky;
|
||||
percentscrolled = scrolldiff / (float)barempty + scrollpercent;
|
||||
}
|
||||
percentscrolled = (float) MathHelper.clip(percentscrolled, 0, 1);
|
||||
}
|
||||
|
||||
public void showSlot(int slot)
|
||||
{
|
||||
int sloty = getSlotY(slot);
|
||||
if(sloty+getSlotHeight() > contenty+contentheight)
|
||||
{
|
||||
int diff = sloty-(contenty+contentheight-getSlotHeight());
|
||||
percentscrolled += diff/(double)(totalContentHeight() - contentheight);
|
||||
calculatePercentScrolled();
|
||||
}
|
||||
else if(sloty < contenty)
|
||||
{
|
||||
int diff = contenty-sloty;
|
||||
percentscrolled -= diff/(double)(totalContentHeight() - contentheight);
|
||||
calculatePercentScrolled();
|
||||
}
|
||||
}
|
||||
|
||||
public void processMouse(int mousex, int mousey)
|
||||
{
|
||||
if(scrollclicky >= 0)
|
||||
{
|
||||
int scrolldiff = mousey - scrollclicky;
|
||||
int barupallowed = (int)((height - getScrollBarHeight()) * scrollpercent + 0.5);
|
||||
int bardownallowed = (height - getScrollBarHeight()) - barupallowed;
|
||||
|
||||
if(-scrolldiff > barupallowed)
|
||||
scrollmousey = scrollclicky - barupallowed;
|
||||
else if(scrolldiff > bardownallowed)
|
||||
scrollmousey = scrollclicky + bardownallowed;
|
||||
else
|
||||
scrollmousey = mousey;
|
||||
|
||||
calculatePercentScrolled();
|
||||
}
|
||||
}
|
||||
|
||||
public void actionPerformed(GuiButton guibutton)
|
||||
{
|
||||
if(!guibutton.enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(scrollupbutton != null && guibutton.id == scrollupbutton.id)
|
||||
{
|
||||
scrollUp();
|
||||
}
|
||||
else if(scrolldownbutton != null && guibutton.id == scrolldownbutton.id)
|
||||
{
|
||||
scrollDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(int mousex, int mousey, int button)
|
||||
{
|
||||
boolean needsfocus = (mousex >= x && mousex < x + width &&
|
||||
mousey >= y && mousey <= y + height);
|
||||
if(needsfocus != focused)
|
||||
{
|
||||
setFocused(needsfocus);
|
||||
}
|
||||
|
||||
int barempty = height - getScrollBarHeight();
|
||||
int sbarx = x + width - getScrollBarWidth();
|
||||
int sbary = y + (int)(barempty * percentscrolled + 0.5);
|
||||
|
||||
if(button == 0 &&
|
||||
getScrollBarHeight() < height && //the scroll bar can move (not full length)
|
||||
mousex >= sbarx && mousex <= x + width &&
|
||||
mousey >= y && mousey <= y + height)//in the scroll pane
|
||||
{
|
||||
if(mousey < sbary)
|
||||
{
|
||||
percentscrolled = (mousey - y) / (float)barempty;
|
||||
calculatePercentScrolled();
|
||||
}
|
||||
else if(mousey > sbary + getScrollBarHeight())
|
||||
{
|
||||
percentscrolled = (mousey - y - getScrollBarHeight() + 1) / (float)barempty;
|
||||
calculatePercentScrolled();
|
||||
}
|
||||
else
|
||||
{
|
||||
scrollclicky = mousey;
|
||||
scrollpercent = percentscrolled;
|
||||
scrollmousey = mousey;
|
||||
}
|
||||
}
|
||||
else if(mousex >= contentx && mousex < sbarx &&
|
||||
mousey >= contenty && mousey <= contenty + contentheight)//in the box
|
||||
{
|
||||
int slot = getClickedSlot(mousey);
|
||||
if(slot >= 0)
|
||||
slotClicked(slot, button, mousex-contentx, mousey-getSlotY(slot),
|
||||
slot == lastslotclicked && button == lastbuttonclicked && System.currentTimeMillis() - lastslotclicktime < 500);
|
||||
|
||||
lastslotclicked = slot;
|
||||
lastbuttonclicked = button;
|
||||
lastslotclicktime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMovedOrUp(int mousex, int mousey, int button)
|
||||
{
|
||||
if(scrollclicky >= 0 && button == 0)//we were scrolling and we released mouse
|
||||
scrollclicky = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(char c, int keycode)
|
||||
{
|
||||
if(!focused)
|
||||
return;
|
||||
|
||||
if(keycode == Keyboard.KEY_UP)
|
||||
selectPrev();
|
||||
if(keycode == Keyboard.KEY_DOWN)
|
||||
selectNext();
|
||||
if(keycode == Keyboard.KEY_RETURN && actionCommand != null)
|
||||
sendAction(actionCommand);
|
||||
}
|
||||
|
||||
public void drawSlotBox(float frame)
|
||||
{
|
||||
drawRect(x, y, x + width, y + height, 0xff000000);
|
||||
}
|
||||
|
||||
public void drawBackground(float frame)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void drawOverlay(float frame)
|
||||
{
|
||||
//outlines
|
||||
drawRect(x, y - 1, x + width, y, 0xffa0a0a0);//top
|
||||
drawRect(x, y + height, x + width, y + height + 1, 0xffa0a0a0);//bottom
|
||||
drawRect(x - 1, y - 1, x, y + height + 1, 0xffa0a0a0);//left
|
||||
drawRect(x + width, y - 1, x + width + 1, y + height + 1, 0xffa0a0a0);//right
|
||||
}
|
||||
|
||||
public void drawScrollBar(float frame)
|
||||
{
|
||||
int sbarw = getScrollBarWidth();
|
||||
int sbarh = getScrollBarHeight();
|
||||
int sbarx = x + width - sbarw;
|
||||
int sbary = y + (int)((height - sbarh) * percentscrolled + 0.4999);
|
||||
|
||||
drawRect(sbarx, sbary, sbarx+sbarw, sbary+sbarh, 0xFF8B8B8B);//corners
|
||||
drawRect(sbarx, sbary, sbarx+sbarw-1, sbary+sbarh - 1, 0xFFF0F0F0);//topleft up
|
||||
drawRect(sbarx + 1, sbary + 1, sbarx+sbarw, sbary+sbarh, 0xFF555555);//bottom right down
|
||||
drawRect(sbarx + 1, sbary + 1, sbarx+sbarw-1, sbary+sbarh - 1, 0xFFC6C6C6);//scrollbar
|
||||
|
||||
if(drawLineGuide())
|
||||
drawRect(sbarx - 1, y, sbarx, y + height, 0xFF808080);//lineguide
|
||||
}
|
||||
|
||||
public boolean drawLineGuide()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void drawSlots(int mousex, int mousey, float frame)
|
||||
{
|
||||
for(int slot = 0; slot < getNumSlots(); slot++)
|
||||
{
|
||||
int sloty = getSlotY(slot);
|
||||
if(sloty > contenty - getSlotHeight() && sloty < contenty + contentheight)
|
||||
drawSlot(slot, contentx, sloty, mousex-contentx, mousey-sloty, isSlotSelected(slot), frame);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(int x, int y, int button, long time)
|
||||
{
|
||||
processMouse(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mousex, int mousey, float frame)
|
||||
{
|
||||
drawBackground(frame);
|
||||
drawSlotBox(frame);
|
||||
drawSlots(mousex, mousey, frame);
|
||||
drawOverlay(frame);
|
||||
drawScrollBar(frame);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package codechicken.core.gui;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
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;
|
||||
public TextureManager renderEngine;
|
||||
public FontRenderer fontRenderer;
|
||||
|
||||
public int x;
|
||||
public int y;
|
||||
public int width;
|
||||
public int height;
|
||||
|
||||
public GuiWidget(int x, int y, int width, int height)
|
||||
{
|
||||
setSize(x, y, width, height);
|
||||
}
|
||||
|
||||
public void setSize(int x, int y, int width, int height)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public boolean pointInside(int px, int py)
|
||||
{
|
||||
return px >= x && px < x + width && py >= y && py < y + height;
|
||||
}
|
||||
|
||||
public void sendAction(String actionCommand, Object... params)
|
||||
{
|
||||
sendAction(parentScreen, actionCommand, params);
|
||||
}
|
||||
|
||||
public static void sendAction(GuiScreen screen, String actionCommand, Object... params)
|
||||
{
|
||||
if(actionCommand != null && screen instanceof IGuiActionListener)
|
||||
((IGuiActionListener) screen).actionPerformed(actionCommand, params);
|
||||
}
|
||||
|
||||
public void mouseClicked(int x, int y, int button)
|
||||
{
|
||||
}
|
||||
|
||||
public void mouseMovedOrUp(int x, int y, int button)
|
||||
{
|
||||
}
|
||||
|
||||
public void mouseDragged(int x, int y, int button, long time)
|
||||
{
|
||||
}
|
||||
|
||||
public void update()
|
||||
{
|
||||
}
|
||||
|
||||
public void draw(int mousex, int mousey, float frame)
|
||||
{
|
||||
}
|
||||
|
||||
public void keyTyped(char c, int keycode)
|
||||
{
|
||||
}
|
||||
|
||||
public void mouseScrolled(int x, int y, int scroll)
|
||||
{
|
||||
}
|
||||
|
||||
public void onAdded(GuiScreen s)
|
||||
{
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
parentScreen = s;
|
||||
renderEngine = mc.renderEngine;
|
||||
fontRenderer = mc.fontRenderer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package codechicken.core.gui;
|
||||
|
||||
public interface IGuiActionListener
|
||||
{
|
||||
public void actionPerformed(String actionCommand, Object... params);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package codechicken.core.internal;
|
||||
|
||||
import codechicken.core.CCUpdateChecker;
|
||||
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import cpw.mods.fml.common.gameevent.TickEvent;
|
||||
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void renderTick(TickEvent.RenderTickEvent event) {
|
||||
if(event.phase == Phase.START)
|
||||
renderFrame = event.renderTickTime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
package codechicken.core.inventory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import codechicken.lib.packet.PacketCustom;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.inventory.ICrafting;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.inventory.Slot;
|
||||
|
||||
public abstract class ContainerExtended extends Container implements ICrafting
|
||||
{
|
||||
public LinkedList<EntityPlayerMP> playerCrafters = new LinkedList<EntityPlayerMP>();
|
||||
|
||||
public ContainerExtended()
|
||||
{
|
||||
crafters.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCraftingToCrafters(ICrafting icrafting)
|
||||
{
|
||||
if(icrafting instanceof EntityPlayerMP)
|
||||
{
|
||||
playerCrafters.add((EntityPlayerMP) icrafting);
|
||||
sendContainerAndContentsToPlayer(this, getInventory(), Arrays.asList((EntityPlayerMP) icrafting));
|
||||
detectAndSendChanges();
|
||||
}
|
||||
else
|
||||
super.addCraftingToCrafters(icrafting);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* May be called from a client packet handler to handle additional info
|
||||
*/
|
||||
public void handleOutputPacket(PacketCustom packet)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* May be called from a server packet handler to handle additional info
|
||||
*/
|
||||
public void handleInputPacket(PacketCustom packet)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* May be called from a server packet handler to handle client input
|
||||
*/
|
||||
public void handleGuiChange(int ID, int value)
|
||||
{
|
||||
}
|
||||
|
||||
public void sendProgressBarUpdate(int barID, int value)
|
||||
{
|
||||
for(ICrafting crafting : (List<ICrafting>)crafters)
|
||||
crafting.sendProgressBarUpdate(this, barID, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package codechicken.core.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>();
|
||||
|
||||
public abstract PacketCustom createSyncPacket();
|
||||
|
||||
@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 handleOutputPacket(PacketCustom packet)
|
||||
{
|
||||
syncVars.get(packet.readUByte()).readChange(packet);
|
||||
}
|
||||
|
||||
public List<IContainerSyncVar> getSyncedVars()
|
||||
{
|
||||
return Collections.unmodifiableList(syncVars);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package codechicken.core.inventory;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.core.gui.GuiWidget;
|
||||
import codechicken.core.gui.IGuiActionListener;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.inventory.Container;
|
||||
|
||||
public class GuiContainerWidget extends GuiContainer implements IGuiActionListener
|
||||
{
|
||||
public ArrayList<GuiWidget> widgets = new ArrayList<GuiWidget>();
|
||||
|
||||
public GuiContainerWidget(Container inventorySlots)
|
||||
{
|
||||
this(inventorySlots, 176, 166);
|
||||
}
|
||||
|
||||
public GuiContainerWidget(Container inventorySlots, int xSize, int ySize)
|
||||
{
|
||||
super(inventorySlots);
|
||||
this.xSize = xSize;
|
||||
this.ySize = ySize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWorldAndResolution(Minecraft mc, int i, int j)
|
||||
{
|
||||
boolean init = this.mc == null;
|
||||
super.setWorldAndResolution(mc, i, j);
|
||||
if(init)
|
||||
addWidgets();
|
||||
}
|
||||
|
||||
public void add(GuiWidget widget)
|
||||
{
|
||||
widgets.add(widget);
|
||||
widget.onAdded(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawGuiContainerBackgroundLayer(float f, int mousex, int mousey)
|
||||
{
|
||||
GL11.glTranslated(guiLeft, guiTop, 0);
|
||||
drawBackground();
|
||||
for(GuiWidget widget : widgets)
|
||||
widget.draw(mousex-guiLeft, mousey-guiTop, f);
|
||||
|
||||
GL11.glTranslated(-guiLeft, -guiTop, 0);
|
||||
}
|
||||
|
||||
public void drawBackground()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClicked(int x, int y, int button)
|
||||
{
|
||||
super.mouseClicked(x, y, button);
|
||||
for(GuiWidget widget : widgets)
|
||||
widget.mouseClicked(x-guiLeft, y-guiTop, button);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseMovedOrUp(int x, int y, int button)
|
||||
{
|
||||
super.mouseMovedOrUp(x, y, button);
|
||||
for(GuiWidget widget : widgets)
|
||||
widget.mouseMovedOrUp(x-guiLeft, y-guiTop, button);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClickMove(int x, int y, int button, long time)
|
||||
{
|
||||
super.mouseClickMove(x, y, button, time);
|
||||
for(GuiWidget widget : widgets)
|
||||
widget.mouseDragged(x-guiLeft, y-guiTop, button, time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateScreen()
|
||||
{
|
||||
super.updateScreen();
|
||||
if(mc.currentScreen == this)
|
||||
for(GuiWidget widget : widgets)
|
||||
widget.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(char c, int keycode)
|
||||
{
|
||||
super.keyTyped(c, keycode);
|
||||
for(GuiWidget widget : widgets)
|
||||
widget.keyTyped(c, keycode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMouseInput()
|
||||
{
|
||||
super.handleMouseInput();
|
||||
int i = Mouse.getEventDWheel();
|
||||
if(i != 0)
|
||||
{
|
||||
Point p = GuiDraw.getMousePosition();
|
||||
int scroll = i > 0 ? 1 : -1;
|
||||
for(GuiWidget widget : widgets)
|
||||
widget.mouseScrolled(p.x, p.y, scroll);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(String ident, Object... params)
|
||||
{
|
||||
}
|
||||
|
||||
public void addWidgets()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed() {
|
||||
super.onGuiClosed();
|
||||
mc = null;
|
||||
widgets.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package codechicken.core.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,34 @@
|
||||
package codechicken.core.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,122 @@
|
||||
package codechicken.core.inventory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public class MappedInventoryAccess implements IInventory
|
||||
{
|
||||
public static interface InventoryAccessor
|
||||
{
|
||||
public boolean canAccessSlot(int slot);
|
||||
}
|
||||
|
||||
public static final InventoryAccessor fullAccess = new InventoryAccessor()
|
||||
{
|
||||
public boolean canAccessSlot(int slot) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private ArrayList<Integer> slotMap = new ArrayList<Integer>();
|
||||
private IInventory inv;
|
||||
private ArrayList<InventoryAccessor> accessors = new ArrayList<MappedInventoryAccess.InventoryAccessor>();
|
||||
|
||||
public MappedInventoryAccess(IInventory inv, InventoryAccessor... accessors) {
|
||||
this.inv = inv;
|
||||
|
||||
for (InventoryAccessor a : accessors)
|
||||
this.accessors.add(a);
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
slotMap.clear();
|
||||
nextslot:
|
||||
for (int i = 0; i < inv.getSizeInventory(); i++) {
|
||||
for (InventoryAccessor a : accessors)
|
||||
if (!a.canAccessSlot(i))
|
||||
continue nextslot;
|
||||
|
||||
slotMap.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSizeInventory() {
|
||||
return slotMap.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackInSlot(int slot) {
|
||||
return inv.getStackInSlot(slotMap.get(slot));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack decrStackSize(int slot, int amount) {
|
||||
return inv.decrStackSize(slotMap.get(slot), amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackInSlotOnClosing(int slot) {
|
||||
return inv.getStackInSlotOnClosing(slotMap.get(slot));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInventorySlotContents(int slot, ItemStack stack) {
|
||||
inv.setInventorySlotContents(slotMap.get(slot), stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInventoryName() {
|
||||
return inv.getInventoryName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInventoryStackLimit() {
|
||||
return inv.getInventoryStackLimit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDirty() {
|
||||
inv.markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseableByPlayer(EntityPlayer player) {
|
||||
return inv.isUseableByPlayer(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory() {
|
||||
inv.openInventory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory() {
|
||||
inv.closeInventory();
|
||||
}
|
||||
|
||||
public void addAccessor(InventoryAccessor accessor) {
|
||||
accessors.add(accessor);
|
||||
reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemValidForSlot(int slot, ItemStack stack) {
|
||||
return inv.isItemValidForSlot(slotMap.get(slot), stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomInventoryName() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<InventoryAccessor> accessors() {
|
||||
return accessors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package codechicken.core.inventory;
|
||||
|
||||
import codechicken.lib.inventory.InventoryUtils;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public class SlotDummy extends SlotHandleClicks
|
||||
{
|
||||
public final int stackLimit;
|
||||
public SlotDummy(IInventory inv, int slot, int x, int y)
|
||||
{
|
||||
this(inv, slot, x, y, 64);
|
||||
}
|
||||
|
||||
public SlotDummy(IInventory inv, int slot, int x, int y, int limit)
|
||||
{
|
||||
super(inv, slot, x, y);
|
||||
stackLimit = limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack slotClick(ContainerExtended container, EntityPlayer player, int button, int modifier)
|
||||
{
|
||||
ItemStack held = player.inventory.getItemStack();
|
||||
boolean shift = modifier == 1;
|
||||
slotClick(held, button, shift);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void slotClick(ItemStack held, int button, boolean shift)
|
||||
{
|
||||
ItemStack tstack = getStack();
|
||||
if(held != null && (tstack == null || !InventoryUtils.canStack(held, tstack)))
|
||||
{
|
||||
int quantity = Math.min(held.stackSize, stackLimit);
|
||||
if(shift)
|
||||
quantity = Math.min(stackLimit, held.getMaxStackSize()*16);
|
||||
if(button == 1)
|
||||
quantity = 1;
|
||||
putStack(InventoryUtils.copyStack(held, quantity));
|
||||
}
|
||||
else if(tstack != null)
|
||||
{
|
||||
int inc;
|
||||
if(held != null)
|
||||
{
|
||||
inc = button == 1 ? -held.stackSize : held.stackSize;
|
||||
if(shift)
|
||||
inc *= 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
inc = button == 1 ? -1 : 1;
|
||||
if(shift)
|
||||
inc *= 16;
|
||||
}
|
||||
int quantity = tstack.stackSize+inc;
|
||||
if(quantity <= 0)
|
||||
putStack(null);
|
||||
else
|
||||
putStack(InventoryUtils.copyStack(tstack, quantity));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putStack(ItemStack stack)
|
||||
{
|
||||
if(stack != null && stack.stackSize > stackLimit)
|
||||
stack = InventoryUtils.copyStack(stack, stackLimit);
|
||||
super.putStack(stack);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package codechicken.core.inventory;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public class SlotDummyOutput extends SlotHandleClicks
|
||||
{
|
||||
public SlotDummyOutput(IInventory inv, int slot, int x, int y)
|
||||
{
|
||||
super(inv, slot, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack slotClick(ContainerExtended container, EntityPlayer player, int button, int modifier)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package codechicken.core.inventory;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public abstract class SlotHandleClicks extends Slot
|
||||
{
|
||||
public SlotHandleClicks(IInventory inv, int slot, int x, int y)
|
||||
{
|
||||
super(inv, slot, x, y);
|
||||
}
|
||||
|
||||
public abstract ItemStack slotClick(ContainerExtended container, EntityPlayer player, int button, int modifier);
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
package codechicken.core.launch;
|
||||
|
||||
import java.awt.Desktop;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
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 codechicken.core.asm.*;
|
||||
import cpw.mods.fml.relauncher.CoreModManager;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
|
||||
import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
|
||||
import cpw.mods.fml.common.versioning.VersionParser;
|
||||
import cpw.mods.fml.relauncher.FMLInjectionData;
|
||||
import cpw.mods.fml.relauncher.IFMLCallHook;
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.TransformerExclusions;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@TransformerExclusions(value = {"codechicken.core.asm", "codechicken.obfuscator"})
|
||||
public class CodeChickenCorePlugin implements IFMLLoadingPlugin, IFMLCallHook
|
||||
{
|
||||
public static final String mcVersion = "[1.7.2]";
|
||||
|
||||
public static File minecraftDir;
|
||||
public static String currentMcVersion;
|
||||
public static Logger logger = LogManager.getLogger("CodeChickenCore");
|
||||
|
||||
public CodeChickenCorePlugin() {
|
||||
if (minecraftDir != null)
|
||||
return;//get called twice, once for 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);
|
||||
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]));
|
||||
} catch (Exception e) {
|
||||
System.err.println("Failed to inject MCPDeobfuscation Transformer");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void versionCheck(String reqVersion, String mod) {
|
||||
String mcVersion = (String) FMLInjectionData.data()[4];
|
||||
if (!VersionParser.parseRange(reqVersion).containsVersion(new DefaultArtifactVersion(mcVersion))) {
|
||||
String err = "This version of " + mod + " does not support minecraft version " + mcVersion;
|
||||
System.err.println(err);
|
||||
|
||||
JEditorPane ep = new JEditorPane("text/html",
|
||||
"<html>" +
|
||||
err +
|
||||
"<br>Remove it from your coremods folder and check <a href=\"http://www.minecraftforum.net/topic/909223-\">here</a> for updates" +
|
||||
"</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, "Fatal error", JOptionPane.ERROR_MESSAGE);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getASMTransformerClass() {
|
||||
versionCheck(mcVersion, "CodeChickenCore");
|
||||
return new String[]{
|
||||
"codechicken.lib.asm.ClassHeirachyManager",
|
||||
"codechicken.core.asm.InterfaceDependancyTransformer",
|
||||
"codechicken.core.asm.TweakTransformer",
|
||||
"codechicken.core.asm.DelegatedTransformer",
|
||||
"codechicken.core.asm.DefaultImplementationTransformer"};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessTransformerClass() {
|
||||
return "codechicken.core.asm.CodeChickenAccessTransformer";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModContainerClass() {
|
||||
return "codechicken.core.asm.CodeChickenCoreModContainer";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSetupClass() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectData(Map<String, Object> data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void call() {
|
||||
CodeChickenCoreModContainer.loadConfig();
|
||||
TweakTransformer.load();
|
||||
scanCodeChickenMods();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void scanCodeChickenMods() {
|
||||
File modsDir = new File(minecraftDir, "mods");
|
||||
for (File file : modsDir.listFiles())
|
||||
scanMod(file);
|
||||
File versionModsDir = new File(minecraftDir, "mods/" + currentMcVersion);
|
||||
if (versionModsDir.exists())
|
||||
for (File file : versionModsDir.listFiles())
|
||||
scanMod(file);
|
||||
}
|
||||
|
||||
private void scanMod(File file) {
|
||||
if (!file.getName().endsWith(".jar") && !file.getName().endsWith(".zip"))
|
||||
return;
|
||||
|
||||
try {
|
||||
JarFile jar = new JarFile(file);
|
||||
try {
|
||||
Manifest manifest = jar.getManifest();
|
||||
if (manifest == null)
|
||||
return;
|
||||
Attributes attr = manifest.getMainAttributes();
|
||||
if (attr == null)
|
||||
return;
|
||||
|
||||
String mapFile = attr.getValue("AccessTransformer");
|
||||
if (mapFile != null)
|
||||
CodeChickenAccessTransformer.addTransformerMap(mapFile);
|
||||
String transformer = attr.getValue("CCTransformer");
|
||||
if (transformer != null)
|
||||
DelegatedTransformer.addTransformer(transformer, jar, file);
|
||||
} finally {
|
||||
jar.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("CodeChickenCore: Failed to read jar file: " + file.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,601 @@
|
||||
package codechicken.core.launch;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
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 net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
import sun.misc.URLClassPath;
|
||||
import sun.net.util.URLUtil;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import javax.swing.event.HyperlinkListener;
|
||||
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.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/**
|
||||
* For autodownloading stuff.
|
||||
* This is really unoriginal, mostly ripped off FML, credits to cpw.
|
||||
*/
|
||||
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);
|
||||
|
||||
void updateProgress(int fullLength);
|
||||
|
||||
boolean shouldStopIt();
|
||||
|
||||
void updateProgressString(String string, Object... data);
|
||||
|
||||
Object makeDialog();
|
||||
|
||||
void showErrorDialog(String name, String url);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProgressString(String progressUpdate, Object... data) {
|
||||
//FMLLog.finest(progressUpdate, data);
|
||||
if (currentActivity != null)
|
||||
currentActivity.setText(String.format(progressUpdate, data));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetProgress(int sizeGuess) {
|
||||
if (progress != null)
|
||||
progress.getModel().setRangeProperties(0, 0, 0, sizeGuess, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProgress(int fullLength) {
|
||||
if (progress != null)
|
||||
progress.getModel().setValue(fullLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPokeThread(Thread currentThread) {
|
||||
this.pokeThread = currentThread;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldStopIt() {
|
||||
return stopIt;
|
||||
}
|
||||
|
||||
@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 occured", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DummyDownloader implements IDownloadDisplay {
|
||||
@Override
|
||||
public void resetProgress(int sizeGuess) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPokeThread(Thread currentThread) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProgress(int fullLength) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldStopIt() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProgressString(String string, Object... data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object makeDialog() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showErrorDialog(String name, String url) {
|
||||
}
|
||||
}
|
||||
|
||||
public static class Dependancy {
|
||||
public String url;
|
||||
public String[] filesplit;
|
||||
public ComparableVersion version;
|
||||
|
||||
public String existing;
|
||||
/**
|
||||
* Flag set to add this dep to the classpath immediately because it is required for a coremod.
|
||||
*/
|
||||
public boolean coreLib;
|
||||
|
||||
public Dependancy(String url, String[] filesplit, boolean coreLib) {
|
||||
this.url = url;
|
||||
this.filesplit = filesplit;
|
||||
this.coreLib = coreLib;
|
||||
version = new ComparableVersion(filesplit[1]);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return filesplit[0];
|
||||
}
|
||||
|
||||
public String fileName() {
|
||||
return filesplit[0] + filesplit[1] + filesplit[2];
|
||||
}
|
||||
}
|
||||
|
||||
public static class DepLoadInst {
|
||||
private File modsDir;
|
||||
private File v_modsDir;
|
||||
private IDownloadDisplay downloadMonitor;
|
||||
private JDialog popupWindow;
|
||||
|
||||
private Map<String, Dependancy> depMap = new HashMap<String, Dependancy>();
|
||||
private HashSet<String> depSet = new HashSet<String>();
|
||||
|
||||
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.";
|
||||
System.err.println(msg);
|
||||
if (!GraphicsEnvironment.isHeadless())
|
||||
JOptionPane.showMessageDialog(null, msg, "An update error has occured", JOptionPane.ERROR_MESSAGE);
|
||||
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private void download(Dependancy dep) {
|
||||
popupWindow = (JDialog) downloadMonitor.makeDialog();
|
||||
File libFile = new File(v_modsDir, dep.fileName());
|
||||
try {
|
||||
URL libDownload = new URL(dep.url + '/' + dep.fileName());
|
||||
downloadMonitor.updateProgressString("Downloading file %s", libDownload.toString());
|
||||
System.out.format("Downloading file %s\n", libDownload.toString());
|
||||
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");
|
||||
System.out.println("Download complete");
|
||||
|
||||
scanDepInfo(libFile);
|
||||
} catch (Exception e) {
|
||||
libFile.delete();
|
||||
if (downloadMonitor.shouldStopIt()) {
|
||||
System.err.println("You have stopped the downloading operation before it could complete");
|
||||
System.exit(1);
|
||||
return;
|
||||
}
|
||||
downloadMonitor.showErrorDialog(dep.fileName(), dep.url + '/' + dep.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(String[] dependency) {
|
||||
for (File f : modsDir.listFiles()) {
|
||||
String[] split = splitFileName(f.getName());
|
||||
if (split == null || !split[0].equals(dependency[0]))
|
||||
continue;
|
||||
|
||||
if (f.renameTo(new File(v_modsDir, f.getName())))
|
||||
continue;
|
||||
|
||||
deleteMod(f);
|
||||
}
|
||||
|
||||
for (File f : v_modsDir.listFiles()) {
|
||||
String[] split = splitFileName(f.getName());
|
||||
if (split == null || !split[0].equals(dependency[0]))
|
||||
continue;
|
||||
|
||||
ComparableVersion found = new ComparableVersion(split[1]);
|
||||
ComparableVersion requested = new ComparableVersion(dependency[1]);
|
||||
|
||||
int cmp = found.compareTo(requested);
|
||||
if (cmp < 0) {
|
||||
System.out.println("Deleted old version " + f.getName());
|
||||
deleteMod(f);
|
||||
return null;
|
||||
}
|
||||
if (cmp > 0) {
|
||||
System.err.println("Warning: version of " + dependency[0] + ", " + split[1] + " is newer than request " + dependency[1]);
|
||||
return f.getName();
|
||||
}
|
||||
return f.getName();//found dependency
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void load() {
|
||||
scanDepInfos();
|
||||
if (depMap.isEmpty())
|
||||
return;
|
||||
|
||||
loadDeps();
|
||||
activateDeps();
|
||||
}
|
||||
|
||||
private void activateDeps() {
|
||||
for (Dependancy 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();
|
||||
Dependancy dep = depMap.get(it.next());
|
||||
it.remove();
|
||||
load(dep);
|
||||
}
|
||||
} finally {
|
||||
if (popupWindow != null) {
|
||||
popupWindow.setVisible(false);
|
||||
popupWindow.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void load(Dependancy dep) {
|
||||
dep.existing = checkExisting(dep.filesplit);
|
||||
if (dep.existing == null)//download dep
|
||||
{
|
||||
download(dep);
|
||||
dep.existing = dep.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) {
|
||||
System.err.println("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 file = node.get("file").getAsString();
|
||||
if (!obfuscated && node.has("dev"))
|
||||
file = node.get("dev").getAsString();
|
||||
|
||||
boolean coreLib = node.has("coreLib") && node.get("coreLib").getAsBoolean();
|
||||
|
||||
String[] split = splitFileName(file);
|
||||
if (split == null)
|
||||
throw new RuntimeException("Invalid filename format for dependency: " + file);
|
||||
|
||||
addDep(new Dependancy(repo, split, coreLib));
|
||||
}
|
||||
|
||||
private void addDep(Dependancy newDep) {
|
||||
if (mergeNew(depMap.get(newDep.getName()), newDep)) {
|
||||
depMap.put(newDep.getName(), newDep);
|
||||
depSet.add(newDep.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean mergeNew(Dependancy oldDep, Dependancy newDep) {
|
||||
if (oldDep == null)
|
||||
return true;
|
||||
|
||||
Dependancy newest = newDep.version.compareTo(oldDep.version) > 0 ? newDep : oldDep;
|
||||
newest.coreLib = newDep.coreLib || oldDep.coreLib;
|
||||
|
||||
return newest == newDep;
|
||||
}
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
if (inst == null) {
|
||||
inst = new DepLoadInst();
|
||||
inst.load();
|
||||
}
|
||||
}
|
||||
|
||||
private static String[] splitFileName(String filename) {
|
||||
Pattern p = Pattern.compile("(.+?)([\\d\\.\\w]+)(\\.[^\\d]+)");
|
||||
Matcher m = p.matcher(filename);
|
||||
if (!m.matches())
|
||||
return null;
|
||||
|
||||
return new String[]{m.group(1), m.group(2), m.group(3)};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getASMTransformerClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModContainerClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSetupClass() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectData(Map<String, Object> data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void call() {
|
||||
load();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessTransformerClass() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package codechicken.obfuscator;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.*;
|
||||
|
||||
public class ConstantObfuscator implements Opcodes
|
||||
{
|
||||
public ObfRemapper obf;
|
||||
public List<ObfMapping> descCalls = new LinkedList<ObfMapping>();
|
||||
public List<ObfMapping> classCalls = new LinkedList<ObfMapping>();
|
||||
|
||||
public ConstantObfuscator(ObfRemapper obf, String[] a_classCalls, String[] a_descCalls)
|
||||
{
|
||||
this.obf = obf;
|
||||
for(String callDesc : a_classCalls)
|
||||
classCalls.add(ObfMapping.fromDesc(callDesc));
|
||||
|
||||
for(String callDesc : a_descCalls)
|
||||
descCalls.add(ObfMapping.fromDesc(callDesc));
|
||||
}
|
||||
|
||||
public void transform(ClassNode cnode)
|
||||
{
|
||||
for(MethodNode method : cnode.methods)
|
||||
for(AbstractInsnNode insn = method.instructions.getFirst(); insn != null; insn = insn.getNext())
|
||||
obfuscateInsnSeq(insn);
|
||||
}
|
||||
|
||||
private void obfuscateInsnSeq(AbstractInsnNode insn)
|
||||
{
|
||||
if(matchesClass(insn))
|
||||
{
|
||||
LdcInsnNode node1 = (LdcInsnNode) insn;
|
||||
node1.cst = obf.map((String) node1.cst);
|
||||
}
|
||||
if(matchesDesc(insn))
|
||||
{
|
||||
LdcInsnNode node1 = (LdcInsnNode) insn;
|
||||
LdcInsnNode node2 = (LdcInsnNode) node1.getNext();
|
||||
LdcInsnNode node3 = (LdcInsnNode) node2.getNext();
|
||||
ObfMapping mapping = new ObfMapping((String) node1.cst, (String) node2.cst, (String) node3.cst).map(obf);
|
||||
node1.cst = mapping.s_owner;
|
||||
node2.cst = mapping.s_name;
|
||||
node3.cst = mapping.s_desc;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean matchesClass(AbstractInsnNode insn)
|
||||
{
|
||||
if(insn.getType() != LDC_INSN) return false;
|
||||
insn = insn.getNext();
|
||||
if(insn == null || insn.getType() != METHOD_INSN) return false;
|
||||
for(ObfMapping m : classCalls)
|
||||
if(m.matches((MethodInsnNode) insn))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean matchesDesc(AbstractInsnNode insn)
|
||||
{
|
||||
if(insn.getType() != LDC_INSN) return false;
|
||||
insn = insn.getNext();
|
||||
if(insn == null || insn.getType() != LDC_INSN) return false;
|
||||
insn = insn.getNext();
|
||||
if(insn == null || insn.getType() != LDC_INSN) return false;
|
||||
insn = insn.getNext();
|
||||
if(insn == null || insn.getType() != METHOD_INSN) return false;
|
||||
for(ObfMapping m : descCalls)
|
||||
if(m.matches((MethodInsnNode) insn))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package codechicken.obfuscator;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class DummyOutputStream extends OutputStream
|
||||
{
|
||||
public static DummyOutputStream instance = new DummyOutputStream();
|
||||
|
||||
@Override
|
||||
public void write(int b)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package codechicken.obfuscator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import codechicken.obfuscator.ObfuscationMap.ObfuscationEntry;
|
||||
|
||||
public interface IHeirachyEvaluator
|
||||
{
|
||||
/**
|
||||
* @param desc The mapping descriptor of the class to evaluate heirachy for
|
||||
* @return A list of parents (srg or obf names)
|
||||
*/
|
||||
public List<String> getParents(ObfuscationEntry desc);
|
||||
|
||||
/**
|
||||
* @param srg_class The srg name of the class in question
|
||||
* @return True if this class does not inherit from any obfuscated class.
|
||||
*/
|
||||
public boolean isLibClass(ObfuscationEntry desc);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package codechicken.obfuscator;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
public interface ILogStreams
|
||||
{
|
||||
public PrintStream err();
|
||||
public PrintStream out();
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package codechicken.obfuscator;
|
||||
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
import codechicken.obfuscator.ObfuscationMap.ObfuscationEntry;
|
||||
|
||||
public class ObfDirection
|
||||
{
|
||||
public boolean obfuscate;
|
||||
public boolean srg;
|
||||
public boolean srg_cst;
|
||||
|
||||
public ObfDirection setObfuscate(boolean obfuscate)
|
||||
{
|
||||
this.obfuscate = obfuscate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObfDirection setSearge(boolean srg)
|
||||
{
|
||||
this.srg = srg;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObfDirection setSeargeConstants(boolean srg_cst)
|
||||
{
|
||||
this.srg_cst = srg_cst;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObfMapping obfuscate(ObfuscationEntry map)
|
||||
{
|
||||
return srg ? map.srg : obfuscate ? map.obf : map.mcp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package codechicken.obfuscator;
|
||||
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
|
||||
import codechicken.obfuscator.ObfuscationMap.ObfuscationEntry;
|
||||
|
||||
public class ObfRemapper extends Remapper
|
||||
{
|
||||
public final ObfuscationMap obf;
|
||||
public ObfDirection dir;
|
||||
|
||||
public ObfRemapper(ObfuscationMap obf, ObfDirection dir)
|
||||
{
|
||||
this.obf = obf;
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String map(String name)
|
||||
{
|
||||
if(name.indexOf('$') >= 0)
|
||||
return map(name.substring(0, name.indexOf('$')))+name.substring(name.indexOf('$'));
|
||||
|
||||
ObfuscationEntry map;
|
||||
if(dir.obfuscate)
|
||||
map = obf.lookupMcpClass(name);
|
||||
else
|
||||
map = obf.lookupObfClass(name);
|
||||
|
||||
if(map != null)
|
||||
return dir.obfuscate(map).s_owner;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapFieldName(String owner, String name, String desc)
|
||||
{
|
||||
ObfuscationEntry map;
|
||||
if(dir.obfuscate)
|
||||
map = obf.lookupMcpField(owner, name);
|
||||
else
|
||||
map = obf.lookupObfField(owner, name);
|
||||
|
||||
if(map == null)
|
||||
map = obf.lookupSrgField(owner, name);
|
||||
|
||||
if(map != null)
|
||||
return dir.obfuscate(map).s_name;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapMethodName(String owner, String name, String desc)
|
||||
{
|
||||
if(owner.length() == 0 || owner.charAt(0) == '[')
|
||||
return name;
|
||||
|
||||
ObfuscationEntry map;
|
||||
if(dir.obfuscate)
|
||||
map = obf.lookupMcpMethod(owner, name, desc);
|
||||
else
|
||||
map = obf.lookupObfMethod(owner, name, desc);
|
||||
|
||||
if(map == null)
|
||||
map = obf.lookupSrg(name);
|
||||
|
||||
if(map != null)
|
||||
return dir.obfuscate(map).s_name;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object mapValue(Object cst)
|
||||
{
|
||||
if(cst instanceof String)
|
||||
{
|
||||
if(dir.srg_cst)
|
||||
{
|
||||
ObfuscationEntry map = obf.lookupSrg((String) cst);
|
||||
if(map != null)
|
||||
return dir.obfuscate(map).s_name;
|
||||
}
|
||||
return cst;
|
||||
}
|
||||
|
||||
return super.mapValue(cst);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
package codechicken.obfuscator;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
|
||||
import codechicken.lib.asm.ObfMapping;
|
||||
|
||||
public class ObfuscationMap
|
||||
{
|
||||
public class ObfuscationEntry
|
||||
{
|
||||
public final ObfMapping obf;
|
||||
public final ObfMapping srg;
|
||||
public final ObfMapping mcp;
|
||||
|
||||
public ObfuscationEntry(ObfMapping obf, ObfMapping srg, ObfMapping mcp)
|
||||
{
|
||||
this.obf = obf;
|
||||
this.srg = srg;
|
||||
this.mcp = mcp;
|
||||
}
|
||||
}
|
||||
|
||||
private class ClassEntry extends ObfuscationEntry
|
||||
{
|
||||
public Map<String, ObfuscationEntry> mcpMap = new HashMap<String, ObfuscationEntry>();
|
||||
public Map<String, ObfuscationEntry> srgMap = new HashMap<String, ObfuscationEntry>();
|
||||
public Map<String, ObfuscationEntry> obfMap = new HashMap<String, ObfuscationEntry>();
|
||||
|
||||
public ClassEntry(String obf, String srg)
|
||||
{
|
||||
super(new ObfMapping(obf, "", ""),
|
||||
new ObfMapping(srg, "", ""),
|
||||
new ObfMapping(srg, "", ""));
|
||||
}
|
||||
|
||||
public ObfuscationEntry addEntry(ObfMapping obf_desc, ObfMapping srg_desc)
|
||||
{
|
||||
ObfuscationEntry entry = new ObfuscationEntry(obf_desc, srg_desc, srg_desc.copy());
|
||||
obfMap.put(obf_desc.s_name.concat(obf_desc.s_desc), entry);
|
||||
srgMap.put(srg_desc.s_name, entry);
|
||||
|
||||
if(srg_desc.s_name.startsWith("field_") || srg_desc.s_name.startsWith("func_"))
|
||||
srgMemberMap.put(srg_desc.s_name, entry);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
public void inheritFrom(ClassEntry p)
|
||||
{
|
||||
inherit(obfMap, p.obfMap);
|
||||
inherit(srgMap, p.srgMap);
|
||||
inherit(mcpMap, p.mcpMap);
|
||||
}
|
||||
|
||||
private void inherit(Map<String, ObfuscationEntry> child, Map<String, ObfuscationEntry> parent)
|
||||
{
|
||||
for(Entry<String, ObfuscationEntry> e : parent.entrySet())
|
||||
if(!child.containsKey(e.getKey()))
|
||||
child.put(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, ClassEntry> srgMap = new HashMap<String, ClassEntry>();
|
||||
private Map<String, ClassEntry> obfMap = new HashMap<String, ClassEntry>();
|
||||
private ArrayListMultimap<String, ObfuscationEntry> srgMemberMap = ArrayListMultimap.create();
|
||||
|
||||
private IHeirachyEvaluator heirachyEvaluator;
|
||||
private HashSet<String> mappedClasses = new HashSet<String>();
|
||||
public ILogStreams log = SystemLogStreams.inst;
|
||||
|
||||
public ObfuscationMap setHeirachyEvaluator(IHeirachyEvaluator eval)
|
||||
{
|
||||
heirachyEvaluator = eval;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObfuscationMap setLog(ILogStreams log)
|
||||
{
|
||||
this.log = log;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObfuscationEntry addClass(String obf, String srg)
|
||||
{
|
||||
return addEntry(new ObfMapping(obf, "", ""), new ObfMapping(srg, "", ""));
|
||||
}
|
||||
|
||||
public ObfuscationEntry addField(String obf_owner, String obf_name, String srg_owner, String srg_name)
|
||||
{
|
||||
return addEntry(new ObfMapping(obf_owner, obf_name, ""),
|
||||
new ObfMapping(srg_owner, srg_name, ""));
|
||||
}
|
||||
|
||||
public ObfuscationEntry addMethod(String obf_owner, String obf_name, String obf_desc, String srg_owner, String srg_name, String srg_desc)
|
||||
{
|
||||
return addEntry(new ObfMapping(obf_owner, obf_name, obf_desc),
|
||||
new ObfMapping(srg_owner, srg_name, srg_desc));
|
||||
}
|
||||
|
||||
public ObfuscationEntry addEntry(ObfMapping obf_desc, ObfMapping srg_desc)
|
||||
{
|
||||
ClassEntry e = srgMap.get(srg_desc.s_owner);
|
||||
if(e == null)
|
||||
{
|
||||
e = new ClassEntry(obf_desc.s_owner, srg_desc.s_owner);
|
||||
obfMap.put(obf_desc.s_owner, e);
|
||||
srgMap.put(srg_desc.s_owner, e);
|
||||
}
|
||||
if(obf_desc.s_name.length() > 0)
|
||||
return e.addEntry(obf_desc, srg_desc);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
public void addMcpName(String srg_name, String mcp_name)
|
||||
{
|
||||
List<ObfuscationEntry> entries = srgMemberMap.get(srg_name);
|
||||
if(entries.isEmpty())
|
||||
{
|
||||
log.err().println("Tried to add mcp name ("+mcp_name+") for unknown srg key ("+srg_name+")");
|
||||
return;
|
||||
}
|
||||
for(ObfuscationEntry entry : entries)
|
||||
{
|
||||
entry.mcp.s_name = mcp_name;
|
||||
srgMap.get(entry.srg.s_owner).mcpMap.put(entry.mcp.s_name.concat(entry.mcp.s_desc), entry);
|
||||
}
|
||||
}
|
||||
|
||||
public ObfuscationEntry lookupSrg(String srg_key)
|
||||
{
|
||||
List<ObfuscationEntry> list = srgMemberMap.get(srg_key);
|
||||
return list.isEmpty() ? null : list.get(0);
|
||||
}
|
||||
|
||||
public ObfuscationEntry lookupMcpClass(String name)
|
||||
{
|
||||
return srgMap.get(name);
|
||||
}
|
||||
|
||||
public ObfuscationEntry lookupObfClass(String name)
|
||||
{
|
||||
return obfMap.get(name);
|
||||
}
|
||||
|
||||
public ObfuscationEntry lookupMcpField(String owner, String name)
|
||||
{
|
||||
return lookupMcpMethod(owner, name, "");
|
||||
}
|
||||
|
||||
public ObfuscationEntry lookupSrgField(String owner, String name)
|
||||
{
|
||||
if(name.startsWith("field_"))
|
||||
{
|
||||
ObfuscationEntry e = lookupSrg(name);
|
||||
if(e != null)
|
||||
return e;
|
||||
}
|
||||
|
||||
evaluateHeirachy(owner);
|
||||
ClassEntry e = srgMap.get(owner);
|
||||
return e == null ? null : e.srgMap.get(name);
|
||||
}
|
||||
|
||||
public ObfuscationEntry lookupObfField(String owner, String name)
|
||||
{
|
||||
return lookupObfMethod(owner, name, "");
|
||||
}
|
||||
|
||||
public ObfuscationEntry lookupMcpMethod(String owner, String name, String desc)
|
||||
{
|
||||
evaluateHeirachy(owner);
|
||||
ClassEntry e = srgMap.get(owner);
|
||||
return e == null ? null : e.mcpMap.get(name.concat(desc));
|
||||
}
|
||||
|
||||
public ObfuscationEntry lookupObfMethod(String owner, String name, String desc)
|
||||
{
|
||||
evaluateHeirachy(owner);
|
||||
ClassEntry e = obfMap.get(owner);
|
||||
return e == null ? null : e.obfMap.get(name.concat(desc));
|
||||
}
|
||||
|
||||
private boolean isMapped(ObfuscationEntry desc)
|
||||
{
|
||||
return mappedClasses.contains(desc.srg.s_owner);
|
||||
}
|
||||
|
||||
private ObfuscationEntry getOrCreateClassEntry(String name)
|
||||
{
|
||||
ObfuscationEntry e = lookupObfClass(name);
|
||||
if(e == null)
|
||||
e = lookupMcpClass(name);
|
||||
if(e == null)
|
||||
e = addClass(name, name);//if the class isn't in obf or srg maps, it must be a custom mod class with no name change.
|
||||
return e;
|
||||
}
|
||||
|
||||
public ObfuscationEntry evaluateHeirachy(String name)
|
||||
{
|
||||
ObfuscationEntry desc = getOrCreateClassEntry(name);
|
||||
if(isMapped(desc))
|
||||
return desc;
|
||||
|
||||
mappedClasses.add(desc.srg.s_owner);
|
||||
if(heirachyEvaluator == null)
|
||||
throw new IllegalArgumentException("Cannot call method/field mappings if a heirachy evaluator is not set.");
|
||||
|
||||
if(!heirachyEvaluator.isLibClass(desc))
|
||||
{
|
||||
List<String> parents = heirachyEvaluator.getParents(desc);
|
||||
if(parents == null)
|
||||
log.err().println("Could not find class: "+desc.srg.s_owner);
|
||||
else
|
||||
for(String parent : parents)
|
||||
inherit(desc, evaluateHeirachy(parent));
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
public void inherit(ObfuscationEntry desc, ObfuscationEntry p_desc)
|
||||
{
|
||||
inherit(desc.srg.s_owner, p_desc.srg.s_owner);
|
||||
}
|
||||
|
||||
public void inherit(String name, String parent)
|
||||
{
|
||||
ClassEntry e = srgMap.get(name);
|
||||
if(e == null)
|
||||
throw new IllegalStateException("Tried to inerit to an undefined class: "+name+" extends "+parent);
|
||||
ClassEntry p = srgMap.get(parent);
|
||||
if(p == null)
|
||||
throw new IllegalStateException("Tried to inerit from undefired parent: "+name+" extends "+parent);
|
||||
e.inheritFrom(p);
|
||||
}
|
||||
|
||||
public void parseMappings(File[] mappings)
|
||||
{
|
||||
parseSRGS(mappings[0]);
|
||||
parseCSV(mappings[1]);
|
||||
parseCSV(mappings[2]);
|
||||
}
|
||||
|
||||
public static String[] splitLast(String s, char c)
|
||||
{
|
||||
int i = s.lastIndexOf(c);
|
||||
return new String[]{s.substring(0, i), s.substring(i+1)};
|
||||
}
|
||||
|
||||
public static String[] split4(String s, char c)
|
||||
{
|
||||
String[] split = new String[4];
|
||||
int i2 = s.indexOf(c);
|
||||
split[0] = s.substring(0, i2);
|
||||
int i = i2+1;
|
||||
i2 = s.indexOf(c, i);
|
||||
split[1] = s.substring(i, i2);
|
||||
i = i2+1;
|
||||
i2 = s.indexOf(c, i);
|
||||
split[2] = s.substring(i, i2);
|
||||
i = i2+1;
|
||||
i2 = s.indexOf(c, i);
|
||||
split[3] = s.substring(i);
|
||||
return split;
|
||||
}
|
||||
|
||||
private void parseSRGS(File srgs)
|
||||
{
|
||||
log.out().println("Parsing "+srgs.getName());
|
||||
|
||||
Function<String, Void> function = new Function<String, Void>()
|
||||
{
|
||||
@Override
|
||||
public Void apply(String line)
|
||||
{
|
||||
int hpos = line.indexOf('#');
|
||||
if(hpos > 0)
|
||||
line = line.substring(0, hpos).trim();
|
||||
if(line.startsWith("CL: "))
|
||||
{
|
||||
String[] params = splitLast(line.substring(4), ' ');
|
||||
addClass(params[0], params[1]);
|
||||
}
|
||||
else if(line.startsWith("FD: "))
|
||||
{
|
||||
String[] params = splitLast(line.substring(4), ' ');
|
||||
String[] p1 = splitLast(params[0], '/');
|
||||
String[] p2 = splitLast(params[1], '/');
|
||||
addField(p1[0], p1[1],
|
||||
p2[0], p2[1]);
|
||||
return null;
|
||||
}
|
||||
else if(line.startsWith("MD: "))
|
||||
{
|
||||
String[] params = split4(line.substring(4), ' ');
|
||||
String[] p1 = splitLast(params[0], '/');
|
||||
String[] p2 = splitLast(params[2], '/');
|
||||
addMethod(p1[0], p1[1], params[1],
|
||||
p2[0], p2[1], params[3]);
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
ObfuscationRun.processLines(srgs, function);
|
||||
}
|
||||
|
||||
private void parseCSV(File csv)
|
||||
{
|
||||
log.out().println("Parsing "+csv.getName());
|
||||
|
||||
Function<String, Void> function = new Function<String, Void>()
|
||||
{
|
||||
@Override
|
||||
public Void apply(String line)
|
||||
{
|
||||
if(line.startsWith("func_") || line.startsWith("field_"))
|
||||
{
|
||||
int i = line.indexOf(',');
|
||||
String srg = line.substring(0, i);
|
||||
int i2 = i+1;
|
||||
i = line.indexOf(',', i2);
|
||||
String mcp = line.substring(i2, i);
|
||||
|
||||
addMcpName(srg, mcp);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
ObfuscationRun.processLines(csv, function);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
package codechicken.obfuscator;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.PrintStream;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.commons.RemappingClassAdapter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
public class ObfuscationRun implements ILogStreams
|
||||
{
|
||||
public final ObfDirection obfDir;
|
||||
public final ObfuscationMap obf;
|
||||
public final ObfRemapper obfMapper;
|
||||
public final ConstantObfuscator cstMappper;
|
||||
|
||||
public File[] mappings;
|
||||
public Map<String, String> config;
|
||||
|
||||
private PrintStream out = System.out;
|
||||
private PrintStream err = System.err;
|
||||
private PrintStream quietStream = new PrintStream(DummyOutputStream.instance);
|
||||
|
||||
private boolean verbose;
|
||||
private boolean quiet;
|
||||
|
||||
public boolean clean;
|
||||
private long startTime;
|
||||
private boolean finished;
|
||||
|
||||
public ObfuscationRun(boolean obfuscate, File[] mappings, Map<String, String> config)
|
||||
{
|
||||
obfDir = new ObfDirection().setObfuscate(obfuscate);
|
||||
this.mappings = mappings;
|
||||
this.config = config;
|
||||
|
||||
obf = new ObfuscationMap().setLog(this);
|
||||
obfMapper = new ObfRemapper(obf, obfDir);
|
||||
cstMappper = new ConstantObfuscator(obfMapper,
|
||||
config.get("classConstantCalls").split(","),
|
||||
config.get("descConstantCalls").split(","));
|
||||
}
|
||||
|
||||
public ObfuscationRun setClean()
|
||||
{
|
||||
clean = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObfuscationRun setVerbose()
|
||||
{
|
||||
verbose = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObfuscationRun setQuiet()
|
||||
{
|
||||
quiet = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObfuscationRun setOut(PrintStream p)
|
||||
{
|
||||
out = p;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PrintStream out()
|
||||
{
|
||||
return quiet ? quietStream : out;
|
||||
}
|
||||
|
||||
public PrintStream fine()
|
||||
{
|
||||
return verbose ? out : quietStream;
|
||||
}
|
||||
|
||||
public ObfuscationRun setErr(PrintStream p)
|
||||
{
|
||||
err = p;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PrintStream err()
|
||||
{
|
||||
return quiet ? quietStream : err;
|
||||
}
|
||||
|
||||
public ObfuscationRun setSearge()
|
||||
{
|
||||
obfDir.setSearge(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObfuscationRun setSeargeConstants()
|
||||
{
|
||||
obfDir.setSeargeConstants(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void start()
|
||||
{
|
||||
startTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public static Map<String, String> fillDefaults(Map<String, String> config)
|
||||
{
|
||||
if(!config.containsKey("excludedPackages"))
|
||||
config.put("excludedPackages", "java/;sun/;javax/;scala/;" +
|
||||
"argo/;org/lwjgl/;org/objectweb/;org/bouncycastle/;com/google/");
|
||||
if(!config.containsKey("ignore"))
|
||||
config.put("ignore", ".");
|
||||
if(!config.containsKey("classConstantCalls"))
|
||||
config.put("classConstantCalls",
|
||||
"codechicken/lib/asm/ObfMapping.<init>(Ljava/lang/String;)V," +
|
||||
"codechicken/lib/asm/ObfMapping.subclass(Ljava/lang/String;)Lcodechicken/lib/asm/ObfMapping;," +
|
||||
"codechicken/lib/asm/ObfMapping.<init>(Lcodechicken/lib/asm/ObfMapping;Ljava/lang/String;)V");
|
||||
if(!config.containsKey("descConstantCalls"))
|
||||
config.put("descConstantCalls",
|
||||
"codechicken/lib/asm/ObfMapping.<init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," +
|
||||
"org/objectweb/asm/MethodVisitor.visitFieldInsn(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," +
|
||||
"org/objectweb/asm/tree/MethodNode.visitFieldInsn(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," +
|
||||
"org/objectweb/asm/MethodVisitor.visitMethodInsn(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," +
|
||||
"org/objectweb/asm/tree/MethodNode.visitMethodInsn(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," +
|
||||
"org/objectweb/asm/tree/MethodInsnNode.<init>(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," +
|
||||
"org/objectweb/asm/tree/FieldInsnNode.<init>(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
public static void processLines(File file, Function<String, Void> function)
|
||||
{
|
||||
try
|
||||
{
|
||||
BufferedReader reader = new BufferedReader(new FileReader(file));
|
||||
String line;
|
||||
while((line = reader.readLine()) != null)
|
||||
function.apply(line);
|
||||
reader.close();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void processFiles(File dir, Function<File, Void> function, boolean recursive)
|
||||
{
|
||||
for(File file : dir.listFiles())
|
||||
if(file.isDirectory() && recursive)
|
||||
processFiles(file, function, recursive);
|
||||
else
|
||||
function.apply(file);
|
||||
}
|
||||
|
||||
public static void deleteDir(File directory, boolean remove)
|
||||
{
|
||||
if(!directory.exists())
|
||||
{
|
||||
if(!remove)directory.mkdirs();
|
||||
return;
|
||||
}
|
||||
for(File file : directory.listFiles())
|
||||
{
|
||||
if(file.isDirectory())
|
||||
{
|
||||
deleteDir(file, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!file.delete())
|
||||
throw new RuntimeException("Delete Failed: "+file);
|
||||
}
|
||||
}
|
||||
if(remove)
|
||||
{
|
||||
if(!directory.delete())
|
||||
throw new RuntimeException("Delete Failed: "+directory);
|
||||
}
|
||||
}
|
||||
|
||||
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};
|
||||
}
|
||||
|
||||
public long startTime()
|
||||
{
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void remap(ClassNode cnode, ClassVisitor cv)
|
||||
{
|
||||
cstMappper.transform(cnode);
|
||||
cnode.accept(new RemappingClassAdapter(cv, obfMapper));
|
||||
}
|
||||
|
||||
public static List<String> getParents(ClassNode cnode)
|
||||
{
|
||||
List<String> parents = new LinkedList<String>();
|
||||
if(cnode.superName != null)
|
||||
parents.add(cnode.superName);
|
||||
|
||||
for(String s_interface : cnode.interfaces)
|
||||
parents.add(s_interface);
|
||||
|
||||
return parents;
|
||||
}
|
||||
|
||||
public void finish(boolean errored)
|
||||
{
|
||||
long millis = System.currentTimeMillis()-startTime;
|
||||
out().println((errored ? "Errored after" : "Done in ")+new DecimalFormat("0.00").format(millis/1000D)+"s");
|
||||
finished = true;
|
||||
}
|
||||
|
||||
public boolean finished()
|
||||
{
|
||||
return finished;
|
||||
}
|
||||
|
||||
public void parseMappings()
|
||||
{
|
||||
obf.parseMappings(mappings);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package codechicken.obfuscator;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
public class SystemLogStreams implements ILogStreams
|
||||
{
|
||||
public static SystemLogStreams inst = new SystemLogStreams();
|
||||
|
||||
@Override
|
||||
public PrintStream err()
|
||||
{
|
||||
return System.err;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintStream out()
|
||||
{
|
||||
return System.out;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user