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..44062dc5f --- /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..1f1fa328c --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ + +Port with permission from phantamanta44. + +# AE2 Fluid Crafting Rework + +[![Downloads](https://cf.way2muchnoise.eu/full_623955_downloads.svg)](https://www.curseforge.com/minecraft/mc-mods/ae2-fluid-crafting-rework) ![MCVsrsion](https://cf.way2muchnoise.eu/versions/623955.svg) + +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.16, 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) + +## Features + + - You can code fluid patterns on fluid terminal directly. + - Mult/Div/Add/Sub Button also works on fluid. + - An extended fluid terminal with 16 inputs and 4 outputs. + - You can add or decrease fluid's amount by clicking with container. + - Fluid Pattern can display its contents when put on pattern terminal. + - [1.12.2] Fix the fluid amount display error when removing fluid. + - [1.12.2] Upgrade cards can be inserted in Dual Interface. + - [1.12.2] Fluid pattern is searchable in interface terminal. + - [1.12.2] Fix crash when using block mode, fluid will also be considered as blockable. + - [1.12.2] Fluid export bus supports crafting card. + +## Installation + +### 1.7.10 +Any version of AE2(Both Official AE2 and GTNH edition AE2 works). + +**Extra Cells isn't needed** + +### 1.12.2 +Unofficial AE2([PAE2](https://www.curseforge.com/minecraft/mc-mods/ae2-extended-life)). + +You can directly upgrade origin AE2FC2 in your old save. + +Official AE2 isn't supported, you can use origin [AE2FC](https://github.com/phantamanta44/ae2-fluid-crafting) if you are playing with Official AE2. + +## How to Use It +https://github.com/GlodBlock/AE2FluidCraft-Rework/wiki + +## Credited Works + +E. Geng(@phantamanta44) and KilaBash (@Yefancy) - Their amazing origin work in 1.12. diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..65e2f8de9 --- /dev/null +++ b/build.gradle @@ -0,0 +1,137 @@ +buildscript { + repositories { + maven { + url 'https://maven.minecraftforge.net/' + } + maven { + name 'Scala CI dependencies' + url 'https://repo1.maven.org/maven2/' + } + maven { + name "forge" + url "https://files.minecraftforge.net/maven" + } + maven { + name "mixins" + url "https://repo.spongepowered.org/repository/maven-public/" + } + mavenLocal() + } + dependencies { + classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true + classpath "org.spongepowered:mixingradle:0.7-SNAPSHOT" + } +} + +apply plugin: 'net.minecraftforge.gradle' +apply plugin: 'idea' +apply plugin: 'org.spongepowered.mixin' + +version = "1.0.0-a" +group = "ae2fc" +archivesBaseName = "Fluid Craft for AE2" + +sourceCompatibility = targetCompatibility = '1.8' +compileJava { + sourceCompatibility = targetCompatibility = '1.8' +} + + +// Generate a fixed tsrg file after generating the default tsrg file +createMcpToSrg { + outputs.upToDateWhen {false} + doLast { + fixFG5TsrgForMixinAP(output.get().asFile, file("${buildDir}/fixMcpToSrg/output.tsrg")) + } +} + +// Function that actually fixes the TSRG file +static def fixFG5TsrgForMixinAP(File inFile, File outFile) { + // Make directory if needed + outFile.parentFile.mkdirs() + + try (Scanner scanner = new Scanner(inFile); PrintWriter out = new PrintWriter(outFile)) { + boolean firstLine = true + while (scanner.hasNextLine()) { + String next = scanner.nextLine() + + // Skip first 'tsrg left right' header line + if (firstLine) { + firstLine = false + continue + } + + // Skip 'static' indicators + if (next.trim() == "static") { + continue + } + + // Export line otherwise + out.println(next) + } + } +} + +repositories { + maven { url 'https://dvs1.progwml6.com/files/maven/' } + maven { url 'https://cursemaven.com/' } + maven { url "https://www.cursemaven.com" } +} + +dependencies { + minecraft([ + group : "net.minecraftforge", + name : "forge", + version: "1.16.5-36.1.17" + ]) + annotationProcessor 'org.spongepowered:mixin:0.8.2:processor' + implementation fg.deobf('mezz.jei:jei-1.16.5:7.7.0.98') //jei + implementation fg.deobf('curse.maven:ae2-extended-life-223794:3608871') //ae2 + implementation fg.deobf('curse.maven:packagedauto-308380:4478954') //pauto +} + +minecraft { + mappings channel: 'snapshot', version: '20210309-1.16.5' + accessTransformer = file('src/main/resources/META-INF/ae2fc_at.cfg') + runs { + client = { + properties "forge.logging.markers": "SCAN,REGISTRIES,REGISTRYDUMP" + properties "forge.logging.console.level": "debug" + properties "mixin.env.remapRefMap": "true" + properties "mixin.env.refMapRemappingFile": "${projectDir}/build/createSrgToMcp/output.srg".toString() + workingDirectory project.file("run").canonicalPath + arg "-mixin.config=" + "mixins.ae2fc.json" + source sourceSets.main + } + server = { + properties "forge.logging.markers": "SCAN,REGISTRIES,REGISTRYDUMP" + properties "forge.logging.console.level": "debug" + properties "mixin.env.remapRefMap": "true" + properties "mixin.env.refMapRemappingFile": "${projectDir}/build/createSrgToMcp/output.srg".toString() + workingDirectory project.file("run").canonicalPath + arg "-mixin.config=" + "mixins.ae2fc.json" + source sourceSets.main + } + } +} + +jar { + manifest { + attributes([ + "Specification-Title": "FluidCraftForAE2", + "Specification-Vendor": "GlodBlock", + "Specification-Version": "1", + "Implementation-Title": "${archivesBaseName}", + "Implementation-Version": "${version}", + "Implementation-Vendor": "GlodBlock", + "TweakClass": "org.spongepowered.asm.launch.MixinTweaker", + "TweakOrder": 0, + "MixinConfigs": "mixins.ae2fc.json" + ]) + } +} + +mixin { + reobfSrgFile = file("${buildDir}/fixMcpToSrg/output.tsrg") + add sourceSets.main, "mixins.ae2fc.refmap.json" +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 000000000..e6a23a955 --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx8G -XX:MaxPermSize=512m diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..490fda857 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..d06389f3b --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip \ No newline at end of file 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..0ee319350 --- /dev/null +++ b/src/main/java/com/glodblock/github/FluidCraft.java @@ -0,0 +1,141 @@ +package com.glodblock.github; + +import appeng.api.config.Upgrades; +import appeng.api.definitions.IItemDefinition; +import appeng.api.features.AEFeature; +import appeng.api.util.AEColor; +import appeng.core.Api; +import appeng.core.features.ItemDefinition; +import appeng.recipes.game.DisassembleRecipe; +import com.glodblock.github.client.model.FluidEncodedPatternModel; +import com.glodblock.github.client.render.DropColourHandler; +import com.glodblock.github.client.render.RenderIngredientBuffer; +import com.glodblock.github.common.block.BlockIngredientBuffer; +import com.glodblock.github.common.block.BlockLargeIngredientBuffer; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.handler.ClientRegistryHandler; +import com.glodblock.github.handler.RegistryHandler; +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.FCUtil; +import com.glodblock.github.util.ModAndClassUtil; +import net.minecraft.client.Minecraft; +import net.minecraft.item.Item; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.item.crafting.SpecialRecipeSerializer; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fml.client.registry.ClientRegistry; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; +import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.EnumSet; +import java.util.Map; +import java.util.Objects; + +@Mod(FluidCraft.MODID) +public class FluidCraft { + + public static final String MODID = "ae2fc"; + + public static Logger log; + public static FluidCraft INSTANCE; + public FluidCraft() { + assert INSTANCE == null; + INSTANCE = this; + FCItems.init(RegistryHandler.INSTANCE); + FCBlocks.init(RegistryHandler.INSTANCE); + IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus(); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> bus.register(ClientRegistryHandler.INSTANCE)); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> bus.register(DropColourHandler.INSTANCE)); + bus.register(RegistryHandler.INSTANCE); + bus.addListener(this::commonSetup); + bus.addListener(this::clientSetup); + bus.addListener(this::imcWait); + bus.addListener(this::imcProcess); + bus.addListener(this::finish); + ModAndClassUtil.init(); + } + + public void commonSetup(FMLCommonSetupEvent event) { + log = LogManager.getLogger(); + ChannelLoader.load(); + if (ModAndClassUtil.AUTO_P) { + //PackagedFluidCrafting.init(); + } + RegistryHandler.INSTANCE.onInit(); + IRecipeSerializer disassembleRecipe = DisassembleRecipe.SERIALIZER; + if (disassembleRecipe instanceof SpecialRecipeSerializer) { + Map map = Ae2Reflect.getDisassemblyNonCellMap( + (DisassembleRecipe) Ae2Reflect.getRecipeFactory((SpecialRecipeSerializer)disassembleRecipe).apply( + new ResourceLocation("appliedenergistics2", "disassemble") + ) + ); + map.put( + createItemDefn(FCItems.DENSE_ENCODED_PATTERN, AEFeature.PATTERNS), + Api.instance().definitions().materials().blankPattern() + ); + } + Upgrades.CRAFTING.registerItem(FCBlocks.DUAL_INTERFACE, 1); + Upgrades.CRAFTING.registerItem(FCItems.PART_DUAL_INTERFACE, 1); + } + + public void clientSetup(FMLClientSetupEvent event) { + ClientRegistryHandler.INSTANCE.onInit(); + ClientRegistry.bindTileEntityRenderer(FCUtil.getTileType(BlockIngredientBuffer.TileIngredientBuffer.class, FCBlocks.INGREDIENT_BUFFER), RenderIngredientBuffer::new); + ClientRegistry.bindTileEntityRenderer(FCUtil.getTileType(BlockLargeIngredientBuffer.TileLargeIngredientBuffer.class, FCBlocks.LARGE_INGREDIENT_BUFFER), RenderIngredientBuffer::new); + + Minecraft.getInstance().getItemColors().register((s, i) -> { + FluidStack fluid = ItemFluidDrop.getFluidStack(s); + return !fluid.isEmpty() ? DropColourHandler.INSTANCE.getColour(fluid) : 0xFFFFFFFF; + }, FCItems.FLUID_DROP); + Minecraft.getInstance().getItemColors().register((s, i) -> { + if (i == 0) { + return 0xFFFFFFFF; + } + FluidStack fluid = ItemFluidPacket.getFluidStack(s); + return !fluid.isEmpty() ? fluid.getFluid().getAttributes().getColor(fluid) : 0xFFFFFFFF; + }, FCItems.FLUID_PACKET); + Minecraft.getInstance().getItemColors().register((s, i) -> AEColor.TRANSPARENT.getVariantByTintIndex(i), FCItems.PART_FLUID_PATTERN_TERMINAL); + Minecraft.getInstance().getItemColors().register((s, i) -> AEColor.TRANSPARENT.getVariantByTintIndex(i), FCItems.PART_DUAL_INTERFACE); + Minecraft.getInstance().getItemColors().register(FluidEncodedPatternModel.PATTERN_ITEM_COLOR_HANDLER); + } + + public void imcWait(InterModEnqueueEvent event) { + + } + + public void imcProcess(InterModEnqueueEvent event) { + + } + + public void finish(FMLLoadCompleteEvent event) { + + } + + private static IItemDefinition createItemDefn(Item item, AEFeature... feature) { + return new ItemDefinition( + Objects.requireNonNull(item.getRegistryName()).toString(), + item, + feature.length > 0 ? + EnumSet.of(AEFeature.PATTERNS) : EnumSet.noneOf(AEFeature.class) + ); + } + + public static ResourceLocation resource(String id) { + return new ResourceLocation(MODID, id); + } + +} 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..3ece43f5c --- /dev/null +++ b/src/main/java/com/glodblock/github/client/GuiFCPriority.java @@ -0,0 +1,67 @@ +package com.glodblock.github.client; + +import appeng.client.gui.AEBaseScreen; +import appeng.client.gui.NumberEntryType; +import appeng.client.gui.implementations.NumberEntryWidget; +import appeng.client.gui.style.ScreenStyle; +import appeng.client.gui.widgets.TabButton; +import appeng.core.sync.network.NetworkHandler; +import appeng.core.sync.packets.SwitchGuisPacket; +import com.glodblock.github.client.container.ContainerFCPriority; +import com.glodblock.github.common.tile.TileDualInterface; +import com.glodblock.github.loader.FCBlocks; +import com.glodblock.github.loader.FCItems; +import com.glodblock.github.network.NetworkManager; +import com.glodblock.github.network.packets.CPacketFluidCraftBtns; +import com.mojang.blaze3d.matrix.MatrixStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.ContainerType; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.ITextComponent; + +import java.util.OptionalInt; + +public class GuiFCPriority extends AEBaseScreen { + private final ContainerType originGui; + private final TabButton back; + private final NumberEntryWidget priority; + + public GuiFCPriority(ContainerFCPriority container, PlayerInventory playerInventory, ITextComponent title, ScreenStyle style) { + super(container, playerInventory, title, style); + this.originGui = container.getPriorityHost().getContainerType(); + ItemRenderer itemRender = Minecraft.getInstance().getItemRenderer(); + ItemStack dual; + if (container.getPriorityHost() instanceof TileDualInterface) { + dual = new ItemStack(FCBlocks.DUAL_INTERFACE); + } else { + dual = new ItemStack(FCItems.PART_DUAL_INTERFACE); + } + this.back = new TabButton(dual, dual.getDisplayName(), itemRender, btn -> + NetworkHandler.instance().sendToServer(new SwitchGuisPacket(this.originGui))); + this.priority = new NumberEntryWidget(NumberEntryType.PRIORITY); + this.priority.setTextFieldBounds(62, 57, 50); + this.priority.setMinValue(Integer.MIN_VALUE); + this.priority.setValue(this.container.getPriorityValue()); + this.priority.setOnChange(this::savePriority); + this.priority.setOnConfirm(() -> { + this.savePriority(); + this.back.onPress(); + }); + this.widgets.add("priority", this.priority); + this.widgets.add("back", this.back); + } + + private void savePriority() { + OptionalInt priority = this.priority.getIntValue(); + if (priority.isPresent()) { + NetworkManager.netHandler.sendToServer(new CPacketFluidCraftBtns("priority", priority.getAsInt())); + } + } + + public void drawBG(MatrixStack matrixStack, int offsetX, int offsetY, int mouseX, int mouseY, float partialTicks) { + super.drawBG(matrixStack, offsetX, offsetY, mouseX, mouseY, partialTicks); + this.priority.render(matrixStack, mouseX, mouseY, partialTicks); + } +} 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..05329834d --- /dev/null +++ b/src/main/java/com/glodblock/github/client/GuiFluidDualInterface.java @@ -0,0 +1,49 @@ +package com.glodblock.github.client; + +import appeng.client.gui.implementations.UpgradeableScreen; +import appeng.client.gui.style.ScreenStyle; +import appeng.client.gui.widgets.TabButton; +import appeng.container.SlotSemantic; +import appeng.core.Api; +import appeng.core.localization.GuiText; +import appeng.core.sync.network.NetworkHandler; +import appeng.core.sync.packets.SwitchGuisPacket; +import appeng.fluids.client.gui.widgets.FluidSlotWidget; +import appeng.fluids.client.gui.widgets.FluidTankWidget; +import appeng.fluids.util.IAEFluidTank; +import com.glodblock.github.client.container.ContainerFCPriority; +import com.glodblock.github.client.container.ContainerFluidDualInterface; +import com.glodblock.github.client.container.ContainerItemDualInterface; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.ITextComponent; + +public class GuiFluidDualInterface extends UpgradeableScreen { + + private final TabButton switchInterface; + private final TabButton priorityBtn; + + public GuiFluidDualInterface(ContainerFluidDualInterface container, PlayerInventory playerInventory, ITextComponent title, ScreenStyle style) { + super(container, playerInventory, title, style); + IAEFluidTank configFluids = this.container.getFluidConfigInventory(); + for(int i = 0; i < 6; ++i) { + this.addSlot(new FluidSlotWidget(configFluids, i), SlotSemantic.CONFIG); + } + IAEFluidTank fluidTank = this.container.getTanks(); + for(int i = 0; i < 6; ++i) { + this.widgets.add("tank" + (i + 1), new FluidTankWidget(fluidTank, i)); + } + ItemRenderer itemRender = Minecraft.getInstance().getItemRenderer(); + ItemStack iconItem = Api.instance().definitions().blocks().iface().maybeStack(1).orElse(ItemStack.EMPTY); + switchInterface = new TabButton(iconItem, iconItem.getDisplayName(), itemRender, btn -> + NetworkHandler.instance().sendToServer(new SwitchGuisPacket(ContainerItemDualInterface.TYPE))); + this.widgets.add("switchInterface", switchInterface); + ItemStack iconWrench = Api.instance().definitions().items().certusQuartzWrench().maybeStack(1).orElse(ItemStack.EMPTY); + this.priorityBtn = new TabButton(iconWrench, GuiText.Priority.text(), itemRender, btn -> + NetworkHandler.instance().sendToServer(new SwitchGuisPacket(ContainerFCPriority.TYPE))); + this.widgets.add("priorityBtn", priorityBtn); + } + +} 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..5d65b296b --- /dev/null +++ b/src/main/java/com/glodblock/github/client/GuiFluidPacketDecoder.java @@ -0,0 +1,15 @@ +package com.glodblock.github.client; + +import appeng.client.gui.AEBaseScreen; +import appeng.client.gui.style.ScreenStyle; +import com.glodblock.github.client.container.ContainerFluidPacketDecoder; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.util.text.ITextComponent; + +public class GuiFluidPacketDecoder extends AEBaseScreen { + + public GuiFluidPacketDecoder(ContainerFluidPacketDecoder container, PlayerInventory playerInventory, ITextComponent title, ScreenStyle style) { + super(container, playerInventory, title, style); + } + +} 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..1db6c743e --- /dev/null +++ b/src/main/java/com/glodblock/github/client/GuiFluidPatternTerminal.java @@ -0,0 +1,166 @@ +package com.glodblock.github.client; + +import appeng.api.config.ActionItems; +import appeng.client.gui.me.common.StackSizeRenderer; +import appeng.client.gui.me.items.ItemTerminalScreen; +import appeng.client.gui.style.Blitter; +import appeng.client.gui.style.ScreenStyle; +import appeng.client.gui.widgets.ActionButton; +import appeng.client.gui.widgets.TabButton; +import appeng.container.SlotSemantic; +import appeng.container.slot.FakeSlot; +import appeng.core.localization.GuiText; +import appeng.util.item.AEItemStack; +import com.glodblock.github.client.button.BlitMap; +import com.glodblock.github.client.button.FCToggleButton; +import com.glodblock.github.client.container.ContainerFluidPatternTerminal; +import com.glodblock.github.client.slot.SlotSingleItem; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.network.NetworkManager; +import com.glodblock.github.network.packets.CPacketFluidCraftBtns; +import com.glodblock.github.util.Ae2ReflectClient; +import com.glodblock.github.util.FluidRenderUtils; +import com.mojang.blaze3d.matrix.MatrixStack; +import net.minecraft.block.Blocks; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.ITextComponent; + +import javax.annotation.Nonnull; + +public class GuiFluidPatternTerminal extends ItemTerminalScreen { + private static final String MODES_TEXTURE = "guis/pattern_modes.png"; + private static final Blitter CRAFTING_MODE_BG = Blitter.texture(MODES_TEXTURE).src(0, 0, 126, 68); + private static final Blitter PROCESSING_MODE_BG = Blitter.texture(MODES_TEXTURE).src(0, 70, 126, 68); + private static final String SUBSTITUTION_DISABLE = "0"; + private static final String SUBSTITUTION_ENABLE = "1"; + private static final String CRAFTMODE_CRAFTING = "1"; + private static final String CRAFTMODE_PROCESSING = "0"; + private final StackSizeRenderer stackSizeRenderer = Ae2ReflectClient.getGuiStyle(this).getStackSizeRenderer(); + private final TabButton tabCraftButton; + private final TabButton tabProcessButton; + private final ActionButton substitutionsEnabledBtn; + private final ActionButton substitutionsDisabledBtn; + private final FCToggleButton combineBtn; + private final FCToggleButton fluidBtn; + + public GuiFluidPatternTerminal(ContainerFluidPatternTerminal container, PlayerInventory playerInventory, ITextComponent title, ScreenStyle style) { + super(container, playerInventory, title, style); + this.tabCraftButton = new TabButton( + new ItemStack(Blocks.CRAFTING_TABLE), GuiText.CraftingPattern.text(), this.itemRenderer, + btn -> toggleCraftMode(CRAFTMODE_PROCESSING)); + widgets.add("craftingPatternMode", this.tabCraftButton); + + this.tabProcessButton = new TabButton( + new ItemStack(Blocks.FURNACE), GuiText.ProcessingPattern.text(), this.itemRenderer, + btn -> toggleCraftMode(CRAFTMODE_CRAFTING)); + widgets.add("processingPatternMode", this.tabProcessButton); + + this.substitutionsEnabledBtn = new ActionButton( + ActionItems.ENABLE_SUBSTITUTION, act -> toggleSubstitutions(SUBSTITUTION_DISABLE)); + this.substitutionsEnabledBtn.setHalfSize(true); + widgets.add("substitutionsEnabled", this.substitutionsEnabledBtn); + + this.substitutionsDisabledBtn = new ActionButton( + ActionItems.DISABLE_SUBSTITUTION, act -> toggleSubstitutions(SUBSTITUTION_ENABLE)); + this.substitutionsDisabledBtn.setHalfSize(true); + widgets.add("substitutionsDisabled", this.substitutionsDisabledBtn); + + this.combineBtn = new FCToggleButton( + btn -> { + FCToggleButton fbtn = (FCToggleButton) btn; + NetworkManager.netHandler.sendToServer(new CPacketFluidCraftBtns("combine", fbtn.getActive() == 1)); + }, BlitMap.NOT_COMBINE, BlitMap.COMBINE + ); + this.combineBtn.setHalfSize(true); + widgets.add("combineBtn", this.combineBtn); + + this.fluidBtn = new FCToggleButton( + btn -> { + FCToggleButton fbtn = (FCToggleButton) btn; + NetworkManager.netHandler.sendToServer(new CPacketFluidCraftBtns("fluidFirst", fbtn.getActive() == 0)); + }, BlitMap.FLUID_FIRST, BlitMap.ITEM_FIRST + ); + this.fluidBtn.setHalfSize(true); + widgets.add("fluidBtn", this.fluidBtn); + + ActionButton clearBtn = new ActionButton(ActionItems.CLOSE, act -> clear()); + clearBtn.setHalfSize(true); + widgets.add("clearPattern", clearBtn); + + ActionButton encodeBtn = new ActionButton(ActionItems.ENCODE, act -> encode()); + widgets.add("encodePattern", encodeBtn); + } + + @Override + protected void updateBeforeRender() { + super.updateBeforeRender(); + if (this.container.isCraftingMode()) { + this.tabCraftButton.visible = true; + this.tabProcessButton.visible = false; + + if (this.container.substitute) { + this.substitutionsEnabledBtn.visible = true; + this.substitutionsDisabledBtn.visible = false; + } else { + this.substitutionsEnabledBtn.visible = false; + this.substitutionsDisabledBtn.visible = true; + } + this.fluidBtn.visible = false; + this.combineBtn.visible = false; + } else { + this.tabCraftButton.visible = false; + this.tabProcessButton.visible = true; + this.substitutionsEnabledBtn.visible = false; + this.substitutionsDisabledBtn.visible = false; + this.fluidBtn.visible = true; + this.combineBtn.visible = true; + } + + setSlotsHidden(SlotSemantic.CRAFTING_RESULT, !this.container.isCraftingMode()); + setSlotsHidden(SlotSemantic.PROCESSING_RESULT, this.container.isCraftingMode()); + } + + private void toggleCraftMode(String mode) { + NetworkManager.netHandler.sendToServer(new CPacketFluidCraftBtns("craft", mode.equals("1"))); + } + + private void toggleSubstitutions(String mode) { + NetworkManager.netHandler.sendToServer(new CPacketFluidCraftBtns("substitute", mode.equals("1"))); + } + + private void encode() { + NetworkManager.netHandler.sendToServer(new CPacketFluidCraftBtns("encode")); + } + + private void clear() { + NetworkManager.netHandler.sendToServer(new CPacketFluidCraftBtns("clear")); + } + + @Override + protected void moveItems(MatrixStack matrices, Slot slot) { + if (!(slot instanceof FakeSlot && (FluidRenderUtils.renderFluidPacketIntoGuiSlot( + slot, slot.getStack(), stackSizeRenderer, font) || renderMEStyleSlot(slot, slot.getStack(), matrices)))) { + super.moveItems(matrices, slot); + } + } + + private boolean renderMEStyleSlot(Slot slot, @Nonnull ItemStack stack, MatrixStack matrices) { + if (slot instanceof FakeSlot && !stack.isEmpty() && !(stack.getItem() instanceof ItemFluidPacket)) { + super.moveItems(matrices, new SlotSingleItem(slot)); + if (stack.getCount() > 1) { + this.stackSizeRenderer.renderStackSize(font, AEItemStack.fromItemStack(stack).getStackSize(), false, slot.xPos, slot.yPos); + } + return true; + } + return false; + } + + @Override + public void drawBG(MatrixStack matrixStack, int offsetX, int offsetY, int mouseX, int mouseY, float partialTicks) { + super.drawBG(matrixStack, offsetX, offsetY, mouseX, mouseY, partialTicks); + Blitter modeBg = this.container.isCraftingMode() ? CRAFTING_MODE_BG : PROCESSING_MODE_BG; + modeBg.dest(this.guiLeft + 9, this.guiTop + this.ySize - 164).blit(matrixStack, this.getBlitOffset()); + } +} \ 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..46db5b6b2 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/GuiIngredientBuffer.java @@ -0,0 +1,59 @@ +package com.glodblock.github.client; + +import appeng.client.gui.AEBaseScreen; +import appeng.client.gui.style.ScreenStyle; +import appeng.fluids.util.IAEFluidTank; +import com.glodblock.github.client.container.ContainerIngredientBuffer; +import com.glodblock.github.handler.ButtonMouseHandler; +import com.glodblock.github.handler.TankMouseHandler; +import com.glodblock.github.util.FluidRenderUtils; +import com.glodblock.github.util.MouseRegionManager; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.platform.GlStateManager; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.PlayerContainer; +import net.minecraft.util.text.ITextComponent; + +public class GuiIngredientBuffer extends AEBaseScreen { + + 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 MouseRegionManager mouseRegions = new MouseRegionManager(this); + + public GuiIngredientBuffer(ContainerIngredientBuffer container, PlayerInventory playerInventory, ITextComponent title, ScreenStyle style) { + super(container, playerInventory, title, style); + for (int i = 0; i < 4; i++) { + mouseRegions.addRegion(TANK_X + TANK_X_OFF * i, TANK_Y, TANK_WIDTH, TANK_HEIGHT, + new TankMouseHandler(container.getTile().getFluidInventory(), i)); + mouseRegions.addRegion(TANK_X + 10 + 22 * i, TANK_Y + TANK_HEIGHT + 2, 7, 7, + ButtonMouseHandler.dumpTank(container, i)); + } + } + + @Override + public boolean mouseClicked(double xCoord, double yCoord, int btn) { + if (mouseRegions.onClick(xCoord, yCoord, btn)) { + return super.mouseClicked(xCoord, yCoord, btn); + } + return true; + } + + @Override + public void drawFG(MatrixStack matrixStack, int offsetX, int offsetY, int mouseX, int mouseY) { + GlStateManager.color4f(1F, 1F, 1F, 1F); + IAEFluidTank fluidInv = container.getTile().getFluidInventory(); + assert minecraft != null; + minecraft.getTextureManager().bindTexture(PlayerContainer.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.getTankCapacity(i)); + } + GlStateManager.color4f(1F, 1F, 1F, 1F); + mouseRegions.render(matrixStack, 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..c92674618 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/GuiItemDualInterface.java @@ -0,0 +1,93 @@ +package com.glodblock.github.client; + +import appeng.api.config.Settings; +import appeng.api.config.YesNo; +import appeng.client.gui.Icon; +import appeng.client.gui.implementations.UpgradeableScreen; +import appeng.client.gui.style.ScreenStyle; +import appeng.client.gui.widgets.ServerSettingToggleButton; +import appeng.client.gui.widgets.SettingToggleButton; +import appeng.client.gui.widgets.TabButton; +import appeng.client.gui.widgets.ToggleButton; +import appeng.core.Api; +import appeng.core.localization.GuiText; +import appeng.core.sync.network.NetworkHandler; +import appeng.core.sync.packets.ConfigButtonPacket; +import appeng.core.sync.packets.SwitchGuisPacket; +import com.glodblock.github.client.button.BlitMap; +import com.glodblock.github.client.button.FCToggleButton; +import com.glodblock.github.client.container.ContainerFCPriority; +import com.glodblock.github.client.container.ContainerFluidDualInterface; +import com.glodblock.github.client.container.ContainerItemDualInterface; +import com.glodblock.github.network.NetworkManager; +import com.glodblock.github.network.packets.CPacketFluidCraftBtns; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.ITextComponent; + +public class GuiItemDualInterface extends UpgradeableScreen { + + private final SettingToggleButton blockMode; + private final ToggleButton interfaceMode; + private final TabButton switchInterface; + private final TabButton priorityBtn; + private final FCToggleButton fluidPacketBtn; + private final FCToggleButton splittingBtn; + private final FCToggleButton blockingBtn; + + public GuiItemDualInterface(ContainerItemDualInterface container, PlayerInventory playerInventory, ITextComponent title, ScreenStyle style) { + super(container, playerInventory, title, style); + this.blockMode = new ServerSettingToggleButton<>(Settings.BLOCK, YesNo.NO); + this.addToLeftToolbar(this.blockMode); + this.interfaceMode = new ToggleButton(Icon.INTERFACE_TERMINAL_SHOW, Icon.INTERFACE_TERMINAL_HIDE, GuiText.InterfaceTerminal.text(), GuiText.InterfaceTerminalHint.text(), (btn) -> { + this.selectNextInterfaceMode(); + }); + this.addToLeftToolbar(this.interfaceMode); + ItemRenderer itemRender = Minecraft.getInstance().getItemRenderer(); + ItemStack iconFluid = Api.instance().definitions().blocks().fluidIface().maybeStack(1).orElse(ItemStack.EMPTY); + this.switchInterface = new TabButton(iconFluid, iconFluid.getDisplayName(), itemRender, btn -> + NetworkHandler.instance().sendToServer(new SwitchGuisPacket(ContainerFluidDualInterface.TYPE))); + this.widgets.add("switchInterface", switchInterface); + ItemStack iconWrench = Api.instance().definitions().items().certusQuartzWrench().maybeStack(1).orElse(ItemStack.EMPTY); + this.priorityBtn = new TabButton(iconWrench, GuiText.Priority.text(), itemRender, btn -> + NetworkHandler.instance().sendToServer(new SwitchGuisPacket(ContainerFCPriority.TYPE))); + this.widgets.add("priorityBtn", priorityBtn); + fluidPacketBtn = new FCToggleButton( + btn -> { + FCToggleButton fbtn = (FCToggleButton) btn; + NetworkManager.netHandler.sendToServer(new CPacketFluidCraftBtns("fluidPacket", fbtn.getActive() == 1)); + }, BlitMap.SEND_FLUID, BlitMap.SEND_PACKET); + this.addToLeftToolbar(fluidPacketBtn); + splittingBtn = new FCToggleButton( + btn -> { + FCToggleButton fbtn = (FCToggleButton) btn; + NetworkManager.netHandler.sendToServer(new CPacketFluidCraftBtns("allowSplitting", fbtn.getActive() == 1)); + }, BlitMap.NOT_SPLITTING, BlitMap.SPLITTING); + this.addToLeftToolbar(splittingBtn); + blockingBtn = new FCToggleButton( + btn -> { + FCToggleButton fbtn = (FCToggleButton) btn; + NetworkManager.netHandler.sendToServer(new CPacketFluidCraftBtns("blockModeEx", fbtn.getActive())); + }, BlitMap.BLOCK_ALL, BlitMap.BLOCK_ITEM, BlitMap.BLOCK_FLUID); + this.addToLeftToolbar(blockingBtn); + } + + @Override + protected void updateBeforeRender() { + super.updateBeforeRender(); + this.blockMode.set(this.container.getBlockingMode()); + this.interfaceMode.setState(this.container.getInterfaceTerminalMode() == YesNo.YES); + this.fluidPacketBtn.forceActive(this.container.fluidPacket ? 1 : 0); + this.splittingBtn.forceActive(this.container.allowSplitting ? 1 : 0); + this.blockingBtn.forceActive(this.container.blockModeEx); + this.blockingBtn.visible = this.blockMode.getCurrentValue() == YesNo.YES; + } + + private void selectNextInterfaceMode() { + boolean backwards = this.isHandlingRightClick(); + NetworkHandler.instance().sendToServer(new ConfigButtonPacket(Settings.INTERFACE_TERMINAL, backwards)); + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/client/GuiLargeIngredientBuffer.java b/src/main/java/com/glodblock/github/client/GuiLargeIngredientBuffer.java new file mode 100644 index 000000000..d529525e1 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/GuiLargeIngredientBuffer.java @@ -0,0 +1,60 @@ +package com.glodblock.github.client; + +import appeng.client.gui.AEBaseScreen; +import appeng.client.gui.style.ScreenStyle; +import appeng.fluids.util.IAEFluidTank; +import com.glodblock.github.client.container.ContainerLargeIngredientBuffer; +import com.glodblock.github.handler.ButtonMouseHandler; +import com.glodblock.github.handler.TankMouseHandler; +import com.glodblock.github.util.FluidRenderUtils; +import com.glodblock.github.util.MouseRegionManager; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.platform.GlStateManager; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.PlayerContainer; +import net.minecraft.util.text.ITextComponent; + +public class GuiLargeIngredientBuffer extends AEBaseScreen { + + private static final int TANK_X = 13, TANK_X_OFF = 22, TANK_Y = 18; + private static final int TANK_WIDTH = 16, TANK_HEIGHT = 37; + + private final MouseRegionManager mouseRegions = new MouseRegionManager(this); + + public GuiLargeIngredientBuffer(ContainerLargeIngredientBuffer container, PlayerInventory playerInventory, ITextComponent title, ScreenStyle style) { + super(container, playerInventory, title, style); + for (int i = 0; i < 7; i++) { + mouseRegions.addRegion(TANK_X + TANK_X_OFF * i, TANK_Y, TANK_WIDTH, TANK_HEIGHT, + new TankMouseHandler(container.getTile().getFluidInventory(), i)); + mouseRegions.addRegion(TANK_X + 10 + 22 * i, TANK_Y + TANK_HEIGHT + 2, 7, 7, + ButtonMouseHandler.dumpTank(container, i)); + } + } + + @Override + public boolean mouseClicked(double xCoord, double yCoord, int btn) { + if (mouseRegions.onClick(xCoord, yCoord, btn)) { + return super.mouseClicked(xCoord, yCoord, btn); + } + return true; + } + + @Override + public void drawFG(MatrixStack matrixStack, int offsetX, int offsetY, int mouseX, int mouseY) { + GlStateManager.color4f(1F, 1F, 1F, 1F); + IAEFluidTank fluidInv = container.getTile().getFluidInventory(); + assert minecraft != null; + minecraft.getTextureManager().bindTexture(PlayerContainer.LOCATION_BLOCKS_TEXTURE); + Tessellator tess = Tessellator.getInstance(); + BufferBuilder buf = tess.getBuffer(); + for (int i = 0; i < 7; i++) { + FluidRenderUtils.renderFluidIntoGui(tess, buf, TANK_X + i * TANK_X_OFF, TANK_Y, TANK_WIDTH, TANK_HEIGHT, + fluidInv.getFluidInSlot(i), fluidInv.getTankCapacity(i)); + } + GlStateManager.color4f(1F, 1F, 1F, 1F); + mouseRegions.render(matrixStack, mouseX, mouseY); + } + +} diff --git a/src/main/java/com/glodblock/github/client/button/BlitMap.java b/src/main/java/com/glodblock/github/client/button/BlitMap.java new file mode 100644 index 000000000..5b17ec215 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/button/BlitMap.java @@ -0,0 +1,52 @@ +package com.glodblock.github.client.button; + +import appeng.client.gui.style.Blitter; +import com.glodblock.github.util.NameConst; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; + +public enum BlitMap { + + NOT_COMBINE(0, 0), + COMBINE(16, 0), + SEND_FLUID(2*16, 0), + SEND_PACKET(3*16, 0), + FLUID_FIRST(0, 16), + ITEM_FIRST(16, 16), + CRAFT_FLUID(2*16, 16), + SPLITTING(3*16, 16), + NOT_SPLITTING(0, 2*16), + BLOCK_ALL(16, 2*16), + BLOCK_ITEM(2*16, 2*16), + BLOCK_FLUID(3*16, 2*16); + + + private final int x; + private final int y; + private final int width; + private final int height; + + BlitMap(int x, int y) { + this(x, y, 16, 16); + } + + BlitMap(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public Blitter getBlitter() { + return Blitter.texture("gui/states.png", 64, 64).src(this.x, this.y, this.width, this.height); + } + + public ITextComponent getDisplayName() { + return new TranslationTextComponent(NameConst.TT_KEY + this.toString().toLowerCase()); + } + + public ITextComponent getHint() { + return new TranslationTextComponent(NameConst.TT_KEY + this.toString().toLowerCase() + ".hint"); + } + +} diff --git a/src/main/java/com/glodblock/github/client/button/FCToggleButton.java b/src/main/java/com/glodblock/github/client/button/FCToggleButton.java new file mode 100644 index 000000000..93a392921 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/button/FCToggleButton.java @@ -0,0 +1,98 @@ +package com.glodblock.github.client.button; + +import appeng.client.gui.Icon; +import appeng.client.gui.widgets.ITooltip; +import com.mojang.blaze3d.matrix.MatrixStack; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; + +import javax.annotation.Nonnull; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +public class FCToggleButton extends Button implements ITooltip { + private final BlitMap[] modes; + private final int length; + private int active; + private boolean halfSize = false; + + public FCToggleButton(Button.IPressable onPress, BlitMap... modes) { + super(0, 0, 16, 16, StringTextComponent.EMPTY, onPress); + this.modes = modes; + this.length = modes.length; + } + + public void next() { + active = (active + 1) % length; + } + + public void forceActive(int value) { + active = value % length; + } + + @Override + public void renderWidget(@Nonnull MatrixStack matrixStack, int mouseX, int mouseY, float partial) { + if (this.visible) { + if (this.halfSize) { + matrixStack.push(); + matrixStack.translate(this.x, this.y, 0.0); + matrixStack.scale(0.5F, 0.5F, 1.0F); + Icon.TOOLBAR_BUTTON_BACKGROUND.getBlitter().dest(0, 0).blit(matrixStack, this.getBlitOffset()); + this.getIcon().getBlitter().dest(0, 0).blit(matrixStack, this.getBlitOffset()); + matrixStack.pop(); + } else { + Icon.TOOLBAR_BUTTON_BACKGROUND.getBlitter().dest(this.x, this.y).blit(matrixStack, this.getBlitOffset()); + this.getIcon().getBlitter().dest(this.x, this.y).blit(matrixStack, this.getBlitOffset()); + } + } + } + + public void setHalfSize(boolean value) { + this.halfSize = value; + if (value) { + this.width = 8; + this.height = 8; + } + } + + @Override + public void onPress() { + this.next(); + this.onPress.onPress(this); + } + + private BlitMap getIcon() { + return this.modes[active]; + } + + public int getActive() { + return this.active; + } + + @Nonnull + public List getTooltipMessage() { + return Arrays.asList(this.getIcon().getDisplayName(), this.getIcon().getHint()); + } + + public int getTooltipAreaX() { + return this.x; + } + + public int getTooltipAreaY() { + return this.y; + } + + public int getTooltipAreaWidth() { + return this.width; + } + + public int getTooltipAreaHeight() { + return this.height; + } + + public boolean isTooltipAreaVisible() { + return this.visible; + } +} diff --git a/src/main/java/com/glodblock/github/client/container/ContainerFCPriority.java b/src/main/java/com/glodblock/github/client/container/ContainerFCPriority.java new file mode 100644 index 000000000..cbbd38f5d --- /dev/null +++ b/src/main/java/com/glodblock/github/client/container/ContainerFCPriority.java @@ -0,0 +1,69 @@ +package com.glodblock.github.client.container; + +import appeng.api.config.SecurityPermissions; +import appeng.container.AEBaseContainer; +import appeng.container.guisync.GuiSync; +import appeng.container.implementations.ContainerTypeBuilder; +import appeng.helpers.IPriorityHost; +import com.glodblock.github.interfaces.ConfigData; +import com.glodblock.github.util.ConfigSet; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.ContainerType; + +public class ContainerFCPriority extends AEBaseContainer implements ConfigData { + public static final ContainerType TYPE = ContainerTypeBuilder.create(ContainerFCPriority::new, IPriorityHost.class) + .requirePermission(SecurityPermissions.BUILD) + .withInitialData( + (host, buffer) -> buffer.writeVarInt(host.getPriority()), + (host, container, buffer) -> container.priorityValue = buffer.readVarInt()) + .build("fc_priority"); + private final IPriorityHost priHost; + private final ConfigSet exConfig = new ConfigSet(); + @GuiSync(2) + public int priorityValue; + + public ContainerFCPriority(int id, PlayerInventory ip, IPriorityHost te) { + super(TYPE, id, ip, te); + this.priHost = te; + this.priorityValue = te.getPriority(); + this.exConfig.addConfig("priority", v -> { + this.priorityValue = (int) v; + this.priHost.setPriority((int) v); + }, () -> this.priorityValue); + } + + public void setPriority(int newValue) { + if (newValue != this.priorityValue) { + if (this.isServer()) { + this.priHost.setPriority(newValue); + this.priorityValue = newValue; + } + } + } + + public void detectAndSendChanges() { + super.detectAndSendChanges(); + this.verifyPermissions(SecurityPermissions.BUILD, false); + if (this.isServer()) { + this.priorityValue = this.priHost.getPriority(); + } + } + + public int getPriorityValue() { + return this.priorityValue; + } + + public IPriorityHost getPriorityHost() { + return this.priHost; + } + + @Override + public void set(String id, Object value) { + this.exConfig.setConfig(id, value); + } + + @Override + public Object get(String id) { + return this.exConfig.getConfig(id); + } +} diff --git a/src/main/java/com/glodblock/github/client/container/ContainerFluidDualInterface.java b/src/main/java/com/glodblock/github/client/container/ContainerFluidDualInterface.java new file mode 100644 index 000000000..754cdb605 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/container/ContainerFluidDualInterface.java @@ -0,0 +1,82 @@ +package com.glodblock.github.client.container; + +import appeng.api.config.SecurityPermissions; +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.util.IConfigManager; +import appeng.container.implementations.ContainerTypeBuilder; +import appeng.fluids.container.FluidConfigurableContainer; +import appeng.fluids.helper.DualityFluidInterface; +import appeng.fluids.helper.FluidSyncHelper; +import appeng.fluids.helper.IFluidInterfaceHost; +import appeng.fluids.util.IAEFluidTank; +import appeng.util.Platform; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.ContainerType; +import net.minecraft.inventory.container.IContainerListener; + +import java.util.Collections; +import java.util.Map; + +public class ContainerFluidDualInterface extends FluidConfigurableContainer { + + private final DualityFluidInterface myDuality; + private final FluidSyncHelper tankSync; + public static final ContainerType TYPE = ContainerTypeBuilder + .create(ContainerFluidDualInterface::new, IFluidInterfaceHost.class) + .build("dual_fluid_interface"); + + public ContainerFluidDualInterface(int id, PlayerInventory ip, IFluidInterfaceHost te) { + super(TYPE, id, ip, te.getDualityFluidInterface().getHost()); + this.myDuality = te.getDualityFluidInterface(); + this.tankSync = new FluidSyncHelper(this.myDuality.getTanks(), 6); + } + + protected void setupConfig() { + // NO-OP + } + + protected void loadSettingsFromHost(IConfigManager cm) { + // NO-OP + } + + public IAEFluidTank getTanks() { + return this.myDuality.getTanks(); + } + + public IAEFluidTank getFluidConfigInventory() { + return this.myDuality.getConfig(); + } + + @Override + public void detectAndSendChanges() { + this.verifyPermissions(SecurityPermissions.BUILD, false); + super.detectAndSendChanges(); + if (Platform.isServer()) { + this.tankSync.sendDiff(this.listeners); + } + standardDetectAndSendChanges(); + } + + public void addListener(IContainerListener listener) { + super.addListener(listener); + this.tankSync.sendFull(Collections.singleton(listener)); + } + + public void receiveFluidSlots(Map fluids) { + super.receiveFluidSlots(fluids); + this.tankSync.readPacket(fluids); + } + + protected boolean supportCapacity() { + return false; + } + + public int availableUpgrades() { + return 0; + } + + public boolean hasToolbox() { + return false; + } + +} 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..966f9b71f --- /dev/null +++ b/src/main/java/com/glodblock/github/client/container/ContainerFluidPacketDecoder.java @@ -0,0 +1,23 @@ +package com.glodblock.github.client.container; + +import appeng.container.AEBaseContainer; +import appeng.container.SlotSemantic; +import appeng.container.implementations.ContainerTypeBuilder; +import appeng.container.slot.AppEngSlot; +import com.glodblock.github.common.tile.TileFluidPacketDecoder; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.ContainerType; + +public class ContainerFluidPacketDecoder extends AEBaseContainer { + + public static final ContainerType TYPE = ContainerTypeBuilder + .create(ContainerFluidPacketDecoder::new, TileFluidPacketDecoder.class) + .build("fluid_packet_decoder"); + + public ContainerFluidPacketDecoder(int id, PlayerInventory ip, TileFluidPacketDecoder tile) { + super(TYPE, id, ip, tile); + addSlot(new AppEngSlot(tile.getInventory(), 0), SlotSemantic.STORAGE); + createPlayerInventorySlots(ip); + } + +} 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..de48ae667 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/container/ContainerFluidPatternTerminal.java @@ -0,0 +1,558 @@ +package com.glodblock.github.client.container; + +import appeng.api.config.Actionable; +import appeng.api.crafting.ICraftingHelper; +import appeng.api.definitions.IDefinitions; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.ITerminalHost; +import appeng.api.storage.channels.IItemStorageChannel; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; +import appeng.container.ContainerNull; +import appeng.container.SlotSemantic; +import appeng.container.guisync.GuiSync; +import appeng.container.implementations.ContainerTypeBuilder; +import appeng.container.me.items.ItemTerminalContainer; +import appeng.container.slot.*; +import appeng.core.Api; +import appeng.core.sync.packets.PatternSlotPacket; +import appeng.helpers.IContainerCraftingPacket; +import appeng.helpers.InventoryAction; +import appeng.items.storage.ViewCellItem; +import appeng.me.helpers.MachineSource; +import appeng.util.InventoryAdaptor; +import appeng.util.Platform; +import appeng.util.inv.AdaptorItemHandler; +import appeng.util.inv.WrapperCursorItemHandler; +import appeng.util.item.AEItemStack; +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.ConfigData; +import com.glodblock.github.interfaces.PatternConsumer; +import com.glodblock.github.loader.FCItems; +import com.glodblock.github.util.ConfigSet; +import com.glodblock.github.util.FCUtil; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.inventory.CraftResultInventory; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.inventory.container.ContainerType; +import net.minecraft.inventory.container.CraftingResultSlot; +import net.minecraft.inventory.container.IContainerListener; +import net.minecraft.inventory.container.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.ICraftingRecipe; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeType; +import net.minecraft.world.World; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; +import net.minecraftforge.items.wrapper.PlayerInvWrapper; + +import javax.annotation.Nonnull; + +public class ContainerFluidPatternTerminal extends ItemTerminalContainer implements IOptionalSlotHost, IContainerCraftingPacket, PatternConsumer, ConfigData { + + private final PartFluidPatternTerminal patternTerminal; + private final IItemHandler craftingGridInv; + private final FakeCraftingMatrixSlot[] craftingGridSlots = new FakeCraftingMatrixSlot[9]; + private final OptionalFakeSlot[] processingOutputSlots = new OptionalFakeSlot[3]; + private final PatternTermSlot craftOutputSlot; + private final RestrictedInputSlot blankPatternSlot; + private final RestrictedInputSlot encodedPatternSlot; + private final ICraftingHelper craftingHelper; + private final ConfigSet config = new ConfigSet(); + private ICraftingRecipe currentRecipe; + private boolean currentRecipeCraftingMode; + public static ContainerType TYPE = ContainerTypeBuilder + .create(ContainerFluidPatternTerminal::new, ITerminalHost.class) + .build("fluid_pattern_terminal"); + @GuiSync(97) + public boolean craftingMode; + @GuiSync(96) + public boolean substitute; + @GuiSync(105) + public boolean combine = false; + @GuiSync(106) + public boolean fluidFirst = false; + + public ContainerFluidPatternTerminal(int id, PlayerInventory ip, ITerminalHost monitorable) { + super(TYPE, id, ip, monitorable, false); + this.craftingHelper = Api.INSTANCE.crafting(); + this.craftingMode = true; + this.substitute = false; + this.patternTerminal = (PartFluidPatternTerminal) monitorable; + IItemHandler patternInv = this.patternTerminal.getInventoryByName("pattern"); + IItemHandler output = this.patternTerminal.getInventoryByName("output"); + this.craftingGridInv = this.patternTerminal.getInventoryByName("crafting"); + int i; + for(i = 0; i < 9; ++i) { + this.addSlot(this.craftingGridSlots[i] = new FakeCraftingMatrixSlot(this.craftingGridInv, i), SlotSemantic.CRAFTING_GRID); + } + + this.addSlot(this.craftOutputSlot = new PatternTermSlot(ip.player, this.getActionSource(), this.powerSource, monitorable, this.craftingGridInv, patternInv, this, 2, this), SlotSemantic.CRAFTING_RESULT); + this.craftOutputSlot.setIcon(null); + + for(i = 0; i < 3; ++i) { + this.addSlot(this.processingOutputSlots[i] = new PatternOutputsSlot(output, this, i, 1), SlotSemantic.PROCESSING_RESULT); + this.processingOutputSlots[i].setRenderDisabled(false); + this.processingOutputSlots[i].setIcon(null); + } + + this.addSlot(this.blankPatternSlot = new RestrictedInputSlot(RestrictedInputSlot.PlacableItemType.BLANK_PATTERN, patternInv, 0), SlotSemantic.BLANK_PATTERN); + this.addSlot(this.encodedPatternSlot = new RestrictedInputSlot(RestrictedInputSlot.PlacableItemType.ENCODED_PATTERN, patternInv, 1), SlotSemantic.ENCODED_PATTERN); + this.encodedPatternSlot.setStackLimit(1); + this.createPlayerInventorySlots(ip); + this.config + .addConfig("combine", v -> { + this.combine = (boolean) v; + this.patternTerminal.setCombineMode((boolean) v); + }, () -> this.combine) + .addConfig("fluidFirst", v -> { + this.fluidFirst = (boolean) v; + this.patternTerminal.setFluidPlaceMode((boolean) v); + }, () -> this.fluidFirst) + .addConfig("craft", v -> { + this.craftingMode = (boolean) v; + this.patternTerminal.setCraftingRecipe((boolean) v); + }, () -> this.craftingMode) + .addConfig("substitute", v -> { + this.substitute = (boolean) v; + this.patternTerminal.setSubstitution((boolean) v); + }, () -> this.substitute) + .addConfig("encode", v -> this.encode(), + () -> {throw new IllegalArgumentException("Doesn't support operation!");}) + .addConfig("clear", v -> this.clear(), + () -> {throw new IllegalArgumentException("Doesn't support operation!");}); + + } + + @Override + public void putStackInSlot(int slotID, @Nonnull ItemStack stack) { + super.putStackInSlot(slotID, stack); + this.getAndUpdateOutput(); + } + + private ItemStack getAndUpdateOutput() { + World world = this.getPlayerInventory().player.world; + CraftingInventory ic = new CraftingInventory(this, 3, 3); + + for(int x = 0; x < ic.getSizeInventory(); ++x) { + ic.setInventorySlotContents(x, this.craftingGridInv.getStackInSlot(x)); + } + + if (this.currentRecipe == null || !this.currentRecipe.matches(ic, world)) { + this.currentRecipe = world.getRecipeManager().getRecipe(IRecipeType.CRAFTING, ic, world).orElse(null); + this.currentRecipeCraftingMode = this.craftingMode; + } + + ItemStack is; + if (this.currentRecipe == null) { + is = ItemStack.EMPTY; + } else { + is = this.currentRecipe.getCraftingResult(ic); + } + + this.craftOutputSlot.setDisplayedCraftingOutput(is); + return is; + } + + public void encode() { + if (checkHasFluidPattern()) { + this.encodeFluidPattern(); + } else { + this.encodeItemPattern(); + } + } + + public void encodeItemPattern() { + ItemStack output = this.encodedPatternSlot.getStack(); + ItemStack[] in = this.getInputs(); + ItemStack[] out = this.getOutputs(); + if (in != null && out != null && (!this.isCraftingMode() || this.currentRecipe != null)) { + if (output.isEmpty() || this.craftingHelper.isEncodedPattern(output)) { + if (output.isEmpty()) { + output = this.blankPatternSlot.getStack(); + if (output.isEmpty() || !isPattern(output)) { + return; + } + output.setCount(output.getCount() - 1); + if (output.getCount() == 0) { + this.blankPatternSlot.putStack(ItemStack.EMPTY); + } + output = null; + } else if (output.getItem() instanceof ItemFluidEncodedPattern) { + output = null; + } + if (this.isCraftingMode()) { + output = this.craftingHelper.encodeCraftingPattern(output, this.currentRecipe, in, out[0], this.isSubstitute()); + } else { + output = this.craftingHelper.encodeProcessingPattern(output, in, out); + } + this.encodedPatternSlot.putStack(output); + } + } + } + + private void encodeFluidPattern() { + ItemStack output = this.encodedPatternSlot.getStack(); + ItemStack[] in = this.getInputs(); + ItemStack[] out = this.getOutputs(); + if (in != null && out != null && (!this.isCraftingMode() || this.currentRecipe != null)) { + if (output.isEmpty() || this.craftingHelper.isEncodedPattern(output)) { + if (output.isEmpty()) { + output = this.blankPatternSlot.getStack(); + if (output.isEmpty() || !isPattern(output)) { + return; + } + output.setCount(output.getCount() - 1); + if (output.getCount() == 0) { + this.blankPatternSlot.putStack(ItemStack.EMPTY); + } + } + output = FCItems.DENSE_ENCODED_PATTERN.encodeStack(in, out); + this.encodedPatternSlot.putStack(output); + } + } + } + + private static boolean isPattern(final ItemStack output) { + if (output.isEmpty()) { + return false; + } + if (output.getItem() instanceof ItemFluidEncodedPattern) { + return true; + } + final IDefinitions defs = Api.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.craftingGridSlots) { + 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.processingOutputSlots) { + 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 ItemStack[] getInputs() { + ItemStack[] input = new ItemStack[9]; + boolean hasValue = false; + for(int x = 0; x < this.craftingGridSlots.length; ++x) { + input[x] = this.craftingGridSlots[x].getStack(); + if (!input[x].isEmpty()) { + hasValue = true; + } + } + return hasValue ? input : null; + } + + private ItemStack[] getOutputs() { + if (this.isCraftingMode()) { + ItemStack out = this.getAndUpdateOutput(); + if (!out.isEmpty() && out.getCount() > 0) { + return new ItemStack[] {out}; + } + } else { + boolean hasValue = false; + ItemStack[] list = new ItemStack[3]; + for(int i = 0; i < this.processingOutputSlots.length; ++i) { + ItemStack out = this.processingOutputSlots[i].getStack(); + list[i] = out; + if (!out.isEmpty()) { + hasValue = true; + } + } + if (hasValue) { + return list; + } + } + return null; + } + + public boolean isSlotEnabled(int idx) { + if (idx == 1) { + return this.isServer() ? !this.patternTerminal.isCraftingRecipe() : !this.isCraftingMode(); + } else if (idx == 2) { + return this.isServer() ? this.patternTerminal.isCraftingRecipe() : this.isCraftingMode(); + } else { + return false; + } + } + + public void craftOrGetItem(PatternSlotPacket packetPatternSlot) { + if (packetPatternSlot.slotItem != null && this.monitor != null) { + IAEItemStack out = packetPatternSlot.slotItem.copy(); + InventoryAdaptor inv = new AdaptorItemHandler(new WrapperCursorItemHandler(this.getPlayerInventory().player.inventory)); + InventoryAdaptor playerInv = InventoryAdaptor.getAdaptor(this.getPlayerInventory().player); + if (packetPatternSlot.shift) { + inv = playerInv; + } + + if (!inv.simulateAdd(out.createItemStack()).isEmpty()) { + return; + } + + IAEItemStack extracted = Platform.poweredExtraction(this.powerSource, this.monitor, out, this.getActionSource()); + PlayerEntity p = this.getPlayerInventory().player; + if (extracted != null) { + inv.addItems(extracted.createItemStack()); + if (p instanceof ServerPlayerEntity) { + this.updateHeld((ServerPlayerEntity)p); + } + + this.detectAndSendChanges(); + return; + } + + CraftingInventory ic = new CraftingInventory(new ContainerNull(), 3, 3); + CraftingInventory real = new CraftingInventory(new ContainerNull(), 3, 3); + + for(int x = 0; x < 9; ++x) { + ic.setInventorySlotContents(x, packetPatternSlot.pattern[x] == null ? ItemStack.EMPTY : packetPatternSlot.pattern[x].createItemStack()); + } + + IRecipe r = p.world.getRecipeManager().getRecipe(IRecipeType.CRAFTING, ic, p.world).orElse(null); + if (r == null) { + return; + } + + IMEMonitor storage = this.patternTerminal.getInventory(Api.instance().storage().getStorageChannel(IItemStorageChannel.class)); + IItemList all = storage.getStorageList(); + ItemStack is = r.getCraftingResult(ic); + + for(int x = 0; x < ic.getSizeInventory(); ++x) { + if (!ic.getStackInSlot(x).isEmpty()) { + ItemStack pulled = Platform.extractItemsByRecipe(this.powerSource, this.getActionSource(), storage, p.world, r, is, ic, ic.getStackInSlot(x), x, all, Actionable.MODULATE, ViewCellItem.createFilter(this.getViewCells())); + real.setInventorySlotContents(x, pulled); + } + } + + IRecipe rr = p.world.getRecipeManager().getRecipe(IRecipeType.CRAFTING, real, p.world).orElse(null); + if (rr == r && Platform.itemComparisons().isSameItem(rr.getCraftingResult(real), is)) { + CraftResultInventory craftingResult = new CraftResultInventory(); + craftingResult.setRecipeUsed(rr); + CraftingResultSlot sc = new CraftingResultSlot(p, real, craftingResult, 0, 0, 0); + sc.onTake(p, is); + + for(int x = 0; x < real.getSizeInventory(); ++x) { + ItemStack failed = playerInv.addItems(real.getStackInSlot(x)); + if (!failed.isEmpty()) { + p.dropItem(failed, false); + } + } + + inv.addItems(is); + if (p instanceof ServerPlayerEntity) { + this.updateHeld((ServerPlayerEntity)p); + } + + this.detectAndSendChanges(); + } else { + for(int x = 0; x < real.getSizeInventory(); ++x) { + ItemStack failed = real.getStackInSlot(x); + if (!failed.isEmpty()) { + this.monitor.injectItems(AEItemStack.fromItemStack(failed), Actionable.MODULATE, new MachineSource(this.patternTerminal)); + } + } + } + } + } + + public boolean isCraftingMode() { + return this.craftingMode; + } + + @Override + public void acceptPattern(Int2ObjectMap inputs, ItemStack[] outputs, boolean combine) { + this.patternTerminal.onChangeCrafting(inputs, outputs, combine); + } + + @Override + public void doAction(ServerPlayerEntity player, InventoryAction action, int slotId, long id) { + if (this.isCraftingMode()) { + super.doAction(player, action, slotId, id); + return; + } + if (slotId < 0 || slotId >= this.inventorySlots.size()) { + super.doAction(player, action, slotId, id); + return; + } + Slot slot = getSlot(slotId); + ItemStack stack = player.inventory.getItemStack(); + if ((slot instanceof FakeCraftingMatrixSlot || slot instanceof PatternOutputsSlot) && !stack.isEmpty() + && stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null).isPresent() && !FCUtil.getFluidFromItem(stack).isEmpty()) { + FluidStack fluid = FluidStack.EMPTY; + switch (action) { + case PICKUP_OR_SET_DOWN: + fluid = FCUtil.getFluidFromItem(stack); + slot.putStack(ItemFluidPacket.newStack(fluid)); + break; + case SPLIT_OR_PLACE_SINGLE: + fluid = FCUtil.getFluidFromItem(ItemHandlerHelper.copyStackWithSize(stack, 1)); + FluidStack origin = ItemFluidPacket.getFluidStack(slot.getStack()); + if (!fluid.isEmpty() && fluid.equals(origin)) { + fluid.grow(origin.getAmount()); + if (fluid.getAmount() <= 0) + fluid = FluidStack.EMPTY; + } + slot.putStack(ItemFluidPacket.newStack(fluid)); + break; + } + if (fluid.isEmpty()) { + super.doAction(player, action, slotId, id); + return; + } + return; + } + if (action == InventoryAction.SPLIT_OR_PLACE_SINGLE) { + if (stack.isEmpty() && !slot.getStack().isEmpty() && slot.getStack().getItem() instanceof ItemFluidPacket) { + FluidStack fluid = ItemFluidPacket.getFluidStack(slot.getStack()); + if (!fluid.isEmpty() && fluid.getAmount() - 1000 >= 1) { + fluid.shrink(1000); + slot.putStack(ItemFluidPacket.newStack(fluid)); + } + } + } + super.doAction(player, action, slotId, id); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + if (Platform.isServer()) { + if (this.isCraftingMode() != this.patternTerminal.isCraftingRecipe()) { + this.setCraftingMode(this.patternTerminal.isCraftingRecipe()); + } + this.substitute = this.patternTerminal.isSubstitution(); + this.combine = patternTerminal.getCombineMode(); + this.fluidFirst = patternTerminal.getFluidPlaceMode(); + } + } + + @Override + public void onServerDataSync() { + super.onServerDataSync(); + if (this.currentRecipeCraftingMode != this.craftingMode) { + this.getAndUpdateOutput(); + } + } + + @Override + public void onSlotChange(Slot s) { + if (s == this.encodedPatternSlot && isServer()) { + for (final IContainerListener listener : this.listeners) { + for (final Slot slot : this.inventorySlots) { + if (slot instanceof OptionalFakeSlot || slot instanceof FakeCraftingMatrixSlot) { + listener.sendSlotContents(this, slot.slotNumber, slot.getStack()); + } + } + if (listener instanceof ServerPlayerEntity) { + ((ServerPlayerEntity) listener).isChangingQuantityOnly = false; + } + } + this.detectAndSendChanges(); + } + + if (s == this.craftOutputSlot && isClient()) { + this.getAndUpdateOutput(); + } + } + + public void clear() { + for (final Slot s : this.craftingGridSlots) { + s.putStack(ItemStack.EMPTY); + } + + for (final Slot s : this.processingOutputSlots) { + s.putStack(ItemStack.EMPTY); + } + + this.detectAndSendChanges(); + this.getAndUpdateOutput(); + } + + @Override + public IItemHandler getInventoryByName(final String name) { + if (name.equals("player")) { + return new PlayerInvWrapper(this.getPlayerInventory()); + } + return this.patternTerminal.getInventoryByName(name); + } + + @Override + public boolean useRealItems() { + return false; + } + + private boolean isSubstitute() { + return this.substitute; + } + + private void setCraftingMode(boolean craftingMode) { + this.craftingMode = craftingMode; + } + + public void setSubstitute(boolean substitute) { + this.substitute = substitute; + } + + public FakeCraftingMatrixSlot[] getCraftingGridSlots() { + return this.craftingGridSlots; + } + + public OptionalFakeSlot[] getProcessingOutputSlots() { + return this.processingOutputSlots; + } + + public PatternTermSlot getCraftOutputSlot() { + return this.craftOutputSlot; + } + + public PartFluidPatternTerminal getPart() { + return this.patternTerminal; + } + + @Override + public void set(String id, Object value) { + this.config.setConfig(id, value); + } + + @Override + public Object get(String id) { + return this.config.getConfig(id); + } +} 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..ab128809b --- /dev/null +++ b/src/main/java/com/glodblock/github/client/container/ContainerIngredientBuffer.java @@ -0,0 +1,46 @@ +package com.glodblock.github.client.container; + +import appeng.container.AEBaseContainer; +import appeng.container.SlotSemantic; +import appeng.container.implementations.ContainerTypeBuilder; +import appeng.container.slot.AppEngSlot; +import com.glodblock.github.common.block.BlockIngredientBuffer; +import com.glodblock.github.interfaces.TankDumpable; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.ContainerType; +import net.minecraftforge.items.IItemHandler; + +public class ContainerIngredientBuffer extends AEBaseContainer implements TankDumpable { + + private final BlockIngredientBuffer.TileIngredientBuffer tile; + public static final ContainerType TYPE = ContainerTypeBuilder + .create(ContainerIngredientBuffer::new, BlockIngredientBuffer.TileIngredientBuffer.class) + .build("ingredient_buffer"); + + public ContainerIngredientBuffer(int id, PlayerInventory ip, BlockIngredientBuffer.TileIngredientBuffer tile) { + super(TYPE, id, ip, tile); + this.tile = tile; + IItemHandler inv = tile.getInternalInventory(); + for (int i = 0; i < 9; i++) { + addSlot(new AppEngSlot(inv, i), SlotSemantic.STORAGE); + } + createPlayerInventorySlots(ip); + } + + public BlockIngredientBuffer.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/ContainerItemDualInterface.java b/src/main/java/com/glodblock/github/client/container/ContainerItemDualInterface.java new file mode 100644 index 000000000..87ebc5558 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/container/ContainerItemDualInterface.java @@ -0,0 +1,121 @@ +package com.glodblock.github.client.container; + +import appeng.api.config.SecurityPermissions; +import appeng.api.config.Settings; +import appeng.api.config.YesNo; +import appeng.api.util.IConfigManager; +import appeng.container.SlotSemantic; +import appeng.container.guisync.GuiSync; +import appeng.container.implementations.ContainerTypeBuilder; +import appeng.container.implementations.UpgradeableContainer; +import appeng.container.slot.AppEngSlot; +import appeng.container.slot.FakeSlot; +import appeng.container.slot.RestrictedInputSlot; +import appeng.helpers.DualityInterface; +import appeng.helpers.IInterfaceHost; +import appeng.util.Platform; +import com.glodblock.github.interfaces.ConfigData; +import com.glodblock.github.coreutil.ExtendedInterface; +import com.glodblock.github.util.ConfigSet; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.ContainerType; + +public class ContainerItemDualInterface extends UpgradeableContainer implements ConfigData { + + @GuiSync(3) + public YesNo bMode; + @GuiSync(4) + public YesNo iTermMode; + @GuiSync(95) + public boolean fluidPacket = false; + @GuiSync(96) + public boolean allowSplitting = true; + @GuiSync(97) + public int blockModeEx = 0; + private final ConfigSet exConfig = new ConfigSet(); + private final DualityInterface dualityInterfaceCopy; + public static final ContainerType TYPE = ContainerTypeBuilder + .create(ContainerItemDualInterface::new, IInterfaceHost.class) + .build("dual_item_interface"); + + public ContainerItemDualInterface(int id, PlayerInventory ip, IInterfaceHost te) { + super(TYPE, id, ip, te.getInterfaceDuality().getHost()); + this.bMode = YesNo.NO; + this.iTermMode = YesNo.YES; + this.dualityInterfaceCopy = te.getInterfaceDuality(); + int x; + for (x = 0; x < 9; ++x) { + this.addSlot(new RestrictedInputSlot(RestrictedInputSlot.PlacableItemType.ENCODED_PATTERN, this.dualityInterfaceCopy.getPatterns(), x), SlotSemantic.ENCODED_PATTERN); + } + for (x = 0; x < 9; ++x) { + this.addSlot(new FakeSlot(this.dualityInterfaceCopy.getConfig(), x), SlotSemantic.CONFIG); + } + for (x = 0; x < 9; ++x) { + this.addSlot(new AppEngSlot(this.dualityInterfaceCopy.getStorage(), x), SlotSemantic.STORAGE); + } + this.exConfig + .addConfig("fluidPacket", v -> { + this.fluidPacket = (boolean) v; + ((ExtendedInterface) dualityInterfaceCopy).setFluidPacketMode((boolean) v); + }, () -> this.fluidPacket) + .addConfig("allowSplitting", v -> { + this.allowSplitting = (boolean) v; + ((ExtendedInterface) dualityInterfaceCopy).setSplittingMode((boolean) v); + }, () -> this.allowSplitting) + .addConfig("blockModeEx", v -> { + this.blockModeEx = (int) v; + ((ExtendedInterface) dualityInterfaceCopy).setExtendedBlockMode((int) v); + }, () -> this.blockModeEx); + } + + protected void setupConfig() { + this.setupUpgrades(); + } + + public int availableUpgrades() { + return 1; + } + + @Override + public void detectAndSendChanges() { + this.verifyPermissions(SecurityPermissions.BUILD, false); + super.detectAndSendChanges(); + if (Platform.isServer()) { + fluidPacket = ((ExtendedInterface) dualityInterfaceCopy).getFluidPacketMode(); + allowSplitting = ((ExtendedInterface) dualityInterfaceCopy).getSplittingMode(); + blockModeEx = ((ExtendedInterface) dualityInterfaceCopy).getExtendedBlockMode(); + } + } + + @Override + protected void loadSettingsFromHost(IConfigManager cm) { + this.setBlockingMode((YesNo)cm.getSetting(Settings.BLOCK)); + this.setInterfaceTerminalMode((YesNo)cm.getSetting(Settings.INTERFACE_TERMINAL)); + } + + public YesNo getBlockingMode() { + return this.bMode; + } + + private void setBlockingMode(YesNo bMode) { + this.bMode = bMode; + } + + public YesNo getInterfaceTerminalMode() { + return this.iTermMode; + } + + private void setInterfaceTerminalMode(YesNo iTermMode) { + this.iTermMode = iTermMode; + } + + @Override + public void set(String id, Object value) { + this.exConfig.setConfig(id, value); + } + + @Override + public Object get(String id) { + return this.exConfig.getConfig(id); + } +} diff --git a/src/main/java/com/glodblock/github/client/container/ContainerLargeIngredientBuffer.java b/src/main/java/com/glodblock/github/client/container/ContainerLargeIngredientBuffer.java new file mode 100644 index 000000000..b4e59a0cc --- /dev/null +++ b/src/main/java/com/glodblock/github/client/container/ContainerLargeIngredientBuffer.java @@ -0,0 +1,46 @@ +package com.glodblock.github.client.container; + +import appeng.container.AEBaseContainer; +import appeng.container.SlotSemantic; +import appeng.container.implementations.ContainerTypeBuilder; +import appeng.container.slot.AppEngSlot; +import com.glodblock.github.common.block.BlockLargeIngredientBuffer; +import com.glodblock.github.interfaces.TankDumpable; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.ContainerType; +import net.minecraftforge.items.IItemHandler; + +public class ContainerLargeIngredientBuffer extends AEBaseContainer implements TankDumpable { + + private final BlockLargeIngredientBuffer.TileLargeIngredientBuffer tile; + public static final ContainerType TYPE = ContainerTypeBuilder + .create(ContainerLargeIngredientBuffer::new, BlockLargeIngredientBuffer.TileLargeIngredientBuffer.class) + .build("large_ingredient_buffer"); + + public ContainerLargeIngredientBuffer(int id, PlayerInventory ip, BlockLargeIngredientBuffer.TileLargeIngredientBuffer tile) { + super(TYPE, id, ip, tile); + this.tile = tile; + IItemHandler inv = tile.getInternalInventory(); + for (int i = 0; i < 27; i++) { + addSlot(new AppEngSlot(inv, i), SlotSemantic.STORAGE); + } + createPlayerInventorySlots(ip); + } + + public BlockLargeIngredientBuffer.TileLargeIngredientBuffer 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); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/client/model/FluidEncodedPatternModel.java b/src/main/java/com/glodblock/github/client/model/FluidEncodedPatternModel.java new file mode 100644 index 000000000..d1c3dd5f7 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/model/FluidEncodedPatternModel.java @@ -0,0 +1,66 @@ +package com.glodblock.github.client.model; + +import appeng.items.misc.EncodedPatternItem; +import com.glodblock.github.util.Ae2ReflectClient; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.mojang.datafixers.util.Pair; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.renderer.color.IItemColor; +import net.minecraft.client.renderer.model.*; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.item.ItemStack; +import net.minecraft.resources.IResourceManager; +import net.minecraft.util.JSONUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.IModelConfiguration; +import net.minecraftforge.client.model.IModelLoader; +import net.minecraftforge.client.model.geometry.IModelGeometry; + +import javax.annotation.Nonnull; +import java.util.Collection; +import java.util.Set; +import java.util.function.Function; + +public class FluidEncodedPatternModel implements IModelGeometry { + private final ResourceLocation baseModel; + + public FluidEncodedPatternModel(ResourceLocation baseModel) { + this.baseModel = baseModel; + } + + public static final IItemColor PATTERN_ITEM_COLOR_HANDLER = (stack, tintIndex) -> { + EncodedPatternItem iep = (EncodedPatternItem) stack.getItem(); + ItemStack output = iep.getOutput(stack); + if (!output.isEmpty() && Screen.hasShiftDown()) { + return Minecraft.getInstance().getItemColors().getColor(output, tintIndex); + } + return 0xFFFFFF; + }; + + public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) { + return modelGetter.apply(this.baseModel).getTextures(modelGetter, missingTextureErrors); + } + + public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, IModelTransform modelTransform, ItemOverrideList overrides, ResourceLocation modelLocation) { + IBakedModel baseModel = bakery.getBakedModel(this.baseModel, modelTransform, spriteGetter); + return Ae2ReflectClient.bakeEncodedPatternModel(baseModel); + } + + public static class Loader implements IModelLoader { + + @Override + public void onResourceManagerReload(@Nonnull IResourceManager iResourceManager) { + // NO-OP + } + + @Nonnull + @Override + public FluidEncodedPatternModel read(@Nonnull JsonDeserializationContext jsonDeserializationContext, @Nonnull JsonObject jsonObject) { + jsonObject.remove("loader"); + ResourceLocation baseModel = new ResourceLocation(JSONUtils.getString(jsonObject, "baseModel")); + return new FluidEncodedPatternModel(baseModel); + } + } +} 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..5d24bb962 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/model/FluidPacketModel.java @@ -0,0 +1,183 @@ +package com.glodblock.github.client.model; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.client.renderer.model.*; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.LivingEntity; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.Fluids; +import net.minecraft.item.ItemStack; +import net.minecraft.resources.IResourceManager; +import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.vector.TransformationMatrix; +import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.client.model.*; +import net.minecraftforge.client.model.geometry.IModelGeometry; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.resource.IResourceType; +import net.minecraftforge.resource.VanillaResourceType; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Predicate; + +import static net.minecraftforge.fluids.FluidAttributes.BUCKET_VOLUME; + +// Adapted from https://github.com/CoFH/ThermalInnovation/blob/1.16.5/src/main/java/cofh/thermal/innovation/client/model/FluidReservoirItemModel.java +public class FluidPacketModel implements IModelGeometry { + + // minimal Z offset to prevent depth-fighting + private static final float NORTH_Z_FLUID = 7.498F / 16F; + private static final float SOUTH_Z_FLUID = 8.502F / 16F; + + @Nonnull + private final FluidStack fluidStack; + private final boolean isDisplay; + + public FluidPacketModel(@Nonnull FluidStack fluidStack, boolean display) { + this.fluidStack = fluidStack; + this.isDisplay = display; + } + + public FluidPacketModel set(@Nonnull FluidStack fluidStack, boolean display) { + return new FluidPacketModel(fluidStack, display); + } + + @Override + public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, IModelTransform modelTransform, ItemOverrideList overrides, ResourceLocation modelLocation) { + + RenderMaterial particleLocation = owner.isTexturePresent("particle") ? owner.resolveTexture("particle") : null; + RenderMaterial fluidMaskLocation = owner.resolveTexture("layer0"); + RenderMaterial background = owner.resolveTexture("layer1"); + + IModelTransform transformsFromModel = owner.getCombinedTransform(); + Fluid fluid = fluidStack.getFluid(); + + TextureAtlasSprite fluidSprite; + if (fluidStack.isEmpty()) { + fluidSprite = spriteGetter.apply(ForgeHooksClient.getBlockMaterial(Fluids.WATER.getAttributes().getStillTexture())); + } else { + fluidSprite = spriteGetter.apply(ForgeHooksClient.getBlockMaterial(fluid.getAttributes().getStillTexture())); + } + ImmutableMap transformMap = PerspectiveMapWrapper.getTransforms(new ModelTransformComposition(transformsFromModel, modelTransform)); + + TextureAtlasSprite particleSprite = particleLocation != null ? spriteGetter.apply(particleLocation) : null; + if (particleSprite == null) particleSprite = fluidSprite; + if (particleSprite == null) particleSprite = spriteGetter.apply(background); + + TransformationMatrix transform = modelTransform.getRotation(); + ItemMultiLayerBakedModel.Builder builder = ItemMultiLayerBakedModel.builder(owner, particleSprite, new ContainedFluidOverrideHandler(bakery, owner, this), transformMap); + + if (!isDisplay) { + builder.addQuads(ItemLayerModel.getLayerRenderType(false), ItemLayerModel.getQuadsForSprite(0, spriteGetter.apply(background), transform)); + } + + if (fluidSprite != null) { + TextureAtlasSprite templateSprite = spriteGetter.apply(fluidMaskLocation); + int luminosity = fluid.getAttributes().getLuminosity(fluidStack); + int color = fluid.getAttributes().getColor(fluidStack); + if (isDisplay) { + builder.addQuads(ItemLayerModel.getLayerRenderType(luminosity > 0), ItemTextureQuadConverter.genQuad(transform, 0F, 0F, 16F, 16F, NORTH_Z_FLUID, fluidSprite, Direction.NORTH, color, 2, luminosity)); + builder.addQuads(ItemLayerModel.getLayerRenderType(luminosity > 0), ItemTextureQuadConverter.genQuad(transform, 0F, 0F, 16F, 16F, SOUTH_Z_FLUID, fluidSprite, Direction.SOUTH, color, 2, luminosity)); + } else if (templateSprite != null) { + builder.addQuads(ItemLayerModel.getLayerRenderType(luminosity > 0), ItemTextureQuadConverter.convertTexture(transform, templateSprite, fluidSprite, NORTH_Z_FLUID, Direction.NORTH, color, 2, luminosity)); + builder.addQuads(ItemLayerModel.getLayerRenderType(luminosity > 0), ItemTextureQuadConverter.convertTexture(transform, templateSprite, fluidSprite, SOUTH_Z_FLUID, Direction.SOUTH, color, 2, luminosity)); + } + } + builder.setParticle(particleSprite); + return builder.build(); + } + + @Override + public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) { + Set texs = Sets.newHashSet(); + if (owner.isTexturePresent("particle")) { + texs.add(owner.resolveTexture("particle")); + } + if (owner.isTexturePresent("fluid_mask")) { + texs.add(owner.resolveTexture("fluid_mask")); + } + if (owner.isTexturePresent("background")) { + texs.add(owner.resolveTexture("background")); + } + return texs; + } + + public static class Loader implements IModelLoader { + + @Override + public IResourceType getResourceType() { + return VanillaResourceType.MODELS; + } + + @Override + public void onResourceManagerReload(@Nonnull IResourceManager resourceManager) { + // NO-OP + } + + @Override + public void onResourceManagerReload(@Nonnull IResourceManager resourceManager, @Nonnull Predicate resourcePredicate) { + // NO-OP + } + + @Nonnull + @Override + public FluidPacketModel read(@Nonnull JsonDeserializationContext deserializationContext, JsonObject modelContents) { + FluidStack stack = FluidStack.EMPTY; + if (modelContents.has("fluid")) { + ResourceLocation fluidName = new ResourceLocation(modelContents.get("fluid").getAsString()); + Fluid fluid = ForgeRegistries.FLUIDS.getValue(fluidName); + if (fluid != null) { + stack = new FluidStack(fluid, BUCKET_VOLUME); + } + } + // create new model with correct liquid + return new FluidPacketModel(stack, false); + } + + } + + private static final class ContainedFluidOverrideHandler extends ItemOverrideList { + + private final Object2ObjectMap, IBakedModel> cache = new Object2ObjectOpenHashMap<>(); // contains all the baked models since they'll never change + private final ModelBakery bakery; + private final IModelConfiguration owner; + private final FluidPacketModel parent; + + private ContainedFluidOverrideHandler(ModelBakery bakery, IModelConfiguration owner, FluidPacketModel parent) { + this.bakery = bakery; + this.owner = owner; + this.parent = parent; + } + + @Override + public IBakedModel getOverrideModel(@Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable ClientWorld world, @Nullable LivingEntity entity) { + FluidStack fluidStack = ItemFluidPacket.getFluidStack(stack); + boolean display = ItemFluidPacket.isDisplay(stack); + Pair p = new Pair<>(fluidStack.getFluid().getRegistryName(), display); + if (!cache.containsKey(p)) { + FluidPacketModel unbaked = this.parent.set(fluidStack, display); + IBakedModel bakedModel = unbaked.bake(owner, bakery, ModelLoader.defaultTextureGetter(), ModelRotation.X0_Y0, this, FluidCraft.resource("fluid_packet_override")); + cache.put(p, bakedModel); + return bakedModel; + } + return cache.get(p); + } + + } + +} 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..acf05dbff --- /dev/null +++ b/src/main/java/com/glodblock/github/client/render/DropColourHandler.java @@ -0,0 +1,61 @@ +package com.glodblock.github.client.render; + +import com.glodblock.github.util.FluidRenderUtils; +import com.glodblock.github.util.HashUtil; +import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenCustomHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.fluid.Fluid; +import net.minecraft.inventory.container.PlayerContainer; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fluids.FluidStack; + +public class DropColourHandler { + + public static final DropColourHandler INSTANCE = new DropColourHandler(); + private final Object2IntMap colourCache = new Object2IntLinkedOpenCustomHashMap<>(HashUtil.FLUID); + + @SubscribeEvent + public void onTextureMapStitch(TextureStitchEvent event) { + if (event.getMap().getTextureLocation().equals(PlayerContainer.LOCATION_BLOCKS_TEXTURE)) { + colourCache.clear(); + } + } + + public int getColour(FluidStack fluidStack) { + Fluid fluid = fluidStack.getFluid(); + int colour = fluid.getAttributes().getColor(fluidStack); + return colour != 0xFFFFFFFF ? colour : getColour(fluid); + } + + public int getColour(Fluid fluid) { + boolean isCached = colourCache.containsKey(fluid); + if (isCached) { + return colourCache.getOrDefault(fluid, 0xFFFFFFFF); + } + int colour = fluid.getAttributes().getColor(); + if (colour == 0xFFFFFFFF) { + TextureAtlasSprite sprite = FluidRenderUtils.prepareRender(fluid); + if (sprite != null && sprite.getFrameCount() > 0) { + int r = 0, g = 0, b = 0, count = 0; + for (int row = 0; row < sprite.getHeight(); row ++) + for (int col = 0; col < sprite.getWidth(); col ++) { + int pixel = sprite.getPixelRGBA(0, row, col); + if (((pixel >>> 24) & 0xFF) > 127) { // is alpha above 50%? + r += (pixel) & 0xFF; + g += (pixel >>> 8) & 0xFF; + b += (pixel >>> 16) & 0xFF; + ++count; + } + } + if (count > 0) { + colour = ((r / count) << 16) | ((g / count) << 8) | (b / count); + } + } + } + colourCache.put(fluid, colour); + return colour; + } + +} 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..cb02a3e2c --- /dev/null +++ b/src/main/java/com/glodblock/github/client/render/RenderIngredientBuffer.java @@ -0,0 +1,55 @@ +package com.glodblock.github.client.render; + +import com.glodblock.github.common.tile.TileSimpleBuffer; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.platform.GlStateManager; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.client.renderer.model.ItemCameraTransforms; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.renderer.tileentity.TileEntityRenderer; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; +import net.minecraft.inventory.container.PlayerContainer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.vector.Vector3f; +import net.minecraftforge.items.IItemHandler; + +import javax.annotation.Nonnull; + +public class RenderIngredientBuffer extends TileEntityRenderer { + + public RenderIngredientBuffer(TileEntityRendererDispatcher dispatcher) { + super(dispatcher); + } + + @Override + public void render(@Nonnull TileSimpleBuffer tile, float partialTicks, @Nonnull MatrixStack matrixStackIn, @Nonnull IRenderTypeBuffer bufferIn, int combinedLightIn, int combinedOverlayIn) { + GlStateManager.enableBlend(); + GlStateManager.blendFunc( + GlStateManager.SourceFactor.SRC_ALPHA.param, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA.param + ); + GlStateManager.enableLighting(); + matrixStackIn.push(); + matrixStackIn.translate(0.5D, 0.25D, 0.5D); + renderDispatcher.textureManager.bindTexture(PlayerContainer.LOCATION_BLOCKS_TEXTURE); + ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer(); + IItemHandler inv = tile.getInternalInventory(); + for (int i = 0; i < inv.getSlots(); i++) { + ItemStack stack = inv.getStackInSlot(i); + if (!stack.isEmpty()) { + matrixStackIn.push(); + matrixStackIn.rotate(Vector3f.YP.rotation((renderDispatcher.world.getGameTime() + partialTicks) / 20.0F)); + itemRenderer.renderItem(stack, ItemCameraTransforms.TransformType.GROUND, combinedLightIn, OverlayTexture.NO_OVERLAY, matrixStackIn, bufferIn); + matrixStackIn.pop(); + break; + } + } + + GlStateManager.color4f(1F, 1F, 1F, 1F); + GlStateManager.disableLighting(); + matrixStackIn.pop(); + } + +} diff --git a/src/main/java/com/glodblock/github/client/slot/SlotSingleItem.java b/src/main/java/com/glodblock/github/client/slot/SlotSingleItem.java new file mode 100644 index 000000000..a8cd8cef6 --- /dev/null +++ b/src/main/java/com/glodblock/github/client/slot/SlotSingleItem.java @@ -0,0 +1,114 @@ +package com.glodblock.github.client.slot; + +import com.mojang.datafixers.util.Pair; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.container.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +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 PlayerEntity 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); + } + + @Nullable + @OnlyIn(Dist.CLIENT) + @Override + public Pair getBackground() { + return this.delegate.getBackground(); + } + + @Override + @Nonnull + public ItemStack decrStackSize(int amount) { + return delegate.decrStackSize(amount); + } + + @Override + public boolean canTakeStack(@Nonnull PlayerEntity playerIn) { + return delegate.canTakeStack(playerIn); + } + + @OnlyIn(Dist.CLIENT) + @Override + public boolean isEnabled() { + return delegate.isEnabled(); + } + + @Override + public int getSlotIndex() { + return delegate.getSlotIndex(); + } + + @Override + public boolean isSameInventory(@Nonnull Slot other) { + return delegate.isSameInventory(other); + } + + @Nonnull + @Override + public Slot setBackground(@Nonnull ResourceLocation rl1, @Nonnull ResourceLocation rl2) { + return delegate.setBackground(rl1, rl2); + } + +} 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..f03f2f144 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/block/BlockDualInterface.java @@ -0,0 +1,81 @@ +package com.glodblock.github.common.block; + +import appeng.api.util.IOrientable; +import appeng.block.AEBaseTileBlock; +import appeng.container.ContainerLocator; +import appeng.container.ContainerOpener; +import appeng.util.Platform; +import com.glodblock.github.client.container.ContainerItemDualInterface; +import com.glodblock.github.common.tile.TileDualInterface; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.material.Material; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.state.BooleanProperty; +import net.minecraft.state.DirectionProperty; +import net.minecraft.state.StateContainer; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.EnumSet; + +public class BlockDualInterface extends AEBaseTileBlock { + + private static final BooleanProperty OMNIDIRECTIONAL = BooleanProperty.create("omnidirectional"); + private static final DirectionProperty FACING = DirectionProperty.create("facing", EnumSet.allOf(Direction.class)); + + public BlockDualInterface() { + super(defaultProps(Material.IRON)); + this.setTileEntity(TileDualInterface.class, TileDualInterface::new); + } + + @Override + public ActionResultType onActivated(World w, BlockPos pos, PlayerEntity p, Hand hand, @Nullable ItemStack heldItem, BlockRayTraceResult hit) { + if (p.isSneaking()) { + return ActionResultType.PASS; + } + final TileDualInterface tg = this.getTileEntity(w, pos); + if (tg != null) { + if (Platform.isServer()) { + ContainerOpener.openContainer( + ContainerItemDualInterface.TYPE, + p, + ContainerLocator.forTileEntitySide(tg, hit.getFace()) + ); + } + return ActionResultType.func_233537_a_(w.isRemote); + } + return ActionResultType.PASS; + } + + @Override + protected void fillStateContainer(@Nonnull StateContainer.Builder builder) { + super.fillStateContainer(builder); + builder.add(OMNIDIRECTIONAL, FACING); + } + + @Override + protected BlockState updateBlockStateFromTileEntity(BlockState currentState, TileDualInterface te) { + return currentState.with(OMNIDIRECTIONAL, te.isOmniDirectional()).with(FACING, te.getForward()); + } + + @Override + protected boolean hasCustomRotation() { + return true; + } + + @Override + protected void customRotateBlock(final IOrientable rotatable, final Direction axis) { + if (rotatable instanceof TileDualInterface) { + ((TileDualInterface) rotatable).setSide(axis); + } + } + +} \ No newline at end of file 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..dc157ee1e --- /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(defaultProps(Material.IRON)); + setTileEntity(TileFluidDiscretizer.class, TileFluidDiscretizer::new); + } + +} 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..cc5a40aa7 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/block/BlockFluidPacketDecoder.java @@ -0,0 +1,43 @@ +package com.glodblock.github.common.block; + +import appeng.block.AEBaseTileBlock; +import appeng.container.ContainerLocator; +import appeng.container.ContainerOpener; +import com.glodblock.github.client.container.ContainerFluidPacketDecoder; +import com.glodblock.github.common.tile.TileFluidPacketDecoder; +import net.minecraft.block.BlockState; +import net.minecraft.block.material.Material; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.world.World; + +public class BlockFluidPacketDecoder extends AEBaseTileBlock { + + public BlockFluidPacketDecoder() { + super(defaultProps(Material.IRON)); + setTileEntity(TileFluidPacketDecoder.class, TileFluidPacketDecoder::new); + } + + @Override + public ActionResultType onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit) { + if (player.isSneaking()) { + return super.onBlockActivated(state, world, pos, player, hand, hit); + } + TileFluidPacketDecoder tile = this.getTileEntity(world, pos); + if (tile != null) { + if (!world.isRemote) { + ContainerOpener.openContainer( + ContainerFluidPacketDecoder.TYPE, + player, + ContainerLocator.forTileEntitySide(tile, hit.getFace()) + ); + } + return ActionResultType.func_233537_a_(world.isRemote); + } + return super.onBlockActivated(state, world, pos, player, hand, hit); + } + +} 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..9520edc18 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/block/BlockIngredientBuffer.java @@ -0,0 +1,64 @@ +package com.glodblock.github.common.block; + +import appeng.block.AEBaseTileBlock; +import appeng.container.ContainerLocator; +import appeng.container.ContainerOpener; +import appeng.fluids.util.AEFluidInventory; +import appeng.tile.inventory.AppEngInternalInventory; +import com.glodblock.github.client.container.ContainerIngredientBuffer; +import com.glodblock.github.common.tile.TileSimpleBuffer; +import com.glodblock.github.loader.FCBlocks; +import com.glodblock.github.util.FCUtil; +import net.minecraft.block.BlockState; +import net.minecraft.block.material.Material; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.world.World; + +public class BlockIngredientBuffer extends AEBaseTileBlock { + + public BlockIngredientBuffer() { + super(defaultProps(Material.IRON).setOpaque((x, y, z) -> false).notSolid()); + setTileEntity(TileIngredientBuffer.class, TileIngredientBuffer::new); + } + + @Override + public ActionResultType onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit) { + if (player.isSneaking()) { + return super.onBlockActivated(state, world, pos, player, hand, hit); + } + TileIngredientBuffer tile = this.getTileEntity(world, pos); + if (tile != null) { + if (!world.isRemote) { + ContainerOpener.openContainer( + ContainerIngredientBuffer.TYPE, + player, + ContainerLocator.forTileEntitySide(tile, hit.getFace()) + ); + } + return ActionResultType.func_233537_a_(world.isRemote); + } + return super.onBlockActivated(state, world, pos, player, hand, hit); + } + + public static class TileIngredientBuffer extends TileSimpleBuffer { + + public TileIngredientBuffer() { + super(FCUtil.getTileType(TileIngredientBuffer.class, FCBlocks.INGREDIENT_BUFFER)); + } + + @Override + protected AppEngInternalInventory createItemBuffer() { + return new AppEngInternalInventory(this, 9); + } + + @Override + protected AEFluidInventory createFluidBuffer() { + return new AEFluidInventory(this, 4, 16000); + } + } + +} diff --git a/src/main/java/com/glodblock/github/common/block/BlockLargeIngredientBuffer.java b/src/main/java/com/glodblock/github/common/block/BlockLargeIngredientBuffer.java new file mode 100644 index 000000000..bcc9a9562 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/block/BlockLargeIngredientBuffer.java @@ -0,0 +1,64 @@ +package com.glodblock.github.common.block; + +import appeng.block.AEBaseTileBlock; +import appeng.container.ContainerLocator; +import appeng.container.ContainerOpener; +import appeng.fluids.util.AEFluidInventory; +import appeng.tile.inventory.AppEngInternalInventory; +import com.glodblock.github.client.container.ContainerLargeIngredientBuffer; +import com.glodblock.github.common.tile.TileSimpleBuffer; +import com.glodblock.github.loader.FCBlocks; +import com.glodblock.github.util.FCUtil; +import net.minecraft.block.BlockState; +import net.minecraft.block.material.Material; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.world.World; + +public class BlockLargeIngredientBuffer extends AEBaseTileBlock { + + public BlockLargeIngredientBuffer() { + super(defaultProps(Material.IRON).setOpaque((x, y, z) -> false).notSolid()); + setTileEntity(TileLargeIngredientBuffer.class, TileLargeIngredientBuffer::new); + } + + @Override + public ActionResultType onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit) { + if (player.isSneaking()) { + return super.onBlockActivated(state, world, pos, player, hand, hit); + } + TileLargeIngredientBuffer tile = this.getTileEntity(world, pos); + if (tile != null) { + if (!world.isRemote) { + ContainerOpener.openContainer( + ContainerLargeIngredientBuffer.TYPE, + player, + ContainerLocator.forTileEntitySide(tile, hit.getFace()) + ); + } + return ActionResultType.func_233537_a_(world.isRemote); + } + return super.onBlockActivated(state, world, pos, player, hand, hit); + } + + public static class TileLargeIngredientBuffer extends TileSimpleBuffer { + + public TileLargeIngredientBuffer() { + super(FCUtil.getTileType(TileLargeIngredientBuffer.class, FCBlocks.LARGE_INGREDIENT_BUFFER)); + } + + @Override + protected AppEngInternalInventory createItemBuffer() { + return new AppEngInternalInventory(this, 27); + } + + @Override + protected AEFluidInventory createFluidBuffer() { + return new AEFluidInventory(this, 7, 16000); + } + } + +} \ No newline at end of file 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..dd9360b89 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemFluidDrop.java @@ -0,0 +1,140 @@ +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.fluid.Fluid; +import net.minecraft.fluid.Fluids; +import net.minecraft.item.Item; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.World; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.registries.ForgeRegistries; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; + +import static com.glodblock.github.loader.FCItems.defaultProps; + +public class ItemFluidDrop extends Item { + + public ItemFluidDrop() { + super(defaultProps()); + } + + @Override + public void fillItemGroup(@Nonnull ItemGroup tab, @Nonnull NonNullList items) { + if (isInGroup(tab)) { + items.add(newStack(new FluidStack(Fluids.WATER, 1))); + items.add(newStack(new FluidStack(Fluids.LAVA, 1))); + } + } + + @Override + @Nonnull + public ITextComponent getDisplayName(@Nonnull ItemStack stack) { + FluidStack fluid = getFluidStack(stack); + return new TranslationTextComponent(getTranslationKey(stack), + !fluid.isEmpty() ? fluid.getDisplayName() : "???" + ); + } + + @Override + public void addInformation(@Nonnull ItemStack stack, @Nullable World worldIn, @Nonnull List tooltip, @Nonnull ITooltipFlag flagIn) { + FluidStack fluid = getFluidStack(stack); + if (!fluid.isEmpty()) { + tooltip.add(new TranslationTextComponent("%s, 1 mB", fluid.getDisplayName()).mergeStyle(TextFormatting.GRAY)); + } else { + tooltip.add(new TranslationTextComponent(NameConst.TT_INVALID_FLUID).mergeStyle(TextFormatting.RED)); + } + } + + @Nonnull + public static FluidStack getFluidStack(ItemStack stack) { + if (stack.isEmpty() || stack.getItem() != FCItems.FLUID_DROP || !stack.hasTag()) { + return FluidStack.EMPTY; + } + CompoundNBT tag = Objects.requireNonNull(stack.getTag()); + if (!tag.contains("Fluid", Constants.NBT.TAG_STRING)) { + return FluidStack.EMPTY; + } + Fluid fluid = ForgeRegistries.FLUIDS.getValue(new ResourceLocation(tag.getString("Fluid"))); + if (fluid == null || fluid == Fluids.EMPTY) { + return FluidStack.EMPTY; + } + FluidStack fluidStack = new FluidStack(fluid, stack.getCount()); + if (tag.contains("FluidTag", Constants.NBT.TAG_COMPOUND)) { + fluidStack.setTag(tag.getCompound("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; + } + + @Nonnull + public static ItemStack newStack(@Nonnull FluidStack fluid) { + if (fluid.isEmpty()) { + return ItemStack.EMPTY; + } + ItemStack stack = new ItemStack(FCItems.FLUID_DROP, fluid.getAmount()); + CompoundNBT tag = new CompoundNBT(); + tag.putString("Fluid", String.valueOf(fluid.getFluid().getRegistryName())); + if (fluid.hasTag()) { + tag.put("FluidTag", fluid.getTag()); + } + stack.setTag(tag); + return stack; + } + + @Nullable + public static IAEItemStack newAeStack(@Nonnull FluidStack fluid) { + if (fluid.isEmpty()) { + return null; + } + IAEItemStack stack = AEItemStack.fromItemStack(newStack(fluid)); + if (stack == null) { + return null; + } + stack.setStackSize(fluid.getAmount()); + 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..d1e1b7bfc --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemFluidEncodedPattern.java @@ -0,0 +1,206 @@ +package com.glodblock.github.common.item; + +import appeng.api.networking.crafting.ICraftingPatternDetails; +import appeng.api.storage.data.IAEItemStack; +import appeng.core.Api; +import appeng.core.localization.GuiText; +import appeng.items.misc.EncodedPatternItem; +import appeng.util.Platform; +import appeng.util.item.AEItemStack; +import com.glodblock.github.interfaces.HasCustomModel; +import com.glodblock.github.loader.FCItems; +import com.glodblock.github.util.FluidPatternDetails; +import com.glodblock.github.util.InvalidFCPatternHelper; +import com.glodblock.github.util.NameConst; +import com.google.common.base.Preconditions; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fluids.FluidStack; + +import java.util.Collection; +import java.util.List; + +import static com.glodblock.github.loader.FCItems.defaultProps; + +public class ItemFluidEncodedPattern extends EncodedPatternItem implements HasCustomModel { + + public ItemFluidEncodedPattern() { + super(defaultProps()); + } + + @OnlyIn(Dist.CLIENT) + @Override + public void addInformation(ItemStack stack, World world, List lines, ITooltipFlag advancedTooltips) { + final ICraftingPatternDetails details = Api.instance().crafting().decodePattern(stack, world); + if (details == null) { + if (!stack.hasTag()) { + return; + } + stack.setDisplayName(GuiText.InvalidPattern.text().deepCopy().mergeStyle(TextFormatting.RED)); + InvalidFCPatternHelper invalid = new InvalidFCPatternHelper(stack); + final ITextComponent label = (GuiText.Creates.text()).deepCopy().appendString(": "); + final ITextComponent and = new StringTextComponent(" ").deepCopy().appendSibling(GuiText.And.text()) + .deepCopy() + .appendString(" "); + final ITextComponent with = GuiText.With.text().deepCopy().appendString(": "); + boolean first = true; + for (final InvalidFCPatternHelper.PatternIngredient output : invalid.getOutputs()) { + lines.add((first ? label : and).deepCopy().appendSibling(output.getFormattedToolTip())); + first = false; + } + + first = true; + for (final InvalidFCPatternHelper.PatternIngredient input : invalid.getInputs()) { + lines.add((first ? with : and).deepCopy().appendSibling(input.getFormattedToolTip())); + first = false; + } + return; + } + + if (stack.hasDisplayName()) { + stack.removeChildTag("display"); + } + + final boolean isCrafting = details.isCraftable(); + final boolean substitute = details.canSubstitute(); + + final Collection in = details.getInputs(); + final Collection out = details.getOutputs(); + + final ITextComponent label = (isCrafting ? GuiText.Crafts.text() : GuiText.Creates.text()).deepCopy() + .appendString(": "); + final ITextComponent and = new StringTextComponent(" ").deepCopy().appendSibling(GuiText.And.text()) + .appendString(" "); + final ITextComponent with = GuiText.With.text().deepCopy().appendString(": "); + + boolean first = true; + for (final IAEItemStack anOut : out) { + if (anOut == null) { + continue; + } + + lines.add((first ? label : and).deepCopy().appendString(anOut.getStackSize() + "x ") + .appendSibling(Platform.getItemDisplayName(anOut))); + first = false; + } + + first = true; + for (final IAEItemStack anIn : in) { + if (anIn == null) { + continue; + } + + lines.add((first ? with : and).deepCopy().appendString(anIn.getStackSize() + "x ") + .appendSibling(Platform.getItemDisplayName(anIn))); + first = false; + } + + if (isCrafting) { + final ITextComponent substitutionLabel = GuiText.Substitute.text().deepCopy().appendString(" "); + final ITextComponent canSubstitute = substitute ? GuiText.Yes.text() : GuiText.No.text(); + + lines.add(substitutionLabel.deepCopy().appendSibling(canSubstitute)); + } + } + + public ICraftingPatternDetails getDetails(ItemStack stack) { + return FluidPatternDetails.fromPattern(stack); + } + + @Override + public boolean isEncodedPattern(ItemStack itemStack) { + return itemStack != null && !itemStack.isEmpty() && itemStack.getItem() instanceof ItemFluidEncodedPattern && itemStack.getTag() != null && itemStack.getTag().contains("in") && itemStack.getTag().contains("out"); + } + + @Override + public ItemStack getOutput(ItemStack item) { + ICraftingPatternDetails d = getDetails(item); + if (d == null) { + return ItemStack.EMPTY; + } else { + return d.getOutputs().size() > 0 ? + d.getOutputs().get(0).createItemStack() : + ItemStack.EMPTY; + } + } + + @Override + public ResourceLocation getCraftingRecipeId(ItemStack itemStack) { + return null; + } + + @Override + public List getIngredients(ItemStack itemStack) { + ICraftingPatternDetails d = getDetails(itemStack); + Preconditions.checkArgument(d != null, "Invalid fluid pattern inputs!"); + return d.getInputs(); + } + + @Override + public List getProducts(ItemStack itemStack) { + ICraftingPatternDetails d = getDetails(itemStack); + Preconditions.checkArgument(d != null, "Invalid fluid pattern outputs!"); + return d.getOutputs(); + } + + @Override + public boolean allowsSubstitution(ItemStack itemStack) { + return false; + } + + @Override + public ResourceLocation getCustomModelPath() { + return NameConst.MODEL_DENSE_ENCODED_PATTERN; + } + + public ItemStack encodeStack(ItemStack[] inputs, ItemStack[] outputs) { + ItemStack pattern = new ItemStack(FCItems.DENSE_ENCODED_PATTERN); + ListNBT tagIn = new ListNBT(); + ListNBT tagOut = new ListNBT(); + CompoundNBT v = new CompoundNBT(); + for (ItemStack stack : inputs) { + tagIn.add(encodeNBT(stack)); + } + for (ItemStack stack : outputs) { + tagOut.add(encodeNBT(stack)); + } + v.put("in", tagIn); + v.put("out", tagOut); + pattern.setTag(v); + return pattern; + } + + private CompoundNBT encodeNBT(ItemStack stack) { + if (stack.isEmpty()) { + return new CompoundNBT(); + } else { + CompoundNBT tag = new CompoundNBT(); + if (stack.getItem() instanceof ItemFluidPacket) { + FluidStack fluid = ItemFluidPacket.getFluidStack(stack); + if (!fluid.isEmpty()) { + IAEItemStack drop = ItemFluidDrop.newAeStack(fluid); + if (drop != null) { + drop.writeToNBT(tag); + } + } + } else { + IAEItemStack aeStack = AEItemStack.fromItemStack(stack); + if (aeStack != null) { + aeStack.writeToNBT(tag); + } + } + return tag; + } + } + +} 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..cca028ec7 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemFluidPacket.java @@ -0,0 +1,130 @@ +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.item.Item; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.TranslationTextComponent; +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; + +import static com.glodblock.github.loader.FCItems.defaultProps; + +public class ItemFluidPacket extends Item implements HasCustomModel { + + public ItemFluidPacket() { + super(defaultProps().maxStackSize(1)); + } + + @Override + public void fillItemGroup(@Nonnull ItemGroup tab, @Nonnull NonNullList items) { + // NO-OP + } + + @Override + @Nonnull + public ITextComponent getDisplayName(@Nonnull ItemStack stack) { + FluidStack fluid = getFluidStack(stack); + boolean display = isDisplay(stack); + if (display) { + return !fluid.isEmpty() ? fluid.getDisplayName() : super.getDisplayName(stack); + } + return !fluid.isEmpty() ? + new TranslationTextComponent(NameConst.TT_FLUID_PACKET_INFO, fluid.getDisplayName(), String.format("%,d", fluid.getAmount())) + : super.getDisplayName(stack); + } + + @Override + public void addInformation(@Nonnull ItemStack stack, @Nullable World worldIn, @Nonnull List tooltip, @Nonnull ITooltipFlag flagIn) { + FluidStack fluid = getFluidStack(stack); + boolean display = isDisplay(stack); + if (display) return; + if (!fluid.isEmpty()) { + tooltip.add(new TranslationTextComponent(NameConst.TT_FLUID_PACKET).mergeStyle(TextFormatting.GRAY)); + } else { + tooltip.add(new TranslationTextComponent(NameConst.TT_INVALID_FLUID).mergeStyle(TextFormatting.RED)); + } + } + + @Nonnull + public static FluidStack getFluidStack(ItemStack stack) { + if (stack.isEmpty() || !stack.hasTag()) { + return FluidStack.EMPTY; + } + return FluidStack.loadFluidStackFromNBT(Objects.requireNonNull(stack.getTag()).getCompound("FluidStack")); + } + + public static boolean isDisplay(ItemStack stack) { + if (stack.isEmpty() || !stack.hasTag()) { + return false; + } + assert stack.getTag() != null; + return stack.getTag().getBoolean("DisplayOnly"); + } + + @Nonnull + public static FluidStack getFluidStack(@Nullable IAEItemStack stack) { + return stack != null ? getFluidStack(stack.getDefinition()) : FluidStack.EMPTY; + } + + @Nonnull + public static ItemStack newStack(@Nonnull FluidStack fluid) { + if (fluid.isEmpty()) { + return ItemStack.EMPTY; + } + ItemStack stack = new ItemStack(FCItems.FLUID_PACKET); + CompoundNBT tag = new CompoundNBT(); + CompoundNBT fluidTag = new CompoundNBT(); + fluid.writeToNBT(fluidTag); + tag.put("FluidStack", fluidTag); + stack.setTag(tag); + return stack; + } + + @Nonnull + public static ItemStack newDisplayStack(@Nonnull FluidStack fluid) { + if (fluid.isEmpty()) { + return ItemStack.EMPTY; + } + FluidStack copy = fluid.copy(); + copy.setAmount(1000); + ItemStack stack = new ItemStack(FCItems.FLUID_PACKET); + CompoundNBT tag = new CompoundNBT(); + CompoundNBT fluidTag = new CompoundNBT(); + copy.writeToNBT(fluidTag); + tag.put("FluidStack", fluidTag); + tag.putBoolean("DisplayOnly", true); + stack.setTag(tag); + return stack; + } + + @Nullable + public static IAEItemStack newAeStack(@Nonnull FluidStack fluid) { + return AEItemStack.fromItemStack(newStack(fluid)); + } + + @Override + public ResourceLocation getCustomModelPath() { + return NameConst.MODEL_FLUID_PACKET; + } + + public static boolean isFluidPacket(ItemStack is) { + return !is.isEmpty() && is.getItem() instanceof ItemFluidPacket; + } + +} \ 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..172548205 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemPartDualInterface.java @@ -0,0 +1,41 @@ +package com.glodblock.github.common.item; + +import appeng.api.parts.IPartItem; +import appeng.core.Api; +import com.glodblock.github.common.part.PartDualInterface; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUseContext; +import net.minecraft.util.ActionResultType; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import static com.glodblock.github.loader.FCItems.defaultProps; + +public class ItemPartDualInterface extends Item implements IPartItem { + + public ItemPartDualInterface() { + super(defaultProps()); + } + + @Nullable + @Override + public PartDualInterface createPart(ItemStack is) { + return new PartDualInterface(is); + } + + @Override + @Nonnull + public ActionResultType onItemUse(@Nonnull ItemUseContext context) { + return Api.instance().partHelper().placeBus( + context.getItem(), + context.getPos(), + context.getFace(), + context.getPlayer(), + context.getHand(), + context.getWorld() + ); + } + +} 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..812b44c31 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/item/ItemPartFluidPatternTerminal.java @@ -0,0 +1,41 @@ +package com.glodblock.github.common.item; + +import appeng.api.parts.IPartItem; +import appeng.core.Api; +import com.glodblock.github.common.part.PartFluidPatternTerminal; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUseContext; +import net.minecraft.util.ActionResultType; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import static com.glodblock.github.loader.FCItems.defaultProps; + +public class ItemPartFluidPatternTerminal extends Item implements IPartItem { + + public ItemPartFluidPatternTerminal() { + super(defaultProps()); + } + + @Nullable + @Override + public PartFluidPatternTerminal createPart(ItemStack is) { + return new PartFluidPatternTerminal(is); + } + + @Override + @Nonnull + public ActionResultType onItemUse(@Nonnull ItemUseContext context) { + return Api.instance().partHelper().placeBus( + context.getItem(), + context.getPos(), + context.getFace(), + context.getPlayer(), + context.getHand(), + context.getWorld() + ); + } + +} diff --git a/src/main/java/com/glodblock/github/common/me/DualityDualInterface.java b/src/main/java/com/glodblock/github/common/me/DualityDualInterface.java new file mode 100644 index 000000000..fcdbc2f0c --- /dev/null +++ b/src/main/java/com/glodblock/github/common/me/DualityDualInterface.java @@ -0,0 +1,204 @@ +package com.glodblock.github.common.me; + +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.fluids.util.AEFluidInventory; +import appeng.helpers.DualityInterface; +import appeng.helpers.IInterfaceHost; +import appeng.me.helpers.AENetworkProxy; +import appeng.util.SettingsFrom; +import appeng.util.inv.InvOperation; +import com.google.common.collect.ImmutableSet; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.Direction; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.capability.IFluidHandler; +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) + fluidDuality.getInstalledUpgrades(u); + } + + public int getPriority() { + return itemDuality.getPriority(); // both interfaces should always have the same priority + } + + public void setPriority(final int newValue) { + itemDuality.setPriority(newValue); + fluidDuality.setPriority(newValue); + } + + @Nonnull + @Override + public LazyOptional getCapability(@Nonnull Capability capability, @Nullable Direction facing) { + LazyOptional capInst = itemDuality.getCapability(capability, facing); + return capInst.isPresent() ? 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(); + } + + 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, CraftingInventory 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 CompoundNBT data) { + CompoundNBT itemIfaceTag = new CompoundNBT(), fluidIfaceTag = new CompoundNBT(); + itemDuality.writeToNBT(itemIfaceTag); + fluidDuality.writeToNBT(fluidIfaceTag); + data.put("itemDuality", itemIfaceTag); + data.put("fluidDuality", fluidIfaceTag); + } + + public void readFromNBT(final CompoundNBT data) { + itemDuality.readFromNBT(data.getCompound("itemDuality")); + fluidDuality.readFromNBT(data.getCompound("fluidDuality")); + } + + public CompoundNBT downloadSettings(SettingsFrom from) { + CompoundNBT tag = new CompoundNBT(); + if (from == SettingsFrom.MEMORY_CARD) { + final IFluidHandler fluidInv = this.fluidDuality.getFluidInventoryByName("config"); + if (fluidInv instanceof AEFluidInventory) { + ((AEFluidInventory) fluidInv).writeToNBT(tag, "fluid_config"); + } + } + return tag; + } + + public void uploadSettings(SettingsFrom from, CompoundNBT compound) { + final IFluidHandler fluidInv = this.fluidDuality.getFluidInventoryByName("config"); + if (from == SettingsFrom.MEMORY_CARD && fluidInv instanceof AEFluidInventory) { + AEFluidInventory target = (AEFluidInventory) fluidInv; + AEFluidInventory tmp = new AEFluidInventory(null, target.getSlots()); + tmp.readFromNBT(compound, "fluid_config"); + for(int x = 0; x < tmp.getSlots(); x++) { + target.setFluidInSlot(x, tmp.getFluidInSlot(x)); + } + } + } + +} 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..a407b7069 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/part/PartDualInterface.java @@ -0,0 +1,261 @@ +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.container.ContainerLocator; +import appeng.container.ContainerOpener; +import appeng.fluids.helper.DualityFluidInterface; +import appeng.fluids.helper.IFluidInterfaceHost; +import appeng.helpers.DualityInterface; +import appeng.helpers.IInterfaceHost; +import appeng.helpers.IPriorityHost; +import appeng.items.parts.PartModels; +import appeng.parts.BasicStatePart; +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.client.container.ContainerItemDualInterface; +import com.glodblock.github.common.me.DualityDualInterface; +import com.glodblock.github.loader.FCItems; +import com.google.common.collect.ImmutableSet; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.inventory.container.ContainerType; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.IItemHandler; + +import javax.annotation.Nonnull; +import java.util.EnumSet; +import java.util.List; + +public class PartDualInterface extends BasicStatePart + implements IGridTickable, IInventoryDestination, IInterfaceHost, IAEAppEngInventory, IPriorityHost, 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); + + 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 CompoundNBT data) { + super.readFromNBT(data); + duality.readFromNBT(data); + } + + @Override + public void writeToNBT(final CompoundNBT 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(PlayerEntity player, Hand hand, Vector3d pos) { + if (Platform.isServer()) { + ContainerOpener.openContainer(ContainerItemDualInterface.TYPE, player, ContainerLocator.forPart(this)); + } + 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 CraftingInventory 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); + } + + @Nonnull + @Override + public LazyOptional getCapability(Capability capabilityClass) { + return duality.getCapability(capabilityClass, getSide().getFacing()); + } + + @Override + public ItemStack getItemStackRepresentation() { + return new ItemStack(FCItems.PART_DUAL_INTERFACE, 1); + } + + @Override + public ContainerType getContainerType() { + return ContainerItemDualInterface.TYPE; + } + + @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; + } + } + +} 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..3caf53a89 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/part/PartFluidPatternTerminal.java @@ -0,0 +1,175 @@ +package com.glodblock.github.common.part; + +import appeng.api.config.SecurityPermissions; +import appeng.api.networking.crafting.ICraftingPatternDetails; +import appeng.api.parts.IPartModel; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; +import appeng.container.me.items.ItemTerminalContainer; +import appeng.items.parts.PartModels; +import appeng.parts.PartModel; +import appeng.parts.reporting.PatternTerminalPart; +import appeng.tile.inventory.AppEngInternalInventory; +import appeng.util.Platform; +import appeng.util.inv.InvOperation; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.container.ContainerFluidPatternTerminal; +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.util.FCUtil; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.container.ContainerType; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.IItemHandlerModifiable; + +import javax.annotation.Nonnull; + +public class PartFluidPatternTerminal extends PatternTerminalPart { + + private boolean combine = false; + private boolean fluidFirst = false; + private final AppEngInternalInventory crafting; + private final AppEngInternalInventory output; + private final AppEngInternalInventory pattern; + + @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); + this.crafting = (AppEngInternalInventory) getInventoryByName("crafting"); + this.output = (AppEngInternalInventory) getInventoryByName("output"); + this.pattern = (AppEngInternalInventory) getInventoryByName("pattern"); + } + + @Nonnull + @Override + public IPartModel getStaticModels() { + return this.selectModel(MODELS_OFF, MODELS_ON, MODELS_HAS_CHANNEL); + } + + @Override + public void readFromNBT(CompoundNBT data) { + super.readFromNBT(data); + combine = data.getBoolean("combineMode"); + fluidFirst = data.getBoolean("fluidFirst"); + } + + public void setCombineMode(boolean value) { + this.combine = value; + } + + public boolean getCombineMode() { + return this.combine; + } + + public void setFluidPlaceMode(boolean value) { + this.fluidFirst = value; + } + + public boolean getFluidPlaceMode() { + return this.fluidFirst; + } + + @Override + public void writeToNBT(CompoundNBT data) { + super.writeToNBT(data); + data.putBoolean("combineMode", combine); + data.putBoolean("fluidFirst", fluidFirst); + } + + @Override + public ContainerType getContainerType(PlayerEntity p) { + return Platform.checkPermissions(p, this, SecurityPermissions.CRAFT, false) ? + ContainerFluidPatternTerminal.TYPE : ItemTerminalContainer.TYPE; + } + + @Override + public void onChangeInventory(IItemHandler inv, int slot, InvOperation mc, ItemStack removedStack, + ItemStack newStack) { + if (slot == 1 && inv == this.pattern) { + final ItemStack is = inv.getStackInSlot(1); + if (!is.isEmpty() && is.getItem() instanceof ItemFluidEncodedPattern) { + final ItemFluidEncodedPattern pattern = (ItemFluidEncodedPattern) is.getItem(); + final ICraftingPatternDetails details = pattern.getDetails(is); + if(details != null) { + this.setCraftingRecipe(details.isCraftable()); + this.setSubstitution(details.canSubstitute()); + for(int x = 0; x < this.crafting.getSlots(); x ++) { + this.crafting.setStackInSlot(x, ItemStack.EMPTY); + } + for(int x = 0; x < this.output.getSlots(); x ++) { + this.output.setStackInSlot(x, ItemStack.EMPTY); + } + putPattern(details.getInputs().toArray(new IAEItemStack[0]), details.getOutputs().toArray(new IAEItemStack[0])); + } + this.getHost().markForSave(); + return; + } + } + super.onChangeInventory(inv, slot, mc, removedStack, newStack); + } + + public void onChangeCrafting(Int2ObjectMap inputs, ItemStack[] outputs, boolean combine) { + IItemHandler crafting = this.getInventoryByName("crafting"); + IItemHandler output = this.getInventoryByName("output"); + IItemList storageList = this.getInventory(FCUtil.ITEM) == null ? + null : this.getInventory(FCUtil.ITEM).getStorageList(); + if (crafting instanceof AppEngInternalInventory && output instanceof AppEngInternalInventory) { + FCUtil.clearItemInventory((IItemHandlerModifiable) crafting); + FCUtil.clearItemInventory((IItemHandlerModifiable) output); + ItemStack[] fuzzyFind = new ItemStack[FCUtil.findMax(inputs.keySet()) + 1]; + for (int index : inputs.keySet()) { + FCUtil.fuzzyTransferItems(index, inputs.get(index), fuzzyFind, storageList); + } + if (combine && !this.isCraftingRecipe()) { + fuzzyFind = FCUtil.compress(fuzzyFind); + } + int bound = Math.min(crafting.getSlots(), fuzzyFind.length); + for (int x = 0; x < bound; x++) { + final ItemStack item = fuzzyFind[x]; + ((AppEngInternalInventory) crafting).setStackInSlot(x, item == null ? ItemStack.EMPTY : item); + } + bound = Math.min(output.getSlots(), outputs.length); + for (int x = 0; x < bound; x++) { + final ItemStack item = outputs[x]; + ((AppEngInternalInventory) output).setStackInSlot(x, item == null ? ItemStack.EMPTY : item); + } + } + } + + public void putPattern(IAEItemStack[] inputs, IAEItemStack[] outputs) { + for( int x = 0; x < this.getInventoryByName("crafting").getSlots() && x < inputs.length; x++ ) + { + final IAEItemStack item = inputs[x]; + if (item != null && item.getItem() instanceof ItemFluidDrop) { + ItemStack packet = ItemFluidPacket.newStack(ItemFluidDrop.getFluidStack(item.createItemStack())); + ((AppEngInternalInventory) this.getInventoryByName("crafting")).setStackInSlot(x, packet); + } + else ((AppEngInternalInventory) this.getInventoryByName("crafting")).setStackInSlot( x, item == null ? ItemStack.EMPTY : item.createItemStack() ); + } + + for( int x = 0; x < this.getInventoryByName("output").getSlots() && x < outputs.length; x++ ) + { + final IAEItemStack item = outputs[x]; + if (item != null && item.getItem() instanceof ItemFluidDrop) { + ItemStack packet = ItemFluidPacket.newStack(ItemFluidDrop.getFluidStack(item.createItemStack())); + ((AppEngInternalInventory) this.getInventoryByName("output")).setStackInSlot(x, packet); + } + else ((AppEngInternalInventory) this.getInventoryByName("output")).setStackInSlot( x, item == null ? ItemStack.EMPTY : item.createItemStack() ); + } + } + +} 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..349eae179 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/tile/TileDualInterface.java @@ -0,0 +1,327 @@ +package com.glodblock.github.common.tile; + +import appeng.api.config.Actionable; +import appeng.api.config.Upgrades; +import appeng.api.networking.GridFlags; +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.helpers.IPriorityHost; +import appeng.tile.grid.AENetworkInvTileEntity; +import appeng.util.Platform; +import appeng.util.SettingsFrom; +import appeng.util.inv.IInventoryDestination; +import appeng.util.inv.InvOperation; +import com.glodblock.github.client.container.ContainerItemDualInterface; +import com.glodblock.github.common.me.DualityDualInterface; +import com.glodblock.github.loader.FCBlocks; +import com.glodblock.github.util.FCUtil; +import com.google.common.collect.ImmutableSet; +import net.minecraft.block.BlockState; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.inventory.container.ContainerType; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.PacketBuffer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +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 AENetworkInvTileEntity + implements IGridTickable, IInventoryDestination, IInterfaceHost, IPriorityHost, IFluidInterfaceHost { + + public TileDualInterface() { + super(FCUtil.getTileType(TileDualInterface.class, FCBlocks.DUAL_INTERFACE)); + getProxy().setIdlePowerUsage(4D); + getProxy().setFlags(GridFlags.REQUIRE_CHANNEL); + } + + 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 Direction facing) { + if (Platform.isClient()) { + return; + } + + Direction 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(Direction.NORTH, Direction.UP); + } else { + Direction newUp = Direction.UP; + if (newForward == Direction.UP || newForward == Direction.DOWN) { + newUp = Direction.NORTH; + } + this.setOrientation(newForward, newUp); + } + + this.configureNodeSides(); + this.markForUpdate(); + this.saveChanges(); + } + + private void configureNodeSides() { + if (this.omniDirectional) { + this.getProxy().setValidSides(EnumSet.allOf(Direction.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 CompoundNBT write(final CompoundNBT data) { + super.write(data); + data.putBoolean("omniDirectional", this.omniDirectional); + duality.writeToNBT(data); + return data; + } + + @Override + public void read(BlockState blockState, CompoundNBT data) { + super.read(blockState, data); + this.omniDirectional = data.getBoolean("omniDirectional"); + duality.readFromNBT(data); + } + + @Override + protected boolean readFromStream(PacketBuffer 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(PacketBuffer 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(Direction.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 CraftingInventory 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; + } + + @Nonnull + @Override + public LazyOptional getCapability(@Nonnull Capability capability, @Nullable Direction facing) { + LazyOptional capInst = duality.getCapability(capability, facing); + return capInst.isPresent() ? capInst : super.getCapability(capability, facing); + } + + @Override + public ItemStack getItemStackRepresentation() { + return new ItemStack(FCBlocks.DUAL_INTERFACE); + } + + @Override + public ContainerType getContainerType() { + return ContainerItemDualInterface.TYPE; + } + + @Override + public CompoundNBT downloadSettings(SettingsFrom from) { + CompoundNBT pre = super.downloadSettings(from); + CompoundNBT tag = pre == null ? new CompoundNBT() : pre; + tag.put("pattern", this.duality.downloadSettings(from)); + return tag.isEmpty() ? null : tag; + } + + @Override + public void uploadSettings(SettingsFrom from, CompoundNBT compound) { + super.uploadSettings(from, compound); + if (compound.contains("pattern")) { + this.duality.uploadSettings(from, compound.getCompound("pattern")); + } + } + +} 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..c3949b740 --- /dev/null +++ b/src/main/java/com/glodblock/github/common/tile/TileFluidDiscretizer.java @@ -0,0 +1,288 @@ +package com.glodblock.github.common.tile; + +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.*; +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.cells.ICellContainer; +import appeng.api.storage.cells.ICellInventory; +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; +import appeng.me.GridAccessException; +import appeng.me.cache.CraftingGridCache; +import appeng.me.helpers.MachineSource; +import appeng.me.storage.MEInventoryHandler; +import appeng.tile.grid.AENetworkTileEntity; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.loader.FCBlocks; +import com.glodblock.github.util.FCUtil; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; + +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.List; + +public class TileFluidDiscretizer extends AENetworkTileEntity 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; + + public TileFluidDiscretizer() { + super(FCUtil.getTileType(TileFluidDiscretizer.class, FCBlocks.FLUID_DISCRETIZER)); + 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 == FCUtil.ITEM) { + return Collections.singletonList(fluidDropInv.invHandler); + } else if (channel == FCUtil.FLUID) { + return Collections.singletonList(fluidCraftInv.invHandler); + } + } + return Collections.emptyList(); + } + + @Override + public void saveChanges(@Nullable ICellInventory cellInventory) { + if (world != null) { + 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(); + } + + @MENetworkEventSubscribe + public void onStorageUpdate(MENetworkStorageEvent 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(FCUtil.FLUID); + } catch (GridAccessException e) { + return null; + } + } + + private class FluidDiscretizingInventory implements IMEInventory, IMEMonitorHandlerReceiver { + + private final MEInventoryHandler invHandler = new MEInventoryHandler<>(this, getChannel()); + @Nullable + private ObjectArrayList 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(fluidGrid.extractItems(fluidStack, mode, ownActionSource)); + } + + @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(fluidGrid.injectItems(fluidStack, type, ownActionSource)); + } + + @Override + public IItemList getAvailableItems(IItemList out) { + if (itemCache == null) { + itemCache = new ObjectArrayList<>(); + 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 { + ObjectArrayList mappedChanges = new ObjectArrayList<>(); + for (IAEFluidStack fluidStack : change) { + boolean isNg = false; + if (fluidStack.getStackSize() < 0) { + isNg = true; + fluidStack.setStackSize( - fluidStack.getStackSize() ); + } + IAEItemStack itemStack = ItemFluidDrop.newAeStack(fluidStack); + if (itemStack != null) { + if (isNg) itemStack.setStackSize( - itemStack.getStackSize() ); + 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 FCUtil.ITEM; + } + + } + + 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 FCUtil.FLUID; + } + + } + +} 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..99fa7e24c --- /dev/null +++ b/src/main/java/com/glodblock/github/common/tile/TileFluidPacketDecoder.java @@ -0,0 +1,125 @@ +package com.glodblock.github.common.tile; + +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.data.IAEFluidStack; +import appeng.fluids.util.AEFluidStack; +import appeng.me.GridAccessException; +import appeng.me.helpers.MachineSource; +import appeng.tile.grid.AENetworkTileEntity; +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 com.glodblock.github.loader.FCBlocks; +import com.glodblock.github.util.FCUtil; +import net.minecraft.block.BlockState; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.Direction; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.IItemHandlerModifiable; + +import javax.annotation.Nonnull; + +public class TileFluidPacketDecoder extends AENetworkTileEntity implements IGridTickable, IAEAppEngInventory { + + private final AppEngInternalInventory inventory = new AppEngInternalInventory(this, 1); + private final IActionSource ownActionSource = new MachineSource(this); + + public TileFluidPacketDecoder() { + super(FCUtil.getTileType(TileFluidPacketDecoder.class, FCBlocks.FLUID_PACKET_DECODER)); + getProxy().setIdlePowerUsage(1.5D); + getProxy().setFlags(GridFlags.REQUIRE_CHANNEL); + } + + public IItemHandlerModifiable getInventory() { + return inventory; + } + + @Override + public boolean canBeRotated() { + return false; + } + + @Nonnull + @SuppressWarnings("unchecked") + @Override + public LazyOptional getCapability(@Nonnull Capability capability, Direction facing) { + if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return LazyOptional.of(() -> (T)inventory); + } else { + return LazyOptional.empty(); + } + } + + @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.isEmpty()) { + 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(FCUtil.FLUID); + 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 CompoundNBT write(CompoundNBT data) { + super.write(data); + inventory.writeToNBT(data, "Inventory"); + return data; + } + + @Override + public void read(BlockState blockState, CompoundNBT data) { + super.read(blockState, data); + inventory.readFromNBT(data, "Inventory"); + } + +} diff --git a/src/main/java/com/glodblock/github/common/tile/TileSimpleBuffer.java b/src/main/java/com/glodblock/github/common/tile/TileSimpleBuffer.java new file mode 100644 index 000000000..fbb87203e --- /dev/null +++ b/src/main/java/com/glodblock/github/common/tile/TileSimpleBuffer.java @@ -0,0 +1,102 @@ +package com.glodblock.github.common.tile; + +import appeng.fluids.util.AEFluidInventory; +import appeng.fluids.util.IAEFluidInventory; +import appeng.fluids.util.IAEFluidTank; +import appeng.tile.AEBaseInvTileEntity; +import appeng.tile.inventory.AppEngInternalInventory; +import appeng.util.inv.InvOperation; +import com.glodblock.github.util.FCUtil; +import net.minecraft.block.BlockState; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.PacketBuffer; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; + +import javax.annotation.Nonnull; +import java.io.IOException; + +public abstract class TileSimpleBuffer extends AEBaseInvTileEntity implements IAEFluidInventory { + + private final AppEngInternalInventory invItems = createItemBuffer(); + private final AEFluidInventory invFluids = createFluidBuffer(); + + public TileSimpleBuffer(TileEntityType type) { + super(type); + } + + abstract protected AppEngInternalInventory createItemBuffer(); + + abstract protected AEFluidInventory createFluidBuffer(); + + @Nonnull + @Override + public IItemHandler getInternalInventory() { + return invItems; + } + + public IAEFluidTank getFluidInventory() { + return invFluids; + } + + @Override + public boolean canBeRotated() { + return false; + } + + @Nonnull + @SuppressWarnings("unchecked") + @Override + public LazyOptional getCapability(@Nonnull Capability capability, Direction facing) { + if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return LazyOptional.of(() -> (T)invItems); + } else if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { + return LazyOptional.of(() -> (T)invFluids); + } + return super.getCapability(capability, facing); + } + + @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(PacketBuffer data) throws IOException { + super.writeToStream(data); + FCUtil.writeFluidInventoryToBuffer(invFluids, data); + } + + @Override + protected boolean readFromStream(PacketBuffer data) throws IOException { + boolean changed = super.readFromStream(data); + changed |= FCUtil.readFluidInventoryToBuffer(invFluids, data); + return changed; + } + + @Override + public void read(BlockState blockState, CompoundNBT data) { + super.read(blockState, data); + invFluids.readFromNBT(data, "FluidInv"); + } + + @Override + public CompoundNBT write(CompoundNBT data) { + super.write(data); + invFluids.writeToNBT(data, "FluidInv"); + return data; + } + +} diff --git a/src/main/java/com/glodblock/github/coreutil/ExtendedInterface.java b/src/main/java/com/glodblock/github/coreutil/ExtendedInterface.java new file mode 100644 index 000000000..a13ed3612 --- /dev/null +++ b/src/main/java/com/glodblock/github/coreutil/ExtendedInterface.java @@ -0,0 +1,29 @@ +package com.glodblock.github.coreutil; + +public interface ExtendedInterface { + + default boolean getFluidPacketMode() { + return false; + } + + default void setFluidPacketMode(boolean value) { + + } + + default boolean getSplittingMode() { + return false; + } + + default void setSplittingMode(boolean value) { + + } + + default int getExtendedBlockMode() { + return 0; + } + + default void setExtendedBlockMode(int value) { + + } + +} 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..8ba35a870 --- /dev/null +++ b/src/main/java/com/glodblock/github/handler/ButtonMouseHandler.java @@ -0,0 +1,49 @@ +package com.glodblock.github.handler; + +import com.glodblock.github.interfaces.TankDumpable; +import com.glodblock.github.network.NetworkManager; +import com.glodblock.github.network.packets.CPacketDumpTank; +import com.glodblock.github.util.MouseRegionManager; +import com.glodblock.github.util.NameConst; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; + +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(new TranslationTextComponent(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)) { + NetworkManager.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..67e9188d9 --- /dev/null +++ b/src/main/java/com/glodblock/github/handler/ClientRegistryHandler.java @@ -0,0 +1,66 @@ +package com.glodblock.github.handler; + +import appeng.core.Api; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.*; +import com.glodblock.github.client.container.*; +import com.glodblock.github.client.model.FluidEncodedPatternModel; +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 com.glodblock.github.loader.FCBlocks; +import com.glodblock.github.util.Ae2ReflectClient; +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.RenderTypeLookup; +import net.minecraft.client.renderer.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.eventbus.api.SubscribeEvent; +import org.apache.commons.lang3.tuple.Pair; + +public class ClientRegistryHandler extends RegistryHandler { + + public static final ClientRegistryHandler INSTANCE = new ClientRegistryHandler(); + + @Override + public void onInit() { + RenderTypeLookup.setRenderLayer(FCBlocks.INGREDIENT_BUFFER, RenderType.getCutout()); + RenderTypeLookup.setRenderLayer(FCBlocks.LARGE_INGREDIENT_BUFFER, RenderType.getCutout()); + Ae2ReflectClient.registerAEGui(ContainerIngredientBuffer.TYPE, GuiIngredientBuffer::new, "/screens/ingredient_buffer.json"); + Ae2ReflectClient.registerAEGui(ContainerLargeIngredientBuffer.TYPE, GuiLargeIngredientBuffer::new, "/screens/large_ingredient_buffer.json"); + Ae2ReflectClient.registerAEGui(ContainerItemDualInterface.TYPE, GuiItemDualInterface::new, "/screens/dual_item_interface.json"); + Ae2ReflectClient.registerAEGui(ContainerFluidDualInterface.TYPE, GuiFluidDualInterface::new, "/screens/dual_fluid_interface.json"); + Ae2ReflectClient.registerAEGui(ContainerFluidPatternTerminal.TYPE, GuiFluidPatternTerminal::new, "/screens/fluid_pattern_terminal.json"); + Ae2ReflectClient.registerAEGui(ContainerFluidPacketDecoder.TYPE, GuiFluidPacketDecoder::new, "/screens/fluid_packet_decoder.json"); + Ae2ReflectClient.registerAEGui(ContainerFCPriority.TYPE, GuiFCPriority::new, "/screens/fc_priority.json"); + } + + @SubscribeEvent + public void onRegisterModels(ModelRegistryEvent event) { + ModelLoaderRegistry.registerLoader(FluidCraft.resource("fluid_encoded_pattern"), new FluidEncodedPatternModel.Loader()); + //ModelLoaderRegistry.registerLoader(new DenseCraftEncodedPatternModel.Loader()); + ModelLoaderRegistry.registerLoader(FluidCraft.resource("fluid_packet"), new FluidPacketModel.Loader()); + for (Pair entry : blocks) { + registerModel(entry.getLeft(), entry.getRight().asItem()); + } + for (Pair entry : items) { + registerModel(entry.getLeft(), entry.getRight()); + } + + Api.instance().registries().partModels().registerModels(PartDualInterface.MODELS); + Api.instance().registries().partModels().registerModels(PartFluidPatternTerminal.MODELS); + //AEApi.instance().registries().partModels().registerModels(PartExtendedFluidPatternTerminal.MODELS); + } + + private static void registerModel(String key, Item item) { + ModelLoader.addSpecialModel(new ModelResourceLocation( + item instanceof HasCustomModel ? + ((HasCustomModel)item).getCustomModelPath() : FluidCraft.resource(key), + "inventory")); + } + +} 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..18a49c4e1 --- /dev/null +++ b/src/main/java/com/glodblock/github/handler/RegistryHandler.java @@ -0,0 +1,106 @@ +package com.glodblock.github.handler; + +import appeng.block.AEBaseBlockItem; +import appeng.block.AEBaseTileBlock; +import appeng.core.features.ActivityState; +import appeng.core.features.BlockStackSrc; +import appeng.tile.AEBaseTileEntity; +import com.glodblock.github.FluidCraft; +import com.glodblock.github.client.container.*; +import com.glodblock.github.loader.FCItems; +import com.glodblock.github.util.FCUtil; +import net.minecraft.block.Block; +import net.minecraft.inventory.container.ContainerType; +import net.minecraft.item.Item; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.registries.ForgeRegistries; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.ArrayList; +import java.util.List; + +public class RegistryHandler { + + public static final RegistryHandler INSTANCE = new RegistryHandler(); + protected final List> blocks = new ArrayList<>(); + protected final List> items = new ArrayList<>(); + protected final List>> tiles = new ArrayList<>(); + + public void block(String name, Block block) { + blocks.add(Pair.of(name, block)); + if (block instanceof AEBaseTileBlock) { + AEBaseTileBlock tileBlock = (AEBaseTileBlock) block; + tile(name, tileBlock.getTileEntityClass(), block); + } + } + + public void item(String name, Item item) { + items.add(Pair.of(name, item)); + } + + public void tile(String name, Class clazz, Block block) { + tiles.add(Pair.of(name, FCUtil.getTileType(clazz, block))); + } + + @SubscribeEvent + public void onRegisterBlocks(RegistryEvent.Register event) { + for (Pair entry : blocks) { + String key = entry.getLeft(); + Block block = entry.getRight(); + block.setRegistryName(key); + event.getRegistry().register(block); + } + } + + @SubscribeEvent + public void onRegisterItems(RegistryEvent.Register event) { + for (Pair entry : blocks) { + event.getRegistry().register(initItem(entry.getLeft(), new AEBaseBlockItem(entry.getRight(), new Item.Properties().group(FCItems.TAB_AE2FC)))); + } + for (Pair entry : items) { + event.getRegistry().register(initItem(entry.getLeft(), entry.getRight())); + } + } + + @SubscribeEvent + public void onRegisterTileEntities(RegistryEvent.Register> event) { + for (Pair> entry : tiles) { + String key = entry.getLeft(); + TileEntityType tile = entry.getRight(); + tile.setRegistryName(key); + event.getRegistry().register(tile); + } + } + + @SubscribeEvent + public void onRegisterContainerTypes(RegistryEvent.Register> event) { + event.getRegistry().register(ContainerIngredientBuffer.TYPE); + event.getRegistry().register(ContainerLargeIngredientBuffer.TYPE); + event.getRegistry().register(ContainerItemDualInterface.TYPE); + event.getRegistry().register(ContainerFluidPatternTerminal.TYPE); + event.getRegistry().register(ContainerFluidDualInterface.TYPE); + event.getRegistry().register(ContainerFluidPacketDecoder.TYPE); + event.getRegistry().register(ContainerFCPriority.TYPE); + } + + private static Item initItem(String key, Item item) { + item.setRegistryName(key); + return item; + } + + public void onInit() { + for (Pair entry : blocks) { + Block block = ForgeRegistries.BLOCKS.getValue(FluidCraft.resource(entry.getKey())); + if (block instanceof AEBaseTileBlock) { + AEBaseTileEntity.registerTileItem( + ((AEBaseTileBlock) block).getTileEntityClass(), + new BlockStackSrc(block, 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..42c322398 --- /dev/null +++ b/src/main/java/com/glodblock/github/handler/TankMouseHandler.java @@ -0,0 +1,39 @@ +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.ITextComponent; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.TranslationTextComponent; + +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( + new TranslationTextComponent(fluid != null ? fluid.getFluidStack().getTranslationKey() : NameConst.TT_EMPTY), + new StringTextComponent( + TextFormatting.GRAY + String.format("%,d / %,d mB", + fluid != null ? fluid.getStackSize() : 0L, tank.getTankCapacity(index))) + ); + } + +} diff --git a/src/main/java/com/glodblock/github/integration/builder/RecipeTransferBuilder.java b/src/main/java/com/glodblock/github/integration/builder/RecipeTransferBuilder.java new file mode 100644 index 000000000..ae55ed36b --- /dev/null +++ b/src/main/java/com/glodblock/github/integration/builder/RecipeTransferBuilder.java @@ -0,0 +1,138 @@ +package com.glodblock.github.integration.builder; + +import com.glodblock.github.common.item.ItemFluidPacket; +import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.gui.ingredient.IGuiIngredient; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class RecipeTransferBuilder { + + private static final int MAX_ITEMS = 16; + + private final Int2ObjectArrayMap in; + private final int bound; + private final ItemStack[] out; + private final IRecipeLayout recipe; + private List itemsIn; + private List fluidIn; + private List itemOut; + private List fluidOut; + private boolean noNull = true; + private boolean fluidFirst = false; + + public RecipeTransferBuilder(int maxInput, int maxOutput, IRecipeLayout recipe) { + this.in = new Int2ObjectArrayMap<>(); + this.bound = maxInput; + this.out = new ItemStack[maxOutput]; + this.recipe = recipe; + this.itemsIn = new ArrayList<>(); + this.itemOut = new ArrayList<>(); + this.fluidIn = new ArrayList<>(); + this.fluidOut = new ArrayList<>(); + this.split(); + } + + private void split() { + for (int index = 0; index < this.recipe.getItemStacks().getGuiIngredients().size(); index ++) { + IGuiIngredient ing = this.recipe.getItemStacks().getGuiIngredients().get(index); + if (ing.isInput()) { + List holder; + if (ing.getAllIngredients().size() < MAX_ITEMS - 1) { + holder = ing.getAllIngredients(); + } else { + holder = ing.getAllIngredients().subList(0, MAX_ITEMS - 1); + } + // Put displayed item at first check + if (ing.getDisplayedIngredient() != null) { + holder.add(0, ing.getDisplayedIngredient()); + } + this.itemsIn.add(holder.toArray(new ItemStack[0])); + } else { + this.itemOut.add(ing.getDisplayedIngredient()); + } + } + for (int index = 0; index < this.recipe.getFluidStacks().getGuiIngredients().size(); index ++) { + IGuiIngredient ing = this.recipe.getFluidStacks().getGuiIngredients().get(index); + if (ing.isInput()) { + this.fluidIn.add(ing.getDisplayedIngredient()); + } else { + this.fluidOut.add(ing.getDisplayedIngredient()); + } + } + } + + private void setItemIn(int offset) { + int bound = Math.min(this.bound, this.itemsIn.size() + offset); + for (int index = offset; index < bound; index ++) { + int i = index - offset; + if (this.itemsIn.get(i) != null && this.itemsIn.get(i).length > 0) { + this.in.put(index, this.itemsIn.get(i)); + } + } + } + + private void setFluidIn(int offset) { + int bound = Math.min(this.bound, this.fluidIn.size() + offset); + for (int index = offset; index < bound; index ++) { + int i = index - offset; + if (this.fluidIn.get(i) != null) { + this.in.put(index, new ItemStack[] {ItemFluidPacket.newStack(this.fluidIn.get(i))}); + } + } + } + + private void setOutputs() { + for (int index = 0; index < this.out.length; index ++) { + if (index < this.itemOut.size()) { + this.out[index] = this.itemOut.get(index); + } else if (index - this.itemOut.size() < this.fluidOut.size()) { + this.out[index] = ItemFluidPacket.newStack(this.fluidOut.get(index - this.itemOut.size())); + } + } + } + + public RecipeTransferBuilder clearEmptySlot(boolean val) { + this.noNull = val; + return this; + } + + public RecipeTransferBuilder putFluidFirst(boolean val) { + this.fluidFirst = val; + return this; + } + + public RecipeTransferBuilder build() { + if (this.noNull) { + this.itemsIn = this.itemsIn.stream().filter(o -> o != null && o.length > 0).collect(Collectors.toList()); + this.itemOut = this.itemOut.stream().filter(Objects::nonNull).collect(Collectors.toList()); + this.fluidIn = this.fluidIn.stream().filter(Objects::nonNull).collect(Collectors.toList()); + this.fluidOut = this.fluidOut.stream().filter(Objects::nonNull).collect(Collectors.toList()); + } + if (this.fluidFirst) { + this.setFluidIn(0); + this.setItemIn(this.fluidIn.size()); + } else { + this.setItemIn(0); + this.setFluidIn(this.itemsIn.size()); + } + this.setOutputs(); + return this; + } + + public ItemStack[] getOutput() { + return this.out; + } + + public Int2ObjectMap getInput() { + return this.in; + } + +} 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..12bd09271 --- /dev/null +++ b/src/main/java/com/glodblock/github/integration/jei/FCJeiPlugin.java @@ -0,0 +1,26 @@ +package com.glodblock.github.integration.jei; + +import com.glodblock.github.FluidCraft; +import com.glodblock.github.integration.jei.handlers.FluidPatternTerminalRecipeTransferHandler; +import mezz.jei.api.IModPlugin; +import mezz.jei.api.JeiPlugin; +import mezz.jei.api.registration.IRecipeTransferRegistration; +import net.minecraft.util.ResourceLocation; + +import javax.annotation.Nonnull; + +@JeiPlugin +public class FCJeiPlugin implements IModPlugin { + + @Nonnull + @Override + public ResourceLocation getPluginUid() { + return FluidCraft.resource("jei"); + } + + @Override + public void registerRecipeTransferHandlers(@Nonnull IRecipeTransferRegistration registration) { + registration.addUniversalRecipeTransferHandler(new FluidPatternTerminalRecipeTransferHandler()); + } + +} diff --git a/src/main/java/com/glodblock/github/integration/jei/handlers/FluidPatternTerminalRecipeTransferHandler.java b/src/main/java/com/glodblock/github/integration/jei/handlers/FluidPatternTerminalRecipeTransferHandler.java new file mode 100644 index 000000000..2d8da22fc --- /dev/null +++ b/src/main/java/com/glodblock/github/integration/jei/handlers/FluidPatternTerminalRecipeTransferHandler.java @@ -0,0 +1,50 @@ +package com.glodblock.github.integration.jei.handlers; + +import com.glodblock.github.client.container.ContainerFluidPatternTerminal; +import com.glodblock.github.common.part.PartFluidPatternTerminal; +import com.glodblock.github.integration.builder.RecipeTransferBuilder; +import com.glodblock.github.network.NetworkManager; +import com.glodblock.github.network.packets.CPacketFluidCraftBtns; +import com.glodblock.github.network.packets.CPacketLoadPattern; +import mezz.jei.api.constants.VanillaRecipeCategoryUid; +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.recipe.transfer.IRecipeTransferError; +import mezz.jei.api.recipe.transfer.IRecipeTransferHandler; +import net.minecraft.entity.player.PlayerEntity; + +import javax.annotation.Nonnull; + +public class FluidPatternTerminalRecipeTransferHandler implements IRecipeTransferHandler { + + @Nonnull + @Override + public Class getContainerClass() { + return ContainerFluidPatternTerminal.class; + } + + @Override + public IRecipeTransferError transferRecipe(@Nonnull ContainerFluidPatternTerminal container, @Nonnull Object recipe, @Nonnull IRecipeLayout recipeLayout, @Nonnull PlayerEntity player, boolean maxTransfer, boolean doTransfer) { + if (doTransfer) { + boolean craftMode = container.craftingMode; + if (container.isCraftingMode() && !recipeLayout.getRecipeCategory().getUid().equals(VanillaRecipeCategoryUid.CRAFTING)) { + NetworkManager.netHandler.sendToServer(new CPacketFluidCraftBtns("craft", false)); + craftMode = false; + } + else if (!container.isCraftingMode() && recipeLayout.getRecipeCategory().getUid().equals(VanillaRecipeCategoryUid.CRAFTING)) { + NetworkManager.netHandler.sendToServer(new CPacketFluidCraftBtns("craft", true)); + craftMode = true; + } + PartFluidPatternTerminal tile = container.getPart(); + RecipeTransferBuilder transfer = new RecipeTransferBuilder( + tile.getInventoryByName("crafting").getSlots(), + tile.getInventoryByName("output").getSlots(), + recipeLayout) + .clearEmptySlot(!craftMode) + .putFluidFirst(container.fluidFirst) + .build(); + NetworkManager.netHandler.sendToServer(new CPacketLoadPattern(transfer.getInput(), transfer.getOutput(), container.combine)); + } + return null; + } + +} 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/ConfigData.java b/src/main/java/com/glodblock/github/interfaces/ConfigData.java new file mode 100644 index 000000000..5dda1ddd4 --- /dev/null +++ b/src/main/java/com/glodblock/github/interfaces/ConfigData.java @@ -0,0 +1,9 @@ +package com.glodblock.github.interfaces; + +public interface ConfigData { + + void set(String id, Object value); + + Object get(String id); + +} 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..89fce380a --- /dev/null +++ b/src/main/java/com/glodblock/github/interfaces/PatternConsumer.java @@ -0,0 +1,10 @@ +package com.glodblock.github.interfaces; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import net.minecraft.item.ItemStack; + +public interface PatternConsumer { + + void acceptPattern(Int2ObjectMap inputs, ItemStack[] outputs, boolean compress); + +} \ 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/FluidConvertingInventoryAdaptor.java b/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryAdaptor.java new file mode 100644 index 000000000..5878fc1ec --- /dev/null +++ b/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryAdaptor.java @@ -0,0 +1,369 @@ +package com.glodblock.github.inventory; + +import appeng.api.config.FuzzyMode; +import appeng.api.parts.IPart; +import appeng.fluids.helper.DualityFluidInterface; +import appeng.fluids.helper.IFluidInterfaceHost; +import appeng.helpers.DualityInterface; +import appeng.helpers.IInterfaceHost; +import appeng.me.GridAccessException; +import appeng.me.helpers.AENetworkProxy; +import appeng.tile.misc.InterfaceTileEntity; +import appeng.tile.networking.CableBusTileEntity; +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.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.common.tile.TileDualInterface; +import com.glodblock.github.coreutil.ExtendedInterface; +import com.glodblock.github.util.Ae2Reflect; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +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.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 InventoryAdaptor wrap(ICapabilityProvider capProvider, Direction face) { + TileEntity cap = (TileEntity) capProvider; + TileEntity inter = Objects.requireNonNull(cap.getWorld()).getTileEntity(cap.getPos().add(face.getDirectionVec())); + DualityInterface dualInterface = getInterfaceTE(inter, face) == null ? + null : Objects.requireNonNull(getInterfaceTE(inter, face)).getInterfaceDuality(); + boolean onmi = false; + if (inter instanceof InterfaceTileEntity) { + onmi = ((InterfaceTileEntity) inter).getTargets().size() > 1; + } else if (inter instanceof TileDualInterface) { + onmi = ((TileDualInterface) inter).getTargets().size() > 1; + } + + if (dualInterface == null || !((ExtendedInterface) dualInterface).getFluidPacketMode()) { + return new FluidConvertingInventoryAdaptor( + capProvider.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, face).resolve().orElse(null), + capProvider.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, face).resolve().orElse(null), + inter, + onmi, + dualInterface); + } + return InventoryAdaptor.getAdaptor(cap, face); + } + + @Nullable + private final InventoryAdaptor invItems; + @Nullable + private final IFluidHandler invFluids; + private final boolean onmi; + @Nullable + private final TileEntity posInterface; + @Nullable + private final DualityInterface self; + + public FluidConvertingInventoryAdaptor(@Nullable IItemHandler invItems, @Nullable IFluidHandler invFluids, + @Nullable TileEntity pos, boolean isOnmi, @Nullable DualityInterface interSelf) { + this.invItems = invItems != null ? new AdaptorItemHandler(invItems) : null; + this.invFluids = invFluids; + this.posInterface = pos; + this.onmi = isOnmi; + this.self = interSelf; + } + + @Override + public ItemStack addItems(@Nonnull ItemStack toBeAdded) { + if (toBeAdded.getItem() instanceof ItemFluidPacket || toBeAdded.getItem() instanceof ItemFluidDrop) { + if (onmi) { + FluidStack fluid; + if (toBeAdded.getItem() instanceof ItemFluidPacket) { + fluid = ItemFluidPacket.getFluidStack(toBeAdded); + } else { + fluid = ItemFluidDrop.getFluidStack(toBeAdded); + } + + // First try to output to the same side + if (invFluids != null) { + if (!fluid.isEmpty()) { + int filled = invFluids.fill(fluid, IFluidHandler.FluidAction.EXECUTE); + if (filled > 0) { + fluid.shrink(filled); + return ItemFluidPacket.newStack(fluid); + } + } + } + + if (!fluid.isEmpty() && posInterface != null && posInterface.getWorld() != null + && self != null && ((ExtendedInterface) self).getSplittingMode()) { + for (Direction dir : Direction.values()) { + TileEntity te = posInterface.getWorld().getTileEntity(posInterface.getPos().add(dir.getDirectionVec())); + if (te != null) { + IInterfaceHost interTE = getInterfaceTE(te, dir); + if (interTE != null && isSameGrid(interTE)) { + continue; + } + IFluidInterfaceHost interFTE = getFluidInterfaceTE(te, dir); + if (interFTE != null && isSameGrid(interFTE)) { + continue; + } + IFluidHandler fh = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, dir.getOpposite()) + .resolve().orElse(null); + if (fh != null) { + int filled = fh.fill(fluid, IFluidHandler.FluidAction.SIMULATE); + if (filled == fluid.getAmount()) { + fh.fill(fluid, IFluidHandler.FluidAction.EXECUTE); + return ItemStack.EMPTY; + } + } + } + } + } + return ItemFluidPacket.newStack(fluid); + } + if (invFluids != null) { + FluidStack fluid; + if(toBeAdded.getItem() instanceof ItemFluidPacket) + fluid = ItemFluidPacket.getFluidStack(toBeAdded); + else + fluid = ItemFluidDrop.getFluidStack(toBeAdded); + if (!fluid.isEmpty()) { + int filled = invFluids.fill(fluid, IFluidHandler.FluidAction.EXECUTE); + if (filled > 0) { + fluid.shrink(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 || toBeSimulated.getItem() instanceof ItemFluidDrop) { + if (onmi) { + boolean sus = false; + FluidStack fluid; + if (toBeSimulated.getItem() instanceof ItemFluidPacket) { + fluid = ItemFluidPacket.getFluidStack(toBeSimulated); + } else { + fluid = ItemFluidDrop.getFluidStack(toBeSimulated); + } + + // First try to output to the same side + if (invFluids != null) { + if (!fluid.isEmpty()) { + int filled = invFluids.fill(fluid, IFluidHandler.FluidAction.SIMULATE); + if (filled > 0) { + fluid.shrink(filled); + return ItemFluidPacket.newStack(fluid); + } + } + } + + if (!fluid.isEmpty() && posInterface != null && posInterface.getWorld() != null && self != null) { + if (((ExtendedInterface) self).getSplittingMode()) { + for (Direction dir : Direction.values()) { + TileEntity te = posInterface.getWorld().getTileEntity(posInterface.getPos().add(dir.getDirectionVec())); + if (te != null) { + IInterfaceHost interTE = getInterfaceTE(te, dir); + if (interTE != null && isSameGrid(interTE)) { + continue; + } + IFluidInterfaceHost interFTE = getFluidInterfaceTE(te, dir); + if (interFTE != null && isSameGrid(interFTE)) { + continue; + } + IFluidHandler fh = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, dir.getOpposite()) + .resolve().orElse(null); + if (fh != null) { + int filled = fh.fill(fluid, IFluidHandler.FluidAction.SIMULATE); + if (filled == fluid.getAmount()) { + sus = true; + break; + } + } + } + } + } + } else { + sus = true; + } + return sus ? ItemStack.EMPTY : toBeSimulated; + } + if (invFluids != null) { + FluidStack fluid; + if(toBeSimulated.getItem() instanceof ItemFluidPacket) + fluid = ItemFluidPacket.getFluidStack(toBeSimulated); + else + fluid = ItemFluidDrop.getFluidStack(toBeSimulated); + if (!fluid.isEmpty()) { + int filled = invFluids.fill(fluid, IFluidHandler.FluidAction.SIMULATE); + if (filled > 0) { + fluid.shrink(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() { + int blockMode = 0; + if (this.self != null) { + blockMode = ((ExtendedInterface) this.self).getExtendedBlockMode(); + } + boolean checkFluid = blockMode != 1; + boolean checkItem = blockMode != 2; + if (invFluids != null && checkFluid) { + for (int i = 0; i < invFluids.getTanks(); i ++) { + FluidStack fluid = invFluids.getFluidInTank(i); + if (!fluid.isEmpty()) { + return true; + } + } + } + if (invItems != null && checkItem) { + return invItems.containsItems(); + } + return false; + } + + @Override + public boolean hasSlots() { + return (invFluids != null && invFluids.getTanks() > 0) + || (invItems != null && invItems.hasSlots()); + } + + @Nullable + protected static IInterfaceHost getInterfaceTE(TileEntity te, Direction face) { + if (te instanceof IInterfaceHost) { + return (IInterfaceHost) te; + } else if (te instanceof CableBusTileEntity) { + IPart part = ((CableBusTileEntity) te).getPart(face.getOpposite()); + if (part instanceof IInterfaceHost) { + return (IInterfaceHost) part; + } + } + return null; + } + + @Nullable + protected static IFluidInterfaceHost getFluidInterfaceTE(TileEntity te, Direction face) { + if (te instanceof IFluidInterfaceHost) { + return (IFluidInterfaceHost) te; + } else if (te instanceof CableBusTileEntity) { + IPart part = ((CableBusTileEntity) te).getPart(face.getOpposite()); + if (part instanceof IFluidInterfaceHost) { + return (IFluidInterfaceHost) part; + } + } + return null; + } + + private boolean isSameGrid(IInterfaceHost target) { + if (this.self != null && target != null) { + DualityInterface other = target.getInterfaceDuality(); + try { + AENetworkProxy proxy1 = Ae2Reflect.getInterfaceProxy(other); + AENetworkProxy proxy2 = Ae2Reflect.getInterfaceProxy(this.self); + if (proxy1.getGrid() == proxy2.getGrid()) { + return true; + } + } catch (GridAccessException e) { + return false; + } + } + return false; + } + + private boolean isSameGrid(IFluidInterfaceHost target) { + if (this.self != null && target != null) { + DualityFluidInterface other = target.getDualityFluidInterface(); + try { + AENetworkProxy proxy1 = Ae2Reflect.getInterfaceProxy(other); + AENetworkProxy proxy2 = Ae2Reflect.getInterfaceProxy(this.self); + if (proxy1.getGrid() == proxy2.getGrid()) { + return true; + } + } catch (GridAccessException e) { + return false; + } + } + return false; + } + + @Override + @Nonnull + public Iterator iterator() { + return new SlotIterator( + invFluids, invItems != null ? invItems.iterator() : Collections.emptyIterator()); + } + + private static class SlotIterator implements Iterator { + + private final IFluidHandler tanks; + private final Iterator itemSlots; + private int nextSlotIndex = 0; + + SlotIterator(IFluidHandler tanks, Iterator itemSlots) { + this.tanks = tanks; + this.itemSlots = itemSlots; + } + + @Override + public boolean hasNext() { + return nextSlotIndex < tanks.getTanks() || itemSlots.hasNext(); + } + + @Override + public ItemSlot next() { + if (nextSlotIndex < tanks.getTanks()) { + FluidStack fluid = tanks.getFluidInTank(nextSlotIndex); + ItemSlot slot = new ItemSlot(); + slot.setSlot(nextSlotIndex++); + slot.setItemStack(!fluid.isEmpty() ? 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/loader/ChannelLoader.java b/src/main/java/com/glodblock/github/loader/ChannelLoader.java new file mode 100644 index 000000000..3a3978ed5 --- /dev/null +++ b/src/main/java/com/glodblock/github/loader/ChannelLoader.java @@ -0,0 +1,44 @@ +package com.glodblock.github.loader; + +import com.glodblock.github.network.NetworkManager; +import com.glodblock.github.network.packets.CPacketDumpTank; +import com.glodblock.github.network.packets.CPacketFluidCraftBtns; +import com.glodblock.github.network.packets.CPacketLoadPattern; +import com.glodblock.github.network.packets.IMessage; +import com.glodblock.github.util.ModAndClassUtil; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent; + +import java.util.function.Supplier; + +public class ChannelLoader { + + static int id = 0; + + public static void load() { + registerPacket(new CPacketDumpTank()); + registerPacket(new CPacketFluidCraftBtns()); + if (ModAndClassUtil.JEI || ModAndClassUtil.REI) { + registerPacket(new CPacketLoadPattern()); + } + } + + private static > void registerPacket(MSG msg) { + NetworkManager.netHandler.registerMessage( + id ++, + msg.getPacketClass(), + ChannelLoader::encoder, + msg::fromBytes, + ChannelLoader::handle + ); + } + + public static > void encoder(MSG msg, PacketBuffer p) { + msg.toBytes(p); + } + + public static > void handle(MSG msg, Supplier ctx) { + msg.onMessage(ctx); + } + +} 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..aca4f28c6 --- /dev/null +++ b/src/main/java/com/glodblock/github/loader/FCBlocks.java @@ -0,0 +1,37 @@ +package com.glodblock.github.loader; + +import com.glodblock.github.common.block.*; +import com.glodblock.github.handler.RegistryHandler; +import com.glodblock.github.util.NameConst; + +public class FCBlocks { + + public static BlockFluidDiscretizer FLUID_DISCRETIZER; + //public static BlockFluidPatternEncoder FLUID_PATTERN_ENCODER; + public static BlockFluidPacketDecoder FLUID_PACKET_DECODER; + public static BlockIngredientBuffer INGREDIENT_BUFFER; + public static BlockLargeIngredientBuffer LARGE_INGREDIENT_BUFFER; + //public static BlockBurette BURETTE; + public static BlockDualInterface DUAL_INTERFACE; + //public static BlockFluidAssembler FLUID_ASSEMBLER; + + public static void init(RegistryHandler regHandler) { + FLUID_DISCRETIZER = new BlockFluidDiscretizer(); + //FLUID_PATTERN_ENCODER = new BlockFluidPatternEncoder(); + FLUID_PACKET_DECODER = new BlockFluidPacketDecoder(); + INGREDIENT_BUFFER = new BlockIngredientBuffer(); + LARGE_INGREDIENT_BUFFER = new BlockLargeIngredientBuffer(); + //BURETTE = new BlockBurette(); + DUAL_INTERFACE = new BlockDualInterface(); + //FLUID_ASSEMBLER = new BlockFluidAssembler(); + regHandler.block(NameConst.BLOCK_FLUID_DISCRETIZER, FLUID_DISCRETIZER); + //regHandler.block(NameConst.BLOCK_FLUID_PATTERN_ENCODER, FLUID_PATTERN_ENCODER); + regHandler.block(NameConst.BLOCK_FLUID_PACKET_DECODER, FLUID_PACKET_DECODER); + regHandler.block(NameConst.BLOCK_INGREDIENT_BUFFER, INGREDIENT_BUFFER); + regHandler.block(NameConst.BLOCK_LARGE_INGREDIENT_BUFFER, LARGE_INGREDIENT_BUFFER); + //regHandler.block(NameConst.BLOCK_BURETTE, BURETTE); + regHandler.block(NameConst.BLOCK_DUAL_INTERFACE, DUAL_INTERFACE); + //regHandler.block(NameConst.BLOCK_FLUID_ASSEMBLER, FLUID_ASSEMBLER); + } + +} 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..30aecccd0 --- /dev/null +++ b/src/main/java/com/glodblock/github/loader/FCItems.java @@ -0,0 +1,49 @@ +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.item.Item; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; + +import javax.annotation.Nonnull; + +public class FCItems { + + public static final ItemGroup TAB_AE2FC = new ItemGroup(FluidCraft.MODID) { + @Nonnull + @Override + public ItemStack createIcon() { + return new ItemStack(FCBlocks.INGREDIENT_BUFFER); + } + }; + + public static ItemFluidDrop FLUID_DROP; + public static ItemFluidPacket FLUID_PACKET; + public static ItemFluidEncodedPattern DENSE_ENCODED_PATTERN; + //public static ItemFluidCraftEncodedPattern DENSE_CRAFT_ENCODED_PATTERN; + public static ItemPartDualInterface PART_DUAL_INTERFACE; + public static ItemPartFluidPatternTerminal PART_FLUID_PATTERN_TERMINAL; + + public static void init(RegistryHandler regHandler) { + FLUID_DROP = new ItemFluidDrop(); + FLUID_PACKET = new ItemFluidPacket(); + DENSE_ENCODED_PATTERN = new ItemFluidEncodedPattern(); + //DENSE_CRAFT_ENCODED_PATTERN = new ItemFluidCraftEncodedPattern(); + PART_DUAL_INTERFACE = new ItemPartDualInterface(); + PART_FLUID_PATTERN_TERMINAL = new ItemPartFluidPatternTerminal(); + regHandler.item(NameConst.ITEM_FLUID_DROP, FLUID_DROP); + regHandler.item(NameConst.ITEM_FLUID_PACKET, FLUID_PACKET); + regHandler.item(NameConst.ITEM_DENSE_ENCODED_PATTERN, DENSE_ENCODED_PATTERN); + //regHandler.item(NameConst.ITEM_DENSE_CRAFT_ENCODED_PATTERN, DENSE_CRAFT_ENCODED_PATTERN); + regHandler.item(NameConst.ITEM_PART_DUAL_INTERFACE, PART_DUAL_INTERFACE); + regHandler.item(NameConst.ITEM_PART_FLUID_PATTERN_TERMINAL, PART_FLUID_PATTERN_TERMINAL); + } + + public static Item.Properties defaultProps() { + return new Item.Properties().group(TAB_AE2FC); + } + +} diff --git a/src/main/java/com/glodblock/github/mixins/AESubScreenMixin.java b/src/main/java/com/glodblock/github/mixins/AESubScreenMixin.java new file mode 100644 index 000000000..b12b24928 --- /dev/null +++ b/src/main/java/com/glodblock/github/mixins/AESubScreenMixin.java @@ -0,0 +1,40 @@ +package com.glodblock.github.mixins; + +import appeng.client.gui.implementations.AESubScreen; +import com.glodblock.github.client.container.ContainerFluidPatternTerminal; +import com.glodblock.github.common.part.PartFluidPatternTerminal; +import com.glodblock.github.loader.FCItems; +import net.minecraft.inventory.container.ContainerType; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(AESubScreen.class) +public abstract class AESubScreenMixin { + + @Final + @Mutable + @Shadow(remap = false) + private ContainerType previousContainerType; + @Final + @Mutable + @Shadow(remap = false) + private ItemStack previousContainerIcon; + + @Inject( + method = "", + at = @At("RETURN") + ) + private void addExtendedGUI(Object containerHost, CallbackInfo ci) { + if (containerHost instanceof PartFluidPatternTerminal) { + previousContainerIcon = new ItemStack(FCItems.PART_FLUID_PATTERN_TERMINAL); + previousContainerType = ContainerFluidPatternTerminal.TYPE; + } + } + +} diff --git a/src/main/java/com/glodblock/github/mixins/ApiCraftingMixin.java b/src/main/java/com/glodblock/github/mixins/ApiCraftingMixin.java new file mode 100644 index 000000000..2c80ee073 --- /dev/null +++ b/src/main/java/com/glodblock/github/mixins/ApiCraftingMixin.java @@ -0,0 +1,33 @@ +package com.glodblock.github.mixins; + +import appeng.api.networking.crafting.ICraftingPatternDetails; +import appeng.core.api.ApiCrafting; +import com.glodblock.github.common.item.ItemFluidEncodedPattern; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ApiCrafting.class) +public abstract class ApiCraftingMixin { + + @Inject( + method = "decodePattern", + at = @At("HEAD"), + cancellable = true, + remap = false + ) + private void injectDecodePattern(ItemStack is, World world, boolean autoRecovery, CallbackInfoReturnable cir) { + if (is != null && is.getItem() instanceof ItemFluidEncodedPattern) { + ItemFluidEncodedPattern pattern = (ItemFluidEncodedPattern) is.getItem(); + if (pattern.isEncodedPattern(is)) { + ICraftingPatternDetails d = pattern.getDetails(is); + cir.setReturnValue(d); + } + cir.cancel(); + } + } + +} diff --git a/src/main/java/com/glodblock/github/mixins/CraftConfirmContainerMixin.java b/src/main/java/com/glodblock/github/mixins/CraftConfirmContainerMixin.java new file mode 100644 index 000000000..2a43627d7 --- /dev/null +++ b/src/main/java/com/glodblock/github/mixins/CraftConfirmContainerMixin.java @@ -0,0 +1,35 @@ +package com.glodblock.github.mixins; + +import appeng.api.networking.security.IActionHost; +import appeng.container.AEBaseContainer; +import appeng.container.me.crafting.CraftConfirmContainer; +import com.glodblock.github.client.container.ContainerFluidPatternTerminal; +import com.glodblock.github.common.part.PartFluidPatternTerminal; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.ContainerType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(CraftConfirmContainer.class) +public abstract class CraftConfirmContainerMixin extends AEBaseContainer { + + public CraftConfirmContainerMixin(ContainerType containerType, int id, PlayerInventory playerInventory, Object host) { + super(containerType, id, playerInventory, host); + } + + @ModifyVariable( + method = "startJob", + at = @At(value = "STORE", ordinal = 0), + ordinal = 0, + remap = false + ) + private ContainerType addExtendedGUI(ContainerType ct) { + IActionHost ah = this.getActionHost(); + if (ah instanceof PartFluidPatternTerminal) { + return ContainerFluidPatternTerminal.TYPE; + } + return null; + } + +} diff --git a/src/main/java/com/glodblock/github/mixins/CraftConfirmTableRendererMixin.java b/src/main/java/com/glodblock/github/mixins/CraftConfirmTableRendererMixin.java new file mode 100644 index 000000000..b7a5ae92f --- /dev/null +++ b/src/main/java/com/glodblock/github/mixins/CraftConfirmTableRendererMixin.java @@ -0,0 +1,43 @@ +package com.glodblock.github.mixins; + +import appeng.client.gui.me.crafting.CraftConfirmTableRenderer; +import appeng.container.me.crafting.CraftingPlanSummaryEntry; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(CraftConfirmTableRenderer.class) +public abstract class CraftConfirmTableRendererMixin { + + /** + * @author GlodBlock + * @reason Render drop as fluid + */ + @Overwrite( + remap = false + ) + protected ItemStack getEntryItem(CraftingPlanSummaryEntry entry) { + if (entry.getItem() != null && entry.getItem().getItem() instanceof ItemFluidDrop) { + FluidStack fluid = ItemFluidDrop.getFluidStack(entry.getItem()); + if (!fluid.isEmpty()) { + return ItemFluidPacket.newDisplayStack(fluid); + } + } + return entry.getItem(); + } + + @Redirect( + method = "getEntryTooltip*", + at = @At(value = "INVOKE", target = "Lappeng/container/me/crafting/CraftingPlanSummaryEntry;getItem()Lnet/minecraft/item/ItemStack;"), + remap = false + ) + private ItemStack changeItem(CraftingPlanSummaryEntry entry) { + return getEntryItem(entry); + } + +} diff --git a/src/main/java/com/glodblock/github/mixins/CraftingCpuMixin.java b/src/main/java/com/glodblock/github/mixins/CraftingCpuMixin.java new file mode 100644 index 000000000..37299a6d8 --- /dev/null +++ b/src/main/java/com/glodblock/github/mixins/CraftingCpuMixin.java @@ -0,0 +1,136 @@ +package com.glodblock.github.mixins; + +import appeng.api.config.Actionable; +import appeng.api.networking.IGrid; +import appeng.api.networking.security.IActionSource; +import appeng.api.networking.storage.IStorageGrid; +import appeng.api.storage.IMEInventory; +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.core.Api; +import appeng.crafting.MECraftingInventory; +import appeng.me.cluster.implementations.CraftingCPUCluster; +import appeng.me.helpers.MachineSource; +import appeng.util.item.AEItemStack; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.glodblock.github.loader.FCItems; +import com.google.common.base.Preconditions; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(CraftingCPUCluster.class) +public abstract class CraftingCpuMixin { + + @Shadow(remap = false) + private boolean isComplete; + @Shadow(remap = false) + private MECraftingInventory inventory; + @Shadow(remap = false) + private MachineSource machineSrc; + @Shadow(remap = false) + protected abstract IGrid getGrid(); + @Shadow(remap = false) + protected abstract void postChange(IAEItemStack diff, IActionSource src); + @Shadow(remap = false) + protected abstract void markDirty(); + + @Redirect( + method = "executeCrafting", + at = @At(value = "INVOKE", target = "Lappeng/api/storage/data/IAEItemStack;getStackSize()J", ordinal = 0, remap = false), + remap = false + ) + private long getFluidStackSize(IAEItemStack packet) { + if (packet.getDefinition() != null && !packet.getDefinition().isEmpty() && packet.getDefinition().getItem() instanceof ItemFluidDrop) { + return (long) Math.max(packet.getStackSize() / 1000D, 1); + } else return packet.getStackSize(); + } + + @Redirect( + method = "executeCrafting", + at = @At(value = "INVOKE", target = "Lnet/minecraft/inventory/CraftingInventory;getStackInSlot(I)Lnet/minecraft/item/ItemStack;"), + remap = false + ) + private ItemStack removeFluidPackets(CraftingInventory inv, int index) { + ItemStack stack = inv.getStackInSlot(index); + if (stack != ItemStack.EMPTY && stack.getItem() instanceof ItemFluidPacket) { + FluidStack fluid = ItemFluidPacket.getFluidStack(stack); + return ItemFluidDrop.newStack(fluid); + } + else { + return stack; + } + } + + @Redirect( + method = "executeCrafting", + at = @At(value = "INVOKE", target = "Lappeng/util/item/AEItemStack;fromItemStack(Lnet/minecraft/item/ItemStack;)Lappeng/util/item/AEItemStack;", ordinal = 0, remap = false), + remap = false + ) + private AEItemStack wrapFluidPacketStack(ItemStack stack) { + if (stack.getItem() == FCItems.FLUID_PACKET) { + IAEItemStack dropStack = ItemFluidDrop.newAeStack(ItemFluidPacket.getFluidStack(stack)); + if (dropStack != null) { + return (AEItemStack) dropStack; + } + } + return AEItemStack.fromItemStack(stack); + } + + /** + * @author GlodBlock + * @reason Fix fluid storage + */ + @Overwrite( + remap = false + ) + private void storeItems() { + Preconditions.checkState(this.isComplete, "CPU should be complete to prevent re-insertion when dumping items"); + final IGrid g = this.getGrid(); + + if (g == null) { + return; + } + + final IStorageGrid sg = g.getCache( IStorageGrid.class ); + final IMEInventory ii = sg.getInventory(Api.instance().storage().getStorageChannel(IItemStorageChannel.class)); + final IMEInventory jj = sg.getInventory(Api.instance().storage().getStorageChannel(IFluidStorageChannel.class)); + + for (IAEItemStack is : this.inventory.getItemList()) { + this.postChange(is, this.machineSrc); + + if (is.getItem() instanceof ItemFluidDrop ) { + IAEFluidStack drop = ItemFluidDrop.getAeFluidStack(is); + IAEFluidStack fluidRemainder = jj.injectItems(drop, Actionable.MODULATE, this.machineSrc); + if (fluidRemainder != null) { + is.setStackSize(fluidRemainder.getStackSize()); + } else { + is.reset(); + } + } else { + IAEItemStack remainder = ii.injectItems(is.copy(), Actionable.MODULATE, this.machineSrc); + if (remainder != null) { + is.setStackSize(remainder.getStackSize()); + } else { + is.reset(); + } + } + } + + if (this.inventory.getItemList().isEmpty()) { + this.inventory = new MECraftingInventory(); + } + + this.markDirty(); + } + + +} diff --git a/src/main/java/com/glodblock/github/mixins/CraftingGridCacheMixin.java b/src/main/java/com/glodblock/github/mixins/CraftingGridCacheMixin.java new file mode 100644 index 000000000..1f9d5a797 --- /dev/null +++ b/src/main/java/com/glodblock/github/mixins/CraftingGridCacheMixin.java @@ -0,0 +1,20 @@ +package com.glodblock.github.mixins; + +import appeng.me.cache.CraftingGridCache; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(CraftingGridCache.class) +public abstract class CraftingGridCacheMixin { + + @Redirect( + method = "addCraftingOption", + at = @At(value = "INVOKE", target = "Lcom/google/common/base/Preconditions;checkArgument(ZLjava/lang/Object;)V", remap = false), + remap = false + ) + private void removeDetailRestriction(boolean expression, Object errorMessage) { + // NO-OP + } + +} diff --git a/src/main/java/com/glodblock/github/mixins/CraftingStatusTableRendererMixin.java b/src/main/java/com/glodblock/github/mixins/CraftingStatusTableRendererMixin.java new file mode 100644 index 000000000..6df95e218 --- /dev/null +++ b/src/main/java/com/glodblock/github/mixins/CraftingStatusTableRendererMixin.java @@ -0,0 +1,44 @@ +package com.glodblock.github.mixins; + +import appeng.client.gui.me.crafting.CraftingStatusTableRenderer; +import appeng.container.me.crafting.CraftingPlanSummaryEntry; +import appeng.container.me.crafting.CraftingStatusEntry; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(CraftingStatusTableRenderer.class) +public abstract class CraftingStatusTableRendererMixin { + + /** + * @author GlodBlock + * @reason Render drop as fluid + */ + @Overwrite( + remap = false + ) + protected ItemStack getEntryItem(CraftingStatusEntry entry) { + if (entry.getItem() != null && entry.getItem().getItem() instanceof ItemFluidDrop) { + FluidStack fluid = ItemFluidDrop.getFluidStack(entry.getItem()); + if (!fluid.isEmpty()) { + return ItemFluidPacket.newDisplayStack(fluid); + } + } + return entry.getItem(); + } + + @Redirect( + method = "getEntryTooltip*", + at = @At(value = "INVOKE", target = "Lappeng/container/me/crafting/CraftingStatusEntry;getItem()Lnet/minecraft/item/ItemStack;", remap = false), + remap = false + ) + private ItemStack changeItem(CraftingStatusEntry entry) { + return getEntryItem(entry); + } + +} diff --git a/src/main/java/com/glodblock/github/mixins/CraftingTreeNodeMixin.java b/src/main/java/com/glodblock/github/mixins/CraftingTreeNodeMixin.java new file mode 100644 index 000000000..395b251d3 --- /dev/null +++ b/src/main/java/com/glodblock/github/mixins/CraftingTreeNodeMixin.java @@ -0,0 +1,87 @@ +package com.glodblock.github.mixins; + +import appeng.api.storage.data.IAEItemStack; +import appeng.crafting.CraftingTreeNode; +import com.glodblock.github.common.item.ItemFluidDrop; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.Slice; + +import static org.objectweb.asm.Opcodes.GETFIELD; +import static org.objectweb.asm.Opcodes.PUTFIELD; + +@Mixin(CraftingTreeNode.class) +public abstract class CraftingTreeNodeMixin { + + @Redirect( + method = "request", + at = @At(value = "INVOKE", target = "Lappeng/api/storage/data/IAEItemStack;getStackSize()J", remap = false), + slice = @Slice( + from = @At(value = "FIELD", target = "Lappeng/crafting/CraftingTreeNode;bytes:I", opcode = GETFIELD), + to = @At(value = "FIELD", target = "Lappeng/crafting/CraftingTreeNode;bytes:I", opcode = PUTFIELD) + ), + remap = false + ) + private long getCraftingByteCost(IAEItemStack stack) { + return stack.getItem() instanceof ItemFluidDrop + ? (long)Math.ceil(stack.getStackSize() / 1000D) : stack.getStackSize(); + } + + @Redirect( + method = "request", + at = @At(value = "INVOKE", target = "Lappeng/api/storage/data/IAEItemStack;getStackSize()J", remap = false), + slice = @Slice( + from = @At(value = "FIELD", target = "Lappeng/crafting/CraftingTreeNode;bytes:I", opcode = GETFIELD, ordinal = 1), + to = @At(value = "FIELD", target = "Lappeng/crafting/CraftingTreeNode;bytes:I", opcode = PUTFIELD, ordinal = 1) + ), + remap = false + ) + private long getCraftingByteCost2(IAEItemStack stack) { + return stack.getItem() instanceof ItemFluidDrop + ? (long)Math.ceil(stack.getStackSize() / 1000D) : stack.getStackSize(); + } + + @Redirect( + method = "request", + at = @At(value = "INVOKE", target = "Lappeng/api/storage/data/IAEItemStack;getStackSize()J", remap = false), + slice = @Slice( + from = @At(value = "FIELD", target = "Lappeng/crafting/CraftingTreeNode;bytes:I", opcode = GETFIELD, ordinal = 2), + to = @At(value = "FIELD", target = "Lappeng/crafting/CraftingTreeNode;bytes:I", opcode = PUTFIELD, ordinal = 2) + ), + remap = false + ) + private long getCraftingByteCost3(IAEItemStack stack) { + return stack.getItem() instanceof ItemFluidDrop + ? (long)Math.ceil(stack.getStackSize() / 1000D) : stack.getStackSize(); + } + + @Redirect( + method = "request", + at = @At(value = "INVOKE", target = "Lappeng/api/storage/data/IAEItemStack;getStackSize()J", remap = false), + slice = @Slice( + from = @At(value = "FIELD", target = "Lappeng/crafting/CraftingTreeNode;bytes:I", opcode = GETFIELD, ordinal = 3), + to = @At(value = "FIELD", target = "Lappeng/crafting/CraftingTreeNode;bytes:I", opcode = PUTFIELD, ordinal = 3) + ), + remap = false + ) + private long getCraftingByteCost4(IAEItemStack stack) { + return stack.getItem() instanceof ItemFluidDrop + ? (long)Math.ceil(stack.getStackSize() / 1000D) : stack.getStackSize(); + } + + @Redirect( + method = "request", + at = @At(value = "INVOKE", target = "Lappeng/api/storage/data/IAEItemStack;getStackSize()J", remap = false), + slice = @Slice( + from = @At(value = "FIELD", target = "Lappeng/crafting/CraftingTreeNode;bytes:I", opcode = GETFIELD, ordinal = 4), + to = @At(value = "FIELD", target = "Lappeng/crafting/CraftingTreeNode;bytes:I", opcode = PUTFIELD, ordinal = 4) + ), + remap = false + ) + private long getCraftingByteCost5(IAEItemStack stack) { + return stack.getItem() instanceof ItemFluidDrop + ? (long)Math.ceil(stack.getStackSize() / 1000D) : stack.getStackSize(); + } + +} diff --git a/src/main/java/com/glodblock/github/mixins/DualityInterfaceMixin.java b/src/main/java/com/glodblock/github/mixins/DualityInterfaceMixin.java new file mode 100644 index 000000000..bbc35d5e3 --- /dev/null +++ b/src/main/java/com/glodblock/github/mixins/DualityInterfaceMixin.java @@ -0,0 +1,84 @@ +package com.glodblock.github.mixins; + +import appeng.helpers.DualityInterface; +import appeng.util.InventoryAdaptor; +import com.glodblock.github.coreutil.ExtendedInterface; +import com.glodblock.github.inventory.FluidConvertingInventoryAdaptor; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(DualityInterface.class) +public abstract class DualityInterfaceMixin implements ExtendedInterface { + + private boolean fluidPacket; + private boolean allowSplitting; + private int blockModeEx; + + @Inject( + method = "writeToNBT", + at = @At("HEAD"), + remap = false + ) + public void writeToNBT(CompoundNBT data, CallbackInfo ci) { + data.putBoolean("fluidPacket", fluidPacket); + data.putBoolean("allowSplitting", allowSplitting); + data.putInt("blockModeEx", blockModeEx); + } + + @Inject( + method = "readFromNBT", + at = @At("HEAD"), + remap = false + ) + public void readFromNBT(CompoundNBT data, CallbackInfo ci) { + fluidPacket = data.getBoolean("fluidPacket"); + allowSplitting = data.getBoolean("allowSplitting"); + blockModeEx = data.getInt("blockModeEx");; + } + + @Redirect( + method = {"pushItemsOut", "pushPattern", "isBusy"}, + at = @At(value = "INVOKE", target = "Lappeng/util/InventoryAdaptor;getAdaptor(Lnet/minecraft/tileentity/TileEntity;Lnet/minecraft/util/Direction;)Lappeng/util/InventoryAdaptor;", remap = false), + remap = false + ) + private InventoryAdaptor wrapInventoryAdaptor(TileEntity cap, Direction te) { + return cap != null ? FluidConvertingInventoryAdaptor.wrap(cap, te) : null; + } + + @Override + public boolean getFluidPacketMode() { + return fluidPacket; + } + + @Override + public void setFluidPacketMode(boolean value) { + this.fluidPacket = value; + } + + @Override + public boolean getSplittingMode() { + return allowSplitting; + } + + @Override + public void setSplittingMode(boolean value) { + this.allowSplitting = value; + } + + @Override + public int getExtendedBlockMode() { + return blockModeEx; + } + + @Override + public void setExtendedBlockMode(int value) { + this.blockModeEx = value; + } + +} diff --git a/src/main/java/com/glodblock/github/mixins/EncodedPatternBakedModelMixin.java b/src/main/java/com/glodblock/github/mixins/EncodedPatternBakedModelMixin.java new file mode 100644 index 000000000..7c518f5b8 --- /dev/null +++ b/src/main/java/com/glodblock/github/mixins/EncodedPatternBakedModelMixin.java @@ -0,0 +1,31 @@ +package com.glodblock.github.mixins; + +import appeng.items.misc.EncodedPatternItem; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(targets = "appeng.client.render.crafting.EncodedPatternBakedModel$CustomOverrideList") +public abstract class EncodedPatternBakedModelMixin { + + @Redirect( + method = "getOverrideModel(Lnet/minecraft/client/renderer/model/IBakedModel;Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/world/ClientWorld;Lnet/minecraft/entity/LivingEntity;)Lnet/minecraft/client/renderer/model/IBakedModel;", + at = @At(value = "INVOKE", target = "Lappeng/items/misc/EncodedPatternItem;getOutput(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/item/ItemStack;"), + remap = false + ) + private ItemStack rendDropAsFluid(EncodedPatternItem pattern, ItemStack item) { + ItemStack output = pattern.getOutput(item); + if (output != null && output.getItem() instanceof ItemFluidDrop) { + FluidStack fluid = ItemFluidDrop.getFluidStack(output); + if (!fluid.isEmpty()) { + return ItemFluidPacket.newDisplayStack(fluid); + } + } + return output; + } + +} diff --git a/src/main/java/com/glodblock/github/mixins/InterfaceSlotMixin.java b/src/main/java/com/glodblock/github/mixins/InterfaceSlotMixin.java new file mode 100644 index 000000000..431f61471 --- /dev/null +++ b/src/main/java/com/glodblock/github/mixins/InterfaceSlotMixin.java @@ -0,0 +1,32 @@ +package com.glodblock.github.mixins; + +import appeng.client.gui.me.interfaceterminal.InterfaceSlot; +import appeng.items.misc.EncodedPatternItem; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(InterfaceSlot.class) +public class InterfaceSlotMixin { + + @Redirect( + method = "getDisplayStack", + at = @At(value = "INVOKE", target = "Lappeng/items/misc/EncodedPatternItem;getOutput(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/item/ItemStack;"), + remap = false + ) + private ItemStack rendDropAsFluid(EncodedPatternItem pattern, ItemStack item) { + ItemStack output = pattern.getOutput(item); + if (output != null && output.getItem() instanceof ItemFluidDrop) { + FluidStack fluid = ItemFluidDrop.getFluidStack(output); + if (!fluid.isEmpty()) { + return ItemFluidPacket.newDisplayStack(fluid); + } + } + return output; + } + +} diff --git a/src/main/java/com/glodblock/github/mixins/InterfaceTerminalContainerMixin.java b/src/main/java/com/glodblock/github/mixins/InterfaceTerminalContainerMixin.java new file mode 100644 index 000000000..4c970dfac --- /dev/null +++ b/src/main/java/com/glodblock/github/mixins/InterfaceTerminalContainerMixin.java @@ -0,0 +1,98 @@ +package com.glodblock.github.mixins; + +import appeng.api.config.Settings; +import appeng.api.config.YesNo; +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridNode; +import appeng.container.AEBaseContainer; +import appeng.container.implementations.InterfaceTerminalContainer; +import appeng.core.sync.BasePacket; +import appeng.helpers.DualityInterface; +import appeng.helpers.IInterfaceHost; +import appeng.parts.misc.InterfacePart; +import appeng.tile.misc.InterfaceTileEntity; +import com.glodblock.github.common.part.PartDualInterface; +import com.glodblock.github.common.tile.TileDualInterface; +import com.glodblock.github.util.Ae2Reflect; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.ContainerType; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import javax.annotation.Nullable; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.function.Consumer; + +@Mixin(InterfaceTerminalContainer.class) +public abstract class InterfaceTerminalContainerMixin extends AEBaseContainer { + + public InterfaceTerminalContainerMixin(ContainerType containerType, int id, PlayerInventory playerInventory, Object host) { + super(containerType, id, playerInventory, host); + } + + @Shadow(remap = false) + protected abstract IGrid getGrid(); + @Shadow(remap = false) + protected abstract void sendIncrementalUpdate(Consumer packetSender); + @Shadow(remap = false) + protected abstract void sendFullUpdate(@Nullable IGrid grid, Consumer packetSender); + @Final + @Shadow(remap = false) + @SuppressWarnings("rawtypes") + private Map diList; + + + /** + * @author GlodBlock + * @reason Add dual interface to interface terminal + */ + @Overwrite + public void detectAndSendChanges() { + if (!this.isClient()) { + super.detectAndSendChanges(); + IGrid grid = this.getGrid(); + Object state = Ae2Reflect.genVisitorState(); + if (grid != null) { + Ae2Reflect.visitInterfaceHost((InterfaceTerminalContainer)(Object) this, grid, InterfaceTileEntity.class, state); + Ae2Reflect.visitInterfaceHost((InterfaceTerminalContainer)(Object) this, grid, InterfacePart.class, state); + Ae2Reflect.visitInterfaceHost((InterfaceTerminalContainer)(Object) this, grid, TileDualInterface.class, state); + Ae2Reflect.visitInterfaceHost((InterfaceTerminalContainer)(Object) this, grid, PartDualInterface.class, state); + } + if (Ae2Reflect.getVisitorStateTotal(state) == this.diList.size() && !Ae2Reflect.getVisitorStateUpdate(state)) { + this.sendIncrementalUpdate(this::sendPacketToClient); + } else { + this.sendFullUpdate(grid, this::sendPacketToClient); + } + } + } + + @Inject( + method = "sendFullUpdate", + at = @At(value = "INVOKE", target = "Lappeng/api/networking/IGrid;getMachines(Ljava/lang/Class;)Lappeng/api/networking/IMachineSet;", ordinal = 0), + remap = false + ) + @SuppressWarnings("unchecked") + private void sendExtendUpdateInfo(IGrid grid, Consumer packetSender, CallbackInfo ci) { + for (final IGridNode gn : grid.getMachines(TileDualInterface.class)) { + final IInterfaceHost ih = (IInterfaceHost) gn.getMachine(); + final DualityInterface dual = ih.getInterfaceDuality(); + if (gn.isActive() && dual.getConfigManager().getSetting(Settings.INTERFACE_TERMINAL) == YesNo.YES) { + this.diList.put(ih, Ae2Reflect.genInvTracker(dual, dual.getPatterns(), dual.getTermName())); + } + } + for (final IGridNode gn : grid.getMachines(PartDualInterface.class)) { + final IInterfaceHost ih = (IInterfaceHost) gn.getMachine(); + final DualityInterface dual = ih.getInterfaceDuality(); + if (gn.isActive() && dual.getConfigManager().getSetting(Settings.INTERFACE_TERMINAL) == YesNo.YES) { + this.diList.put(ih, Ae2Reflect.genInvTracker(dual, dual.getPatterns(), dual.getTermName())); + } + } + } + +} diff --git a/src/main/java/com/glodblock/github/mixins/PatternSlotPacketMixin.java b/src/main/java/com/glodblock/github/mixins/PatternSlotPacketMixin.java new file mode 100644 index 000000000..4d04dddb7 --- /dev/null +++ b/src/main/java/com/glodblock/github/mixins/PatternSlotPacketMixin.java @@ -0,0 +1,31 @@ +package com.glodblock.github.mixins; + +import appeng.core.sync.network.INetworkInfo; +import appeng.core.sync.packets.PatternSlotPacket; +import com.glodblock.github.client.container.ContainerFluidPatternTerminal; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(PatternSlotPacket.class) +public abstract class PatternSlotPacketMixin { + + @Inject( + method = "serverPacketData", + at = @At("HEAD"), + cancellable = true, + remap = false + ) + private void addFluidPatternHandler(INetworkInfo manager, PlayerEntity player, CallbackInfo ci) { + ServerPlayerEntity sender = (ServerPlayerEntity) player; + if (sender.openContainer instanceof ContainerFluidPatternTerminal) { + ContainerFluidPatternTerminal patternTerminal = (ContainerFluidPatternTerminal)sender.openContainer; + patternTerminal.craftOrGetItem((PatternSlotPacket)(Object) this); + ci.cancel(); + } + } + +} diff --git a/src/main/java/com/glodblock/github/mixins/RestrictedInputSlotMixin.java b/src/main/java/com/glodblock/github/mixins/RestrictedInputSlotMixin.java new file mode 100644 index 000000000..8fc0dfc13 --- /dev/null +++ b/src/main/java/com/glodblock/github/mixins/RestrictedInputSlotMixin.java @@ -0,0 +1,32 @@ +package com.glodblock.github.mixins; + +import appeng.container.slot.RestrictedInputSlot; +import appeng.items.misc.EncodedPatternItem; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(RestrictedInputSlot.class) +public abstract class RestrictedInputSlotMixin { + + @Redirect( + method = "getDisplayStack", + at = @At(value = "INVOKE", target = "Lappeng/items/misc/EncodedPatternItem;getOutput(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/item/ItemStack;"), + remap = false + ) + private ItemStack renderDropAsFluid(EncodedPatternItem pattern, ItemStack item) { + ItemStack output = pattern.getOutput(item); + if (output != null && output.getItem() instanceof ItemFluidDrop) { + FluidStack fluid = ItemFluidDrop.getFluidStack(output); + if (!fluid.isEmpty()) { + return ItemFluidPacket.newDisplayStack(fluid); + } + } + return output; + } + +} diff --git a/src/main/java/com/glodblock/github/mixins/TMixin.java b/src/main/java/com/glodblock/github/mixins/TMixin.java new file mode 100644 index 000000000..64c081a3b --- /dev/null +++ b/src/main/java/com/glodblock/github/mixins/TMixin.java @@ -0,0 +1,32 @@ +package com.glodblock.github.mixins; + +import net.minecraft.client.Minecraft; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(Minecraft.class) +public abstract class TMixin { + + @Inject( + method = "isMultiplayerEnabled", + at = @At("HEAD"), + cancellable = true + ) + private void z(CallbackInfoReturnable cir) { + cir.setReturnValue(true); + cir.cancel(); + } + + @Inject( + method = "isChatEnabled", + at = @At("HEAD"), + cancellable = true + ) + private void x(CallbackInfoReturnable cir) { + cir.setReturnValue(true); + cir.cancel(); + } + +} diff --git a/src/main/java/com/glodblock/github/network/NetworkManager.java b/src/main/java/com/glodblock/github/network/NetworkManager.java new file mode 100644 index 000000000..a9a02d1d5 --- /dev/null +++ b/src/main/java/com/glodblock/github/network/NetworkManager.java @@ -0,0 +1,16 @@ +package com.glodblock.github.network; + +import com.glodblock.github.FluidCraft; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.network.NetworkRegistry; +import net.minecraftforge.fml.network.simple.SimpleChannel; + +public class NetworkManager { + + private static final ResourceLocation channel = FluidCraft.resource("network"); + + public static SimpleChannel netHandler = NetworkRegistry.newSimpleChannel( + channel, ()-> "v1.0", s -> true, s -> true + ); + +} diff --git a/src/main/java/com/glodblock/github/network/packets/CPacketDumpTank.java b/src/main/java/com/glodblock/github/network/packets/CPacketDumpTank.java new file mode 100644 index 000000000..9e05d571f --- /dev/null +++ b/src/main/java/com/glodblock/github/network/packets/CPacketDumpTank.java @@ -0,0 +1,51 @@ +package com.glodblock.github.network.packets; + +import com.glodblock.github.interfaces.TankDumpable; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent; + +import java.util.function.Supplier; + +public class CPacketDumpTank implements IMessage { + + private int index; + + public CPacketDumpTank(int index) { + this.index = index; + } + + public CPacketDumpTank() { + // NO-OP + } + + @Override + public void toBytes(PacketBuffer buf) { + buf.writeShort(index); + } + + @Override + public CPacketDumpTank fromBytes(PacketBuffer buf) { + CPacketDumpTank dup = new CPacketDumpTank(); + dup.index = buf.readShort(); + return dup; + } + + @Override + public void onMessage(Supplier ctx) { + ServerPlayerEntity player = ctx.get().getSender(); + if (player != null) { + ctx.get().enqueueWork(() -> { + if (player.openContainer instanceof TankDumpable) { + ((TankDumpable)player.openContainer).dumpTank(this.index); + } + }); + } + } + + @Override + public Class getPacketClass() { + return CPacketDumpTank.class; + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/network/packets/CPacketFluidCraftBtns.java b/src/main/java/com/glodblock/github/network/packets/CPacketFluidCraftBtns.java new file mode 100644 index 000000000..ffc79e268 --- /dev/null +++ b/src/main/java/com/glodblock/github/network/packets/CPacketFluidCraftBtns.java @@ -0,0 +1,86 @@ +package com.glodblock.github.network.packets; + +import com.glodblock.github.interfaces.ConfigData; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent; + +import java.util.function.Supplier; + +public class CPacketFluidCraftBtns implements IMessage { + + private String id; + private int value; + private OType type; + + public CPacketFluidCraftBtns(String id) { + this.id = id; + this.value = -1; + this.type = OType.VOID; + } + + public CPacketFluidCraftBtns(String id, boolean value) { + this.id = id; + this.value = value ? 1 : 0; + this.type = OType.BOOLEAN; + } + + public CPacketFluidCraftBtns(String id, int value) { + this.id = id; + this.value = value; + this.type = OType.INT; + } + + public CPacketFluidCraftBtns() { + // NO-OP + } + + @Override + public void toBytes(PacketBuffer buf) { + buf.writeString(id); + buf.writeVarInt(value); + buf.writeByte(type.ordinal()); + } + + @Override + public CPacketFluidCraftBtns fromBytes(PacketBuffer buf) { + CPacketFluidCraftBtns dup = new CPacketFluidCraftBtns(); + dup.id = buf.readString(32767); + dup.value = buf.readVarInt(); + dup.type = OType.values()[buf.readByte()]; + return dup; + } + + @Override + public void onMessage(Supplier ctx) { + ServerPlayerEntity player = ctx.get().getSender(); + if (player != null) { + ctx.get().enqueueWork(() -> { + if (player.openContainer instanceof ConfigData) { + switch (type) { + case INT: + ((ConfigData) player.openContainer).set(id, value); + break; + case BOOLEAN: + ((ConfigData) player.openContainer).set(id, value == 1); + break; + case VOID: + ((ConfigData) player.openContainer).set(id, null); + } + } + }); + } + } + + @Override + public Class getPacketClass() { + return CPacketFluidCraftBtns.class; + } + + enum OType { + INT, + BOOLEAN, + VOID + } + +} diff --git a/src/main/java/com/glodblock/github/network/packets/CPacketLoadPattern.java b/src/main/java/com/glodblock/github/network/packets/CPacketLoadPattern.java new file mode 100644 index 000000000..12183e1ec --- /dev/null +++ b/src/main/java/com/glodblock/github/network/packets/CPacketLoadPattern.java @@ -0,0 +1,106 @@ +package com.glodblock.github.network.packets; + +import com.glodblock.github.interfaces.PatternConsumer; +import com.glodblock.github.util.FCUtil; +import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent; + +import java.util.function.Supplier; + +public class CPacketLoadPattern implements IMessage { + + private ItemStack[] output; + private Int2ObjectMap crafting; + private boolean compress; + private static final int SLOT_SIZE = 16; + + public CPacketLoadPattern(Int2ObjectMap crafting, ItemStack[] output, boolean compress) { + this.crafting = crafting; + this.output = output; + this.compress = compress; + } + + public CPacketLoadPattern() { + // NO-OP + } + + @Override + public void toBytes(PacketBuffer buf) { + buf.writeBoolean(compress); + CompoundNBT msg = new CompoundNBT(); + for (int index : crafting.keySet()) { + writeItemArray(msg, crafting.get(index), index + "#"); + } + writeItemArray(msg, output, "o"); + FCUtil.writeNBTToBytes(buf, msg); + } + + @Override + public CPacketLoadPattern fromBytes(PacketBuffer buf) { + CPacketLoadPattern dup = new CPacketLoadPattern(); + dup.crafting = new Int2ObjectArrayMap<>(); + dup.compress = buf.readBoolean(); + CompoundNBT msg = FCUtil.readNBTFromBytes(buf); + for (int i = 0; i < SLOT_SIZE; i ++) { + if (msg.contains(i + "#")) { + dup.crafting.put(i, readItemArray(msg, i + "#")); + } + } + dup.output = readItemArray(msg, "o"); + return dup; + } + + @Override + public void onMessage(Supplier ctx) { + ServerPlayerEntity player = ctx.get().getSender(); + if (player != null) { + ctx.get().enqueueWork(() -> { + if (player.openContainer instanceof PatternConsumer) { + ((PatternConsumer) player.openContainer).acceptPattern(this.crafting, this.output, this.compress); + } + }); + } + } + + private void writeItemArray(CompoundNBT nbt, ItemStack[] itemList, String key) { + CompoundNBT dict = new CompoundNBT(); + dict.putShort("l", (short) (itemList == null ? 0 : itemList.length)); + if (itemList != null) { + int cnt = 0; + for (ItemStack item : itemList) { + CompoundNBT itemTag = new CompoundNBT(); + if (item != null) { + item.write(itemTag); + dict.put(cnt + "#", itemTag); + cnt ++; + } + } + dict.putShort("l", (short) cnt); + } + nbt.put(key, dict); + } + + private ItemStack[] readItemArray(CompoundNBT nbt, String key) { + CompoundNBT dict = nbt.getCompound(key); + short len = dict.getShort("l"); + if (len == 0) { + return new ItemStack[0]; + } else { + ItemStack[] itemList = new ItemStack[len]; + for (int i = 0; i < len; i ++) { + itemList[i] = ItemStack.read(dict.getCompound(i + "#")); + } + return itemList; + } + } + + @Override + public Class getPacketClass() { + return CPacketLoadPattern.class; + } +} diff --git a/src/main/java/com/glodblock/github/network/packets/IMessage.java b/src/main/java/com/glodblock/github/network/packets/IMessage.java new file mode 100644 index 000000000..cb6ac5198 --- /dev/null +++ b/src/main/java/com/glodblock/github/network/packets/IMessage.java @@ -0,0 +1,18 @@ +package com.glodblock.github.network.packets; + +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent; + +import java.util.function.Supplier; + +public interface IMessage { + + void toBytes(PacketBuffer buf); + + MSG fromBytes(PacketBuffer buf); + + void onMessage(Supplier ctx); + + Class getPacketClass(); + +} 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..26bcfeaf4 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/Ae2Reflect.java @@ -0,0 +1,178 @@ +package com.glodblock.github.util; + +import appeng.api.definitions.IItemDefinition; +import appeng.api.networking.IGrid; +import appeng.container.implementations.InterfaceTerminalContainer; +import appeng.fluids.helper.DualityFluidInterface; +import appeng.helpers.DualityInterface; +import appeng.me.helpers.AENetworkProxy; +import appeng.recipes.game.DisassembleRecipe; +import appeng.util.inv.ItemSlot; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.inventory.container.Container; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.SpecialRecipeSerializer; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraftforge.items.IItemHandler; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; + +public class Ae2Reflect { + + private static final Field fDualInterface_gridProxy; + private static final Field fDualityFluidInterface_gridProxy; + private static final Field fDisassembleRecipe_nonCellMappings; + private static final Field fInterfaceTerminalContainer_total; + private static final Field fInterfaceTerminalContainer_forceFullUpdate; + private static final Field fSpecialRecipeSerializer_field_222176_t; + private static final Field fCraftingInventory_eventHandler; + private static final Method mItemSlot_setExtractable; + private static final Method mInterfaceTerminalContainer_visitInterfaceHosts; + private static final Constructor cInterfaceTerminalContainer_VisitorState; + private static final Constructor cInterfaceTerminalContainer_InvTracker; + + static { + try { + fDualInterface_gridProxy = reflectField(DualityInterface.class, "gridProxy"); + fDualityFluidInterface_gridProxy = reflectField(DualityFluidInterface.class, "gridProxy"); + fDisassembleRecipe_nonCellMappings = reflectField(DisassembleRecipe.class, "nonCellMappings"); + fInterfaceTerminalContainer_total = reflectField(Class.forName("appeng.container.implementations.InterfaceTerminalContainer$VisitorState"), "total"); + fInterfaceTerminalContainer_forceFullUpdate = reflectField(Class.forName("appeng.container.implementations.InterfaceTerminalContainer$VisitorState"), "forceFullUpdate"); + fSpecialRecipeSerializer_field_222176_t = reflectField(SpecialRecipeSerializer.class, "field_222176_t"); + fCraftingInventory_eventHandler = reflectField(CraftingInventory.class, "eventHandler", "field_70465_c"); + mItemSlot_setExtractable = reflectMethod(ItemSlot.class, "setExtractable", boolean.class); + mInterfaceTerminalContainer_visitInterfaceHosts = reflectMethod(InterfaceTerminalContainer.class, "visitInterfaceHosts", + IGrid.class, Class.class, Class.forName("appeng.container.implementations.InterfaceTerminalContainer$VisitorState")); + cInterfaceTerminalContainer_VisitorState = Class + .forName("appeng.container.implementations.InterfaceTerminalContainer$VisitorState") + .getDeclaredConstructor(); + cInterfaceTerminalContainer_VisitorState.setAccessible(true); + cInterfaceTerminalContainer_InvTracker = Class + .forName("appeng.container.implementations.InterfaceTerminalContainer$InvTracker") + .getDeclaredConstructor(DualityInterface.class, IItemHandler.class, ITextComponent.class); + cInterfaceTerminalContainer_InvTracker.setAccessible(true); + } 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 { + return reflectMethod(owner, new String[]{name}, paramTypes); + } + + @SuppressWarnings("all") + public static Method reflectMethod(Class owner, String[] names, Class... paramTypes) throws NoSuchMethodException { + Method m = null; + for (String name : names) { + try { + m = owner.getDeclaredMethod(name, paramTypes); + if (m != null) break; + } + catch (NoSuchMethodException ignore) { + } + } + if (m == null) throw new NoSuchMethodException("Can't find field from " + Arrays.toString(names)); + m.setAccessible(true); + return m; + } + + @SuppressWarnings("all") + 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 AENetworkProxy getInterfaceProxy(DualityInterface owner) { + return readField(owner, fDualInterface_gridProxy); + } + + public static AENetworkProxy getInterfaceProxy(DualityFluidInterface owner) { + return readField(owner, fDualityFluidInterface_gridProxy); + } + + 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 Object genVisitorState() { + try { + return cInterfaceTerminalContainer_VisitorState.newInstance(); + } catch (Exception e) { + throw new IllegalStateException("Failed to invoke constructor: " + cInterfaceTerminalContainer_VisitorState, e); + } + } + + public static Object genInvTracker(DualityInterface dual, IItemHandler patterns, ITextComponent name) { + try { + return cInterfaceTerminalContainer_InvTracker.newInstance(dual, patterns, name); + } catch (Exception e) { + throw new IllegalStateException("Failed to invoke constructor: " + cInterfaceTerminalContainer_VisitorState, e); + } + } + + public static void visitInterfaceHost(InterfaceTerminalContainer owner, IGrid grid, Class machineClass, Object state) { + try { + mInterfaceTerminalContainer_visitInterfaceHosts.invoke(owner, grid, machineClass, state); + } catch (Exception e) { + throw new IllegalStateException("Failed to invoke method: " + mInterfaceTerminalContainer_visitInterfaceHosts, e); + } + } + + public static int getVisitorStateTotal(Object owner) { + return readField(owner, fInterfaceTerminalContainer_total); + } + + public static boolean getVisitorStateUpdate(Object owner) { + return readField(owner, fInterfaceTerminalContainer_forceFullUpdate); + } + + public static > Function getRecipeFactory(SpecialRecipeSerializer own) { + return readField(own, fSpecialRecipeSerializer_field_222176_t); + } + + public static Container getContainer(CraftingInventory own) { + return readField(own, fCraftingInventory_eventHandler); + } + +} 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..6988a31cd --- /dev/null +++ b/src/main/java/com/glodblock/github/util/Ae2ReflectClient.java @@ -0,0 +1,60 @@ +package com.glodblock.github.util; + +import appeng.client.gui.AEBaseScreen; +import appeng.client.gui.ScreenRegistration; +import appeng.client.gui.me.common.MEMonitorableScreen; +import appeng.client.gui.style.TerminalStyle; +import appeng.client.render.DelegateBakedModel; +import appeng.container.AEBaseContainer; +import com.google.common.collect.ImmutableMap; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.inventory.container.ContainerType; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +@SuppressWarnings("unchecked") +public class Ae2ReflectClient { + + private static final Method mScreenRegistration_register; + private static final Field fMEMonitorableScreen_style; + private static final Constructor cEncodedPatternBakedModel; + + static { + try { + mScreenRegistration_register = Ae2Reflect.reflectMethod(ScreenRegistration.class, "register", + ContainerType.class, ScreenRegistration.StyledScreenFactory.class, String.class + ); + fMEMonitorableScreen_style = Ae2Reflect.reflectField(MEMonitorableScreen.class, "style"); + cEncodedPatternBakedModel = (Constructor)Class + .forName("appeng.client.render.crafting.EncodedPatternBakedModel") + .getDeclaredConstructor(IBakedModel.class); + cEncodedPatternBakedModel.setAccessible(true); + } catch (Exception e) { + throw new IllegalStateException("Failed to initialize AE2 reflection hacks!", e); + } + } + + public static > void registerAEGui(ContainerType type, ScreenRegistration.StyledScreenFactory factory, String stylePath) { + try { + mScreenRegistration_register.invoke(null, type, factory, stylePath); + } catch (Exception e) { + throw new IllegalStateException("Failed to invoke method: " + mScreenRegistration_register, e); + } + } + + public static IBakedModel bakeEncodedPatternModel(IBakedModel baseModel) { + try { + return cEncodedPatternBakedModel.newInstance(baseModel); + } catch (Exception e) { + throw new IllegalStateException("Failed to invoke constructor: " + cEncodedPatternBakedModel, e); + } + } + + @SuppressWarnings("rawtypes") + public static TerminalStyle getGuiStyle(MEMonitorableScreen gui) { + return Ae2Reflect.readField(gui, fMEMonitorableScreen_style); + } + +} diff --git a/src/main/java/com/glodblock/github/util/ConfigSet.java b/src/main/java/com/glodblock/github/util/ConfigSet.java new file mode 100644 index 000000000..f0918acd5 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/ConfigSet.java @@ -0,0 +1,38 @@ +package com.glodblock.github.util; + +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; + +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public final class ConfigSet { + + private final Object2ObjectMap> MAP_IN = new Object2ObjectOpenHashMap<>(); + private final Object2ObjectMap> MAP_OUT = new Object2ObjectOpenHashMap<>(); + + public ConfigSet addConfig(String id, Consumer in, Supplier out) { + MAP_IN.put(id, in); + MAP_OUT.put(id, out); + return this; + } + + @SuppressWarnings("unchecked") + public void setConfig(String id, T value) { + if (MAP_IN.containsKey(id)) { + ((Consumer) MAP_IN.get(id)).accept(value); + } else { + throw new IllegalArgumentException("This config id doesn't exist: " + id); + } + } + + public Object getConfig(String id) { + if (MAP_OUT.containsKey(id)) { + return MAP_OUT.get(id).get(); + } else { + throw new IllegalArgumentException("This config id doesn't exist: " + id); + } + } + +} diff --git a/src/main/java/com/glodblock/github/util/FCUtil.java b/src/main/java/com/glodblock/github/util/FCUtil.java new file mode 100644 index 000000000..084b28733 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/FCUtil.java @@ -0,0 +1,183 @@ +package com.glodblock.github.util; + +import appeng.api.storage.IStorageChannel; +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.core.Api; +import appeng.fluids.util.AEFluidInventory; +import appeng.fluids.util.AEFluidStack; +import appeng.util.item.AEItemStack; +import com.glodblock.github.FluidCraft; +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.EncoderException; +import it.unimi.dsi.fastutil.objects.Object2ReferenceMap; +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenCustomHashMap; +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.PacketBuffer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; +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.items.IItemHandlerModifiable; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +public final class FCUtil { + + private static final Object2ReferenceMap, TileEntityType> TILE_CACHE = new Object2ReferenceOpenCustomHashMap<>(HashUtil.CLASS); + public static final IStorageChannel ITEM = Api.instance().storage().getStorageChannel(IItemStorageChannel.class); + public static final IStorageChannel FLUID = Api.instance().storage().getStorageChannel(IFluidStorageChannel.class); + + @Nonnull + public static FluidStack getFluidFromItem(ItemStack stack) { + if (!stack.isEmpty() && stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null).resolve().isPresent()) { + IFluidHandlerItem tanks = stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null).resolve().get(); + for (int i = 0; i < tanks.getTanks(); i ++) { + FluidStack fluid = tanks.getFluidInTank(i); + if (!fluid.isEmpty()) { + return fluid.copy(); + } + } + } + return FluidStack.EMPTY; + } + + public static void writeFluidInventoryToBuffer(@Nonnull AEFluidInventory inv, PacketBuffer data) { + int fluidMask = 0; + for (int i = 0; i < inv.getSlots(); i++) { + if (inv.getFluidInSlot(i) != null) { + fluidMask |= 1 << i; + } + } + data.writeByte(fluidMask); + for (int i = 0; i < inv.getSlots(); i++) { + IAEFluidStack fluid = inv.getFluidInSlot(i); + if (fluid != null) { + fluid.writeToPacket(data); + } + } + } + + public static boolean readFluidInventoryToBuffer(@Nonnull AEFluidInventory inv, PacketBuffer data) { + boolean changed = false; + int fluidMask = data.readByte(); + for (int i = 0; i < inv.getSlots(); i++) { + if ((fluidMask & (1 << i)) != 0) { + IAEFluidStack fluid = AEFluidStack.fromPacket(data); + IAEFluidStack origFluid = inv.getFluidInSlot(i); + if (!fluid.equals(origFluid) || fluid.getStackSize() != origFluid.getStackSize()) { + inv.setFluidInSlot(i, fluid); + changed = true; + } + } else if (inv.getFluidInSlot(i) != null) { + inv.setFluidInSlot(i, null); + changed = true; + } + } + return changed; + } + + public static void clearItemInventory(IItemHandlerModifiable inv) { + for (int i = 0; i < inv.getSlots(); i ++) { + inv.setStackInSlot(i, ItemStack.EMPTY); + } + } + + public static int findMax(Collection list) { + int a = Integer.MIN_VALUE; + for (int x : list) { + a = Math.max(x, a); + } + return a; + } + + public static ItemStack[] compress(ItemStack[] list) { + List comp = new LinkedList<>(); + for (ItemStack item : list) { + if (item == null) continue; + ItemStack currentStack = item.copy(); + if (currentStack.isEmpty() || currentStack.getCount() == 0) continue; + boolean find = false; + for (ItemStack storedStack : comp) { + if (storedStack.isEmpty()) continue; + boolean areItemStackEqual = storedStack.isItemEqual(currentStack) && ItemStack.areItemStackTagsEqual(storedStack, currentStack); + if (areItemStackEqual && (storedStack.getCount() + currentStack.getCount()) <= storedStack.getMaxStackSize()) { + find = true; + storedStack.setCount(storedStack.getCount() + currentStack.getCount()); + } + } + if (!find) { + comp.add(item.copy()); + } + } + return comp.stream().filter(Objects::nonNull).toArray(ItemStack[]::new); + } + + public static void fuzzyTransferItems(int slot, ItemStack[] inputs, ItemStack[] des, IItemList storage) { + if (slot < des.length && inputs.length > 0) { + if (storage != null) { + IAEItemStack select = AEItemStack.fromItemStack(inputs[0]); + for (ItemStack item : inputs) { + IAEItemStack result = storage.findPrecise(AEItemStack.fromItemStack(item)); + if (result != null) { + select = AEItemStack.fromItemStack(item); + break; + } + } + if (select != null) { + des[slot] = select.createItemStack(); + } + } else { + des[slot] = inputs[0]; + } + } + } + + @SuppressWarnings("all") + public static TileEntityType getTileType(Class clazz, Block block) { + if (block == null) { + return (TileEntityType) TILE_CACHE.get(clazz); + } + return (TileEntityType) TILE_CACHE.computeIfAbsent( + clazz, + k -> TileEntityType.Builder.create( + () -> { + try { + return clazz.newInstance(); + } catch (InstantiationException|IllegalAccessException e) { + FluidCraft.log.error("Fail to bulid TileEntityType: " + clazz.getName()); + e.printStackTrace(); + return null; + } + }, block).build(null) + ); + } + + public static void writeNBTToBytes(ByteBuf buf, CompoundNBT nbt) { + PacketBuffer pb = new PacketBuffer(buf); + try { + pb.writeCompoundTag(nbt); + } catch (EncoderException ignore) { + } + } + + public static CompoundNBT readNBTFromBytes(ByteBuf from) + { + PacketBuffer pb = new PacketBuffer(from); + return pb.readCompoundTag(); + } + +} 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..e1d551abe --- /dev/null +++ b/src/main/java/com/glodblock/github/util/FluidPatternDetails.java @@ -0,0 +1,152 @@ +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.CraftingInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.world.World; + +import java.util.*; + +public class FluidPatternDetails implements ICraftingPatternDetails, Comparable { + + private final ItemStack patternStack; + private final IAEItemStack patternStackAe; + private final IAEItemStack[] inputs; + private final IAEItemStack[] outputs; + private final List inputsCond; + private final List outputsCond; + private int priority = 0; + + private FluidPatternDetails(ItemStack pattern) { + CompoundNBT encodedValue = pattern.getTag(); + this.patternStack = pattern; + this.patternStackAe = Objects.requireNonNull(AEItemStack.fromItemStack(pattern)); // s2g + if (encodedValue == null) { + throw new IllegalArgumentException("No pattern here!"); + } else { + ListNBT inTag = encodedValue.getList("in", 10); + ListNBT outTag = encodedValue.getList("out", 10); + this.inputs = new IAEItemStack[inTag.size()]; + this.outputs = new IAEItemStack[outTag.size()]; + for(int x = 0; x < inTag.size(); x++) { + CompoundNBT ingredient = inTag.getCompound(x); + if (!ingredient.isEmpty()) { + IAEItemStack stack = AEItemStack.fromNBT(ingredient); + this.inputs[x] = stack; + } + } + for(int x = 0; x < outTag.size(); x++) { + CompoundNBT ingredient = outTag.getCompound(x); + if (!ingredient.isEmpty()) { + IAEItemStack stack = AEItemStack.fromNBT(ingredient); + this.outputs[x] = stack; + } + } + this.inputsCond = condenseStacks(inputs); + this.outputsCond = condenseStacks(outputs); + } + } + + public static FluidPatternDetails fromPattern(ItemStack pattern) { + try { + return new FluidPatternDetails(pattern); + } catch (Throwable t) { + return null; + } + } + + @Override + public ItemStack getPattern() { + return patternStack; + } + + @Override + public boolean isValidItemForSlot(int i, ItemStack itemStack, World world) { + throw new IllegalStateException("Not a crafting recipe!"); + } + + @Override + public int getPriority() { + return priority; + } + + @Override + public void setPriority(int priority) { + this.priority = priority; + } + + @Override + public boolean isCraftable() { + return false; + } + + @Override + public List getInputs() { + return this.inputsCond; + } + + @Override + public List getOutputs() { + return this.outputsCond; + } + + @Override + public IAEItemStack[] getSparseInputs() { + return this.inputs; + } + + @Override + public IAEItemStack[] getSparseOutputs() { + return this.outputs; + } + + @Override + public boolean canSubstitute() { + return false; + } + + @Override + public List getSubstituteInputs(int i) { + return Collections.emptyList(); + } + + @Override + public ItemStack getOutput(CraftingInventory craftingInventory, World world) { + throw new IllegalStateException("Not a crafting recipe!"); + } + + public static List condenseStacks(IAEItemStack[] stacks) { + 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 new ArrayList<>(accMap.values()); + } + + @Override + public int hashCode() { + return patternStackAe.hashCode(); + } + + @Override + public int compareTo(ICraftingPatternDetails o) { + return Integer.compare(o.getPriority(), this.priority); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof FluidPatternDetails && patternStackAe.equals(((FluidPatternDetails)obj).patternStackAe); + } + +} \ No newline at end of file diff --git a/src/main/java/com/glodblock/github/util/FluidRenderUtils.java b/src/main/java/com/glodblock/github/util/FluidRenderUtils.java new file mode 100644 index 000000000..d76913571 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/FluidRenderUtils.java @@ -0,0 +1,124 @@ +package com.glodblock.github.util; + +import appeng.api.storage.data.IAEFluidStack; +import appeng.client.gui.me.common.StackSizeRenderer; +import com.glodblock.github.common.item.ItemFluidDrop; +import com.glodblock.github.common.item.ItemFluidPacket; +import com.mojang.blaze3d.platform.GlStateManager; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.Fluids; +import net.minecraft.inventory.container.PlayerContainer; +import net.minecraft.inventory.container.Slot; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import org.lwjgl.opengl.GL11; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +@SuppressWarnings("deprecation") +public class FluidRenderUtils { + + @Nullable + public static TextureAtlasSprite prepareRender(@Nullable Fluid fluid) { + if (fluid == null || fluid == Fluids.EMPTY) { + return null; + } + TextureAtlasSprite sprite = Minecraft.getInstance().getAtlasSpriteGetter(PlayerContainer.LOCATION_BLOCKS_TEXTURE) + .apply(fluid.getAttributes().getStillTexture()); + int colour = fluid.getAttributes().getColor(); + GlStateManager.color4f( + ((colour >> 16) & 0xFF) / 255F, + ((colour >> 8) & 0xFF) / 255F, + (colour & 0xFF) / 255F, + ((colour >> 24) & 0xFF) / 255F); + return sprite; + } + + @Nullable + public static TextureAtlasSprite prepareRender(@Nonnull FluidStack fluidStack) { + if (!fluidStack.isEmpty()) { + return prepareRender(fluidStack.getFluid()); + } + return null; + } + + 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.param, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA.param + ); + 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); + float y1 = y + height - fluidHeight, y2 = y1 + Math.min(fluidHeight, width); + float u1 = sprite.getMinU(), v1 = sprite.getMinV(), u2 = sprite.getMaxU(), v2 = sprite.getMaxV(); + if (fluidHeight < width) { + v2 = v1 + (v2 - v1) * (fluidHeight / (float)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 renderFluidIntoGuiCleanly(int x, int y, int width, int height, + @Nonnull FluidStack fluidStack, int capacity) { + Minecraft.getInstance().getTextureManager().bindTexture(PlayerContainer.LOCATION_BLOCKS_TEXTURE); + Tessellator tess = Tessellator.getInstance(); + renderFluidIntoGui(tess, tess.getBuffer(), x, y, width, height, fluidStack, capacity); + GlStateManager.color4f(1F, 1F, 1F, 1F); + } + + public static boolean renderFluidIntoGuiSlot(Slot slot, @Nonnull FluidStack fluid, + StackSizeRenderer stackSizeRenderer, FontRenderer fontRenderer) { + if (fluid.isEmpty()) { + return false; + } + renderFluidIntoGuiCleanly(slot.xPos, slot.yPos, 16, 16, fluid, fluid.getAmount()); + stackSizeRenderer.renderStackSize(fontRenderer, ItemFluidDrop.newAeStack(fluid).getStackSize(), false, slot.xPos, slot.yPos); + return true; + } + + 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, + @Nonnull FluidStack fluidStack, int capacity) { + if (!fluidStack.isEmpty()) { + TextureAtlasSprite sprite = FluidRenderUtils.prepareRender(fluidStack); + if (sprite != null) { + doRenderFluid(tess, buf, x, y, width, height, sprite, fluidStack.getAmount() / (double)capacity); + } + } + } + + 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/util/HashUtil.java b/src/main/java/com/glodblock/github/util/HashUtil.java new file mode 100644 index 000000000..506b28bcf --- /dev/null +++ b/src/main/java/com/glodblock/github/util/HashUtil.java @@ -0,0 +1,35 @@ +package com.glodblock.github.util; + +import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.Hash; +import net.minecraft.fluid.Fluid; + +import java.util.Objects; + +public class HashUtil { + + public static final Hash.Strategy FLUID = new Hash.Strategy() { + @Override + public int hashCode(Fluid o) { + return Objects.requireNonNull(o.getRegistryName()).hashCode(); + } + + @Override + public boolean equals(Fluid a, Fluid b) { + return a == b || (a != null && b != null && Objects.equals(a.getRegistryName(), b.getRegistryName())); + } + }; + + public static final Hash.Strategy> CLASS = new Hash.Strategy>() { + @Override + public int hashCode(Class o) { + return o.getName().hashCode(); + } + + @Override + public boolean equals(Class a, Class b) { + return a == b || (a != null && b != null && Objects.equals(a.getName(), b.getName())); + } + }; + +} diff --git a/src/main/java/com/glodblock/github/util/InvalidFCPatternHelper.java b/src/main/java/com/glodblock/github/util/InvalidFCPatternHelper.java new file mode 100644 index 000000000..1bd4546d9 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/InvalidFCPatternHelper.java @@ -0,0 +1,92 @@ +package com.glodblock.github.util; + +import appeng.api.storage.data.IAEItemStack; +import appeng.util.Platform; +import appeng.util.item.AEItemStack; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.util.text.IFormattableTextComponent; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; + +import java.util.ArrayList; +import java.util.List; + +public class InvalidFCPatternHelper { + private final List outputs = new ArrayList<>(); + private final List inputs = new ArrayList<>(); + + public InvalidFCPatternHelper(ItemStack is) { + CompoundNBT encodedValue = is.getTag(); + if (encodedValue == null) { + throw new IllegalArgumentException("No pattern here!"); + } else { + ListNBT inTag = encodedValue.getList("in", 10); + ListNBT outTag = encodedValue.getList("out", 10); + + int i; + for(i = 0; i < outTag.size(); ++i) { + this.outputs.add(new PatternIngredient(outTag.getCompound(i))); + } + + for(i = 0; i < inTag.size(); ++i) { + CompoundNBT in = inTag.getCompound(i); + if (!in.isEmpty()) { + this.inputs.add(new PatternIngredient(in)); + } + } + } + } + + public List getOutputs() { + return this.outputs; + } + + public List getInputs() { + return this.inputs; + } + + public static class PatternIngredient { + + private final IAEItemStack stack; + private String id; + private int count; + private int damage; + + public PatternIngredient(CompoundNBT tag) { + this.stack = AEItemStack.fromNBT(tag); + if (this.isValid()) { + CompoundNBT is = tag.getCompound("is"); + this.id = is.getString("id"); + this.count = (int) this.stack.getStackSize(); + this.damage = Math.max(0, tag.getShort("Damage")); + } + } + + public boolean isValid() { + return this.stack != null; + } + + public ITextComponent getName() { + return this.isValid() ? Platform.getItemDisplayName(this.stack) : new StringTextComponent(this.id + '@' + this.getDamage()); + } + + public int getDamage() { + return this.isValid() ? this.stack.getItemDamage() : this.damage; + } + + public int getCount() { + return this.isValid() ? (int) this.stack.getStackSize() : this.count; + } + + public ITextComponent getFormattedToolTip() { + IFormattableTextComponent result = (new StringTextComponent(this.getCount() + " ")).appendSibling(this.getName()); + if (!this.isValid()) { + result.mergeStyle(TextFormatting.RED); + } + return result; + } + } +} \ 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..a01f06d08 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/ModAndClassUtil.java @@ -0,0 +1,30 @@ +package com.glodblock.github.util; + +import net.minecraftforge.fml.ModList; + +public final class ModAndClassUtil { + + public static boolean AUTO_P = false; + public static boolean NEE = false; + public static boolean JEI = false; + public static boolean REI = false; + + public static void init() { + if (ModList.get().isLoaded("packagedauto")) { + AUTO_P = true; + } + + if (ModList.get().isLoaded("neenergistics")) { + NEE = true; + } + + if (ModList.get().isLoaded("jei")) { + JEI = true; + } + + if (ModList.get().isLoaded("roughlyenoughitems")) { + REI = 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..ee38c8310 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/MouseRegionManager.java @@ -0,0 +1,84 @@ +package com.glodblock.github.util; + +import appeng.client.gui.AEBaseScreen; +import com.mojang.blaze3d.matrix.MatrixStack; +import net.minecraft.client.audio.SimpleSound; +import net.minecraft.util.SoundEvents; +import net.minecraft.util.text.ITextComponent; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + +public class MouseRegionManager { + + private final AEBaseScreen gui; + private final List regions = new ArrayList<>(); + + public MouseRegionManager(AEBaseScreen 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(double mX, double mY, int button) { + mX -= gui.getGuiLeft(); + mY -= gui.getGuiTop(); + for (Region region : regions) { + if (region.containsMouse(mX, mY) && region.handler.onClick(button)) { + gui.getMinecraft().getSoundHandler().play(SimpleSound.master(SoundEvents.UI_BUTTON_CLICK, 1F)); + return false; + } + } + return true; + } + + public void render(MatrixStack mStack, 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.drawTooltip(mStack, mX, mY, tooltip); + 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(double mX, double 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..ec4d56110 --- /dev/null +++ b/src/main/java/com/glodblock/github/util/NameConst.java @@ -0,0 +1,57 @@ +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_LARGE_INGREDIENT_BUFFER = "large_ingredient_buffer"; + public static final String BLOCK_BURETTE = "burette"; + public static final String BLOCK_DUAL_INTERFACE = "dual_interface"; + public static final String BLOCK_FLUID_LEVEL_MAINTAINER = "fluid_level_maintainer"; + public static final String BLOCK_FLUID_ASSEMBLER = "fluid_assembler"; + + 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 = "fluid_encoded_pattern"; + public static final String ITEM_DENSE_CRAFT_ENCODED_PATTERN = "dense_craft_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 ITEM_PART_EXTENDED_FLUID_PATTERN_TERMINAL = "part_fluid_pattern_ex_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_FLUID_PACKET_INFO = TT_KEY + "fluid_packet_info"; + 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_LARGE_INGREDIENT_BUFFER = GUI_KEY + BLOCK_LARGE_INGREDIENT_BUFFER; + public static final String GUI_BURETTE = GUI_KEY + BLOCK_BURETTE; + public static final String GUI_FLUID_LEVEL_MAINTAINER = GUI_KEY + BLOCK_FLUID_LEVEL_MAINTAINER; + public static final String GUI_FLUID_ASSEMBLER = GUI_KEY + BLOCK_FLUID_ASSEMBLER; + public static final String GUI_ITEM_AMOUNT_SET = GUI_KEY + "item_amount_set"; + public static final String GUI_ITEM_AMOUNT_SET_CONFIRM = GUI_KEY + "set"; + + public static final String MISC = FluidCraft.MODID + ".misc."; + public static final String MISC_THRESHOLD = MISC + "threshold"; + public static final String MISC_REQ = MISC + "request"; + + public static final ResourceLocation MODEL_DENSE_ENCODED_PATTERN = FluidCraft.resource("builtin/fluid_encoded_pattern"); + public static final ResourceLocation MODEL_DENSE_CRAFT_ENCODED_PATTERN = FluidCraft.resource("builtin/dense_craft_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/resources/META-INF/ae2fc_at.cfg b/src/main/resources/META-INF/ae2fc_at.cfg new file mode 100644 index 000000000..f1c62c4f0 --- /dev/null +++ b/src/main/resources/META-INF/ae2fc_at.cfg @@ -0,0 +1 @@ +protected net.minecraft.inventory.container.Container field_75149_d # listeners diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml new file mode 100644 index 000000000..577f33a54 --- /dev/null +++ b/src/main/resources/META-INF/mods.toml @@ -0,0 +1,48 @@ +modLoader="javafml" +loaderVersion="[32,)" +issueTrackerURL="https://github.com/GlodBlock/AE2FluidCraft-Rework/issues" +displayURL="https://github.com/GlodBlock/AE2FluidCraft-Rework" +logoFile="logo.png" +authors="GlodBlock" +license="LGPL-3.0" + +[[mods]] +modId="ae2fc" +version="1.0.0-a" +displayName="Fluid Craft for AE2" +description="Lets you do Crafting... with Fluids!" + +[[dependencies.ae2fc]] +modId="forge" +mandatory=true +versionRange="[36.1.10,37.0.0)" +ordering="NONE" +side="BOTH" + +[[dependencies.ae2fc]] +modId="minecraft" +mandatory=true +versionRange="[1.16.5,1.17.0)" +ordering="NONE" +side="BOTH" + +[[dependencies.ae2fc]] +modId="jei" +mandatory=false +versionRange="[7.7.0.98,)" +ordering="AFTER" +side="CLIENT" + +[[dependencies.ae2fc]] +modId="roughlyenoughitems" +mandatory=false +versionRange="[6.5.436,)" +ordering="AFTER" +side="CLIENT" + +[[dependencies.ae2fc]] +modId="appliedenergistics2" +mandatory=true +versionRange="[8.4.7,)" +ordering="AFTER" +side="BOTH" \ No newline at end of file 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..399a22d6c --- /dev/null +++ b/src/main/resources/assets/ae2fc/blockstates/dual_interface.json @@ -0,0 +1,48 @@ +{ + "variants": { + "omnidirectional=true,facing=east": { + "model": "ae2fc:block/dual_interface" + }, + "omnidirectional=true,facing=west": { + "model": "ae2fc:block/dual_interface" + }, + "omnidirectional=true,facing=south": { + "model": "ae2fc:block/dual_interface" + }, + "omnidirectional=true,facing=north": { + "model": "ae2fc:block/dual_interface" + }, + "omnidirectional=true,facing=up": { + "model": "ae2fc:block/dual_interface" + }, + "omnidirectional=true,facing=down": { + "model": "ae2fc:block/dual_interface" + }, + "omnidirectional=false,facing=east": { + "model": "ae2fc:block/dual_interface_oriented", + "x": 90, + "y": 90 + }, + "omnidirectional=false,facing=west": { + "model": "ae2fc:block/dual_interface_oriented", + "x": 90, + "y": 270 + }, + "omnidirectional=false,facing=south": { + "model": "ae2fc:block/dual_interface_oriented", + "x": 270 + }, + "omnidirectional=false,facing=north": { + "model": "ae2fc:block/dual_interface_oriented", + "x": 90 + }, + "omnidirectional=false,facing=up": { + "model": "ae2fc:block/dual_interface_oriented", + "x": 0 + }, + "omnidirectional=false,facing=down": { + "model": "ae2fc:block/dual_interface_oriented", + "x": 180 + } + } +} \ No newline at end of file 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..819b26baf --- /dev/null +++ b/src/main/resources/assets/ae2fc/blockstates/fluid_discretizer.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "ae2fc:block/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..0205c7610 --- /dev/null +++ b/src/main/resources/assets/ae2fc/blockstates/fluid_packet_decoder.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "ae2fc:block/fluid_packet_decoder" + } + } +} 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..a48586a74 --- /dev/null +++ b/src/main/resources/assets/ae2fc/blockstates/ingredient_buffer.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "ae2fc:block/ingredient_buffer" + } + } +} diff --git a/src/main/resources/assets/ae2fc/blockstates/large_ingredient_buffer.json b/src/main/resources/assets/ae2fc/blockstates/large_ingredient_buffer.json new file mode 100644 index 000000000..980e8487b --- /dev/null +++ b/src/main/resources/assets/ae2fc/blockstates/large_ingredient_buffer.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "ae2fc:block/large_ingredient_buffer" + } + } +} diff --git a/src/main/resources/assets/ae2fc/lang/en_us.json b/src/main/resources/assets/ae2fc/lang/en_us.json new file mode 100644 index 000000000..07b1e79be --- /dev/null +++ b/src/main/resources/assets/ae2fc/lang/en_us.json @@ -0,0 +1,57 @@ +{ + "itemGroup.ae2fc": "AE2 Fluid Crafting", + + "block.ae2fc.ingredient_buffer": "Ingredient Buffer", + "block.ae2fc.large_ingredient_buffer": "Large Ingredient Buffer", + "block.ae2fc.fluid_discretizer": "ME Fluid Discretizer", + "block.ae2fc.dual_interface": "ME Dual Interface", + "block.ae2fc.fluid_packet_decoder": "ME Fluid Packet Decoder", + + "item.ae2fc.fluid_drop": "Drop of %s", + "item.ae2fc.fluid_packet": "Fluid Packet", + "item.ae2fc.part_fluid_pattern_terminal": "ME Fluid Pattern Terminal", + "item.ae2fc.part_dual_interface": "ME Dual Interface", + "item.ae2fc.fluid_encoded_pattern": "Encoded Pattern", + + "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.large_ingredient_buffer": "Large Ingredient Buffer", + "ae2fc.gui.burette": "Precision Burette", + "ae2fc.gui.fluid_level_maintainer": "ME Fluid Level Maintainer", + "ae2fc.gui.fluid_assembler": "ME Fluid Assembler", + "ae2fc.gui.fluid_pattern_terminal": "Fluid Pattern Terminal", + "ae2fc.gui.item_amount_set": "Set Amount", + "ae2fc.gui.set": "Set", + + "ae2fc.tooltip.empty": "Empty", + "ae2fc.tooltip.dump_tank": "Dump Tank Contents", + "ae2fc.tooltip.invalid_fluid": "Invalid fluid!", + "ae2fc.tooltip.fluid_packet": "Use a Fluid Packet Decoder to convert this back into fluid.", + "ae2fc.tooltip.fluid_packet_info": "%s, %s mB", + + "ae2fc.tooltip.not_combine": "Merge the same items", + "ae2fc.tooltip.not_combine.hint": "Disabled", + "ae2fc.tooltip.combine": "Merge the same items", + "ae2fc.tooltip.combine.hint": "Enabled", + "ae2fc.tooltip.send_fluid": "Send Real Fluid", + "ae2fc.tooltip.send_fluid.hint": "The real fluid will be sent to target container", + "ae2fc.tooltip.send_packet": "Send Fluid Packet", + "ae2fc.tooltip.send_packet.hint": "The fluid packet item will be sent to target container", + "ae2fc.tooltip.fluid_first": "Place Fluid First In Pattern", + "ae2fc.tooltip.fluid_first.hint": "Enable", + "ae2fc.tooltip.item_first": "Place Fluid First In Pattern", + "ae2fc.tooltip.item_first.hint": "Disabled", + "ae2fc.tooltip.craft_fluid": "Encode Pattern", + "ae2fc.tooltip.craft_fluid.hint": "Special pattern for ME fluid assembler. You can use fluid directly in crafting recipes instead of buckets.", + "ae2fc.tooltip.splitting": "Allow Splitting Items and Fluids", + "ae2fc.tooltip.splitting.hint": "Items and fluids may be separated to different sides if the interface does not point into any direction.", + "ae2fc.tooltip.not_splitting": "Prevent Splitting Items and Fluids", + "ae2fc.tooltip.not_splitting.hint": "Items and fluids can only be pushed out together through the same side of the interface.", + "ae2fc.tooltip.block_all": "Block All", + "ae2fc.tooltip.block_all.hint": "Blocking mode checks both item and fluid.", + "ae2fc.tooltip.block_item": "Block Item", + "ae2fc.tooltip.block_item.hint": "Blocking mode only checks item.", + "ae2fc.tooltip.block_fluid": "Block Fluid", + "ae2fc.tooltip.block_fluid.hint": "Blocking mode only checks fluid." +} \ No newline at end of file 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_assembler.json b/src/main/resources/assets/ae2fc/models/block/fluid_assembler.json new file mode 100644 index 000000000..9d17496c4 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/block/fluid_assembler.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ae2fc:blocks/fluid_assembler" + } +} 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_level_maintainer.json b/src/main/resources/assets/ae2fc/models/block/fluid_level_maintainer.json new file mode 100644 index 000000000..b4de2a3f1 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/block/fluid_level_maintainer.json @@ -0,0 +1,12 @@ +{ + "parent": "block/orientable", + "textures": { + "particle": "ae2fc:blocks/fluid_level_maintainer", + "down": "ae2fc:blocks/fluid_level_maintainer_side", + "up": "ae2fc:blocks/fluid_level_maintainer", + "north": "ae2fc:blocks/fluid_level_maintainer_side", + "south": "ae2fc:blocks/fluid_level_maintainer_side", + "east": "ae2fc:blocks/fluid_level_maintainer_side", + "west": "ae2fc:blocks/fluid_level_maintainer_side" + } +} \ No newline at end of file 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/block/large_ingredient_buffer.json b/src/main/resources/assets/ae2fc/models/block/large_ingredient_buffer.json new file mode 100644 index 000000000..3c79f2d95 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/block/large_ingredient_buffer.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "ae2fc:blocks/large_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_craft_encoded_pattern.json b/src/main/resources/assets/ae2fc/models/item/dense_craft_encoded_pattern.json new file mode 100644 index 000000000..b0c5dcfd1 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/dense_craft_encoded_pattern.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ae2fc:items/dense_craft_encoded_pattern" + } +} \ No newline at end of file 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_assembler.json b/src/main/resources/assets/ae2fc/models/item/fluid_assembler.json new file mode 100644 index 000000000..33b212cbf --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/fluid_assembler.json @@ -0,0 +1,3 @@ +{ + "parent": "ae2fc:block/fluid_assembler" +} \ No newline at end of file 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_encoded_pattern.json b/src/main/resources/assets/ae2fc/models/item/fluid_encoded_pattern.json new file mode 100644 index 000000000..a31fec85b --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/fluid_encoded_pattern.json @@ -0,0 +1,4 @@ +{ + "loader": "ae2fc:fluid_encoded_pattern", + "baseModel": "ae2fc:item/fluid_encoded_pattern_base" +} diff --git a/src/main/resources/assets/ae2fc/models/item/fluid_encoded_pattern_base.json b/src/main/resources/assets/ae2fc/models/item/fluid_encoded_pattern_base.json new file mode 100644 index 000000000..dcf8ebad7 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/fluid_encoded_pattern_base.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "ae2fc:items/fluid_encoded_pattern" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ae2fc/models/item/fluid_level_maintainer.json b/src/main/resources/assets/ae2fc/models/item/fluid_level_maintainer.json new file mode 100644 index 000000000..95e97f173 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/fluid_level_maintainer.json @@ -0,0 +1,3 @@ +{ + "parent": "ae2fc:block/fluid_level_maintainer" +} 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..405e2874e --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/fluid_packet.json @@ -0,0 +1,8 @@ +{ + "loader": "ae2fc:fluid_packet", + "parent": "item/generated", + "textures": { + "layer0": "ae2fc:items/fluid_packet_mask", + "layer1": "ae2fc:items/fluid_packet" + } +} 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/large_ingredient_buffer.json b/src/main/resources/assets/ae2fc/models/item/large_ingredient_buffer.json new file mode 100644 index 000000000..d324c988b --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/large_ingredient_buffer.json @@ -0,0 +1,3 @@ +{ + "parent": "ae2fc:block/large_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..be9fa71be --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/part_dual_interface.json @@ -0,0 +1,106 @@ +{ + "parent": "appliedenergistics2:item/part_base", + "textures": { + "sides": "appliedenergistics2:part/monitor_sides", + "back": "appliedenergistics2:part/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_ex_terminal.json b/src/main/resources/assets/ae2fc/models/item/part_fluid_pattern_ex_terminal.json new file mode 100644 index 000000000..dced00638 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/part_fluid_pattern_ex_terminal.json @@ -0,0 +1,9 @@ +{ + "parent": "appliedenergistics2:item/part/display", + "textures": { + "front": "appliedenergistics2:items/part/expanded_processing_pattern_terminal", + "front_bright": "ae2fc:parts/pattern_terminal_ex_bright", + "front_medium": "ae2fc:parts/pattern_terminal_ex_medium", + "front_dark": "ae2fc:parts/pattern_terminal_ex_dark" + } +} \ No newline at end of file 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..6c08834b5 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/item/part_fluid_pattern_terminal.json @@ -0,0 +1,9 @@ +{ + "parent": "appliedenergistics2:item/display_base", + "textures": { + "front": "appliedenergistics2:part/pattern_terminal", + "front_bright": "ae2fc:parts/pattern_terminal_bright", + "front_medium": "ae2fc:parts/pattern_terminal_medium", + "front_dark": "ae2fc:parts/pattern_terminal_dark" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ae2fc/models/part/f_pattern_ex_term_off.json b/src/main/resources/assets/ae2fc/models/part/f_pattern_ex_term_off.json new file mode 100644 index 000000000..64da5c376 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/part/f_pattern_ex_term_off.json @@ -0,0 +1,8 @@ +{ + "parent": "appliedenergistics2:part/display_off", + "textures": { + "lightsBright": "ae2fc:parts/pattern_terminal_ex_bright", + "lightsMedium": "ae2fc:parts/pattern_terminal_ex_medium", + "lightsDark": "ae2fc:parts/pattern_terminal_ex_dark" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ae2fc/models/part/f_pattern_ex_term_on.json b/src/main/resources/assets/ae2fc/models/part/f_pattern_ex_term_on.json new file mode 100644 index 000000000..7f91dad83 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/part/f_pattern_ex_term_on.json @@ -0,0 +1,76 @@ +{ + "ae2_uvl_marker": true, + "textures": { + "lightsBright": "ae2fc:parts/pattern_terminal_ex_bright", + "lightsMedium": "ae2fc:parts/pattern_terminal_ex_medium", + "lightsDark": "ae2fc:parts/pattern_terminal_ex_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 + } + } + } + } + ] +} \ No newline at end of file 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..f23c08f8b --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/part/f_pattern_term_on.json @@ -0,0 +1,8 @@ +{ + "parent": "appliedenergistics2:part/pattern_terminal_on", + "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/interface_base.json b/src/main/resources/assets/ae2fc/models/part/interface_base.json new file mode 100644 index 000000000..c3eb02ab5 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/part/interface_base.json @@ -0,0 +1,104 @@ +{ + "textures": { + "sides": "appliedenergistics2:part/export_bus_sides", + "sidesStatus": "appliedenergistics2:part/monitor_sides_status", + "back": "appliedenergistics2:part/monitor_back", + "front": "ae2fc:blocks/interface", + "particle": "appliedenergistics2:part/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..77bbb93c2 --- /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:part/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..433a4a233 --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/part/interface_off.json @@ -0,0 +1,33 @@ +{ + "textures": { + "indicator": "appliedenergistics2:part/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..187259ceb --- /dev/null +++ b/src/main/resources/assets/ae2fc/models/part/interface_on.json @@ -0,0 +1,54 @@ +{ + "ae2_uvl_marker": true, + "textures": { + "indicator": "appliedenergistics2:part/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/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_assembler.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_assembler.png new file mode 100644 index 000000000..a0859beb0 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_assembler.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..c0da91e8e 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_level_maintainer.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_level_maintainer.png new file mode 100644 index 000000000..66f1159ee Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_level_maintainer.png differ diff --git a/src/main/resources/assets/ae2fc/textures/blocks/fluid_level_maintainer_side.png b/src/main/resources/assets/ae2fc/textures/blocks/fluid_level_maintainer_side.png new file mode 100644 index 000000000..88304b937 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/fluid_level_maintainer_side.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..a6c298937 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..99ce20c0e 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..80a60336b 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/blocks/large_ingredient_buffer.png b/src/main/resources/assets/ae2fc/textures/blocks/large_ingredient_buffer.png new file mode 100644 index 000000000..31d8cd0b8 Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/blocks/large_ingredient_buffer.png differ diff --git a/src/main/resources/assets/ae2fc/textures/items/dense_craft_encoded_pattern.png b/src/main/resources/assets/ae2fc/textures/items/dense_craft_encoded_pattern.png new file mode 100644 index 000000000..86bc00a2f Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/items/dense_craft_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_encoded_pattern.png b/src/main/resources/assets/ae2fc/textures/items/fluid_encoded_pattern.png new file mode 100644 index 000000000..f4210af1e Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/items/fluid_encoded_pattern.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..9b745b1ec 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_mask.png b/src/main/resources/assets/ae2fc/textures/items/fluid_packet_mask.png new file mode 100644 index 000000000..0ed80022c Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/items/fluid_packet_mask.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_ex_bright.png b/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_ex_bright.png new file mode 100644 index 000000000..45985f13d Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_ex_bright.png differ diff --git a/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_ex_dark.png b/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_ex_dark.png new file mode 100644 index 000000000..44e4c64ff Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_ex_dark.png differ diff --git a/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_ex_medium.png b/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_ex_medium.png new file mode 100644 index 000000000..e881def0c Binary files /dev/null and b/src/main/resources/assets/ae2fc/textures/parts/pattern_terminal_ex_medium.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/assets/appliedenergistics2/screens/dual_fluid_interface.json b/src/main/resources/assets/appliedenergistics2/screens/dual_fluid_interface.json new file mode 100644 index 000000000..ddb529421 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/screens/dual_fluid_interface.json @@ -0,0 +1,90 @@ +{ + "$schema": "schema.json", + "includes": ["common/common.json", "common/player_inventory.json"], + "background": { + "texture": "guis/interfacefluid.png", + "srcRect": [0, 0, 176, 231] + }, + "slots": { + "CONFIG": { + "left": 35, + "top": 35, + "grid": "HORIZONTAL" + } + }, + "text": { + "dialog_title": { + "text": { + "translate": "gui.appliedenergistics2.FluidInterface" + }, + "position": { + "left": 8, + "top": 6 + } + }, + "interface_config": { + "text": { + "translate": "gui.appliedenergistics2.Config" + }, + "position": { + "left": 35, + "top": 24 + } + }, + "interface_stored_fluids": { + "text": { + "translate": "gui.appliedenergistics2.StoredFluids" + }, + "position": { + "left": 35, + "top": 125 + } + } + }, + "widgets": { + "priorityBtn": { + "left": 154, + "top": 0 + }, + "switchInterface": { + "left": 133, + "top": 0 + }, + "tank1": { + "left": 35, + "top": 53, + "width": 16, + "height": 68 + }, + "tank2": { + "left": 53, + "top": 53, + "width": 16, + "height": 68 + }, + "tank3": { + "left": 71, + "top": 53, + "width": 16, + "height": 68 + }, + "tank4": { + "left": 89, + "top": 53, + "width": 16, + "height": 68 + }, + "tank5": { + "left": 107, + "top": 53, + "width": 16, + "height": 68 + }, + "tank6": { + "left": 125, + "top": 53, + "width": 16, + "height": 68 + } + } +} diff --git a/src/main/resources/assets/appliedenergistics2/screens/dual_item_interface.json b/src/main/resources/assets/appliedenergistics2/screens/dual_item_interface.json new file mode 100644 index 000000000..245a93d45 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/screens/dual_item_interface.json @@ -0,0 +1,73 @@ +{ + "$schema": "schema.json", + "includes": ["common/common.json", "common/player_inventory.json"], + "background": { + "texture": "guis/interface.png", + "srcRect": [0, 0, 176, 211] + }, + "slots": { + "CONFIG": { + "left": 8, + "top": 35, + "grid": "HORIZONTAL" + }, + "STORAGE": { + "left": 8, + "top": 53, + "grid": "HORIZONTAL" + }, + "ENCODED_PATTERN": { + "left": 8, + "top": 97, + "grid": "HORIZONTAL" + } + }, + "text": { + "dialog_title": { + "text": { + "translate": "gui.appliedenergistics2.Interface" + }, + "position": { + "left": 8, + "top": 6 + } + }, + "interface_config": { + "text": { + "translate": "gui.appliedenergistics2.Config" + }, + "position": { + "left": 8, + "top": 24 + } + }, + "interface_stored_items": { + "text": { + "translate": "gui.appliedenergistics2.StoredItems" + }, + "position": { + "left": 8, + "top": 73 + } + }, + "interface_patterns": { + "text": { + "translate": "gui.appliedenergistics2.Patterns" + }, + "position": { + "left": 8, + "top": 86 + } + } + }, + "widgets": { + "priorityBtn": { + "left": 154, + "top": 0 + }, + "switchInterface": { + "left": 133, + "top": 0 + } + } +} diff --git a/src/main/resources/assets/appliedenergistics2/screens/fc_priority.json b/src/main/resources/assets/appliedenergistics2/screens/fc_priority.json new file mode 100644 index 000000000..7fc761361 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/screens/fc_priority.json @@ -0,0 +1,49 @@ +{ + "$schema": "schema.json", + "includes": ["common/common.json"], + "background": { + "texture": "guis/priority.png", + "srcRect": [0, 0, 176, 125] + }, + "text": { + "dialog_title": { + "text": { + "translate": "gui.appliedenergistics2.Priority" + }, + "position": { + "left": 8, + "top": 6 + } + }, + "priority_insertion_hint": { + "text": { + "translate": "gui.appliedenergistics2.PriorityInsertionHint" + }, + "position": { + "left": 8, + "top": 98 + } + }, + "priority_extraction_hint": { + "text": { + "translate": "gui.appliedenergistics2.PriorityExtractionHint" + }, + "position": { + "left": 8, + "top": 110 + } + } + }, + "widgets": { + "back": { + "left": 154, + "top": 0 + }, + "priority": { + "left": 20, + "top": 30, + "width": 138, + "height": 62 + } + } +} diff --git a/src/main/resources/assets/appliedenergistics2/screens/fluid_packet_decoder.json b/src/main/resources/assets/appliedenergistics2/screens/fluid_packet_decoder.json new file mode 100644 index 000000000..77ef26f24 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/screens/fluid_packet_decoder.json @@ -0,0 +1,26 @@ +{ + "$schema": "schema.json", + "includes": ["common/common.json", "common/player_inventory.json"], + "background": { + "texture": "gui/fluid_packet_decoder.png", + "srcRect": [0, 0, 176, 166] + }, + "slots": { + "STORAGE": { + "left": 80, + "top": 35, + "grid": "HORIZONTAL" + } + }, + "text": { + "dialog_title": { + "text": { + "translate": "ae2fc.gui.fluid_packet_decoder" + }, + "position": { + "left": 8, + "top": 6 + } + } + } +} diff --git a/src/main/resources/assets/appliedenergistics2/screens/fluid_pattern_terminal.json b/src/main/resources/assets/appliedenergistics2/screens/fluid_pattern_terminal.json new file mode 100644 index 000000000..052718a7a --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/screens/fluid_pattern_terminal.json @@ -0,0 +1,104 @@ +{ + "$schema": "../schema.json", + "includes": ["terminals/item_terminal.json"], + "slots": { + "BLANK_PATTERN": { + "left": 147, + "bottom": 161 + }, + "ENCODED_PATTERN": { + "left": 147, + "bottom": 118 + }, + "CRAFTING_GRID": { + "left": 18, + "bottom": 156, + "grid": "BREAK_AFTER_3COLS" + }, + "CRAFTING_RESULT": { + "left": 110, + "bottom": 138 + }, + "PROCESSING_RESULT": { + "left": 110, + "bottom": 156, + "grid": "VERTICAL" + } + }, + "text": { + "dialog_title": { + "text": { + "translate": "gui.appliedenergistics2.Terminal" + }, + "position": { + "left": 8, + "top": 6 + } + }, + "crafting_grid_title": { + "text": { + "translate": "ae2fc.gui.fluid_pattern_terminal" + }, + "position": { + "left": 8, + "bottom": 175 + } + } + }, + "terminalStyle": { + "header": { + "texture": "guis/pattern.png", + "srcRect": [0, 0, 195, 17] + }, + "firstRow": { + "texture": "guis/pattern.png", + "srcRect": [0, 17, 195, 18] + }, + "row": { + "texture": "guis/pattern.png", + "srcRect": [0, 35, 195, 18] + }, + "lastRow": { + "texture": "guis/pattern.png", + "srcRect": [0, 53, 195, 18] + }, + "bottom": { + "texture": "guis/pattern.png", + "srcRect": [0, 71, 195, 178] + } + }, + "widgets": { + "craftingPatternMode": { + "left": 173, + "bottom": 177 + }, + "processingPatternMode": { + "left": 173, + "bottom": 177 + }, + "substitutionsEnabled": { + "left": 84, + "bottom": 163 + }, + "substitutionsDisabled": { + "left": 84, + "bottom": 163 + }, + "clearPattern": { + "left": 74, + "bottom": 163 + }, + "combineBtn": { + "left": 84, + "bottom": 163 + }, + "fluidBtn": { + "left": 74, + "bottom": 153 + }, + "encodePattern": { + "left": 147, + "bottom": 142 + } + } +} diff --git a/src/main/resources/assets/appliedenergistics2/screens/ingredient_buffer.json b/src/main/resources/assets/appliedenergistics2/screens/ingredient_buffer.json new file mode 100644 index 000000000..63f9bb7ba --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/screens/ingredient_buffer.json @@ -0,0 +1,26 @@ +{ + "$schema": "schema.json", + "includes": ["common/common.json", "common/player_inventory.json"], + "background": { + "texture": "gui/ingredient_buffer.png", + "srcRect": [0, 0, 176, 222] + }, + "slots": { + "STORAGE": { + "left": 8, + "top": 108, + "grid": "HORIZONTAL" + } + }, + "text": { + "dialog_title": { + "text": { + "translate": "ae2fc.gui.ingredient_buffer" + }, + "position": { + "left": 8, + "top": 6 + } + } + } +} diff --git a/src/main/resources/assets/appliedenergistics2/screens/large_ingredient_buffer.json b/src/main/resources/assets/appliedenergistics2/screens/large_ingredient_buffer.json new file mode 100644 index 000000000..462073c55 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/screens/large_ingredient_buffer.json @@ -0,0 +1,26 @@ +{ + "$schema": "schema.json", + "includes": ["common/common.json", "common/player_inventory.json"], + "background": { + "texture": "gui/large_ingredient_buffer.png", + "srcRect": [0, 0, 176, 222] + }, + "slots": { + "STORAGE": { + "left": 8, + "top": 72, + "grid": "BREAK_AFTER_9COLS" + } + }, + "text": { + "dialog_title": { + "text": { + "translate": "ae2fc.gui.large_ingredient_buffer" + }, + "position": { + "left": 8, + "top": 6 + } + } + } +} diff --git a/src/main/resources/assets/appliedenergistics2/textures/gui/burette.png b/src/main/resources/assets/appliedenergistics2/textures/gui/burette.png new file mode 100644 index 000000000..7238bf637 Binary files /dev/null and b/src/main/resources/assets/appliedenergistics2/textures/gui/burette.png differ diff --git a/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_assembler.png b/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_assembler.png new file mode 100644 index 000000000..6435daecd Binary files /dev/null and b/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_assembler.png differ diff --git a/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_assembler2.png b/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_assembler2.png new file mode 100644 index 000000000..023c41a2d Binary files /dev/null and b/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_assembler2.png differ diff --git a/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_assembler3.png b/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_assembler3.png new file mode 100644 index 000000000..795d0306d Binary files /dev/null and b/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_assembler3.png differ diff --git a/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_assembler4.png b/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_assembler4.png new file mode 100644 index 000000000..a65acc2bc Binary files /dev/null and b/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_assembler4.png differ diff --git a/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_level_maintainer.png b/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_level_maintainer.png new file mode 100644 index 000000000..e575eb122 Binary files /dev/null and b/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_level_maintainer.png differ diff --git a/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_packet_decoder.png b/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_packet_decoder.png new file mode 100644 index 000000000..4e17ee57f Binary files /dev/null and b/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_packet_decoder.png differ diff --git a/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_pattern_encoder.png b/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_pattern_encoder.png new file mode 100644 index 000000000..045611f80 Binary files /dev/null and b/src/main/resources/assets/appliedenergistics2/textures/gui/fluid_pattern_encoder.png differ diff --git a/src/main/resources/assets/appliedenergistics2/textures/gui/ingredient_buffer.png b/src/main/resources/assets/appliedenergistics2/textures/gui/ingredient_buffer.png new file mode 100644 index 000000000..e1d351945 Binary files /dev/null and b/src/main/resources/assets/appliedenergistics2/textures/gui/ingredient_buffer.png differ diff --git a/src/main/resources/assets/appliedenergistics2/textures/gui/large_ingredient_buffer.png b/src/main/resources/assets/appliedenergistics2/textures/gui/large_ingredient_buffer.png new file mode 100644 index 000000000..f7763ab05 Binary files /dev/null and b/src/main/resources/assets/appliedenergistics2/textures/gui/large_ingredient_buffer.png differ diff --git a/src/main/resources/assets/appliedenergistics2/textures/gui/states.png b/src/main/resources/assets/appliedenergistics2/textures/gui/states.png new file mode 100644 index 000000000..8c25f121e Binary files /dev/null and b/src/main/resources/assets/appliedenergistics2/textures/gui/states.png differ diff --git a/src/main/resources/data/ae2fc/recipes/dual_interface.json b/src/main/resources/data/ae2fc/recipes/dual_interface.json new file mode 100644 index 000000000..28bbaa329 --- /dev/null +++ b/src/main/resources/data/ae2fc/recipes/dual_interface.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "tag": "appliedenergistics2:interface" + }, + { + "tag": "appliedenergistics2:fluid_interface" + } + ], + "result": { + "item": "ae2fc:dual_interface", + "nbt": {} + } +} diff --git a/src/main/resources/data/ae2fc/recipes/dual_interface_alter.json b/src/main/resources/data/ae2fc/recipes/dual_interface_alter.json new file mode 100644 index 000000000..56e59a894 --- /dev/null +++ b/src/main/resources/data/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" + } +} \ No newline at end of file diff --git a/src/main/resources/data/ae2fc/recipes/fluid_discretizer.json b/src/main/resources/data/ae2fc/recipes/fluid_discretizer.json new file mode 100644 index 000000000..7d39d207e --- /dev/null +++ b/src/main/resources/data/ae2fc/recipes/fluid_discretizer.json @@ -0,0 +1,29 @@ +{ + "type": "minecraft:crafting_shaped", + "result": { + "item": "ae2fc:fluid_discretizer", + "count": 1 + }, + "pattern": [ + "ipi", + "smt", + "ipi" + ], + "key": { + "i": { + "tag": "forge:ingots/iron" + }, + "p": { + "item": "appliedenergistics2:engineering_processor" + }, + "s": { + "item": "appliedenergistics2:fluid_storage_bus" + }, + "m": { + "item": "appliedenergistics2:condenser" + }, + "t": { + "item": "appliedenergistics2:storage_bus" + } + } +} diff --git a/src/main/resources/data/ae2fc/recipes/fluid_packet_decoder.json b/src/main/resources/data/ae2fc/recipes/fluid_packet_decoder.json new file mode 100644 index 000000000..0aaac741c --- /dev/null +++ b/src/main/resources/data/ae2fc/recipes/fluid_packet_decoder.json @@ -0,0 +1,29 @@ +{ + "type": "minecraft:crafting_shaped", + "result": { + "item": "ae2fc:fluid_packet_decoder", + "count": 1 + }, + "pattern": [ + "ihi", + "cfc", + "ipi" + ], + "key": { + "i": { + "tag": "forge:ingots/iron" + }, + "h": { + "item": "minecraft:hopper" + }, + "c": { + "item": "appliedenergistics2:fluix_glass_cable" + }, + "f": { + "tag": "appliedenergistics2:fluid_interface" + }, + "p": { + "item": "appliedenergistics2:calculation_processor" + } + } +} diff --git a/src/main/resources/data/ae2fc/recipes/ingredient_buffer.json b/src/main/resources/data/ae2fc/recipes/ingredient_buffer.json new file mode 100644 index 000000000..1447b1a73 --- /dev/null +++ b/src/main/resources/data/ae2fc/recipes/ingredient_buffer.json @@ -0,0 +1,32 @@ +{ + "type": "minecraft:crafting_shaped", + "result": { + "item": "ae2fc:ingredient_buffer", + "count": 1 + }, + "pattern": [ + "ili", + "agf", + "isi" + ], + "key": { + "i": { + "tag": "forge:ingots/iron" + }, + "g": { + "item": "appliedenergistics2:quartz_glass" + }, + "l": { + "item": "appliedenergistics2:1k_cell_component" + }, + "a": { + "item": "appliedenergistics2:annihilation_core" + }, + "f": { + "item": "appliedenergistics2:formation_core" + }, + "s": { + "item": "appliedenergistics2:1k_fluid_cell_component" + } + } +} diff --git a/src/main/resources/data/ae2fc/recipes/large_ingredient_buffer.json b/src/main/resources/data/ae2fc/recipes/large_ingredient_buffer.json new file mode 100644 index 000000000..d04428e76 --- /dev/null +++ b/src/main/resources/data/ae2fc/recipes/large_ingredient_buffer.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "result": { + "item": "ae2fc:large_ingredient_buffer", + "count": 1 + }, + "pattern": [ + "bgb", + "geg", + "bgb" + ], + "key": { + "b": { + "item": "ae2fc:ingredient_buffer" + }, + "g": { + "item": "appliedenergistics2:quartz_glass" + }, + "e": { + "item": "appliedenergistics2:engineering_processor" + } + } +} diff --git a/src/main/resources/data/ae2fc/recipes/part_dual_interface.json b/src/main/resources/data/ae2fc/recipes/part_dual_interface.json new file mode 100644 index 000000000..dc5d91f7b --- /dev/null +++ b/src/main/resources/data/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/data/ae2fc/recipes/part_fluid_pattern_terminal.json b/src/main/resources/data/ae2fc/recipes/part_fluid_pattern_terminal.json new file mode 100644 index 000000000..648e007ad --- /dev/null +++ b/src/main/resources/data/ae2fc/recipes/part_fluid_pattern_terminal.json @@ -0,0 +1,14 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "appliedenergistics2:pattern_terminal" + }, + { + "item": "ae2fc:fluid_packet_decoder" + } + ], + "result": { + "item": "ae2fc:part_fluid_pattern_terminal" + } +} diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png new file mode 100644 index 000000000..129cbc24f Binary files /dev/null and b/src/main/resources/logo.png differ diff --git a/src/main/resources/mixins.ae2fc.json b/src/main/resources/mixins.ae2fc.json new file mode 100644 index 000000000..f4d2e44e9 --- /dev/null +++ b/src/main/resources/mixins.ae2fc.json @@ -0,0 +1,25 @@ +{ + "required": true, + "package": "com.glodblock.github.mixins", + "refmap": "mixins.ae2fc.refmap.json", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "ApiCraftingMixin", + "CraftConfirmContainerMixin", + "CraftingCpuMixin", + "CraftingGridCacheMixin", + "CraftingTreeNodeMixin", + "DualityInterfaceMixin", + "InterfaceSlotMixin", + "InterfaceTerminalContainerMixin", + "PatternSlotPacketMixin", + "RestrictedInputSlotMixin" + ], + "client": [ + "AESubScreenMixin", + "CraftConfirmTableRendererMixin", + "CraftingStatusTableRendererMixin", + "EncodedPatternBakedModelMixin" + ], + "server": [] +} \ 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 + } +}