├── .github ├── FUNDING.yml └── workflows │ ├── main.yml │ └── release.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── media ├── 2020-04-18_01.04.55.png ├── 2020-04-18_01.05.17.png ├── 2020-04-18_01.06.11.png ├── 2020-10-17_00.58.03.png ├── banner.png ├── logo.png └── terminal.png ├── settings.gradle └── src └── main ├── java └── de │ └── ellpeck │ └── prettypipes │ ├── PrettyPipes.java │ ├── Registry.java │ ├── Utility.java │ ├── compat │ └── jei │ │ ├── CraftingModuleTransferHandler.java │ │ ├── CraftingTerminalTransferHandler.java │ │ └── JEIPrettyPipesPlugin.java │ ├── entities │ ├── PipeFrameEntity.java │ └── PipeFrameRenderer.java │ ├── items │ ├── IModule.java │ ├── ModuleItem.java │ ├── ModuleTier.java │ ├── PipeFrameItem.java │ └── WrenchItem.java │ ├── misc │ ├── DirectionSelector.java │ ├── EquatableItemStack.java │ ├── Events.java │ ├── FilterSlot.java │ ├── ItemEquality.java │ ├── ItemFilter.java │ ├── ItemOrder.java │ ├── ItemTerminalWidget.java │ ├── ModuleClearingRecipe.java │ └── PlayerPrefs.java │ ├── network │ ├── ActiveCraft.java │ ├── NetworkEdge.java │ ├── NetworkItem.java │ ├── NetworkLocation.java │ ├── NetworkLock.java │ ├── PipeItem.java │ └── PipeNetwork.java │ ├── packets │ ├── PacketButton.java │ ├── PacketCraftingModuleTransfer.java │ ├── PacketGhostSlot.java │ ├── PacketItemEnterPipe.java │ ├── PacketNetworkItems.java │ └── PacketRequest.java │ ├── pipe │ ├── ConnectionType.java │ ├── IPipeConnectable.java │ ├── IPipeItem.java │ ├── PipeBlock.java │ ├── PipeBlockEntity.java │ ├── PipeRenderer.java │ ├── containers │ │ ├── AbstractPipeContainer.java │ │ ├── AbstractPipeGui.java │ │ ├── MainPipeContainer.java │ │ └── MainPipeGui.java │ └── modules │ │ ├── HighPriorityModuleItem.java │ │ ├── LowPriorityModuleItem.java │ │ ├── RedstoneModuleItem.java │ │ ├── SortingModuleItem.java │ │ ├── SpeedModuleItem.java │ │ ├── craft │ │ ├── CraftingModuleContainer.java │ │ ├── CraftingModuleGui.java │ │ └── CraftingModuleItem.java │ │ ├── extraction │ │ ├── ExtractionModuleContainer.java │ │ ├── ExtractionModuleGui.java │ │ └── ExtractionModuleItem.java │ │ ├── filter │ │ ├── FilterIncreaseModuleContainer.java │ │ ├── FilterIncreaseModuleGui.java │ │ └── FilterIncreaseModuleItem.java │ │ ├── insertion │ │ ├── FilterModuleContainer.java │ │ ├── FilterModuleGui.java │ │ └── FilterModuleItem.java │ │ ├── modifier │ │ ├── FilterModifierModuleContainer.java │ │ ├── FilterModifierModuleGui.java │ │ └── FilterModifierModuleItem.java │ │ ├── retrieval │ │ ├── RetrievalModuleContainer.java │ │ ├── RetrievalModuleGui.java │ │ └── RetrievalModuleItem.java │ │ └── stacksize │ │ ├── StackSizeModuleContainer.java │ │ ├── StackSizeModuleGui.java │ │ └── StackSizeModuleItem.java │ ├── pressurizer │ ├── PressurizerBlock.java │ ├── PressurizerBlockEntity.java │ ├── PressurizerContainer.java │ └── PressurizerGui.java │ └── terminal │ ├── CraftingTerminalBlock.java │ ├── CraftingTerminalBlockEntity.java │ ├── ItemTerminalBlock.java │ ├── ItemTerminalBlockEntity.java │ └── containers │ ├── CraftingTerminalContainer.java │ ├── CraftingTerminalGui.java │ ├── ItemTerminalContainer.java │ ├── ItemTerminalGui.java │ └── WrappedCraftingInventory.java └── resources ├── META-INF └── neoforge.mods.toml ├── assets └── prettypipes │ ├── blockstates │ ├── crafting_terminal.json │ ├── item_terminal.json │ ├── pipe.json │ └── pressurizer.json │ ├── lang │ ├── en_us.json │ ├── fr_fr.json │ └── ru_ru.json │ ├── models │ ├── block │ │ ├── crafting_terminal.json │ │ ├── item_terminal.json │ │ ├── pipe_center.json │ │ ├── pipe_end.json │ │ ├── pipe_legs.json │ │ └── pressurizer.json │ └── item │ │ ├── blank_module.json │ │ ├── crafting_terminal.json │ │ ├── damage_filter_modifier.json │ │ ├── filter_increase_modifier.json │ │ ├── high_crafting_module.json │ │ ├── high_extraction_module.json │ │ ├── high_filter_module.json │ │ ├── high_high_priority_module.json │ │ ├── high_low_priority_module.json │ │ ├── high_retrieval_module.json │ │ ├── high_speed_module.json │ │ ├── item_terminal.json │ │ ├── low_crafting_module.json │ │ ├── low_extraction_module.json │ │ ├── low_filter_module.json │ │ ├── low_high_priority_module.json │ │ ├── low_low_priority_module.json │ │ ├── low_retrieval_module.json │ │ ├── low_speed_module.json │ │ ├── medium_crafting_module.json │ │ ├── medium_extraction_module.json │ │ ├── medium_filter_module.json │ │ ├── medium_high_priority_module.json │ │ ├── medium_low_priority_module.json │ │ ├── medium_retrieval_module.json │ │ ├── medium_speed_module.json │ │ ├── mod_filter_modifier.json │ │ ├── nbt_filter_modifier.json │ │ ├── pipe.json │ │ ├── pipe_frame.json │ │ ├── pressurizer.json │ │ ├── random_sorting_modifier.json │ │ ├── redstone_module.json │ │ ├── round_robin_sorting_modifier.json │ │ ├── stack_size_module.json │ │ ├── tag_filter_modifier.json │ │ └── wrench.json │ └── textures │ ├── block │ ├── crafting_terminal.png │ ├── item_terminal.png │ ├── item_terminal_top.png │ ├── pipe.png │ ├── pipe_legs.png │ └── pressurizer.png │ ├── gui │ ├── crafting_terminal.png │ ├── item_terminal.png │ ├── pipe.png │ └── pressurizer.png │ └── item │ ├── blank_module.png │ ├── damage_filter_modifier.png │ ├── filter_increase_modifier.png │ ├── high_crafting_module.png │ ├── high_extraction_module.png │ ├── high_filter_module.png │ ├── high_high_priority_module.png │ ├── high_low_priority_module.png │ ├── high_retrieval_module.png │ ├── high_speed_module.png │ ├── low_crafting_module.png │ ├── low_extraction_module.png │ ├── low_filter_module.png │ ├── low_high_priority_module.png │ ├── low_low_priority_module.png │ ├── low_retrieval_module.png │ ├── low_speed_module.png │ ├── medium_crafting_module.png │ ├── medium_extraction_module.png │ ├── medium_filter_module.png │ ├── medium_high_priority_module.png │ ├── medium_low_priority_module.png │ ├── medium_retrieval_module.png │ ├── medium_speed_module.png │ ├── mod_filter_modifier.png │ ├── nbt_filter_modifier.png │ ├── pipe_frame.png │ ├── random_sorting_modifier.png │ ├── redstone_module.png │ ├── round_robin_sorting_modifier.png │ ├── stack_size_module.png │ ├── tag_filter_modifier.png │ └── wrench.png ├── data ├── minecraft │ └── tags │ │ └── block │ │ └── mineable │ │ └── pickaxe.json └── prettypipes │ ├── loot_table │ └── blocks │ │ ├── crafting_terminal.json │ │ ├── item_terminal.json │ │ ├── pipe.json │ │ └── pressurizer.json │ └── recipe │ ├── blank_module.json │ ├── crafting_terminal.json │ ├── damage_filter_modifier.json │ ├── filter_increase_modifier.json │ ├── high_crafting_module.json │ ├── high_extraction_module.json │ ├── high_filter_module.json │ ├── high_high_priority_module.json │ ├── high_low_priority_module.json │ ├── high_retrieval_module.json │ ├── high_speed_module.json │ ├── item_terminal.json │ ├── low_crafting_module.json │ ├── low_extraction_module.json │ ├── low_filter_module.json │ ├── low_high_priority_module.json │ ├── low_low_priority_module.json │ ├── low_retrieval_module.json │ ├── low_speed_module.json │ ├── medium_crafting_module.json │ ├── medium_extraction_module.json │ ├── medium_filter_module.json │ ├── medium_high_priority_module.json │ ├── medium_low_priority_module.json │ ├── medium_retrieval_module.json │ ├── medium_speed_module.json │ ├── mod_filter_modifier.json │ ├── module_clearing.json │ ├── nbt_filter_modifier.json │ ├── pipe.json │ ├── pipe_frame.json │ ├── pressurizer.json │ ├── random_sorting_modifier.json │ ├── redstone_module.json │ ├── round_robin_sorting_modifier.json │ ├── stack_size_module.json │ ├── tag_filter_modifier.json │ └── wrench.json └── pack.mcmeta /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: Ellpeck 2 | patreon: Ellpeck 3 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | jobs: 3 | build: 4 | runs-on: ubuntu-latest 5 | steps: 6 | - name: Clone Repository 7 | uses: actions/checkout@v4 8 | - name: Setup Java 9 | uses: actions/setup-java@v4 10 | with: 11 | java-version: '21' 12 | distribution: 'temurin' 13 | - name: Cache 14 | uses: actions/cache@v4 15 | with: 16 | path: | 17 | ~/.gradle/caches 18 | ~/.gradle/wrapper 19 | key: ${{ hashFiles('**/build.gradle', '**/gradle-wrapper.properties', '**/gradle.properties') }} 20 | - name: Build 21 | run: | 22 | chmod +x ./gradlew 23 | ./gradlew build --no-daemon 24 | - name: Upload 25 | uses: actions/upload-artifact@v4 26 | with: 27 | name: Mod Jar 28 | path: build/libs/**.jar 29 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: ["*"] 4 | jobs: 5 | release: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Clone Repository 9 | uses: actions/checkout@v4 10 | - name: Setup Java 11 | uses: actions/setup-java@v4 12 | with: 13 | java-version: '21' 14 | distribution: 'temurin' 15 | - name: Cache 16 | uses: actions/cache@v4 17 | with: 18 | path: | 19 | ~/.gradle/caches 20 | ~/.gradle/wrapper 21 | key: ${{ hashFiles('**/build.gradle', '**/gradle-wrapper.properties', '**/gradle.properties') }} 22 | - name: Grab Changelog from Commit Message Body 23 | run: | 24 | changelog=$(echo -e "$MESSAGE" | sed -n '/^$/,$p' | sed '1d') 25 | echo -e "$changelog" 26 | { 27 | echo 'CHANGELOG<> "$GITHUB_ENV" 31 | env: 32 | MESSAGE: ${{ github.event.head_commit.message }} 33 | - name: Release 34 | run: | 35 | chmod +x ./gradlew 36 | ./gradlew publishMods --no-daemon 37 | env: 38 | MR_TOKEN: ${{ secrets.MR_TOKEN }} 39 | CF_TOKEN: ${{ secrets.CF_TOKEN }} 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /rebuild.bat 2 | /doAllTheThings.bat 3 | /.gradle 4 | /build 5 | /out 6 | /idea 7 | /.idea 8 | /*.iml 9 | /*.ipr 10 | /*.iws 11 | /lib 12 | /classes 13 | /bin/ 14 | /run/ 15 | /logs 16 | /runs 17 | 18 | *.classpath 19 | *.project 20 | .settings/org.eclipse.buildship.core.prefs 21 | *.launch 22 | .settings/org.eclipse.jdt.core.prefs 23 | *.prefs 24 | .cache 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2021 Ellpeck 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PrettyPipes 2 | wow pipes, how creative 3 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1G 2 | org.gradle.daemon=false 3 | org.gradle.debug=false 4 | 5 | #read more on this at https://github.com/neoforged/NeoGradle/blob/NG_7.0/README.md#apply-parchment-mappings 6 | # you can also find the latest versions at: https://parchmentmc.org/docs/getting-started 7 | neogradle.subsystems.parchment.minecraftVersion=1.21 8 | neogradle.subsystems.parchment.mappingsVersion=2024.07.28 9 | # Environment Properties 10 | # You can find the latest versions here: https://projects.neoforged.net/neoforged/neoforge 11 | # The Minecraft version must agree with the Neo version to get a valid artifact 12 | minecraft_version=1.21.1 13 | minecraft_version_range=[1.21.1,1.22) 14 | # The Neo version must agree with the Minecraft version to get a valid artifact 15 | neo_version=21.1.45 16 | # The Neo version range can use any version of Neo as bounds 17 | neo_version_range=[21.1.0,) 18 | # The loader version range can only use the major version of FML as bounds 19 | loader_version_range=[4,) 20 | 21 | jei_version=19.18.3.204 22 | jgt_version=1.5.2 23 | jheaps_version=0.14 24 | apfloat_version=1.10.1 25 | 26 | 27 | ## Mod Properties 28 | 29 | # The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63} 30 | # Must match the String constant located in the main mod class annotated with @Mod. 31 | mod_id=prettypipes 32 | # The human-readable display name for the mod. 33 | mod_name=PrettyPipes 34 | # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. 35 | mod_license=MIT 36 | # The mod version. See https://semver.org/ 37 | mod_version=1.21.0 38 | # STABLE, BETA, ALPHA 39 | mod_release_state=BETA 40 | # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. 41 | # This should match the base package used for the mod sources. 42 | # See https://maven.apache.org/guides/mini/guide-naming-conventions.html 43 | mod_group_id=de.ellpeck.prettypipes 44 | # The authors of the mod. This is a simple text string that is used for display purposes in the mod list. 45 | mod_authors=Ellpeck 46 | # The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list. 47 | mod_description=wow pipes, how creative 48 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /media/2020-04-18_01.04.55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/media/2020-04-18_01.04.55.png -------------------------------------------------------------------------------- /media/2020-04-18_01.05.17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/media/2020-04-18_01.05.17.png -------------------------------------------------------------------------------- /media/2020-04-18_01.06.11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/media/2020-04-18_01.06.11.png -------------------------------------------------------------------------------- /media/2020-10-17_00.58.03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/media/2020-10-17_00.58.03.png -------------------------------------------------------------------------------- /media/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/media/banner.png -------------------------------------------------------------------------------- /media/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/media/logo.png -------------------------------------------------------------------------------- /media/terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/media/terminal.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | mavenLocal() 4 | gradlePluginPortal() 5 | maven { url = 'https://maven.neoforged.net/releases' } 6 | } 7 | } 8 | 9 | plugins { 10 | id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0' 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/PrettyPipes.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes; 2 | 3 | import net.neoforged.fml.common.Mod; 4 | 5 | @Mod(PrettyPipes.ID) 6 | public final class PrettyPipes { 7 | 8 | public static final String ID = "prettypipes"; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/compat/jei/CraftingModuleTransferHandler.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.compat.jei; 2 | 3 | import de.ellpeck.prettypipes.Registry; 4 | import de.ellpeck.prettypipes.misc.ItemEquality; 5 | import de.ellpeck.prettypipes.packets.PacketCraftingModuleTransfer; 6 | import de.ellpeck.prettypipes.pipe.modules.craft.CraftingModuleContainer; 7 | import mezz.jei.api.constants.VanillaTypes; 8 | import mezz.jei.api.gui.ingredient.IRecipeSlotsView; 9 | import mezz.jei.api.recipe.RecipeIngredientRole; 10 | import mezz.jei.api.recipe.transfer.IRecipeTransferError; 11 | import mezz.jei.api.recipe.transfer.IUniversalRecipeTransferHandler; 12 | import net.minecraft.world.entity.player.Player; 13 | import net.minecraft.world.inventory.MenuType; 14 | import net.minecraft.world.item.ItemStack; 15 | import net.neoforged.neoforge.network.PacketDistributor; 16 | import org.jetbrains.annotations.Nullable; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Optional; 20 | 21 | public class CraftingModuleTransferHandler implements IUniversalRecipeTransferHandler { 22 | 23 | @Override 24 | public Class getContainerClass() { 25 | return CraftingModuleContainer.class; 26 | } 27 | 28 | @Override 29 | public Optional> getMenuType() { 30 | return Optional.of(Registry.craftingModuleContainer); 31 | } 32 | 33 | @Override 34 | public @Nullable IRecipeTransferError transferRecipe(CraftingModuleContainer container, Object recipe, IRecipeSlotsView recipeSlots, Player player, boolean maxTransfer, boolean doTransfer) { 35 | if (!doTransfer) 36 | return null; 37 | var inputs = new ArrayList(); 38 | var outputs = new ArrayList(); 39 | for (var entry : recipeSlots.getSlotViews()) { 40 | var allIngredients = entry.getIngredients(VanillaTypes.ITEM_STACK).toList(); 41 | if (allIngredients.isEmpty()) 42 | continue; 43 | var remain = allIngredients.getFirst().copy(); 44 | var toAdd = entry.getRole() == RecipeIngredientRole.INPUT ? inputs : outputs; 45 | var lastAdded = toAdd.isEmpty() ? ItemStack.EMPTY : toAdd.getLast(); 46 | if (ItemEquality.compareItems(lastAdded, remain)) { 47 | var fits = Math.min(lastAdded.getMaxStackSize() - lastAdded.getCount(), remain.getCount()); 48 | lastAdded.grow(fits); 49 | remain.shrink(fits); 50 | } 51 | if (!remain.isEmpty()) 52 | toAdd.add(remain); 53 | } 54 | PacketDistributor.sendToServer(new PacketCraftingModuleTransfer(inputs, outputs)); 55 | return null; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/compat/jei/CraftingTerminalTransferHandler.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.compat.jei; 2 | 3 | import de.ellpeck.prettypipes.Registry; 4 | import de.ellpeck.prettypipes.packets.PacketGhostSlot; 5 | import de.ellpeck.prettypipes.terminal.containers.CraftingTerminalContainer; 6 | import mezz.jei.api.constants.RecipeTypes; 7 | import mezz.jei.api.constants.VanillaTypes; 8 | import mezz.jei.api.gui.ingredient.IRecipeSlotsView; 9 | import mezz.jei.api.recipe.RecipeIngredientRole; 10 | import mezz.jei.api.recipe.RecipeType; 11 | import mezz.jei.api.recipe.transfer.IRecipeTransferError; 12 | import mezz.jei.api.recipe.transfer.IRecipeTransferHandler; 13 | import net.minecraft.world.entity.player.Player; 14 | import net.minecraft.world.inventory.MenuType; 15 | import net.minecraft.world.item.crafting.CraftingRecipe; 16 | import net.minecraft.world.item.crafting.RecipeHolder; 17 | import net.neoforged.neoforge.network.PacketDistributor; 18 | import org.jetbrains.annotations.Nullable; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.Optional; 23 | import java.util.stream.Collectors; 24 | 25 | public class CraftingTerminalTransferHandler implements IRecipeTransferHandler> { 26 | 27 | @Override 28 | public Class getContainerClass() { 29 | return CraftingTerminalContainer.class; 30 | } 31 | 32 | @Override 33 | public Optional> getMenuType() { 34 | return Optional.of(Registry.craftingTerminalContainer); 35 | } 36 | 37 | @Override 38 | public RecipeType> getRecipeType() { 39 | return RecipeTypes.CRAFTING; 40 | } 41 | 42 | @Override 43 | public @Nullable IRecipeTransferError transferRecipe(CraftingTerminalContainer container, RecipeHolder recipe, IRecipeSlotsView slots, Player player, boolean maxTransfer, boolean doTransfer) { 44 | if (!doTransfer) 45 | return null; 46 | List stacks = new ArrayList<>(); 47 | var ingredients = slots.getSlotViews(RecipeIngredientRole.INPUT); 48 | for (var entry : ingredients) 49 | stacks.add(PacketGhostSlot.Entry.fromStacks(player.level(), entry.getIngredients(VanillaTypes.ITEM_STACK).collect(Collectors.toList()))); 50 | PacketDistributor.sendToServer(new PacketGhostSlot(container.getTile().getBlockPos(), stacks)); 51 | return null; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/entities/PipeFrameRenderer.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.entities; 2 | 3 | import com.mojang.blaze3d.vertex.PoseStack; 4 | import com.mojang.math.Axis; 5 | import net.minecraft.client.gui.Font; 6 | import net.minecraft.client.renderer.MultiBufferSource; 7 | import net.minecraft.client.renderer.entity.EntityRendererProvider; 8 | import net.minecraft.client.renderer.entity.ItemFrameRenderer; 9 | 10 | public class PipeFrameRenderer extends ItemFrameRenderer { 11 | 12 | public PipeFrameRenderer(EntityRendererProvider.Context renderManagerIn) { 13 | super(renderManagerIn); 14 | } 15 | 16 | @Override 17 | public void render(PipeFrameEntity entityIn, float entityYaw, float partialTicks, PoseStack matrixStackIn, MultiBufferSource bufferIn, int packedLightIn) { 18 | super.render(entityIn, entityYaw, partialTicks, matrixStackIn, bufferIn, packedLightIn); 19 | matrixStackIn.pushPose(); 20 | var direction = entityIn.getDirection(); 21 | var vec3d = this.getRenderOffset(entityIn, partialTicks); 22 | matrixStackIn.translate(-vec3d.x, -vec3d.y, -vec3d.z); 23 | matrixStackIn.translate(direction.getStepX() * 0.46875, direction.getStepY() * 0.46875, direction.getStepZ() * 0.46875); 24 | matrixStackIn.mulPose(Axis.XP.rotationDegrees(entityIn.getXRot())); 25 | matrixStackIn.mulPose(Axis.YP.rotationDegrees(180.0F - entityIn.getYRot())); 26 | 27 | var font = this.getFont(); 28 | var amount = entityIn.getAmount(); 29 | var amountStrg = amount < 0 ? "?" : String.valueOf(amount); 30 | var x = 0.5F - font.width(amountStrg) / 2F; 31 | var matrix4f = matrixStackIn.last().pose(); 32 | matrixStackIn.translate(0, 0.285F, 0.415F); 33 | matrixStackIn.scale(-0.02F, -0.02F, 0.02F); 34 | font.drawInBatch(amountStrg, x, 0, 0xFFFFFF, false, matrix4f, bufferIn, Font.DisplayMode.NORMAL, 0, packedLightIn); 35 | 36 | matrixStackIn.popPose(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/items/IModule.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.items; 2 | 3 | import de.ellpeck.prettypipes.misc.DirectionSelector; 4 | import de.ellpeck.prettypipes.misc.ItemFilter; 5 | import de.ellpeck.prettypipes.network.ActiveCraft; 6 | import de.ellpeck.prettypipes.pipe.PipeBlockEntity; 7 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; 8 | import net.minecraft.core.BlockPos; 9 | import net.minecraft.core.Direction; 10 | import net.minecraft.world.entity.player.Inventory; 11 | import net.minecraft.world.entity.player.Player; 12 | import net.minecraft.world.item.ItemStack; 13 | import net.neoforged.neoforge.items.IItemHandler; 14 | import org.apache.commons.lang3.tuple.Pair; 15 | 16 | import java.util.Collection; 17 | import java.util.List; 18 | import java.util.Stack; 19 | import java.util.function.Consumer; 20 | 21 | public interface IModule { 22 | 23 | void tick(ItemStack module, PipeBlockEntity tile); 24 | 25 | boolean canNetworkSee(ItemStack module, PipeBlockEntity tile, Direction direction, IItemHandler handler); 26 | 27 | boolean canAcceptItem(ItemStack module, PipeBlockEntity tile, ItemStack stack, Direction direction, IItemHandler destination); 28 | 29 | int getMaxInsertionAmount(ItemStack module, PipeBlockEntity tile, ItemStack stack, IItemHandler destination); 30 | 31 | int getPriority(ItemStack module, PipeBlockEntity tile); 32 | 33 | boolean isCompatible(ItemStack module, PipeBlockEntity tile, IModule other); 34 | 35 | boolean hasContainer(ItemStack module, PipeBlockEntity tile); 36 | 37 | AbstractPipeContainer getContainer(ItemStack module, PipeBlockEntity tile, int windowId, Inventory inv, Player player, int moduleIndex); 38 | 39 | float getItemSpeedIncrease(ItemStack module, PipeBlockEntity tile); 40 | 41 | boolean canPipeWork(ItemStack module, PipeBlockEntity tile); 42 | 43 | List getAllCraftables(ItemStack module, PipeBlockEntity tile); 44 | 45 | int getCraftableAmount(ItemStack module, PipeBlockEntity tile, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain); 46 | 47 | Pair> craft(ItemStack module, PipeBlockEntity tile, BlockPos destPipe, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain); 48 | 49 | Integer getCustomNextNode(ItemStack module, PipeBlockEntity tile, List nodes, int index); 50 | 51 | ItemFilter getItemFilter(ItemStack module, PipeBlockEntity tile); 52 | 53 | DirectionSelector getDirectionSelector(ItemStack module, PipeBlockEntity tile); 54 | 55 | ItemStack store(ItemStack module, PipeBlockEntity tile, ItemStack stack, Direction direction); 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/items/ModuleItem.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.items; 2 | 3 | import de.ellpeck.prettypipes.Utility; 4 | import de.ellpeck.prettypipes.misc.DirectionSelector; 5 | import de.ellpeck.prettypipes.misc.ItemFilter; 6 | import de.ellpeck.prettypipes.network.ActiveCraft; 7 | import de.ellpeck.prettypipes.pipe.PipeBlockEntity; 8 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; 9 | import net.minecraft.core.BlockPos; 10 | import net.minecraft.core.Direction; 11 | import net.minecraft.network.chat.Component; 12 | import net.minecraft.world.entity.player.Inventory; 13 | import net.minecraft.world.entity.player.Player; 14 | import net.minecraft.world.item.Item; 15 | import net.minecraft.world.item.ItemStack; 16 | import net.minecraft.world.item.TooltipFlag; 17 | import net.neoforged.api.distmarker.Dist; 18 | import net.neoforged.api.distmarker.OnlyIn; 19 | import net.neoforged.neoforge.items.IItemHandler; 20 | import org.apache.commons.lang3.tuple.Pair; 21 | 22 | import java.util.Collection; 23 | import java.util.Collections; 24 | import java.util.List; 25 | import java.util.Stack; 26 | import java.util.function.Consumer; 27 | 28 | public abstract class ModuleItem extends Item implements IModule { 29 | 30 | private final String name; 31 | 32 | public ModuleItem(String name, Item.Properties properties) { 33 | super(properties.stacksTo(16)); 34 | this.name = name; 35 | } 36 | 37 | @Override 38 | @OnlyIn(Dist.CLIENT) 39 | public void appendHoverText(ItemStack pStack, TooltipContext pContext, List pTooltipComponents, TooltipFlag pTooltipFlag) { 40 | super.appendHoverText(pStack, pContext, pTooltipComponents, pTooltipFlag); 41 | Utility.addTooltip(this.name, pTooltipComponents); 42 | } 43 | 44 | @Override 45 | public void tick(ItemStack module, PipeBlockEntity tile) { 46 | 47 | } 48 | 49 | @Override 50 | public boolean canNetworkSee(ItemStack module, PipeBlockEntity tile, Direction direction, IItemHandler handler) { 51 | return true; 52 | } 53 | 54 | @Override 55 | public boolean canAcceptItem(ItemStack module, PipeBlockEntity tile, ItemStack stack, Direction direction, IItemHandler destination) { 56 | return true; 57 | } 58 | 59 | @Override 60 | public int getMaxInsertionAmount(ItemStack module, PipeBlockEntity tile, ItemStack stack, IItemHandler destination) { 61 | return Integer.MAX_VALUE; 62 | } 63 | 64 | @Override 65 | public int getPriority(ItemStack module, PipeBlockEntity tile) { 66 | return 0; 67 | } 68 | 69 | @Override 70 | public AbstractPipeContainer getContainer(ItemStack module, PipeBlockEntity tile, int windowId, Inventory inv, Player player, int moduleIndex) { 71 | return null; 72 | } 73 | 74 | @Override 75 | public float getItemSpeedIncrease(ItemStack module, PipeBlockEntity tile) { 76 | return 0; 77 | } 78 | 79 | @Override 80 | public boolean canPipeWork(ItemStack module, PipeBlockEntity tile) { 81 | return true; 82 | } 83 | 84 | @Override 85 | public List getAllCraftables(ItemStack module, PipeBlockEntity tile) { 86 | return Collections.emptyList(); 87 | } 88 | 89 | @Override 90 | public int getCraftableAmount(ItemStack module, PipeBlockEntity tile, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain) { 91 | return 0; 92 | } 93 | 94 | @Override 95 | public Pair> craft(ItemStack module, PipeBlockEntity tile, BlockPos destPipe, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain) { 96 | return Pair.of(stack, List.of()); 97 | } 98 | 99 | @Override 100 | public Integer getCustomNextNode(ItemStack module, PipeBlockEntity tile, List nodes, int index) { 101 | return null; 102 | } 103 | 104 | @Override 105 | public ItemFilter getItemFilter(ItemStack module, PipeBlockEntity tile) { 106 | return null; 107 | } 108 | 109 | @Override 110 | public DirectionSelector getDirectionSelector(ItemStack module, PipeBlockEntity tile) { 111 | return null; 112 | } 113 | 114 | @Override 115 | public ItemStack store(ItemStack module, PipeBlockEntity tile, ItemStack stack, Direction direction) { 116 | return stack; 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/items/ModuleTier.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.items; 2 | 3 | public enum ModuleTier { 4 | 5 | LOW, 6 | MEDIUM, 7 | HIGH; 8 | 9 | public final T forTier(T low, T medium, T high) { 10 | return switch (this) { 11 | case LOW -> low; 12 | case MEDIUM -> medium; 13 | case HIGH -> high; 14 | }; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/items/PipeFrameItem.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.items; 2 | 3 | import de.ellpeck.prettypipes.Registry; 4 | import de.ellpeck.prettypipes.Utility; 5 | import de.ellpeck.prettypipes.entities.PipeFrameEntity; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.core.Direction; 8 | import net.minecraft.core.component.DataComponents; 9 | import net.minecraft.core.registries.BuiltInRegistries; 10 | import net.minecraft.network.chat.Component; 11 | import net.minecraft.world.InteractionResult; 12 | import net.minecraft.world.entity.EntityType; 13 | import net.minecraft.world.entity.decoration.HangingEntity; 14 | import net.minecraft.world.entity.player.Player; 15 | import net.minecraft.world.item.Item; 16 | import net.minecraft.world.item.ItemStack; 17 | import net.minecraft.world.item.TooltipFlag; 18 | import net.minecraft.world.item.component.CustomData; 19 | import net.minecraft.world.item.context.UseOnContext; 20 | 21 | import java.util.List; 22 | 23 | public class PipeFrameItem extends Item { 24 | 25 | public PipeFrameItem() { 26 | super(new Properties()); 27 | } 28 | 29 | // HangingEntityItem copypasta mostly, since it hardcodes the entities bleh 30 | @Override 31 | public InteractionResult useOn(UseOnContext context) { 32 | var blockpos = context.getClickedPos(); 33 | var direction = context.getClickedFace(); 34 | var blockpos1 = blockpos.relative(direction); 35 | var playerentity = context.getPlayer(); 36 | var itemstack = context.getItemInHand(); 37 | if (playerentity != null && !this.canPlace(playerentity, direction, itemstack, blockpos1)) { 38 | return InteractionResult.FAIL; 39 | } else { 40 | var world = context.getLevel(); 41 | HangingEntity hangingentity = new PipeFrameEntity(Registry.pipeFrameEntity, world, blockpos1, direction); 42 | 43 | var customdata = itemstack.getOrDefault(DataComponents.ENTITY_DATA, CustomData.EMPTY); 44 | if (!customdata.isEmpty()) 45 | EntityType.updateCustomEntityTag(world, playerentity, hangingentity, customdata); 46 | 47 | if (hangingentity.survives()) { 48 | if (!world.isClientSide) { 49 | hangingentity.playPlacementSound(); 50 | world.addFreshEntity(hangingentity); 51 | } 52 | 53 | itemstack.shrink(1); 54 | return InteractionResult.SUCCESS; 55 | } else { 56 | return InteractionResult.CONSUME; 57 | } 58 | } 59 | } 60 | 61 | protected boolean canPlace(Player playerIn, Direction directionIn, ItemStack itemStackIn, BlockPos posIn) { 62 | return !directionIn.getAxis().isVertical() && playerIn.mayUseItemAt(posIn, directionIn, itemStackIn) && PipeFrameEntity.canPlace(playerIn.level(), posIn, directionIn); 63 | } 64 | 65 | @Override 66 | public void appendHoverText(ItemStack pStack, TooltipContext pContext, List pTooltipComponents, TooltipFlag pTooltipFlag) { 67 | super.appendHoverText(pStack, pContext, pTooltipComponents, pTooltipFlag); 68 | Utility.addTooltip(BuiltInRegistries.ITEM.getKey(this).getPath(), pTooltipComponents); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/misc/EquatableItemStack.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.misc; 2 | 3 | import net.minecraft.world.item.ItemStack; 4 | 5 | import java.util.Arrays; 6 | import java.util.Objects; 7 | 8 | public record EquatableItemStack(ItemStack stack, ItemEquality... equalityTypes) { 9 | 10 | public boolean equals(Object o) { 11 | if (o instanceof EquatableItemStack other) 12 | return Arrays.equals(this.equalityTypes, other.equalityTypes) && ItemEquality.compareItems(this.stack, other.stack, this.equalityTypes); 13 | return false; 14 | } 15 | 16 | @Override 17 | public int hashCode() { 18 | return Objects.hash(this.stack.getItem(), this.stack.getComponents()); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/misc/Events.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.misc; 2 | 3 | import de.ellpeck.prettypipes.PrettyPipes; 4 | import de.ellpeck.prettypipes.network.PipeNetwork; 5 | import net.minecraft.commands.Commands; 6 | import net.minecraft.network.chat.Component; 7 | import net.neoforged.bus.api.SubscribeEvent; 8 | import net.neoforged.fml.common.EventBusSubscriber; 9 | import net.neoforged.neoforge.event.server.ServerStartingEvent; 10 | 11 | import java.io.IOException; 12 | import java.nio.charset.StandardCharsets; 13 | import java.nio.file.Files; 14 | import java.nio.file.Paths; 15 | 16 | @EventBusSubscriber 17 | public final class Events { 18 | 19 | @SubscribeEvent 20 | public static void onServerStarting(ServerStartingEvent event) { 21 | event.getServer().getCommands().getDispatcher().register(Commands.literal(PrettyPipes.ID).requires(s -> s.hasPermission(2)) 22 | .then(Commands.literal("dump").executes(c -> { 23 | var source = c.getSource(); 24 | var file = Paths.get('_' + PrettyPipes.ID + "dump.txt"); 25 | var dump = PipeNetwork.get(source.getLevel()).toString(); 26 | try { 27 | Files.writeString(file, dump, StandardCharsets.UTF_8); 28 | source.sendSuccess(() -> Component.literal("Wrote network dump to file " + file.toAbsolutePath()), true); 29 | } catch (IOException e) { 30 | source.sendFailure(Component.literal("Failed to write network dump to file " + file.toAbsolutePath())); 31 | return -1; 32 | } 33 | return 0; 34 | })) 35 | .then(Commands.literal("uncache").executes(c -> { 36 | var source = c.getSource(); 37 | PipeNetwork.get(source.getLevel()).clearCaches(); 38 | source.sendSuccess(() -> Component.literal("Cleared all pipe caches in the world"), true); 39 | return 0; 40 | })) 41 | .then(Commands.literal("unlock").executes(c -> { 42 | var source = c.getSource(); 43 | PipeNetwork.get(source.getLevel()).unlock(); 44 | source.sendSuccess(() -> Component.literal("Resolved all network locks in the world"), true); 45 | return 0; 46 | })) 47 | .then(Commands.literal("uncraft").executes(c -> { 48 | var source = c.getSource(); 49 | PipeNetwork.get(source.getLevel()).cancelCrafts(); 50 | source.sendSuccess(() -> Component.literal("Canceled all active crafts in the world"), true); 51 | return 0; 52 | }))); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/misc/FilterSlot.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.misc; 2 | 3 | import net.minecraft.world.entity.player.Player; 4 | import net.minecraft.world.inventory.AbstractContainerMenu; 5 | import net.minecraft.world.item.ItemStack; 6 | import net.neoforged.neoforge.items.IItemHandler; 7 | import net.neoforged.neoforge.items.SlotItemHandler; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | public class FilterSlot extends SlotItemHandler { 11 | 12 | private final boolean onlyOneItem; 13 | 14 | public FilterSlot(IItemHandler itemHandler, int index, int xPosition, int yPosition, boolean onlyOneItem) { 15 | super(itemHandler, index, xPosition, yPosition); 16 | this.onlyOneItem = onlyOneItem; 17 | } 18 | 19 | public static boolean checkFilter(AbstractContainerMenu menu, int slotId) { 20 | if (slotId >= 0 && slotId < menu.slots.size()) { 21 | var slot = menu.getSlot(slotId); 22 | if (slot instanceof FilterSlot) { 23 | ((FilterSlot) slot).slotClick(menu); 24 | return true; 25 | } 26 | } 27 | return false; 28 | } 29 | 30 | private void slotClick(AbstractContainerMenu menu) { 31 | var heldStack = menu.getCarried(); 32 | var stackInSlot = this.getItem(); 33 | 34 | if (!stackInSlot.isEmpty() && heldStack.isEmpty()) { 35 | this.set(ItemStack.EMPTY); 36 | } else if (!heldStack.isEmpty()) { 37 | var s = heldStack.copy(); 38 | if (this.onlyOneItem) 39 | s.setCount(1); 40 | this.set(s); 41 | } 42 | } 43 | 44 | @Override 45 | public boolean mayPlace(@NotNull ItemStack stack) { 46 | return false; 47 | } 48 | 49 | @Override 50 | public boolean mayPickup(Player playerIn) { 51 | return false; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/misc/ItemEquality.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.misc; 2 | 3 | import net.minecraft.resources.ResourceLocation; 4 | import net.minecraft.world.item.ItemStack; 5 | 6 | import java.util.Objects; 7 | import java.util.function.BiFunction; 8 | import java.util.function.Supplier; 9 | 10 | public class ItemEquality { 11 | 12 | public static final ItemEquality DAMAGE = new ItemEquality((stack, filter) -> stack.getDamageValue() == filter.getDamageValue(), false, Type.DAMAGE); 13 | public static final ItemEquality NBT = new ItemEquality((stack, filter) -> Objects.equals(stack.getComponents(), filter.getComponents()), false, Type.NBT); 14 | public static final ItemEquality MOD = new ItemEquality((stack, filter) -> stack.getItem().getCreatorModId(stack).equals(filter.getItem().getCreatorModId(filter)), true, Type.MOD); 15 | 16 | public final Type type; 17 | private final BiFunction filter; 18 | private final boolean ignoreItemEquality; 19 | 20 | ItemEquality(BiFunction filter, boolean ignoreItemEquality, Type type) { 21 | this.filter = filter; 22 | this.ignoreItemEquality = ignoreItemEquality; 23 | this.type = type; 24 | } 25 | 26 | public static ItemEquality tag(ResourceLocation tag) { 27 | return new ItemEquality((stack, filter) -> stack.getTags().anyMatch(t -> Objects.equals(tag, t.location())), true, Type.TAG); 28 | } 29 | 30 | public static boolean compareItems(ItemStack stack, ItemStack filter, ItemEquality... types) { 31 | var equal = ItemStack.isSameItem(stack, filter); 32 | if (types.length <= 0) 33 | return equal; 34 | for (var type : types) { 35 | if (!type.ignoreItemEquality && !equal) 36 | return false; 37 | if (!type.filter.apply(stack, filter)) 38 | return false; 39 | } 40 | return true; 41 | } 42 | 43 | public enum Type { 44 | DAMAGE(() -> ItemEquality.DAMAGE), 45 | NBT(() -> ItemEquality.NBT), 46 | MOD(() -> ItemEquality.MOD), 47 | TAG(null); 48 | 49 | private final Supplier defaultInstance; 50 | 51 | Type(Supplier defaultInstance) { 52 | this.defaultInstance = defaultInstance; 53 | } 54 | 55 | public ItemEquality getDefaultInstance() { 56 | return this.defaultInstance.get(); 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/misc/ItemOrder.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.misc; 2 | 3 | import net.minecraft.world.item.ItemStack; 4 | 5 | import java.util.Comparator; 6 | 7 | public enum ItemOrder { 8 | AMOUNT(Comparator.comparingInt(ItemStack::getCount)), 9 | NAME(Comparator.comparing(s -> s.getHoverName().getString())), 10 | MOD(Comparator.comparing(s -> s.getItem().getCreatorModId(s))); 11 | 12 | public final Comparator comparator; 13 | 14 | ItemOrder(Comparator comparator) { 15 | this.comparator = comparator; 16 | } 17 | 18 | public ItemOrder next() { 19 | return ItemOrder.values()[(this.ordinal() + 1) % ItemOrder.values().length]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/misc/ItemTerminalWidget.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.misc; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import de.ellpeck.prettypipes.terminal.containers.ItemTerminalGui; 5 | import net.minecraft.ChatFormatting; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import net.minecraft.client.gui.components.AbstractWidget; 8 | import net.minecraft.client.gui.narration.NarrationElementOutput; 9 | import net.minecraft.client.gui.screens.Screen; 10 | import net.minecraft.network.chat.Component; 11 | import net.minecraft.network.chat.MutableComponent; 12 | import net.minecraft.world.item.ItemStack; 13 | 14 | import java.util.Optional; 15 | 16 | public class ItemTerminalWidget extends AbstractWidget { 17 | 18 | private final ItemTerminalGui screen; 19 | public final int gridX; 20 | public final int gridY; 21 | public boolean selected; 22 | public ItemStack stack = ItemStack.EMPTY; 23 | public boolean craftable; 24 | 25 | public ItemTerminalWidget(int xIn, int yIn, int gridX, int gridY, ItemTerminalGui screen) { 26 | super(xIn, yIn, 16, 16, Component.literal("")); 27 | this.gridX = gridX; 28 | this.gridY = gridY; 29 | this.screen = screen; 30 | this.visible = false; 31 | } 32 | 33 | @Override 34 | public void onClick(double x, double y) { 35 | this.screen.streamWidgets().forEach(w -> w.selected = false); 36 | this.selected = true; 37 | } 38 | 39 | @Override 40 | protected void renderWidget(GuiGraphics graphics, int p_268034_, int p_268009_, float p_268085_) { 41 | var mc = this.screen.getMinecraft(); 42 | graphics.pose().translate(0, 0, 100); 43 | if (this.selected) 44 | graphics.fill(this.getX(), this.getY(), this.getX() + 16, this.getY() + 16, -2130706433); 45 | RenderSystem.enableDepthTest(); 46 | graphics.renderItem(this.stack, this.getX(), this.getY()); 47 | var amount = !this.craftable ? this.stack.getCount() : 0; 48 | var amountStrg = this.stack.getCount() >= 1000 ? amount / 1000 + "k" : String.valueOf(amount); 49 | graphics.renderItemDecorations(mc.font, this.stack, this.getX(), this.getY(), amountStrg); 50 | graphics.pose().translate(0, 0, -100); 51 | 52 | if (this.isHoveredOrFocused()) { 53 | RenderSystem.disableDepthTest(); 54 | RenderSystem.colorMask(true, true, true, false); 55 | graphics.fillGradient(this.getX(), this.getY(), this.getX() + 16, this.getY() + 16, -2130706433, -2130706433); 56 | RenderSystem.colorMask(true, true, true, true); 57 | RenderSystem.enableDepthTest(); 58 | } 59 | } 60 | 61 | public void renderToolTip(GuiGraphics graphics, int mouseX, int mouseY) { 62 | if (this.visible && this.isHovered()) { 63 | var tooltip = Screen.getTooltipFromItem(this.screen.getMinecraft(), this.stack); 64 | if (this.stack.getCount() >= 1000) { 65 | var comp = tooltip.get(0); 66 | if (comp instanceof MutableComponent m) 67 | tooltip.set(0, m.append(Component.literal(" (" + this.stack.getCount() + ')').withStyle(ChatFormatting.BOLD))); 68 | } 69 | graphics.renderTooltip(this.screen.getMinecraft().font, tooltip, Optional.empty(), mouseX, mouseY); 70 | } 71 | } 72 | 73 | @Override 74 | public void updateWidgetNarration(NarrationElementOutput output) { 75 | this.defaultButtonNarrationText(output); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/misc/ModuleClearingRecipe.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.misc; 2 | 3 | import de.ellpeck.prettypipes.items.IModule; 4 | import net.minecraft.core.HolderLookup; 5 | import net.minecraft.world.item.ItemStack; 6 | import net.minecraft.world.item.crafting.*; 7 | import net.minecraft.world.level.Level; 8 | 9 | public class ModuleClearingRecipe extends CustomRecipe { 10 | 11 | public static final RecipeSerializer SERIALIZER = new SimpleCraftingRecipeSerializer<>(ModuleClearingRecipe::new); 12 | 13 | public ModuleClearingRecipe(CraftingBookCategory cat) { 14 | super(cat); 15 | } 16 | 17 | @Override 18 | public boolean matches(CraftingInput container, Level level) { 19 | var foundModule = false; 20 | for (var i = 0; i < container.size(); i++) { 21 | var stack = container.getItem(i); 22 | if (!foundModule && stack.getItem() instanceof IModule) { 23 | foundModule = true; 24 | } else if (!stack.isEmpty()) { 25 | return false; 26 | } 27 | } 28 | return foundModule; 29 | } 30 | 31 | @Override 32 | public ItemStack assemble(CraftingInput container, HolderLookup.Provider pRegistries) { 33 | for (var i = 0; i < container.size(); i++) { 34 | var stack = container.getItem(i); 35 | if (stack.getItem() instanceof IModule) 36 | return new ItemStack(stack.getItem()); 37 | } 38 | return ItemStack.EMPTY; 39 | } 40 | 41 | @Override 42 | public boolean canCraftInDimensions(int x, int y) { 43 | return x >= 1 && y >= 1; 44 | } 45 | 46 | @Override 47 | public RecipeSerializer getSerializer() { 48 | return ModuleClearingRecipe.SERIALIZER; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/misc/PlayerPrefs.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.misc; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import de.ellpeck.prettypipes.PrettyPipes; 6 | import net.minecraft.client.Minecraft; 7 | 8 | import java.io.File; 9 | import java.io.FileReader; 10 | import java.io.FileWriter; 11 | import java.io.IOException; 12 | 13 | public class PlayerPrefs { 14 | 15 | private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); 16 | private static PlayerPrefs instance; 17 | 18 | public ItemOrder terminalItemOrder = ItemOrder.AMOUNT; 19 | public boolean terminalAscending; 20 | public boolean syncJei = true; 21 | 22 | public void save() { 23 | var file = PlayerPrefs.getFile(); 24 | if (file.exists()) 25 | file.delete(); 26 | try (var writer = new FileWriter(file)) { 27 | PlayerPrefs.GSON.toJson(this, writer); 28 | } catch (IOException e) { 29 | e.printStackTrace(); 30 | } 31 | } 32 | 33 | public static PlayerPrefs get() { 34 | if (PlayerPrefs.instance == null) { 35 | var file = PlayerPrefs.getFile(); 36 | if (file.exists()) { 37 | try (var reader = new FileReader(file)) { 38 | PlayerPrefs.instance = PlayerPrefs.GSON.fromJson(reader, PlayerPrefs.class); 39 | return PlayerPrefs.instance; 40 | } catch (IOException e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | PlayerPrefs.instance = new PlayerPrefs(); 45 | } 46 | return PlayerPrefs.instance; 47 | } 48 | 49 | private static File getFile() { 50 | var location = Minecraft.getInstance().gameDirectory; 51 | return new File(location, PrettyPipes.ID + "prefs"); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/network/NetworkEdge.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.network; 2 | 3 | import de.ellpeck.prettypipes.Utility; 4 | import net.minecraft.core.BlockPos; 5 | import net.minecraft.core.HolderLookup; 6 | import net.minecraft.nbt.CompoundTag; 7 | import net.minecraft.nbt.ListTag; 8 | import net.minecraft.nbt.NbtUtils; 9 | import net.minecraft.nbt.Tag; 10 | import net.neoforged.neoforge.common.util.INBTSerializable; 11 | import org.jgrapht.graph.DefaultWeightedEdge; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | public class NetworkEdge extends DefaultWeightedEdge implements INBTSerializable { 17 | 18 | public final List pipes = new ArrayList<>(); 19 | 20 | public NetworkEdge() { 21 | } 22 | 23 | public NetworkEdge(HolderLookup.Provider provider, CompoundTag nbt) { 24 | this.deserializeNBT(provider, nbt); 25 | } 26 | 27 | public BlockPos getStartPipe() { 28 | return this.pipes.getFirst(); 29 | } 30 | 31 | public BlockPos getEndPipe() { 32 | return this.pipes.getLast(); 33 | } 34 | 35 | @Override 36 | public CompoundTag serializeNBT(HolderLookup.Provider provider) { 37 | var nbt = new CompoundTag(); 38 | var list = new ListTag(); 39 | for (var pos : this.pipes) 40 | list.add(NbtUtils.writeBlockPos(pos)); 41 | nbt.put("pipes", list); 42 | return nbt; 43 | } 44 | 45 | @Override 46 | public void deserializeNBT(HolderLookup.Provider provider, CompoundTag nbt) { 47 | this.pipes.clear(); 48 | for (var tag : nbt.getList("pipes", Tag.TAG_INT_ARRAY)) 49 | this.pipes.add(Utility.readBlockPos(tag)); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/network/NetworkItem.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.network; 2 | 3 | import de.ellpeck.prettypipes.misc.EquatableItemStack; 4 | import net.minecraft.world.item.ItemStack; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Collection; 8 | import java.util.List; 9 | 10 | public class NetworkItem { 11 | 12 | private final List locations = new ArrayList<>(); 13 | private final EquatableItemStack item; 14 | private int amount; 15 | 16 | public NetworkItem(EquatableItemStack item) { 17 | this.item = item; 18 | } 19 | 20 | public void add(NetworkLocation location, ItemStack stack) { 21 | this.amount += stack.getCount(); 22 | if (!this.locations.contains(location)) 23 | this.locations.add(location); 24 | } 25 | 26 | public Collection getLocations() { 27 | return this.locations; 28 | } 29 | 30 | public ItemStack asStack() { 31 | var stack = this.item.stack().copy(); 32 | stack.setCount(this.amount); 33 | return stack; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/network/NetworkLocation.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.network; 2 | 3 | import de.ellpeck.prettypipes.misc.ItemEquality; 4 | import net.minecraft.core.BlockPos; 5 | import net.minecraft.core.Direction; 6 | import net.minecraft.core.HolderLookup; 7 | import net.minecraft.nbt.CompoundTag; 8 | import net.minecraft.nbt.NbtUtils; 9 | import net.minecraft.world.item.ItemStack; 10 | import net.minecraft.world.level.Level; 11 | import net.neoforged.neoforge.common.util.INBTSerializable; 12 | import net.neoforged.neoforge.items.IItemHandler; 13 | 14 | import java.util.Collections; 15 | import java.util.HashMap; 16 | import java.util.List; 17 | import java.util.Map; 18 | import java.util.stream.Collectors; 19 | 20 | public class NetworkLocation implements INBTSerializable { 21 | 22 | public BlockPos pipePos; 23 | public Direction direction; 24 | private Map itemCache; 25 | private IItemHandler handlerCache; 26 | 27 | public NetworkLocation(BlockPos pipePos, Direction direction) { 28 | this.pipePos = pipePos; 29 | this.direction = direction; 30 | } 31 | 32 | public NetworkLocation(HolderLookup.Provider provider, CompoundTag nbt) { 33 | this.deserializeNBT(provider, nbt); 34 | } 35 | 36 | public List getStackSlots(Level world, ItemStack stack, ItemEquality... equalityTypes) { 37 | if (this.isEmpty(world)) 38 | return Collections.emptyList(); 39 | return this.getItems(world).entrySet().stream() 40 | .filter(kv -> ItemEquality.compareItems(kv.getValue(), stack, equalityTypes) && this.canExtract(world, kv.getKey())) 41 | .map(Map.Entry::getKey).collect(Collectors.toList()); 42 | } 43 | 44 | public int getItemAmount(Level world, ItemStack stack, ItemEquality... equalityTypes) { 45 | if (this.isEmpty(world)) 46 | return 0; 47 | return this.getItems(world).entrySet().stream() 48 | .filter(kv -> ItemEquality.compareItems(stack, kv.getValue(), equalityTypes) && this.canExtract(world, kv.getKey())) 49 | .mapToInt(kv -> kv.getValue().getCount()).sum(); 50 | } 51 | 52 | public Map getItems(Level world) { 53 | if (this.itemCache == null) { 54 | var handler = this.getItemHandler(world); 55 | if (handler != null) { 56 | for (var i = 0; i < handler.getSlots(); i++) { 57 | var stack = handler.getStackInSlot(i); 58 | // check if the slot is accessible to us 59 | if (stack.isEmpty()) 60 | continue; 61 | if (this.itemCache == null) 62 | this.itemCache = new HashMap<>(); 63 | // use getStackInSlot since there might be more than 64 items in there 64 | this.itemCache.put(i, stack); 65 | } 66 | } 67 | } 68 | return this.itemCache; 69 | } 70 | 71 | public boolean canExtract(Level world, int slot) { 72 | var handler = this.getItemHandler(world); 73 | return handler != null && !handler.extractItem(slot, 1, true).isEmpty(); 74 | } 75 | 76 | public IItemHandler getItemHandler(Level world) { 77 | if (this.handlerCache == null) { 78 | var network = PipeNetwork.get(world); 79 | var pipe = network.getPipe(this.pipePos); 80 | this.handlerCache = pipe.getItemHandler(this.direction); 81 | } 82 | return this.handlerCache; 83 | } 84 | 85 | public boolean isEmpty(Level world) { 86 | var items = this.getItems(world); 87 | return items == null || items.isEmpty(); 88 | } 89 | 90 | public BlockPos getPos() { 91 | return this.pipePos.relative(this.direction); 92 | } 93 | 94 | @Override 95 | public CompoundTag serializeNBT(HolderLookup.Provider provider) { 96 | var nbt = new CompoundTag(); 97 | nbt.put("pipe_pos", NbtUtils.writeBlockPos(this.pipePos)); 98 | nbt.putInt("direction", this.direction.ordinal()); 99 | return nbt; 100 | } 101 | 102 | @Override 103 | public void deserializeNBT(HolderLookup.Provider provider, CompoundTag nbt) { 104 | this.pipePos = NbtUtils.readBlockPos(nbt, "pipe_pos").orElse(null); 105 | this.direction = Direction.values()[nbt.getInt("direction")]; 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/network/NetworkLock.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.network; 2 | 3 | import net.minecraft.core.HolderLookup; 4 | import net.minecraft.nbt.CompoundTag; 5 | import net.minecraft.world.item.ItemStack; 6 | import net.neoforged.neoforge.common.util.INBTSerializable; 7 | 8 | import java.util.Objects; 9 | import java.util.UUID; 10 | 11 | public class NetworkLock implements INBTSerializable { 12 | 13 | // identify locks by UUID since network locks can't be identified by location and locked item alone 14 | // (two locks could be set for the same item and the same amount if it exists twice in the chest) 15 | private UUID lockId = UUID.randomUUID(); 16 | public NetworkLocation location; 17 | public ItemStack stack; 18 | 19 | public NetworkLock(NetworkLocation location, ItemStack stack) { 20 | this.location = location; 21 | this.stack = stack; 22 | } 23 | 24 | public NetworkLock(HolderLookup.Provider provider, CompoundTag nbt) { 25 | this.deserializeNBT(provider, nbt); 26 | } 27 | 28 | @Override 29 | public CompoundTag serializeNBT(HolderLookup.Provider provider) { 30 | var nbt = new CompoundTag(); 31 | nbt.putUUID("id", this.lockId); 32 | nbt.put("location", this.location.serializeNBT(provider)); 33 | nbt.put("stack", this.stack.save(provider)); 34 | return nbt; 35 | } 36 | 37 | @Override 38 | public void deserializeNBT(HolderLookup.Provider provider, CompoundTag nbt) { 39 | this.lockId = nbt.getUUID("id"); 40 | this.location = new NetworkLocation(provider, nbt.getCompound("location")); 41 | this.stack = ItemStack.parseOptional(provider, nbt.getCompound("stack")); 42 | } 43 | 44 | @Override 45 | public boolean equals(Object o) { 46 | if (o instanceof NetworkLock that) 47 | return this.lockId.equals(that.lockId); 48 | return false; 49 | } 50 | 51 | @Override 52 | public int hashCode() { 53 | return Objects.hash(this.lockId); 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return "NetworkLock{" + "location=" + this.location.pipePos + ", stack=" + this.stack + '}'; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/packets/PacketCraftingModuleTransfer.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.packets; 2 | 3 | import de.ellpeck.prettypipes.PrettyPipes; 4 | import de.ellpeck.prettypipes.pipe.modules.craft.CraftingModuleContainer; 5 | import net.minecraft.network.RegistryFriendlyByteBuf; 6 | import net.minecraft.network.codec.ByteBufCodecs; 7 | import net.minecraft.network.codec.StreamCodec; 8 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 9 | import net.minecraft.resources.ResourceLocation; 10 | import net.minecraft.world.item.ItemStack; 11 | import net.neoforged.neoforge.items.ItemHandlerHelper; 12 | import net.neoforged.neoforge.items.ItemStackHandler; 13 | import net.neoforged.neoforge.network.handling.IPayloadContext; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | public record PacketCraftingModuleTransfer(List inputs, List outputs) implements CustomPacketPayload { 19 | 20 | public static final Type TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(PrettyPipes.ID, "crafting_module_transfer")); 21 | public static final StreamCodec CODEC = StreamCodec.composite( 22 | ItemStack.LIST_STREAM_CODEC, PacketCraftingModuleTransfer::inputs, 23 | ItemStack.LIST_STREAM_CODEC, PacketCraftingModuleTransfer::outputs, 24 | PacketCraftingModuleTransfer::new); 25 | 26 | @Override 27 | public Type type() { 28 | return PacketCraftingModuleTransfer.TYPE; 29 | } 30 | 31 | public static void onMessage(PacketCraftingModuleTransfer message, IPayloadContext ctx) { 32 | var player = ctx.player(); 33 | if (player.containerMenu instanceof CraftingModuleContainer container) { 34 | PacketCraftingModuleTransfer.copy(container.input, message.inputs); 35 | PacketCraftingModuleTransfer.copy(container.output, message.outputs); 36 | container.modified = true; 37 | container.broadcastChanges(); 38 | } 39 | } 40 | 41 | private static void copy(ItemStackHandler container, List contents) { 42 | for (var i = 0; i < container.getSlots(); i++) 43 | container.setStackInSlot(i, i < contents.size() ? contents.get(i) : ItemStack.EMPTY); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/packets/PacketGhostSlot.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.packets; 2 | 3 | import com.google.common.collect.Streams; 4 | import com.mojang.datafixers.util.Pair; 5 | import de.ellpeck.prettypipes.PrettyPipes; 6 | import de.ellpeck.prettypipes.Utility; 7 | import de.ellpeck.prettypipes.terminal.CraftingTerminalBlockEntity; 8 | import net.minecraft.core.BlockPos; 9 | import net.minecraft.core.registries.Registries; 10 | import net.minecraft.network.RegistryFriendlyByteBuf; 11 | import net.minecraft.network.codec.ByteBufCodecs; 12 | import net.minecraft.network.codec.StreamCodec; 13 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 14 | import net.minecraft.resources.ResourceLocation; 15 | import net.minecraft.tags.TagKey; 16 | import net.minecraft.world.item.Item; 17 | import net.minecraft.world.item.ItemStack; 18 | import net.minecraft.world.item.Items; 19 | import net.minecraft.world.level.Level; 20 | import net.neoforged.neoforge.network.handling.IPayloadContext; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | import java.util.Optional; 25 | import java.util.stream.Collectors; 26 | 27 | public record PacketGhostSlot(BlockPos pos, List stacks) implements CustomPacketPayload { 28 | 29 | public static final Type TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(PrettyPipes.ID, "ghost_slot")); 30 | public static final StreamCodec CODEC = StreamCodec.composite( 31 | BlockPos.STREAM_CODEC, PacketGhostSlot::pos, 32 | ByteBufCodecs.collection(ArrayList::new, Entry.CODEC), PacketGhostSlot::stacks, 33 | PacketGhostSlot::new); 34 | 35 | @Override 36 | public Type type() { 37 | return PacketGhostSlot.TYPE; 38 | } 39 | 40 | public static void onMessage(PacketGhostSlot message, IPayloadContext ctx) { 41 | var player = ctx.player(); 42 | var tile = Utility.getBlockEntity(CraftingTerminalBlockEntity.class, player.level(), message.pos); 43 | if (tile != null) 44 | tile.setGhostItems(message.stacks); 45 | } 46 | 47 | // TODO the crafting module should probably also use a system like this to allow recipes that have multiple options & to also pick the items we have most of (like the terminal does in setGhostItems) 48 | public record Entry(Optional> stacks, Optional> tag) { 49 | 50 | public static final StreamCodec CODEC = StreamCodec.composite( 51 | ByteBufCodecs.optional(ItemStack.OPTIONAL_LIST_STREAM_CODEC), Entry::stacks, 52 | ByteBufCodecs.optional(ByteBufCodecs.fromCodec(TagKey.codec(Registries.ITEM))), Entry::tag, 53 | Entry::new); 54 | 55 | public static Entry fromStacks(Level level, List stacks) { 56 | var tag = Entry.getTagForStacks(level, stacks); 57 | if (tag != null) { 58 | return new Entry(Optional.empty(), Optional.of(tag)); 59 | } else { 60 | return new Entry(Optional.of(stacks), Optional.empty()); 61 | } 62 | } 63 | 64 | public List getStacks(Level level) { 65 | return this.stacks.orElseGet(() -> 66 | Streams.stream(level.registryAccess().registry(Registries.ITEM).orElseThrow().getTagOrEmpty(this.tag.orElseThrow()).iterator()) 67 | .filter(h -> h.value() != null & h.value() != Items.AIR) 68 | .map(h -> new ItemStack(h.value())).collect(Collectors.toList())); 69 | } 70 | 71 | private static TagKey getTagForStacks(Level level, List stacks) { 72 | return level.registryAccess().registry(Registries.ITEM).orElseThrow().getTags().filter(e -> { 73 | var tag = e.getSecond(); 74 | if (tag.size() != stacks.size()) 75 | return false; 76 | for (var i = 0; i < tag.size(); i++) { 77 | if (stacks.get(i).getItem() != tag.get(i).value()) 78 | return false; 79 | } 80 | return true; 81 | }).map(Pair::getFirst).findFirst().orElse(null); 82 | } 83 | 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/packets/PacketItemEnterPipe.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.packets; 2 | 3 | import de.ellpeck.prettypipes.PrettyPipes; 4 | import de.ellpeck.prettypipes.Utility; 5 | import de.ellpeck.prettypipes.pipe.IPipeItem; 6 | import de.ellpeck.prettypipes.pipe.PipeBlockEntity; 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraft.core.BlockPos; 9 | import net.minecraft.nbt.CompoundTag; 10 | import net.minecraft.network.RegistryFriendlyByteBuf; 11 | import net.minecraft.network.codec.ByteBufCodecs; 12 | import net.minecraft.network.codec.StreamCodec; 13 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 14 | import net.minecraft.resources.ResourceLocation; 15 | import net.neoforged.neoforge.network.handling.IPayloadContext; 16 | 17 | public record PacketItemEnterPipe(BlockPos tilePos, CompoundTag item) implements CustomPacketPayload { 18 | 19 | public static final Type TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(PrettyPipes.ID, "item_enter_pipe")); 20 | public static final StreamCodec CODEC = StreamCodec.composite( 21 | BlockPos.STREAM_CODEC, PacketItemEnterPipe::tilePos, 22 | ByteBufCodecs.COMPOUND_TAG, PacketItemEnterPipe::item, 23 | PacketItemEnterPipe::new); 24 | 25 | @Override 26 | public Type type() { 27 | return PacketItemEnterPipe.TYPE; 28 | } 29 | 30 | public static void onMessage(PacketItemEnterPipe message, IPayloadContext ctx) { 31 | var mc = Minecraft.getInstance(); 32 | if (mc.level == null) 33 | return; 34 | var item = IPipeItem.load(mc.level.registryAccess(), message.item); 35 | var pipe = Utility.getBlockEntity(PipeBlockEntity.class, mc.level, message.tilePos); 36 | if (pipe != null) 37 | pipe.getItems().add(item); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/packets/PacketNetworkItems.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.packets; 2 | 3 | import de.ellpeck.prettypipes.PrettyPipes; 4 | import de.ellpeck.prettypipes.terminal.containers.ItemTerminalGui; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.network.RegistryFriendlyByteBuf; 7 | import net.minecraft.network.codec.ByteBufCodecs; 8 | import net.minecraft.network.codec.StreamCodec; 9 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 10 | import net.minecraft.resources.ResourceLocation; 11 | import net.minecraft.world.item.ItemStack; 12 | import net.neoforged.neoforge.network.handling.IPayloadContext; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | public record PacketNetworkItems(List items, List craftables, List currentlyCrafting) implements CustomPacketPayload { 18 | 19 | public static final Type TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(PrettyPipes.ID, "network_items")); 20 | public static final StreamCodec CODEC = StreamCodec.composite( 21 | ItemStack.LIST_STREAM_CODEC, PacketNetworkItems::items, 22 | ItemStack.LIST_STREAM_CODEC, PacketNetworkItems::craftables, 23 | ItemStack.LIST_STREAM_CODEC, PacketNetworkItems::currentlyCrafting, 24 | PacketNetworkItems::new); 25 | 26 | @Override 27 | public Type type() { 28 | return PacketNetworkItems.TYPE; 29 | } 30 | 31 | public static void onMessage(PacketNetworkItems message, IPayloadContext ctx) { 32 | var mc = Minecraft.getInstance(); 33 | if (mc.screen instanceof ItemTerminalGui terminal) 34 | terminal.updateItemList(message.items, message.craftables, message.currentlyCrafting); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/packets/PacketRequest.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.packets; 2 | 3 | import de.ellpeck.prettypipes.PrettyPipes; 4 | import de.ellpeck.prettypipes.Utility; 5 | import de.ellpeck.prettypipes.terminal.ItemTerminalBlockEntity; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.network.RegistryFriendlyByteBuf; 8 | import net.minecraft.network.codec.ByteBufCodecs; 9 | import net.minecraft.network.codec.StreamCodec; 10 | import net.minecraft.network.protocol.common.custom.CustomPacketPayload; 11 | import net.minecraft.resources.ResourceLocation; 12 | import net.minecraft.world.item.ItemStack; 13 | import net.neoforged.neoforge.network.handling.IPayloadContext; 14 | 15 | public record PacketRequest(BlockPos pos, ItemStack stack, int componentsHash, int amount) implements CustomPacketPayload { 16 | 17 | public static final Type TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(PrettyPipes.ID, "request")); 18 | public static final StreamCodec CODEC = StreamCodec.composite( 19 | BlockPos.STREAM_CODEC, PacketRequest::pos, 20 | ItemStack.STREAM_CODEC, PacketRequest::stack, 21 | ByteBufCodecs.INT, PacketRequest::componentsHash, 22 | ByteBufCodecs.INT, PacketRequest::amount, 23 | PacketRequest::new); 24 | 25 | public PacketRequest(BlockPos pos, ItemStack stack, int amount) { 26 | this(pos, stack, !stack.isComponentsPatchEmpty() ? stack.getComponents().hashCode() : 0, amount); 27 | } 28 | 29 | @Override 30 | public Type type() { 31 | return PacketRequest.TYPE; 32 | } 33 | 34 | public static void onMessage(PacketRequest message, IPayloadContext ctx) { 35 | var player = ctx.player(); 36 | var tile = Utility.getBlockEntity(ItemTerminalBlockEntity.class, player.level(), message.pos); 37 | message.stack.setCount(message.amount); 38 | tile.requestItem(player, message.stack, message.componentsHash); 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/ConnectionType.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe; 2 | 3 | import net.minecraft.util.StringRepresentable; 4 | 5 | import java.util.Locale; 6 | 7 | public enum ConnectionType implements StringRepresentable { 8 | CONNECTED(true), 9 | DISCONNECTED(false), 10 | BLOCKED(false), 11 | LEGS(false); 12 | 13 | private final String name; 14 | private final boolean isConnected; 15 | 16 | ConnectionType(boolean isConnected) { 17 | this.name = this.name().toLowerCase(Locale.ROOT); 18 | this.isConnected = isConnected; 19 | } 20 | 21 | public boolean isConnected() { 22 | return this.isConnected; 23 | } 24 | 25 | @Override 26 | public String getSerializedName() { 27 | return this.name; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/IPipeConnectable.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe; 2 | 3 | import net.minecraft.core.BlockPos; 4 | import net.minecraft.core.Direction; 5 | import net.minecraft.world.item.ItemStack; 6 | 7 | public interface IPipeConnectable { 8 | 9 | ConnectionType getConnectionType(BlockPos pipePos, Direction direction); 10 | 11 | default ItemStack insertItem(BlockPos pipePos, Direction direction, ItemStack stack, boolean simulate) { 12 | return stack; 13 | } 14 | 15 | default boolean allowsModules(BlockPos pipePos, Direction direction) { 16 | return false; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/IPipeItem.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe; 2 | 3 | import com.mojang.blaze3d.vertex.PoseStack; 4 | import de.ellpeck.prettypipes.network.NetworkEdge; 5 | import de.ellpeck.prettypipes.network.PipeItem; 6 | import net.minecraft.client.renderer.MultiBufferSource; 7 | import net.minecraft.core.BlockPos; 8 | import net.minecraft.core.HolderLookup; 9 | import net.minecraft.nbt.CompoundTag; 10 | import net.minecraft.resources.ResourceLocation; 11 | import net.minecraft.world.item.ItemStack; 12 | import net.minecraft.world.level.Level; 13 | import net.neoforged.api.distmarker.Dist; 14 | import net.neoforged.api.distmarker.OnlyIn; 15 | import net.neoforged.neoforge.common.util.INBTSerializable; 16 | import org.apache.commons.lang3.function.TriFunction; 17 | import org.jgrapht.GraphPath; 18 | 19 | import java.util.Collections; 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | import java.util.Random; 23 | 24 | public interface IPipeItem extends INBTSerializable { 25 | 26 | Map> TYPES = new HashMap<>( 27 | Collections.singletonMap(PipeItem.TYPE, PipeItem::new)); 28 | 29 | ItemStack getContent(); 30 | 31 | void setDestination(BlockPos startInventory, BlockPos destInventory, GraphPath path); 32 | 33 | void updateInPipe(PipeBlockEntity currPipe); 34 | 35 | void drop(Level world, ItemStack stack); 36 | 37 | BlockPos getDestPipe(); 38 | 39 | BlockPos getCurrentPipe(); 40 | 41 | BlockPos getDestInventory(); 42 | 43 | int getItemsOnTheWay(BlockPos goalInv); 44 | 45 | @OnlyIn(Dist.CLIENT) 46 | void render(PipeBlockEntity tile, PoseStack matrixStack, Random random, float partialTicks, int light, int overlay, MultiBufferSource source); 47 | 48 | static IPipeItem load(HolderLookup.Provider provider, CompoundTag nbt) { 49 | var type = ResourceLocation.parse(nbt.getString("type")); 50 | var func = IPipeItem.TYPES.get(type); 51 | return func != null ? func.apply(provider, type, nbt) : null; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/PipeRenderer.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe; 2 | 3 | import com.mojang.blaze3d.vertex.PoseStack; 4 | import net.minecraft.client.Minecraft; 5 | import net.minecraft.client.renderer.MultiBufferSource; 6 | import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; 7 | import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; 8 | import net.minecraft.util.RandomSource; 9 | import net.minecraft.world.phys.AABB; 10 | import net.neoforged.neoforge.client.model.data.ModelData; 11 | 12 | import java.util.Random; 13 | 14 | public class PipeRenderer implements BlockEntityRenderer { 15 | 16 | private final Random random = new Random(); 17 | 18 | public PipeRenderer(BlockEntityRendererProvider.Context ctx) { 19 | } 20 | 21 | @Override 22 | public void render(PipeBlockEntity tile, float partialTicks, PoseStack matrixStack, MultiBufferSource source, int light, int overlay) { 23 | if (!tile.getItems().isEmpty()) { 24 | matrixStack.pushPose(); 25 | var tilePos = tile.getBlockPos(); 26 | matrixStack.translate(-tilePos.getX(), -tilePos.getY(), -tilePos.getZ()); 27 | for (var item : tile.getItems()) { 28 | matrixStack.pushPose(); 29 | item.render(tile, matrixStack, this.random, partialTicks, light, overlay, source); 30 | matrixStack.popPose(); 31 | } 32 | matrixStack.popPose(); 33 | } 34 | if (tile.cover != null) { 35 | matrixStack.pushPose(); 36 | var renderer = Minecraft.getInstance().getBlockRenderer(); 37 | var model = renderer.getBlockModel(tile.cover); 38 | for (var layer : model.getRenderTypes(tile.cover, RandomSource.create(tile.cover.getSeed(tile.getBlockPos())), ModelData.EMPTY)) { 39 | renderer.getModelRenderer().tesselateBlock(tile.getLevel(), model, tile.cover, tile.getBlockPos(), matrixStack, source.getBuffer(layer), true, RandomSource.create(), tile.cover.getSeed(tile.getBlockPos()), overlay, ModelData.EMPTY, layer); 40 | } 41 | matrixStack.popPose(); 42 | } 43 | } 44 | 45 | @Override 46 | public AABB getRenderBoundingBox(PipeBlockEntity blockEntity) { 47 | // our render bounding box should always be the full block in case we're covered 48 | return new AABB(blockEntity.getBlockPos()); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/containers/AbstractPipeContainer.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.containers; 2 | 3 | import de.ellpeck.prettypipes.Utility; 4 | import de.ellpeck.prettypipes.items.IModule; 5 | import de.ellpeck.prettypipes.misc.FilterSlot; 6 | import de.ellpeck.prettypipes.pipe.PipeBlockEntity; 7 | import net.minecraft.core.BlockPos; 8 | import net.minecraft.world.entity.player.Player; 9 | import net.minecraft.world.inventory.AbstractContainerMenu; 10 | import net.minecraft.world.inventory.ClickType; 11 | import net.minecraft.world.inventory.MenuType; 12 | import net.minecraft.world.inventory.Slot; 13 | import net.minecraft.world.item.ItemStack; 14 | import org.apache.commons.lang3.tuple.Pair; 15 | 16 | import javax.annotation.Nullable; 17 | 18 | public abstract class AbstractPipeContainer extends AbstractContainerMenu { 19 | 20 | public final PipeBlockEntity tile; 21 | public final T module; 22 | public final int moduleIndex; 23 | public final ItemStack moduleStack; 24 | 25 | public AbstractPipeContainer(@Nullable MenuType type, int id, Player player, BlockPos pos, int moduleIndex) { 26 | super(type, id); 27 | this.tile = Utility.getBlockEntity(PipeBlockEntity.class, player.level(), pos); 28 | this.moduleStack = moduleIndex < 0 ? null : this.tile.modules.getStackInSlot(moduleIndex); 29 | this.module = moduleIndex < 0 ? null : (T) this.moduleStack.getItem(); 30 | this.moduleIndex = moduleIndex; 31 | 32 | // needs to be done here so transferStackInSlot works correctly, bleh 33 | this.addSlots(); 34 | 35 | for (var l = 0; l < 3; ++l) 36 | for (var j1 = 0; j1 < 9; ++j1) 37 | this.addSlot(new Slot(player.getInventory(), j1 + l * 9 + 9, 8 + j1 * 18, 89 + l * 18 + 32)); 38 | for (var i1 = 0; i1 < 9; ++i1) 39 | this.addSlot(new Slot(player.getInventory(), i1, 8 + i1 * 18, 147 + 32)); 40 | } 41 | 42 | protected abstract void addSlots(); 43 | 44 | @Override 45 | public ItemStack quickMoveStack(Player player, int slotIndex) { 46 | return Utility.transferStackInSlot(this, this::moveItemStackTo, player, slotIndex, stack -> { 47 | if (stack.getItem() instanceof IModule) 48 | return Pair.of(0, 3); 49 | return null; 50 | }); 51 | } 52 | 53 | @Override 54 | public void clicked(int slotId, int dragType, ClickType clickTypeIn, Player player) { 55 | if (FilterSlot.checkFilter(this, slotId)) 56 | return; 57 | super.clicked(slotId, dragType, clickTypeIn, player); 58 | } 59 | 60 | @Override 61 | public boolean stillValid(Player player) { 62 | return true; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/containers/MainPipeContainer.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.containers; 2 | 3 | import de.ellpeck.prettypipes.items.IModule; 4 | import net.minecraft.core.BlockPos; 5 | import net.minecraft.world.entity.player.Player; 6 | import net.minecraft.world.inventory.MenuType; 7 | import net.neoforged.neoforge.items.SlotItemHandler; 8 | 9 | import javax.annotation.Nullable; 10 | 11 | public class MainPipeContainer extends AbstractPipeContainer { 12 | 13 | public MainPipeContainer(@Nullable MenuType type, int id, Player player, BlockPos pos) { 14 | super(type, id, player, pos, -1); 15 | } 16 | 17 | @Override 18 | protected void addSlots() { 19 | for (var i = 0; i < 3; i++) 20 | this.addSlot(new SlotItemHandler(this.tile.modules, i, 62 + i * 18, 17 + 32)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/containers/MainPipeGui.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.containers; 2 | 3 | import net.minecraft.network.chat.Component; 4 | import net.minecraft.world.entity.player.Inventory; 5 | 6 | public class MainPipeGui extends AbstractPipeGui { 7 | 8 | public MainPipeGui(MainPipeContainer screenContainer, Inventory inv, Component titleIn) { 9 | super(screenContainer, inv, titleIn); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/HighPriorityModuleItem.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules; 2 | 3 | import de.ellpeck.prettypipes.items.IModule; 4 | import de.ellpeck.prettypipes.items.ModuleItem; 5 | import de.ellpeck.prettypipes.items.ModuleTier; 6 | import de.ellpeck.prettypipes.pipe.PipeBlockEntity; 7 | import net.minecraft.world.item.ItemStack; 8 | 9 | public class HighPriorityModuleItem extends ModuleItem { 10 | 11 | private final int priority; 12 | 13 | public HighPriorityModuleItem(String name, ModuleTier tier) { 14 | super(name, new Properties()); 15 | this.priority = tier.forTier(50, 100, 200); 16 | } 17 | 18 | @Override 19 | public int getPriority(ItemStack module, PipeBlockEntity tile) { 20 | return this.priority; 21 | } 22 | 23 | @Override 24 | public boolean isCompatible(ItemStack module, PipeBlockEntity tile, IModule other) { 25 | return !(other instanceof HighPriorityModuleItem) && !(other instanceof LowPriorityModuleItem); 26 | } 27 | 28 | @Override 29 | public boolean hasContainer(ItemStack module, PipeBlockEntity tile) { 30 | return false; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/LowPriorityModuleItem.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules; 2 | 3 | import de.ellpeck.prettypipes.items.IModule; 4 | import de.ellpeck.prettypipes.items.ModuleItem; 5 | import de.ellpeck.prettypipes.items.ModuleTier; 6 | import de.ellpeck.prettypipes.pipe.PipeBlockEntity; 7 | import net.minecraft.world.item.ItemStack; 8 | 9 | public class LowPriorityModuleItem extends ModuleItem { 10 | 11 | private final int priority; 12 | 13 | public LowPriorityModuleItem(String name, ModuleTier tier) { 14 | super(name, new Properties()); 15 | this.priority = tier.forTier(-50, -100, -200); 16 | } 17 | 18 | @Override 19 | public int getPriority(ItemStack module, PipeBlockEntity tile) { 20 | return this.priority; 21 | } 22 | 23 | @Override 24 | public boolean isCompatible(ItemStack module, PipeBlockEntity tile, IModule other) { 25 | return !(other instanceof LowPriorityModuleItem) && !(other instanceof HighPriorityModuleItem); 26 | } 27 | 28 | @Override 29 | public boolean hasContainer(ItemStack module, PipeBlockEntity tile) { 30 | return false; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/RedstoneModuleItem.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules; 2 | 3 | import de.ellpeck.prettypipes.items.IModule; 4 | import de.ellpeck.prettypipes.items.ModuleItem; 5 | import de.ellpeck.prettypipes.pipe.PipeBlockEntity; 6 | import net.minecraft.world.item.ItemStack; 7 | 8 | public class RedstoneModuleItem extends ModuleItem { 9 | 10 | public RedstoneModuleItem() { 11 | super("redstone_module", new Properties()); 12 | } 13 | 14 | @Override 15 | public boolean canPipeWork(ItemStack module, PipeBlockEntity tile) { 16 | return !tile.getLevel().hasNeighborSignal(tile.getBlockPos()); 17 | } 18 | 19 | @Override 20 | public boolean isCompatible(ItemStack module, PipeBlockEntity tile, IModule other) { 21 | return other != this; 22 | } 23 | 24 | @Override 25 | public boolean hasContainer(ItemStack module, PipeBlockEntity tile) { 26 | return false; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/SortingModuleItem.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules; 2 | 3 | import com.mojang.serialization.Codec; 4 | import com.mojang.serialization.codecs.RecordCodecBuilder; 5 | import de.ellpeck.prettypipes.items.IModule; 6 | import de.ellpeck.prettypipes.items.ModuleItem; 7 | import de.ellpeck.prettypipes.pipe.PipeBlockEntity; 8 | import net.minecraft.core.BlockPos; 9 | import net.minecraft.core.component.DataComponentType; 10 | import net.minecraft.world.item.ItemStack; 11 | 12 | import java.util.List; 13 | 14 | public class SortingModuleItem extends ModuleItem { 15 | 16 | private final Type type; 17 | 18 | public SortingModuleItem(String name, Type type) { 19 | super(name, new Properties()); 20 | this.type = type; 21 | } 22 | 23 | @Override 24 | public boolean isCompatible(ItemStack module, PipeBlockEntity tile, IModule other) { 25 | return !(other instanceof SortingModuleItem); 26 | } 27 | 28 | @Override 29 | public boolean hasContainer(ItemStack module, PipeBlockEntity tile) { 30 | return false; 31 | } 32 | 33 | @Override 34 | public Integer getCustomNextNode(ItemStack module, PipeBlockEntity tile, List nodes, int index) { 35 | switch (this.type) { 36 | case ROUND_ROBIN: 37 | // store an ever-increasing index and choose destinations based on that 38 | var prevData = module.get(Data.TYPE); 39 | var next = prevData != null ? prevData.last + 1 : 0; 40 | module.set(Data.TYPE, new Data(next)); 41 | return next % nodes.size(); 42 | case RANDOM: 43 | return tile.getLevel().random.nextInt(nodes.size()); 44 | } 45 | return null; 46 | } 47 | 48 | public enum Type { 49 | ROUND_ROBIN, 50 | RANDOM 51 | } 52 | 53 | public record Data(int last) { 54 | 55 | public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group(Codec.INT.fieldOf("last").forGetter(f -> f.last)).apply(i, Data::new)); 56 | public static final DataComponentType TYPE = DataComponentType.builder().persistent(Data.CODEC).cacheEncoding().build(); 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/SpeedModuleItem.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules; 2 | 3 | import de.ellpeck.prettypipes.items.IModule; 4 | import de.ellpeck.prettypipes.items.ModuleItem; 5 | import de.ellpeck.prettypipes.items.ModuleTier; 6 | import de.ellpeck.prettypipes.pipe.PipeBlockEntity; 7 | import net.minecraft.world.item.ItemStack; 8 | 9 | public class SpeedModuleItem extends ModuleItem { 10 | 11 | private final float speedIncrease; 12 | 13 | public SpeedModuleItem(String name, ModuleTier tier) { 14 | super(name, new Properties()); 15 | this.speedIncrease = tier.forTier(0.05F, 0.1F, 0.2F); 16 | } 17 | 18 | @Override 19 | public boolean isCompatible(ItemStack module, PipeBlockEntity tile, IModule other) { 20 | return !(other instanceof SpeedModuleItem); 21 | } 22 | 23 | @Override 24 | public boolean hasContainer(ItemStack module, PipeBlockEntity tile) { 25 | return false; 26 | } 27 | 28 | @Override 29 | public float getItemSpeedIncrease(ItemStack module, PipeBlockEntity tile) { 30 | return this.speedIncrease; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/craft/CraftingModuleContainer.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.craft; 2 | 3 | import de.ellpeck.prettypipes.Utility; 4 | import de.ellpeck.prettypipes.misc.FilterSlot; 5 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.world.entity.player.Player; 8 | import net.minecraft.world.inventory.MenuType; 9 | import net.neoforged.neoforge.items.ItemStackHandler; 10 | 11 | public class CraftingModuleContainer extends AbstractPipeContainer { 12 | 13 | public ItemStackHandler input; 14 | public ItemStackHandler output; 15 | public boolean emitRedstone; 16 | public CraftingModuleItem.InsertionType insertionType; 17 | public boolean insertUnstacked; 18 | public boolean modified; 19 | 20 | public CraftingModuleContainer(MenuType type, int id, Player player, BlockPos pos, int moduleIndex) { 21 | super(type, id, player, pos, moduleIndex); 22 | } 23 | 24 | @Override 25 | protected void addSlots() { 26 | var contents = this.moduleStack.get(CraftingModuleItem.Contents.TYPE); 27 | this.emitRedstone = contents.emitRedstone(); 28 | this.insertionType = contents.insertionType(); 29 | this.insertUnstacked = contents.insertUnstacked(); 30 | 31 | this.input = Utility.copy(contents.input()); 32 | for (var i = 0; i < this.input.getSlots(); i++) { 33 | this.addSlot(new FilterSlot(this.input, i, (176 - this.input.getSlots() * 18) / 2 + 1 + i % 9 * 18, 17 + 32 + i / 9 * 18, false) { 34 | @Override 35 | public void setChanged() { 36 | super.setChanged(); 37 | CraftingModuleContainer.this.modified = true; 38 | } 39 | 40 | }); 41 | } 42 | 43 | this.output = Utility.copy(contents.output()); 44 | for (var i = 0; i < this.output.getSlots(); i++) { 45 | this.addSlot(new FilterSlot(this.output, i, (176 - this.output.getSlots() * 18) / 2 + 1 + i % 9 * 18, 85 + i / 9 * 18, false) { 46 | @Override 47 | public void setChanged() { 48 | super.setChanged(); 49 | CraftingModuleContainer.this.modified = true; 50 | } 51 | }); 52 | } 53 | } 54 | 55 | @Override 56 | public void removed(Player playerIn) { 57 | super.removed(playerIn); 58 | if (this.modified) { 59 | this.moduleStack.set(CraftingModuleItem.Contents.TYPE, new CraftingModuleItem.Contents(this.input, this.output, this.emitRedstone, this.insertionType, this.insertUnstacked)); 60 | this.tile.setChanged(); 61 | } 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/craft/CraftingModuleGui.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.craft; 2 | 3 | import de.ellpeck.prettypipes.PrettyPipes; 4 | import de.ellpeck.prettypipes.packets.PacketButton; 5 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeGui; 6 | import net.minecraft.ChatFormatting; 7 | import net.minecraft.client.gui.GuiGraphics; 8 | import net.minecraft.client.gui.components.Button; 9 | import net.minecraft.client.gui.components.Tooltip; 10 | import net.minecraft.network.chat.Component; 11 | import net.minecraft.network.chat.MutableComponent; 12 | import net.minecraft.world.entity.player.Inventory; 13 | 14 | import java.util.List; 15 | import java.util.Locale; 16 | import java.util.function.Supplier; 17 | 18 | public class CraftingModuleGui extends AbstractPipeGui { 19 | 20 | public CraftingModuleGui(CraftingModuleContainer screenContainer, Inventory inv, Component titleIn) { 21 | super(screenContainer, inv, titleIn); 22 | } 23 | 24 | @Override 25 | protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) { 26 | super.renderBg(graphics, partialTicks, mouseX, mouseY); 27 | graphics.blit(AbstractPipeGui.TEXTURE, this.leftPos + 176 / 2 - 16 / 2, this.topPos + 32 + 18 * 2, 176, 80, 16, 16); 28 | } 29 | 30 | @Override 31 | protected void init() { 32 | super.init(); 33 | 34 | var redstoneText = (Supplier) () -> "info." + PrettyPipes.ID + ".emit_redstone_" + (this.menu.emitRedstone ? "on" : "off"); 35 | this.addRenderableWidget(Button.builder(Component.translatable(redstoneText.get()), button -> { 36 | PacketButton.sendAndExecute(this.menu.tile.getBlockPos(), PacketButton.ButtonResult.EMIT_REDSTONE_BUTTON, List.of()); 37 | button.setMessage(Component.translatable(redstoneText.get())); 38 | }).bounds(this.leftPos + this.imageWidth - 7 - 20, this.topPos + 17 + 32 + 18 * 2 + 2, 20, 20).tooltip( 39 | Tooltip.create(Component.translatable("info." + PrettyPipes.ID + ".emit_redstone.description").withStyle(ChatFormatting.GRAY))).build()); 40 | var unstackedText = (Supplier) () -> "info." + PrettyPipes.ID + ".insert_unstacked_" + (this.menu.insertUnstacked ? "on" : "off"); 41 | this.addRenderableWidget(Button.builder(Component.translatable(unstackedText.get()), button -> { 42 | PacketButton.sendAndExecute(this.menu.tile.getBlockPos(), PacketButton.ButtonResult.INSERT_UNSTACKED_BUTTON, List.of()); 43 | button.setMessage(Component.translatable(unstackedText.get())); 44 | }).bounds(this.leftPos + this.imageWidth - 7 - 20 - 22, this.topPos + 17 + 32 + 18 * 2 + 2, 20, 20).tooltip( 45 | Tooltip.create(Component.translatable("info." + PrettyPipes.ID + ".insert_unstacked.description").withStyle(ChatFormatting.GRAY))).build()); 46 | 47 | var insertionTypeText = (Supplier) () -> Component.translatable(this.menu.insertionType.translationKey()); 48 | var insertionTypeTooltip = (Supplier) () -> Tooltip.create(Component.translatable(this.menu.insertionType.translationKey() + ".description").withStyle(ChatFormatting.GRAY)); 49 | this.addRenderableWidget(Button.builder(insertionTypeText.get(), button -> { 50 | PacketButton.sendAndExecute(this.menu.tile.getBlockPos(), PacketButton.ButtonResult.INSERTION_TYPE_BUTTON, List.of()); 51 | button.setMessage(insertionTypeText.get()); 52 | button.setTooltip(insertionTypeTooltip.get()); 53 | }).bounds(this.leftPos + 7, this.topPos + 17 + 32 + 18 * 2 + 2, 42, 20).tooltip(insertionTypeTooltip.get()).build()); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/extraction/ExtractionModuleContainer.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.extraction; 2 | 3 | import de.ellpeck.prettypipes.misc.DirectionSelector; 4 | import de.ellpeck.prettypipes.misc.DirectionSelector.IDirectionContainer; 5 | import de.ellpeck.prettypipes.misc.ItemFilter; 6 | import de.ellpeck.prettypipes.misc.ItemFilter.IFilteredContainer; 7 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; 8 | import net.minecraft.core.BlockPos; 9 | import net.minecraft.world.entity.player.Player; 10 | import net.minecraft.world.inventory.MenuType; 11 | 12 | import javax.annotation.Nullable; 13 | 14 | public class ExtractionModuleContainer extends AbstractPipeContainer implements IFilteredContainer, IDirectionContainer { 15 | 16 | public ItemFilter filter; 17 | public DirectionSelector directionSelector; 18 | 19 | public ExtractionModuleContainer(@Nullable MenuType type, int id, Player player, BlockPos pos, int moduleIndex) { 20 | super(type, id, player, pos, moduleIndex); 21 | } 22 | 23 | @Override 24 | protected void addSlots() { 25 | this.filter = this.module.getItemFilter(this.moduleStack, this.tile); 26 | this.directionSelector = this.module.getDirectionSelector(this.moduleStack, this.tile); 27 | 28 | for (var slot : this.filter.getSlots((176 - this.module.filterSlots * 18) / 2 + 1, 17 + 32)) 29 | this.addSlot(slot); 30 | } 31 | 32 | @Override 33 | public void removed(Player playerIn) { 34 | super.removed(playerIn); 35 | this.filter.save(); 36 | this.directionSelector.save(); 37 | } 38 | 39 | @Override 40 | public ItemFilter getFilter() { 41 | return this.filter; 42 | } 43 | 44 | @Override 45 | public DirectionSelector getSelector() { 46 | return this.directionSelector; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/extraction/ExtractionModuleGui.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.extraction; 2 | 3 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeGui; 4 | import net.minecraft.network.chat.Component; 5 | import net.minecraft.world.entity.player.Inventory; 6 | 7 | public class ExtractionModuleGui extends AbstractPipeGui { 8 | 9 | public ExtractionModuleGui(ExtractionModuleContainer screenContainer, Inventory inv, Component titleIn) { 10 | super(screenContainer, inv, titleIn); 11 | } 12 | 13 | @Override 14 | protected void init() { 15 | super.init(); 16 | for (var widget : this.menu.filter.getButtons(this, this.leftPos + this.imageWidth - 7, this.topPos + 17 + 32 + 20, true)) 17 | this.addRenderableWidget(widget); 18 | this.addRenderableWidget(this.menu.directionSelector.getButton(this.leftPos + 7, this.topPos + 17 + 32 + 20)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/extraction/ExtractionModuleItem.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.extraction; 2 | 3 | import de.ellpeck.prettypipes.Registry; 4 | import de.ellpeck.prettypipes.items.IModule; 5 | import de.ellpeck.prettypipes.items.ModuleItem; 6 | import de.ellpeck.prettypipes.items.ModuleTier; 7 | import de.ellpeck.prettypipes.misc.DirectionSelector; 8 | import de.ellpeck.prettypipes.misc.ItemFilter; 9 | import de.ellpeck.prettypipes.network.PipeNetwork; 10 | import de.ellpeck.prettypipes.pipe.PipeBlockEntity; 11 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; 12 | import net.minecraft.core.Direction; 13 | import net.minecraft.world.entity.player.Inventory; 14 | import net.minecraft.world.entity.player.Player; 15 | import net.minecraft.world.item.ItemStack; 16 | import net.neoforged.neoforge.items.IItemHandler; 17 | 18 | public class ExtractionModuleItem extends ModuleItem { 19 | 20 | private final int maxExtraction; 21 | private final int speed; 22 | private final boolean preventOversending; 23 | public final int filterSlots; 24 | 25 | public ExtractionModuleItem(String name, ModuleTier tier) { 26 | super(name, new Properties()); 27 | this.maxExtraction = tier.forTier(1, 8, 64); 28 | this.speed = tier.forTier(20, 15, 10); 29 | this.filterSlots = tier.forTier(3, 6, 9); 30 | this.preventOversending = tier.forTier(false, true, true); 31 | } 32 | 33 | @Override 34 | public void tick(ItemStack module, PipeBlockEntity tile) { 35 | if (!tile.shouldWorkNow(this.speed) || !tile.canWork()) 36 | return; 37 | var filter = this.getItemFilter(module, tile); 38 | var dirSelector = this.getDirectionSelector(module, tile); 39 | for (var dir : dirSelector.directions()) { 40 | var handler = tile.getItemHandler(dir); 41 | if (handler == null) 42 | continue; 43 | var network = PipeNetwork.get(tile.getLevel()); 44 | for (var j = 0; j < handler.getSlots(); j++) { 45 | var stack = handler.extractItem(j, this.maxExtraction, true); 46 | if (stack.isEmpty()) 47 | continue; 48 | if (!filter.isAllowed(stack, dir)) 49 | continue; 50 | var remain = network.routeItem(tile.getBlockPos(), tile.getBlockPos().relative(dir), stack, this.preventOversending); 51 | if (remain.getCount() != stack.getCount()) { 52 | handler.extractItem(j, stack.getCount() - remain.getCount(), false); 53 | return; 54 | } 55 | } 56 | } 57 | } 58 | 59 | @Override 60 | public boolean canNetworkSee(ItemStack module, PipeBlockEntity tile, Direction direction, IItemHandler handler) { 61 | return !this.getDirectionSelector(module, tile).has(direction); 62 | } 63 | 64 | @Override 65 | public boolean canAcceptItem(ItemStack module, PipeBlockEntity tile, ItemStack stack, Direction direction, IItemHandler destination) { 66 | return !this.getDirectionSelector(module, tile).has(direction); 67 | } 68 | 69 | @Override 70 | public boolean isCompatible(ItemStack module, PipeBlockEntity tile, IModule other) { 71 | return !(other instanceof ExtractionModuleItem); 72 | } 73 | 74 | @Override 75 | public boolean hasContainer(ItemStack module, PipeBlockEntity tile) { 76 | return true; 77 | } 78 | 79 | @Override 80 | public AbstractPipeContainer getContainer(ItemStack module, PipeBlockEntity tile, int windowId, Inventory inv, Player player, int moduleIndex) { 81 | return new ExtractionModuleContainer(Registry.extractionModuleContainer, windowId, player, tile.getBlockPos(), moduleIndex); 82 | } 83 | 84 | @Override 85 | public ItemFilter getItemFilter(ItemStack module, PipeBlockEntity tile) { 86 | return new ItemFilter(this.filterSlots, module, tile); 87 | } 88 | 89 | @Override 90 | public DirectionSelector getDirectionSelector(ItemStack module, PipeBlockEntity tile) { 91 | return new DirectionSelector(module, tile); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/filter/FilterIncreaseModuleContainer.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.filter; 2 | 3 | import de.ellpeck.prettypipes.misc.ItemFilter; 4 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; 5 | import net.minecraft.core.BlockPos; 6 | import net.minecraft.world.entity.player.Player; 7 | import net.minecraft.world.inventory.MenuType; 8 | 9 | public class FilterIncreaseModuleContainer extends AbstractPipeContainer implements ItemFilter.IFilteredContainer { 10 | 11 | public ItemFilter filter; 12 | 13 | public FilterIncreaseModuleContainer(MenuType type, int id, Player player, BlockPos pos, int moduleIndex) { 14 | super(type, id, player, pos, moduleIndex); 15 | } 16 | 17 | @Override 18 | protected void addSlots() { 19 | this.filter = this.module.getItemFilter(this.moduleStack, this.tile); 20 | for (var slot : this.filter.getSlots(8, 49)) 21 | this.addSlot(slot); 22 | } 23 | 24 | @Override 25 | public void removed(Player playerIn) { 26 | super.removed(playerIn); 27 | this.filter.save(); 28 | } 29 | 30 | @Override 31 | public ItemFilter getFilter() { 32 | return this.filter; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/filter/FilterIncreaseModuleGui.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.filter; 2 | 3 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeGui; 4 | import net.minecraft.network.chat.Component; 5 | import net.minecraft.world.entity.player.Inventory; 6 | 7 | public class FilterIncreaseModuleGui extends AbstractPipeGui { 8 | 9 | public FilterIncreaseModuleGui(FilterIncreaseModuleContainer screenContainer, Inventory inv, Component titleIn) { 10 | super(screenContainer, inv, titleIn); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/filter/FilterIncreaseModuleItem.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.filter; 2 | 3 | import de.ellpeck.prettypipes.Registry; 4 | import de.ellpeck.prettypipes.items.IModule; 5 | import de.ellpeck.prettypipes.items.ModuleItem; 6 | import de.ellpeck.prettypipes.misc.ItemFilter; 7 | import de.ellpeck.prettypipes.pipe.PipeBlockEntity; 8 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; 9 | import net.minecraft.world.entity.player.Inventory; 10 | import net.minecraft.world.entity.player.Player; 11 | import net.minecraft.world.item.ItemStack; 12 | 13 | public class FilterIncreaseModuleItem extends ModuleItem { 14 | 15 | public FilterIncreaseModuleItem() { 16 | super("filter_increase_modifier", new Properties()); 17 | } 18 | 19 | @Override 20 | public boolean isCompatible(ItemStack module, PipeBlockEntity tile, IModule other) { 21 | return true; 22 | } 23 | 24 | @Override 25 | public boolean hasContainer(ItemStack module, PipeBlockEntity tile) { 26 | return true; 27 | } 28 | 29 | @Override 30 | public AbstractPipeContainer getContainer(ItemStack module, PipeBlockEntity tile, int windowId, Inventory inv, Player player, int moduleIndex) { 31 | return new FilterIncreaseModuleContainer(Registry.filterIncreaseModuleContainer, windowId, player, tile.getBlockPos(), moduleIndex); 32 | } 33 | 34 | @Override 35 | public ItemFilter getItemFilter(ItemStack module, PipeBlockEntity tile) { 36 | var filter = new ItemFilter(27, module, tile); 37 | filter.canModifyWhitelist = false; 38 | return filter; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/insertion/FilterModuleContainer.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.insertion; 2 | 3 | import de.ellpeck.prettypipes.misc.DirectionSelector; 4 | import de.ellpeck.prettypipes.misc.DirectionSelector.IDirectionContainer; 5 | import de.ellpeck.prettypipes.misc.ItemFilter; 6 | import de.ellpeck.prettypipes.misc.ItemFilter.IFilteredContainer; 7 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; 8 | import net.minecraft.core.BlockPos; 9 | import net.minecraft.world.entity.player.Player; 10 | import net.minecraft.world.inventory.MenuType; 11 | 12 | import javax.annotation.Nullable; 13 | 14 | public class FilterModuleContainer extends AbstractPipeContainer implements IFilteredContainer, IDirectionContainer { 15 | 16 | public ItemFilter filter; 17 | public DirectionSelector directionSelector; 18 | 19 | public FilterModuleContainer(@Nullable MenuType type, int id, Player player, BlockPos pos, int moduleIndex) { 20 | super(type, id, player, pos, moduleIndex); 21 | } 22 | 23 | @Override 24 | public void onFilterPopulated() { 25 | // reload the filter so that it displays correctly on the client 26 | this.filter.load(); 27 | } 28 | 29 | @Override 30 | protected void addSlots() { 31 | this.filter = this.module.getItemFilter(this.moduleStack, this.tile); 32 | this.directionSelector = this.module.getDirectionSelector(this.moduleStack, this.tile); 33 | 34 | for (var slot : this.filter.getSlots((176 - Math.min(this.module.filterSlots, 9) * 18) / 2 + 1, 17 + 32)) 35 | this.addSlot(slot); 36 | } 37 | 38 | @Override 39 | public void removed(Player playerIn) { 40 | super.removed(playerIn); 41 | this.filter.save(); 42 | this.directionSelector.save(); 43 | } 44 | 45 | @Override 46 | public ItemFilter getFilter() { 47 | return this.filter; 48 | } 49 | 50 | @Override 51 | public DirectionSelector getSelector() { 52 | return this.directionSelector; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/insertion/FilterModuleGui.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.insertion; 2 | 3 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeGui; 4 | import net.minecraft.network.chat.Component; 5 | import net.minecraft.util.Mth; 6 | import net.minecraft.world.entity.player.Inventory; 7 | 8 | public class FilterModuleGui extends AbstractPipeGui { 9 | 10 | public FilterModuleGui(FilterModuleContainer screenContainer, Inventory inv, Component titleIn) { 11 | super(screenContainer, inv, titleIn); 12 | } 13 | 14 | @Override 15 | protected void init() { 16 | super.init(); 17 | var buttonsY = this.topPos + 17 + 32 + 18 * Mth.ceil(this.menu.filter.content.getSlots() / 9F) + 2; 18 | for (var widget : this.menu.filter.getButtons(this, this.leftPos + this.imageWidth - 7, buttonsY, true)) 19 | this.addRenderableWidget(widget); 20 | this.addRenderableWidget(this.menu.directionSelector.getButton(this.leftPos + 7, buttonsY)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/insertion/FilterModuleItem.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.insertion; 2 | 3 | import de.ellpeck.prettypipes.Registry; 4 | import de.ellpeck.prettypipes.items.IModule; 5 | import de.ellpeck.prettypipes.items.ModuleItem; 6 | import de.ellpeck.prettypipes.items.ModuleTier; 7 | import de.ellpeck.prettypipes.misc.DirectionSelector; 8 | import de.ellpeck.prettypipes.misc.ItemFilter; 9 | import de.ellpeck.prettypipes.pipe.PipeBlockEntity; 10 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; 11 | import net.minecraft.core.Direction; 12 | import net.minecraft.world.entity.player.Inventory; 13 | import net.minecraft.world.entity.player.Player; 14 | import net.minecraft.world.item.ItemStack; 15 | import net.neoforged.neoforge.items.IItemHandler; 16 | 17 | public class FilterModuleItem extends ModuleItem { 18 | 19 | public final int filterSlots; 20 | private final boolean canPopulateFromInventories; 21 | 22 | public FilterModuleItem(String name, ModuleTier tier) { 23 | super(name, new Properties()); 24 | this.filterSlots = tier.forTier(5, 9, 18); 25 | this.canPopulateFromInventories = tier.forTier(false, false, true); 26 | } 27 | 28 | @Override 29 | public boolean canAcceptItem(ItemStack module, PipeBlockEntity tile, ItemStack stack, Direction direction, IItemHandler destination) { 30 | return !this.getDirectionSelector(module, tile).has(direction) || this.getItemFilter(module, tile).isAllowed(stack, direction); 31 | } 32 | 33 | @Override 34 | public boolean isCompatible(ItemStack module, PipeBlockEntity tile, IModule other) { 35 | return !(other instanceof FilterModuleItem); 36 | } 37 | 38 | @Override 39 | public boolean hasContainer(ItemStack module, PipeBlockEntity tile) { 40 | return true; 41 | } 42 | 43 | @Override 44 | public AbstractPipeContainer getContainer(ItemStack module, PipeBlockEntity tile, int windowId, Inventory inv, Player player, int moduleIndex) { 45 | return new FilterModuleContainer(Registry.filterModuleContainer, windowId, player, tile.getBlockPos(), moduleIndex); 46 | } 47 | 48 | @Override 49 | public ItemFilter getItemFilter(ItemStack module, PipeBlockEntity tile) { 50 | var filter = new ItemFilter(this.filterSlots, module, tile); 51 | filter.canPopulateFromInventories = this.canPopulateFromInventories; 52 | return filter; 53 | } 54 | 55 | @Override 56 | public DirectionSelector getDirectionSelector(ItemStack module, PipeBlockEntity tile) { 57 | return new DirectionSelector(module, tile); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/modifier/FilterModifierModuleContainer.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.modifier; 2 | 3 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; 4 | import net.minecraft.core.BlockPos; 5 | import net.minecraft.resources.ResourceLocation; 6 | import net.minecraft.world.entity.player.Player; 7 | import net.minecraft.world.inventory.MenuType; 8 | 9 | import javax.annotation.Nullable; 10 | import java.util.HashSet; 11 | import java.util.List; 12 | import java.util.Set; 13 | import java.util.stream.Collectors; 14 | 15 | public class FilterModifierModuleContainer extends AbstractPipeContainer { 16 | 17 | public FilterModifierModuleContainer(@Nullable MenuType type, int id, Player player, BlockPos pos, int moduleIndex) { 18 | super(type, id, player, pos, moduleIndex); 19 | } 20 | 21 | public List getTags() { 22 | Set unsortedTags = new HashSet<>(); 23 | for (var filter : this.tile.getFilters(null)) { 24 | for (var i = 0; i < filter.content.getSlots(); i++) { 25 | var stack = filter.content.getStackInSlot(i); 26 | stack.getTags().forEach(t -> unsortedTags.add(t.location())); 27 | } 28 | } 29 | return unsortedTags.stream().sorted().collect(Collectors.toList()); 30 | } 31 | 32 | @Override 33 | protected void addSlots() { 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/modifier/FilterModifierModuleItem.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.modifier; 2 | 3 | import com.mojang.serialization.Codec; 4 | import com.mojang.serialization.codecs.RecordCodecBuilder; 5 | import de.ellpeck.prettypipes.Registry; 6 | import de.ellpeck.prettypipes.items.IModule; 7 | import de.ellpeck.prettypipes.items.ModuleItem; 8 | import de.ellpeck.prettypipes.misc.ItemEquality; 9 | import de.ellpeck.prettypipes.pipe.PipeBlockEntity; 10 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; 11 | import net.minecraft.core.component.DataComponentType; 12 | import net.minecraft.resources.ResourceLocation; 13 | import net.minecraft.world.entity.player.Inventory; 14 | import net.minecraft.world.entity.player.Player; 15 | import net.minecraft.world.item.ItemStack; 16 | 17 | public class FilterModifierModuleItem extends ModuleItem { 18 | 19 | public final ItemEquality.Type type; 20 | 21 | public FilterModifierModuleItem(String name, ItemEquality.Type type) { 22 | super(name, new Properties()); 23 | this.type = type; 24 | } 25 | 26 | @Override 27 | public boolean isCompatible(ItemStack module, PipeBlockEntity tile, IModule other) { 28 | return other != this; 29 | } 30 | 31 | @Override 32 | public boolean hasContainer(ItemStack module, PipeBlockEntity tile) { 33 | return this.type == ItemEquality.Type.TAG; 34 | } 35 | 36 | @Override 37 | public AbstractPipeContainer getContainer(ItemStack module, PipeBlockEntity tile, int windowId, Inventory inv, Player player, int moduleIndex) { 38 | return new FilterModifierModuleContainer(Registry.filterModifierModuleContainer, windowId, player, tile.getBlockPos(), moduleIndex); 39 | } 40 | 41 | public ItemEquality getEqualityType(ItemStack stack) { 42 | if (this.type == ItemEquality.Type.TAG) { 43 | return ItemEquality.tag(FilterModifierModuleItem.getFilterTag(stack)); 44 | } else { 45 | return this.type.getDefaultInstance(); 46 | } 47 | } 48 | 49 | public static ResourceLocation getFilterTag(ItemStack stack) { 50 | var data = stack.get(Data.TYPE); 51 | return data != null && data.filterTag != null ? ResourceLocation.parse(data.filterTag) : null; 52 | } 53 | 54 | public static void setFilterTag(ItemStack stack, ResourceLocation tag) { 55 | stack.set(Data.TYPE, new Data(tag.toString())); 56 | } 57 | 58 | public record Data(String filterTag) { 59 | 60 | public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( 61 | Codec.STRING.fieldOf("filter_tag").forGetter(f -> f.filterTag) 62 | ).apply(i, Data::new)); 63 | public static final DataComponentType TYPE = DataComponentType.builder().persistent(Data.CODEC).cacheEncoding().build(); 64 | 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleContainer.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.retrieval; 2 | 3 | import de.ellpeck.prettypipes.misc.DirectionSelector; 4 | import de.ellpeck.prettypipes.misc.DirectionSelector.IDirectionContainer; 5 | import de.ellpeck.prettypipes.misc.ItemFilter; 6 | import de.ellpeck.prettypipes.misc.ItemFilter.IFilteredContainer; 7 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; 8 | import net.minecraft.core.BlockPos; 9 | import net.minecraft.world.entity.player.Player; 10 | import net.minecraft.world.inventory.MenuType; 11 | 12 | import javax.annotation.Nullable; 13 | 14 | public class RetrievalModuleContainer extends AbstractPipeContainer implements IFilteredContainer, IDirectionContainer { 15 | 16 | public ItemFilter filter; 17 | public DirectionSelector directionSelector; 18 | 19 | public RetrievalModuleContainer(@Nullable MenuType type, int id, Player player, BlockPos pos, int moduleIndex) { 20 | super(type, id, player, pos, moduleIndex); 21 | } 22 | 23 | @Override 24 | protected void addSlots() { 25 | this.filter = this.module.getItemFilter(this.moduleStack, this.tile); 26 | this.directionSelector = this.module.getDirectionSelector(this.moduleStack, this.tile); 27 | 28 | for (var slot : this.filter.getSlots((176 - this.module.filterSlots * 18) / 2 + 1, 17 + 32)) 29 | this.addSlot(slot); 30 | } 31 | 32 | @Override 33 | public void removed(Player playerIn) { 34 | super.removed(playerIn); 35 | this.filter.save(); 36 | this.directionSelector.save(); 37 | } 38 | 39 | @Override 40 | public ItemFilter getFilter() { 41 | return this.filter; 42 | } 43 | 44 | @Override 45 | public DirectionSelector getSelector() { 46 | return this.directionSelector; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleGui.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.retrieval; 2 | 3 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeGui; 4 | import net.minecraft.network.chat.Component; 5 | import net.minecraft.world.entity.player.Inventory; 6 | 7 | public class RetrievalModuleGui extends AbstractPipeGui { 8 | 9 | public RetrievalModuleGui(RetrievalModuleContainer screenContainer, Inventory inv, Component titleIn) { 10 | super(screenContainer, inv, titleIn); 11 | } 12 | 13 | @Override 14 | protected void init() { 15 | super.init(); 16 | for (var widget : this.menu.filter.getButtons(this, this.leftPos + this.imageWidth - 7, this.topPos + 17 + 32 + 20, true)) 17 | this.addRenderableWidget(widget); 18 | this.addRenderableWidget(this.menu.directionSelector.getButton(this.leftPos + 7, this.topPos + 17 + 32 + 20)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleItem.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.retrieval; 2 | 3 | import de.ellpeck.prettypipes.Registry; 4 | import de.ellpeck.prettypipes.items.IModule; 5 | import de.ellpeck.prettypipes.items.ModuleItem; 6 | import de.ellpeck.prettypipes.items.ModuleTier; 7 | import de.ellpeck.prettypipes.misc.DirectionSelector; 8 | import de.ellpeck.prettypipes.misc.ItemFilter; 9 | import de.ellpeck.prettypipes.network.PipeNetwork; 10 | import de.ellpeck.prettypipes.pipe.PipeBlockEntity; 11 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; 12 | import net.minecraft.core.Direction; 13 | import net.minecraft.world.entity.player.Inventory; 14 | import net.minecraft.world.entity.player.Player; 15 | import net.minecraft.world.item.ItemStack; 16 | import net.neoforged.neoforge.items.IItemHandler; 17 | 18 | import java.util.Arrays; 19 | 20 | public class RetrievalModuleItem extends ModuleItem { 21 | 22 | private final int maxExtraction; 23 | private final int speed; 24 | private final boolean preventOversending; 25 | public final int filterSlots; 26 | 27 | public RetrievalModuleItem(String name, ModuleTier tier) { 28 | super(name, new Properties()); 29 | this.maxExtraction = tier.forTier(1, 8, 16); 30 | this.speed = tier.forTier(40, 20, 10); 31 | this.filterSlots = tier.forTier(3, 6, 9); 32 | this.preventOversending = tier.forTier(false, true, true); 33 | } 34 | 35 | @Override 36 | public void tick(ItemStack module, PipeBlockEntity tile) { 37 | if (!tile.shouldWorkNow(this.speed) || !tile.canWork()) 38 | return; 39 | var directions = this.getDirectionSelector(module, tile).directions(); 40 | var network = PipeNetwork.get(tile.getLevel()); 41 | var equalityTypes = ItemFilter.getEqualityTypes(tile); 42 | // loop through filters to see which items to pull 43 | Arrays.stream(directions).flatMap(d -> tile.getFilters(d).stream()).distinct().forEach(f -> { 44 | for (var i = 0; i < f.content.getSlots(); i++) { 45 | var filtered = f.content.getStackInSlot(i); 46 | if (filtered.isEmpty()) 47 | continue; 48 | var copy = filtered.copy(); 49 | copy.setCount(this.maxExtraction); 50 | var dest = tile.getAvailableDestination(directions, copy, true, this.preventOversending); 51 | if (dest == null) 52 | continue; 53 | var remain = dest.getRight().copy(); 54 | // are we already waiting for crafting results? If so, don't request those again 55 | remain.shrink(network.getCurrentlyCraftingAmount(tile.getBlockPos(), copy, true, equalityTypes)); 56 | if (network.requestItem(tile.getBlockPos(), dest.getLeft(), remain, equalityTypes).isEmpty()) 57 | break; 58 | } 59 | }); 60 | } 61 | 62 | @Override 63 | public boolean canNetworkSee(ItemStack module, PipeBlockEntity tile, Direction direction, IItemHandler handler) { 64 | return !this.getDirectionSelector(module, tile).has(direction); 65 | } 66 | 67 | @Override 68 | public boolean canAcceptItem(ItemStack module, PipeBlockEntity tile, ItemStack stack, Direction direction, IItemHandler destination) { 69 | return !this.getDirectionSelector(module, tile).has(direction); 70 | } 71 | 72 | @Override 73 | public boolean isCompatible(ItemStack module, PipeBlockEntity tile, IModule other) { 74 | return !(other instanceof RetrievalModuleItem); 75 | } 76 | 77 | @Override 78 | public boolean hasContainer(ItemStack module, PipeBlockEntity tile) { 79 | return true; 80 | } 81 | 82 | @Override 83 | public AbstractPipeContainer getContainer(ItemStack module, PipeBlockEntity tile, int windowId, Inventory inv, Player player, int moduleIndex) { 84 | return new RetrievalModuleContainer(Registry.retrievalModuleContainer, windowId, player, tile.getBlockPos(), moduleIndex); 85 | } 86 | 87 | @Override 88 | public ItemFilter getItemFilter(ItemStack module, PipeBlockEntity tile) { 89 | var filter = new ItemFilter(this.filterSlots, module, tile); 90 | filter.canModifyWhitelist = false; 91 | filter.isWhitelist = true; 92 | return filter; 93 | } 94 | 95 | @Override 96 | public DirectionSelector getDirectionSelector(ItemStack module, PipeBlockEntity tile) { 97 | return new DirectionSelector(module, tile); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/stacksize/StackSizeModuleContainer.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.stacksize; 2 | 3 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; 4 | import net.minecraft.core.BlockPos; 5 | import net.minecraft.world.entity.player.Player; 6 | import net.minecraft.world.inventory.MenuType; 7 | 8 | import javax.annotation.Nullable; 9 | 10 | public class StackSizeModuleContainer extends AbstractPipeContainer { 11 | 12 | public StackSizeModuleContainer(@Nullable MenuType type, int id, Player player, BlockPos pos, int moduleIndex) { 13 | super(type, id, player, pos, moduleIndex); 14 | } 15 | 16 | @Override 17 | protected void addSlots() { 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/stacksize/StackSizeModuleGui.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.stacksize; 2 | 3 | import de.ellpeck.prettypipes.PrettyPipes; 4 | import de.ellpeck.prettypipes.packets.PacketButton; 5 | import de.ellpeck.prettypipes.packets.PacketButton.ButtonResult; 6 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeGui; 7 | import net.minecraft.client.gui.GuiGraphics; 8 | import net.minecraft.client.gui.components.Button; 9 | import net.minecraft.client.gui.components.EditBox; 10 | import net.minecraft.client.resources.language.I18n; 11 | import net.minecraft.network.chat.Component; 12 | import net.minecraft.world.entity.player.Inventory; 13 | 14 | import java.util.List; 15 | import java.util.function.Supplier; 16 | 17 | public class StackSizeModuleGui extends AbstractPipeGui { 18 | 19 | public StackSizeModuleGui(StackSizeModuleContainer screenContainer, Inventory inv, Component titleIn) { 20 | super(screenContainer, inv, titleIn); 21 | } 22 | 23 | @Override 24 | protected void init() { 25 | super.init(); 26 | var textField = this.addRenderableWidget(new EditBox(this.font, this.leftPos + 7, this.topPos + 20 + 32 + 10, 40, 20, Component.translatable("info." + PrettyPipes.ID + ".max_stack_size")) { 27 | @Override 28 | public void insertText(String textToWrite) { 29 | var ret = new StringBuilder(); 30 | for (var c : textToWrite.toCharArray()) { 31 | if (Character.isDigit(c)) 32 | ret.append(c); 33 | } 34 | super.insertText(ret.toString()); 35 | } 36 | 37 | }); 38 | Supplier data = () -> this.menu.moduleStack.getOrDefault(StackSizeModuleItem.Data.TYPE, StackSizeModuleItem.Data.DEFAULT); 39 | textField.setValue(String.valueOf(data.get().maxStackSize())); 40 | textField.setMaxLength(4); 41 | textField.setResponder(s -> { 42 | if (s.isEmpty()) 43 | return; 44 | var amount = Integer.parseInt(s); 45 | PacketButton.sendAndExecute(this.menu.tile.getBlockPos(), ButtonResult.STACK_SIZE_AMOUNT, List.of(amount)); 46 | }); 47 | Supplier buttonText = () -> Component.translatable("info." + PrettyPipes.ID + ".limit_to_max_" + (data.get().limitToMaxStackSize() ? "on" : "off")); 48 | this.addRenderableWidget(Button.builder(buttonText.get(), b -> { 49 | PacketButton.sendAndExecute(this.menu.tile.getBlockPos(), ButtonResult.STACK_SIZE_MODULE_BUTTON, List.of()); 50 | b.setMessage(buttonText.get()); 51 | }).bounds(this.leftPos + 7, this.topPos + 20 + 32 + 10 + 22, 120, 20).build()); 52 | } 53 | 54 | @Override 55 | protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) { 56 | super.renderLabels(graphics, mouseX, mouseY); 57 | graphics.drawString(this.font, I18n.get("info." + PrettyPipes.ID + ".max_stack_size") + ":", 8, 20 + 32, 4210752, false); 58 | 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pipe/modules/stacksize/StackSizeModuleItem.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pipe.modules.stacksize; 2 | 3 | import com.mojang.serialization.Codec; 4 | import com.mojang.serialization.codecs.RecordCodecBuilder; 5 | import de.ellpeck.prettypipes.Registry; 6 | import de.ellpeck.prettypipes.items.IModule; 7 | import de.ellpeck.prettypipes.items.ModuleItem; 8 | import de.ellpeck.prettypipes.misc.ItemEquality; 9 | import de.ellpeck.prettypipes.misc.ItemFilter; 10 | import de.ellpeck.prettypipes.pipe.PipeBlockEntity; 11 | import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; 12 | import net.minecraft.core.component.DataComponentType; 13 | import net.minecraft.world.entity.player.Inventory; 14 | import net.minecraft.world.entity.player.Player; 15 | import net.minecraft.world.item.ItemStack; 16 | import net.neoforged.neoforge.items.IItemHandler; 17 | 18 | public class StackSizeModuleItem extends ModuleItem { 19 | 20 | public StackSizeModuleItem() { 21 | super("stack_size_module", new Properties()); 22 | } 23 | 24 | @Override 25 | public int getMaxInsertionAmount(ItemStack module, PipeBlockEntity tile, ItemStack stack, IItemHandler destination) { 26 | var types = ItemFilter.getEqualityTypes(tile); 27 | var data = module.getOrDefault(Data.TYPE, Data.DEFAULT); 28 | var max = data.maxStackSize; 29 | if (data.limitToMaxStackSize) 30 | max = Math.min(max, stack.getMaxStackSize()); 31 | var amount = 0; 32 | for (var i = 0; i < destination.getSlots(); i++) { 33 | var stored = destination.getStackInSlot(i); 34 | if (stored.isEmpty()) 35 | continue; 36 | if (!ItemEquality.compareItems(stored, stack, types)) 37 | continue; 38 | amount += stored.getCount(); 39 | if (amount >= max) 40 | return 0; 41 | } 42 | return max - amount; 43 | } 44 | 45 | @Override 46 | public boolean isCompatible(ItemStack module, PipeBlockEntity tile, IModule other) { 47 | return !(other instanceof StackSizeModuleItem); 48 | } 49 | 50 | @Override 51 | public boolean hasContainer(ItemStack module, PipeBlockEntity tile) { 52 | return true; 53 | } 54 | 55 | @Override 56 | public AbstractPipeContainer getContainer(ItemStack module, PipeBlockEntity tile, int windowId, Inventory inv, Player player, int moduleIndex) { 57 | return new StackSizeModuleContainer(Registry.stackSizeModuleContainer, windowId, player, tile.getBlockPos(), moduleIndex); 58 | } 59 | 60 | public record Data(int maxStackSize, boolean limitToMaxStackSize) { 61 | 62 | public static final Data DEFAULT = new Data(64, false); 63 | 64 | public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( 65 | Codec.INT.fieldOf("max_stack_size").forGetter(f -> f.maxStackSize), 66 | Codec.BOOL.fieldOf("limit_to_max_stack_size").forGetter(f -> f.limitToMaxStackSize) 67 | ).apply(i, StackSizeModuleItem.Data::new)); 68 | public static final DataComponentType TYPE = DataComponentType.builder().persistent(StackSizeModuleItem.Data.CODEC).cacheEncoding().build(); 69 | 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pressurizer/PressurizerBlock.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pressurizer; 2 | 3 | import com.mojang.serialization.MapCodec; 4 | import de.ellpeck.prettypipes.Registry; 5 | import de.ellpeck.prettypipes.Utility; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.core.registries.BuiltInRegistries; 8 | import net.minecraft.network.chat.Component; 9 | import net.minecraft.world.InteractionResult; 10 | import net.minecraft.world.entity.player.Player; 11 | import net.minecraft.world.item.Item; 12 | import net.minecraft.world.item.ItemStack; 13 | import net.minecraft.world.item.TooltipFlag; 14 | import net.minecraft.world.level.Level; 15 | import net.minecraft.world.level.block.BaseEntityBlock; 16 | import net.minecraft.world.level.block.RenderShape; 17 | import net.minecraft.world.level.block.entity.BlockEntity; 18 | import net.minecraft.world.level.block.entity.BlockEntityTicker; 19 | import net.minecraft.world.level.block.entity.BlockEntityType; 20 | import net.minecraft.world.level.block.state.BlockBehaviour; 21 | import net.minecraft.world.level.block.state.BlockState; 22 | import net.minecraft.world.phys.BlockHitResult; 23 | 24 | import java.util.List; 25 | 26 | public class PressurizerBlock extends BaseEntityBlock { 27 | 28 | public static final MapCodec CODEC = BlockBehaviour.simpleCodec(PressurizerBlock::new); 29 | 30 | public PressurizerBlock(Properties properties) { 31 | super(properties); 32 | } 33 | 34 | @Override 35 | protected MapCodec codec() { 36 | return PressurizerBlock.CODEC; 37 | } 38 | 39 | @Override 40 | public InteractionResult useWithoutItem(BlockState state, Level worldIn, BlockPos pos, Player player, BlockHitResult result) { 41 | var tile = Utility.getBlockEntity(PressurizerBlockEntity.class, worldIn, pos); 42 | if (tile == null) 43 | return InteractionResult.PASS; 44 | if (!worldIn.isClientSide) 45 | player.openMenu(tile, pos); 46 | return InteractionResult.SUCCESS; 47 | } 48 | 49 | @org.jetbrains.annotations.Nullable 50 | @Override 51 | public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { 52 | return new PressurizerBlockEntity(pos, state); 53 | } 54 | 55 | @Override 56 | public RenderShape getRenderShape(BlockState state) { 57 | return RenderShape.MODEL; 58 | } 59 | 60 | @Override 61 | public void appendHoverText(ItemStack pStack, Item.TooltipContext pContext, List pTooltipComponents, TooltipFlag pTooltipFlag) { 62 | Utility.addTooltip(BuiltInRegistries.BLOCK.getKey(this).getPath(), pTooltipComponents); 63 | } 64 | 65 | @org.jetbrains.annotations.Nullable 66 | @Override 67 | public BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType type) { 68 | return level.isClientSide ? null : BaseEntityBlock.createTickerHelper(type, Registry.pressurizerBlockEntity, PressurizerBlockEntity::tick); 69 | } 70 | 71 | @Override 72 | public boolean hasAnalogOutputSignal(BlockState state) { 73 | return true; 74 | } 75 | 76 | @Override 77 | public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) { 78 | var pipe = Utility.getBlockEntity(PressurizerBlockEntity.class, world, pos); 79 | if (pipe == null) 80 | return 0; 81 | return (int) (pipe.getEnergy() / (float) pipe.getMaxEnergy() * 15); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pressurizer/PressurizerContainer.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pressurizer; 2 | 3 | import de.ellpeck.prettypipes.Utility; 4 | import net.minecraft.core.BlockPos; 5 | import net.minecraft.world.entity.player.Player; 6 | import net.minecraft.world.inventory.AbstractContainerMenu; 7 | import net.minecraft.world.inventory.MenuType; 8 | import net.minecraft.world.inventory.Slot; 9 | import net.minecraft.world.item.ItemStack; 10 | 11 | import javax.annotation.Nullable; 12 | 13 | public class PressurizerContainer extends AbstractContainerMenu { 14 | 15 | public final PressurizerBlockEntity tile; 16 | 17 | public PressurizerContainer(@Nullable MenuType type, int id, Player player, BlockPos pos) { 18 | super(type, id); 19 | this.tile = Utility.getBlockEntity(PressurizerBlockEntity.class, player.level(), pos); 20 | 21 | for (var l = 0; l < 3; ++l) 22 | for (var j1 = 0; j1 < 9; ++j1) 23 | this.addSlot(new Slot(player.getInventory(), j1 + l * 9 + 9, 8 + j1 * 18, 55 + l * 18)); 24 | for (var i1 = 0; i1 < 9; ++i1) 25 | this.addSlot(new Slot(player.getInventory(), i1, 8 + i1 * 18, 113)); 26 | } 27 | 28 | @Override 29 | public ItemStack quickMoveStack(Player player, int slotIndex) { 30 | return Utility.transferStackInSlot(this, this::moveItemStackTo, player, slotIndex, stack -> null); 31 | } 32 | 33 | @Override 34 | public boolean stillValid(Player player) { 35 | return true; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/pressurizer/PressurizerGui.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.pressurizer; 2 | 3 | import de.ellpeck.prettypipes.PrettyPipes; 4 | import net.minecraft.client.gui.GuiGraphics; 5 | import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; 6 | import net.minecraft.network.chat.Component; 7 | import net.minecraft.resources.ResourceLocation; 8 | import net.minecraft.world.entity.player.Inventory; 9 | 10 | public class PressurizerGui extends AbstractContainerScreen { 11 | 12 | private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(PrettyPipes.ID, "textures/gui/pressurizer.png"); 13 | 14 | public PressurizerGui(PressurizerContainer screenContainer, Inventory inv, Component titleIn) { 15 | super(screenContainer, inv, titleIn); 16 | this.imageWidth = 176; 17 | this.imageHeight = 137; 18 | } 19 | 20 | @Override 21 | public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { 22 | super.render(graphics, mouseX, mouseY, partialTicks); 23 | this.renderTooltip(graphics, mouseX, mouseY); 24 | if (mouseX >= this.leftPos + 26 && mouseY >= this.topPos + 22 && mouseX < this.leftPos + 26 + 124 && mouseY < this.topPos + 22 + 12) 25 | graphics.renderTooltip(this.font, Component.translatable("info." + PrettyPipes.ID + ".energy", this.menu.tile.getEnergy(), this.menu.tile.getMaxEnergy()), mouseX, mouseY); 26 | } 27 | 28 | @Override 29 | protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) { 30 | graphics.drawString(this.font, this.playerInventoryTitle.getString(), 8, this.imageHeight - 96 + 2, 4210752, false); 31 | graphics.drawString(this.font, this.title.getString(), 8, 6, 4210752, false); 32 | } 33 | 34 | @Override 35 | protected void renderBg(GuiGraphics graphics, float partialTicks, int x, int y) { 36 | graphics.blit(PressurizerGui.TEXTURE, this.leftPos, this.topPos, 0, 0, 176, 137); 37 | var energy = (int) (this.menu.tile.getEnergyPercentage() * 124); 38 | graphics.blit(PressurizerGui.TEXTURE, this.leftPos + 26, this.topPos + 22, 0, 137, energy, 12); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/terminal/CraftingTerminalBlock.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.terminal; 2 | 3 | import com.mojang.serialization.MapCodec; 4 | import de.ellpeck.prettypipes.Registry; 5 | import net.minecraft.core.BlockPos; 6 | import net.minecraft.world.level.Level; 7 | import net.minecraft.world.level.block.BaseEntityBlock; 8 | import net.minecraft.world.level.block.entity.BlockEntity; 9 | import net.minecraft.world.level.block.entity.BlockEntityTicker; 10 | import net.minecraft.world.level.block.entity.BlockEntityType; 11 | import net.minecraft.world.level.block.state.BlockBehaviour; 12 | import net.minecraft.world.level.block.state.BlockState; 13 | 14 | public class CraftingTerminalBlock extends ItemTerminalBlock { 15 | 16 | public static final MapCodec CODEC = BlockBehaviour.simpleCodec(CraftingTerminalBlock::new); 17 | 18 | public CraftingTerminalBlock(Properties properties) { 19 | super(properties); 20 | } 21 | 22 | @Override 23 | protected MapCodec codec() { 24 | return CraftingTerminalBlock.CODEC; 25 | } 26 | 27 | @Override 28 | public @org.jetbrains.annotations.Nullable BlockEntity newBlockEntity(BlockPos pos, BlockState state) { 29 | return new CraftingTerminalBlockEntity(pos, state); 30 | } 31 | 32 | @org.jetbrains.annotations.Nullable 33 | @Override 34 | public BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType type) { 35 | return BaseEntityBlock.createTickerHelper(type, Registry.craftingTerminalBlockEntity, ItemTerminalBlockEntity::tick); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalBlock.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.terminal; 2 | 3 | import com.mojang.serialization.MapCodec; 4 | import de.ellpeck.prettypipes.Registry; 5 | import de.ellpeck.prettypipes.Utility; 6 | import net.minecraft.ChatFormatting; 7 | import net.minecraft.core.BlockPos; 8 | import net.minecraft.core.registries.BuiltInRegistries; 9 | import net.minecraft.network.chat.Component; 10 | import net.minecraft.world.InteractionResult; 11 | import net.minecraft.world.entity.player.Player; 12 | import net.minecraft.world.item.Item; 13 | import net.minecraft.world.item.ItemStack; 14 | import net.minecraft.world.item.TooltipFlag; 15 | import net.minecraft.world.level.Level; 16 | import net.minecraft.world.level.block.BaseEntityBlock; 17 | import net.minecraft.world.level.block.RenderShape; 18 | import net.minecraft.world.level.block.entity.BlockEntity; 19 | import net.minecraft.world.level.block.entity.BlockEntityTicker; 20 | import net.minecraft.world.level.block.entity.BlockEntityType; 21 | import net.minecraft.world.level.block.state.BlockBehaviour; 22 | import net.minecraft.world.level.block.state.BlockState; 23 | import net.minecraft.world.phys.BlockHitResult; 24 | 25 | import java.util.List; 26 | 27 | public class ItemTerminalBlock extends BaseEntityBlock { 28 | 29 | public static final MapCodec CODEC = BlockBehaviour.simpleCodec(ItemTerminalBlock::new); 30 | 31 | public ItemTerminalBlock(Properties properties) { 32 | super(properties); 33 | } 34 | 35 | @Override 36 | protected MapCodec codec() { 37 | return ItemTerminalBlock.CODEC; 38 | } 39 | 40 | @Override 41 | protected InteractionResult useWithoutItem(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, BlockHitResult pHitResult) { 42 | var tile = Utility.getBlockEntity(ItemTerminalBlockEntity.class, pLevel, pPos); 43 | if (tile == null) 44 | return InteractionResult.PASS; 45 | var reason = tile.getInvalidTerminalReason(); 46 | if (reason != null) { 47 | if (!pLevel.isClientSide) 48 | pPlayer.sendSystemMessage(Component.translatable(reason).withStyle(ChatFormatting.RED)); 49 | return InteractionResult.SUCCESS; 50 | } 51 | if (!pLevel.isClientSide) { 52 | pPlayer.openMenu(tile, pPos); 53 | tile.updateItems(pPlayer); 54 | } 55 | return InteractionResult.SUCCESS; 56 | } 57 | 58 | @Override 59 | public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { 60 | if (state.getBlock() != newState.getBlock()) { 61 | var tile = Utility.getBlockEntity(ItemTerminalBlockEntity.class, worldIn, pos); 62 | if (tile != null) 63 | Utility.dropInventory(tile, tile.items); 64 | super.onRemove(state, worldIn, pos, newState, isMoving); 65 | } 66 | } 67 | 68 | @org.jetbrains.annotations.Nullable 69 | @Override 70 | public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { 71 | return new ItemTerminalBlockEntity(pos, state); 72 | } 73 | 74 | @Override 75 | public RenderShape getRenderShape(BlockState state) { 76 | return RenderShape.MODEL; 77 | } 78 | 79 | @Override 80 | public void appendHoverText(ItemStack pStack, Item.TooltipContext pContext, List pTooltipComponents, TooltipFlag pTooltipFlag) { 81 | Utility.addTooltip(BuiltInRegistries.BLOCK.getKey(this).getPath(), pTooltipComponents); 82 | } 83 | 84 | @org.jetbrains.annotations.Nullable 85 | @Override 86 | public BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType type) { 87 | return BaseEntityBlock.createTickerHelper(type, Registry.itemTerminalBlockEntity, ItemTerminalBlockEntity::tick); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/terminal/containers/CraftingTerminalGui.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.terminal.containers; 2 | 3 | import com.mojang.blaze3d.platform.InputConstants; 4 | import de.ellpeck.prettypipes.PrettyPipes; 5 | import de.ellpeck.prettypipes.packets.PacketButton; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import net.minecraft.client.gui.components.Button; 8 | import net.minecraft.client.gui.components.Tooltip; 9 | import net.minecraft.client.gui.screens.Screen; 10 | import net.minecraft.network.chat.Component; 11 | import net.minecraft.resources.ResourceLocation; 12 | import net.minecraft.world.entity.player.Inventory; 13 | import net.neoforged.neoforge.network.PacketDistributor; 14 | 15 | import java.util.Arrays; 16 | import java.util.List; 17 | 18 | public class CraftingTerminalGui extends ItemTerminalGui { 19 | 20 | private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(PrettyPipes.ID, "textures/gui/crafting_terminal.png"); 21 | private Button requestButton; 22 | private Button sendBackButton; 23 | 24 | public CraftingTerminalGui(ItemTerminalContainer screenContainer, Inventory inv, Component titleIn) { 25 | super(screenContainer, inv, titleIn); 26 | this.imageWidth = 256; 27 | } 28 | 29 | @Override 30 | protected void init() { 31 | super.init(); 32 | this.requestButton = this.addRenderableWidget(Button.builder(Component.translatable("info." + PrettyPipes.ID + ".request"), button -> { 33 | var amount = ItemTerminalGui.requestModifier(); 34 | // also allow holding backspace instead of alt for people whose alt key is inaccessible (linux?) 35 | var force = Screen.hasAltDown() || InputConstants.isKeyDown(this.minecraft.getWindow().getWindow(), 259) ? 1 : 0; 36 | PacketDistributor.sendToServer(new PacketButton(this.menu.tile.getBlockPos(), PacketButton.ButtonResult.CRAFT_TERMINAL_REQUEST, Arrays.asList(amount, force))); 37 | }).bounds(this.leftPos + 8, this.topPos + 100, 50, 20).build()); 38 | this.sendBackButton = this.addRenderableWidget(Button.builder(Component.literal(">"), button -> { 39 | PacketDistributor.sendToServer(new PacketButton(this.menu.tile.getBlockPos(), PacketButton.ButtonResult.CRAFT_TERMINAL_SEND_BACK, List.of())); 40 | }).bounds(this.leftPos + 47, this.topPos + 72, 12, 12).build()); 41 | this.tick(); 42 | } 43 | 44 | @Override 45 | public void containerTick() { 46 | super.containerTick(); 47 | var tile = this.getCraftingContainer().getTile(); 48 | this.requestButton.active = false; 49 | this.sendBackButton.active = false; 50 | for (var i = 0; i < tile.craftItems.getSlots(); i++) { 51 | var requestStack = tile.getRequestedCraftItem(i); 52 | if (!requestStack.isEmpty() && requestStack.getCount() < requestStack.getMaxStackSize()) 53 | this.requestButton.active = true; 54 | var realStack = tile.craftItems.getStackInSlot(i); 55 | if (!realStack.isEmpty()) 56 | this.sendBackButton.active = true; 57 | } 58 | } 59 | 60 | @Override 61 | protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) { 62 | super.renderLabels(graphics, mouseX, mouseY); 63 | 64 | var container = this.getCraftingContainer(); 65 | var tile = container.getTile(); 66 | for (var i = 0; i < tile.ghostItems.getSlots(); i++) { 67 | if (!tile.craftItems.getStackInSlot(i).isEmpty()) 68 | continue; 69 | var ghost = tile.ghostItems.getStackInSlot(i); 70 | if (ghost.isEmpty()) 71 | continue; 72 | var finalI = i; 73 | var slot = container.slots.stream().filter(s -> s.container == container.craftInventory && s.getSlotIndex() == finalI).findFirst().orElse(null); 74 | if (slot == null) 75 | continue; 76 | graphics.renderItem(ghost, slot.x, slot.y); 77 | graphics.renderItemDecorations(this.font, ghost, slot.x, slot.y, "0"); 78 | } 79 | } 80 | 81 | @Override 82 | protected ResourceLocation getTexture() { 83 | return CraftingTerminalGui.TEXTURE; 84 | } 85 | 86 | @Override 87 | protected int getXOffset() { 88 | return 65; 89 | } 90 | 91 | protected CraftingTerminalContainer getCraftingContainer() { 92 | return (CraftingTerminalContainer) this.menu; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/terminal/containers/ItemTerminalContainer.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.terminal.containers; 2 | 3 | import de.ellpeck.prettypipes.Utility; 4 | import de.ellpeck.prettypipes.terminal.ItemTerminalBlockEntity; 5 | import net.minecraft.core.BlockPos; 6 | import net.minecraft.world.entity.player.Player; 7 | import net.minecraft.world.inventory.AbstractContainerMenu; 8 | import net.minecraft.world.inventory.MenuType; 9 | import net.minecraft.world.inventory.Slot; 10 | import net.minecraft.world.item.ItemStack; 11 | import net.neoforged.neoforge.items.SlotItemHandler; 12 | import org.apache.commons.lang3.tuple.Pair; 13 | 14 | import javax.annotation.Nullable; 15 | 16 | public class ItemTerminalContainer extends AbstractContainerMenu { 17 | 18 | public final ItemTerminalBlockEntity tile; 19 | 20 | public ItemTerminalContainer(@Nullable MenuType type, int id, Player player, BlockPos pos) { 21 | super(type, id); 22 | this.tile = Utility.getBlockEntity(ItemTerminalBlockEntity.class, player.level(), pos); 23 | 24 | this.addOwnSlots(player); 25 | 26 | var off = this.getSlotXOffset(); 27 | for (var l = 0; l < 3; ++l) 28 | for (var j1 = 0; j1 < 9; ++j1) 29 | this.addSlot(new Slot(player.getInventory(), j1 + l * 9 + 9, 8 + off + j1 * 18, 154 + l * 18)); 30 | for (var i1 = 0; i1 < 9; ++i1) 31 | this.addSlot(new Slot(player.getInventory(), i1, 8 + off + i1 * 18, 212)); 32 | } 33 | 34 | protected void addOwnSlots(Player player) { 35 | var off = this.getSlotXOffset(); 36 | for (var i = 0; i < 6; i++) 37 | this.addSlot(new SlotItemHandler(this.tile.items, i, 8 + off + i % 3 * 18, 102 + i / 3 * 18)); 38 | for (var i = 0; i < 6; i++) 39 | this.addSlot(new SlotItemHandler(this.tile.items, i + 6, 116 + off + i % 3 * 18, 102 + i / 3 * 18)); 40 | } 41 | 42 | protected int getSlotXOffset() { 43 | return 0; 44 | } 45 | 46 | @Override 47 | public ItemStack quickMoveStack(Player player, int slotIndex) { 48 | return Utility.transferStackInSlot(this, this::moveItemStackTo, player, slotIndex, stack -> Pair.of(6, 12)); 49 | } 50 | 51 | @Override 52 | public boolean stillValid(Player player) { 53 | return true; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/de/ellpeck/prettypipes/terminal/containers/WrappedCraftingInventory.java: -------------------------------------------------------------------------------- 1 | package de.ellpeck.prettypipes.terminal.containers; 2 | 3 | import net.minecraft.world.entity.player.Player; 4 | import net.minecraft.world.entity.player.StackedContents; 5 | import net.minecraft.world.inventory.CraftingContainer; 6 | import net.minecraft.world.item.ItemStack; 7 | import net.neoforged.neoforge.items.ItemStackHandler; 8 | 9 | import java.util.List; 10 | import java.util.stream.IntStream; 11 | 12 | public class WrappedCraftingInventory implements CraftingContainer { 13 | 14 | private final ItemStackHandler items; 15 | private final CraftingTerminalContainer eventHandler; 16 | 17 | public WrappedCraftingInventory(ItemStackHandler items, CraftingTerminalContainer eventHandlerIn) { 18 | this.eventHandler = eventHandlerIn; 19 | this.items = items; 20 | } 21 | 22 | @Override 23 | public int getContainerSize() { 24 | return this.items.getSlots(); 25 | } 26 | 27 | @Override 28 | public boolean isEmpty() { 29 | for (var i = 0; i < this.items.getSlots(); i++) { 30 | if (!this.items.getStackInSlot(i).isEmpty()) 31 | return false; 32 | } 33 | return true; 34 | } 35 | 36 | @Override 37 | public ItemStack getItem(int index) { 38 | return this.items.getStackInSlot(index); 39 | } 40 | 41 | @Override 42 | public ItemStack removeItemNoUpdate(int index) { 43 | var before = this.items.getStackInSlot(index); 44 | this.items.setStackInSlot(index, ItemStack.EMPTY); 45 | return before; 46 | } 47 | 48 | @Override 49 | public ItemStack removeItem(int index, int count) { 50 | var slotStack = this.items.getStackInSlot(index); 51 | var ret = !slotStack.isEmpty() && count > 0 ? slotStack.split(count) : ItemStack.EMPTY; 52 | if (!ret.isEmpty()) { 53 | this.eventHandler.slotsChanged(this); 54 | } 55 | return ret; 56 | } 57 | 58 | @Override 59 | public void setItem(int index, ItemStack stack) { 60 | this.items.setStackInSlot(index, stack); 61 | this.eventHandler.slotsChanged(this); 62 | } 63 | 64 | @Override 65 | public void setChanged() { 66 | this.eventHandler.slotsChanged(this); 67 | } 68 | 69 | @Override 70 | public boolean stillValid(Player player) { 71 | return true; 72 | } 73 | 74 | @Override 75 | public void clearContent() { 76 | for (var i = 0; i < this.items.getSlots(); i++) 77 | this.items.setStackInSlot(i, ItemStack.EMPTY); 78 | } 79 | 80 | @Override 81 | public void fillStackedContents(StackedContents helper) { 82 | for (var i = 0; i < this.items.getSlots(); i++) 83 | helper.accountStack(this.items.getStackInSlot(i)); 84 | } 85 | 86 | @Override 87 | public int getWidth() { 88 | return 3; 89 | } 90 | 91 | @Override 92 | public int getHeight() { 93 | return 3; 94 | } 95 | 96 | @Override 97 | public List getItems() { 98 | return IntStream.range(0, this.getContainerSize()).mapToObj(this::getItem).toList(); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/blockstates/crafting_terminal.json: -------------------------------------------------------------------------------- 1 | { 2 | "variants": { 3 | "": { 4 | "model": "prettypipes:block/crafting_terminal" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/blockstates/item_terminal.json: -------------------------------------------------------------------------------- 1 | { 2 | "variants": { 3 | "": { 4 | "model": "prettypipes:block/item_terminal" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/blockstates/pipe.json: -------------------------------------------------------------------------------- 1 | { 2 | "multipart": [ 3 | { 4 | "apply": { 5 | "model": "prettypipes:block/pipe_center" 6 | } 7 | }, 8 | { 9 | "when": { 10 | "north": "connected" 11 | }, 12 | "apply": { 13 | "model": "prettypipes:block/pipe_end" 14 | } 15 | }, 16 | { 17 | "when": { 18 | "south": "connected" 19 | }, 20 | "apply": { 21 | "model": "prettypipes:block/pipe_end", 22 | "y": 180 23 | } 24 | }, 25 | { 26 | "when": { 27 | "east": "connected" 28 | }, 29 | "apply": { 30 | "model": "prettypipes:block/pipe_end", 31 | "y": 90 32 | } 33 | }, 34 | { 35 | "when": { 36 | "west": "connected" 37 | }, 38 | "apply": { 39 | "model": "prettypipes:block/pipe_end", 40 | "y": 270 41 | } 42 | }, 43 | { 44 | "when": { 45 | "down": "connected" 46 | }, 47 | "apply": { 48 | "model": "prettypipes:block/pipe_end", 49 | "x": 90 50 | } 51 | }, 52 | { 53 | "when": { 54 | "up": "connected" 55 | }, 56 | "apply": { 57 | "model": "prettypipes:block/pipe_end", 58 | "x": 270 59 | } 60 | }, 61 | { 62 | "when": { 63 | "north": "legs" 64 | }, 65 | "apply": { 66 | "model": "prettypipes:block/pipe_legs", 67 | "x": 90, 68 | "y": 180 69 | } 70 | }, 71 | { 72 | "when": { 73 | "south": "legs" 74 | }, 75 | "apply": { 76 | "model": "prettypipes:block/pipe_legs", 77 | "x": 90 78 | } 79 | }, 80 | { 81 | "when": { 82 | "east": "legs" 83 | }, 84 | "apply": { 85 | "model": "prettypipes:block/pipe_legs", 86 | "x": 90, 87 | "y": 270 88 | } 89 | }, 90 | { 91 | "when": { 92 | "west": "legs" 93 | }, 94 | "apply": { 95 | "model": "prettypipes:block/pipe_legs", 96 | "x": 90, 97 | "y": 90 98 | } 99 | }, 100 | { 101 | "when": { 102 | "down": "legs" 103 | }, 104 | "apply": { 105 | "model": "prettypipes:block/pipe_legs" 106 | } 107 | }, 108 | { 109 | "when": { 110 | "up": "legs" 111 | }, 112 | "apply": { 113 | "model": "prettypipes:block/pipe_legs", 114 | "x": 180 115 | } 116 | } 117 | ] 118 | } -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/blockstates/pressurizer.json: -------------------------------------------------------------------------------- 1 | { 2 | "variants": { 3 | "": { 4 | "model": "prettypipes:block/pressurizer" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/block/crafting_terminal.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "block/cube_column", 3 | "textures": { 4 | "end": "prettypipes:block/item_terminal_top", 5 | "side": "prettypipes:block/crafting_terminal" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/block/item_terminal.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "block/cube_column", 3 | "textures": { 4 | "end": "prettypipes:block/item_terminal_top", 5 | "side": "prettypipes:block/item_terminal" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/block/pipe_end.json: -------------------------------------------------------------------------------- 1 | { 2 | "credit": "Made with Blockbench", 3 | "render_type": "cutout", 4 | "textures": { 5 | "0": "prettypipes:block/pipe", 6 | "particle": "prettypipes:block/pipe" 7 | }, 8 | "elements": [ 9 | { 10 | "from": [5, 10, 0], 11 | "to": [6, 11, 5], 12 | "faces": { 13 | "north": { 14 | "uv": [0, 0, 1, 1], 15 | "texture": "#0" 16 | }, 17 | "east": { 18 | "uv": [0, 0, 5, 1], 19 | "texture": "#0" 20 | }, 21 | "south": { 22 | "uv": [0, 0, 1, 1], 23 | "texture": "#0" 24 | }, 25 | "west": { 26 | "uv": [0, 0, 5, 1], 27 | "texture": "#0" 28 | }, 29 | "up": { 30 | "uv": [0, 0, 5, 1], 31 | "rotation": 90, 32 | "texture": "#0" 33 | }, 34 | "down": { 35 | "uv": [0, 0, 5, 1], 36 | "rotation": 270, 37 | "texture": "#0" 38 | } 39 | } 40 | }, 41 | { 42 | "from": [5, 5, 0], 43 | "to": [6, 6, 5], 44 | "faces": { 45 | "north": { 46 | "uv": [0, 0, 1, 1], 47 | "texture": "#0" 48 | }, 49 | "east": { 50 | "uv": [0, 0, 5, 1], 51 | "texture": "#0" 52 | }, 53 | "south": { 54 | "uv": [0, 0, 1, 1], 55 | "texture": "#0" 56 | }, 57 | "west": { 58 | "uv": [0, 0, 5, 1], 59 | "texture": "#0" 60 | }, 61 | "up": { 62 | "uv": [0, 0, 5, 1], 63 | "rotation": 90, 64 | "texture": "#0" 65 | }, 66 | "down": { 67 | "uv": [0, 0, 5, 1], 68 | "rotation": 270, 69 | "texture": "#0" 70 | } 71 | } 72 | }, 73 | { 74 | "from": [10, 5, 0], 75 | "to": [11, 6, 5], 76 | "faces": { 77 | "north": { 78 | "uv": [0, 0, 1, 1], 79 | "texture": "#0" 80 | }, 81 | "east": { 82 | "uv": [0, 0, 5, 1], 83 | "texture": "#0" 84 | }, 85 | "south": { 86 | "uv": [0, 0, 1, 1], 87 | "texture": "#0" 88 | }, 89 | "west": { 90 | "uv": [0, 0, 5, 1], 91 | "texture": "#0" 92 | }, 93 | "up": { 94 | "uv": [0, 0, 5, 1], 95 | "rotation": 90, 96 | "texture": "#0" 97 | }, 98 | "down": { 99 | "uv": [0, 0, 5, 1], 100 | "rotation": 270, 101 | "texture": "#0" 102 | } 103 | } 104 | }, 105 | { 106 | "from": [10, 10, 0], 107 | "to": [11, 11, 5], 108 | "faces": { 109 | "north": { 110 | "uv": [0, 0, 1, 1], 111 | "texture": "#0" 112 | }, 113 | "east": { 114 | "uv": [0, 0, 5, 1], 115 | "texture": "#0" 116 | }, 117 | "south": { 118 | "uv": [0, 0, 1, 1], 119 | "texture": "#0" 120 | }, 121 | "west": { 122 | "uv": [0, 0, 5, 1], 123 | "texture": "#0" 124 | }, 125 | "up": { 126 | "uv": [0, 0, 5, 1], 127 | "rotation": 90, 128 | "texture": "#0" 129 | }, 130 | "down": { 131 | "uv": [0, 0, 5, 1], 132 | "rotation": 270, 133 | "texture": "#0" 134 | } 135 | } 136 | } 137 | ] 138 | } -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/block/pipe_legs.json: -------------------------------------------------------------------------------- 1 | { 2 | "credit": "Made with Blockbench", 3 | "parent": "block/block", 4 | "render_type": "cutout", 5 | "textures": { 6 | "1": "prettypipes:block/pipe_legs", 7 | "particle": "prettypipes:block/pipe" 8 | }, 9 | "elements": [ 10 | { 11 | "from": [6, 4, 6], 12 | "to": [10, 5, 10], 13 | "faces": { 14 | "north": { 15 | "uv": [0, 7, 4, 8], 16 | "texture": "#1" 17 | }, 18 | "east": { 19 | "uv": [0, 7, 4, 8], 20 | "texture": "#1" 21 | }, 22 | "south": { 23 | "uv": [0, 7, 4, 8], 24 | "texture": "#1" 25 | }, 26 | "west": { 27 | "uv": [0, 7, 4, 8], 28 | "texture": "#1" 29 | }, 30 | "up": { 31 | "uv": [1, 1, 5, 5], 32 | "texture": "#1" 33 | }, 34 | "down": { 35 | "uv": [1, 1, 5, 5], 36 | "texture": "#1" 37 | } 38 | } 39 | }, 40 | { 41 | "from": [7, 0, 7], 42 | "to": [9, 4, 9], 43 | "faces": { 44 | "north": { 45 | "uv": [1, 1, 3, 5], 46 | "texture": "#1" 47 | }, 48 | "east": { 49 | "uv": [1, 1, 3, 5], 50 | "texture": "#1" 51 | }, 52 | "south": { 53 | "uv": [1, 1, 3, 5], 54 | "texture": "#1" 55 | }, 56 | "west": { 57 | "uv": [1, 1, 3, 5], 58 | "texture": "#1" 59 | }, 60 | "down": { 61 | "uv": [1, 1, 3, 3], 62 | "texture": "#1" 63 | } 64 | } 65 | } 66 | ] 67 | } -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/block/pressurizer.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "block/cube_column", 3 | "textures": { 4 | "end": "prettypipes:block/pressurizer", 5 | "side": "prettypipes:block/pressurizer" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/blank_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/blank_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/crafting_terminal.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "prettypipes:block/crafting_terminal" 3 | } -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/damage_filter_modifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/damage_filter_modifier" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/filter_increase_modifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/filter_increase_modifier" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/high_crafting_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/high_crafting_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/high_extraction_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/high_extraction_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/high_filter_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/high_filter_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/high_high_priority_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/high_high_priority_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/high_low_priority_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/high_low_priority_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/high_retrieval_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/high_retrieval_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/high_speed_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/high_speed_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/item_terminal.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "prettypipes:block/item_terminal" 3 | } -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/low_crafting_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/low_crafting_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/low_extraction_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/low_extraction_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/low_filter_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/low_filter_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/low_high_priority_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/low_high_priority_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/low_low_priority_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/low_low_priority_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/low_retrieval_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/low_retrieval_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/low_speed_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/low_speed_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/medium_crafting_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/medium_crafting_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/medium_extraction_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/medium_extraction_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/medium_filter_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/medium_filter_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/medium_high_priority_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/medium_high_priority_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/medium_low_priority_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/medium_low_priority_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/medium_retrieval_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/medium_retrieval_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/medium_speed_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/medium_speed_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/mod_filter_modifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/mod_filter_modifier" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/nbt_filter_modifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/nbt_filter_modifier" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/pipe.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "prettypipes:block/pipe_center" 3 | } -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/pipe_frame.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/pipe_frame" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/pressurizer.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "prettypipes:block/pressurizer" 3 | } -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/random_sorting_modifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/random_sorting_modifier" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/redstone_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/redstone_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/round_robin_sorting_modifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/round_robin_sorting_modifier" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/stack_size_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/stack_size_module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/tag_filter_modifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "prettypipes:item/tag_filter_modifier" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/models/item/wrench.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/handheld", 3 | "textures": { 4 | "layer0": "prettypipes:item/wrench" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/block/crafting_terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/block/crafting_terminal.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/block/item_terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/block/item_terminal.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/block/item_terminal_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/block/item_terminal_top.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/block/pipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/block/pipe.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/block/pipe_legs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/block/pipe_legs.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/block/pressurizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/block/pressurizer.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/gui/crafting_terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/gui/crafting_terminal.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/gui/item_terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/gui/item_terminal.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/gui/pipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/gui/pipe.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/gui/pressurizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/gui/pressurizer.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/blank_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/blank_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/damage_filter_modifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/damage_filter_modifier.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/filter_increase_modifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/filter_increase_modifier.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/high_crafting_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/high_crafting_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/high_extraction_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/high_extraction_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/high_filter_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/high_filter_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/high_high_priority_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/high_high_priority_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/high_low_priority_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/high_low_priority_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/high_retrieval_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/high_retrieval_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/high_speed_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/high_speed_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/low_crafting_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/low_crafting_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/low_extraction_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/low_extraction_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/low_filter_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/low_filter_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/low_high_priority_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/low_high_priority_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/low_low_priority_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/low_low_priority_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/low_retrieval_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/low_retrieval_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/low_speed_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/low_speed_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/medium_crafting_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/medium_crafting_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/medium_extraction_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/medium_extraction_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/medium_filter_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/medium_filter_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/medium_high_priority_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/medium_high_priority_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/medium_low_priority_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/medium_low_priority_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/medium_retrieval_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/medium_retrieval_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/medium_speed_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/medium_speed_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/mod_filter_modifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/mod_filter_modifier.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/nbt_filter_modifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/nbt_filter_modifier.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/pipe_frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/pipe_frame.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/random_sorting_modifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/random_sorting_modifier.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/redstone_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/redstone_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/round_robin_sorting_modifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/round_robin_sorting_modifier.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/stack_size_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/stack_size_module.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/tag_filter_modifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/tag_filter_modifier.png -------------------------------------------------------------------------------- /src/main/resources/assets/prettypipes/textures/item/wrench.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/PrettyPipes/208667d6fc34124f257474864a54e1f8e8d7234e/src/main/resources/assets/prettypipes/textures/item/wrench.png -------------------------------------------------------------------------------- /src/main/resources/data/minecraft/tags/block/mineable/pickaxe.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": [ 3 | "prettypipes:pipe", 4 | "prettypipes:item_terminal", 5 | "prettypipes:crafting_terminal", 6 | "prettypipes:pressurizer" 7 | ] 8 | } -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/loot_table/blocks/crafting_terminal.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:block", 3 | "pools": [ 4 | { 5 | "rolls": 1, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "name": "prettypipes:crafting_terminal" 10 | } 11 | ], 12 | "conditions": [ 13 | { 14 | "condition": "minecraft:survives_explosion" 15 | } 16 | ] 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/loot_table/blocks/item_terminal.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:block", 3 | "pools": [ 4 | { 5 | "rolls": 1, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "name": "prettypipes:item_terminal" 10 | } 11 | ], 12 | "conditions": [ 13 | { 14 | "condition": "minecraft:survives_explosion" 15 | } 16 | ] 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/loot_table/blocks/pipe.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:block", 3 | "pools": [ 4 | { 5 | "rolls": 1, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "name": "prettypipes:pipe" 10 | } 11 | ], 12 | "conditions": [ 13 | { 14 | "condition": "minecraft:survives_explosion" 15 | } 16 | ] 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/loot_table/blocks/pressurizer.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:block", 3 | "pools": [ 4 | { 5 | "rolls": 1, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "name": "prettypipes:pressurizer" 10 | } 11 | ], 12 | "conditions": [ 13 | { 14 | "condition": "minecraft:survives_explosion" 15 | } 16 | ] 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/blank_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "QRQ", 5 | "SPS", 6 | "QRQ" 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "P": { 13 | "item": "prettypipes:pipe" 14 | }, 15 | "S": { 16 | "item": "minecraft:stone_slab" 17 | }, 18 | "Q": { 19 | "item": "minecraft:quartz" 20 | } 21 | }, 22 | "result": { 23 | "id": "prettypipes:blank_module" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/crafting_terminal.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " C ", 5 | "RTR", 6 | " R " 7 | ], 8 | "key": { 9 | "T": { 10 | "item": "prettypipes:item_terminal" 11 | }, 12 | "C": { 13 | "item": "minecraft:crafting_table" 14 | }, 15 | "R": { 16 | "item": "minecraft:redstone" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:crafting_terminal" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/damage_filter_modifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " H ", 5 | "RMR", 6 | " R " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "H": { 13 | "item": "minecraft:iron_pickaxe" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:damage_filter_modifier" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/filter_increase_modifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " B ", 5 | "RMR", 6 | " R " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "B": { 13 | "item": "minecraft:iron_bars" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:filter_increase_modifier" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/high_crafting_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "GIG", 5 | "GMG", 6 | "GIG" 7 | ], 8 | "key": { 9 | "I": { 10 | "item": "minecraft:iron_ingot" 11 | }, 12 | "G": { 13 | "item": "minecraft:gold_ingot" 14 | }, 15 | "M": { 16 | "item": "prettypipes:medium_crafting_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:high_crafting_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/high_extraction_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "GDG", 5 | "GMG", 6 | "GGG" 7 | ], 8 | "key": { 9 | "D": { 10 | "item": "minecraft:diamond" 11 | }, 12 | "G": { 13 | "item": "minecraft:gold_ingot" 14 | }, 15 | "M": { 16 | "item": "prettypipes:medium_extraction_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:high_extraction_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/high_filter_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "GBG", 5 | "BMB", 6 | "GBG" 7 | ], 8 | "key": { 9 | "G": { 10 | "item": "minecraft:gold_ingot" 11 | }, 12 | "M": { 13 | "item": "prettypipes:medium_filter_module" 14 | }, 15 | "B": { 16 | "item": "minecraft:iron_bars" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:high_filter_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/high_high_priority_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "CCC", 5 | "CMC", 6 | "CCC" 7 | ], 8 | "key": { 9 | "C": { 10 | "item": "minecraft:paper" 11 | }, 12 | "M": { 13 | "item": "prettypipes:medium_high_priority_module" 14 | } 15 | }, 16 | "result": { 17 | "id": "prettypipes:high_high_priority_module" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/high_low_priority_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "CCC", 5 | "CMC", 6 | "CCC" 7 | ], 8 | "key": { 9 | "C": { 10 | "tag": "c:cobblestones" 11 | }, 12 | "M": { 13 | "item": "prettypipes:medium_low_priority_module" 14 | } 15 | }, 16 | "result": { 17 | "id": "prettypipes:high_low_priority_module" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/high_retrieval_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "RDR", 5 | "GMG", 6 | "RGR" 7 | ], 8 | "key": { 9 | "G": { 10 | "item": "minecraft:gold_ingot" 11 | }, 12 | "M": { 13 | "item": "prettypipes:medium_retrieval_module" 14 | }, 15 | "D": { 16 | "item": "minecraft:diamond" 17 | }, 18 | "R": { 19 | "item": "minecraft:redstone_block" 20 | } 21 | }, 22 | "result": { 23 | "id": "prettypipes:high_retrieval_module" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/high_speed_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "GBG", 5 | "BMB", 6 | "GBG" 7 | ], 8 | "key": { 9 | "G": { 10 | "item": "minecraft:gold_ingot" 11 | }, 12 | "M": { 13 | "item": "prettypipes:medium_speed_module" 14 | }, 15 | "B": { 16 | "item": "minecraft:sugar" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:high_speed_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/item_terminal.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "DPI", 5 | "RCE", 6 | "IPD" 7 | ], 8 | "key": { 9 | "E": { 10 | "item": "prettypipes:high_extraction_module" 11 | }, 12 | "R": { 13 | "item": "prettypipes:high_retrieval_module" 14 | }, 15 | "P": { 16 | "item": "minecraft:ender_pearl" 17 | }, 18 | "I": { 19 | "item": "minecraft:iron_block" 20 | }, 21 | "C": { 22 | "tag": "c:chests" 23 | }, 24 | "D": { 25 | "item": "minecraft:diamond" 26 | } 27 | }, 28 | "result": { 29 | "id": "prettypipes:item_terminal" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/low_crafting_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " P ", 5 | "RMR", 6 | " R " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "P": { 13 | "item": "minecraft:crafting_table" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:low_crafting_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/low_extraction_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " P ", 5 | "RMR", 6 | " R " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "P": { 13 | "item": "minecraft:piston" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:low_extraction_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/low_filter_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " H ", 5 | "RMR", 6 | " R " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "H": { 13 | "item": "minecraft:hopper" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:low_filter_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/low_high_priority_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " C ", 5 | "RMR", 6 | " R " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "C": { 13 | "item": "minecraft:paper" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:low_high_priority_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/low_low_priority_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " C ", 5 | "RMR", 6 | " R " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "C": { 13 | "tag": "c:cobblestones" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:low_low_priority_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/low_retrieval_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " P ", 5 | "RMR", 6 | " E " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone_block" 11 | }, 12 | "P": { 13 | "item": "minecraft:sticky_piston" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | }, 18 | "E": { 19 | "item": "minecraft:ender_pearl" 20 | } 21 | }, 22 | "result": { 23 | "id": "prettypipes:low_retrieval_module" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/low_speed_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " S ", 5 | "RMR", 6 | " R " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "S": { 13 | "item": "minecraft:sugar" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:low_speed_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/medium_crafting_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "GIG", 5 | "IMI", 6 | "GIG" 7 | ], 8 | "key": { 9 | "I": { 10 | "item": "minecraft:iron_ingot" 11 | }, 12 | "G": { 13 | "item": "minecraft:gold_ingot" 14 | }, 15 | "M": { 16 | "item": "prettypipes:low_crafting_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:medium_crafting_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/medium_extraction_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " I ", 5 | "IMI", 6 | " I " 7 | ], 8 | "key": { 9 | "I": { 10 | "item": "minecraft:iron_ingot" 11 | }, 12 | "M": { 13 | "item": "prettypipes:low_extraction_module" 14 | } 15 | }, 16 | "result": { 17 | "id": "prettypipes:medium_extraction_module" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/medium_filter_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " B ", 5 | "IMI", 6 | " B " 7 | ], 8 | "key": { 9 | "I": { 10 | "item": "minecraft:iron_ingot" 11 | }, 12 | "M": { 13 | "item": "prettypipes:low_filter_module" 14 | }, 15 | "B": { 16 | "item": "minecraft:iron_bars" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:medium_filter_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/medium_high_priority_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " C ", 5 | "CMC", 6 | " C " 7 | ], 8 | "key": { 9 | "C": { 10 | "item": "minecraft:paper" 11 | }, 12 | "M": { 13 | "item": "prettypipes:low_high_priority_module" 14 | } 15 | }, 16 | "result": { 17 | "id": "prettypipes:medium_high_priority_module" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/medium_low_priority_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " C ", 5 | "CMC", 6 | " C " 7 | ], 8 | "key": { 9 | "C": { 10 | "tag": "c:cobblestones" 11 | }, 12 | "M": { 13 | "item": "prettypipes:low_low_priority_module" 14 | } 15 | }, 16 | "result": { 17 | "id": "prettypipes:medium_low_priority_module" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/medium_retrieval_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "RRR", 5 | "IMI", 6 | " I " 7 | ], 8 | "key": { 9 | "I": { 10 | "item": "minecraft:gold_ingot" 11 | }, 12 | "M": { 13 | "item": "prettypipes:low_retrieval_module" 14 | }, 15 | "R": { 16 | "item": "minecraft:redstone_block" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:medium_retrieval_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/medium_speed_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "ISI", 5 | "SMS", 6 | "ISI" 7 | ], 8 | "key": { 9 | "S": { 10 | "item": "minecraft:sugar" 11 | }, 12 | "M": { 13 | "item": "prettypipes:low_speed_module" 14 | }, 15 | "I": { 16 | "item": "minecraft:iron_ingot" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:medium_speed_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/mod_filter_modifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " H ", 5 | "RMR", 6 | " R " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "H": { 13 | "item": "minecraft:anvil" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:mod_filter_modifier" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/module_clearing.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "prettypipes:module_clearing", 3 | "category": "misc" 4 | } -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/nbt_filter_modifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " H ", 5 | "RMR", 6 | " R " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "H": { 13 | "item": "minecraft:book" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:nbt_filter_modifier" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/pipe.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " R ", 5 | "IGI", 6 | " C " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "I": { 13 | "item": "minecraft:iron_bars" 14 | }, 15 | "G": { 16 | "tag": "c:glass_blocks" 17 | }, 18 | "C": { 19 | "item": "minecraft:copper_ingot" 20 | } 21 | }, 22 | "result": { 23 | "id": "prettypipes:pipe", 24 | "count": 4 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/pipe_frame.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shapeless", 3 | "ingredients": [ 4 | { 5 | "item": "minecraft:item_frame" 6 | }, 7 | { 8 | "item": "prettypipes:pipe" 9 | }, 10 | { 11 | "item": "minecraft:redstone" 12 | } 13 | ], 14 | "result": { 15 | "id": "prettypipes:pipe_frame" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/pressurizer.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "TST", 5 | "SRS", 6 | "TST" 7 | ], 8 | "key": { 9 | "S": { 10 | "item": "prettypipes:high_speed_module" 11 | }, 12 | "R": { 13 | "item": "minecraft:redstone_block" 14 | }, 15 | "T": { 16 | "item": "minecraft:iron_ingot" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:pressurizer" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/random_sorting_modifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " H ", 5 | "RMR", 6 | " R " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "H": { 13 | "item": "minecraft:dispenser" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:random_sorting_modifier" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/redstone_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " S ", 5 | "RMR", 6 | " R " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "S": { 13 | "item": "minecraft:redstone_torch" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:redstone_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/round_robin_sorting_modifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " H ", 5 | "RMR", 6 | " R " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "H": { 13 | "item": "minecraft:arrow" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:round_robin_sorting_modifier" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/stack_size_module.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " D ", 5 | "RMR", 6 | " R " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "D": { 13 | "item": "minecraft:dropper" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:stack_size_module" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/tag_filter_modifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | " H ", 5 | "RMR", 6 | " R " 7 | ], 8 | "key": { 9 | "R": { 10 | "item": "minecraft:redstone" 11 | }, 12 | "H": { 13 | "item": "minecraft:iron_ore" 14 | }, 15 | "M": { 16 | "item": "prettypipes:blank_module" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:tag_filter_modifier" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/data/prettypipes/recipe/wrench.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "PI ", 5 | "II ", 6 | " R" 7 | ], 8 | "key": { 9 | "P": { 10 | "item": "prettypipes:pipe" 11 | }, 12 | "I": { 13 | "item": "minecraft:iron_ingot" 14 | }, 15 | "R": { 16 | "tag": "c:dyes/red" 17 | } 18 | }, 19 | "result": { 20 | "id": "prettypipes:wrench" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "Pretty Pipes", 4 | "pack_format": 4, 5 | "_comment": "A pack_format of 4 requires json lang files. Note: we require v4 pack meta for all mods." 6 | } 7 | } --------------------------------------------------------------------------------