diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..dfe077042 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..0ed9cfa05 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# eclipse +bin +*.launch +.settings +.metadata +.classpath +.project + +# idea +out +*.ipr +*.iws +*.iml +/.idea + +# gradle +build +.gradle + +# other +/run +classes +logs/debug.log +logs/latest.log diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 000000000..0a041280b --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/README.md b/README.md new file mode 100644 index 000000000..c3709f967 --- /dev/null +++ b/README.md @@ -0,0 +1,74 @@ +# AE2 Fluid Crafting Rework + +Put fluids in the pattern! + +AE2 autocrafting is amazing and everyone loves it, but it is always becoming painful when dealing with fluids. You have to put fluids in a container or use a dummy item to write patterns with fluids. + +That's because AE2 doesn't support fluid as valid crafting ingredients before 1.18, so it can't handle fluids directly. + +However, it is changed now! With **AE2 Fluid Crafting** you can write patterns with fluids freely. Your AE system can output and accept fluids like items without worrying about how to handle these fluid cells. + +This is a rework and ported version of [ae2-fluid-crafting](https://github.com/phantamanta44/ae2-fluid-crafting) + +## Installation + +### 1.7.10 +Any version of AE2(Both Official AE2 and GTNH edition AE2 works). +**Extra Cells isn't needed** + +### 1.12.2 +WIP + +### 1.16.5 +WIP + +## Basic Devices + +### Fluid Discretizer +The **Fluid Discretizer** is a device that, when attached to ME network, exposes the contents of its fluid storage grid as items, which take the form of "fluid drops". +It does this by functioning as a sort of storage bus: when fluid drops are removed from its storage via the item grid, it extracts the corresponding fluid from the fluid grid. +Conversely, when fluid drops inserted into its storage via the item grid, it injects the corresponding fluid into the fluid grid. +Each fluid drop is equivalent to one mB of its respective fluid, which means a full stack of them is equivalent to 64 mB. +Fluid drops have an important property: when an ME interface attempts to export fluid drops to a machine, it will attempt to convert them to fluid. +This means an interface exporting drops of gelid cryotheum into a fluid transposer will successfully fill the transposer's internal tank rather than inserting the drops as items. +This is the central mechanic that makes fluid autocrafting possible. +Note that the only way to convert between fluids and fluid drops is a discretizer attached to an ME network. +While you could theoretically use this as a very convoluted method of transporting fluids, it is not recomomended to do so. + +### Fluid Pattern Encoder +Most crafting recipes involving fluids require far more than 64 mB of a particular fluid, and so the standard pattern terminal will not do for encoding such recipes into patterns. +This problem is solved by the **Fluid Pattern Encoder**, a utility that functions similarly to a pattern terminal. +When a fluid-handling item (e.g. a bucket or tank) is inserted into the crafting ingredient slots, they will be converted into an equivalent stack of the corresponding fluid drops. +Using this, patterns for recipes that require more than a stack of fluid drops can easily be encoded. +AE2 Fluid Crafting also comes with a handy JEI integration module that allows the fluid pattern encoder to encode any JEI recipe involving fluids. +This is the recommended way to play with the mod, since encoding patterns by hand is a little cumbersome. + +### Fluid Pattern Terminal + +Encoding recipes in a big and bulky workbench separate from the rest of your AE2 equipment can be a little inconvenient. +Luckily, we have the **Fluid Pattern Terminal**, which combines the functionality of the standard pattern terminal and the fluid pattern encoder. +Now, you can encode your fluid recipes using the same familiar interface you know and love! + +### Fluid Pattern Interface + +The standard ME interface lets you emit items and fluid packets with AE2FC, but it will only accept items, as in vanilla AE2. +This is a little inconvenient when you want to build compact setups for autocrafting with fluid outputs, where you would need to use both an item interface for inputs, and a separate fluid interface for outputs. +To make things easier, we have the **Fluid Pattern Interface**, which functions as a combination of an item interface and a fluid interface! +Its GUI is the same as normal ME interface, but it can emit fluids directly instead of fluid packets! It also accepts fluid and item inputs. +Automating fluid crafting machines has never been this quick and painless! + +### Fluid Packets + +When putting fluid pattern in a normal ME interface, it will emit fluid packets as fluid. +So if you prefer to deal with item instead of fluids, you can transport these packets and turn them back to fluid with **ME Fluid Packet Decoder**. +Simply connect the decoder to your ME network and insert the fluid packet; the decoder will, if possible, inject the fluid into your fluid storage grid. + +## Credited Works + +E. Geng(@phantamanta44) and KilaBash (@Yefancy) - Their amazing origin work in 1.12. + +## To-Do + + - [ ] Port to 1.12, with supporting for PAE2 + + - [ ] Port to 1.16.5 diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..cf7d305bd --- /dev/null +++ b/build.gradle @@ -0,0 +1,78 @@ +buildscript { + repositories { + maven { + url 'https://maven.minecraftforge.net/' + } + maven { + name 'sonatype' + url 'https://oss.sonatype.org/content/repositories/snapshots/' + } + maven { + name 'Scala CI dependencies' + url 'https://repo1.maven.org/maven2/' + } + maven { + name 'jitpack' + url 'https://jitpack.io' + } + mavenLocal() + } + dependencies { + classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' + } +} + +apply plugin: 'net.minecraftforge.gradle.forge' +apply plugin: 'idea' + +version = "1.0.0" +group = "ae2fc" +archivesBaseName = "Fluid Craft for AE2" + +sourceCompatibility = targetCompatibility = '1.8' +compileJava { + sourceCompatibility = targetCompatibility = '1.8' +} + +repositories { + maven { url 'https://dvs1.progwml6.com/files/maven/' } + maven { url 'https://jitpack.io/' } + maven { url 'https://cfa2.cursemaven.com/' } +} + +dependencies { + compile 'com.github.phantamanta44:jsr305:1.0.1' + deobfCompile 'mezz.jei:jei_1.12.2:4.15.0.293' + deobfCompile "curse.maven:ae2-extended-life-570458:2747063" // pae2 + deobfCompile "curse.maven:packagedauto-308380:2977147" // 1.0.3.14 + deobfCompile "curse.maven:modular-machinery-270790:2761302" // 1.11.1 +} + +minecraft { + version = "1.12.2-14.23.5.2847" + runDir = "run" + mappings = "stable_39" + useDepAts = true + makeObfSourceJar = false +} + +jar { + manifest { + attributes 'FMLCorePluginContainsFMLMod': 'true' + } +} + +processResources { + inputs.property "version", project.version + inputs.property "mcversion", project.minecraft.version + + from(sourceSets.main.resources.srcDirs) { + include 'mcmod.info' + + expand 'version': project.version, 'mcversion': project.minecraft.version + } + + from(sourceSets.main.resources.srcDirs) { + exclude 'mcmod.info' + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..736fb7d3f Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..2d146a2b8 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sun May 24 18:34:45 CEST 2020 +distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100644 index 000000000..cccdd3d51 --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# 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\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# 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 +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + 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" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..f9553162f --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@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 + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@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= + +@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 Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +: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 diff --git a/logo.png b/logo.png new file mode 100644 index 000000000..129cbc24f Binary files /dev/null and b/logo.png differ diff --git a/src/main/java/com/glodblock/github/FluidCraft.java b/src/main/java/com/glodblock/github/FluidCraft.java new file mode 100644 index 000000000..a751dbc21 --- /dev/null +++ b/src/main/java/com/glodblock/github/FluidCraft.java @@ -0,0 +1,44 @@ +package com.glodblock.github; + +import com.glodblock.github.proxy.CommonProxy; +import com.glodblock.github.util.ModAndClassUtil; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.SidedProxy; +import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; + +@Mod(modid = FluidCraft.MODID, version = FluidCraft.VERSION, useMetadata = true) +public class FluidCraft { + + public static final String MODID = "ae2fc"; + public static final String VERSION = "2.0.0-r"; + + @Mod.Instance(MODID) + public static FluidCraft INSTANCE; + + @SidedProxy(clientSide = "com.glodblock.github.proxy.ClientProxy", serverSide = "com.glodblock.github.proxy.CommonProxy") + public static CommonProxy proxy; + + @Mod.EventHandler + public void onPreInit(FMLPreInitializationEvent event) { + ModAndClassUtil.init(); + proxy.preInit(event); + } + + @Mod.EventHandler + public void onInit(FMLInitializationEvent event) { + proxy.init(event); + } + + @Mod.EventHandler + public void onPostInit(FMLPostInitializationEvent event) { + proxy.postInit(event); + } + + public static ResourceLocation resource(String path) { + return new ResourceLocation(MODID, path); + } + +} diff --git a/src/main/java/com/glodblock/github/client/GuiBurette.java b/src/main/java/com/glodblock/github/client/GuiBurette.java new file mode 100644 index 000000000..575cf102c --- /dev/null +++ b/src/main/java/com/glodblock/github/client/GuiBurette.java @@ -0,0 +1,119 @@ +package com.glodblock.github.client; + +import appeng.client.gui.AEBaseGui; +import appeng.client.gui.widgets.GuiNumberBox; +import appeng.core.localization.GuiText; +import appeng.fluids.util.IAEFluidTank; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.container.ContainerBurette; +import com.glodblock.github.client.render.FluidRenderUtils; +import com.glodblock.github.common.tile.TileBurette; +import com.glodblock.github.handler.ButtonMouseHandler; +import com.glodblock.github.handler.TankMouseHandler; +import com.glodblock.github.network.CPacketTransposeFluid; +import com.glodblock.github.util.MouseRegionManager; +import com.glodblock.github.util.NameConst; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.util.ResourceLocation; + +import java.io.IOException; + +public class GuiBurette extends AEBaseGui { + + private static final ResourceLocation TEX_BG = FluidCraft.resource("textures/gui/burette.png"); + private static final int TANK_X = 52, TANK_Y = 17; + private static final int TANK_WIDTH = 16, TANK_HEIGHT = 32; + + private final ContainerBurette cont; + private GuiNumberBox amountField; + private final MouseRegionManager mouseRegions = new MouseRegionManager(this); + + public GuiBurette(InventoryPlayer ipl, TileBurette tile) { + super(new ContainerBurette(ipl, tile)); + this.cont = (ContainerBurette)inventorySlots; + + mouseRegions.addRegion(TANK_X, TANK_Y, TANK_WIDTH, TANK_HEIGHT, + new TankMouseHandler(cont.getTile().getFluidInventory(), 0)); + mouseRegions.addRegion(70, 16, 7, 7, ButtonMouseHandler.dumpTank(cont, 0)); + mouseRegions.addRegion(73, 42, 8, 16, createTransposeButton(true)); + mouseRegions.addRegion(81, 42, 8, 16, createTransposeButton(false)); + } + + @Override + public void initGui() { + super.initGui(); + amountField = new GuiNumberBox(fontRenderer, guiLeft + 95, guiTop + 46, 28, fontRenderer.FONT_HEIGHT, Integer.class); + amountField.setEnableBackgroundDrawing(false); + amountField.setMaxStringLength(4); + amountField.setTextColor(0xffffff); + amountField.setVisible(true); + amountField.setFocused(true); + amountField.setText("1000"); + } + + private ButtonMouseHandler createTransposeButton(boolean into) { + return new ButtonMouseHandler(into ? NameConst.TT_TRANSPOSE_IN : NameConst.TT_TRANSPOSE_OUT, () -> { + try { + int amount = Integer.parseInt(amountField.getText()); + if (cont.canTranferFluid(into)) { + FluidCraft.proxy.netHandler.sendToServer(new CPacketTransposeFluid(amount, into)); + } + } catch (NumberFormatException e) { + // NO-OP + } + }); + } + + @Override + protected void mouseClicked(int xCoord, int yCoord, int btn) throws IOException { + if (mouseRegions.onClick(xCoord, yCoord, btn)) { + amountField.mouseClicked(xCoord, yCoord, btn); + super.mouseClicked(xCoord, yCoord, btn); + } + } + + @Override + protected void keyTyped(final char character, final int key) throws IOException { + if (!checkHotbarKeys(key)) { + if ((key == 211 || key == 205 || key == 203 || key == 14 || Character.isDigit(character)) + && amountField.textboxKeyTyped(character, key)) { + try { + int amount = Integer.parseInt(amountField.getText()); + if (amount < 0) { + amountField.setText("1"); + } else { + amountField.setText(Long.toString(amount)); + } + } catch (final NumberFormatException e) { + // NO-OP + } + } else { + super.keyTyped(character, key); + } + } + } + + @Override + public void drawBG(int offsetX, int offsetY, int mouseX, int mouseY) { + mc.getTextureManager().bindTexture(TEX_BG); + drawTexturedModalRect(offsetX, offsetY, 0, 0, 176, ySize); + amountField.drawTextBox(); + GlStateManager.color(1F, 1F, 1F, 1F); + } + + @Override + public void drawFG(int offsetX, int offsetY, int mouseX, int mouseY) { + fontRenderer.drawString(getGuiDisplayName(I18n.format(NameConst.GUI_BURETTE)), 8, 6, 0x404040); + fontRenderer.drawString(GuiText.inventory.getLocal(), 8, ySize - 94, 0x404040); + GlStateManager.color(1F, 1F, 1F, 1F); + + IAEFluidTank fluidInv = cont.getTile().getFluidInventory(); + FluidRenderUtils.renderFluidIntoGuiCleanly(TANK_X, TANK_Y, TANK_WIDTH, TANK_HEIGHT, + fluidInv.getFluidInSlot(0), fluidInv.getTankProperties()[0].getCapacity()); + + mouseRegions.render(mouseX, mouseY); + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/client/GuiFCPriority.java b/src/main/java/com/glodblock/github/client/GuiFCPriority.java new file mode 100644 index 000000000..552a4bf5b --- /dev/null +++ b/src/main/java/com/glodblock/github/client/GuiFCPriority.java @@ -0,0 +1,43 @@ +package com.glodblock.github.client; + +import appeng.client.gui.implementations.GuiPriority; +import appeng.client.gui.widgets.GuiTabButton; +import com.glodblock.github.interfaces.FCPriorityHost; +import com.glodblock.github.inventory.GuiType; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.util.Ae2ReflectClient; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.InventoryPlayer; + +import java.io.IOException; + +public class GuiFCPriority extends GuiPriority { + + private final GuiType originalGui; + private GuiTabButton originalGuiBtn; + + public GuiFCPriority(final InventoryPlayer inventoryPlayer, final FCPriorityHost te) { + super(inventoryPlayer, te); + this.originalGui = te.getGuiType(); + } + + @Override + public void initGui() { + super.initGui(); + originalGuiBtn = Ae2ReflectClient.getOriginalGuiButton(this); + } + + @Override + protected void actionPerformed(final GuiButton btn) throws IOException { + if (btn == originalGuiBtn) { + InventoryHandler.switchGui(originalGui); + } else { + super.actionPerformed(btn); + } + } + + protected String getBackground() { + return "guis/priority.png"; + } + +} diff --git a/src/main/java/com/glodblock/github/client/GuiFluidDualInterface.java b/src/main/java/com/glodblock/github/client/GuiFluidDualInterface.java new file mode 100644 index 000000000..aaab99da8 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/GuiFluidDualInterface.java @@ -0,0 +1,50 @@ +package com.glodblock.github.client; + +import appeng.api.AEApi; +import appeng.client.gui.widgets.GuiTabButton; +import appeng.fluids.client.gui.GuiFluidInterface; +import appeng.fluids.helper.IFluidInterfaceHost; +import com.glodblock.github.inventory.GuiType; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.util.Ae2ReflectClient; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; + +import java.io.IOException; + +public class GuiFluidDualInterface extends GuiFluidInterface { + + private GuiTabButton switchInterface; + private GuiTabButton priorityBtn; + + public GuiFluidDualInterface(final InventoryPlayer ip, final IFluidInterfaceHost te) { + super(ip, te); + } + + @Override + public void initGui() { + super.initGui(); + ItemStack icon = AEApi.instance().definitions().blocks().iface().maybeStack(1).orElse(ItemStack.EMPTY); + switchInterface = new GuiTabButton(guiLeft + 133, guiTop, icon, icon.getDisplayName(), itemRender); + buttonList.add(switchInterface); + priorityBtn = Ae2ReflectClient.getPriorityButton(this); + } + + @Override + protected void actionPerformed(final GuiButton btn) throws IOException { + if (btn == switchInterface) { + InventoryHandler.switchGui(GuiType.DUAL_ITEM_INTERFACE); + } else if (btn == priorityBtn) { + InventoryHandler.switchGui(GuiType.PRIORITY); + } else { + super.actionPerformed(btn); + } + } + + @Override + protected boolean drawUpgrades() { + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/client/GuiFluidPacketDecoder.java b/src/main/java/com/glodblock/github/client/GuiFluidPacketDecoder.java new file mode 100644 index 000000000..0dd00f871 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/GuiFluidPacketDecoder.java @@ -0,0 +1,33 @@ +package com.glodblock.github.client; + +import appeng.client.gui.AEBaseGui; +import appeng.core.localization.GuiText; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.container.ContainerFluidPacketDecoder; +import com.glodblock.github.common.tile.TileFluidPacketDecoder; +import com.glodblock.github.util.NameConst; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.util.ResourceLocation; + +public class GuiFluidPacketDecoder extends AEBaseGui { + + private static final ResourceLocation TEX_BG = FluidCraft.resource("textures/gui/fluid_packet_decoder.png"); + + public GuiFluidPacketDecoder(InventoryPlayer ipl, TileFluidPacketDecoder tile) { + super(new ContainerFluidPacketDecoder(ipl, tile)); + } + + @Override + public void drawBG(int offsetX, int offsetY, int mouseX, int mouseY) { + mc.getTextureManager().bindTexture(TEX_BG); + drawTexturedModalRect(offsetX, offsetY, 0, 0, 176, ySize); + } + + @Override + public void drawFG(int offsetX, int offsetY, int mouseX, int mouseY) { + fontRenderer.drawString(getGuiDisplayName(I18n.format(NameConst.GUI_FLUID_PACKET_DECODER)), 8, 6, 0x404040); + fontRenderer.drawString(GuiText.inventory.getLocal(), 8, ySize - 94, 0x404040); + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/client/GuiFluidPatternTerminal.java b/src/main/java/com/glodblock/github/client/GuiFluidPatternTerminal.java new file mode 100644 index 000000000..1bac12d21 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/GuiFluidPatternTerminal.java @@ -0,0 +1,53 @@ +package com.glodblock.github.client; + +import appeng.api.storage.ITerminalHost; +import appeng.client.gui.implementations.GuiPatternTerm; +import appeng.client.gui.widgets.GuiTabButton; +import appeng.client.render.StackSizeRenderer; +import appeng.container.slot.SlotFake; +import com.glodblock.github.client.container.ContainerFluidPatternTerminal; +import com.glodblock.github.client.render.FluidRenderUtils; +import com.glodblock.github.inventory.GuiType; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.util.Ae2ReflectClient; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; + +public class GuiFluidPatternTerminal extends GuiPatternTerm { + + private final StackSizeRenderer stackSizeRenderer = Ae2ReflectClient.getStackSizeRenderer(this); + private GuiTabButton craftingStatusBtn; + + public GuiFluidPatternTerminal(InventoryPlayer inventoryPlayer, ITerminalHost te) { + super(inventoryPlayer, te); + ContainerFluidPatternTerminal container = new ContainerFluidPatternTerminal(inventoryPlayer, te); + container.setGui(this); + this.inventorySlots = container; + Ae2ReflectClient.setGuiContainer(this, container); + } + + @Override + public void initGui() { + super.initGui(); + craftingStatusBtn = Ae2ReflectClient.getCraftingStatusButton(this); + } + + @Override + public void drawSlot(Slot slot) { + if (!(slot instanceof SlotFake && FluidRenderUtils.renderFluidPacketIntoGuiSlot( + slot, slot.getStack(), stackSizeRenderer, fontRenderer))) { + super.drawSlot(slot); + } + } + + @Override + protected void actionPerformed(final GuiButton btn) { + if (btn == craftingStatusBtn) { + InventoryHandler.switchGui(GuiType.FLUID_PAT_TERM_CRAFTING_STATUS); + } else { + super.actionPerformed(btn); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/client/GuiFluidPatternTerminalCraftingStatus.java b/src/main/java/com/glodblock/github/client/GuiFluidPatternTerminalCraftingStatus.java new file mode 100644 index 000000000..fec68de3a --- /dev/null +++ b/src/main/java/com/glodblock/github/client/GuiFluidPatternTerminalCraftingStatus.java @@ -0,0 +1,37 @@ +package com.glodblock.github.client; + +import appeng.api.storage.ITerminalHost; +import appeng.client.gui.implementations.GuiCraftingStatus; +import appeng.client.gui.widgets.GuiTabButton; +import com.glodblock.github.inventory.GuiType; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.util.Ae2ReflectClient; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.InventoryPlayer; + +import java.io.IOException; + +public class GuiFluidPatternTerminalCraftingStatus extends GuiCraftingStatus { + + private GuiTabButton originalGuiBtn; + + public GuiFluidPatternTerminalCraftingStatus(InventoryPlayer inventoryPlayer, ITerminalHost te) { + super(inventoryPlayer, te); + } + + @Override + public void initGui() { + super.initGui(); + originalGuiBtn = Ae2ReflectClient.getOriginalGuiButton(this); + } + + @Override + protected void actionPerformed(final GuiButton btn) throws IOException { + if (btn == originalGuiBtn) { + InventoryHandler.switchGui(GuiType.FLUID_PATTERN_TERMINAL); + } else { + super.actionPerformed(btn); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/client/GuiIngredientBuffer.java b/src/main/java/com/glodblock/github/client/GuiIngredientBuffer.java new file mode 100644 index 000000000..c41816192 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/GuiIngredientBuffer.java @@ -0,0 +1,77 @@ +package com.glodblock.github.client; + +import appeng.client.gui.AEBaseGui; +import appeng.core.localization.GuiText; +import appeng.fluids.util.IAEFluidTank; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.container.ContainerIngredientBuffer; +import com.glodblock.github.client.render.FluidRenderUtils; +import com.glodblock.github.common.tile.TileIngredientBuffer; +import com.glodblock.github.handler.ButtonMouseHandler; +import com.glodblock.github.handler.TankMouseHandler; +import com.glodblock.github.util.MouseRegionManager; +import com.glodblock.github.util.NameConst; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.util.ResourceLocation; + +import java.io.IOException; + +public class GuiIngredientBuffer extends AEBaseGui { + + private static final ResourceLocation TEX_BG = FluidCraft.resource("textures/gui/ingredient_buffer.png"); + private static final int TANK_X = 47, TANK_X_OFF = 22, TANK_Y = 18; + private static final int TANK_WIDTH = 16, TANK_HEIGHT = 74; + + private final ContainerIngredientBuffer cont; + private final MouseRegionManager mouseRegions = new MouseRegionManager(this); + + public GuiIngredientBuffer(InventoryPlayer ipl, TileIngredientBuffer tile) { + super(new ContainerIngredientBuffer(ipl, tile)); + this.cont = (ContainerIngredientBuffer)inventorySlots; + this.ySize = 222; + for (int i = 0; i < 4; i++) { + mouseRegions.addRegion(TANK_X + TANK_X_OFF * i, TANK_Y, TANK_WIDTH, TANK_HEIGHT, + new TankMouseHandler(cont.getTile().getFluidInventory(), i)); + mouseRegions.addRegion(TANK_X + 10 + 22 * i, TANK_Y + TANK_HEIGHT + 2, 7, 7, + ButtonMouseHandler.dumpTank(cont, i)); + } + } + + @Override + protected void mouseClicked(int xCoord, int yCoord, int btn) throws IOException { + if (mouseRegions.onClick(xCoord, yCoord, btn)) { + super.mouseClicked(xCoord, yCoord, btn); + } + } + + @Override + public void drawBG(int offsetX, int offsetY, int mouseX, int mouseY) { + mc.getTextureManager().bindTexture(TEX_BG); + drawTexturedModalRect(offsetX, offsetY, 0, 0, 176, ySize); + } + + @Override + public void drawFG(int offsetX, int offsetY, int mouseX, int mouseY) { + fontRenderer.drawString(getGuiDisplayName(I18n.format(NameConst.GUI_INGREDIENT_BUFFER)), 8, 6, 0x404040); + fontRenderer.drawString(GuiText.inventory.getLocal(), 8, ySize - 94, 0x404040); + GlStateManager.color(1F, 1F, 1F, 1F); + + IAEFluidTank fluidInv = cont.getTile().getFluidInventory(); + mc.getTextureManager().bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); + Tessellator tess = Tessellator.getInstance(); + BufferBuilder buf = tess.getBuffer(); + for (int i = 0; i < 4; i++) { + FluidRenderUtils.renderFluidIntoGui(tess, buf, TANK_X + i * TANK_X_OFF, TANK_Y, TANK_WIDTH, TANK_HEIGHT, + fluidInv.getFluidInSlot(i), fluidInv.getTankProperties()[i].getCapacity()); + } + GlStateManager.color(1F, 1F, 1F, 1F); + + mouseRegions.render(mouseX, mouseY); + } + +} diff --git a/src/main/java/com/glodblock/github/client/GuiItemDualInterface.java b/src/main/java/com/glodblock/github/client/GuiItemDualInterface.java new file mode 100644 index 000000000..60dde6ed2 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/GuiItemDualInterface.java @@ -0,0 +1,50 @@ +package com.glodblock.github.client; + +import appeng.api.AEApi; +import appeng.client.gui.implementations.GuiInterface; +import appeng.client.gui.widgets.GuiTabButton; +import appeng.helpers.IInterfaceHost; +import com.glodblock.github.inventory.GuiType; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.util.Ae2ReflectClient; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; + +import java.io.IOException; + +public class GuiItemDualInterface extends GuiInterface { + + private GuiTabButton switchInterface; + private GuiTabButton priorityBtn; + + public GuiItemDualInterface(final InventoryPlayer inventoryPlayer, final IInterfaceHost te) { + super(inventoryPlayer, te); + } + + @Override + protected void addButtons() { + super.addButtons(); + ItemStack icon = AEApi.instance().definitions().blocks().fluidIface().maybeStack(1).orElse(ItemStack.EMPTY); + switchInterface = new GuiTabButton(guiLeft + 133, guiTop, icon, icon.getDisplayName(), itemRender); + buttonList.add(switchInterface); + priorityBtn = Ae2ReflectClient.getPriorityButton(this); + } + + @Override + protected String getBackground() { + return "guis/interface.png"; + } + + @Override + protected void actionPerformed(final GuiButton btn) throws IOException { + if (btn == switchInterface) { + InventoryHandler.switchGui(GuiType.DUAL_FLUID_INTERFACE); + } else if (btn == priorityBtn) { + InventoryHandler.switchGui(GuiType.PRIORITY); + } else { + super.actionPerformed(btn); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/client/container/ContainerBurette.java b/src/main/java/com/glodblock/github/client/container/ContainerBurette.java new file mode 100644 index 000000000..6a1bf5a7e --- /dev/null +++ b/src/main/java/com/glodblock/github/client/container/ContainerBurette.java @@ -0,0 +1,134 @@ +package com.glodblock.github.client.container; + +import appeng.api.storage.data.IAEFluidStack; +import appeng.container.AEBaseContainer; +import appeng.container.slot.SlotNormal; +import appeng.fluids.container.IFluidSyncContainer; +import appeng.fluids.helper.FluidSyncHelper; +import appeng.fluids.util.IAEFluidTank; +import appeng.util.Platform; +import com.glodblock.github.common.tile.TileBurette; +import com.glodblock.github.interfaces.TankDumpable; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.IContainerListener; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandlerItem; +import net.minecraftforge.fluids.capability.IFluidTankProperties; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; + +public class ContainerBurette extends AEBaseContainer implements IFluidSyncContainer, TankDumpable { + + private final TileBurette tile; + private final FluidSyncHelper fluidSync; + + public ContainerBurette(InventoryPlayer ipl, TileBurette tile) { + super(ipl, tile); + this.tile = tile; + this.fluidSync = new FluidSyncHelper(tile.getFluidInventory(), 0); + addSlotToContainer(new SlotNormal(tile.getInternalInventory(), 0, 52, 53)); + bindPlayerInventory(ipl, 0, 84); + } + + public TileBurette getTile() { + return tile; + } + + public boolean canTranferFluid(boolean into) { + IAEFluidTank tileTank = tile.getFluidInventory(); + IFluidTankProperties tileTankInfo = tileTank.getTankProperties()[0]; + IAEFluidStack tileFluid = tileTank.getFluidInSlot(0); + if (into) { + if (tileFluid != null && tileFluid.getStackSize() >= tileTankInfo.getCapacity()) { + return false; + } + } else if (tileFluid == null) { + return false; + } + ItemStack stack = tile.getInternalInventory().getStackInSlot(0); + if (stack.isEmpty() || !stack.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null)) { + return false; + } + IFluidHandlerItem itemTank = Objects.requireNonNull( + stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null)); + for (IFluidTankProperties itemTankInfo : itemTank.getTankProperties()) { + if (into) { + if (itemTankInfo.canDrain() && tileTankInfo.canFillFluidType(itemTankInfo.getContents())) { + return true; + } + } else if (itemTankInfo.canFillFluidType(tileFluid.getFluidStack())) { + return true; + } + } + return false; + } + + public void tryTransferFluid(int amount, boolean into) { + ItemStack stack = tile.getInternalInventory().getStackInSlot(0); + if (stack.isEmpty() || !stack.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null)) { + return; + } + IAEFluidTank tileTank = tile.getFluidInventory(); + IFluidHandlerItem itemTank = Objects.requireNonNull( + stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null)); + if (into) { + transferFluidBetween(itemTank, tileTank, amount); + } else { + transferFluidBetween(tileTank, itemTank, amount); + } + tile.getInternalInventory().setStackInSlot(0, itemTank.getContainer()); + } + + private void transferFluidBetween(IFluidHandler from, IFluidHandler to, int amount) { + // simulated pass to figure out the real amount we can transfer + FluidStack fluid = from.drain(amount, false); + if (fluid == null) { + return; + } + amount = Math.min(amount, to.fill(fluid, false)); + // actually do the transfer + fluid = from.drain(amount, true); + if (fluid != null) { + fluid.amount -= to.fill(fluid, true); + if (fluid.amount > 0) { // just in case the tanks don't behave exactly as simulated + from.fill(fluid, true); + } + } + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + if (Platform.isServer()) { + fluidSync.sendDiff(listeners); + } + } + + @Override + public void addListener(@Nonnull IContainerListener listener) { + super.addListener(listener); + fluidSync.sendFull(Collections.singleton(listener)); + } + + @Override + public void receiveFluidSlots(Map fluids) { + fluidSync.readPacket(fluids); + } + + @Override + public boolean canDumpTank(int index) { + return tile.getFluidInventory().getFluidInSlot(0) != null; + } + + @Override + public void dumpTank(int index) { + tile.getFluidInventory().setFluidInSlot(0, null); + } + +} diff --git a/src/main/java/com/glodblock/github/client/container/ContainerFluidPacketDecoder.java b/src/main/java/com/glodblock/github/client/container/ContainerFluidPacketDecoder.java new file mode 100644 index 000000000..220f8b06a --- /dev/null +++ b/src/main/java/com/glodblock/github/client/container/ContainerFluidPacketDecoder.java @@ -0,0 +1,16 @@ +package com.glodblock.github.client.container; + +import appeng.container.AEBaseContainer; +import appeng.container.slot.SlotNormal; +import com.glodblock.github.common.tile.TileFluidPacketDecoder; +import net.minecraft.entity.player.InventoryPlayer; + +public class ContainerFluidPacketDecoder extends AEBaseContainer { + + public ContainerFluidPacketDecoder(InventoryPlayer ipl, TileFluidPacketDecoder tile) { + super(ipl, tile); + addSlotToContainer(new SlotNormal(tile.getInventory(), 0, 80, 35)); + bindPlayerInventory(ipl, 0, 84); + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/client/container/ContainerFluidPatternEncoder.java b/src/main/java/com/glodblock/github/client/container/ContainerFluidPatternEncoder.java new file mode 100644 index 000000000..139052825 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/container/ContainerFluidPatternEncoder.java @@ -0,0 +1,216 @@ +package com.glodblock.github.client.container; + +import appeng.api.AEApi; +import appeng.api.storage.data.IAEItemStack; +import appeng.container.AEBaseContainer; +import appeng.container.slot.SlotFake; +import appeng.container.slot.SlotRestrictedInput; +import appeng.helpers.InventoryAction; +import appeng.util.item.AEItemStack; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidEncodedPattern; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.common.tile.TileFluidPatternEncoder; +import com.glodblock.github.handler.AeItemStackHandler; +import com.glodblock.github.interfaces.AeStackInventory; +import com.glodblock.github.interfaces.PatternConsumer; +import com.glodblock.github.interfaces.SlotFluid; +import com.glodblock.github.loader.FCItems; +import com.glodblock.github.util.FluidPatternDetails; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidTankProperties; +import net.minecraftforge.items.ItemHandlerHelper; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class ContainerFluidPatternEncoder extends AEBaseContainer implements PatternConsumer { + + private final TileFluidPatternEncoder tile; + + public ContainerFluidPatternEncoder(InventoryPlayer ipl, TileFluidPatternEncoder tile) { + super(ipl, tile); + this.tile = tile; + AeItemStackHandler crafting = new AeItemStackHandler(tile.getCraftingSlots()); + AeItemStackHandler output = new AeItemStackHandler(tile.getOutputSlots()); + for (int y = 0; y < 3; y++) { + for (int x = 0; x < 3; x++) { + addSlotToContainer(new SlotFluidConvertingFake(crafting, y * 3 + x, 23 + x * 18, 17 + y * 18)); + } + addSlotToContainer(new SlotFluidConvertingFake(output, y, 113, 17 + y * 18)); + } + addSlotToContainer(new SlotRestrictedInput( + SlotRestrictedInput.PlacableItemType.BLANK_PATTERN, tile.getInventory(), 0, 138, 20, ipl)); + addSlotToContainer(new SlotRestrictedInput( + SlotRestrictedInput.PlacableItemType.ENCODED_PATTERN, tile.getInventory(), 1, 138, 50, ipl)); + bindPlayerInventory(ipl, 0, 84); + } + + public TileFluidPatternEncoder getTile() { + return tile; + } + + public boolean canEncodePattern() { + if (isNotPattern(tile.getInventory().getStackInSlot(0)) && isNotPattern(tile.getInventory().getStackInSlot(1))) { + return false; + } + find_input: + { + for (IAEItemStack stack : tile.getCraftingSlots()) { + if (stack != null && stack.getStackSize() > 0) { + break find_input; + } + } + return false; + } + for (IAEItemStack stack : tile.getOutputSlots()) { + if (stack != null && stack.getStackSize() > 0) { + return true; + } + } + return false; + } + + private static boolean isNotPattern(ItemStack stack) { + return stack.isEmpty() || !(AEApi.instance().definitions().materials().blankPattern().isSameAs(stack) + || (stack.getItem() instanceof ItemFluidEncodedPattern)); + } + + public void encodePattern() { + if (canEncodePattern()) { + // if there is an encoded pattern, overwrite it; otherwise, consume a blank + if (tile.getInventory().getStackInSlot(1).isEmpty()) { + tile.getInventory().extractItem(0, 1, false); // this better work + } + ItemStack patternStack = new ItemStack(FCItems.DENSE_ENCODED_PATTERN); + FluidPatternDetails pattern = new FluidPatternDetails(patternStack); + pattern.setInputs(collectAeInventory(tile.getCraftingSlots())); + pattern.setOutputs(collectAeInventory(tile.getOutputSlots())); + tile.getInventory().setStackInSlot(1, pattern.writeToStack()); + } + } + + private static IAEItemStack[] collectAeInventory(AeStackInventory inv) { + // see note at top of DensePatternDetails + List acc = new ArrayList<>(); + for (IAEItemStack stack : inv) { + if (stack != null) { + if (stack.getItem() instanceof ItemFluidPacket) { + IAEItemStack dropStack = ItemFluidDrop.newAeStack(ItemFluidPacket.getFluidStack(stack)); + if (dropStack != null) { + acc.add(dropStack); + continue; + } + } + acc.add(stack); + } + } + return acc.toArray(new IAEItemStack[0]); + } + + // adapted from ae2's AEBaseContainer#doAction + @Override + public void doAction(EntityPlayerMP player, InventoryAction action, int slotId, long id) { + Slot slot = getSlot(slotId); + if (slot instanceof SlotFluidConvertingFake) { + final ItemStack stack = player.inventory.getItemStack(); + switch (action) { + case PICKUP_OR_SET_DOWN: + if (stack.isEmpty()) { + slot.putStack(ItemStack.EMPTY); + } else { + ((SlotFluidConvertingFake)slot).putConvertedStack(stack.copy()); + } + break; + case PLACE_SINGLE: + if (!stack.isEmpty()) { + ((SlotFluidConvertingFake)slot).putConvertedStack(ItemHandlerHelper.copyStackWithSize(stack, 1)); + } + break; + case SPLIT_OR_PLACE_SINGLE: + ItemStack inSlot = slot.getStack(); + if (!inSlot.isEmpty()) { + if (stack.isEmpty()) { + slot.putStack(ItemHandlerHelper.copyStackWithSize(inSlot, Math.max(1, inSlot.getCount() - 1))); + } else if (stack.isItemEqual(inSlot)) { + slot.putStack(ItemHandlerHelper.copyStackWithSize(inSlot, + Math.min(inSlot.getMaxStackSize(), inSlot.getCount() + 1))); + } else { + ((SlotFluidConvertingFake)slot).putConvertedStack(ItemHandlerHelper.copyStackWithSize(stack, 1)); + } + } else if (!stack.isEmpty()) { + ((SlotFluidConvertingFake)slot).putConvertedStack(ItemHandlerHelper.copyStackWithSize(stack, 1)); + } + break; + } + } else { + super.doAction(player, action, slotId, id); + } + } + + @Override + public void acceptPattern(IAEItemStack[] inputs, IAEItemStack[] outputs) { + copyStacks(inputs, tile.getCraftingSlots()); + copyStacks(outputs, tile.getOutputSlots()); + } + + private static void copyStacks(IAEItemStack[] src, AeStackInventory dest) { + int bound = Math.min(src.length, dest.getSlotCount()); + for (int i = 0; i < bound; i++) { + dest.setStack(i, src[i]); + } + } + + private static class SlotFluidConvertingFake extends SlotFake implements SlotFluid { + + private final AeStackInventory inv; + + public SlotFluidConvertingFake(AeItemStackHandler inv, int idx, int x, int y) { + super(inv, idx, x, y); + this.inv = inv.getAeInventory(); + } + + @Override + public void putStack(ItemStack stack) { + inv.setStack(getSlotIndex(), AEItemStack.fromItemStack(stack)); + } + + @Override + public void setAeStack(@Nullable IAEItemStack stack, boolean sync) { + inv.setStack(getSlotIndex(), stack); + } + + public void putConvertedStack(ItemStack stack) { + if (stack.isEmpty()) { + setAeStack(null, false); + return; + } else if (stack.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null)) { + IFluidTankProperties[] tanks = Objects.requireNonNull( + stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null)) + .getTankProperties(); + for (IFluidTankProperties tank : tanks) { + IAEItemStack aeStack = ItemFluidPacket.newAeStack(tank.getContents()); + if (aeStack != null) { + setAeStack(aeStack, false); + return; + } + } + } + putStack(stack); + } + + @Nullable + @Override + public IAEItemStack getAeStack() { + return inv.getStack(getSlotIndex()); + } + + } + +} diff --git a/src/main/java/com/glodblock/github/client/container/ContainerFluidPatternTerminal.java b/src/main/java/com/glodblock/github/client/container/ContainerFluidPatternTerminal.java new file mode 100644 index 000000000..306e3b006 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/container/ContainerFluidPatternTerminal.java @@ -0,0 +1,148 @@ +package com.glodblock.github.client.container; + +import appeng.api.AEApi; +import appeng.api.definitions.IDefinitions; +import appeng.api.storage.ITerminalHost; +import appeng.api.storage.data.IAEItemStack; +import appeng.container.implementations.ContainerPatternTerm; +import appeng.util.item.AEItemStack; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidEncodedPattern; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.common.part.PartFluidPatternTerminal; +import com.glodblock.github.interfaces.PatternConsumer; +import com.glodblock.github.loader.FCItems; +import com.glodblock.github.util.Ae2Reflect; +import com.glodblock.github.util.FluidPatternDetails; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +import java.util.ArrayList; +import java.util.List; + +public class ContainerFluidPatternTerminal extends ContainerPatternTerm implements PatternConsumer { + + private final Slot[] craftingSlots; + private final Slot[] outputSlots; + private final Slot patternSlotIN; + private final Slot patternSlotOUT; + + public ContainerFluidPatternTerminal(InventoryPlayer ip, ITerminalHost monitorable) { + super(ip, monitorable); + craftingSlots = Ae2Reflect.getCraftingSlots(this); + outputSlots = Ae2Reflect.getOutputSlots(this); + patternSlotIN = Ae2Reflect.getPatternSlotIn(this); + patternSlotOUT = Ae2Reflect.getPatternSlotOut(this); + } + + @Override + public void encode() { + if (!checkHasFluidPattern()) { + super.encode(); + return; + } + ItemStack stack = this.patternSlotOUT.getStack(); + if (stack.isEmpty()) { + stack = this.patternSlotIN.getStack(); + if (stack.isEmpty() || !isPattern(stack)) { + return; + } + if (stack.getCount() == 1) { + this.patternSlotIN.putStack(ItemStack.EMPTY); + } else { + stack.shrink(1); + } + encodeFluidPattern(); + } else if (isPattern(stack)) { + encodeFluidPattern(); + } + } + + private static boolean isPattern(final ItemStack output) { + if (output.isEmpty()) { + return false; + } + if (output.getItem() instanceof ItemFluidEncodedPattern) { + return true; + } + final IDefinitions defs = AEApi.instance().definitions(); + return defs.items().encodedPattern().isSameAs(output) || defs.materials().blankPattern().isSameAs(output); + } + + private boolean checkHasFluidPattern() { + if (this.craftingMode) { + return false; + } + boolean hasFluid = false, search = false; + for (Slot craftingSlot : this.craftingSlots) { + final ItemStack crafting = craftingSlot.getStack(); + if (crafting.isEmpty()) { + continue; + } + search = true; + if (crafting.getItem() instanceof ItemFluidPacket) { + hasFluid = true; + break; + } + } + if (!search) { // search=false -> inputs were empty + return false; + } + // `search` should be true at this point + for (Slot outputSlot : this.outputSlots) { + final ItemStack out = outputSlot.getStack(); + if (out.isEmpty()) { + continue; + } + search = false; + if (hasFluid) { + break; + } else if (out.getItem() instanceof ItemFluidPacket) { + hasFluid = true; + break; + } + } + return hasFluid && !search; // search=true -> outputs were empty + } + + private void encodeFluidPattern() { + ItemStack patternStack = new ItemStack(FCItems.DENSE_ENCODED_PATTERN); + FluidPatternDetails pattern = new FluidPatternDetails(patternStack); + pattern.setInputs(collectInventory(craftingSlots)); + pattern.setOutputs(collectInventory(outputSlots)); + patternSlotOUT.putStack(pattern.writeToStack()); + } + + private static IAEItemStack[] collectInventory(Slot[] slots) { + // see note at top of DensePatternDetails + List acc = new ArrayList<>(); + for (Slot slot : slots) { + ItemStack stack = slot.getStack(); + if (stack.isEmpty()) { + continue; + } + if (stack.getItem() instanceof ItemFluidPacket) { + IAEItemStack dropStack = ItemFluidDrop.newAeStack(ItemFluidPacket.getFluidStack(stack)); + if (dropStack != null) { + acc.add(dropStack); + continue; + } + } + IAEItemStack aeStack = AEItemStack.fromItemStack(stack); + if (aeStack == null) { + continue; + } + acc.add(aeStack); + } + return acc.toArray(new IAEItemStack[0]); + } + + @Override + public void acceptPattern(IAEItemStack[] inputs, IAEItemStack[] outputs) { + if (getPatternTerminal() instanceof PartFluidPatternTerminal) { + ((PartFluidPatternTerminal)getPatternTerminal()).onChangeCrafting(inputs, outputs); + } + } + +} diff --git a/src/main/java/com/glodblock/github/client/container/ContainerIngredientBuffer.java b/src/main/java/com/glodblock/github/client/container/ContainerIngredientBuffer.java new file mode 100644 index 000000000..9cab2265f --- /dev/null +++ b/src/main/java/com/glodblock/github/client/container/ContainerIngredientBuffer.java @@ -0,0 +1,40 @@ +package com.glodblock.github.client.container; + +import appeng.container.AEBaseContainer; +import appeng.container.slot.SlotNormal; +import com.glodblock.github.common.tile.TileIngredientBuffer; +import com.glodblock.github.interfaces.TankDumpable; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraftforge.items.IItemHandler; + +public class ContainerIngredientBuffer extends AEBaseContainer implements TankDumpable { + + private final TileIngredientBuffer tile; + + public ContainerIngredientBuffer(InventoryPlayer ipl, TileIngredientBuffer tile) { + super(ipl, tile); + this.tile = tile; + IItemHandler inv = tile.getInternalInventory(); + for (int i = 0; i < 9; i++) { + addSlotToContainer(new SlotNormal(inv, i, 8 + 18 * i, 108)); + } + bindPlayerInventory(ipl, 0, 140); + } + + public TileIngredientBuffer getTile() { + return tile; + } + + @Override + public boolean canDumpTank(int index) { + return tile.getFluidInventory().getFluidInSlot(index) != null; + } + + @Override + public void dumpTank(int index) { + if (index >= 0 && index < tile.getFluidInventory().getSlots()) { + tile.getFluidInventory().setFluidInSlot(index, null); + } + } + +} diff --git a/src/main/java/com/glodblock/github/client/container/GuiFluidPatternEncoder.java b/src/main/java/com/glodblock/github/client/container/GuiFluidPatternEncoder.java new file mode 100644 index 000000000..1ca5dfdef --- /dev/null +++ b/src/main/java/com/glodblock/github/client/container/GuiFluidPatternEncoder.java @@ -0,0 +1,107 @@ +package com.glodblock.github.client.container; + +import appeng.api.storage.data.IAEItemStack; +import appeng.client.gui.AEBaseGui; +import appeng.client.render.StackSizeRenderer; +import appeng.core.localization.GuiText; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.render.FluidRenderUtils; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.common.tile.TileFluidPatternEncoder; +import com.glodblock.github.interfaces.SlotFluid; +import com.glodblock.github.inventory.slot.SlotSingleItem; +import com.glodblock.github.network.CPacketEncodePattern; +import com.glodblock.github.util.Ae2ReflectClient; +import com.glodblock.github.util.MouseRegionManager; +import com.glodblock.github.util.NameConst; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.fluids.FluidStack; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class GuiFluidPatternEncoder extends AEBaseGui { + + private static final ResourceLocation TEX_BG = FluidCraft.resource("textures/gui/fluid_pattern_encoder.png"); + + private final ContainerFluidPatternEncoder cont; + private final MouseRegionManager mouseRegions = new MouseRegionManager(this); + private final StackSizeRenderer stackSizeRenderer = Ae2ReflectClient.getStackSizeRenderer(this); + + public GuiFluidPatternEncoder(InventoryPlayer ipl, TileFluidPatternEncoder tile) { + super(new ContainerFluidPatternEncoder(ipl, tile)); + this.cont = (ContainerFluidPatternEncoder)inventorySlots; + mouseRegions.addRegion(141, 38, 10, 10, new MouseRegionManager.Handler() { + @Override + public List getTooltip() { + return Collections.singletonList(I18n.format(NameConst.TT_ENCODE_PATTERN)); + } + + @Override + public boolean onClick(int button) { + if (button == 0) { + if (cont.canEncodePattern()) { + FluidCraft.proxy.netHandler.sendToServer(new CPacketEncodePattern()); + } + return true; + } + return false; + } + }); + } + + @Override + protected void mouseClicked(int xCoord, int yCoord, int btn) throws IOException { + if (mouseRegions.onClick(xCoord, yCoord, btn)) { + super.mouseClicked(xCoord, yCoord, btn); + } + } + + @Override + public void drawBG(int offsetX, int offsetY, int mouseX, int mouseY) { + mc.getTextureManager().bindTexture(TEX_BG); + drawTexturedModalRect(offsetX, offsetY, 0, 0, 176, ySize); + } + + @Override + public void drawFG(int offsetX, int offsetY, int mouseX, int mouseY) { + fontRenderer.drawString(getGuiDisplayName(I18n.format(NameConst.GUI_FLUID_PATTERN_ENCODER)), 8, 6, 0x404040); + fontRenderer.drawString(GuiText.inventory.getLocal(), 8, ySize - 94, 0x404040); + mouseRegions.render(mouseX, mouseY); + } + + @Override + public void drawSlot(Slot slot) { + if (slot instanceof SlotFluid) { + IAEItemStack stack = ((SlotFluid)slot).getAeStack(); + if (FluidRenderUtils.renderFluidPacketIntoGuiSlot(slot, stack, stackSizeRenderer, fontRenderer)) { + return; + } + super.drawSlot(new SlotSingleItem(slot)); + stackSizeRenderer.renderStackSize(fontRenderer, stack, slot.xPos, slot.yPos); + } else { + super.drawSlot(slot); + } + } + + @Override + @Nonnull + public List getItemToolTip(ItemStack stack) { + if (stack.getItem() instanceof ItemFluidPacket) { + FluidStack fluid = ItemFluidPacket.getFluidStack(stack); + if (fluid != null) { + return Arrays.asList(fluid.getLocalizedName(), String.format(TextFormatting.GRAY + "%,d mB", fluid.amount)); + } + } + return super.getItemToolTip(stack); + } + +} diff --git a/src/main/java/com/glodblock/github/client/model/DenseEncodedPatternModel.java b/src/main/java/com/glodblock/github/client/model/DenseEncodedPatternModel.java new file mode 100644 index 000000000..7be8e3e8c --- /dev/null +++ b/src/main/java/com/glodblock/github/client/model/DenseEncodedPatternModel.java @@ -0,0 +1,67 @@ +package com.glodblock.github.client.model; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.util.Ae2ReflectClient; +import com.glodblock.github.util.NameConst; +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.ICustomModelLoader; +import net.minecraftforge.client.model.IModel; +import net.minecraftforge.client.model.ModelLoaderRegistry; +import net.minecraftforge.client.model.PerspectiveMapWrapper; +import net.minecraftforge.common.model.IModelState; + +import javax.annotation.Nonnull; +import java.util.Collection; +import java.util.Collections; +import java.util.function.Function; + +public class DenseEncodedPatternModel implements IModel { + + private static final ResourceLocation BASE_MODEL = FluidCraft.resource("item/dense_encoded_pattern"); + + @Override + @Nonnull + public Collection getDependencies() { + return Collections.singletonList(BASE_MODEL); + } + + // adapted from ae2's ItemEncodedPatternModel#bake + @Override + @Nonnull + public IBakedModel bake(@Nonnull IModelState state, @Nonnull VertexFormat format, @Nonnull Function bakedTextureGetter) { + IBakedModel baseModel; + try { + baseModel = ModelLoaderRegistry.getModel(BASE_MODEL).bake(state, format, bakedTextureGetter); + } catch (Exception e) { + throw new RuntimeException(e); + } + return Ae2ReflectClient.bakeEncodedPatternModel(baseModel, PerspectiveMapWrapper.getTransforms(state)); + } + + public static class Loader implements ICustomModelLoader { + + @Override + public void onResourceManagerReload(@Nonnull IResourceManager resourceManager) { + // NO-OP + } + + @Override + public boolean accepts(ResourceLocation modelLocation) { + // modelLocation will probably be a ModelResourceLocation, so using compareTo lets us bypass the + // ModelResourceLocation equality behaviour and fall back to that of ResourceLocation + return modelLocation.compareTo(NameConst.MODEL_DENSE_ENCODED_PATTERN) == 0; + } + + @Override + @Nonnull + public IModel loadModel(@Nonnull ResourceLocation modelLocation) { + return new DenseEncodedPatternModel(); + } + + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/client/model/FluidPacketModel.java b/src/main/java/com/glodblock/github/client/model/FluidPacketModel.java new file mode 100644 index 000000000..5f8ec5dde --- /dev/null +++ b/src/main/java/com/glodblock/github/client/model/FluidPacketModel.java @@ -0,0 +1,234 @@ +package com.glodblock.github.client.model; + +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.util.FluidKey; +import com.glodblock.github.util.NameConst; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.*; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import net.minecraftforge.client.model.ICustomModelLoader; +import net.minecraftforge.client.model.IModel; +import net.minecraftforge.client.model.ItemLayerModel; +import net.minecraftforge.common.model.IModelState; +import net.minecraftforge.common.model.TRSRTransformation; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; +import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.util.vector.Vector3f; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.vecmath.Matrix4f; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +public class FluidPacketModel implements IModel { + + @SuppressWarnings("deprecation") + private static final ItemCameraTransforms CAMERA_TRANSFORMS = new ItemCameraTransforms( + new ItemTransformVec3f(new Vector3f(0F, 0F, 0F), new Vector3f(0F, 0.1875F, 0.0625F), new Vector3f(0.55F, 0.55F, 0.55F)), + new ItemTransformVec3f(new Vector3f(0F, 0F, 0F), new Vector3f(0F, 0.1875F, 0.0625F), new Vector3f(0.55F, 0.55F, 0.55F)), + new ItemTransformVec3f(new Vector3f(0F, -90F, 25F), new Vector3f(0.070625F, 0.2F, 0.070625F), new Vector3f(0.68F, 0.68F, 0.68F)), + new ItemTransformVec3f(new Vector3f(0F, -90F, 25F), new Vector3f(0.070625F, 0.2F, 0.070625F), new Vector3f(0.68F, 0.68F, 0.68F)), + new ItemTransformVec3f(new Vector3f(0F, 180F, 0F), new Vector3f(0F, 0.8125F, 0.4375F), new Vector3f(1F, 1F, 1F)), + ItemTransformVec3f.DEFAULT, + new ItemTransformVec3f(new Vector3f(0F, 0F, 0F), new Vector3f(0F, 0.125F, 0F), new Vector3f(0.5F, 0.5F, 0.5F)), + new ItemTransformVec3f(new Vector3f(0F, 180F, 0F), new Vector3f(0F, 0F, 0F), new Vector3f(1F, 1F, 1F))); + + @Override + @Nonnull + public IBakedModel bake(@Nonnull IModelState state, @Nonnull VertexFormat format, @Nonnull Function textureBakery) { + return new BakedFluidPacketModel(state, format); + } + + public static class Loader implements ICustomModelLoader { + + @Override + public void onResourceManagerReload(@Nonnull IResourceManager resourceManager) { + // NO-OP + } + + @Override + public boolean accepts(ResourceLocation modelLocation) { + // modelLocation will probably be a ModelResourceLocation, so using compareTo lets us bypass the + // ModelResourceLocation equality behaviour and fall back to that of ResourceLocation + return modelLocation.compareTo(NameConst.MODEL_FLUID_PACKET) == 0; + } + + @Override + @Nonnull + public IModel loadModel(@Nonnull ResourceLocation modelLocation) { + return new FluidPacketModel(); + } + + } + + private static class BakedFluidPacketModel implements IBakedModel { + + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") + private final Optional modelTransform; + private final VertexFormat vertexFormat; + private final OverrideCache overrides; + private final OverrideCache.OverrideModel defaultOverride; + + public BakedFluidPacketModel(IModelState modelState, VertexFormat vertexFormat) { + this.modelTransform = modelState.apply(Optional.empty()); + this.vertexFormat = vertexFormat; + this.overrides = new OverrideCache(); + this.defaultOverride = overrides.resolve(new FluidStack(FluidRegistry.WATER, Fluid.BUCKET_VOLUME)); + } + + @Override + @Nonnull + public List getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand) { + return defaultOverride.getQuads(state, side, rand); + } + + @Override + public boolean isAmbientOcclusion() { + return defaultOverride.isAmbientOcclusion(); + } + + @Override + public boolean isGui3d() { + return defaultOverride.isGui3d(); + } + + @Override + public boolean isBuiltInRenderer() { + return defaultOverride.isBuiltInRenderer(); + } + + @Override + @Nonnull + public TextureAtlasSprite getParticleTexture() { + return defaultOverride.getParticleTexture(); + } + + @Override + public boolean isAmbientOcclusion(@Nonnull IBlockState state) { + return defaultOverride.isAmbientOcclusion(state); + } + + @SuppressWarnings("deprecation") + @Override + @Nonnull + public ItemCameraTransforms getItemCameraTransforms() { + return defaultOverride.getItemCameraTransforms(); + } + + @Override + @Nonnull + public Pair handlePerspective(@Nonnull ItemCameraTransforms.TransformType cameraTransformType) { + return defaultOverride.handlePerspective(cameraTransformType); + } + + @Override + @Nonnull + public ItemOverrideList getOverrides() { + return overrides; + } + + private class OverrideCache extends ItemOverrideList { + + private final Cache cache = CacheBuilder.newBuilder() + .maximumSize(1000) // cache params borrowed from Tinkers' Construct model system, which is under MIT + .expireAfterWrite(5, TimeUnit.MINUTES) + .build(); + + OverrideCache() { + super(Collections.emptyList()); + } + + @Override + @Nonnull + public IBakedModel handleItemState(@Nonnull IBakedModel originalModel, ItemStack stack, + @Nullable World world, @Nullable EntityLivingBase entity) { + if (!(stack.getItem() instanceof ItemFluidPacket)) { + return originalModel; + } + FluidStack fluid = ItemFluidPacket.getFluidStack(stack); + return fluid != null ? resolve(fluid) : originalModel; + } + + OverrideModel resolve(FluidStack fluid) { + try { + return cache.get(new FluidKey(fluid), () -> new OverrideModel(fluid)); + } catch (ExecutionException e) { + throw new IllegalStateException(e); + } + } + + class OverrideModel implements IBakedModel { + + private final TextureAtlasSprite texture; + private final List quads; + + OverrideModel(FluidStack fluidStack) { + this.texture = Minecraft.getMinecraft().getTextureMapBlocks() + .getAtlasSprite(fluidStack.getFluid().getStill(fluidStack).toString()); + this.quads = ItemLayerModel.getQuadsForSprite(1, texture, vertexFormat, modelTransform); + } + + @Override + @Nonnull + public List getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand) { + return quads; + } + + @Override + public boolean isAmbientOcclusion() { + return false; + } + + @Override + public boolean isGui3d() { + return false; + } + + @Override + public boolean isBuiltInRenderer() { + return false; + } + + @Override + @Nonnull + public TextureAtlasSprite getParticleTexture() { + return texture; + } + + @Override + @Nonnull + @SuppressWarnings("deprecation") + public ItemCameraTransforms getItemCameraTransforms() { + return CAMERA_TRANSFORMS; + } + + @Override + @Nonnull + public ItemOverrideList getOverrides() { + return OverrideCache.this; + } + + } + + } + + } + +} diff --git a/src/main/java/com/glodblock/github/client/render/DropColourHandler.java b/src/main/java/com/glodblock/github/client/render/DropColourHandler.java new file mode 100644 index 000000000..bc8bd8f5b --- /dev/null +++ b/src/main/java/com/glodblock/github/client/render/DropColourHandler.java @@ -0,0 +1,62 @@ +package com.glodblock.github.client.render; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.HashMap; +import java.util.Map; + +public class DropColourHandler { + + private final Map colourCache = new HashMap<>(); + + @SubscribeEvent + public void onTextureMapStitch(TextureStitchEvent event) { + if (event.getMap() == Minecraft.getMinecraft().getTextureMapBlocks()) { + colourCache.clear(); + } + } + + public int getColour(FluidStack fluidStack) { + Fluid fluid = fluidStack.getFluid(); + int colour = fluid.getColor(fluidStack); + return colour != -1 ? colour : getColour(fluid); + } + + public int getColour(Fluid fluid) { + Integer cached = colourCache.get(fluid.getName()); + if (cached != null) { + return cached; + } + int colour = fluid.getColor(); + if (colour == -1) { + TextureAtlasSprite sprite = Minecraft.getMinecraft().getTextureMapBlocks() + .getTextureExtry(fluid.getStill().toString()); + if (sprite != null && sprite.getFrameCount() > 0) { + int[][] image = sprite.getFrameTextureData(0); + int r = 0, g = 0, b = 0, count = 0; + for (int[] row : image) { + for (int pixel : row) { + if (((pixel >> 24) & 0xFF) > 127) { // is alpha above 50%? + r += (pixel >> 16) & 0xFF; + g += (pixel >> 8) & 0xFF; + b += pixel & 0xFF; + ++count; + } + } + } + if (count > 0) { + // probably shouldn't need to mask each component by 0xFF + colour = ((r / count) << 16) | ((g / count) << 8) | (b / count); + } + } + } + colourCache.put(fluid.getName(), colour); + return colour; + } + +} diff --git a/src/main/java/com/glodblock/github/client/render/FluidRenderUtils.java b/src/main/java/com/glodblock/github/client/render/FluidRenderUtils.java new file mode 100644 index 000000000..add1ac295 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/render/FluidRenderUtils.java @@ -0,0 +1,127 @@ +package com.glodblock.github.client.render; + +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IAEItemStack; +import appeng.client.render.StackSizeRenderer; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import org.lwjgl.opengl.GL11; + +import javax.annotation.Nullable; + +public class FluidRenderUtils { + + @Nullable + public static TextureAtlasSprite prepareRender(@Nullable FluidStack fluidStack) { + if (fluidStack == null) { + return null; + } + Fluid fluid = fluidStack.getFluid(); + TextureAtlasSprite sprite = Minecraft.getMinecraft().getTextureMapBlocks() + .getAtlasSprite(fluid.getStill(fluidStack).toString()); + int colour = fluid.getColor(fluidStack); + GlStateManager.color( + ((colour >> 16) & 0xFF) / 255F, + ((colour >> 8) & 0xFF) / 255F, + (colour & 0xFF) / 255F, + ((colour >> 24) & 0xFF) / 255F); + return sprite; + } + + private static void doRenderFluid(Tessellator tess, BufferBuilder buf, int x, int y, int width, int height, + TextureAtlasSprite sprite, double fraction) { + GlStateManager.enableBlend(); + GlStateManager.blendFunc( + GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); + int fluidHeight = Math.round(height * (float)Math.min(1D, Math.max(0D, fraction))); + double x2 = x + width; + while (fluidHeight > 0) { + buf.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + double y1 = y + height - fluidHeight, y2 = y1 + Math.min(fluidHeight, width); + double u1 = sprite.getMinU(), v1 = sprite.getMinV(), u2 = sprite.getMaxU(), v2 = sprite.getMaxV(); + if (fluidHeight < width) { + v2 = v1 + (v2 - v1) * (fluidHeight / (double)width); + fluidHeight = 0; + } else { + //noinspection SuspiciousNameCombination + fluidHeight -= width; + } + buf.pos(x, y1, 0D).tex(u1, v1).endVertex(); + buf.pos(x, y2, 0D).tex(u1, v2).endVertex(); + buf.pos(x2, y2, 0D).tex(u2, v2).endVertex(); + buf.pos(x2, y1, 0D).tex(u2, v1).endVertex(); + tess.draw(); + } + } + + public static void renderFluidIntoGui(Tessellator tess, BufferBuilder buf, int x, int y, int width, int height, + @Nullable IAEFluidStack aeFluidStack, int capacity) { + if (aeFluidStack != null) { + TextureAtlasSprite sprite = FluidRenderUtils.prepareRender(aeFluidStack.getFluidStack()); + if (sprite != null) { + doRenderFluid(tess, buf, x, y, width, height, sprite, aeFluidStack.getStackSize() / (double)capacity); + } + } + } + + public static void renderFluidIntoGui(Tessellator tess, BufferBuilder buf, int x, int y, int width, int height, + @Nullable FluidStack fluidStack, int capacity) { + if (fluidStack != null) { + TextureAtlasSprite sprite = FluidRenderUtils.prepareRender(fluidStack); + if (sprite != null) { + doRenderFluid(tess, buf, x, y, width, height, sprite, fluidStack.amount / (double)capacity); + } + } + } + + public static void renderFluidIntoGuiCleanly(int x, int y, int width, int height, + @Nullable IAEFluidStack aeFluidStack, int capacity) { + Minecraft.getMinecraft().getTextureManager().bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); + Tessellator tess = Tessellator.getInstance(); + renderFluidIntoGui(tess, tess.getBuffer(), x, y, width, height, aeFluidStack, capacity); + GlStateManager.color(1F, 1F, 1F, 1F); + } + + public static void renderFluidIntoGuiCleanly(int x, int y, int width, int height, + @Nullable FluidStack fluidStack, int capacity) { + Minecraft.getMinecraft().getTextureManager().bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); + Tessellator tess = Tessellator.getInstance(); + renderFluidIntoGui(tess, tess.getBuffer(), x, y, width, height, fluidStack, capacity); + GlStateManager.color(1F, 1F, 1F, 1F); + } + + public static boolean renderFluidIntoGuiSlot(Slot slot, @Nullable FluidStack fluid, + StackSizeRenderer stackSizeRenderer, FontRenderer fontRenderer) { + if (fluid == null || fluid.amount <= 0) { + return false; + } + renderFluidIntoGuiCleanly(slot.xPos, slot.yPos, 16, 16, fluid, fluid.amount); + stackSizeRenderer.renderStackSize(fontRenderer, ItemFluidDrop.newAeStack(fluid), slot.xPos, slot.yPos); + return true; + } + + public static boolean renderFluidPacketIntoGuiSlot(Slot slot, @Nullable IAEItemStack stack, + StackSizeRenderer stackSizeRenderer, FontRenderer fontRenderer) { + return stack != null && stack.getItem() instanceof ItemFluidPacket + && renderFluidIntoGuiSlot(slot, ItemFluidPacket.getFluidStack(stack), stackSizeRenderer, fontRenderer); + } + + public static boolean renderFluidPacketIntoGuiSlot(Slot slot, ItemStack stack, + StackSizeRenderer stackSizeRenderer, FontRenderer fontRenderer) { + return !stack.isEmpty() && stack.getItem() instanceof ItemFluidPacket + && renderFluidIntoGuiSlot(slot, ItemFluidPacket.getFluidStack(stack), stackSizeRenderer, fontRenderer); + } + +} diff --git a/src/main/java/com/glodblock/github/client/render/RenderIngredientBuffer.java b/src/main/java/com/glodblock/github/client/render/RenderIngredientBuffer.java new file mode 100644 index 000000000..656b89ac7 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/render/RenderIngredientBuffer.java @@ -0,0 +1,81 @@ +package com.glodblock.github.client.render; + +import com.glodblock.github.common.tile.TileIngredientBuffer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.RenderItem; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.capability.IFluidTankProperties; +import net.minecraftforge.items.IItemHandler; +import org.lwjgl.opengl.GL11; + +public class RenderIngredientBuffer extends TileEntitySpecialRenderer { + + private static final double d = 0.45D; + + @Override + public void render(TileIngredientBuffer tile, double x, double y, double z, float partialTicks, int destroyStage, float alpha) { + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); + GlStateManager.enableLighting(); + GlStateManager.pushMatrix(); + GlStateManager.translate(x + 0.5D, y + 0.5D, z + 0.5D); + bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); + + IItemHandler inv = tile.getInternalInventory(); + for (int i = 0; i < inv.getSlots(); i++) { + ItemStack stack = inv.getStackInSlot(i); + if (!stack.isEmpty()) { + GlStateManager.pushMatrix(); + float scale = stack.getItem() instanceof ItemBlock ? 0.36F : 0.64F; + GlStateManager.scale(scale, scale, scale); + GlStateManager.rotate((getWorld().getTotalWorldTime() + partialTicks) * 6F, 0F, 1F, 0F); + RenderItem renderer = Minecraft.getMinecraft().getRenderItem(); + renderer.renderItem(stack, renderer.getItemModelWithOverrides(stack, getWorld(), null)); + GlStateManager.popMatrix(); + break; + } + } + + for (IFluidTankProperties tank : tile.getFluidInventory().getTankProperties()) { + TextureAtlasSprite fluidSprite = FluidRenderUtils.prepareRender(tank.getContents()); + if (fluidSprite != null) { + Tessellator tess = Tessellator.getInstance(); + BufferBuilder buf = tess.getBuffer(); + // not necessarily the most efficient way to draw a cube, but probably the least tedious + GlStateManager.pushMatrix(); + drawFace(tess, buf, fluidSprite); + for (int i = 0; i < 3; i++) { + GlStateManager.rotate(90F, 1F, 0F, 0F); + drawFace(tess, buf, fluidSprite); + } + GlStateManager.rotate(90F, 0F, 0F, 1F); + drawFace(tess, buf, fluidSprite); + GlStateManager.rotate(180F, 0F, 0F, 1F); + drawFace(tess, buf, fluidSprite); + GlStateManager.popMatrix(); + break; + } + } + + GlStateManager.color(1F, 1F, 1F, 1F); + GlStateManager.popMatrix(); + } + + private static void drawFace(Tessellator tess, BufferBuilder buf, TextureAtlasSprite sprite) { + buf.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + buf.pos(-d, d, -d).tex(sprite.getMinU(), sprite.getMinV()).endVertex(); + buf.pos(-d, d, d).tex(sprite.getMinU(), sprite.getMaxV()).endVertex(); + buf.pos(d, d, d).tex(sprite.getMaxU(), sprite.getMaxV()).endVertex(); + buf.pos(d, d, -d).tex(sprite.getMaxU(), sprite.getMinV()).endVertex(); + tess.draw(); + } + +} diff --git a/src/main/java/com/glodblock/github/common/block/BlockBurette.java b/src/main/java/com/glodblock/github/common/block/BlockBurette.java new file mode 100644 index 000000000..583a5e81c --- /dev/null +++ b/src/main/java/com/glodblock/github/common/block/BlockBurette.java @@ -0,0 +1,38 @@ +package com.glodblock.github.common.block; + +import appeng.block.AEBaseTileBlock; +import com.glodblock.github.common.tile.TileBurette; +import com.glodblock.github.inventory.GuiType; +import com.glodblock.github.inventory.InventoryHandler; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class BlockBurette extends AEBaseTileBlock { + + public BlockBurette() { + super(Material.IRON); + setTileEntity(TileBurette.class); + } + + @Override + public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, + EnumFacing facing, float hitX, float hitY, float hitZ) { + if (player.isSneaking()) { + return false; + } + TileBurette tile = getTileEntity(world, pos); + if (tile != null) { + if (!world.isRemote) { + InventoryHandler.openGui(player, world, pos, facing, GuiType.PRECISION_BURETTE); + } + return true; + } + return false; + } + +} diff --git a/src/main/java/com/glodblock/github/common/block/BlockDualInterface.java b/src/main/java/com/glodblock/github/common/block/BlockDualInterface.java new file mode 100644 index 000000000..6dee9140c --- /dev/null +++ b/src/main/java/com/glodblock/github/common/block/BlockDualInterface.java @@ -0,0 +1,85 @@ +package com.glodblock.github.common.block; + +import appeng.api.util.IOrientable; +import appeng.block.AEBaseTileBlock; +import appeng.util.Platform; +import com.glodblock.github.common.tile.TileDualInterface; +import com.glodblock.github.inventory.GuiType; +import com.glodblock.github.inventory.InventoryHandler; +import net.minecraft.block.material.Material; +import net.minecraft.block.properties.IProperty; +import net.minecraft.block.properties.PropertyBool; +import net.minecraft.block.properties.PropertyDirection; +import net.minecraft.block.state.BlockStateContainer; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class BlockDualInterface extends AEBaseTileBlock { + + private static final PropertyBool OMNIDIRECTIONAL = PropertyBool.create("omnidirectional"); + private static final PropertyDirection FACING = PropertyDirection.create("facing"); + + public BlockDualInterface() { + super(Material.IRON); + this.setTileEntity(TileDualInterface.class); + } + + @SuppressWarnings("rawtypes") + @Override + protected IProperty[] getAEStates() { + return new IProperty[] { OMNIDIRECTIONAL }; + } + + @Override + protected BlockStateContainer createBlockState() { + return new BlockStateContainer(this, OMNIDIRECTIONAL, FACING); + } + + @Override + public boolean onActivated(final World w, final BlockPos pos, final EntityPlayer p, + final EnumHand hand, final @Nullable ItemStack heldItem, final EnumFacing side, + final float hitX, final float hitY, final float hitZ) { + if (p.isSneaking()) { + return false; + } + final TileDualInterface tg = this.getTileEntity(w, pos); + if (tg != null) { + if (Platform.isServer()) { + InventoryHandler.openGui(p, w, pos, side, GuiType.DUAL_ITEM_INTERFACE); + } + return true; + } + return false; + } + + @SuppressWarnings("deprecation") + @Override + @Nonnull + public IBlockState getActualState(@Nonnull IBlockState state, @Nonnull IBlockAccess world, @Nonnull BlockPos pos) { + TileDualInterface te = this.getTileEntity(world, pos); + return te == null ? state + : state.withProperty(OMNIDIRECTIONAL, te.isOmniDirectional()).withProperty(FACING, te.getForward()); + } + + @Override + protected boolean hasCustomRotation() { + return true; + } + + @Override + protected void customRotateBlock(final IOrientable rotatable, final EnumFacing axis) { + if (rotatable instanceof TileDualInterface) { + ((TileDualInterface)rotatable).setSide(axis); + } + } + +} diff --git a/src/main/java/com/glodblock/github/common/block/BlockFluidDiscretizer.java b/src/main/java/com/glodblock/github/common/block/BlockFluidDiscretizer.java new file mode 100644 index 000000000..16fbbbadd --- /dev/null +++ b/src/main/java/com/glodblock/github/common/block/BlockFluidDiscretizer.java @@ -0,0 +1,14 @@ +package com.glodblock.github.common.block; + +import appeng.block.AEBaseTileBlock; +import com.glodblock.github.common.tile.TileFluidDiscretizer; +import net.minecraft.block.material.Material; + +public class BlockFluidDiscretizer extends AEBaseTileBlock { + + public BlockFluidDiscretizer() { + super(Material.IRON); + setTileEntity(TileFluidDiscretizer.class); + } + +} diff --git a/src/main/java/com/glodblock/github/common/block/BlockFluidPacketDecoder.java b/src/main/java/com/glodblock/github/common/block/BlockFluidPacketDecoder.java new file mode 100644 index 000000000..243630141 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/block/BlockFluidPacketDecoder.java @@ -0,0 +1,38 @@ +package com.glodblock.github.common.block; + +import appeng.block.AEBaseTileBlock; +import com.glodblock.github.common.tile.TileFluidPacketDecoder; +import com.glodblock.github.inventory.GuiType; +import com.glodblock.github.inventory.InventoryHandler; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class BlockFluidPacketDecoder extends AEBaseTileBlock { + + public BlockFluidPacketDecoder() { + super(Material.IRON); + setTileEntity(TileFluidPacketDecoder.class); + } + + @Override + public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, + EnumFacing facing, float hitX, float hitY, float hitZ) { + if (player.isSneaking()) { + return false; + } + TileFluidPacketDecoder tile = getTileEntity(world, pos); + if (tile != null) { + if (!world.isRemote) { + InventoryHandler.openGui(player, world, pos, facing, GuiType.FLUID_PACKET_DECODER); + } + return true; + } + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/common/block/BlockFluidPatternEncoder.java b/src/main/java/com/glodblock/github/common/block/BlockFluidPatternEncoder.java new file mode 100644 index 000000000..4b84a3bf3 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/block/BlockFluidPatternEncoder.java @@ -0,0 +1,38 @@ +package com.glodblock.github.common.block; + +import appeng.block.AEBaseTileBlock; +import com.glodblock.github.common.tile.TileFluidPatternEncoder; +import com.glodblock.github.inventory.GuiType; +import com.glodblock.github.inventory.InventoryHandler; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class BlockFluidPatternEncoder extends AEBaseTileBlock { + + public BlockFluidPatternEncoder() { + super(Material.IRON); + setTileEntity(TileFluidPatternEncoder.class); + } + + @Override + public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, + EnumFacing facing, float hitX, float hitY, float hitZ) { + if (player.isSneaking()) { + return false; + } + TileFluidPatternEncoder tile = getTileEntity(world, pos); + if (tile != null) { + if (!world.isRemote) { + InventoryHandler.openGui(player, world, pos, facing, GuiType.FLUID_PATTERN_ENCODER); + } + return true; + } + return false; + } + +} diff --git a/src/main/java/com/glodblock/github/common/block/BlockIngredientBuffer.java b/src/main/java/com/glodblock/github/common/block/BlockIngredientBuffer.java new file mode 100644 index 000000000..f01dd2f7e --- /dev/null +++ b/src/main/java/com/glodblock/github/common/block/BlockIngredientBuffer.java @@ -0,0 +1,58 @@ +package com.glodblock.github.common.block; + +import appeng.block.AEBaseTileBlock; +import com.glodblock.github.common.tile.TileIngredientBuffer; +import com.glodblock.github.inventory.GuiType; +import com.glodblock.github.inventory.InventoryHandler; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import javax.annotation.Nonnull; + +public class BlockIngredientBuffer extends AEBaseTileBlock { + + public BlockIngredientBuffer() { + super(Material.IRON); + setTileEntity(TileIngredientBuffer.class); + setOpaque(false); + this.lightOpacity = 4; + } + + @Override + public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, + EnumFacing facing, float hitX, float hitY, float hitZ) { + if (player.isSneaking()) { + return false; + } + TileIngredientBuffer tile = getTileEntity(world, pos); + if (tile != null) { + if (!world.isRemote) { + InventoryHandler.openGui(player, world, pos, facing, GuiType.INGREDIENT_BUFFER); + } + return true; + } + return false; + } + + @SideOnly(Side.CLIENT) + @Override + @Nonnull + public BlockRenderLayer getRenderLayer() { + return BlockRenderLayer.CUTOUT; + } + + @SuppressWarnings("deprecation") + @Override + public boolean isFullCube(@Nonnull IBlockState state) { + return false; + } + +} diff --git a/src/main/java/com/glodblock/github/common/component/DualityDualInterface.java b/src/main/java/com/glodblock/github/common/component/DualityDualInterface.java new file mode 100644 index 000000000..b9040d06a --- /dev/null +++ b/src/main/java/com/glodblock/github/common/component/DualityDualInterface.java @@ -0,0 +1,184 @@ +package com.glodblock.github.common.component; + +import appeng.api.config.Actionable; +import appeng.api.config.Upgrades; +import appeng.api.networking.IGridNode; +import appeng.api.networking.crafting.ICraftingLink; +import appeng.api.networking.crafting.ICraftingPatternDetails; +import appeng.api.networking.crafting.ICraftingProviderHelper; +import appeng.api.networking.events.MENetworkChannelsChanged; +import appeng.api.networking.events.MENetworkPowerStatusChange; +import appeng.api.networking.ticking.TickRateModulation; +import appeng.api.networking.ticking.TickingRequest; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.util.IConfigManager; +import appeng.fluids.helper.DualityFluidInterface; +import appeng.fluids.helper.IFluidInterfaceHost; +import appeng.helpers.DualityInterface; +import appeng.helpers.IInterfaceHost; +import appeng.me.helpers.AENetworkProxy; +import appeng.util.inv.InvOperation; +import com.google.common.collect.ImmutableSet; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.items.IItemHandler; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; + +public class DualityDualInterface implements ICapabilityProvider { + + private final DualityInterface itemDuality; + private final DualityFluidInterface fluidDuality; + + public DualityDualInterface(AENetworkProxy networkProxy, H host) { + this.itemDuality = new DualityInterface(networkProxy, host); + this.fluidDuality = new DualityFluidInterface(networkProxy, host); + } + + public DualityInterface getItemInterface() { + return itemDuality; + } + + public DualityFluidInterface getFluidInterface() { + return fluidDuality; + } + + public IConfigManager getConfigManager() { + return itemDuality.getConfigManager(); // fluid interface has no meaningful config, so this is fine + } + + public int getInstalledUpgrades(final Upgrades u) { + return itemDuality.getInstalledUpgrades(u); // fluid interface supports no upgrades, so this is fine + } + + public int getPriority() { + return itemDuality.getPriority(); // both ifaces should always have the same prio + } + + public void setPriority(final int newValue) { + itemDuality.setPriority(newValue); + fluidDuality.setPriority(newValue); + } + + @Override + public boolean hasCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { + return itemDuality.hasCapability(capability, facing) || fluidDuality.hasCapability(capability, facing); + } + + @Nullable + @Override + public T getCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { + T capInst = itemDuality.getCapability(capability, facing); + return capInst != null ? capInst : fluidDuality.getCapability(capability, facing); + } + + // dual behaviour + + public void initialize() { + itemDuality.initialize(); + } + + public TickingRequest getTickingRequest(IGridNode node) { + TickingRequest item = itemDuality.getTickingRequest(node), fluid = fluidDuality.getTickingRequest(node); + return new TickingRequest( + Math.min(item.minTickRate, fluid.minTickRate), + Math.max(item.maxTickRate, fluid.maxTickRate), + item.isSleeping && fluid.isSleeping, // might cause some unnecessary ticking, but oh well + true); + } + + public TickRateModulation onTick(IGridNode node, int ticksSinceLastCall) { + TickRateModulation item = itemDuality.tickingRequest(node, ticksSinceLastCall); + TickRateModulation fluid = fluidDuality.tickingRequest(node, ticksSinceLastCall); + if (item.ordinal() >= fluid.ordinal()) { // return whichever is most urgent + return item; + } else { + return fluid; + } + } + + public void onChannelStateChange(final MENetworkChannelsChanged c) { + itemDuality.notifyNeighbors(); + fluidDuality.notifyNeighbors(); + } + + public void onPowerStateChange(final MENetworkPowerStatusChange c) { + itemDuality.notifyNeighbors(); + fluidDuality.notifyNeighbors(); + } + + public void onGridChanged() { + itemDuality.gridChanged(); + fluidDuality.gridChanged(); + } + + // item interface behaviour + + public void addDrops(List drops) { + itemDuality.addDrops(drops); + } + + public boolean canInsertItem(ItemStack stack) { + return itemDuality.canInsert(stack); + } + + public IItemHandler getItemInventoryByName(String name) { + return itemDuality.getInventoryByName(name); + } + + public IItemHandler getInternalItemInventory() { + return itemDuality.getInternalInventory(); + } + + public void onItemInventoryChange(IItemHandler inv, int slot, InvOperation op, ItemStack removed, ItemStack added) { + itemDuality.onChangeInventory(inv, slot, op, removed, added); + } + + // autocrafting + + public boolean pushPattern(ICraftingPatternDetails patternDetails, InventoryCrafting table) { + return itemDuality.pushPattern(patternDetails, table); + } + + public boolean isCraftingBusy() { + return itemDuality.isBusy(); + } + + public void provideCrafting(ICraftingProviderHelper craftingTracker) { + itemDuality.provideCrafting(craftingTracker); + } + + public ImmutableSet getRequestCraftingJobs() { + return itemDuality.getRequestedJobs(); + } + + public IAEItemStack injectCraftedItems(ICraftingLink link, IAEItemStack items, Actionable mode) { + return itemDuality.injectCraftedItems(link, items, mode); + } + + public void onCraftingJobStateChange(ICraftingLink link) { + itemDuality.jobStateChange(link); + } + + // serialization + + public void writeToNBT(final NBTTagCompound data) { + NBTTagCompound itemIfaceTag = new NBTTagCompound(), fluidIfaceTag = new NBTTagCompound(); + itemDuality.writeToNBT(itemIfaceTag); + fluidDuality.writeToNBT(fluidIfaceTag); + data.setTag("itemDuality", itemIfaceTag); + data.setTag("fluidDuality", fluidIfaceTag); + } + + public void readFromNBT(final NBTTagCompound data) { + itemDuality.readFromNBT(data.getCompoundTag("itemDuality")); + fluidDuality.readFromNBT(data.getCompoundTag("fluidDuality")); + } + +} diff --git a/src/main/java/com/glodblock/github/common/item/ItemFluidDrop.java b/src/main/java/com/glodblock/github/common/item/ItemFluidDrop.java new file mode 100644 index 000000000..c290ef1c5 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemFluidDrop.java @@ -0,0 +1,131 @@ +package com.glodblock.github.common.item; + +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IAEItemStack; +import appeng.fluids.util.AEFluidStack; +import appeng.util.item.AEItemStack; +import com.glodblock.github.loader.FCItems; +import com.glodblock.github.util.NameConst; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.NonNullList; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.translation.I18n; +import net.minecraft.world.World; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; + +public class ItemFluidDrop extends Item { + + @Override + public void getSubItems(@Nonnull CreativeTabs tab,@Nonnull NonNullList items) { + if (isInCreativeTab(tab)) { + items.add(newStack(new FluidStack(FluidRegistry.WATER, 1))); + items.add(newStack(new FluidStack(FluidRegistry.LAVA, 1))); + } + } + + @SuppressWarnings("deprecation") + @Override + @Nonnull + public String getItemStackDisplayName(@Nonnull ItemStack stack) { + FluidStack fluid = getFluidStack(stack); + // would like to use I18n::format instead of this deprecated function, but that only exists on the client :/ + return I18n.translateToLocalFormatted(getTranslationKey(stack) + ".name", fluid != null ? fluid.getLocalizedName() : "???"); + } + + @SuppressWarnings("deprecation") + @Override + public void addInformation(@Nonnull ItemStack stack, @Nullable World world, @Nonnull List tooltip, @Nonnull ITooltipFlag flags) { + FluidStack fluid = getFluidStack(stack); + if (fluid != null) { + tooltip.add(String.format(TextFormatting.GRAY + "%s, 1 mB", fluid.getLocalizedName())); + } else { + tooltip.add(TextFormatting.RED + I18n.translateToLocal(NameConst.TT_INVALID_FLUID)); + } + } + + @Nullable + public static FluidStack getFluidStack(ItemStack stack) { + if (stack.isEmpty() || stack.getItem() != FCItems.FLUID_DROP || !stack.hasTagCompound()) { + return null; + } + NBTTagCompound tag = Objects.requireNonNull(stack.getTagCompound()); + if (!tag.hasKey("Fluid", Constants.NBT.TAG_STRING)) { + return null; + } + Fluid fluid = FluidRegistry.getFluid(tag.getString("Fluid")); + if (fluid == null) { + return null; + } + FluidStack fluidStack = new FluidStack(fluid, stack.getCount()); + if (tag.hasKey("FluidTag", Constants.NBT.TAG_COMPOUND)) { + fluidStack.tag = tag.getCompoundTag("FluidTag"); + } + return fluidStack; + } + + @Nullable + public static IAEFluidStack getAeFluidStack(@Nullable IAEItemStack stack) { + if (stack == null) { + return null; + } + IAEFluidStack fluidStack = AEFluidStack.fromFluidStack(getFluidStack(stack.getDefinition())); + if (fluidStack == null) { + return null; + } + fluidStack.setStackSize(stack.getStackSize()); + return fluidStack; + } + + public static ItemStack newStack(@Nullable FluidStack fluid) { + if (fluid == null || fluid.amount <= 0) { + return ItemStack.EMPTY; + } + ItemStack stack = new ItemStack(FCItems.FLUID_DROP, fluid.amount); + NBTTagCompound tag = new NBTTagCompound(); + tag.setString("Fluid", fluid.getFluid().getName()); + if (fluid.tag != null) { + tag.setTag("FluidTag", fluid.tag); + } + stack.setTagCompound(tag); + return stack; + } + + @Nullable + public static IAEItemStack newAeStack(@Nullable FluidStack fluid) { + if (fluid == null || fluid.amount <= 0) { + return null; + } + IAEItemStack stack = AEItemStack.fromItemStack(newStack(fluid)); + if (stack == null) { + return null; + } + stack.setStackSize(fluid.amount); + return stack; + } + + @Nullable + public static IAEItemStack newAeStack(@Nullable IAEFluidStack fluid) { + if (fluid == null || fluid.getStackSize() <= 0) { + return null; + } + IAEItemStack stack = AEItemStack.fromItemStack(newStack(fluid.getFluidStack())); + if (stack == null) { + return null; + } + stack.setStackSize(fluid.getStackSize()); + return stack; + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/common/item/ItemFluidEncodedPattern.java b/src/main/java/com/glodblock/github/common/item/ItemFluidEncodedPattern.java new file mode 100644 index 000000000..63c00dd36 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemFluidEncodedPattern.java @@ -0,0 +1,35 @@ +package com.glodblock.github.common.item; + +import appeng.api.networking.crafting.ICraftingPatternDetails; +import appeng.items.misc.ItemEncodedPattern; +import com.glodblock.github.interfaces.HasCustomModel; +import com.glodblock.github.util.FluidPatternDetails; +import com.glodblock.github.util.NameConst; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.ItemStack; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; + +import javax.annotation.Nullable; + +public class ItemFluidEncodedPattern extends ItemEncodedPattern implements HasCustomModel { + + @Override + protected void getCheckedSubItems(CreativeTabs creativeTab, NonNullList itemStacks) { + // NO-OP + } + + @Nullable + @Override + public ICraftingPatternDetails getPatternForItem(ItemStack is, World w) { + FluidPatternDetails pattern = new FluidPatternDetails(is); + return pattern.readFromStack() ? pattern : null; + } + + @Override + public ResourceLocation getCustomModelPath() { + return NameConst.MODEL_DENSE_ENCODED_PATTERN; + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/common/item/ItemFluidPacket.java b/src/main/java/com/glodblock/github/common/item/ItemFluidPacket.java new file mode 100644 index 000000000..ad27784a6 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemFluidPacket.java @@ -0,0 +1,94 @@ +package com.glodblock.github.common.item; + +import appeng.api.storage.data.IAEItemStack; +import appeng.util.item.AEItemStack; +import com.glodblock.github.interfaces.HasCustomModel; +import com.glodblock.github.loader.FCItems; +import com.glodblock.github.util.NameConst; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.translation.I18n; +import net.minecraft.world.World; +import net.minecraftforge.fluids.FluidStack; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; + +public class ItemFluidPacket extends Item implements HasCustomModel { + + public ItemFluidPacket() { + setMaxStackSize(1); + } + + @Override + public void getSubItems(@Nonnull CreativeTabs tab,@Nonnull NonNullList items) { + // NO-OP + } + + @Override + @Nonnull + public String getItemStackDisplayName(@Nonnull ItemStack stack) { + FluidStack fluid = getFluidStack(stack); + return fluid != null ? String.format("%s, %,d mB", fluid.getLocalizedName(), fluid.amount) + : super.getItemStackDisplayName(stack); + } + + @SuppressWarnings("deprecation") + @Override + public void addInformation(@Nonnull ItemStack stack, @Nullable World world, @Nonnull List tooltip, @Nonnull ITooltipFlag flags) { + FluidStack fluid = getFluidStack(stack); + if (fluid != null) { + for (String line : I18n.translateToLocal(NameConst.TT_FLUID_PACKET).split("\\\\n")) { + tooltip.add(TextFormatting.GRAY + line); + } + } else { + tooltip.add(TextFormatting.RED + I18n.translateToLocal(NameConst.TT_INVALID_FLUID)); + } + } + + @Nullable + public static FluidStack getFluidStack(ItemStack stack) { + if (stack.isEmpty() || !stack.hasTagCompound()) { + return null; + } + FluidStack fluid = FluidStack.loadFluidStackFromNBT(Objects.requireNonNull(stack.getTagCompound()).getCompoundTag("FluidStack")); + return (fluid != null && fluid.amount > 0) ? fluid : null; + } + + @Nullable + public static FluidStack getFluidStack(@Nullable IAEItemStack stack) { + return stack != null ? getFluidStack(stack.getDefinition()) : null; + } + + public static ItemStack newStack(@Nullable FluidStack fluid) { + if (fluid == null || fluid.amount == 0) { + return ItemStack.EMPTY; + } + ItemStack stack = new ItemStack(FCItems.FLUID_PACKET); + NBTTagCompound tag = new NBTTagCompound(); + NBTTagCompound fluidTag = new NBTTagCompound(); + fluid.writeToNBT(fluidTag); + tag.setTag("FluidStack", fluidTag); + stack.setTagCompound(tag); + return stack; + } + + @Nullable + public static IAEItemStack newAeStack(@Nullable FluidStack fluid) { + return AEItemStack.fromItemStack(newStack(fluid)); + } + + @Override + public ResourceLocation getCustomModelPath() { + return NameConst.MODEL_FLUID_PACKET; + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/common/item/ItemPartDualInterface.java b/src/main/java/com/glodblock/github/common/item/ItemPartDualInterface.java new file mode 100644 index 000000000..18c154fb4 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemPartDualInterface.java @@ -0,0 +1,37 @@ +package com.glodblock.github.common.item; + +import appeng.api.AEApi; +import appeng.api.parts.IPartItem; +import com.glodblock.github.common.part.PartDualInterface; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class ItemPartDualInterface extends Item implements IPartItem { + + public ItemPartDualInterface() { + this.setMaxStackSize(64); + } + + @Nullable + @Override + public PartDualInterface createPartFromItemStack(ItemStack is) { + return new PartDualInterface(is); + } + + @Override + @Nonnull + public EnumActionResult onItemUse(@Nonnull EntityPlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumHand hand, @Nonnull EnumFacing side, + float hitX, float hitY, float hitZ) { + return AEApi.instance().partHelper().placeBus(player.getHeldItem(hand), pos, side, player, hand, world); + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/common/item/ItemPartFluidPatternTerminal.java b/src/main/java/com/glodblock/github/common/item/ItemPartFluidPatternTerminal.java new file mode 100644 index 000000000..9d8597a3a --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemPartFluidPatternTerminal.java @@ -0,0 +1,37 @@ +package com.glodblock.github.common.item; + +import appeng.api.AEApi; +import appeng.api.parts.IPartItem; +import com.glodblock.github.common.part.PartFluidPatternTerminal; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class ItemPartFluidPatternTerminal extends Item implements IPartItem { + + public ItemPartFluidPatternTerminal() { + this.setMaxStackSize(64); + } + + @Nullable + @Override + public PartFluidPatternTerminal createPartFromItemStack(ItemStack is) { + return new PartFluidPatternTerminal(is); + } + + @Override + @Nonnull + public EnumActionResult onItemUse(@Nonnull EntityPlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumHand hand, @Nonnull EnumFacing side, + float hitX, float hitY, float hitZ) { + return AEApi.instance().partHelper().placeBus(player.getHeldItem(hand), pos, side, player, hand, world); + } + +} diff --git a/src/main/java/com/glodblock/github/common/part/PartDualInterface.java b/src/main/java/com/glodblock/github/common/part/PartDualInterface.java new file mode 100644 index 000000000..e4b118b13 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/part/PartDualInterface.java @@ -0,0 +1,267 @@ +package com.glodblock.github.common.part; + +import appeng.api.config.Actionable; +import appeng.api.config.Upgrades; +import appeng.api.networking.IGridNode; +import appeng.api.networking.crafting.ICraftingLink; +import appeng.api.networking.crafting.ICraftingPatternDetails; +import appeng.api.networking.crafting.ICraftingProviderHelper; +import appeng.api.networking.events.MENetworkChannelsChanged; +import appeng.api.networking.events.MENetworkEventSubscribe; +import appeng.api.networking.events.MENetworkPowerStatusChange; +import appeng.api.networking.ticking.IGridTickable; +import appeng.api.networking.ticking.TickRateModulation; +import appeng.api.networking.ticking.TickingRequest; +import appeng.api.parts.IPartCollisionHelper; +import appeng.api.parts.IPartModel; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.util.AECableType; +import appeng.api.util.IConfigManager; +import appeng.fluids.helper.DualityFluidInterface; +import appeng.fluids.helper.IFluidInterfaceHost; +import appeng.helpers.DualityInterface; +import appeng.helpers.IInterfaceHost; +import appeng.helpers.Reflected; +import appeng.items.parts.PartModels; +import appeng.parts.PartBasicState; +import appeng.parts.PartModel; +import appeng.util.Platform; +import appeng.util.inv.IAEAppEngInventory; +import appeng.util.inv.IInventoryDestination; +import appeng.util.inv.InvOperation; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.common.component.DualityDualInterface; +import com.glodblock.github.interfaces.FCPriorityHost; +import com.glodblock.github.inventory.GuiType; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.loader.FCItems; +import com.google.common.collect.ImmutableSet; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.items.IItemHandler; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.EnumSet; +import java.util.List; + +public class PartDualInterface extends PartBasicState + implements IGridTickable, IInventoryDestination, IInterfaceHost, IAEAppEngInventory, FCPriorityHost, IFluidInterfaceHost { + + @PartModels + public static ResourceLocation[] MODELS = new ResourceLocation[] { + new ResourceLocation(FluidCraft.MODID, "part/interface_base"), + new ResourceLocation(FluidCraft.MODID, "part/interface_on"), + new ResourceLocation(FluidCraft.MODID, "part/interface_off"), + new ResourceLocation(FluidCraft.MODID, "part/interface_has_channel") + }; + + public static final PartModel MODELS_OFF = new PartModel(MODELS[0], MODELS[2]); + public static final PartModel MODELS_ON = new PartModel(MODELS[0], MODELS[1]); + public static final PartModel MODELS_HAS_CHANNEL = new PartModel(MODELS[0], MODELS[3]); + + private final DualityDualInterface duality = new DualityDualInterface<>(getProxy(), this); + + @Reflected + public PartDualInterface(final ItemStack is) { + super(is); + } + + @MENetworkEventSubscribe + public void stateChange(final MENetworkChannelsChanged c) { + duality.onChannelStateChange(c); + } + + @MENetworkEventSubscribe + public void stateChange(final MENetworkPowerStatusChange c) { + duality.onPowerStateChange(c); + } + + @Override + public void getBoxes(final IPartCollisionHelper bch) { + bch.addBox(2, 2, 14, 14, 14, 16); + bch.addBox(5, 5, 12, 11, 11, 14); + } + + @Override + public int getInstalledUpgrades(final Upgrades u) { + return duality.getInstalledUpgrades(u); + } + + @Override + public void gridChanged() { + duality.onGridChanged(); + } + + @Override + public void readFromNBT(final NBTTagCompound data) { + super.readFromNBT(data); + duality.readFromNBT(data); + } + + @Override + public void writeToNBT(final NBTTagCompound data) { + super.writeToNBT(data); + duality.writeToNBT(data); + } + + @Override + public void addToWorld() { + super.addToWorld(); + duality.initialize(); + } + + @Override + public void getDrops(final List drops, final boolean wrenched) { + duality.addDrops(drops); + } + + @Override + public float getCableConnectionLength(AECableType cable) { + return 4; + } + + @Override + public IConfigManager getConfigManager() { + return duality.getConfigManager(); + } + + @Override + public IItemHandler getInventoryByName(final String name) { + return duality.getItemInventoryByName(name); + } + + @Override + public boolean onPartActivate(final EntityPlayer p, final EnumHand hand, final Vec3d pos) { + if (Platform.isServer()) { + TileEntity tile = getTileEntity(); + InventoryHandler.openGui(p, tile.getWorld(), tile.getPos(), getSide().getFacing(), GuiType.DUAL_ITEM_INTERFACE); + } + return true; + } + + @Override + public boolean canInsert(final ItemStack stack) { + return duality.canInsertItem(stack); + } + + @Override + @Nonnull + public TickingRequest getTickingRequest(@Nonnull final IGridNode node) { + return duality.getTickingRequest(node); + } + + @Override + @Nonnull + public TickRateModulation tickingRequest(@Nonnull final IGridNode node, final int ticksSinceLastCall) { + return duality.onTick(node, ticksSinceLastCall); + } + + @Override + public void onChangeInventory(final IItemHandler inv, final int slot, final InvOperation mc, + final ItemStack removedStack, final ItemStack newStack) { + duality.onItemInventoryChange(inv, slot, mc, removedStack, newStack); + } + + @Override + public DualityInterface getInterfaceDuality() { + return duality.getItemInterface(); + } + + @Override + public DualityFluidInterface getDualityFluidInterface() { + return duality.getFluidInterface(); + } + + @Override + public EnumSet getTargets() { + return EnumSet.of(this.getSide().getFacing()); + } + + @Override + public TileEntity getTileEntity() { + return super.getHost().getTile(); + } + + @Override + public boolean pushPattern(final ICraftingPatternDetails patternDetails, final InventoryCrafting table) { + return duality.pushPattern(patternDetails, table); + } + + @Override + public boolean isBusy() { + return duality.isCraftingBusy(); + } + + @Override + public void provideCrafting(final ICraftingProviderHelper craftingTracker) { + duality.provideCrafting(craftingTracker); + } + + @Override + public ImmutableSet getRequestedJobs() { + return duality.getRequestCraftingJobs(); + } + + @Override + public IAEItemStack injectCraftedItems(final ICraftingLink link, final IAEItemStack items, final Actionable mode) { + return duality.injectCraftedItems(link, items, mode); + } + + @Override + public void jobStateChange(final ICraftingLink link) { + duality.onCraftingJobStateChange(link); + } + + @Override + public int getPriority() { + return duality.getPriority(); + } + + @Override + public void setPriority(final int newValue) { + duality.setPriority(newValue); + } + + @Override + public boolean hasCapability(Capability capabilityClass) { + return duality.hasCapability(capabilityClass, getSide().getFacing()); + } + + @Nullable + @Override + public T getCapability(Capability capabilityClass) { + return duality.getCapability(capabilityClass, getSide().getFacing()); + } + + @Override + public GuiType getGuiType() { + return GuiType.DUAL_ITEM_INTERFACE; + } + + @Override + public ItemStack getItemStackRepresentation() { + return new ItemStack(FCItems.PART_DUAL_INTERFACE, 1); + } + + @Nonnull + @Override + public IPartModel getStaticModels() { + if (this.isActive() && this.isPowered()) { + return MODELS_HAS_CHANNEL; + } else if (this.isPowered()) { + return MODELS_ON; + } else { + return MODELS_OFF; + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/common/part/PartFluidPatternTerminal.java b/src/main/java/com/glodblock/github/common/part/PartFluidPatternTerminal.java new file mode 100644 index 000000000..6a0413bf2 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/part/PartFluidPatternTerminal.java @@ -0,0 +1,96 @@ +package com.glodblock.github.common.part; + +import appeng.api.parts.IPartModel; +import appeng.api.storage.data.IAEItemStack; +import appeng.core.sync.GuiBridge; +import appeng.items.parts.PartModels; +import appeng.parts.PartModel; +import appeng.parts.reporting.PartPatternTerminal; +import appeng.tile.inventory.AppEngInternalInventory; +import appeng.util.Platform; +import appeng.util.inv.InvOperation; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.common.item.ItemFluidEncodedPattern; +import com.glodblock.github.inventory.GuiType; +import com.glodblock.github.inventory.InventoryHandler; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.items.IItemHandler; + +import javax.annotation.Nonnull; + +public class PartFluidPatternTerminal extends PartPatternTerminal { + + @PartModels + public static ResourceLocation[] MODELS = new ResourceLocation[] { + new ResourceLocation(FluidCraft.MODID, "part/f_pattern_term_on"), // 0 + new ResourceLocation(FluidCraft.MODID, "part/f_pattern_term_off"), // 1 + }; + + private static final IPartModel MODELS_ON = new PartModel(MODEL_BASE, MODELS[0], MODEL_STATUS_ON); + private static final IPartModel MODELS_OFF = new PartModel(MODEL_BASE, MODELS[1], MODEL_STATUS_OFF); + private static final IPartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, MODELS[0], MODEL_STATUS_HAS_CHANNEL); + + public PartFluidPatternTerminal(ItemStack is) { + super(is); + } + + @Nonnull + @Override + public IPartModel getStaticModels() { + return this.selectModel(MODELS_OFF, MODELS_ON, MODELS_HAS_CHANNEL); + } + + @Override + public boolean onPartActivate(final EntityPlayer player, final EnumHand hand, final Vec3d pos) { + TileEntity te = this.getTile(); + BlockPos tePos = te.getPos(); + if (Platform.isWrench(player, player.inventory.getCurrentItem(), tePos)) { + return super.onPartActivate(player, hand, pos); + } + if (Platform.isServer()) { + if (GuiBridge.GUI_PATTERN_TERMINAL.hasPermissions(te, tePos.getX(), tePos.getY(), tePos.getZ(), getSide(), player)) { + InventoryHandler.openGui(player, te.getWorld(), tePos, getSide().getFacing(), GuiType.FLUID_PATTERN_TERMINAL); + } else { + Platform.openGUI(player, this.getHost().getTile(), this.getSide(), GuiBridge.GUI_ME); + } + } + return true; + } + + @Override + public void onChangeInventory(IItemHandler inv, int slot, InvOperation mc, ItemStack removedStack, + ItemStack newStack) { + if (slot == 1) { + final ItemStack is = inv.getStackInSlot(1); + if (!is.isEmpty() && is.getItem() instanceof ItemFluidEncodedPattern) { + return; + } + } + super.onChangeInventory(inv, slot, mc, removedStack, newStack); + } + + public void onChangeCrafting(IAEItemStack[] newCrafting, IAEItemStack[] newOutput) { + IItemHandler crafting = this.getInventoryByName("crafting"); + IItemHandler output = this.getInventoryByName("output"); + if (crafting instanceof AppEngInternalInventory && output instanceof AppEngInternalInventory) { + for (int x = 0; x < crafting.getSlots() && x < newCrafting.length; x++) { + final IAEItemStack item = newCrafting[x]; + ((AppEngInternalInventory)crafting) + .setStackInSlot(x, item == null ? ItemStack.EMPTY : item.createItemStack()); + } + + for (int x = 0; x < output.getSlots() && x < newOutput.length; x++) { + final IAEItemStack item = newOutput[x]; + ((AppEngInternalInventory)output) + .setStackInSlot(x, item == null ? ItemStack.EMPTY : item.createItemStack()); + } + } + } + +} diff --git a/src/main/java/com/glodblock/github/common/tile/TileBurette.java b/src/main/java/com/glodblock/github/common/tile/TileBurette.java new file mode 100644 index 000000000..bf548db40 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/tile/TileBurette.java @@ -0,0 +1,84 @@ +package com.glodblock.github.common.tile; + +import appeng.fluids.util.AEFluidInventory; +import appeng.fluids.util.IAEFluidInventory; +import appeng.fluids.util.IAEFluidTank; +import appeng.tile.AEBaseInvTile; +import appeng.tile.inventory.AppEngInternalInventory; +import appeng.util.inv.InvOperation; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.IItemHandlerModifiable; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class TileBurette extends AEBaseInvTile implements IAEFluidInventory { + + private final AppEngInternalInventory invTarget = new AppEngInternalInventory(this, 1); + private final AEFluidInventory invFluid = new AEFluidInventory(this, 1, 8000); + + @Nonnull + @Override + public IItemHandlerModifiable getInternalInventory() { + return invTarget; + } + + public IAEFluidTank getFluidInventory() { + return invFluid; + } + + @Override + public boolean canBeRotated() { + return false; + } + + @Override + public boolean hasCapability(Capability capability, EnumFacing facing) { + return capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY + || capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY; + } + + @SuppressWarnings("unchecked") + @Nullable + @Override + public T getCapability(Capability capability, @Nullable EnumFacing facing) { + if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return (T)invTarget; + } else if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { + return (T)invFluid; + } + return null; + } + + @Override + public void onChangeInventory(IItemHandler inv, int slot, InvOperation mc, ItemStack removed, ItemStack added) { + // NO-OP + } + + @Override + public void onFluidInventoryChanged(IAEFluidTank inv, int slot) { + saveChanges(); + } + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + invTarget.readFromNBT(data, "ItemInv"); + invFluid.readFromNBT(data, "FluidInv"); + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); + invTarget.writeToNBT(data, "ItemInv"); + invFluid.writeToNBT(data, "FluidInv"); + return data; + } + +} diff --git a/src/main/java/com/glodblock/github/common/tile/TileDualInterface.java b/src/main/java/com/glodblock/github/common/tile/TileDualInterface.java new file mode 100644 index 000000000..bf7df9813 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/tile/TileDualInterface.java @@ -0,0 +1,309 @@ +package com.glodblock.github.common.tile; + +import appeng.api.config.Actionable; +import appeng.api.config.Upgrades; +import appeng.api.networking.IGridNode; +import appeng.api.networking.crafting.ICraftingLink; +import appeng.api.networking.crafting.ICraftingPatternDetails; +import appeng.api.networking.crafting.ICraftingProviderHelper; +import appeng.api.networking.events.MENetworkChannelsChanged; +import appeng.api.networking.events.MENetworkEventSubscribe; +import appeng.api.networking.events.MENetworkPowerStatusChange; +import appeng.api.networking.ticking.IGridTickable; +import appeng.api.networking.ticking.TickRateModulation; +import appeng.api.networking.ticking.TickingRequest; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.util.AECableType; +import appeng.api.util.AEPartLocation; +import appeng.api.util.DimensionalCoord; +import appeng.api.util.IConfigManager; +import appeng.fluids.helper.DualityFluidInterface; +import appeng.fluids.helper.IFluidInterfaceHost; +import appeng.helpers.DualityInterface; +import appeng.helpers.IInterfaceHost; +import appeng.tile.grid.AENetworkInvTile; +import appeng.util.Platform; +import appeng.util.inv.IInventoryDestination; +import appeng.util.inv.InvOperation; +import com.glodblock.github.common.component.DualityDualInterface; +import com.glodblock.github.interfaces.FCPriorityHost; +import com.glodblock.github.inventory.GuiType; +import com.glodblock.github.loader.FCBlocks; +import com.google.common.collect.ImmutableSet; +import io.netty.buffer.ByteBuf; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.items.IItemHandler; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.IOException; +import java.util.EnumSet; +import java.util.List; + +public class TileDualInterface extends AENetworkInvTile + implements IGridTickable, IInventoryDestination, IInterfaceHost, FCPriorityHost, IFluidInterfaceHost { + + public TileDualInterface() { + super(); + } + + private final DualityDualInterface duality = new DualityDualInterface<>(getProxy(), this); + + // Indicates that this interface has no specific direction set + private boolean omniDirectional = true; + + @MENetworkEventSubscribe + public void stateChange(final MENetworkChannelsChanged c) { + duality.onChannelStateChange(c); + } + + @MENetworkEventSubscribe + public void stateChange(final MENetworkPowerStatusChange c) { + duality.onPowerStateChange(c); + } + + public void setSide(final EnumFacing facing) { + if (Platform.isClient()) { + return; + } + + EnumFacing newForward; + + if (!this.omniDirectional && this.getForward() == facing.getOpposite()) { + newForward = facing; + } else if (!this.omniDirectional + && (this.getForward() == facing || this.getForward() == facing.getOpposite())) { + newForward = facing; + this.omniDirectional = true; + } else if (this.omniDirectional) { + newForward = facing.getOpposite(); + this.omniDirectional = false; + } else { + newForward = Platform.rotateAround(this.getForward(), facing); + } + + if (this.omniDirectional) { + this.setOrientation(EnumFacing.NORTH, EnumFacing.UP); + } else { + EnumFacing newUp = EnumFacing.UP; + if (newForward == EnumFacing.UP || newForward == EnumFacing.DOWN) { + newUp = EnumFacing.NORTH; + } + this.setOrientation(newForward, newUp); + } + + this.configureNodeSides(); + this.markForUpdate(); + this.saveChanges(); + } + + private void configureNodeSides() { + if (this.omniDirectional) { + this.getProxy().setValidSides(EnumSet.allOf(EnumFacing.class)); + } else { + this.getProxy().setValidSides(EnumSet.complementOf(EnumSet.of(this.getForward()))); + } + } + + @Override + public void getDrops(final World w, final BlockPos pos, final List drops) { + duality.addDrops(drops); + } + + @Override + public void gridChanged() { + duality.onGridChanged(); + } + + @Override + public void onReady() { + this.configureNodeSides(); + + super.onReady(); + duality.initialize(); + } + + @Override + public NBTTagCompound writeToNBT(final NBTTagCompound data) { + super.writeToNBT(data); + data.setBoolean("omniDirectional", this.omniDirectional); + duality.writeToNBT(data); + return data; + } + + @Override + public void readFromNBT(final NBTTagCompound data) { + super.readFromNBT(data); + this.omniDirectional = data.getBoolean("omniDirectional"); + duality.readFromNBT(data); + } + + @Override + protected boolean readFromStream(final ByteBuf data) throws IOException { + final boolean c = super.readFromStream(data); + boolean oldOmniDirectional = this.omniDirectional; + this.omniDirectional = data.readBoolean(); + return oldOmniDirectional != this.omniDirectional || c; + } + + @Override + protected void writeToStream(final ByteBuf data) throws IOException { + super.writeToStream(data); + data.writeBoolean(this.omniDirectional); + } + + @Override + @Nonnull + public AECableType getCableConnectionType(@Nonnull final AEPartLocation dir) { + return AECableType.SMART; + } + + @Override + public DimensionalCoord getLocation() { + return new DimensionalCoord(this.getTileEntity()); + } + + @Override + public boolean canInsert(final ItemStack stack) { + return duality.canInsertItem(stack); + } + + @Override + public IItemHandler getInventoryByName(final String name) { + return duality.getItemInventoryByName(name); + } + + @Override + @Nonnull + public TickingRequest getTickingRequest(@Nonnull final IGridNode node) { + return duality.getTickingRequest(node); + } + + @Override + @Nonnull + public TickRateModulation tickingRequest(@Nonnull final IGridNode node, final int ticksSinceLastCall) { + return duality.onTick(node, ticksSinceLastCall); + } + + @Override + @Nonnull + public IItemHandler getInternalInventory() { + return duality.getInternalItemInventory(); + } + + @Override + public void onChangeInventory(final IItemHandler inv, final int slot, final InvOperation mc, + final ItemStack removed, final ItemStack added) { + duality.onItemInventoryChange(inv, slot, mc, removed, added); + } + + @Override + public DualityInterface getInterfaceDuality() { + return duality.getItemInterface(); + } + + @Override + public DualityFluidInterface getDualityFluidInterface() { + return duality.getFluidInterface(); + } + + @Override + public EnumSet getTargets() { + if (this.omniDirectional) { + return EnumSet.allOf(EnumFacing.class); + } + return EnumSet.of(this.getForward()); + } + + @Override + public TileEntity getTileEntity() { + return this; + } + + @Override + public IConfigManager getConfigManager() { + return duality.getConfigManager(); + } + + @Override + public boolean pushPattern(final ICraftingPatternDetails patternDetails, final InventoryCrafting table) { + return duality.pushPattern(patternDetails, table); + } + + @Override + public boolean isBusy() { + return duality.isCraftingBusy(); + } + + @Override + public void provideCrafting(final ICraftingProviderHelper craftingTracker) { + duality.provideCrafting(craftingTracker); + } + + @Override + public int getInstalledUpgrades(final Upgrades u) { + return duality.getInstalledUpgrades(u); + } + + @Override + public ImmutableSet getRequestedJobs() { + return duality.getRequestCraftingJobs(); + } + + @Override + public IAEItemStack injectCraftedItems(final ICraftingLink link, final IAEItemStack items, final Actionable mode) { + return duality.injectCraftedItems(link, items, mode); + } + + @Override + public void jobStateChange(final ICraftingLink link) { + duality.onCraftingJobStateChange(link); + } + + @Override + public int getPriority() { + return duality.getPriority(); + } + + @Override + public void setPriority(final int newValue) { + duality.setPriority(newValue); + } + + /** + * @return True if this interface is omni-directional. + */ + public boolean isOmniDirectional() { + return this.omniDirectional; + } + + @Override + public boolean hasCapability(Capability capability, @Nullable EnumFacing facing) { + return duality.hasCapability(capability, facing) || super.hasCapability(capability, facing); + } + + @Nullable + @Override + public T getCapability(Capability capability, @Nullable EnumFacing facing) { + T capInst = duality.getCapability(capability, facing); + return capInst != null ? capInst : super.getCapability(capability, facing); + } + + @Override + public ItemStack getItemStackRepresentation() { + return new ItemStack(FCBlocks.DUAL_INTERFACE); + } + + @Override + public GuiType getGuiType() { + return GuiType.DUAL_ITEM_INTERFACE; + } + +} diff --git a/src/main/java/com/glodblock/github/common/tile/TileFluidDiscretizer.java b/src/main/java/com/glodblock/github/common/tile/TileFluidDiscretizer.java new file mode 100644 index 000000000..e8a22e543 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/tile/TileFluidDiscretizer.java @@ -0,0 +1,279 @@ +package com.glodblock.github.common.tile; + +import appeng.api.AEApi; +import appeng.api.config.Actionable; +import appeng.api.networking.GridFlags; +import appeng.api.networking.crafting.ICraftingGrid; +import appeng.api.networking.energy.IEnergyGrid; +import appeng.api.networking.events.MENetworkCellArrayUpdate; +import appeng.api.networking.events.MENetworkChannelsChanged; +import appeng.api.networking.events.MENetworkEventSubscribe; +import appeng.api.networking.events.MENetworkPowerStatusChange; +import appeng.api.networking.security.IActionSource; +import appeng.api.networking.storage.IBaseMonitor; +import appeng.api.networking.storage.IStorageGrid; +import appeng.api.storage.*; +import appeng.api.storage.channels.IFluidStorageChannel; +import appeng.api.storage.channels.IItemStorageChannel; +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; +import appeng.helpers.Reflected; +import appeng.me.GridAccessException; +import appeng.me.cache.CraftingGridCache; +import appeng.me.helpers.MachineSource; +import appeng.me.storage.MEInventoryHandler; +import appeng.tile.grid.AENetworkTile; +import appeng.util.Platform; +import com.glodblock.github.common.item.ItemFluidDrop; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class TileFluidDiscretizer extends AENetworkTile implements ICellContainer { + + private final FluidDiscretizingInventory fluidDropInv = new FluidDiscretizingInventory(); + private final FluidCraftingInventory fluidCraftInv = new FluidCraftingInventory(); + private final IActionSource ownActionSource = new MachineSource(this); + private boolean prevActiveState = false; + + @Reflected + public TileFluidDiscretizer() { + getProxy().setIdlePowerUsage(3D); + getProxy().setFlags(GridFlags.REQUIRE_CHANNEL); + } + + @Override + public boolean canBeRotated() { + return false; + } + + @Override + public int getPriority() { + return Integer.MAX_VALUE; + } + + @SuppressWarnings("rawtypes") + @Override + public List getCellArray(IStorageChannel channel) { + if (getProxy().isActive()) { + if (channel == AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)) { + return Collections.singletonList(fluidDropInv.invHandler); + } else if (channel == AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class)) { + return Collections.singletonList(fluidCraftInv.invHandler); + } + } + return Collections.emptyList(); + } + + @Override + public void saveChanges(@Nullable ICellInventory cellInventory) { + world.markChunkDirty(pos, this); // optimization, i guess? + } + + @Override + public void gridChanged() { + IMEMonitor fluidGrid = getFluidGrid(); + if (fluidGrid != null) { + fluidGrid.addListener(fluidDropInv, fluidGrid); + } + } + + @MENetworkEventSubscribe + public void onPowerUpdate(MENetworkPowerStatusChange event) { + updateState(); + } + + @MENetworkEventSubscribe + public void onChannelUpdate(MENetworkChannelsChanged event) { + updateState(); + } + + private void updateState() { + boolean isActive = getProxy().isActive(); + if (isActive != prevActiveState) { + prevActiveState = isActive; + try { + getProxy().getGrid().postEvent(new MENetworkCellArrayUpdate()); + } catch (GridAccessException e) { + // NO-OP + } + } + } + + @Override + public void blinkCell(int slot) { + // NO-OP + } + + @Nullable + private IEnergyGrid getEnergyGrid() { + try { + return getProxy().getGrid().getCache(IEnergyGrid.class); + } catch (GridAccessException e) { + return null; + } + } + + @Nullable + private IMEMonitor getFluidGrid() { + try { + return getProxy().getGrid().getCache(IStorageGrid.class) + .getInventory(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class)); + } catch (GridAccessException e) { + return null; + } + } + + private class FluidDiscretizingInventory implements IMEInventory, IMEMonitorHandlerReceiver { + + private final MEInventoryHandler invHandler = new MEInventoryHandler<>(this, getChannel()); + @Nullable + private List itemCache = null; + + FluidDiscretizingInventory() { + invHandler.setPriority(Integer.MAX_VALUE); + } + + @SuppressWarnings("DuplicatedCode") + @Nullable + @Override + public IAEItemStack extractItems(IAEItemStack request, Actionable mode, IActionSource src) { + IAEFluidStack fluidStack = ItemFluidDrop.getAeFluidStack(request); + if (fluidStack == null) { + return null; + } + IMEMonitor fluidGrid = getFluidGrid(); + if (fluidGrid == null) { + return null; + } + IEnergyGrid energyGrid = getEnergyGrid(); + if (energyGrid == null) { + return null; + } + return ItemFluidDrop.newAeStack(Platform.poweredExtraction(energyGrid, fluidGrid, fluidStack, ownActionSource, mode)); + } + + @SuppressWarnings("DuplicatedCode") + @Nullable + @Override + public IAEItemStack injectItems(IAEItemStack input, Actionable type, IActionSource src) { + IAEFluidStack fluidStack = ItemFluidDrop.getAeFluidStack(input); + if (fluidStack == null) { + return input; + } + IMEMonitor fluidGrid = getFluidGrid(); + if (fluidGrid == null) { + return input; + } + IEnergyGrid energyGrid = getEnergyGrid(); + if (energyGrid == null) { + return input; + } + return ItemFluidDrop.newAeStack(Platform.poweredInsert(energyGrid, fluidGrid, fluidStack, ownActionSource, type)); + } + + @Override + public IItemList getAvailableItems(IItemList out) { + if (itemCache == null) { + itemCache = new ArrayList<>(); + IMEMonitor fluidGrid = getFluidGrid(); + if (fluidGrid != null) { + for (IAEFluidStack fluid : fluidGrid.getStorageList()) { + IAEItemStack stack = ItemFluidDrop.newAeStack(fluid); + if (stack != null) { + itemCache.add(stack); + } + } + } + } + for (IAEItemStack stack : itemCache) { + out.addStorage(stack); + } + return out; + } + + @Override + public boolean isValid(Object verificationToken) { + IMEMonitor fluidGrid = getFluidGrid(); + return fluidGrid != null && fluidGrid == verificationToken; + } + + @Override + public void postChange(IBaseMonitor monitor, Iterable change, IActionSource actionSource) { + itemCache = null; + try { + List mappedChanges = new ArrayList<>(); + for (IAEFluidStack fluidStack : change) { + IAEItemStack itemStack = ItemFluidDrop.newAeStack(fluidStack); + if (itemStack != null) { + mappedChanges.add(itemStack); + } + } + getProxy().getGrid().getCache(IStorageGrid.class) + .postAlterationOfStoredItems(getChannel(), mappedChanges, ownActionSource); + } catch (GridAccessException e) { + // NO-OP + } + } + + @Override + public void onListUpdate() { + // NO-OP + } + + @Override + public IStorageChannel getChannel() { + return AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class); + } + + } + + private class FluidCraftingInventory implements IMEInventory { + + private final MEInventoryHandler invHandler = new MEInventoryHandler<>(this, getChannel()); + + FluidCraftingInventory() { + invHandler.setPriority(Integer.MAX_VALUE); + } + + @Nullable + @Override + public IAEFluidStack injectItems(IAEFluidStack input, Actionable type, IActionSource src) { + ICraftingGrid craftingGrid; + try { + craftingGrid = getProxy().getGrid().getCache(ICraftingGrid.class); + } catch (GridAccessException e) { + return null; + } + if (craftingGrid instanceof CraftingGridCache) { + IAEItemStack remaining = ((CraftingGridCache)craftingGrid).injectItems( + ItemFluidDrop.newAeStack(input), type, ownActionSource); + if (remaining != null) { + return ItemFluidDrop.getAeFluidStack(remaining); + } + } + return null; + } + + @Nullable + @Override + public IAEFluidStack extractItems(IAEFluidStack request, Actionable mode, IActionSource src) { + return null; + } + + @Override + public IItemList getAvailableItems(IItemList out) { + return out; + } + + @Override + public IStorageChannel getChannel() { + return AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class); + } + + } + +} diff --git a/src/main/java/com/glodblock/github/common/tile/TileFluidPacketDecoder.java b/src/main/java/com/glodblock/github/common/tile/TileFluidPacketDecoder.java new file mode 100644 index 000000000..dcec9b7bf --- /dev/null +++ b/src/main/java/com/glodblock/github/common/tile/TileFluidPacketDecoder.java @@ -0,0 +1,130 @@ +package com.glodblock.github.common.tile; + +import appeng.api.AEApi; +import appeng.api.networking.GridFlags; +import appeng.api.networking.IGridNode; +import appeng.api.networking.energy.IEnergyGrid; +import appeng.api.networking.security.IActionSource; +import appeng.api.networking.storage.IStorageGrid; +import appeng.api.networking.ticking.IGridTickable; +import appeng.api.networking.ticking.TickRateModulation; +import appeng.api.networking.ticking.TickingRequest; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.channels.IFluidStorageChannel; +import appeng.api.storage.data.IAEFluidStack; +import appeng.fluids.util.AEFluidStack; +import appeng.helpers.Reflected; +import appeng.me.GridAccessException; +import appeng.me.helpers.MachineSource; +import appeng.tile.grid.AENetworkTile; +import appeng.tile.inventory.AppEngInternalInventory; +import appeng.util.Platform; +import appeng.util.inv.IAEAppEngInventory; +import appeng.util.inv.InvOperation; +import com.glodblock.github.common.item.ItemFluidPacket; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.IItemHandlerModifiable; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class TileFluidPacketDecoder extends AENetworkTile implements IGridTickable, IAEAppEngInventory { + + private final AppEngInternalInventory inventory = new AppEngInternalInventory(this, 1); + private final IActionSource ownActionSource = new MachineSource(this); + + @Reflected + public TileFluidPacketDecoder() { + getProxy().setIdlePowerUsage(1D); + getProxy().setFlags(GridFlags.REQUIRE_CHANNEL); + } + + public IItemHandlerModifiable getInventory() { + return inventory; + } + + @Override + public boolean canBeRotated() { + return false; + } + + @Override + public boolean hasCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { + return capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; + } + + @SuppressWarnings("unchecked") + @Nullable + @Override + public T getCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { + if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return (T)inventory; + } else { + return null; + } + } + + @Override + @Nonnull + public TickingRequest getTickingRequest(@Nonnull IGridNode node) { + return new TickingRequest(5, 120, false, true); + } + + @Override + @Nonnull + public TickRateModulation tickingRequest(@Nonnull IGridNode node, int ticksSinceLastCall) { + ItemStack stack = inventory.getStackInSlot(0); + if (stack.isEmpty() || !(stack.getItem() instanceof ItemFluidPacket)) { + return TickRateModulation.SLEEP; + } + FluidStack fluid = ItemFluidPacket.getFluidStack(stack); + if (fluid == null || fluid.amount <= 0) { + inventory.setStackInSlot(0, ItemStack.EMPTY); + return TickRateModulation.SLEEP; + } + IAEFluidStack aeFluid = AEFluidStack.fromFluidStack(fluid); + IEnergyGrid energyGrid = node.getGrid().getCache(IEnergyGrid.class); + IMEMonitor fluidGrid = node.getGrid().getCache(IStorageGrid.class) + .getInventory(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class)); + IAEFluidStack remaining = Platform.poweredInsert(energyGrid, fluidGrid, aeFluid, ownActionSource); + if (remaining != null) { + if (remaining.getStackSize() == aeFluid.getStackSize()) { + return TickRateModulation.SLOWER; + } + inventory.setStackInSlot(0, ItemFluidPacket.newStack(remaining.getFluidStack())); + return TickRateModulation.FASTER; + } else { + inventory.setStackInSlot(0, ItemStack.EMPTY); + return TickRateModulation.SLEEP; + } + } + + @Override + public void onChangeInventory(IItemHandler inv, int slot, InvOperation mc, ItemStack removedStack, ItemStack newStack) { + try { + getProxy().getTick().alertDevice(getProxy().getNode()); + } catch (GridAccessException e) { + // NO-OP + } + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); + inventory.writeToNBT(data, "Inventory"); + return data; + } + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + inventory.readFromNBT(data, "Inventory"); + } + +} diff --git a/src/main/java/com/glodblock/github/common/tile/TileFluidPatternEncoder.java b/src/main/java/com/glodblock/github/common/tile/TileFluidPatternEncoder.java new file mode 100644 index 000000000..b8e8d1624 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/tile/TileFluidPatternEncoder.java @@ -0,0 +1,98 @@ +package com.glodblock.github.common.tile; + +import appeng.api.AEApi; +import appeng.api.storage.channels.IItemStorageChannel; +import appeng.api.storage.data.IAEItemStack; +import appeng.tile.AEBaseTile; +import appeng.tile.inventory.AppEngInternalInventory; +import appeng.util.inv.IAEAppEngInventory; +import appeng.util.inv.InvOperation; +import com.glodblock.github.interfaces.AeStackInventory; +import com.glodblock.github.inventory.AeStackInventoryImpl; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.IItemHandlerModifiable; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; + +public class TileFluidPatternEncoder extends AEBaseTile implements IAEAppEngInventory { + + private final AppEngInternalInventory patternInv = new AppEngInternalInventory(this, 2); + private final AeStackInventoryImpl crafting = new AeStackInventoryImpl<>( + AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class), 9, this); + private final AeStackInventoryImpl output = new AeStackInventoryImpl<>( + AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class), 3, this); + + public IItemHandlerModifiable getInventory() { + return patternInv; + } + + public AeStackInventory getCraftingSlots() { + return crafting; + } + + public AeStackInventory getOutputSlots() { + return output; + } + + @Override + public boolean canBeRotated() { + return false; + } + + @Override + public boolean hasCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { + return capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; + } + + @SuppressWarnings("unchecked") + @Nullable + @Override + public T getCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { + if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return (T)patternInv; + } else { + return null; + } + } + + @Override + public void onChangeInventory(IItemHandler inv, int slot, InvOperation mc, ItemStack removedStack, ItemStack newStack) { + // NO-OP + } + + @Override + public void getDrops(World world, BlockPos pos, List drops) { + for (ItemStack stack : patternInv) { + if (!stack.isEmpty()) { + drops.add(stack); + } + } + } + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + patternInv.readFromNBT(data, "Inventory"); + crafting.readFromNbt(data, "CraftingSlots"); + output.readFromNbt(data, "OutputSlots"); + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); + patternInv.writeToNBT(data, "Inventory"); + crafting.writeToNbt(data, "CraftingSlots"); + output.writeToNbt(data, "OutputSlots"); + return data; + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/common/tile/TileIngredientBuffer.java b/src/main/java/com/glodblock/github/common/tile/TileIngredientBuffer.java new file mode 100644 index 000000000..225f8a286 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/tile/TileIngredientBuffer.java @@ -0,0 +1,139 @@ +package com.glodblock.github.common.tile; + +import appeng.api.storage.data.IAEFluidStack; +import appeng.fluids.util.AEFluidInventory; +import appeng.fluids.util.AEFluidStack; +import appeng.fluids.util.IAEFluidInventory; +import appeng.fluids.util.IAEFluidTank; +import appeng.tile.AEBaseInvTile; +import appeng.tile.inventory.AppEngInternalInventory; +import appeng.util.inv.InvOperation; +import io.netty.buffer.ByteBuf; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fml.common.network.ByteBufUtils; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.IOException; + +public class TileIngredientBuffer extends AEBaseInvTile implements IAEFluidInventory { + + private final AppEngInternalInventory invItems = new AppEngInternalInventory(this, 9); + private final AEFluidInventory invFluids = new AEFluidInventory(this, 4, 16000); + + @Nonnull + @Override + public IItemHandler getInternalInventory() { + return invItems; + } + + public IAEFluidTank getFluidInventory() { + return invFluids; + } + + @Override + public boolean canBeRotated() { + return false; + } + + @Override + public boolean hasCapability(Capability capability, EnumFacing facing) { + return capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY + || capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY; + } + + @SuppressWarnings("unchecked") + @Nullable + @Override + public T getCapability(Capability capability, @Nullable EnumFacing facing) { + if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return (T)invItems; + } else if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { + return (T)invFluids; + } + return null; + } + + @Override + public void onChangeInventory(IItemHandler inv, int slot, InvOperation mc, ItemStack removed, ItemStack added) { + markForUpdate(); + } + + @Override + public void onFluidInventoryChanged(IAEFluidTank inv, int slot) { + saveChanges(); + markForUpdate(); + } + + @Override + protected void writeToStream(ByteBuf data) throws IOException { + super.writeToStream(data); + for (int i = 0; i < invItems.getSlots(); i++) { + ByteBufUtils.writeItemStack(data, invItems.getStackInSlot(i)); + } + int fluidMask = 0; + for (int i = 0; i < invFluids.getSlots(); i++) { + if (invFluids.getFluidInSlot(i) != null) { + fluidMask |= 1 << i; + } + } + data.writeByte(fluidMask); + for (int i = 0; i < invFluids.getSlots(); i++) { + IAEFluidStack fluid = invFluids.getFluidInSlot(i); + if (fluid != null) { + fluid.writeToPacket(data); + } + } + } + + @Override + protected boolean readFromStream(ByteBuf data) throws IOException { + boolean changed = super.readFromStream(data); + for (int i = 0; i < invItems.getSlots(); i++) { + ItemStack stack = ByteBufUtils.readItemStack(data); + if (!ItemStack.areItemStacksEqual(stack, invItems.getStackInSlot(i))) { + invItems.setStackInSlot(i, stack); + changed = true; + } + } + int fluidMask = data.readByte(); + for (int i = 0; i < invFluids.getSlots(); i++) { + if ((fluidMask & (1 << i)) != 0) { + IAEFluidStack fluid = AEFluidStack.fromPacket(data); + if (fluid != null) { // this shouldn't happen, but better safe than sorry + IAEFluidStack origFluid = invFluids.getFluidInSlot(i); + if (!fluid.equals(origFluid) || fluid.getStackSize() != origFluid.getStackSize()) { + invFluids.setFluidInSlot(i, fluid); + changed = true; + } + } + } else if (invFluids.getFluidInSlot(i) != null) { + invFluids.setFluidInSlot(i, null); + changed = true; + } + } + return changed; + } + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + invItems.readFromNBT(data, "ItemInv"); + invFluids.readFromNBT(data, "FluidInv"); + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); + invItems.writeToNBT(data, "ItemInv"); + invFluids.writeToNBT(data, "FluidInv"); + return data; + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/coremod/CoreModHooks.java b/src/main/java/com/glodblock/github/coremod/CoreModHooks.java new file mode 100644 index 000000000..b14ef6786 --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/CoreModHooks.java @@ -0,0 +1,105 @@ +package com.glodblock.github.coremod; + +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridHost; +import appeng.api.networking.IGridNode; +import appeng.api.networking.IMachineSet; +import appeng.api.storage.data.IAEItemStack; +import appeng.me.MachineSet; +import appeng.parts.misc.PartInterface; +import appeng.tile.misc.TileInterface; +import appeng.util.InventoryAdaptor; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.common.part.PartDualInterface; +import com.glodblock.github.common.tile.TileDualInterface; +import com.glodblock.github.handler.FluidConvertingItemHandler; +import com.glodblock.github.inventory.FluidConvertingInventoryAdaptor; +import com.glodblock.github.inventory.FluidConvertingInventoryCrafting; +import com.glodblock.github.loader.FCItems; +import com.glodblock.github.util.Ae2Reflect; +import com.glodblock.github.util.SetBackedMachineSet; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; + +import javax.annotation.Nullable; +import java.util.HashSet; +import java.util.Set; +import com.google.common.collect.Sets; + +public class CoreModHooks { + + public static InventoryCrafting wrapCraftingBuffer(InventoryCrafting inv) { + return new FluidConvertingInventoryCrafting(Ae2Reflect.getCraftContainer(inv), inv.getWidth(), inv.getHeight()); + } + + public static IAEItemStack wrapFluidPacketStack(IAEItemStack stack) { + if (stack.getItem() == FCItems.FLUID_PACKET) { + IAEItemStack dropStack = ItemFluidDrop.newAeStack(ItemFluidPacket.getFluidStack(stack.getDefinition())); + if (dropStack != null) { + return dropStack; + } + } + return stack; + } + + @Nullable + public static InventoryAdaptor wrapInventory(@Nullable TileEntity tile, EnumFacing face) { + return tile != null ? FluidConvertingInventoryAdaptor.wrap(tile, face) : null; + } + + public static long getCraftingByteCost(IAEItemStack stack) { + return stack.getItem() instanceof ItemFluidDrop + ? (long)Math.ceil(stack.getStackSize() / 1000D) : stack.getStackSize(); + } + + public static boolean checkForItemHandler(ICapabilityProvider capProvider, Capability capability, EnumFacing side) { + return capProvider.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side) + || capProvider.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, side); + } + + public static IItemHandler wrapItemHandler(ICapabilityProvider capProvider, Capability capability, EnumFacing side) { + return FluidConvertingItemHandler.wrap(capProvider, side); + } + + public static IAEItemStack[] flattenFluidPackets(IAEItemStack[] stacks) { + for (int i = 0; i < stacks.length; i++) { + if (stacks[i].getItem() instanceof ItemFluidPacket) { + stacks[i] = ItemFluidDrop.newAeStack(ItemFluidPacket.getFluidStack(stacks[i])); + } + } + return stacks; + } + + public static IMachineSet getMachines(IGrid grid, Class c) { + if (c == TileInterface.class) { + return unionMachineSets(grid.getMachines(c), grid.getMachines(TileDualInterface.class)); + } else if (c == PartInterface.class) { + return unionMachineSets(grid.getMachines(c), grid.getMachines(PartDualInterface.class)); + } else { + return grid.getMachines(c); + } + } + + private static IMachineSet unionMachineSets(IMachineSet a, IMachineSet b) { + if (a.isEmpty()) { + return b; + } else if (b.isEmpty()) { + return a; + } else if (a instanceof MachineSet && b instanceof MachineSet) { + return new SetBackedMachineSet(TileInterface.class, Sets.union((MachineSet)a, (MachineSet)b)); + } else { + Set union = new HashSet<>(); + a.forEach(union::add); + b.forEach(union::add); + return new SetBackedMachineSet(TileInterface.class, union); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/coremod/FCClassTransformer.java b/src/main/java/com/glodblock/github/coremod/FCClassTransformer.java new file mode 100644 index 000000000..2a681268c --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/FCClassTransformer.java @@ -0,0 +1,67 @@ +package com.glodblock.github.coremod; + +import com.glodblock.github.coremod.transform.*; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import net.minecraft.launchwrapper.IClassTransformer; +import org.objectweb.asm.ClassWriter; + +public class FCClassTransformer implements IClassTransformer { + + @Override + public byte[] transform(String name, String transformedName, byte[] code) { + Transform tform; + switch (transformedName) { + case "appeng.crafting.CraftingTreeNode": + tform = CraftingTreeNodeTransformer.INSTANCE; + break; + case "appeng.helpers.DualityInterface": + tform = DualityInterfaceTransformer.INSTANCE; + break; + case "appeng.me.cluster.implementations.CraftingCPUCluster": + tform = CraftingCpuTransformer.INSTANCE; + break; + case "thelm.packagedauto.integration.appeng.recipe.PackageCraftingPatternHelper": + tform = PautoCraftingPatternHelperTransformer.TFORM_INPUTS; + break; + case "thelm.packagedauto.integration.appeng.recipe.RecipeCraftingPatternHelper": + tform = PautoCraftingPatternHelperTransformer.TFORM_OUTPUTS; + break; + case "thelm.packagedauto.tile.TileUnpackager": + tform = TileUnpackagerTransformer.INSTANCE; + break; + case "appeng.container.implementations.ContainerInterfaceTerminal": + tform = ContainerInterfaceTerminalTransformer.INSTANCE; + break; + default: + return code; + } + System.out.println("[AE2FC] Transforming class: " + transformedName); + return tform.transformClass(code); + } + + public interface Transform { + + byte[] transformClass(byte[] code); + + } + + public static abstract class ClassMapper implements Transform { + + @Override + public byte[] transformClass(byte[] code) { + ClassReader reader = new ClassReader(code); + ClassWriter writer = new ClassWriter(reader, getWriteFlags()); + reader.accept(getClassMapper(writer), 0); + return writer.toByteArray(); + } + + protected int getWriteFlags() { + return 0; + } + + protected abstract ClassVisitor getClassMapper(ClassVisitor downstream); + + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/coremod/FCCoreMod.java b/src/main/java/com/glodblock/github/coremod/FCCoreMod.java new file mode 100644 index 000000000..789f05fc2 --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/FCCoreMod.java @@ -0,0 +1,40 @@ +package com.glodblock.github.coremod; + +import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; + +import javax.annotation.Nullable; +import java.util.Map; + +@IFMLLoadingPlugin.MCVersion("1.12.2") +@IFMLLoadingPlugin.TransformerExclusions("com.glodblock.github.coremod") +public class FCCoreMod implements IFMLLoadingPlugin { + + @Override + public String[] getASMTransformerClass() { + return new String[] { FCCoreMod.class.getPackage().getName() + ".FCClassTransformer" }; + } + + @Nullable + @Override + public String getModContainerClass() { + return null; + } + + @Nullable + @Override + public String getSetupClass() { + return null; + } + + @Override + public void injectData(Map data) { + // NO-OP + } + + @Nullable + @Override + public String getAccessTransformerClass() { + return null; + } + +} diff --git a/src/main/java/com/glodblock/github/coremod/transform/ContainerInterfaceTerminalTransformer.java b/src/main/java/com/glodblock/github/coremod/transform/ContainerInterfaceTerminalTransformer.java new file mode 100644 index 000000000..5d6c82e1a --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/transform/ContainerInterfaceTerminalTransformer.java @@ -0,0 +1,58 @@ +package com.glodblock.github.coremod.transform; + +import com.glodblock.github.coremod.FCClassTransformer; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class ContainerInterfaceTerminalTransformer extends FCClassTransformer.ClassMapper { + + public static final ContainerInterfaceTerminalTransformer INSTANCE = new ContainerInterfaceTerminalTransformer(); + + private ContainerInterfaceTerminalTransformer() { + // NO-OP + } + + @Override + protected ClassVisitor getClassMapper(ClassVisitor downstream) { + return new TransformContainerInterfaceTerminal(Opcodes.ASM5, downstream); + } + + private static class TransformContainerInterfaceTerminal extends ClassVisitor { + + TransformContainerInterfaceTerminal(int api, ClassVisitor cv) { + super(api, cv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if (name.equals("detectAndSendChanges") || name.equals("func_75142_b") || name.equals("regenList")) { + return new TransformDetectAndSendChanges(api, super.visitMethod(access, name, desc, signature, exceptions)); + } + return super.visitMethod(access, name, desc, signature, exceptions); + } + + } + + private static class TransformDetectAndSendChanges extends MethodVisitor { + + TransformDetectAndSendChanges(int api, MethodVisitor mv) { + super(api, mv); + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (opcode == Opcodes.INVOKEINTERFACE + && owner.equals("appeng/api/networking/IGrid") && name.equals("getMachines")) { + super.visitMethodInsn(Opcodes.INVOKESTATIC, + "com/glodblock/github/coremod/CoreModHooks", + "getMachines", + "(Lappeng/api/networking/IGrid;Ljava/lang/Class;)Lappeng/api/networking/IMachineSet;", + false); + } else { + super.visitMethodInsn(opcode, owner, name, desc, itf); + } + } + + } +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/coremod/transform/CraftingCpuTransformer.java b/src/main/java/com/glodblock/github/coremod/transform/CraftingCpuTransformer.java new file mode 100644 index 000000000..c98e7f7b6 --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/transform/CraftingCpuTransformer.java @@ -0,0 +1,86 @@ +package com.glodblock.github.coremod.transform; + +import com.glodblock.github.coremod.FCClassTransformer; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class CraftingCpuTransformer extends FCClassTransformer.ClassMapper { + + public static final CraftingCpuTransformer INSTANCE = new CraftingCpuTransformer(); + + private CraftingCpuTransformer() { + // NO-OP + } + + @Override + protected ClassVisitor getClassMapper(ClassVisitor downstream) { + return new TransformCraftingCPUCluster(Opcodes.ASM5, downstream); + } + + private static class TransformCraftingCPUCluster extends ClassVisitor { + + TransformCraftingCPUCluster(int api, ClassVisitor cv) { + super(api, cv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if (name.equals("executeCrafting")) { + return new TransformExecuteCrafting(api, super.visitMethod(access, name, desc, signature, exceptions)); + } + return super.visitMethod(access, name, desc, signature, exceptions); + } + + } + + private static class TransformExecuteCrafting extends MethodVisitor { + + private boolean gotInventory = false; + + TransformExecuteCrafting(int api, MethodVisitor mv) { + super(api, mv); + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, String desc) { + if (opcode == Opcodes.GETFIELD + && owner.equals("appeng/me/cluster/implementations/CraftingCPUCluster") && name.equals("inventory")) { + gotInventory = true; + } + super.visitFieldInsn(opcode, owner, name, desc); + } + + @Override + public void visitLineNumber(int line, Label start) { + gotInventory = false; + super.visitLineNumber(line, start); + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + if (gotInventory) { + if (opcode == Opcodes.INVOKESTATIC + && owner.equals("appeng/util/item/AEItemStack") && name.equals("fromItemStack")) { + gotInventory = false; + super.visitMethodInsn(Opcodes.INVOKESTATIC, + "com/glodblock/github/coremod/CoreModHooks", + "wrapFluidPacketStack", + "(Lappeng/api/storage/data/IAEItemStack;)Lappeng/api/storage/data/IAEItemStack;", + false); + } + } else if (opcode == Opcodes.INVOKESPECIAL + && owner.equals("net/minecraft/inventory/InventoryCrafting") && name.equals("")) { + super.visitMethodInsn(Opcodes.INVOKESTATIC, + "com/glodblock/github/coremod/CoreModHooks", + "wrapCraftingBuffer", + "(Lnet/minecraft/inventory/InventoryCrafting;)Lnet/minecraft/inventory/InventoryCrafting;", + false); + } + } + + } + +} diff --git a/src/main/java/com/glodblock/github/coremod/transform/CraftingTreeNodeTransformer.java b/src/main/java/com/glodblock/github/coremod/transform/CraftingTreeNodeTransformer.java new file mode 100644 index 000000000..c4028f3c2 --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/transform/CraftingTreeNodeTransformer.java @@ -0,0 +1,77 @@ +package com.glodblock.github.coremod.transform; + +import com.glodblock.github.coremod.FCClassTransformer; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class CraftingTreeNodeTransformer extends FCClassTransformer.ClassMapper { + + public static final CraftingTreeNodeTransformer INSTANCE = new CraftingTreeNodeTransformer(); + + private CraftingTreeNodeTransformer() { + // NO-OP + } + + @Override + protected ClassVisitor getClassMapper(ClassVisitor downstream) { + return new TransformCraftingTreeNode(Opcodes.ASM5, downstream); + } + + private static class TransformCraftingTreeNode extends ClassVisitor { + + TransformCraftingTreeNode(int api, ClassVisitor cv) { + super(api, cv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if (name.equals("request")) { + return new TransformRequest(api, super.visitMethod(access, name, desc, signature, exceptions)); + } + return super.visitMethod(access, name, desc, signature, exceptions); + } + + } + + private static class TransformRequest extends MethodVisitor { + + private boolean writingBytes = false; + + TransformRequest(int api, MethodVisitor mv) { + super(api, mv); + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, String desc) { + if (opcode == Opcodes.GETFIELD && owner.equals("appeng/crafting/CraftingTreeNode") && name.equals("bytes")) { + writingBytes = true; + } + super.visitFieldInsn(opcode, owner, name, desc); + } + + @Override + public void visitLineNumber(int line, Label start) { + writingBytes = false; // no write here + super.visitLineNumber(line, start); + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (writingBytes && opcode == Opcodes.INVOKEINTERFACE + && owner.equals("appeng/api/storage/data/IAEItemStack") && name.equals("getStackSize")) { + writingBytes = false; + super.visitMethodInsn(Opcodes.INVOKESTATIC, + "com/glodblock/github/coremod/CoreModHooks", + "getCraftingByteCost", + "(Lappeng/api/storage/data/IAEItemStack;)J", + false); + } else { + super.visitMethodInsn(opcode, owner, name, desc, itf); + } + } + + } + +} diff --git a/src/main/java/com/glodblock/github/coremod/transform/DualityInterfaceTransformer.java b/src/main/java/com/glodblock/github/coremod/transform/DualityInterfaceTransformer.java new file mode 100644 index 000000000..7db0adabd --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/transform/DualityInterfaceTransformer.java @@ -0,0 +1,62 @@ +package com.glodblock.github.coremod.transform; + +import com.glodblock.github.coremod.FCClassTransformer; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class DualityInterfaceTransformer extends FCClassTransformer.ClassMapper { + + public static final DualityInterfaceTransformer INSTANCE = new DualityInterfaceTransformer(); + + private DualityInterfaceTransformer() { + // NO-OP + } + + @Override + protected ClassVisitor getClassMapper(ClassVisitor downstream) { + return new TransformDualityInterface(Opcodes.ASM5, downstream); + } + + private static class TransformDualityInterface extends ClassVisitor { + + TransformDualityInterface(int api, ClassVisitor cv) { + super(api, cv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + switch (name) { + case "pushItemsOut": + case "pushPattern": + case "isBusy": + return new TransformInvAdaptorCalls(api, super.visitMethod(access, name, desc, signature, exceptions)); + default: + return super.visitMethod(access, name, desc, signature, exceptions); + } + } + + } + + private static class TransformInvAdaptorCalls extends MethodVisitor { + + TransformInvAdaptorCalls(int api, MethodVisitor mv) { + super(api, mv); + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (opcode == Opcodes.INVOKESTATIC && owner.equals("appeng/util/InventoryAdaptor") && name.equals("getAdaptor")) { + super.visitMethodInsn(Opcodes.INVOKESTATIC, + "com/glodblock/github/coremod/CoreModHooks", + "wrapInventory", + "(Lnet/minecraft/tileentity/TileEntity;Lnet/minecraft/util/EnumFacing;)Lappeng/util/InventoryAdaptor;", + false); + } else { + super.visitMethodInsn(opcode, owner, name, desc, itf); + } + } + + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/coremod/transform/PautoCraftingPatternHelperTransformer.java b/src/main/java/com/glodblock/github/coremod/transform/PautoCraftingPatternHelperTransformer.java new file mode 100644 index 000000000..22be04773 --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/transform/PautoCraftingPatternHelperTransformer.java @@ -0,0 +1,57 @@ +package com.glodblock.github.coremod.transform; + +import com.glodblock.github.coremod.FCClassTransformer; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class PautoCraftingPatternHelperTransformer extends FCClassTransformer.ClassMapper { + + public static final PautoCraftingPatternHelperTransformer TFORM_INPUTS = new PautoCraftingPatternHelperTransformer("inputs"); + public static final PautoCraftingPatternHelperTransformer TFORM_OUTPUTS = new PautoCraftingPatternHelperTransformer("outputs"); + + private final String fieldName; + + private PautoCraftingPatternHelperTransformer(String fieldName) { + this.fieldName = fieldName; + } + + @Override + protected ClassVisitor getClassMapper(ClassVisitor downstream) { + return new TransformPackageCraftingPatternHelper(Opcodes.ASM5, downstream); + } + + private class TransformPackageCraftingPatternHelper extends ClassVisitor { + + TransformPackageCraftingPatternHelper(int api, ClassVisitor cv) { + super(api, cv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if (name.equals("")) { + return new TransformCtor(api, super.visitMethod(access, name, desc, signature, exceptions)); + } + return super.visitMethod(access, name, desc, signature, exceptions); + } + + } + + private class TransformCtor extends MethodVisitor { + + TransformCtor(int api, MethodVisitor mv) { + super(api, mv); + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, String desc) { + if (opcode == Opcodes.PUTFIELD && name.equals(fieldName) && desc.equals("[Lappeng/api/storage/data/IAEItemStack;")) { + super.visitMethodInsn(Opcodes.INVOKESTATIC, "com/glodblock/github/coremod/CoreModHooks", "flattenFluidPackets", + "([Lappeng/api/storage/data/IAEItemStack;)[Lappeng/api/storage/data/IAEItemStack;", false); + } + super.visitFieldInsn(opcode, owner, name, desc); + } + + } + +} diff --git a/src/main/java/com/glodblock/github/coremod/transform/TileUnpackagerTransformer.java b/src/main/java/com/glodblock/github/coremod/transform/TileUnpackagerTransformer.java new file mode 100644 index 000000000..bf3b32708 --- /dev/null +++ b/src/main/java/com/glodblock/github/coremod/transform/TileUnpackagerTransformer.java @@ -0,0 +1,84 @@ +package com.glodblock.github.coremod.transform; + +import com.glodblock.github.coremod.FCClassTransformer; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class TileUnpackagerTransformer extends FCClassTransformer.ClassMapper { + + public static final TileUnpackagerTransformer INSTANCE = new TileUnpackagerTransformer(); + + private TileUnpackagerTransformer() { + // NO-OP + } + + @Override + protected ClassVisitor getClassMapper(ClassVisitor downstream) { + return new TransformTileUnpackager(Opcodes.ASM5, downstream); + } + + private static class TransformTileUnpackager extends ClassVisitor { + + TransformTileUnpackager(int api, ClassVisitor cv) { + super(api, cv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if (name.equals("emptyTrackers") && desc.equals("()V")) { + return new TransformEmptyTrackers(api, super.visitMethod(access, name, desc, signature, exceptions)); + } + return super.visitMethod(access, name, desc, signature, exceptions); + } + + } + + private static class TransformEmptyTrackers extends MethodVisitor { + + private boolean gettingItemHandlerCap = false; + + TransformEmptyTrackers(int api, MethodVisitor mv) { + super(api, mv); + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, String desc) { + super.visitFieldInsn(opcode, owner, name, desc); + if (opcode == Opcodes.GETSTATIC && desc.equals("Lnet/minecraftforge/common/capabilities/Capability;")) { + gettingItemHandlerCap = name.equals("ITEM_HANDLER_CAPABILITY"); + } + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (opcode == Opcodes.INVOKEVIRTUAL && gettingItemHandlerCap) { + switch (name) { + case "hasCapability": + if (desc.equals("(Lnet/minecraftforge/common/capabilities/Capability;Lnet/minecraft/util/EnumFacing;)Z")) { + super.visitMethodInsn(Opcodes.INVOKESTATIC, "com/glodblock/github/coremod/CoreModHooks", "checkForItemHandler", + "(Lnet/minecraftforge/common/capabilities/ICapabilityProvider;Lnet/minecraftforge/common/capabilities/Capability;" + + "Lnet/minecraft/util/EnumFacing;)Z", false); + gettingItemHandlerCap = false; + } + break; + case "getCapability": + if (desc.equals("(Lnet/minecraftforge/common/capabilities/Capability;Lnet/minecraft/util/EnumFacing;)Ljava/lang/Object;")) { + super.visitMethodInsn(Opcodes.INVOKESTATIC, "com/glodblock/github/coremod/CoreModHooks", "wrapItemHandler", + "(Lnet/minecraftforge/common/capabilities/ICapabilityProvider;Lnet/minecraftforge/common/capabilities/Capability;" + + "Lnet/minecraft/util/EnumFacing;)Lnet/minecraftforge/items/IItemHandler;", false); + gettingItemHandlerCap = false; + } + break; + default: + super.visitMethodInsn(opcode, owner, name, desc, itf); + break; + } + } else { + super.visitMethodInsn(opcode, owner, name, desc, itf); + } + } + + } + +} diff --git a/src/main/java/com/glodblock/github/handler/AeItemStackHandler.java b/src/main/java/com/glodblock/github/handler/AeItemStackHandler.java new file mode 100644 index 000000000..106372dc2 --- /dev/null +++ b/src/main/java/com/glodblock/github/handler/AeItemStackHandler.java @@ -0,0 +1,46 @@ +package com.glodblock.github.handler; + +import appeng.api.storage.data.IAEItemStack; +import com.glodblock.github.interfaces.AeStackInventory; +import net.minecraft.item.ItemStack; +import net.minecraftforge.items.IItemHandler; + +public class AeItemStackHandler implements IItemHandler { + + private final AeStackInventory inv; + + public AeItemStackHandler(AeStackInventory inv) { + this.inv = inv; + } + + public AeStackInventory getAeInventory() { + return inv; + } + + @Override + public int getSlots() { + return inv.getSlotCount(); + } + + @Override + public ItemStack getStackInSlot(int slot) { + IAEItemStack stack = inv.getStack(slot); + return stack != null ? stack.createItemStack() : ItemStack.EMPTY; + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + return ItemStack.EMPTY; + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + return ItemStack.EMPTY; + } + + @Override + public int getSlotLimit(int slot) { + return 64; + } + +} diff --git a/src/main/java/com/glodblock/github/handler/ButtonMouseHandler.java b/src/main/java/com/glodblock/github/handler/ButtonMouseHandler.java new file mode 100644 index 000000000..3050bfe6f --- /dev/null +++ b/src/main/java/com/glodblock/github/handler/ButtonMouseHandler.java @@ -0,0 +1,48 @@ +package com.glodblock.github.handler; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.interfaces.TankDumpable; +import com.glodblock.github.network.CPacketDumpTank; +import com.glodblock.github.util.MouseRegionManager; +import com.glodblock.github.util.NameConst; +import net.minecraft.client.resources.I18n; + +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.List; + +public class ButtonMouseHandler implements MouseRegionManager.Handler { + + @Nullable + private final String tooltipKey; + private final Runnable callback; + + public ButtonMouseHandler(@Nullable String tooltipKey, Runnable callback) { + this.tooltipKey = tooltipKey; + this.callback = callback; + } + + @Nullable + @Override + public List getTooltip() { + return tooltipKey != null ? Collections.singletonList(I18n.format(tooltipKey)) : null; + } + + @Override + public boolean onClick(int button) { + if (button == 0) { + callback.run(); + return true; + } + return false; + } + + public static ButtonMouseHandler dumpTank(TankDumpable host, int index) { + return new ButtonMouseHandler(NameConst.TT_DUMP_TANK, () -> { + if (host.canDumpTank(index)) { + FluidCraft.proxy.netHandler.sendToServer(new CPacketDumpTank(index)); + } + }); + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/handler/ClientRegistryHandler.java b/src/main/java/com/glodblock/github/handler/ClientRegistryHandler.java new file mode 100644 index 000000000..b325d9b4f --- /dev/null +++ b/src/main/java/com/glodblock/github/handler/ClientRegistryHandler.java @@ -0,0 +1,41 @@ +package com.glodblock.github.handler; + +import appeng.api.AEApi; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.model.DenseEncodedPatternModel; +import com.glodblock.github.client.model.FluidPacketModel; +import com.glodblock.github.common.part.PartDualInterface; +import com.glodblock.github.common.part.PartFluidPatternTerminal; +import com.glodblock.github.interfaces.HasCustomModel; +import net.minecraft.block.Block; +import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.item.Item; +import net.minecraftforge.client.event.ModelRegistryEvent; +import net.minecraftforge.client.model.ModelLoader; +import net.minecraftforge.client.model.ModelLoaderRegistry; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.apache.commons.lang3.tuple.Pair; + +public class ClientRegistryHandler extends RegistryHandler { + + @SubscribeEvent + public void onRegisterModels(ModelRegistryEvent event) { + ModelLoaderRegistry.registerLoader(new DenseEncodedPatternModel.Loader()); + ModelLoaderRegistry.registerLoader(new FluidPacketModel.Loader()); + for (Pair entry : blocks) { + registerModel(entry.getLeft(), Item.getItemFromBlock(entry.getRight())); + } + for (Pair entry : items) { + registerModel(entry.getLeft(), entry.getRight()); + } + AEApi.instance().registries().partModels().registerModels(PartDualInterface.MODELS); + AEApi.instance().registries().partModels().registerModels(PartFluidPatternTerminal.MODELS); + } + + private static void registerModel(String key, Item item) { + ModelLoader.setCustomModelResourceLocation(item, 0, new ModelResourceLocation( + item instanceof HasCustomModel ? ((HasCustomModel)item).getCustomModelPath() : FluidCraft.resource(key), + "inventory")); + } + +} diff --git a/src/main/java/com/glodblock/github/handler/FluidConvertingItemHandler.java b/src/main/java/com/glodblock/github/handler/FluidConvertingItemHandler.java new file mode 100644 index 000000000..2317eb845 --- /dev/null +++ b/src/main/java/com/glodblock/github/handler/FluidConvertingItemHandler.java @@ -0,0 +1,147 @@ +package com.glodblock.github.handler; + +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidTankProperties; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Objects; + +public class FluidConvertingItemHandler implements IItemHandler { + + public static FluidConvertingItemHandler wrap(ICapabilityProvider capProvider, EnumFacing face) { + // sometimes i wish i had the monadic version from 1.15 + return new FluidConvertingItemHandler( + capProvider.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, face) + ? Objects.requireNonNull(capProvider.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, face)) + : null, + capProvider.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, face) + ? Objects.requireNonNull(capProvider.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, face)) + : null); + } + + @Nullable + private final IItemHandler invItems; + @Nullable + private final IFluidHandler invFluids; + + private FluidConvertingItemHandler(@Nullable IItemHandler invItems, @Nullable IFluidHandler invFluids) { + this.invItems = invItems; + this.invFluids = invFluids; + } + + @Override + public int getSlots() { + int slots = 0; + if (invItems != null) { + slots += invItems.getSlots(); + } + if (invFluids != null) { + slots += invFluids.getTankProperties().length; + } + return slots; + } + + @Override + @Nonnull + public ItemStack getStackInSlot(int slot) { + return slotOp(slot, IItemHandler::getStackInSlot, + (fh, i) -> ItemFluidDrop.newStack(fh.getTankProperties()[i].getContents())); + } + + @Override + @Nonnull + public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) { + return slotOp(slot, + (ih, i) -> (stack.getItem() instanceof ItemFluidDrop || stack.getItem() instanceof ItemFluidPacket) + ? stack : ih.insertItem(i, stack, simulate), + (fh, i) -> { + if (stack.getItem() instanceof ItemFluidDrop) { + FluidStack toInsert = ItemFluidDrop.getFluidStack(stack); + if (toInsert != null && toInsert.amount > 0) { + FluidStack contained = fh.getTankProperties()[i].getContents(); + if (contained == null || contained.amount == 0 || contained.isFluidEqual(toInsert)) { + toInsert.amount -= fh.fill(toInsert, !simulate); + return ItemFluidDrop.newStack(toInsert); + } + } + } else if (stack.getItem() instanceof ItemFluidPacket) { + FluidStack toInsert = ItemFluidPacket.getFluidStack(stack); + if (toInsert != null && toInsert.amount > 0) { + FluidStack contained = fh.getTankProperties()[i].getContents(); + if (contained == null || contained.amount == 0 || contained.isFluidEqual(toInsert)) { + int insertable = fh.fill(toInsert, false); // only insert if the entire packet fits + if (insertable >= toInsert.amount) { + if (!simulate) { + fh.fill(toInsert, true); + } + return ItemStack.EMPTY; + } + } + } + } + return stack; + }); + } + + @Override + @Nonnull + public ItemStack extractItem(int slot, int amount, boolean simulate) { + return slotOp(slot, (ih, i) -> ih.extractItem(i, slot, simulate), (fh, i) -> { + FluidStack contained = fh.getTankProperties()[i].getContents(); + if (contained != null && contained.amount > 0) { + return ItemFluidDrop.newStack(fh.drain(contained, !simulate)); + } + return ItemStack.EMPTY; + }); + } + + @Override + public int getSlotLimit(int slot) { + return slotOp(slot, IItemHandler::getSlotLimit, (fh, i) -> fh.getTankProperties()[i].getCapacity()); + } + + @Override + public boolean isItemValid(int slot, @Nonnull ItemStack stack) { + return slotOp(slot, (ih, i) -> ih.isItemValid(i, stack), + (fh, i) -> stack.getItem() instanceof ItemFluidDrop || stack.getItem() instanceof ItemFluidPacket); + } + + private T slotOp(int slot, Op itemConsumer, Op fluidConsumer) { + if (slot >= 0) { + int fluidSlot = slot; + if (invItems != null) { + if (slot < invItems.getSlots()) { + return itemConsumer.apply(invItems, slot); + } else { + fluidSlot -= invItems.getSlots(); + } + } + if (invFluids != null) { + IFluidTankProperties[] tanks = invFluids.getTankProperties(); + if (fluidSlot < tanks.length) { + return fluidConsumer.apply(invFluids, fluidSlot); + } + } + } + throw new IndexOutOfBoundsException(String.format("Slot index %d out of bounds! |items| = %d, |fluids| = %d", slot, + invItems != null ? invItems.getSlots() : 0, invFluids != null ? invFluids.getTankProperties().length : 0)); + } + + @FunctionalInterface + private interface Op { + + T apply(C collection, int index); + + } + +} diff --git a/src/main/java/com/glodblock/github/handler/RegistryHandler.java b/src/main/java/com/glodblock/github/handler/RegistryHandler.java new file mode 100644 index 000000000..fde38289b --- /dev/null +++ b/src/main/java/com/glodblock/github/handler/RegistryHandler.java @@ -0,0 +1,74 @@ +package com.glodblock.github.handler; + +import appeng.block.AEBaseItemBlock; +import appeng.block.AEBaseTileBlock; +import appeng.core.features.ActivityState; +import appeng.core.features.BlockStackSrc; +import appeng.tile.AEBaseTile; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.loader.FCItems; +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.registry.ForgeRegistries; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.ArrayList; +import java.util.List; + +public class RegistryHandler { + + protected final List> blocks = new ArrayList<>(); + protected final List> items = new ArrayList<>(); + + public void block(String name, Block block) { + blocks.add(Pair.of(name, block)); + } + + public void item(String name, Item item) { + items.add(Pair.of(name, item)); + } + + @SubscribeEvent + public void onRegisterBlocks(RegistryEvent.Register event) { + for (Pair entry : blocks) { + String key = entry.getLeft(); + Block block = entry.getRight(); + block.setRegistryName(key); + block.setTranslationKey(FluidCraft.MODID + ":" + key); + block.setCreativeTab(FCItems.TAB_AE2FC); + event.getRegistry().register(block); + } + } + + @SubscribeEvent + public void onRegisterItems(RegistryEvent.Register event) { + // TODO some way to handle blocks with custom ItemBlock + for (Pair entry : blocks) { + event.getRegistry().register(initItem(entry.getLeft(), new AEBaseItemBlock(entry.getRight()))); + } + for (Pair entry : items) { + event.getRegistry().register(initItem(entry.getLeft(), entry.getRight())); + } + } + + private static Item initItem(String key, Item item) { + item.setRegistryName(key); + item.setTranslationKey(FluidCraft.MODID + ":" + key); + item.setCreativeTab(FCItems.TAB_AE2FC); + return item; + } + + public void onInit() { + for (Pair entry : blocks) { + // respects registry overrides, i guess + Block block = ForgeRegistries.BLOCKS.getValue(FluidCraft.resource(entry.getKey())); + if (block instanceof AEBaseTileBlock) { + AEBaseTile.registerTileItem(((AEBaseTileBlock)block).getTileEntityClass(), + new BlockStackSrc(block, 0, ActivityState.Enabled)); + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/handler/TankMouseHandler.java b/src/main/java/com/glodblock/github/handler/TankMouseHandler.java new file mode 100644 index 000000000..b95d120ac --- /dev/null +++ b/src/main/java/com/glodblock/github/handler/TankMouseHandler.java @@ -0,0 +1,34 @@ +package com.glodblock.github.handler; + +import appeng.api.storage.data.IAEFluidStack; +import appeng.fluids.util.IAEFluidTank; +import com.glodblock.github.util.MouseRegionManager; +import com.glodblock.github.util.NameConst; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.text.TextFormatting; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.List; + +public class TankMouseHandler implements MouseRegionManager.Handler { + + private final IAEFluidTank tank; + private final int index; + + public TankMouseHandler(IAEFluidTank tank, int index) { + this.tank = tank; + this.index = index; + } + + @Nullable + @Override + public List getTooltip() { + IAEFluidStack fluid = tank.getFluidInSlot(index); + return Arrays.asList( + fluid != null ? fluid.getFluidStack().getLocalizedName() : I18n.format(NameConst.TT_EMPTY), + TextFormatting.GRAY + String.format("%,d / %,d mB", + fluid != null ? fluid.getStackSize() : 0L, tank.getTankProperties()[index].getCapacity())); + } + +} diff --git a/src/main/java/com/glodblock/github/integration/jei/ExtraExtractors.java b/src/main/java/com/glodblock/github/integration/jei/ExtraExtractors.java new file mode 100644 index 000000000..cf455ecce --- /dev/null +++ b/src/main/java/com/glodblock/github/integration/jei/ExtraExtractors.java @@ -0,0 +1,23 @@ +package com.glodblock.github.integration.jei; + +import com.glodblock.github.integration.jei.interfaces.IngredientExtractor; +import mezz.jei.api.gui.IRecipeLayout; +import net.minecraftforge.fluids.FluidStack; + +import javax.annotation.Nullable; +import java.util.stream.Stream; + +public class ExtraExtractors { + + @Nullable + private final IngredientExtractor extModMach; + + public ExtraExtractors(@Nullable IngredientExtractor extModMach) { + this.extModMach = extModMach; + } + + public Stream> extractFluids(IRecipeLayout recipeLayout) { + return extModMach != null ? extModMach.extract(recipeLayout) : Stream.empty(); + } + +} diff --git a/src/main/java/com/glodblock/github/integration/jei/FCJeiPlugin.java b/src/main/java/com/glodblock/github/integration/jei/FCJeiPlugin.java new file mode 100644 index 000000000..a2c83ec14 --- /dev/null +++ b/src/main/java/com/glodblock/github/integration/jei/FCJeiPlugin.java @@ -0,0 +1,35 @@ +package com.glodblock.github.integration.jei; + +import com.glodblock.github.integration.jei.interfaces.IngredientExtractor; +import mezz.jei.api.IModPlugin; +import mezz.jei.api.IModRegistry; +import mezz.jei.api.JEIPlugin; +import mezz.jei.config.Constants; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.common.Loader; + +import javax.annotation.Nullable; +import java.util.Objects; + +@JEIPlugin +public class FCJeiPlugin implements IModPlugin { + + @Nullable + private static ExtraExtractors ext = null; + + public static ExtraExtractors getExtraExtractors() { + return Objects.requireNonNull(ext); + } + + @Override + public void register(IModRegistry registry) { + IngredientExtractor extModMach = Loader.isModLoaded("modularmachinery") + ? new ModMachHybridFluidStackExtractor(registry) : null; + ext = new ExtraExtractors(extModMach); + registry.getRecipeTransferRegistry().addRecipeTransferHandler( + new FluidPatternEncoderRecipeTransferHandler(ext), Constants.UNIVERSAL_RECIPE_TRANSFER_UID); + registry.getRecipeTransferRegistry().addRecipeTransferHandler( + new FluidPatternTerminalRecipeTransferHandler(ext), Constants.UNIVERSAL_RECIPE_TRANSFER_UID); + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/integration/jei/FluidPatternEncoderRecipeTransferHandler.java b/src/main/java/com/glodblock/github/integration/jei/FluidPatternEncoderRecipeTransferHandler.java new file mode 100644 index 000000000..e45f082d9 --- /dev/null +++ b/src/main/java/com/glodblock/github/integration/jei/FluidPatternEncoderRecipeTransferHandler.java @@ -0,0 +1,105 @@ +package com.glodblock.github.integration.jei; + +import appeng.api.storage.data.IAEItemStack; +import appeng.util.item.AEItemStack; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.container.ContainerFluidPatternEncoder; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.common.tile.TileFluidPatternEncoder; +import com.glodblock.github.network.CPacketLoadPattern; +import com.glodblock.github.util.NameConst; +import mezz.jei.api.gui.IGuiIngredient; +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.recipe.VanillaRecipeCategoryUid; +import mezz.jei.api.recipe.transfer.IRecipeTransferError; +import mezz.jei.api.recipe.transfer.IRecipeTransferHandler; +import mezz.jei.transfer.RecipeTransferErrorTooltip; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Iterator; + +public class FluidPatternEncoderRecipeTransferHandler implements IRecipeTransferHandler { + + private final ExtraExtractors ext; + + public FluidPatternEncoderRecipeTransferHandler(ExtraExtractors ext) { + this.ext = ext; + } + + @Override + @Nonnull + public Class getContainerClass() { + return ContainerFluidPatternEncoder.class; + } + + @Nullable + @Override + public IRecipeTransferError transferRecipe(@Nonnull ContainerFluidPatternEncoder container, IRecipeLayout recipeLayout, + @Nonnull EntityPlayer player, boolean maxTransfer, boolean doTransfer) { + if (recipeLayout.getRecipeCategory().getUid().equals(VanillaRecipeCategoryUid.CRAFTING)) { + return new RecipeTransferErrorTooltip(I18n.format(NameConst.TT_PROCESSING_RECIPE_ONLY)); + } + if (doTransfer) { + TileFluidPatternEncoder tile = container.getTile(); + IAEItemStack[] crafting = new IAEItemStack[tile.getCraftingSlots().getSlotCount()]; + IAEItemStack[] output = new IAEItemStack[tile.getOutputSlots().getSlotCount()]; + transferRecipeSlots(recipeLayout, crafting, output, false, ext); + FluidCraft.proxy.netHandler.sendToServer(new CPacketLoadPattern(crafting, output)); + } + return null; + } + + public static void transferRecipeSlots(IRecipeLayout recipeLayout, IAEItemStack[] crafting, IAEItemStack[] output, + boolean retainEmptyInputs, ExtraExtractors ext) { + int ndxCrafting = 0, ndxOutput = 0; + for (IGuiIngredient ing : recipeLayout.getItemStacks().getGuiIngredients().values()) { + if (ing.isInput()) { + if (ndxCrafting < crafting.length) { + ItemStack stack = ing.getDisplayedIngredient(); + if (stack != null) { + crafting[ndxCrafting++] = AEItemStack.fromItemStack(stack); + } else if (retainEmptyInputs) { + crafting[ndxCrafting++] = null; + } + } + } else { + if (ndxOutput < output.length) { + ItemStack stack = ing.getDisplayedIngredient(); + if (stack != null) { + output[ndxOutput++] = AEItemStack.fromItemStack(stack); + } + } + } + } + for (IGuiIngredient ing : recipeLayout.getFluidStacks().getGuiIngredients().values()) { + if (ing.isInput()) { + if (ndxCrafting < crafting.length) { + crafting[ndxCrafting++] = ItemFluidPacket.newAeStack(ing.getDisplayedIngredient()); + } + } else { + if (ndxOutput < output.length) { + output[ndxOutput++] = ItemFluidPacket.newAeStack(ing.getDisplayedIngredient()); + } + } + } + Iterator> iter = ext.extractFluids(recipeLayout).iterator(); + while (iter.hasNext()) { + WrappedIngredient ing = iter.next(); + if (ing.isInput()) { + if (ndxCrafting < crafting.length) { + crafting[ndxCrafting++] = ItemFluidPacket.newAeStack(ing.getIngredient()); + } + } else { + if (ndxOutput < output.length) { + output[ndxOutput++] = ItemFluidPacket.newAeStack(ing.getIngredient()); + } + } + } + } + +} diff --git a/src/main/java/com/glodblock/github/integration/jei/FluidPatternTerminalRecipeTransferHandler.java b/src/main/java/com/glodblock/github/integration/jei/FluidPatternTerminalRecipeTransferHandler.java new file mode 100644 index 000000000..5b41dec06 --- /dev/null +++ b/src/main/java/com/glodblock/github/integration/jei/FluidPatternTerminalRecipeTransferHandler.java @@ -0,0 +1,55 @@ +package com.glodblock.github.integration.jei; + +import appeng.api.storage.data.IAEItemStack; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.container.ContainerFluidPatternTerminal; +import com.glodblock.github.common.part.PartFluidPatternTerminal; +import com.glodblock.github.network.CPacketLoadPattern; +import com.glodblock.github.util.NameConst; +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.recipe.VanillaRecipeCategoryUid; +import mezz.jei.api.recipe.transfer.IRecipeTransferError; +import mezz.jei.api.recipe.transfer.IRecipeTransferHandler; +import mezz.jei.transfer.RecipeTransferErrorTooltip; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.EntityPlayer; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class FluidPatternTerminalRecipeTransferHandler implements IRecipeTransferHandler { + + private final ExtraExtractors ext; + + FluidPatternTerminalRecipeTransferHandler(ExtraExtractors ext) { + this.ext = ext; + } + + @Override + @Nonnull + public Class getContainerClass() { + return ContainerFluidPatternTerminal.class; + } + + @Nullable + @Override + public IRecipeTransferError transferRecipe(@Nonnull ContainerFluidPatternTerminal container, @Nonnull IRecipeLayout recipeLayout, + @Nonnull EntityPlayer player, boolean maxTransfer, boolean doTransfer) { + if (container.craftingMode) { + if (!recipeLayout.getRecipeCategory().getUid().equals(VanillaRecipeCategoryUid.CRAFTING)) { + return new RecipeTransferErrorTooltip(I18n.format(NameConst.TT_CRAFTING_RECIPE_ONLY)); + } + } else if (recipeLayout.getRecipeCategory().getUid().equals(VanillaRecipeCategoryUid.CRAFTING)) { + return new RecipeTransferErrorTooltip(I18n.format(NameConst.TT_PROCESSING_RECIPE_ONLY)); + } + if (doTransfer && container.getPatternTerminal() instanceof PartFluidPatternTerminal) { + PartFluidPatternTerminal tile = (PartFluidPatternTerminal)container.getPatternTerminal(); + IAEItemStack[] crafting = new IAEItemStack[tile.getInventoryByName("crafting").getSlots()]; + IAEItemStack[] output = new IAEItemStack[tile.getInventoryByName("output").getSlots()]; + FluidPatternEncoderRecipeTransferHandler.transferRecipeSlots(recipeLayout, crafting, output, container.craftingMode, ext); + FluidCraft.proxy.netHandler.sendToServer(new CPacketLoadPattern(crafting, output)); + } + return null; + } + +} diff --git a/src/main/java/com/glodblock/github/integration/jei/ModMachHybridFluidStackExtractor.java b/src/main/java/com/glodblock/github/integration/jei/ModMachHybridFluidStackExtractor.java new file mode 100644 index 000000000..ffa75f438 --- /dev/null +++ b/src/main/java/com/glodblock/github/integration/jei/ModMachHybridFluidStackExtractor.java @@ -0,0 +1,29 @@ +package com.glodblock.github.integration.jei; + +import com.glodblock.github.integration.jei.interfaces.IngredientExtractor; +import hellfirepvp.modularmachinery.common.integration.ingredient.HybridFluid; +import mezz.jei.api.IModRegistry; +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.recipe.IIngredientType; +import net.minecraftforge.fluids.FluidStack; + +import java.util.Objects; +import java.util.stream.Stream; + +public class ModMachHybridFluidStackExtractor implements IngredientExtractor { + + private final IIngredientType ingTypeHybridFluid; + + ModMachHybridFluidStackExtractor(IModRegistry registry) { + ingTypeHybridFluid = Objects.requireNonNull(registry.getIngredientRegistry().getIngredientType(HybridFluid.class)); + } + + public Stream> extract(IRecipeLayout recipeLayout) { + return recipeLayout.getIngredientsGroup(ingTypeHybridFluid).getGuiIngredients().values().stream() + .map(ing -> { + HybridFluid hf = ing.getDisplayedIngredient(); + return new WrappedIngredient<>(hf != null ? hf.asFluidStack() : null, ing.isInput()); + }); + } + +} diff --git a/src/main/java/com/glodblock/github/integration/jei/WrappedIngredient.java b/src/main/java/com/glodblock/github/integration/jei/WrappedIngredient.java new file mode 100644 index 000000000..4d158e4ac --- /dev/null +++ b/src/main/java/com/glodblock/github/integration/jei/WrappedIngredient.java @@ -0,0 +1,25 @@ +package com.glodblock.github.integration.jei; + +import javax.annotation.Nullable; + +public class WrappedIngredient { + + @Nullable + private final T ingredient; + private final boolean isInput; + + public WrappedIngredient(@Nullable T ingredient, boolean isInput) { + this.ingredient = ingredient; + this.isInput = isInput; + } + + @Nullable + public T getIngredient() { + return ingredient; + } + + public boolean isInput() { + return isInput; + } + +} diff --git a/src/main/java/com/glodblock/github/integration/jei/interfaces/IngredientExtractor.java b/src/main/java/com/glodblock/github/integration/jei/interfaces/IngredientExtractor.java new file mode 100644 index 000000000..75347312e --- /dev/null +++ b/src/main/java/com/glodblock/github/integration/jei/interfaces/IngredientExtractor.java @@ -0,0 +1,12 @@ +package com.glodblock.github.integration.jei.interfaces; + +import com.glodblock.github.integration.jei.WrappedIngredient; +import mezz.jei.api.gui.IRecipeLayout; + +import java.util.stream.Stream; + +public interface IngredientExtractor { + + Stream> extract(IRecipeLayout recipeLayout); + +} diff --git a/src/main/java/com/glodblock/github/integration/pauto/PackagedFluidCrafting.java b/src/main/java/com/glodblock/github/integration/pauto/PackagedFluidCrafting.java new file mode 100644 index 000000000..617c6da7c --- /dev/null +++ b/src/main/java/com/glodblock/github/integration/pauto/PackagedFluidCrafting.java @@ -0,0 +1,19 @@ +package com.glodblock.github.integration.pauto; + +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import thelm.packagedauto.api.RecipeTypeRegistry; + +public class PackagedFluidCrafting { + + public static void init() { + RecipeTypeRegistry.registerRecipeType(RecipeTypeFluidProcessing.INSTANCE); + } + + @SideOnly(Side.CLIENT) + public static void initClient() { + MinecraftForge.EVENT_BUS.register(new RecipeEncoderFluidTooltipHandler()); + } + +} diff --git a/src/main/java/com/glodblock/github/integration/pauto/RecipeEncoderFluidTooltipHandler.java b/src/main/java/com/glodblock/github/integration/pauto/RecipeEncoderFluidTooltipHandler.java new file mode 100644 index 000000000..d00e95199 --- /dev/null +++ b/src/main/java/com/glodblock/github/integration/pauto/RecipeEncoderFluidTooltipHandler.java @@ -0,0 +1,34 @@ +package com.glodblock.github.integration.pauto; + +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.loader.FCItems; +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.event.entity.player.ItemTooltipEvent; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import thelm.packagedauto.client.gui.GuiEncoder; + +import java.util.List; + +public class RecipeEncoderFluidTooltipHandler { + + @SubscribeEvent(priority = EventPriority.HIGHEST) + public void onItemTooltip(ItemTooltipEvent event) { + if (Minecraft.getMinecraft().currentScreen instanceof GuiEncoder) { + ItemStack stack = event.getItemStack(); + if (stack.getItem() == FCItems.FLUID_PACKET) { + FluidStack fluid = ItemFluidPacket.getFluidStack(stack); + if (fluid != null) { + List tooltip = event.getToolTip(); + tooltip.clear(); + tooltip.add(fluid.getLocalizedName()); + tooltip.add(String.format(TextFormatting.GRAY + "%,d mB", fluid.amount)); + } + } + } + } + +} diff --git a/src/main/java/com/glodblock/github/integration/pauto/RecipeInfoFluidProcessing.java b/src/main/java/com/glodblock/github/integration/pauto/RecipeInfoFluidProcessing.java new file mode 100644 index 000000000..a23e79efa --- /dev/null +++ b/src/main/java/com/glodblock/github/integration/pauto/RecipeInfoFluidProcessing.java @@ -0,0 +1,13 @@ +package com.glodblock.github.integration.pauto; + +import thelm.packagedauto.api.IRecipeType; +import thelm.packagedauto.recipe.RecipeInfoProcessing; + +public class RecipeInfoFluidProcessing extends RecipeInfoProcessing { + + @Override + public IRecipeType getRecipeType() { + return RecipeTypeFluidProcessing.INSTANCE; + } + +} diff --git a/src/main/java/com/glodblock/github/integration/pauto/RecipeTypeFluidProcessing.java b/src/main/java/com/glodblock/github/integration/pauto/RecipeTypeFluidProcessing.java new file mode 100644 index 000000000..0ad3e602b --- /dev/null +++ b/src/main/java/com/glodblock/github/integration/pauto/RecipeTypeFluidProcessing.java @@ -0,0 +1,150 @@ +package com.glodblock.github.integration.pauto; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.integration.jei.FCJeiPlugin; +import com.glodblock.github.integration.jei.WrappedIngredient; +import com.glodblock.github.loader.FCBlocks; +import it.unimi.dsi.fastutil.ints.*; +import mezz.jei.api.gui.IGuiIngredient; +import mezz.jei.api.gui.IRecipeLayout; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.translation.I18n; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.common.Optional; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import thelm.packagedauto.api.IRecipeInfo; +import thelm.packagedauto.api.IRecipeType; +import thelm.packagedauto.integration.jei.PackagedAutoJEIPlugin; + +import java.awt.*; +import java.util.Iterator; +import java.util.List; + +public class RecipeTypeFluidProcessing implements IRecipeType { + + public static final RecipeTypeFluidProcessing INSTANCE = new RecipeTypeFluidProcessing(); + + private static final ResourceLocation NAME = FluidCraft.resource("fluid_processing"); + private static final IntSet SLOTS; + private static final Color SLOT_COLOUR = new Color(0x8B8BAC); + private static final int NUM_SLOTS_CRAFT = 81, NUM_SLOTS_OUT = 9; + + static { + IntSet slots = new IntOpenHashSet(); + for (int i = 0; i < 90; i++) { + slots.add(i); + } + SLOTS = IntSets.unmodifiable(slots); + } + + private RecipeTypeFluidProcessing() { + // NO-OP + } + + @Override + public ResourceLocation getName() { + return NAME; + } + + @SuppressWarnings("deprecation") + @Override + public String getLocalizedName() { + return I18n.translateToLocal("ae2fc.pauto.fluid_processing.name"); + } + + @SuppressWarnings("deprecation") + @Override + public String getLocalizedNameShort() { + return I18n.translateToLocal("ae2fc.pauto.fluid_processing.name_short"); + } + + @Override + public IRecipeInfo getNewRecipeInfo() { + return new RecipeInfoFluidProcessing(); + } + + @Override + public IntSet getEnabledSlots() { + return SLOTS; + } + + @Override + public boolean canSetOutput() { + return true; + } + + @Override + public boolean hasMachine() { + return false; + } + + @Override + public List getJEICategories() { + return PackagedAutoJEIPlugin.getAllRecipeCategories(); + } + + @SideOnly(Side.CLIENT) + @Override + public Object getRepresentation() { + return new ItemStack(FCBlocks.FLUID_PATTERN_ENCODER); + } + + @SideOnly(Side.CLIENT) + @Override + public Color getSlotColor(int slot) { + return SLOT_COLOUR; + } + + @Optional.Method(modid = "jei") + @Override + public Int2ObjectMap getRecipeTransferMap(IRecipeLayout recipeLayout, String category) { + Int2ObjectMap tfrs = new Int2ObjectOpenHashMap<>(); + int ndxCrafting = 0, ndxOutput = 0; + for (IGuiIngredient ing : recipeLayout.getItemStacks().getGuiIngredients().values()) { + if (ing.isInput()) { + if (ndxCrafting < NUM_SLOTS_CRAFT) { + ItemStack stack = ing.getDisplayedIngredient(); + if (stack != null) { + tfrs.put(ndxCrafting++, stack); + } + } + } else { + if (ndxOutput < NUM_SLOTS_OUT) { + ItemStack stack = ing.getDisplayedIngredient(); + if (stack != null) { + tfrs.put(NUM_SLOTS_CRAFT + ndxOutput++, stack); + } + } + } + } + for (IGuiIngredient ing : recipeLayout.getFluidStacks().getGuiIngredients().values()) { + if (ing.isInput()) { + if (ndxCrafting < NUM_SLOTS_CRAFT) { + tfrs.put(ndxCrafting++, ItemFluidPacket.newStack(ing.getDisplayedIngredient())); + } + } else { + if (ndxOutput < NUM_SLOTS_OUT) { + tfrs.put(NUM_SLOTS_CRAFT + ndxOutput++, ItemFluidPacket.newStack(ing.getDisplayedIngredient())); + } + } + } + Iterator> iter = FCJeiPlugin.getExtraExtractors().extractFluids(recipeLayout).iterator(); + while (iter.hasNext()) { + WrappedIngredient ing = iter.next(); + if (ing.isInput()) { + if (ndxCrafting < NUM_SLOTS_CRAFT) { + tfrs.put(ndxCrafting++, ItemFluidPacket.newStack(ing.getIngredient())); + } + } else { + if (ndxOutput < NUM_SLOTS_OUT) { + tfrs.put(NUM_SLOTS_CRAFT + ndxOutput++, ItemFluidPacket.newStack(ing.getIngredient())); + } + } + } + return tfrs; + } + +} diff --git a/src/main/java/com/glodblock/github/interfaces/AeStackInventory.java b/src/main/java/com/glodblock/github/interfaces/AeStackInventory.java new file mode 100644 index 000000000..bc8b01af8 --- /dev/null +++ b/src/main/java/com/glodblock/github/interfaces/AeStackInventory.java @@ -0,0 +1,19 @@ +package com.glodblock.github.interfaces; + +import appeng.api.storage.data.IAEStack; + +import javax.annotation.Nullable; +import java.util.stream.Stream; + +public interface AeStackInventory > extends Iterable { + + int getSlotCount(); + + @Nullable + T getStack(int slot); + + void setStack(int slot, @Nullable T stack); + + Stream stream(); + +} diff --git a/src/main/java/com/glodblock/github/interfaces/FCPriorityHost.java b/src/main/java/com/glodblock/github/interfaces/FCPriorityHost.java new file mode 100644 index 000000000..af5f3aefe --- /dev/null +++ b/src/main/java/com/glodblock/github/interfaces/FCPriorityHost.java @@ -0,0 +1,16 @@ +package com.glodblock.github.interfaces; + +import appeng.core.sync.GuiBridge; +import appeng.helpers.IPriorityHost; +import com.glodblock.github.inventory.GuiType; + +public interface FCPriorityHost extends IPriorityHost { + + GuiType getGuiType(); + + @Override + default GuiBridge getGuiBridge() { + return GuiBridge.GUI_Handler; + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/interfaces/HasCustomModel.java b/src/main/java/com/glodblock/github/interfaces/HasCustomModel.java new file mode 100644 index 000000000..6fab7cb3c --- /dev/null +++ b/src/main/java/com/glodblock/github/interfaces/HasCustomModel.java @@ -0,0 +1,9 @@ +package com.glodblock.github.interfaces; + +import net.minecraft.util.ResourceLocation; + +public interface HasCustomModel { + + ResourceLocation getCustomModelPath(); + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/interfaces/PatternConsumer.java b/src/main/java/com/glodblock/github/interfaces/PatternConsumer.java new file mode 100644 index 000000000..48ee01208 --- /dev/null +++ b/src/main/java/com/glodblock/github/interfaces/PatternConsumer.java @@ -0,0 +1,9 @@ +package com.glodblock.github.interfaces; + +import appeng.api.storage.data.IAEItemStack; + +public interface PatternConsumer { + + void acceptPattern(IAEItemStack[] inputs, IAEItemStack[] outputs); + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/interfaces/SlotFluid.java b/src/main/java/com/glodblock/github/interfaces/SlotFluid.java new file mode 100644 index 000000000..506ad2b24 --- /dev/null +++ b/src/main/java/com/glodblock/github/interfaces/SlotFluid.java @@ -0,0 +1,14 @@ +package com.glodblock.github.interfaces; + +import appeng.api.storage.data.IAEItemStack; + +import javax.annotation.Nullable; + +public interface SlotFluid { + + @Nullable + IAEItemStack getAeStack(); + + void setAeStack(@Nullable IAEItemStack stack, boolean sync); + +} diff --git a/src/main/java/com/glodblock/github/interfaces/TankDumpable.java b/src/main/java/com/glodblock/github/interfaces/TankDumpable.java new file mode 100644 index 000000000..97361d8d0 --- /dev/null +++ b/src/main/java/com/glodblock/github/interfaces/TankDumpable.java @@ -0,0 +1,9 @@ +package com.glodblock.github.interfaces; + +public interface TankDumpable { + + boolean canDumpTank(int index); + + void dumpTank(int index); + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/inventory/AeStackInventoryImpl.java b/src/main/java/com/glodblock/github/inventory/AeStackInventoryImpl.java new file mode 100644 index 000000000..59e669e2b --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/AeStackInventoryImpl.java @@ -0,0 +1,98 @@ +package com.glodblock.github.inventory; + +import appeng.api.storage.IStorageChannel; +import appeng.api.storage.data.IAEStack; +import appeng.util.inv.IAEAppEngInventory; +import com.glodblock.github.interfaces.AeStackInventory; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.Constants; +import org.apache.logging.log4j.core.util.ObjectArrayIterator; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Iterator; +import java.util.stream.Stream; + +public class AeStackInventoryImpl > implements AeStackInventory { + + private final IStorageChannel channel; + private final T[] inv; + @Nullable + private final IAEAppEngInventory owner; + + @SuppressWarnings("unchecked") + public AeStackInventoryImpl(IStorageChannel channel, int slotCount, @Nullable IAEAppEngInventory owner) { + this.channel = channel; + this.inv = (T[])new IAEStack[slotCount]; + this.owner = owner; + } + + public AeStackInventoryImpl(IStorageChannel channel, int slotCount) { + this(channel, slotCount, null); + } + + @Override + public int getSlotCount() { + return inv.length; + } + + @Override + @Nullable + public T getStack(int slot) { + return inv[slot]; + } + + @Override + public void setStack(int slot, @Nullable T stack) { + inv[slot] = stack; + if (owner != null) { + owner.saveChanges(); + } + } + + @Override + @Nonnull + public Iterator iterator() { + return new ObjectArrayIterator<>(inv); + } + + @Override + public Stream stream() { + return Arrays.stream(inv); + } + + public void writeToNbt(NBTTagCompound tag) { + NBTTagList stacksTag = new NBTTagList(); + for (T stack : inv) { + if (stack == null) { + stacksTag.appendTag(new NBTTagCompound()); + } else { + NBTTagCompound stackTag = new NBTTagCompound(); + stack.writeToNBT(stackTag); + stacksTag.appendTag(stackTag); + } + } + tag.setTag("Contents", stacksTag); + } + + public void writeToNbt(NBTTagCompound parentTag, String key) { + NBTTagCompound tag = new NBTTagCompound(); + writeToNbt(tag); + parentTag.setTag(key, tag); + } + + public void readFromNbt(NBTTagCompound tag) { + NBTTagList stacksTag = tag.getTagList("Contents", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < inv.length; i++) { + NBTTagCompound stackTag = stacksTag.getCompoundTagAt(i); + inv[i] = stackTag.isEmpty() ? null : channel.createFromNBT(stackTag); + } + } + + public void readFromNbt(NBTTagCompound parentTag, String key) { + readFromNbt(parentTag.getCompoundTag(key)); + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryAdaptor.java b/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryAdaptor.java new file mode 100644 index 000000000..f463f6479 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryAdaptor.java @@ -0,0 +1,166 @@ +package com.glodblock.github.inventory; + +import appeng.api.config.FuzzyMode; +import appeng.util.InventoryAdaptor; +import appeng.util.inv.AdaptorItemHandler; +import appeng.util.inv.IInventoryDestination; +import appeng.util.inv.ItemSlot; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.util.Ae2Reflect; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidTankProperties; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.Iterator; +import java.util.Objects; + +public class FluidConvertingInventoryAdaptor extends InventoryAdaptor { + + public static FluidConvertingInventoryAdaptor wrap(ICapabilityProvider capProvider, EnumFacing face) { + // sometimes i wish i had the monadic version from 1.15 + return new FluidConvertingInventoryAdaptor( + capProvider.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, face) + ? Objects.requireNonNull(capProvider.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, face)) + : null, + capProvider.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, face) + ? Objects.requireNonNull(capProvider.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, face)) + : null); + } + + @Nullable + private final InventoryAdaptor invItems; + @Nullable + private final IFluidHandler invFluids; + + public FluidConvertingInventoryAdaptor(@Nullable IItemHandler invItems, @Nullable IFluidHandler invFluids) { + this.invItems = invItems != null ? new AdaptorItemHandler(invItems) : null; + this.invFluids = invFluids; + } + + @Override + public ItemStack addItems(ItemStack toBeAdded) { + if (toBeAdded.getItem() instanceof ItemFluidPacket) { + if (invFluids != null) { + FluidStack fluid = ItemFluidPacket.getFluidStack(toBeAdded); + if (fluid != null) { + int filled = invFluids.fill(fluid, true); + if (filled > 0) { + fluid.amount -= filled; + return ItemFluidPacket.newStack(fluid); + } + } + } + return toBeAdded; + } + return invItems != null ? invItems.addItems(toBeAdded) : toBeAdded; + } + + @Override + public ItemStack simulateAdd(ItemStack toBeSimulated) { + if (toBeSimulated.getItem() instanceof ItemFluidPacket) { + if (invFluids != null) { + FluidStack fluid = ItemFluidPacket.getFluidStack(toBeSimulated); + if (fluid != null) { + int filled = invFluids.fill(fluid, false); + if (filled > 0) { + fluid.amount -= filled; + return ItemFluidPacket.newStack(fluid); + } + } + } + return toBeSimulated; + } + return invItems != null ? invItems.simulateAdd(toBeSimulated) : toBeSimulated; + } + + @Override + public ItemStack removeItems(int amount, ItemStack filter, IInventoryDestination destination) { + return invItems != null ? invItems.removeItems(amount, filter, destination) : ItemStack.EMPTY; + } + + @Override + public ItemStack simulateRemove(int amount, ItemStack filter, IInventoryDestination destination) { + return invItems != null ? invItems.simulateRemove(amount, filter, destination) : ItemStack.EMPTY; + } + + @Override + public ItemStack removeSimilarItems(int amount, ItemStack filter, FuzzyMode fuzzyMode, IInventoryDestination destination) { + return invItems != null ? invItems.removeSimilarItems(amount, filter, fuzzyMode, destination) : ItemStack.EMPTY; + } + + @Override + public ItemStack simulateSimilarRemove(int amount, ItemStack filter, FuzzyMode fuzzyMode, IInventoryDestination destination) { + return invItems != null ? invItems.simulateSimilarRemove(amount, filter, fuzzyMode, destination) : ItemStack.EMPTY; + } + + @Override + public boolean containsItems() { + if (invFluids != null) { + for (IFluidTankProperties tank : invFluids.getTankProperties()) { + FluidStack fluid = tank.getContents(); + if (fluid != null && fluid.amount > 0) { + return true; + } + } + } + return invItems != null && invItems.containsItems(); + } + + @Override + public boolean hasSlots() { + return (invFluids != null && invFluids.getTankProperties().length > 0) + || (invItems != null && invItems.hasSlots()); + } + + @Override + @Nonnull + public Iterator iterator() { + return new SlotIterator( + invFluids != null ? invFluids.getTankProperties() : new IFluidTankProperties[0], + invItems != null ? invItems.iterator() : Collections.emptyIterator()); + } + + private static class SlotIterator implements Iterator { + + private final IFluidTankProperties[] tanks; + private final Iterator itemSlots; + private int nextSlotIndex = 0; + + SlotIterator(IFluidTankProperties[] tanks, Iterator itemSlots) { + this.tanks = tanks; + this.itemSlots = itemSlots; + } + + @Override + public boolean hasNext() { + return nextSlotIndex < tanks.length || itemSlots.hasNext(); + } + + @Override + public ItemSlot next() { + if (nextSlotIndex < tanks.length) { + FluidStack fluid = tanks[nextSlotIndex].getContents(); + ItemSlot slot = new ItemSlot(); + slot.setSlot(nextSlotIndex++); + slot.setItemStack(fluid != null ? ItemFluidPacket.newStack(fluid) : ItemStack.EMPTY); + Ae2Reflect.setItemSlotExtractable(slot, false); + return slot; + } else { + ItemSlot slot = itemSlots.next(); + slot.setSlot(nextSlotIndex++); + return slot; + } + } + + } + +} diff --git a/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryCrafting.java b/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryCrafting.java new file mode 100644 index 000000000..f3fdb7bbf --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryCrafting.java @@ -0,0 +1,32 @@ +package com.glodblock.github.inventory; + +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +public class FluidConvertingInventoryCrafting extends InventoryCrafting { + + public FluidConvertingInventoryCrafting(Container container, int width, int height) { + super(container, width, height); + } + + @Override + public void setInventorySlotContents(int index, ItemStack stack) { + if (stack.getItem() instanceof ItemFluidDrop) { + FluidStack fluid = ItemFluidDrop.getFluidStack(stack); + if (fluid != null) { + super.setInventorySlotContents(index, ItemFluidPacket.newStack(new FluidStack(fluid, stack.getCount()))); + } else { + // wtf? + super.setInventorySlotContents(index, ItemFluidPacket.newStack(new FluidStack(FluidRegistry.WATER, 1000))); + } + } else { + super.setInventorySlotContents(index, stack); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/inventory/GuiType.java b/src/main/java/com/glodblock/github/inventory/GuiType.java new file mode 100644 index 000000000..b6d824bc4 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/GuiType.java @@ -0,0 +1,265 @@ +package com.glodblock.github.inventory; + +import appeng.api.parts.IPart; +import appeng.api.parts.IPartHost; +import appeng.api.storage.ITerminalHost; +import appeng.api.util.AEPartLocation; +import appeng.container.AEBaseContainer; +import appeng.container.ContainerOpenContext; +import appeng.container.implementations.ContainerCraftingStatus; +import appeng.container.implementations.ContainerInterface; +import appeng.container.implementations.ContainerPriority; +import appeng.fluids.container.ContainerFluidInterface; +import appeng.fluids.helper.IFluidInterfaceHost; +import appeng.helpers.IInterfaceHost; +import com.glodblock.github.client.*; +import com.glodblock.github.client.container.*; +import com.glodblock.github.common.part.PartFluidPatternTerminal; +import com.glodblock.github.common.tile.TileBurette; +import com.glodblock.github.common.tile.TileFluidPacketDecoder; +import com.glodblock.github.common.tile.TileFluidPatternEncoder; +import com.glodblock.github.common.tile.TileIngredientBuffer; +import com.glodblock.github.interfaces.FCPriorityHost; +import com.google.common.collect.ImmutableList; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import javax.annotation.Nullable; +import java.util.List; + +public enum GuiType { + + INGREDIENT_BUFFER(new TileGuiFactory(TileIngredientBuffer.class) { + @Override + protected Object createServerGui(EntityPlayer player, TileIngredientBuffer inv) { + return new ContainerIngredientBuffer(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, TileIngredientBuffer inv) { + return new GuiIngredientBuffer(player.inventory, inv); + } + }), + + FLUID_PATTERN_ENCODER(new TileGuiFactory(TileFluidPatternEncoder.class) { + @Override + protected Object createServerGui(EntityPlayer player, TileFluidPatternEncoder inv) { + return new ContainerFluidPatternEncoder(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, TileFluidPatternEncoder inv) { + return new GuiFluidPatternEncoder(player.inventory, inv); + } + }), + + FLUID_PACKET_DECODER(new TileGuiFactory(TileFluidPacketDecoder.class) { + @Override + protected Object createServerGui(EntityPlayer player, TileFluidPacketDecoder inv) { + return new ContainerFluidPacketDecoder(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, TileFluidPacketDecoder inv) { + return new GuiFluidPacketDecoder(player.inventory, inv); + } + }), + + PRECISION_BURETTE(new TileGuiFactory(TileBurette.class) { + @Override + protected Object createServerGui(EntityPlayer player, TileBurette inv) { + return new ContainerBurette(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, TileBurette inv) { + return new GuiBurette(player.inventory, inv); + } + }), + + DUAL_ITEM_INTERFACE(new PartOrTileGuiFactory(IInterfaceHost.class) { + @Override + protected Object createServerGui(EntityPlayer player, IInterfaceHost inv) { + return new ContainerInterface(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, IInterfaceHost inv) { + return new GuiItemDualInterface(player.inventory, inv); + } + }), + + DUAL_FLUID_INTERFACE(new PartOrTileGuiFactory(IFluidInterfaceHost.class) { + @Override + protected Object createServerGui(EntityPlayer player, IFluidInterfaceHost inv) { + return new ContainerFluidInterface(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, IFluidInterfaceHost inv) { + return new GuiFluidDualInterface(player.inventory, inv); + } + }), + + FLUID_PAT_TERM_CRAFTING_STATUS(new PartGuiFactory(PartFluidPatternTerminal.class) { + @Override + protected Object createServerGui(EntityPlayer player, PartFluidPatternTerminal inv) { + return new ContainerCraftingStatus(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, PartFluidPatternTerminal inv) { + return new GuiFluidPatternTerminalCraftingStatus(player.inventory, inv); + } + }), + + FLUID_PATTERN_TERMINAL(new PartGuiFactory(ITerminalHost.class) { + @Override + protected Object createServerGui(EntityPlayer player, ITerminalHost inv) { + return new ContainerFluidPatternTerminal(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, ITerminalHost inv) { + return new GuiFluidPatternTerminal(player.inventory, inv); + } + }), + + PRIORITY(new PartOrTileGuiFactory(FCPriorityHost.class) { + @Override + protected Object createServerGui(EntityPlayer player, FCPriorityHost inv) { + return new ContainerPriority(player.inventory, inv); + } + + @Override + protected Object createClientGui(EntityPlayer player, FCPriorityHost inv) { + return new GuiFCPriority(player.inventory, inv); + } + }); + + public static final List VALUES = ImmutableList.copyOf(values()); + + @Nullable + public static GuiType getByOrdinal(int ordinal) { + return ordinal < 0 || ordinal >= VALUES.size() ? null : VALUES.get(ordinal); + } + + final GuiFactory guiFactory; + + GuiType(GuiFactory guiFactory) { + this.guiFactory = guiFactory; + } + + public interface GuiFactory { + + @Nullable + Object createServerGui(EntityPlayer player, World world, int x, int y, int z, EnumFacing face); + + @SideOnly(Side.CLIENT) + @Nullable + Object createClientGui(EntityPlayer player, World world, int x, int y, int z, EnumFacing face); + + } + + private static abstract class TileGuiFactory implements GuiFactory { + + protected final Class invClass; + + TileGuiFactory(Class invClass) { + this.invClass = invClass; + } + + @Nullable + protected T getInventory(TileEntity tile, EnumFacing face) { + return invClass.isInstance(tile) ? invClass.cast(tile) : null; + } + + @Nullable + @Override + public Object createServerGui(EntityPlayer player, World world, int x, int y, int z, EnumFacing face) { + TileEntity tile = world.getTileEntity(new BlockPos(x, y, z)); + if (tile == null) { + return null; + } + T inv = getInventory(tile, face); + if (inv == null) { + return null; + } + Object gui = createServerGui(player, inv); + if (gui instanceof AEBaseContainer) { + ContainerOpenContext ctx = new ContainerOpenContext(inv); + ctx.setWorld(world); + ctx.setX(x); + ctx.setY(y); + ctx.setZ(z); + ctx.setSide(AEPartLocation.fromFacing(face)); + ((AEBaseContainer)gui).setOpenContext(ctx); + } + return gui; + } + + @Nullable + protected abstract Object createServerGui(EntityPlayer player, T inv); + + @Nullable + @Override + public Object createClientGui(EntityPlayer player, World world, int x, int y, int z, EnumFacing face) { + TileEntity tile = world.getTileEntity(new BlockPos(x, y, z)); + if (tile == null) { + return null; + } + T inv = getInventory(tile, face); + return inv != null ? createClientGui(player, inv) : null; + } + + @Nullable + protected abstract Object createClientGui(EntityPlayer player, T inv); + + } + + private static abstract class PartOrTileGuiFactory extends TileGuiFactory { + + PartOrTileGuiFactory(Class invClass) { + super(invClass); + } + + @Nullable + @Override + protected T getInventory(TileEntity tile, EnumFacing face) { + if (tile instanceof IPartHost) { + IPart part = ((IPartHost)tile).getPart(face); + if (invClass.isInstance(part)) { + return invClass.cast(part); + } + } + return super.getInventory(tile, face); + } + + } + + private static abstract class PartGuiFactory extends TileGuiFactory { + + PartGuiFactory(Class invClass) { + super(invClass); + } + + @Nullable + @Override + protected T getInventory(TileEntity tile, EnumFacing face) { + if (tile instanceof IPartHost) { + IPart part = ((IPartHost)tile).getPart(face); + if (invClass.isInstance(part)) { + return invClass.cast(part); + } + } + return null; + } + + } + +} diff --git a/src/main/java/com/glodblock/github/inventory/InventoryHandler.java b/src/main/java/com/glodblock/github/inventory/InventoryHandler.java new file mode 100644 index 000000000..4561fdb47 --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/InventoryHandler.java @@ -0,0 +1,51 @@ +package com.glodblock.github.inventory; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.network.CPacketSwitchGuis; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.network.IGuiHandler; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import javax.annotation.Nullable; + +public class InventoryHandler implements IGuiHandler { + + public static void switchGui(GuiType guiType) { + FluidCraft.proxy.netHandler.sendToServer(new CPacketSwitchGuis(guiType)); + } + + public static void openGui(EntityPlayer player, World world, BlockPos pos, EnumFacing face, GuiType guiType) { + player.openGui(FluidCraft.INSTANCE, + (guiType.ordinal() << 3) | face.ordinal(), world, pos.getX(), pos.getY(), pos.getZ()); + } + + @Nullable + @Override + public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + int faceOrd = id & 0x7; + if (faceOrd > EnumFacing.VALUES.length) { + return null; + } + EnumFacing face = EnumFacing.VALUES[faceOrd]; + GuiType type = GuiType.getByOrdinal(id >>> 3); + return type != null ? type.guiFactory.createServerGui(player, world, x, y, z, face) : null; + } + + @SideOnly(Side.CLIENT) + @Nullable + @Override + public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + int faceOrd = id & 0x7; + if (faceOrd > EnumFacing.VALUES.length) { + return null; + } + EnumFacing face = EnumFacing.VALUES[faceOrd]; + GuiType type = GuiType.getByOrdinal(id >>> 3); + return type != null ? type.guiFactory.createClientGui(player, world, x, y, z, face) : null; + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/inventory/slot/SlotSingleItem.java b/src/main/java/com/glodblock/github/inventory/slot/SlotSingleItem.java new file mode 100644 index 000000000..d0026120d --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/slot/SlotSingleItem.java @@ -0,0 +1,139 @@ +package com.glodblock.github.inventory.slot; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.items.ItemHandlerHelper; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class SlotSingleItem extends Slot { + + private final Slot delegate; + + public SlotSingleItem(Slot delegate) { + super(delegate.inventory, delegate.getSlotIndex(), delegate.xPos, delegate.yPos); + this.delegate = delegate; + } + + @Override + @Nonnull + public ItemStack getStack() { + ItemStack stack = delegate.getStack(); + return stack.isEmpty() ? ItemStack.EMPTY : ItemHandlerHelper.copyStackWithSize(stack, 1); + } + + // delegated + + @Override + public void onSlotChange(@Nonnull ItemStack p_75220_1_, @Nonnull ItemStack p_75220_2_) { + delegate.onSlotChange(p_75220_1_, p_75220_2_); + } + + @Override + @Nonnull + public ItemStack onTake(@Nonnull EntityPlayer thePlayer, @Nonnull ItemStack stack) { + return delegate.onTake(thePlayer, stack); + } + + @Override + public boolean isItemValid(@Nonnull ItemStack stack) { + return delegate.isItemValid(stack); + } + + @Override + public boolean getHasStack() { + return delegate.getHasStack(); + } + + @Override + public void putStack(@Nonnull ItemStack stack) { + delegate.putStack(stack); + } + + @Override + public void onSlotChanged() { + delegate.onSlotChanged(); + } + + @Override + public int getSlotStackLimit() { + return delegate.getSlotStackLimit(); + } + + @Override + public int getItemStackLimit(@Nonnull ItemStack stack) { + return delegate.getItemStackLimit(stack); + } + + @Override + @SideOnly(Side.CLIENT) + @Nullable + public String getSlotTexture() { + return delegate.getSlotTexture(); + } + + @Override + @Nonnull + public ItemStack decrStackSize(int amount) { + return delegate.decrStackSize(amount); + } + + @Override + public boolean isHere(@Nonnull IInventory inv, int slotIn) { + return delegate.isHere(inv, slotIn); + } + + @Override + public boolean canTakeStack(@Nonnull EntityPlayer playerIn) { + return delegate.canTakeStack(playerIn); + } + + @Override + @SideOnly(Side.CLIENT) + public boolean isEnabled() { + return delegate.isEnabled(); + } + + @Override + @SideOnly(Side.CLIENT) + @Nonnull + public ResourceLocation getBackgroundLocation() { + return delegate.getBackgroundLocation(); + } + + @Override + @SideOnly(Side.CLIENT) + public void setBackgroundLocation(@Nonnull ResourceLocation texture) { + delegate.setBackgroundLocation(texture); + } + + @Override + public void setBackgroundName(@Nullable String name) { + delegate.setBackgroundName(name); + } + + @Override + @SideOnly(Side.CLIENT) + @Nullable + public TextureAtlasSprite getBackgroundSprite() { + return delegate.getBackgroundSprite(); + } + + @Override + public int getSlotIndex() { + return delegate.getSlotIndex(); + } + + @Override + public boolean isSameInventory(@Nonnull Slot other) { + return delegate.isSameInventory(other); + } + +} diff --git a/src/main/java/com/glodblock/github/loader/ChannelLoader.java b/src/main/java/com/glodblock/github/loader/ChannelLoader.java new file mode 100644 index 000000000..ec3db5434 --- /dev/null +++ b/src/main/java/com/glodblock/github/loader/ChannelLoader.java @@ -0,0 +1,19 @@ +package com.glodblock.github.loader; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.network.*; +import net.minecraftforge.fml.relauncher.Side; + +public class ChannelLoader implements Runnable { + + @Override + public void run() { + int id = 0; + FluidCraft.proxy.netHandler.registerMessage(new CPacketSwitchGuis.Handler(), CPacketSwitchGuis.class, id ++, Side.SERVER); + FluidCraft.proxy.netHandler.registerMessage(new CPacketDumpTank.Handler(), CPacketDumpTank.class, id ++, Side.SERVER); + FluidCraft.proxy.netHandler.registerMessage(new CPacketTransposeFluid.Handler(), CPacketTransposeFluid.class, id ++, Side.SERVER); + FluidCraft.proxy.netHandler.registerMessage(new CPacketEncodePattern.Handler(), CPacketEncodePattern.class, id ++, Side.SERVER); + FluidCraft.proxy.netHandler.registerMessage(new CPacketLoadPattern.Handler(), CPacketLoadPattern.class, id ++, Side.SERVER); + } + +} diff --git a/src/main/java/com/glodblock/github/loader/FCBlocks.java b/src/main/java/com/glodblock/github/loader/FCBlocks.java new file mode 100644 index 000000000..14fde4b5d --- /dev/null +++ b/src/main/java/com/glodblock/github/loader/FCBlocks.java @@ -0,0 +1,33 @@ +package com.glodblock.github.loader; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.common.block.*; +import com.glodblock.github.handler.RegistryHandler; +import com.glodblock.github.util.NameConst; +import net.minecraftforge.fml.common.registry.GameRegistry; + +public class FCBlocks { + + @GameRegistry.ObjectHolder(FluidCraft.MODID + ":" + NameConst.BLOCK_FLUID_DISCRETIZER) + public static BlockFluidDiscretizer FLUID_DISCRETIZER; + @GameRegistry.ObjectHolder(FluidCraft.MODID + ":" + NameConst.BLOCK_FLUID_PATTERN_ENCODER) + public static BlockFluidPatternEncoder FLUID_PATTERN_ENCODER; + @GameRegistry.ObjectHolder(FluidCraft.MODID + ":" + NameConst.BLOCK_FLUID_PACKET_DECODER) + public static BlockFluidPacketDecoder FLUID_PACKET_DECODER; + @GameRegistry.ObjectHolder(FluidCraft.MODID + ":" + NameConst.BLOCK_INGREDIENT_BUFFER) + public static BlockIngredientBuffer INGREDIENT_BUFFER; + @GameRegistry.ObjectHolder(FluidCraft.MODID + ":" + NameConst.BLOCK_BURETTE) + public static BlockBurette BURETTE; + @GameRegistry.ObjectHolder(FluidCraft.MODID + ":" + NameConst.BLOCK_DUAL_INTERFACE) + public static BlockDualInterface DUAL_INTERFACE; + + public static void init(RegistryHandler regHandler) { + regHandler.block(NameConst.BLOCK_FLUID_DISCRETIZER, new BlockFluidDiscretizer()); + regHandler.block(NameConst.BLOCK_FLUID_PATTERN_ENCODER, new BlockFluidPatternEncoder()); + regHandler.block(NameConst.BLOCK_FLUID_PACKET_DECODER, new BlockFluidPacketDecoder()); + regHandler.block(NameConst.BLOCK_INGREDIENT_BUFFER, new BlockIngredientBuffer()); + regHandler.block(NameConst.BLOCK_BURETTE, new BlockBurette()); + regHandler.block(NameConst.BLOCK_DUAL_INTERFACE, new BlockDualInterface()); + } + +} diff --git a/src/main/java/com/glodblock/github/loader/FCItems.java b/src/main/java/com/glodblock/github/loader/FCItems.java new file mode 100644 index 000000000..db116d350 --- /dev/null +++ b/src/main/java/com/glodblock/github/loader/FCItems.java @@ -0,0 +1,39 @@ +package com.glodblock.github.loader; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.common.item.*; +import com.glodblock.github.handler.RegistryHandler; +import com.glodblock.github.util.NameConst; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fml.common.registry.GameRegistry; + +public class FCItems { + + public static final CreativeTabs TAB_AE2FC = new CreativeTabs(FluidCraft.MODID) { + @Override + public ItemStack createIcon() { + return new ItemStack(DENSE_ENCODED_PATTERN); + } + }; + + @GameRegistry.ObjectHolder(FluidCraft.MODID + ":" + NameConst.ITEM_FLUID_DROP) + public static ItemFluidDrop FLUID_DROP; + @GameRegistry.ObjectHolder(FluidCraft.MODID + ":" + NameConst.ITEM_FLUID_PACKET) + public static ItemFluidPacket FLUID_PACKET; + @GameRegistry.ObjectHolder(FluidCraft.MODID + ":" + NameConst.ITEM_DENSE_ENCODED_PATTERN) + public static ItemFluidEncodedPattern DENSE_ENCODED_PATTERN; + @GameRegistry.ObjectHolder(FluidCraft.MODID + ":" + NameConst.ITEM_PART_DUAL_INTERFACE) + public static ItemPartDualInterface PART_DUAL_INTERFACE; + @GameRegistry.ObjectHolder(FluidCraft.MODID + ":" + NameConst.ITEM_PART_FLUID_PATTERN_TERMINAL) + public static ItemPartFluidPatternTerminal PART_FLUID_PATTERN_TERMINAL; + + public static void init(RegistryHandler regHandler) { + regHandler.item(NameConst.ITEM_FLUID_DROP, new ItemFluidDrop()); + regHandler.item(NameConst.ITEM_FLUID_PACKET, new ItemFluidPacket()); + regHandler.item(NameConst.ITEM_DENSE_ENCODED_PATTERN, new ItemFluidEncodedPattern()); + regHandler.item(NameConst.ITEM_PART_DUAL_INTERFACE, new ItemPartDualInterface()); + regHandler.item(NameConst.ITEM_PART_FLUID_PATTERN_TERMINAL, new ItemPartFluidPatternTerminal()); + } + +} diff --git a/src/main/java/com/glodblock/github/network/CPacketDumpTank.java b/src/main/java/com/glodblock/github/network/CPacketDumpTank.java new file mode 100644 index 000000000..4a4962daa --- /dev/null +++ b/src/main/java/com/glodblock/github/network/CPacketDumpTank.java @@ -0,0 +1,50 @@ +package com.glodblock.github.network; + +import com.glodblock.github.interfaces.TankDumpable; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +import javax.annotation.Nullable; + +public class CPacketDumpTank implements IMessage { + + private int index; + + public CPacketDumpTank(int index) { + this.index = index; + } + + public CPacketDumpTank() { + // NO-OP + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeShort(index); + } + + @Override + public void fromBytes(ByteBuf buf) { + index = buf.readShort(); + } + + public static class Handler implements IMessageHandler { + + @Nullable + @Override + public IMessage onMessage(CPacketDumpTank message, MessageContext ctx) { + EntityPlayerMP player = ctx.getServerHandler().player; + player.getServerWorld().addScheduledTask(() -> { + if (player.openContainer instanceof TankDumpable) { + ((TankDumpable)player.openContainer).dumpTank(message.index); + } + }); + return null; + } + + } + +} diff --git a/src/main/java/com/glodblock/github/network/CPacketEncodePattern.java b/src/main/java/com/glodblock/github/network/CPacketEncodePattern.java new file mode 100644 index 000000000..56e083efa --- /dev/null +++ b/src/main/java/com/glodblock/github/network/CPacketEncodePattern.java @@ -0,0 +1,40 @@ +package com.glodblock.github.network; + +import com.glodblock.github.client.container.ContainerFluidPatternEncoder; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +import javax.annotation.Nullable; + +public class CPacketEncodePattern implements IMessage { + + @Override + public void toBytes(ByteBuf buf) { + // NO-OP + } + + @Override + public void fromBytes(ByteBuf buf) { + // NO-OP + } + + public static class Handler implements IMessageHandler { + + @Nullable + @Override + public IMessage onMessage(CPacketEncodePattern message, MessageContext ctx) { + EntityPlayerMP player = ctx.getServerHandler().player; + player.getServerWorld().addScheduledTask(() -> { + if (player.openContainer instanceof ContainerFluidPatternEncoder) { + ((ContainerFluidPatternEncoder)player.openContainer).encodePattern(); + } + }); + return null; + } + + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/network/CPacketLoadPattern.java b/src/main/java/com/glodblock/github/network/CPacketLoadPattern.java new file mode 100644 index 000000000..b0a04c4dd --- /dev/null +++ b/src/main/java/com/glodblock/github/network/CPacketLoadPattern.java @@ -0,0 +1,87 @@ +package com.glodblock.github.network; + +import appeng.api.storage.data.IAEItemStack; +import appeng.util.item.AEItemStack; +import com.glodblock.github.interfaces.PatternConsumer; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +import javax.annotation.Nullable; +import java.io.IOException; + +public class CPacketLoadPattern implements IMessage { + + private IAEItemStack[] crafting, output; + + public CPacketLoadPattern(IAEItemStack[] crafting, IAEItemStack[] output) { + this.crafting = crafting; + this.output = output; + } + + public CPacketLoadPattern() { + // NO-OP + } + + @Override + public void toBytes(ByteBuf buf) { + writeStacksWithNulls(buf, crafting); + writeStacksWithNulls(buf, output); + } + + @Override + public void fromBytes(ByteBuf buf) { + crafting = readStacksWithNulls(buf); + output = readStacksWithNulls(buf); + } + + private static IAEItemStack[] readStacksWithNulls(ByteBuf buf) { + IAEItemStack[] stacks = new IAEItemStack[buf.readByte()]; + int mask = buf.readInt(); + for (int i = 0; i < stacks.length; i++) { + if ((mask & (1 << i)) != 0) { + stacks[i] = AEItemStack.fromPacket(buf); + } + } + return stacks; + } + + private static void writeStacksWithNulls(ByteBuf buf, IAEItemStack[] stacks) { + buf.writeByte(stacks.length); + int mask = 0; + for (int i = 0; i < stacks.length; i++) { + if (stacks[i] != null) { + mask |= 1 << i; + } + } + buf.writeInt(mask); + for (IAEItemStack stack : stacks) { + try { + if (stack != null) { + stack.writeToPacket(buf); + } + } catch (IOException e) { + throw new IllegalStateException("Failed to write AE item stack!", e); + } + } + } + + public static class Handler implements IMessageHandler { + + @Nullable + @Override + public IMessage onMessage(CPacketLoadPattern message, MessageContext ctx) { + EntityPlayerMP player = ctx.getServerHandler().player; + player.getServerWorld().addScheduledTask(() -> { + if (player.openContainer instanceof PatternConsumer) { + ((PatternConsumer)player.openContainer).acceptPattern(message.crafting, message.output); + } + }); + return null; + } + + } + +} diff --git a/src/main/java/com/glodblock/github/network/CPacketSwitchGuis.java b/src/main/java/com/glodblock/github/network/CPacketSwitchGuis.java new file mode 100644 index 000000000..6aec08dab --- /dev/null +++ b/src/main/java/com/glodblock/github/network/CPacketSwitchGuis.java @@ -0,0 +1,64 @@ +package com.glodblock.github.network; + +import appeng.container.AEBaseContainer; +import appeng.container.ContainerOpenContext; +import com.glodblock.github.inventory.GuiType; +import com.glodblock.github.inventory.InventoryHandler; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.Container; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +import javax.annotation.Nullable; + +public class CPacketSwitchGuis implements IMessage { + + private GuiType guiType; + + public CPacketSwitchGuis(GuiType guiType) { + this.guiType = guiType; + } + + public CPacketSwitchGuis() { + // NO-OP + } + + @Override + public void fromBytes(ByteBuf byteBuf) { + guiType = GuiType.getByOrdinal(byteBuf.readByte()); + } + + @Override + public void toBytes(ByteBuf byteBuf) { + byteBuf.writeByte(guiType != null ? guiType.ordinal() : 0); + } + + public static class Handler implements IMessageHandler { + @Nullable + @Override + public IMessage onMessage(CPacketSwitchGuis message, MessageContext ctx) { + if (message.guiType == null) { + return null; + } + EntityPlayerMP player = ctx.getServerHandler().player; + Container cont = player.openContainer; + if (!(cont instanceof AEBaseContainer)) { + return null; + } + ContainerOpenContext context = ((AEBaseContainer)cont).getOpenContext(); + if (context == null) { + return null; + } + TileEntity te = context.getTile(); + if (te == null) { + return null; + } + InventoryHandler.openGui(player, player.world, te.getPos(), context.getSide().getFacing(), message.guiType); + return null; + } + + } +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/network/CPacketTransposeFluid.java b/src/main/java/com/glodblock/github/network/CPacketTransposeFluid.java new file mode 100644 index 000000000..dbafb30f3 --- /dev/null +++ b/src/main/java/com/glodblock/github/network/CPacketTransposeFluid.java @@ -0,0 +1,53 @@ +package com.glodblock.github.network; + +import com.glodblock.github.client.container.ContainerBurette; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +import javax.annotation.Nullable; + +public class CPacketTransposeFluid implements IMessage { + + private int amount; + private boolean into; + + public CPacketTransposeFluid(int amount, boolean into) { + this.amount = amount; + this.into = into; + } + + public CPacketTransposeFluid() { + // NO-OP + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeInt(amount).writeBoolean(into); + } + + @Override + public void fromBytes(ByteBuf buf) { + amount = buf.readInt(); + into = buf.readBoolean(); + } + + public static class Handler implements IMessageHandler { + + @Nullable + @Override + public IMessage onMessage(CPacketTransposeFluid message, MessageContext ctx) { + EntityPlayerMP player = ctx.getServerHandler().player; + player.getServerWorld().addScheduledTask(() -> { + if (player.openContainer instanceof ContainerBurette) { + ((ContainerBurette)player.openContainer).tryTransferFluid(message.amount, message.into); + } + }); + return null; + } + + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/proxy/ClientProxy.java b/src/main/java/com/glodblock/github/proxy/ClientProxy.java new file mode 100644 index 000000000..873e15589 --- /dev/null +++ b/src/main/java/com/glodblock/github/proxy/ClientProxy.java @@ -0,0 +1,66 @@ +package com.glodblock.github.proxy; + +import appeng.api.util.AEColor; +import com.glodblock.github.client.render.DropColourHandler; +import com.glodblock.github.client.render.RenderIngredientBuffer; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.common.tile.TileIngredientBuffer; +import com.glodblock.github.handler.ClientRegistryHandler; +import com.glodblock.github.handler.RegistryHandler; +import com.glodblock.github.integration.pauto.PackagedFluidCrafting; +import com.glodblock.github.loader.FCItems; +import net.minecraft.client.Minecraft; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.client.registry.ClientRegistry; +import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; + +public class ClientProxy extends CommonProxy { + + private final DropColourHandler dropColourHandler = new DropColourHandler(); + + @Override + public RegistryHandler createRegistryHandler() { + return new ClientRegistryHandler(); + } + + @Override + public void preInit(FMLPreInitializationEvent event){ + super.preInit(event); + MinecraftForge.EVENT_BUS.register(dropColourHandler); + ClientRegistry.bindTileEntitySpecialRenderer(TileIngredientBuffer.class, new RenderIngredientBuffer()); + } + + @Override + protected void initPackagedAutoIntegration() { + super.initPackagedAutoIntegration(); + PackagedFluidCrafting.initClient(); + } + + @Override + public void init(FMLInitializationEvent event){ + super.init(event); + Minecraft.getMinecraft().getItemColors().registerItemColorHandler((s, i) -> { + FluidStack fluid = ItemFluidDrop.getFluidStack(s); + return fluid != null ? dropColourHandler.getColour(fluid) : -1; + }, FCItems.FLUID_DROP); + Minecraft.getMinecraft().getItemColors().registerItemColorHandler((s, i) -> { + if (i == 0) { + return -1; + } + FluidStack fluid = ItemFluidPacket.getFluidStack(s); + return fluid != null ? fluid.getFluid().getColor(fluid) : -1; + }, FCItems.FLUID_PACKET); + Minecraft.getMinecraft().getItemColors().registerItemColorHandler((s, i) -> AEColor.TRANSPARENT.getVariantByTintIndex(i), FCItems.PART_FLUID_PATTERN_TERMINAL); + + } + + @Override + public void postInit(FMLPostInitializationEvent event){ + super.postInit(event); + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/proxy/CommonProxy.java b/src/main/java/com/glodblock/github/proxy/CommonProxy.java new file mode 100644 index 000000000..ea0dde14d --- /dev/null +++ b/src/main/java/com/glodblock/github/proxy/CommonProxy.java @@ -0,0 +1,86 @@ +package com.glodblock.github.proxy; + +import appeng.api.AEApi; +import appeng.api.definitions.IItemDefinition; +import appeng.core.AppEng; +import appeng.core.features.ItemDefinition; +import appeng.recipes.game.DisassembleRecipe; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.common.tile.*; +import com.glodblock.github.handler.RegistryHandler; +import com.glodblock.github.integration.pauto.PackagedFluidCrafting; +import com.glodblock.github.inventory.InventoryHandler; +import com.glodblock.github.loader.ChannelLoader; +import com.glodblock.github.loader.FCBlocks; +import com.glodblock.github.loader.FCItems; +import com.glodblock.github.util.Ae2Reflect; +import com.glodblock.github.util.ModAndClassUtil; +import com.glodblock.github.util.NameConst; +import net.minecraft.item.Item; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.common.network.NetworkRegistry; +import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper; +import net.minecraftforge.fml.common.registry.ForgeRegistries; +import net.minecraftforge.fml.common.registry.GameRegistry; +import net.minecraftforge.fml.relauncher.Side; + +import java.util.Objects; + +public class CommonProxy { + + public final RegistryHandler regHandler = createRegistryHandler(); + public final SimpleNetworkWrapper netHandler = NetworkRegistry.INSTANCE.newSimpleChannel(FluidCraft.MODID); + + public RegistryHandler createRegistryHandler() { + return new RegistryHandler(); + } + + public void preInit(FMLPreInitializationEvent event) { + MinecraftForge.EVENT_BUS.register(regHandler); + FCBlocks.init(regHandler); + FCItems.init(regHandler); + GameRegistry.registerTileEntity(TileFluidDiscretizer.class, FluidCraft.resource(NameConst.BLOCK_FLUID_DISCRETIZER)); + GameRegistry.registerTileEntity(TileFluidPatternEncoder.class, FluidCraft.resource(NameConst.BLOCK_FLUID_PATTERN_ENCODER)); + GameRegistry.registerTileEntity(TileFluidPacketDecoder.class, FluidCraft.resource(NameConst.BLOCK_FLUID_PACKET_DECODER)); + GameRegistry.registerTileEntity(TileIngredientBuffer.class, FluidCraft.resource(NameConst.BLOCK_INGREDIENT_BUFFER)); + GameRegistry.registerTileEntity(TileBurette.class, FluidCraft.resource(NameConst.BLOCK_BURETTE)); + GameRegistry.registerTileEntity(TileDualInterface.class, FluidCraft.resource(NameConst.BLOCK_DUAL_INTERFACE)); + (new ChannelLoader()).run(); + if (ModAndClassUtil.AUTO_P) { + initPackagedAutoIntegration(); + } + } + + protected void initPackagedAutoIntegration() { + PackagedFluidCrafting.init(); + } + + public void init(FMLInitializationEvent event) { + regHandler.onInit(); + IRecipe disassembleRecipe = ForgeRegistries.RECIPES.getValue(new ResourceLocation(AppEng.MOD_ID, "disassemble")); + if (disassembleRecipe instanceof DisassembleRecipe) { + Ae2Reflect.getDisassemblyNonCellMap((DisassembleRecipe)disassembleRecipe).put( + createItemDefn(FCItems.DENSE_ENCODED_PATTERN), + AEApi.instance().definitions().materials().blankPattern()); + } + } + + public void postInit(FMLPostInitializationEvent event) { + NetworkRegistry.INSTANCE.registerGuiHandler(FluidCraft.INSTANCE, new InventoryHandler()); + } + + private static IItemDefinition createItemDefn(Item item) { + return new ItemDefinition(Objects.requireNonNull(item.getRegistryName()).toString(), item); + } + + public SimpleNetworkWrapper getNetHandler() { + return netHandler; + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/util/Ae2Reflect.java b/src/main/java/com/glodblock/github/util/Ae2Reflect.java new file mode 100644 index 000000000..ed01916fa --- /dev/null +++ b/src/main/java/com/glodblock/github/util/Ae2Reflect.java @@ -0,0 +1,112 @@ +package com.glodblock.github.util; + +import appeng.api.definitions.IItemDefinition; +import appeng.container.implementations.ContainerPatternTerm; +import appeng.container.slot.OptionalSlotFake; +import appeng.container.slot.SlotFakeCraftingMatrix; +import appeng.container.slot.SlotRestrictedInput; +import appeng.recipes.game.DisassembleRecipe; +import appeng.util.inv.ItemSlot; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.InventoryCrafting; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Map; + +public class Ae2Reflect { + + private static final Method mItemSlot_setExtractable; + private static final Field fDisassembleRecipe_nonCellMappings; + private static final Field fContainerPatternTerm_craftingSlots; + private static final Field fContainerPatternTerm_outputSlots; + private static final Field fContainerPatternTerm_patternSlotIN; + private static final Field fContainerPatternTerm_patternSlotOUT; + private static final Field fInventory_container; + + static { + try { + mItemSlot_setExtractable = reflectMethod(ItemSlot.class, "setExtractable", boolean.class); + fInventory_container = reflectField(InventoryCrafting.class, "eventHandler", "field_70465_c", "c"); + fDisassembleRecipe_nonCellMappings = reflectField(DisassembleRecipe.class, "nonCellMappings"); + fContainerPatternTerm_craftingSlots = reflectField(ContainerPatternTerm.class, "craftingSlots"); + fContainerPatternTerm_outputSlots = reflectField(ContainerPatternTerm.class, "outputSlots"); + fContainerPatternTerm_patternSlotIN = reflectField(ContainerPatternTerm.class, "patternSlotIN"); + fContainerPatternTerm_patternSlotOUT = reflectField(ContainerPatternTerm.class, "patternSlotOUT"); + } catch (Exception e) { + throw new IllegalStateException("Failed to initialize AE2 reflection hacks!", e); + } + } + + public static Method reflectMethod(Class owner, String name, Class... paramTypes) throws NoSuchMethodException { + Method m = owner.getDeclaredMethod(name, paramTypes); + m.setAccessible(true); + return m; + } + + public static Field reflectField(Class owner, String ...names) throws NoSuchFieldException { + Field f = null; + for (String name : names) { + try { + f = owner.getDeclaredField(name); + if (f != null) break; + } + catch (NoSuchFieldException ignore) { + } + } + if (f == null) throw new NoSuchFieldException("Can't find field from " + Arrays.toString(names)); + f.setAccessible(true); + return f; + } + + @SuppressWarnings("unchecked") + public static T readField(Object owner, Field field) { + try { + return (T)field.get(owner); + } catch (Exception e) { + throw new IllegalStateException("Failed to read field: " + field); + } + } + + public static void writeField(Object owner, Field field, Object value) { + try { + field.set(owner, value); + } catch (Exception e) { + throw new IllegalStateException("Failed to write field: " + field); + } + } + + public static Container getCraftContainer(InventoryCrafting inv) { + return Ae2Reflect.readField(inv, fInventory_container); + } + + public static void setItemSlotExtractable(ItemSlot slot, boolean extractable) { + try { + mItemSlot_setExtractable.invoke(slot, extractable); + } catch (Exception e) { + throw new IllegalStateException("Failed to invoke method: " + mItemSlot_setExtractable, e); + } + } + + public static Map getDisassemblyNonCellMap(DisassembleRecipe recipe) { + return readField(recipe, fDisassembleRecipe_nonCellMappings); + } + + public static SlotFakeCraftingMatrix[] getCraftingSlots(ContainerPatternTerm cont) { + return readField(cont, fContainerPatternTerm_craftingSlots); + } + + public static OptionalSlotFake[] getOutputSlots(ContainerPatternTerm cont) { + return readField(cont, fContainerPatternTerm_outputSlots); + } + + public static SlotRestrictedInput getPatternSlotIn(ContainerPatternTerm cont) { + return readField(cont, fContainerPatternTerm_patternSlotIN); + } + + public static SlotRestrictedInput getPatternSlotOut(ContainerPatternTerm cont) { + return readField(cont, fContainerPatternTerm_patternSlotOUT); + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/util/Ae2ReflectClient.java b/src/main/java/com/glodblock/github/util/Ae2ReflectClient.java new file mode 100644 index 000000000..2d6078a46 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/Ae2ReflectClient.java @@ -0,0 +1,90 @@ +package com.glodblock.github.util; + +import appeng.client.gui.AEBaseGui; +import appeng.client.gui.implementations.*; +import appeng.client.gui.widgets.GuiTabButton; +import appeng.client.render.StackSizeRenderer; +import appeng.fluids.client.gui.GuiFluidInterface; +import com.glodblock.github.client.container.ContainerFluidPatternTerminal; +import com.google.common.collect.ImmutableMap; +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.block.model.ItemCameraTransforms; +import net.minecraftforge.common.model.TRSRTransformation; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; + +@SuppressWarnings("unchecked") +public class Ae2ReflectClient { + + private static final Field fAEBaseGui_stackSizeRenderer; + private static final Constructor cItemEncodedPatternBakedModel; + private static final Field fGuiPriority_originalGuiBtn; + private static final Field fGuiCraftingStatus_originalGuiBtn; + private static final Field fGuiPatternTerm_container; + private static final Field fGuiMEMonitorable_monitorableContainer; + private static final Field fGuiMEMonitorable_configSrc; + private static final Field fGuiMEMonitorable_craftingStatusBtn; + private static final Field fGuiInterface_priority; + private static final Field fGuiFluidInterface_priority; + + static { + try { + fAEBaseGui_stackSizeRenderer = Ae2Reflect.reflectField(AEBaseGui.class, "stackSizeRenderer"); + cItemEncodedPatternBakedModel = (Constructor)Class + .forName("appeng.client.render.crafting.ItemEncodedPatternBakedModel") + .getDeclaredConstructor(IBakedModel.class, ImmutableMap.class); + cItemEncodedPatternBakedModel.setAccessible(true); + fGuiPriority_originalGuiBtn = Ae2Reflect.reflectField(GuiPriority.class, "originalGuiBtn"); + fGuiCraftingStatus_originalGuiBtn = Ae2Reflect.reflectField(GuiCraftingStatus.class, "originalGuiBtn"); + fGuiPatternTerm_container = Ae2Reflect.reflectField(GuiPatternTerm.class, "container"); + fGuiMEMonitorable_monitorableContainer = Ae2Reflect.reflectField(GuiMEMonitorable.class, "monitorableContainer"); + fGuiMEMonitorable_configSrc = Ae2Reflect.reflectField(GuiMEMonitorable.class, "configSrc"); + fGuiMEMonitorable_craftingStatusBtn = Ae2Reflect.reflectField(GuiMEMonitorable.class, "craftingStatusBtn"); + fGuiInterface_priority = Ae2Reflect.reflectField(GuiInterface.class, "priority"); + fGuiFluidInterface_priority = Ae2Reflect.reflectField(GuiFluidInterface.class, "priority"); + } catch (Exception e) { + throw new IllegalStateException("Failed to initialize AE2 reflection hacks!", e); + } + } + + public static StackSizeRenderer getStackSizeRenderer(AEBaseGui gui) { + return Ae2Reflect.readField(gui, fAEBaseGui_stackSizeRenderer); + } + + public static IBakedModel bakeEncodedPatternModel(IBakedModel baseModel, + ImmutableMap transforms) { + try { + return cItemEncodedPatternBakedModel.newInstance(baseModel, transforms); + } catch (Exception e) { + throw new IllegalStateException("Failed to invoke constructor: " + cItemEncodedPatternBakedModel, e); + } + } + + public static GuiTabButton getOriginalGuiButton(GuiPriority gui) { + return Ae2Reflect.readField(gui, fGuiPriority_originalGuiBtn); + } + + public static GuiTabButton getOriginalGuiButton(GuiCraftingStatus gui) { + return Ae2Reflect.readField(gui, fGuiCraftingStatus_originalGuiBtn); + } + + public static void setGuiContainer(GuiPatternTerm instance, ContainerFluidPatternTerminal container) { + Ae2Reflect.writeField(instance, fGuiPatternTerm_container, container); + Ae2Reflect.writeField(instance, fGuiMEMonitorable_monitorableContainer, container); + Ae2Reflect.writeField(instance, fGuiMEMonitorable_configSrc, container.getConfigManager()); + } + + public static GuiTabButton getCraftingStatusButton(GuiMEMonitorable gui) { + return Ae2Reflect.readField(gui, fGuiMEMonitorable_craftingStatusBtn); + } + + public static GuiTabButton getPriorityButton(GuiInterface gui) { + return Ae2Reflect.readField(gui, fGuiInterface_priority); + } + + public static GuiTabButton getPriorityButton(GuiFluidInterface gui) { + return Ae2Reflect.readField(gui, fGuiFluidInterface_priority); + } + +} diff --git a/src/main/java/com/glodblock/github/util/FluidKey.java b/src/main/java/com/glodblock/github/util/FluidKey.java new file mode 100644 index 000000000..f09dbc390 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/FluidKey.java @@ -0,0 +1,38 @@ +package com.glodblock.github.util; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; + +import javax.annotation.Nullable; +import java.util.Objects; + +public class FluidKey { + + private final Fluid fluid; + @Nullable + private final NBTTagCompound tag; + + public FluidKey(Fluid fluid, @Nullable NBTTagCompound tag) { + this.fluid = fluid; + this.tag = tag; + } + + public FluidKey(FluidStack fluid) { + this(fluid.getFluid(), fluid.tag); + } + + @Override + public int hashCode() { + return fluid.getName().hashCode() ^ (tag != null ? Integer.rotateLeft(tag.hashCode(), 17) : 0x4e6f5467); // NoTg + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof FluidKey)) { + return false; + } + return fluid.getName().equals(((FluidKey)obj).fluid.getName()) && Objects.equals(tag, ((FluidKey)obj).tag); + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/util/FluidPatternDetails.java b/src/main/java/com/glodblock/github/util/FluidPatternDetails.java new file mode 100644 index 000000000..8fdf53528 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/FluidPatternDetails.java @@ -0,0 +1,199 @@ +package com.glodblock.github.util; + +import appeng.api.networking.crafting.ICraftingPatternDetails; +import appeng.api.storage.data.IAEItemStack; +import appeng.util.item.AEItemStack; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.world.World; +import net.minecraftforge.common.util.Constants; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class FluidPatternDetails implements ICraftingPatternDetails, Comparable { + + private final ItemStack patternStack; + private IAEItemStack patternStackAe; + private IAEItemStack[] inputs = null, inputsCond = null, outputs = null, outputsCond = null; + private int priority = 0; + + public FluidPatternDetails(ItemStack stack) { + this.patternStack = stack; + this.patternStackAe = Objects.requireNonNull(AEItemStack.fromItemStack(stack)); // s2g + } + + @Override + public ItemStack getPattern() { + return patternStack; + } + + @Override + public int getPriority() { + return priority; + } + + @Override + public void setPriority(int priority) { + this.priority = priority; + } + + @Override + public boolean isCraftable() { + return false; + } + + @Override + public boolean canSubstitute() { + return false; + } + + @Override + public IAEItemStack[] getInputs() { + return checkInitialized(inputs); + } + + @Override + public IAEItemStack[] getCondensedInputs() { + return checkInitialized(inputsCond); + } + + public boolean setInputs(IAEItemStack[] inputs) { + for (IAEItemStack stack : inputs) { // see note at top of class + if (stack == null) { + return false; + } + } + IAEItemStack[] condensed = condenseStacks(inputs); + if (condensed.length == 0) { + return false; + } + this.inputs = inputs; + this.inputsCond = condensed; + return true; + } + + @Override + public IAEItemStack[] getOutputs() { + return checkInitialized(outputs); + } + + @Override + public IAEItemStack[] getCondensedOutputs() { + return checkInitialized(outputsCond); + } + + public boolean setOutputs(IAEItemStack[] outputs) { + for (IAEItemStack stack : outputs) { // see note at top of class + if (stack == null) { + return false; + } + } + IAEItemStack[] condensed = condenseStacks(outputs); + if (condensed.length == 0) { + return false; + } + this.outputs = outputs; + this.outputsCond = condensed; + return true; + } + + private static IAEItemStack[] condenseStacks(IAEItemStack[] stacks) { + // AE item stacks are equivalent iff they are of the same item type (not accounting for stack size) + // thus, it's not the semantically-correct definition of "equal" but it's useful for matching item types + Map accMap = new HashMap<>(); + for (IAEItemStack stack : stacks) { + if (stack != null) { + IAEItemStack acc = accMap.get(stack); + if (acc == null) { + accMap.put(stack, stack.copy()); + } else { + acc.add(stack); + } + } + } + return accMap.values().toArray(new IAEItemStack[0]); + } + + @Override + public ItemStack getOutput(InventoryCrafting craftingInv, World world) { + throw new IllegalStateException("Not a crafting recipe!"); + } + + @Override + public boolean isValidItemForSlot(int slotIndex, ItemStack itemStack, World world) { + throw new IllegalStateException("Not a crafting recipe!"); + } + + private static T checkInitialized(@Nullable T value) { + if (value == null) { + throw new IllegalStateException("Pattern is not initialized!"); + } + return value; + } + + @Override + public int hashCode() { + return patternStackAe.hashCode(); + } + + @Override + public boolean equals(Object obj) { + // ae2 null-checks the pattern stack here for some reason, but doesn't null-check in hashCode() + // this is inconsistent, so i've just decided to assert non-null in the constructor, which is to say that + // the pattern stack can never be null here + return obj instanceof FluidPatternDetails && patternStackAe.equals(((FluidPatternDetails)obj).patternStackAe); + } + + @Override + public int compareTo(FluidPatternDetails o) { + return Integer.compare(o.priority, this.priority); + } + + public ItemStack writeToStack() { + NBTTagCompound tag = new NBTTagCompound(); + tag.setTag("Inputs", writeStackArray(checkInitialized(inputs))); + tag.setTag("Outputs", writeStackArray(checkInitialized(outputs))); + patternStack.setTagCompound(tag); + patternStackAe = Objects.requireNonNull(AEItemStack.fromItemStack(patternStack)); + return patternStack; + } + + public static NBTTagList writeStackArray(IAEItemStack[] stacks) { + NBTTagList listTag = new NBTTagList(); + for (IAEItemStack stack : stacks) { + if (stack != null) { + // see note at top of class + NBTTagCompound stackTag = new NBTTagCompound(); + stack.writeToNBT(stackTag); + listTag.appendTag(stackTag); + } + } + return listTag; + } + + public boolean readFromStack() { + if (!patternStack.hasTagCompound()) { + return false; + } + NBTTagCompound tag = Objects.requireNonNull(patternStack.getTagCompound()); + // may be possible to enter a partially-correct state if setInputs succeeds but setOutputs failed + // but outside code should treat it as completely incorrect and not attempt to make calls + return setInputs(readStackArray(tag.getTagList("Inputs", Constants.NBT.TAG_COMPOUND), 9)) + && setOutputs(readStackArray(tag.getTagList("Outputs", Constants.NBT.TAG_COMPOUND), 3)); + } + + public static IAEItemStack[] readStackArray(NBTTagList listTag, int maxCount) { + // see note at top of class + IAEItemStack[] stacks = new IAEItemStack[Math.min(listTag.tagCount(), maxCount)]; + for (int i = 0; i < stacks.length; i++) { + stacks[i] = AEItemStack.fromNBT(listTag.getCompoundTagAt(i)); + } + return stacks; + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/util/ModAndClassUtil.java b/src/main/java/com/glodblock/github/util/ModAndClassUtil.java new file mode 100644 index 000000000..20bee1e24 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/ModAndClassUtil.java @@ -0,0 +1,15 @@ +package com.glodblock.github.util; + +import net.minecraftforge.fml.common.Loader; + +public final class ModAndClassUtil { + + public static boolean AUTO_P = false; + + public static void init() { + if (Loader.isModLoaded("packagedauto")) { + AUTO_P = true; + } + } + +} diff --git a/src/main/java/com/glodblock/github/util/MouseRegionManager.java b/src/main/java/com/glodblock/github/util/MouseRegionManager.java new file mode 100644 index 000000000..14ac897f9 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/MouseRegionManager.java @@ -0,0 +1,82 @@ +package com.glodblock.github.util; + +import net.minecraft.client.audio.PositionedSoundRecord; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.init.SoundEvents; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + +public class MouseRegionManager { + + private final GuiContainer gui; + private final List regions = new ArrayList<>(); + + public MouseRegionManager(GuiContainer gui) { + this.gui = gui; + } + + public void addRegion(int x, int y, int width, int height, Handler handler) { + regions.add(new Region(x, y, width, height, handler)); + } + + public boolean onClick(int mX, int mY, int button) { + mX -= gui.getGuiLeft(); + mY -= gui.getGuiTop(); + for (Region region : regions) { + if (region.containsMouse(mX, mY) && region.handler.onClick(button)) { + gui.mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(SoundEvents.UI_BUTTON_CLICK, 1F)); + return false; + } + } + return true; + } + + public void render(int mX, int mY) { + mX -= gui.getGuiLeft(); + mY -= gui.getGuiTop(); + for (Region region : regions) { + if (region.containsMouse(mX, mY)) { + List tooltip = region.handler.getTooltip(); + if (tooltip != null) { + gui.drawHoveringText(tooltip, mX, mY); + return; + } + } + } + } + + private static class Region { + + private final int x, y, width, height; + private final Handler handler; + + Region(int x, int y, int width, int height, Handler handler) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.handler = handler; + } + + boolean containsMouse(int mX, int mY) { + return mX >= x && mX < x + width && mY >= y && mY < y + height; + } + + } + + public interface Handler { + + @Nullable + default List getTooltip() { + return null; + } + + default boolean onClick(int button) { + return false; + } + + } + +} diff --git a/src/main/java/com/glodblock/github/util/NameConst.java b/src/main/java/com/glodblock/github/util/NameConst.java new file mode 100644 index 000000000..2cf43fa5b --- /dev/null +++ b/src/main/java/com/glodblock/github/util/NameConst.java @@ -0,0 +1,41 @@ +package com.glodblock.github.util; + +import com.glodblock.github.FluidCraft; +import net.minecraft.util.ResourceLocation; + +public final class NameConst { + + public static final String BLOCK_FLUID_DISCRETIZER = "fluid_discretizer"; + public static final String BLOCK_FLUID_PATTERN_ENCODER = "fluid_pattern_encoder"; + public static final String BLOCK_FLUID_PACKET_DECODER = "fluid_packet_decoder"; + public static final String BLOCK_INGREDIENT_BUFFER = "ingredient_buffer"; + public static final String BLOCK_BURETTE = "burette"; + public static final String BLOCK_DUAL_INTERFACE = "dual_interface"; + + public static final String ITEM_FLUID_DROP = "fluid_drop"; + public static final String ITEM_FLUID_PACKET = "fluid_packet"; + public static final String ITEM_DENSE_ENCODED_PATTERN = "dense_encoded_pattern"; + public static final String ITEM_PART_DUAL_INTERFACE = "part_dual_interface"; + public static final String ITEM_PART_FLUID_PATTERN_TERMINAL = "part_fluid_pattern_terminal"; + + public static final String TT_KEY = FluidCraft.MODID + ".tooltip."; + public static final String TT_FLUID_PACKET = TT_KEY + "fluid_packet"; + public static final String TT_INVALID_FLUID = TT_KEY + "invalid_fluid"; + public static final String TT_PROCESSING_RECIPE_ONLY = TT_KEY + "processing_recipe_only"; + public static final String TT_CRAFTING_RECIPE_ONLY = TT_KEY + "crafting_recipe_only"; + public static final String TT_ENCODE_PATTERN = TT_KEY + "encode_pattern"; + public static final String TT_EMPTY = TT_KEY + "empty"; + public static final String TT_DUMP_TANK = TT_KEY + "dump_tank"; + public static final String TT_TRANSPOSE_IN = TT_KEY + "transpose_in"; + public static final String TT_TRANSPOSE_OUT = TT_KEY + "transpose_out"; + + private static final String GUI_KEY = FluidCraft.MODID + ".gui."; + public static final String GUI_FLUID_PATTERN_ENCODER = GUI_KEY + BLOCK_FLUID_PATTERN_ENCODER; + public static final String GUI_FLUID_PACKET_DECODER = GUI_KEY + BLOCK_FLUID_PACKET_DECODER; + public static final String GUI_INGREDIENT_BUFFER = GUI_KEY + BLOCK_INGREDIENT_BUFFER; + public static final String GUI_BURETTE = GUI_KEY + BLOCK_BURETTE; + + public static final ResourceLocation MODEL_DENSE_ENCODED_PATTERN = FluidCraft.resource("builtin/dense_encoded_pattern"); + public static final ResourceLocation MODEL_FLUID_PACKET = FluidCraft.resource("builtin/fluid_packet"); + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/util/SetBackedMachineSet.java b/src/main/java/com/glodblock/github/util/SetBackedMachineSet.java new file mode 100644 index 000000000..3b645a2a9 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/SetBackedMachineSet.java @@ -0,0 +1,61 @@ +package com.glodblock.github.util; + +import appeng.api.networking.IGridHost; +import appeng.api.networking.IGridNode; +import appeng.api.networking.IMachineSet; + +import javax.annotation.Nonnull; +import java.util.Iterator; +import java.util.Set; +import java.util.Spliterator; +import java.util.function.Consumer; + +public class SetBackedMachineSet implements IMachineSet { + + private final Class machineClass; + private final Set backingSet; + + public SetBackedMachineSet(Class machineClass, Set backingSet) { + this.machineClass = machineClass; + this.backingSet = backingSet; + } + + @Nonnull + @Override + public Class getMachineClass() { + return machineClass; + } + + @Override + public int size() { + return backingSet.size(); + } + + @Override + public boolean isEmpty() { + return backingSet.isEmpty(); + } + + @Override + public boolean contains(Object o) { + //noinspection SuspiciousMethodCalls + return backingSet.contains(o); + } + + @Override + @Nonnull + public Iterator iterator() { + return backingSet.iterator(); + } + + @Override + public void forEach(Consumer action) { + backingSet.forEach(action); + } + + @Override + public Spliterator spliterator() { + return backingSet.spliterator(); + } + +} \ No newline at end of file diff --git a/src/main/resources/assets/ae2fc/blockstates/burette.json b/src/main/resources/assets/ae2fc/blockstates/burette.json new file mode 100644 index 000000000..d1ed555f3 --- /dev/null +++ b/src/main/resources/assets/ae2fc/blockstates/burette.json @@ -0,0 +1,7 @@ +{ + "variants": { + "normal": { + "model": "ae2fc:burette" + } + } +} diff --git a/src/main/resources/assets/ae2fc/blockstates/dual_interface.json b/src/main/resources/assets/ae2fc/blockstates/dual_interface.json new file mode 100644 index 000000000..40f5dd3d9 --- /dev/null +++ b/src/main/resources/assets/ae2fc/blockstates/dual_interface.json @@ -0,0 +1,35 @@ +{ + "forge_marker": 1, + "variants": { + "omnidirectional": { + "true": { + "model": "ae2fc:dual_interface" + }, + "false": { + "model": "ae2fc:dual_interface_oriented" + } + }, + "facing": { + "east": { + "x": 90, + "y": 90 + }, + "west": { + "x": 90, + "y": 270 + }, + "south": { + "x": 270 + }, + "north": { + "x": 90 + }, + "up": { + "x": 0 + }, + "down": { + "x": 180 + } + } + } +} diff --git a/src/main/resources/assets/ae2fc/blockstates/fluid_discretizer.json b/src/main/resources/assets/ae2fc/blockstates/fluid_discretizer.json new file mode 100644 index 000000000..2aece3ea9 --- /dev/null +++ b/src/main/resources/assets/ae2fc/blockstates/fluid_discretizer.json @@ -0,0 +1,7 @@ +{ + "variants": { + "normal": { + "model": "ae2fc:fluid_discretizer" + } + } +} diff --git a/src/main/resources/assets/ae2fc/blockstates/fluid_packet_decoder.json b/src/main/resources/assets/ae2fc/blockstates/fluid_packet_decoder.json new file mode 100644 index 000000000..e008e19aa --- /dev/null +++ b/src/main/resources/assets/ae2fc/blockstates/fluid_packet_decoder.json @@ -0,0 +1,7 @@ +{ + "variants": { + "normal": { + "model": "ae2fc:fluid_packet_decoder" + } + } +} diff --git a/src/main/resources/assets/ae2fc/blockstates/fluid_pattern_encoder.json b/src/main/resources/assets/ae2fc/blockstates/fluid_pattern_encoder.json new file mode 100644 index 000000000..28ddc775c --- /dev/null +++ b/src/main/resources/assets/ae2fc/blockstates/fluid_pattern_encoder.json @@ -0,0 +1,7 @@ +{ + "variants": { + "normal": { + "model": "ae2fc:fluid_pattern_encoder" + } + } +} diff --git a/src/main/resources/assets/ae2fc/blockstates/ingredient_buffer.json b/src/main/resources/assets/ae2fc/blockstates/ingredient_buffer.json new file mode 100644 index 000000000..15db1e22f --- /dev/null +++ b/src/main/resources/assets/ae2fc/blockstates/ingredient_buffer.json @@ -0,0 +1,7 @@ +{ + "variants": { + "normal": { + "model": "ae2fc:ingredient_buffer" + } + } +} diff --git a/src/main/resources/assets/ae2fc/lang/en_us.lang b/src/main/resources/assets/ae2fc/lang/en_us.lang new file mode 100644 index 000000000..0234a8b97 --- /dev/null +++ b/src/main/resources/assets/ae2fc/lang/en_us.lang @@ -0,0 +1,33 @@ +itemGroup.ae2fc=AE2 Fluid Crafting + +tile.ae2fc:fluid_discretizer.name=ME Fluid Discretizer +tile.ae2fc:fluid_pattern_encoder.name=Fluid Pattern Encoder +tile.ae2fc:fluid_packet_decoder.name=ME Fluid Packet Decoder +tile.ae2fc:ingredient_buffer.name=Ingredient Buffer +tile.ae2fc:burette.name=Precision Burette +tile.ae2fc:dual_interface.name=ME Dual Interface +tile.ae2fc:part_dual_interface.name=ME Dual Interface + +item.ae2fc:fluid_drop.name=Drop of %s +item.ae2fc:fluid_packet.name=Fluid Packet +item.ae2fc:dense_encoded_pattern.name=Encoded Pattern +item.ae2fc:part_dual_interface.name=ME Dual Interface +item.ae2fc:part_fluid_pattern_terminal.name=ME Fluid Pattern Terminal + +ae2fc.gui.fluid_pattern_encoder=Fluid Pattern Encoder +ae2fc.gui.fluid_packet_decoder=ME Fluid Packet Decoder +ae2fc.gui.ingredient_buffer=Ingredient Buffer +ae2fc.gui.burette=Precision Burette + +ae2fc.tooltip.fluid_packet=Use a Fluid Packet Decoder to\nconvert this back into fluid. +ae2fc.tooltip.invalid_fluid=Invalid fluid! +ae2fc.tooltip.processing_recipe_only=Not a processing recipe! +ae2fc.tooltip.crafting_recipe_only=Not a crafting recipe! +ae2fc.tooltip.encode_pattern=Encode Pattern +ae2fc.tooltip.empty=Empty +ae2fc.tooltip.dump_tank=Dump Tank Contents +ae2fc.tooltip.transpose_in=Transfer Into Tank +ae2fc.tooltip.transpose_out=Transfer Into Item + +ae2fc.pauto.fluid_processing.name=Fluid Processing +ae2fc.pauto.fluid_processing.name_short=Fluid diff --git a/src/main/resources/assets/ae2fc/models/block/burette.json b/src/main/resources/assets/ae2fc/models/block/burette.json new file mode 100644 index 000000000..4c773d93b --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/block/burette.json @@ -0,0 +1,12 @@ +{ + "parent": "block/cube", + "textures": { + "particle": "ae2fc:blocks/burette_top", + "down": "ae2fc:blocks/burette_top", + "up": "ae2fc:blocks/burette_top", + "north": "ae2fc:blocks/burette_side", + "east": "ae2fc:blocks/burette_side", + "south": "ae2fc:blocks/burette_side", + "west": "ae2fc:blocks/burette_side" + } +} diff --git a/src/main/resources/assets/ae2fc/models/block/dual_interface.json b/src/main/resources/assets/ae2fc/models/block/dual_interface.json new file mode 100644 index 000000000..c118eccff --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/block/dual_interface.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ae2fc:blocks/interface" + } +} diff --git a/src/main/resources/assets/ae2fc/models/block/dual_interface_oriented.json b/src/main/resources/assets/ae2fc/models/block/dual_interface_oriented.json new file mode 100644 index 000000000..72db67793 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/block/dual_interface_oriented.json @@ -0,0 +1,12 @@ +{ + "parent": "block/cube", + "textures": { + "particle": "ae2fc:blocks/interface", + "down": "ae2fc:blocks/interface_alternate", + "up": "ae2fc:blocks/interface", + "north": "ae2fc:blocks/interface_alternate_arrow", + "south": "ae2fc:blocks/interface_alternate_arrow", + "east": "ae2fc:blocks/interface_alternate_arrow", + "west": "ae2fc:blocks/interface_alternate_arrow" + } +} diff --git a/src/main/resources/assets/ae2fc/models/block/fluid_discretizer.json b/src/main/resources/assets/ae2fc/models/block/fluid_discretizer.json new file mode 100644 index 000000000..fea0d3f8d --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/block/fluid_discretizer.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ae2fc:blocks/fluid_discretizer" + } +} diff --git a/src/main/resources/assets/ae2fc/models/block/fluid_packet_decoder.json b/src/main/resources/assets/ae2fc/models/block/fluid_packet_decoder.json new file mode 100644 index 000000000..622135b4d --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/block/fluid_packet_decoder.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ae2fc:blocks/fluid_packet_decoder" + } +} diff --git a/src/main/resources/assets/ae2fc/models/block/fluid_pattern_encoder.json b/src/main/resources/assets/ae2fc/models/block/fluid_pattern_encoder.json new file mode 100644 index 000000000..3452f91b9 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/block/fluid_pattern_encoder.json @@ -0,0 +1,12 @@ +{ + "parent": "block/cube", + "textures": { + "particle": "ae2fc:blocks/fluid_pattern_encoder_top", + "down": "ae2fc:blocks/fluid_pattern_encoder_bottom", + "up": "ae2fc:blocks/fluid_pattern_encoder_top", + "north": "ae2fc:blocks/fluid_pattern_encoder_side", + "east": "ae2fc:blocks/fluid_pattern_encoder_side", + "south": "ae2fc:blocks/fluid_pattern_encoder_side", + "west": "ae2fc:blocks/fluid_pattern_encoder_side" + } +} diff --git a/src/main/resources/assets/ae2fc/models/block/ingredient_buffer.json b/src/main/resources/assets/ae2fc/models/block/ingredient_buffer.json new file mode 100644 index 000000000..b5b2fb4d3 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/block/ingredient_buffer.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ae2fc:blocks/ingredient_buffer" + } +} diff --git a/src/main/resources/assets/ae2fc/models/item/burette.json b/src/main/resources/assets/ae2fc/models/item/burette.json new file mode 100644 index 000000000..b4f5de04a --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/burette.json @@ -0,0 +1,3 @@ +{ + "parent": "ae2fc:block/burette" +} diff --git a/src/main/resources/assets/ae2fc/models/item/dense_encoded_pattern.json b/src/main/resources/assets/ae2fc/models/item/dense_encoded_pattern.json new file mode 100644 index 000000000..41c52e0a6 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/dense_encoded_pattern.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ae2fc:items/dense_encoded_pattern" + } +} diff --git a/src/main/resources/assets/ae2fc/models/item/dual_interface.json b/src/main/resources/assets/ae2fc/models/item/dual_interface.json new file mode 100644 index 000000000..24aed2604 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/dual_interface.json @@ -0,0 +1,3 @@ +{ + "parent": "ae2fc:block/dual_interface" +} diff --git a/src/main/resources/assets/ae2fc/models/item/fluid_discretizer.json b/src/main/resources/assets/ae2fc/models/item/fluid_discretizer.json new file mode 100644 index 000000000..54ada676d --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/fluid_discretizer.json @@ -0,0 +1,3 @@ +{ + "parent": "ae2fc:block/fluid_discretizer" +} diff --git a/src/main/resources/assets/ae2fc/models/item/fluid_drop.json b/src/main/resources/assets/ae2fc/models/item/fluid_drop.json new file mode 100644 index 000000000..ca55bf1da --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/fluid_drop.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ae2fc:items/fluid_drop" + } +} diff --git a/src/main/resources/assets/ae2fc/models/item/fluid_packet.json b/src/main/resources/assets/ae2fc/models/item/fluid_packet.json new file mode 100644 index 000000000..134d55d6f --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/fluid_packet.json @@ -0,0 +1,7 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ae2fc:items/fluid_packet", + "layer1": "ae2fc:items/fluid_packet_overlay" + } +} diff --git a/src/main/resources/assets/ae2fc/models/item/fluid_packet_decoder.json b/src/main/resources/assets/ae2fc/models/item/fluid_packet_decoder.json new file mode 100644 index 000000000..b34f43ede --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/fluid_packet_decoder.json @@ -0,0 +1,3 @@ +{ + "parent": "ae2fc:block/fluid_packet_decoder" +} diff --git a/src/main/resources/assets/ae2fc/models/item/fluid_pattern_encoder.json b/src/main/resources/assets/ae2fc/models/item/fluid_pattern_encoder.json new file mode 100644 index 000000000..2d6ab9fd0 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/fluid_pattern_encoder.json @@ -0,0 +1,3 @@ +{ + "parent": "ae2fc:block/fluid_pattern_encoder" +} diff --git a/src/main/resources/assets/ae2fc/models/item/ingredient_buffer.json b/src/main/resources/assets/ae2fc/models/item/ingredient_buffer.json new file mode 100644 index 000000000..8e58f24ca --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/ingredient_buffer.json @@ -0,0 +1,3 @@ +{ + "parent": "ae2fc:block/ingredient_buffer" +} diff --git a/src/main/resources/assets/ae2fc/models/item/part_dual_interface.json b/src/main/resources/assets/ae2fc/models/item/part_dual_interface.json new file mode 100644 index 000000000..e4a14e799 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/part_dual_interface.json @@ -0,0 +1,106 @@ +{ + "parent": "appliedenergistics2:item/part/part", + "textures": { + "sides": "appliedenergistics2:parts/monitor_sides", + "back": "appliedenergistics2:parts/monitor_back", + "front": "ae2fc:blocks/interface" + }, + "elements": [ + { + "from": [ + 2, + 2, + 7 + ], + "to": [ + 14, + 14, + 9 + ], + "faces": { + "north": { + "texture": "#front" + }, + "south": { + "texture": "#back" + }, + "east": { + "texture": "#sides" + }, + "west": { + "texture": "#sides" + }, + "up": { + "texture": "#sides" + }, + "down": { + "texture": "#sides" + } + } + }, + { + "from": [ + 5, + 5, + 10 + ], + "to": [ + 11, + 11, + 11 + ], + "faces": { + "north": { + "texture": "#front" + }, + "south": { + "texture": "#back" + }, + "east": { + "texture": "#sides" + }, + "west": { + "texture": "#sides" + }, + "up": { + "texture": "#sides" + }, + "down": { + "texture": "#sides" + } + } + }, + { + "from": [ + 5, + 5, + 9 + ], + "to": [ + 11, + 11, + 10 + ], + "faces": { + "north": { + "texture": "#front" + }, + "south": { + "texture": "#back" + }, + "east": { + "texture": "#sides" + }, + "west": { + "texture": "#sides" + }, + "up": { + "texture": "#sides" + }, + "down": { + "texture": "#sides" + } + } + } + ] +} diff --git a/src/main/resources/assets/ae2fc/models/item/part_fluid_pattern_terminal.json b/src/main/resources/assets/ae2fc/models/item/part_fluid_pattern_terminal.json new file mode 100644 index 000000000..d0516315d --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/part_fluid_pattern_terminal.json @@ -0,0 +1,9 @@ +{ + "parent": "appliedenergistics2:item/part/display", + "textures": { + "front": "appliedenergistics2:items/part/pattern_terminal", + "front_bright": "ae2fc:parts/pattern_terminal_bright", + "front_medium": "ae2fc:parts/pattern_terminal_medium", + "front_dark": "ae2fc:parts/pattern_terminal_dark" + } +} diff --git a/src/main/resources/assets/ae2fc/models/part/f_pattern_term_off.json b/src/main/resources/assets/ae2fc/models/part/f_pattern_term_off.json new file mode 100644 index 000000000..217560bcb --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/part/f_pattern_term_off.json @@ -0,0 +1,8 @@ +{ + "parent": "appliedenergistics2:part/display_off", + "textures": { + "lightsBright": "ae2fc:parts/pattern_terminal_bright", + "lightsMedium": "ae2fc:parts/pattern_terminal_medium", + "lightsDark": "ae2fc:parts/pattern_terminal_dark" + } +} diff --git a/src/main/resources/assets/ae2fc/models/part/f_pattern_term_on.json b/src/main/resources/assets/ae2fc/models/part/f_pattern_term_on.json new file mode 100644 index 000000000..124b40516 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/part/f_pattern_term_on.json @@ -0,0 +1,76 @@ +{ + "ae2_uvl_marker": true, + "textures": { + "lightsBright": "ae2fc:parts/pattern_terminal_bright", + "lightsMedium": "ae2fc:parts/pattern_terminal_medium", + "lightsDark": "ae2fc:parts/pattern_terminal_dark" + }, + "elements": [ + { + "from": [ + 2, + 2, + 0 + ], + "to": [ + 14, + 14, + 2 + ], + "faces": { + "north": { + "texture": "#lightsBright", + "tintindex": 3, + "uvlightmap": { + "sky": 0.007, + "block": 0.007 + } + } + } + }, + { + "from": [ + 2, + 2, + 0 + ], + "to": [ + 14, + 14, + 2 + ], + "faces": { + "north": { + "texture": "#lightsMedium", + "tintindex": 2, + "uvlightmap": { + "sky": 0.007, + "block": 0.007 + } + } + } + }, + { + "from": [ + 2, + 2, + 0 + ], + "to": [ + 14, + 14, + 2 + ], + "faces": { + "north": { + "texture": "#lightsDark", + "tintindex": 1, + "uvlightmap": { + "sky": 0.007, + "block": 0.007 + } + } + } + } + ] +} diff --git a/src/main/resources/assets/ae2fc/models/part/interface_base.json b/src/main/resources/assets/ae2fc/models/part/interface_base.json new file mode 100644 index 000000000..685f8f0b2 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/part/interface_base.json @@ -0,0 +1,104 @@ +{ + "textures": { + "sides": "appliedenergistics2:parts/export_bus_sides", + "sidesStatus": "appliedenergistics2:parts/monitor_sides_status", + "back": "appliedenergistics2:parts/monitor_back", + "front": "ae2fc:blocks/interface", + "particle": "appliedenergistics2:parts/monitor_back" + }, + "elements": [ + { + "from": [ + 2, + 2, + 0 + ], + "to": [ + 14, + 14, + 2 + ], + "faces": { + "down": { + "texture": "#sides" + }, + "up": { + "texture": "#sides" + }, + "south": { + "texture": "#back" + }, + "east": { + "texture": "#sides" + }, + "north": { + "texture": "#front" + }, + "west": { + "texture": "#sides" + } + } + }, + { + "from": [ + 5, + 5, + 3 + ], + "to": [ + 11, + 11, + 4 + ], + "faces": { + "down": { + "texture": "#sides" + }, + "up": { + "texture": "#sides" + }, + "south": { + "texture": "#back" + }, + "east": { + "texture": "#sides" + }, + "north": { + "texture": "#front" + }, + "west": { + "texture": "#sides" + } + } + }, + { + "from": [ + 5, + 5, + 2 + ], + "to": [ + 11, + 11, + 3 + ], + "faces": { + "down": { + "texture": "#sidesStatus" + }, + "up": { + "texture": "#sidesStatus" + }, + "south": { + "texture": "#back" + }, + "east": { + "texture": "#sidesStatus" + }, + "west": { + "texture": "#sidesStatus" + } + } + } + ] +} diff --git a/src/main/resources/assets/ae2fc/models/part/interface_has_channel.json b/src/main/resources/assets/ae2fc/models/part/interface_has_channel.json new file mode 100644 index 000000000..f47216bf2 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/part/interface_has_channel.json @@ -0,0 +1,54 @@ +{ + "ae2_uvl_marker": true, + "textures": { + "indicator": "appliedenergistics2:parts/monitor_sides_status_has_channel" + }, + "elements": [ + { + "from": [ + 5, + 5, + 2 + ], + "to": [ + 11, + 11, + 3 + ], + "faces": { + "down": { + "texture": "#indicator", + "tintindex": 1, + "uvlightmap": { + "sky": 0.007, + "block": 0.007 + } + }, + "up": { + "texture": "#indicator", + "tintindex": 1, + "uvlightmap": { + "sky": 0.007, + "block": 0.007 + } + }, + "east": { + "texture": "#indicator", + "tintindex": 1, + "uvlightmap": { + "sky": 0.007, + "block": 0.007 + } + }, + "west": { + "texture": "#indicator", + "tintindex": 1, + "uvlightmap": { + "sky": 0.007, + "block": 0.007 + } + } + } + } + ] +} diff --git a/src/main/resources/assets/ae2fc/models/part/interface_off.json b/src/main/resources/assets/ae2fc/models/part/interface_off.json new file mode 100644 index 000000000..3ab8507fa --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/part/interface_off.json @@ -0,0 +1,33 @@ +{ + "textures": { + "indicator": "appliedenergistics2:parts/monitor_sides_status_off" + }, + "elements": [ + { + "from": [ + 5, + 5, + 2 + ], + "to": [ + 11, + 11, + 3 + ], + "faces": { + "down": { + "texture": "#indicator" + }, + "up": { + "texture": "#indicator" + }, + "east": { + "texture": "#indicator" + }, + "west": { + "texture": "#indicator" + } + } + } + ] +} diff --git a/src/main/resources/assets/ae2fc/models/part/interface_on.json b/src/main/resources/assets/ae2fc/models/part/interface_on.json new file mode 100644 index 000000000..cd41b8f73 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/part/interface_on.json @@ -0,0 +1,54 @@ +{ + "ae2_uvl_marker": true, + "textures": { + "indicator": "appliedenergistics2:parts/monitor_sides_status_on" + }, + "elements": [ + { + "from": [ + 5, + 5, + 2 + ], + "to": [ + 11, + 11, + 3 + ], + "faces": { + "down": { + "texture": "#indicator", + "tintindex": 3, + "uvlightmap": { + "sky": 0.007, + "block": 0.007 + } + }, + "up": { + "texture": "#indicator", + "tintindex": 3, + "uvlightmap": { + "sky": 0.007, + "block": 0.007 + } + }, + "east": { + "texture": "#indicator", + "tintindex": 3, + "uvlightmap": { + "sky": 0.007, + "block": 0.007 + } + }, + "west": { + "texture": "#indicator", + "tintindex": 3, + "uvlightmap": { + "sky": 0.007, + "block": 0.007 + } + } + } + } + ] +} diff --git a/src/main/resources/assets/ae2fc/recipes/burette.json b/src/main/resources/assets/ae2fc/recipes/burette.json new file mode 100644 index 000000000..6c52cd1bc --- /dev/null +++ b/src/main/resources/assets/ae2fc/recipes/burette.json @@ -0,0 +1,31 @@ +{ + "type": "forge:ore_shaped", + "result": { + "item": "ae2fc:burette", + "count": 1 + }, + "pattern": [ + "ihi", + "gbg", + "ici" + ], + "key": { + "i": { + "type": "forge:ore_dict", + "ore": "ingotIron" + }, + "h": { + "item": "minecraft:hopper" + }, + "g": { + "item": "appliedenergistics2:quartz_glass" + }, + "b": { + "item": "minecraft:bucket" + }, + "c": { + "type": "appliedenergistics2:part", + "part": "material.calculation_processor" + } + } +} diff --git a/src/main/resources/assets/ae2fc/recipes/dual_interface.json b/src/main/resources/assets/ae2fc/recipes/dual_interface.json new file mode 100644 index 000000000..fca5492aa --- /dev/null +++ b/src/main/resources/assets/ae2fc/recipes/dual_interface.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "appliedenergistics2:interface" + }, + { + "item": "appliedenergistics2:fluid_interface" + } + ], + "result": { + "item": "ae2fc:dual_interface", + "nbt": {} + } +} diff --git a/src/main/resources/assets/ae2fc/recipes/dual_interface_alter.json b/src/main/resources/assets/ae2fc/recipes/dual_interface_alter.json new file mode 100644 index 000000000..a68c62def --- /dev/null +++ b/src/main/resources/assets/ae2fc/recipes/dual_interface_alter.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "ae2fc:part_dual_interface" + } + ], + "result": { + "item": "ae2fc:dual_interface" + } +} diff --git a/src/main/resources/assets/ae2fc/recipes/fluid_discretizer.json b/src/main/resources/assets/ae2fc/recipes/fluid_discretizer.json new file mode 100644 index 000000000..1684ef4f0 --- /dev/null +++ b/src/main/resources/assets/ae2fc/recipes/fluid_discretizer.json @@ -0,0 +1,33 @@ +{ + "type": "forge:ore_shaped", + "result": { + "item": "ae2fc:fluid_discretizer", + "count": 1 + }, + "pattern": [ + "ipi", + "smt", + "ipi" + ], + "key": { + "i": { + "type": "forge:ore_dict", + "ore": "ingotIron" + }, + "p": { + "type": "appliedenergistics2:part", + "part": "material.engineering_processor" + }, + "s": { + "type": "appliedenergistics2:part", + "part": "part.fluid_storage_bus" + }, + "m": { + "item": "appliedenergistics2:condenser" + }, + "t": { + "type": "appliedenergistics2:part", + "part": "part.storage_bus" + } + } +} diff --git a/src/main/resources/assets/ae2fc/recipes/fluid_packet_decoder.json b/src/main/resources/assets/ae2fc/recipes/fluid_packet_decoder.json new file mode 100644 index 000000000..1b5155c9c --- /dev/null +++ b/src/main/resources/assets/ae2fc/recipes/fluid_packet_decoder.json @@ -0,0 +1,32 @@ +{ + "type": "forge:ore_shaped", + "result": { + "item": "ae2fc:fluid_packet_decoder", + "count": 1 + }, + "pattern": [ + "ihi", + "cfc", + "ipi" + ], + "key": { + "i": { + "type": "forge:ore_dict", + "ore": "ingotIron" + }, + "h": { + "item": "minecraft:hopper" + }, + "c": { + "type": "appliedenergistics2:part", + "part": "cable_glass.fluix" + }, + "f": { + "item": "appliedenergistics2:fluid_interface" + }, + "p": { + "type": "appliedenergistics2:part", + "part": "material.calculation_processor" + } + } +} diff --git a/src/main/resources/assets/ae2fc/recipes/fluid_pattern_encoder.json b/src/main/resources/assets/ae2fc/recipes/fluid_pattern_encoder.json new file mode 100644 index 000000000..cec58226c --- /dev/null +++ b/src/main/resources/assets/ae2fc/recipes/fluid_pattern_encoder.json @@ -0,0 +1,30 @@ +{ + "type": "forge:ore_shaped", + "result": { + "item": "ae2fc:fluid_pattern_encoder", + "count": 1 + }, + "pattern": [ + "lpl", + "iwi", + "iii" + ], + "key": { + "l": { + "type": "forge:ore_dict", + "ore": "blockLapis" + }, + "p": { + "type": "appliedenergistics2:part", + "part": "material.engineering_processor" + }, + "i": { + "type": "forge:ore_dict", + "ore": "ingotIron" + }, + "w": { + "type": "forge:ore_dict", + "ore": "workbench" + } + } +} diff --git a/src/main/resources/assets/ae2fc/recipes/ingredient_buffer.json b/src/main/resources/assets/ae2fc/recipes/ingredient_buffer.json new file mode 100644 index 000000000..f08fc818b --- /dev/null +++ b/src/main/resources/assets/ae2fc/recipes/ingredient_buffer.json @@ -0,0 +1,37 @@ +{ + "type": "forge:ore_shaped", + "result": { + "item": "ae2fc:ingredient_buffer", + "count": 1 + }, + "pattern": [ + "ili", + "agf", + "isi" + ], + "key": { + "i": { + "type": "forge:ore_dict", + "ore": "ingotIron" + }, + "g": { + "item": "appliedenergistics2:quartz_glass" + }, + "l": { + "type": "appliedenergistics2:part", + "part": "material.cell1k_part" + }, + "a": { + "type": "appliedenergistics2:part", + "part": "material.annihilation_core" + }, + "f": { + "type": "appliedenergistics2:part", + "part": "material.formation_core" + }, + "s": { + "type": "appliedenergistics2:part", + "part": "material.fluid_cell1k_part" + } + } +} diff --git a/src/main/resources/assets/ae2fc/recipes/part_dual_interface.json b/src/main/resources/assets/ae2fc/recipes/part_dual_interface.json new file mode 100644 index 000000000..dc5d91f7b --- /dev/null +++ b/src/main/resources/assets/ae2fc/recipes/part_dual_interface.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "ae2fc:dual_interface" + } + ], + "result": { + "item": "ae2fc:part_dual_interface" + } +} diff --git a/src/main/resources/assets/ae2fc/recipes/part_fluid_pattern_terminal.json b/src/main/resources/assets/ae2fc/recipes/part_fluid_pattern_terminal.json new file mode 100644 index 000000000..bd2103a91 --- /dev/null +++ b/src/main/resources/assets/ae2fc/recipes/part_fluid_pattern_terminal.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "type": "appliedenergistics2:part", + "part": "part.pattern_terminal" + }, + { + "item": "ae2fc:fluid_pattern_encoder" + } + ], + "result": { + "item": "ae2fc:part_fluid_pattern_terminal" + } +} diff --git a/src/main/resources/assets/ae2fc/textures/blocks/burette_side.png b/src/main/resources/assets/ae2fc/textures/blocks/burette_side.png new file mode 100644 index 000000000..f633ef09a Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/burette_side.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/burette_top.png b/src/main/resources/assets/ae2fc/textures/blocks/burette_top.png new file mode 100644 index 000000000..0cff59c3d Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/burette_top.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/fluid_discretizer.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_discretizer.png new file mode 100644 index 000000000..d08e7976c Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_discretizer.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/fluid_packet_decoder.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_packet_decoder.png new file mode 100644 index 000000000..623fb299b Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_packet_decoder.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoder_bottom.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoder_bottom.png new file mode 100644 index 000000000..38ca52d36 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoder_bottom.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoder_side.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoder_side.png new file mode 100644 index 000000000..b2b560145 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoder_side.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoder_top.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoder_top.png new file mode 100644 index 000000000..967533398 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_pattern_encoder_top.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/ingredient_buffer.png b/src/main/resources/assets/ae2fc/textures/blocks/ingredient_buffer.png new file mode 100644 index 000000000..8233dcdcb Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/ingredient_buffer.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/interface.png b/src/main/resources/assets/ae2fc/textures/blocks/interface.png new file mode 100644 index 000000000..1fd54c43d Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/interface.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/interface_alternate.png b/src/main/resources/assets/ae2fc/textures/blocks/interface_alternate.png new file mode 100644 index 000000000..d8948d150 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/interface_alternate.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/interface_alternate_arrow.png b/src/main/resources/assets/ae2fc/textures/blocks/interface_alternate_arrow.png new file mode 100644 index 000000000..f86bc6759 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/interface_alternate_arrow.png differ diff --git a/src/main/resources/assets/ae2fc/textures/gui/burette.png b/src/main/resources/assets/ae2fc/textures/gui/burette.png new file mode 100644 index 000000000..7238bf637 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/gui/burette.png differ diff --git a/src/main/resources/assets/ae2fc/textures/gui/fluid_packet_decoder.png b/src/main/resources/assets/ae2fc/textures/gui/fluid_packet_decoder.png new file mode 100644 index 000000000..4e17ee57f Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/gui/fluid_packet_decoder.png differ diff --git a/src/main/resources/assets/ae2fc/textures/gui/fluid_pattern_encoder.png b/src/main/resources/assets/ae2fc/textures/gui/fluid_pattern_encoder.png new file mode 100644 index 000000000..045611f80 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/gui/fluid_pattern_encoder.png differ diff --git a/src/main/resources/assets/ae2fc/textures/gui/ingredient_buffer.png b/src/main/resources/assets/ae2fc/textures/gui/ingredient_buffer.png new file mode 100644 index 000000000..e1d351945 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/gui/ingredient_buffer.png differ diff --git a/src/main/resources/assets/ae2fc/textures/items/dense_encoded_pattern.png b/src/main/resources/assets/ae2fc/textures/items/dense_encoded_pattern.png new file mode 100644 index 000000000..1a19d070b Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/items/dense_encoded_pattern.png differ diff --git a/src/main/resources/assets/ae2fc/textures/items/fluid_drop.png b/src/main/resources/assets/ae2fc/textures/items/fluid_drop.png new file mode 100644 index 000000000..32ae84ab4 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/items/fluid_drop.png differ diff --git a/src/main/resources/assets/ae2fc/textures/items/fluid_packet.png b/src/main/resources/assets/ae2fc/textures/items/fluid_packet.png new file mode 100644 index 000000000..bb301cdbe Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/items/fluid_packet.png differ diff --git a/src/main/resources/assets/ae2fc/textures/items/fluid_packet_overlay.png b/src/main/resources/assets/ae2fc/textures/items/fluid_packet_overlay.png new file mode 100644 index 000000000..6610c0fe5 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/items/fluid_packet_overlay.png differ diff --git a/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_bright.png b/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_bright.png new file mode 100644 index 000000000..11e59a01d Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_bright.png differ diff --git a/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_dark.png b/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_dark.png new file mode 100644 index 000000000..44e4c64ff Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_dark.png differ diff --git a/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_medium.png b/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_medium.png new file mode 100644 index 000000000..a9271aa88 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_medium.png differ diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info new file mode 100644 index 000000000..2e1f9cd4a --- /dev/null +++ b/src/main/resources/mcmod.info @@ -0,0 +1,18 @@ +[ + { + "modid": "ae2fc", + "name": "AE2 Fluid Crafting", + "description": "Lets you do Crafting... with Fluids!", + "version": "${version}", + "mcversion": "${mcversion}", + "url": "", + "updateUrl": "", + "authorList": ["GlodBlock"], + "credits":"phantamanta44", + "logoFile": "", + "screenshots": [], + "useDependencyInformation": true, + "dependencies": ["appliedenergistics2"], + "requiredMods": ["appliedenergistics2"] + } +] \ No newline at end of file diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta new file mode 100644 index 000000000..5744378fb --- /dev/null +++ b/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "Cool Mod", + "pack_format": 3 + } +}