Initial commit

This commit is contained in:
Chicken-Bomes committed 2014-04-29 00:35:55 +10:00
commit 0d94e9ac7f
78 files changed
+7045

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
/build/build
/build/.gradle
+173
View File
@@ -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())
}
}
}
}
+4
View File
@@ -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
Binary file not shown.
+6
View File
@@ -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
+164
View File
@@ -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 "$@"
+90
View File
@@ -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
+19
View File
@@ -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
+11
View File
@@ -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" ]
}
]
+9
View File
@@ -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
}
+118
View File
@@ -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());
}
}
+144
View File
@@ -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);
}
}
}
}
+60
View File
@@ -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;
}
}
+63
View File
@@ -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);
}
+6
View File
@@ -0,0 +1,6 @@
package codechicken.core;
public interface IStringMatcher
{
public boolean matches(String test);
}
+39
View File
@@ -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");
}
}
+38
View File
@@ -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();
}
};
}
}
+316
View File
@@ -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);
}
}
+62
View File
@@ -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);
}
}
+66
View File
@@ -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);
}
}
+75
View File
@@ -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()
{
}
}
+361
View File
@@ -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);
}
}
+87
View File
@@ -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());
}
}
}
+601
View File
@@ -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;
}
}