Compare commits

...
Author SHA1 Message Date
June Awesome 4058f23490 testing if this works 2026-03-22 18:53:26 -04:00
slprime 0ba14091fb Refactor DebugHandlerWidget (#900) 2026-03-22 14:10:10 +02:00
slprimeandUltraProdigy 6ed0be7961 Add Repair Handler (#899)
Co-authored-by: UltraProdigy <[email protected]>
2026-03-21 15:04:09 +02:00
slprime d40b951cce Fix areStacksSameTypeWithNBT damage check (#896) 2026-03-19 14:43:45 +02:00
slprime ecdf7892ce updateBuildScript (#895) 2026-03-19 09:39:59 +02:00
slprime 1eaaac94bc Fix filtered permutations (#893) 2026-03-18 01:25:27 +02:00
slprime e99167dddb Change calculateBounds (#892) 2026-03-15 22:41:31 +02:00
slprime 34cb0dc43f Set minimum GTNHLib version to 0.9.6 (#891) 2026-03-15 16:07:31 +01:00
slprime acaad4bf91 Fix Favorite Option (#887) 2026-03-09 21:23:22 +02:00
slprime 3de75f4e26 Fix bookmark slot placement logic (#885) 2026-03-08 12:23:18 +02:00
slprime 47497090ea fix glColor4f; disabled generateSingleRecipeFavorites by default (#884) 2026-03-07 16:58:30 +02:00
slprime 8b45a1757f Add Favorite Item Support (#880) 2026-03-07 16:34:41 +02:00
UltraProdigy 2782f8252e Optimize images (#883) 2026-03-07 09:40:11 +01:00
slprime a5538b2566 Always Show Recipe Ingredients Overlay (#878) 2026-03-01 11:38:05 +02:00
slprime a1f324b796 Remove Generated Favorites from Accepts Followings Tooltip (#873) 2026-02-23 09:32:15 +02:00
slprimeandMartin Robertz f3b6be26df Generate Single-Recipe Favorites (#863)
Co-authored-by: Martin Robertz <[email protected]>
2026-02-16 23:14:55 +01:00
slprime 9c764e3682 Restore the 'get infinite items' action (#867) 2026-02-16 18:39:17 +02:00
slprime 08605c3d73 Removed GTNHLib from required dependency (#866) 2026-02-16 04:37:20 -05:00
slprime 9ec1e0f0cd Change Bookmarks Panel Width (#862) 2026-02-10 19:41:28 +02:00
UltraProdigy e61151186c Exclude Duplicates (#860) 2026-02-09 23:05:15 +01:00
Martin Robertz f7787a9a22 update gradle + deps + bs 2026-02-09 22:32:25 +01:00
slprimeandUltraProdigy a91083bb5a Fix Pull Bookmarked Items (#857)
Co-authored-by: UltraProdigy <[email protected]>
2026-02-09 21:29:07 +00:00
slprimeandUltraProdigy 51f830bdf6 Reset item panel page on search result size change (#855)
Co-authored-by: UltraProdigy <[email protected]>
2026-02-09 16:18:22 -05:00
slprime 9326ac48ad Align panels from center to edges (#856) 2026-02-09 21:11:10 +00:00
c125b71ae0 Added checks for abstract classes when retrieving entities (#833)
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-08 20:49:58 +00:00
Ranzu 805b90d6f8 Add debug text localization and tooltips (#854) 2026-02-03 17:58:20 +02:00
RanzuandMartin Robertz 900b9f90e7 Added show all handlers and recipes function (#852)
Co-authored-by: Martin Robertz <[email protected]>
2026-02-03 15:38:35 +02:00
Ranzuandslprime 06d4a96c3a Add texture for toggled state of magnet button (#849)
Co-authored-by: slprime <[email protected]>
2026-01-26 20:15:10 +02:00
sbwaz 9a5a4a77ef [Extended+] Quote in extended+ depending on "Quote Drop Item Name" NEI option (#848) 2026-01-26 20:08:27 +02:00
Connor-ColensoandConnor Colenso 4d874ec910 Format number centralisation (#846)
Co-authored-by: Connor Colenso <colen@CONNORSPC>
2026-01-23 20:51:38 -05:00
slprime 7f0f2466a5 Fix Information Handler Background Padding (#843) 2026-01-19 13:13:14 +02:00
slprime 83e1966ff2 Fix Recipe Handlers Padding (#842) 2026-01-19 07:47:05 +01:00
slprime 548f754823 Fix Autocrafting for recipe without ingredients in bookmarks (#841) 2026-01-19 07:46:46 +01:00
slprime e036fd14a8 Correctly crop colored text (#839) 2026-01-13 15:16:09 +02:00
slprime 463f4c9b60 Fix transparency border (#838) 2026-01-13 13:06:59 +02:00
Ranzu 5070fde640 Added optional subset label localization (#836) 2026-01-06 03:02:38 +02:00
454b4f7e1d Added Transparency Border to recipe-background and catalyst-tab (#822)
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: slprime <[email protected]>
2025-12-28 15:40:21 +01:00
7b83456f01 Add tooltip for "Required Crafts" with shift (#810)
Co-authored-by: Wilhelm Schuster <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: slprime <[email protected]>
2025-12-28 15:36:39 +02:00
PLASMAchicken 4b7b84b031 Restore NEIModContainer public plugins field (#829) 2025-12-26 19:31:41 +01:00
slprime 75309b81ec Hide Untranslator Subset when Untranslator disabled (#827) 2025-12-21 13:26:26 +02:00
slprimeandMartin Robertz 24e46bb43e Add the ability to move bookmark groups between namespaces (#803)
Co-authored-by: Martin Robertz <[email protected]>
2025-12-16 23:39:32 +02:00
Alexdoru 2ba0773401 [Memory-opti:fix leak] Fix WorldServer leak in NEIServerConfig (#815) 2025-12-16 19:44:15 +00:00
PLASMAchicken eac913c80c Remove Obsolete Code from ModContainer (#820) 2025-12-13 12:42:40 +02:00
slprime 126f0ea73c Fix missing favorites and incorrect crafting chains for recipes with identical ingredients (#814) 2025-11-25 07:24:30 +01:00
slprimeandMartin Robertz cd4668ec84 Backup bookmarks.ini if loading failed (#798)
Co-authored-by: Martin Robertz <[email protected]>
2025-11-24 08:52:01 +02:00
slprime 7c247dd0d2 Ignore space hotkeys when typing in search bar (#808) 2025-11-24 00:21:24 +02:00
slprime 87b549fab5 Normalize Fluid Packet (#811) 2025-11-16 14:17:56 +02:00
slprimeandMartin Robertz 8ed1f7a043 Properly clears inventory before filling a recipe (#796)
Co-authored-by: Martin Robertz <[email protected]>
2025-11-13 08:19:55 +02:00
slprime f2efa35654 Extend HandlerInfo.Builder interface (#809) 2025-11-08 23:54:35 +02:00
slprime bcef287e71 Fix Permutations for Information Handler (#804) 2025-11-08 09:32:47 +02:00
slprime 7f555f7a7f Add Tooltip for debug option (#805) 2025-11-08 09:27:21 +02:00
slprime 9fd38da205 Correctly collapse recipe (#807) 2025-11-08 09:18:14 +02:00
slprime 2fa5563408 Optimizing cross-dimension loading (#806) 2025-11-08 09:12:40 +02:00
slprimeandMartin Robertz 541c0e2def Add 'Bookmark recipe with count' Option (#776)
Co-authored-by: Martin Robertz <[email protected]>
2025-11-07 19:54:09 +02:00
Martin Robertz ac868097e7 update 2025-11-07 18:32:09 +01:00
slprimeandMartin Robertz 2f0de0b6a8 Add 'Show only favorites' option to the 'Craftables' panel (#800)
Co-authored-by: Martin Robertz <[email protected]>
2025-11-06 17:37:00 +02:00
sisyphussy 32bc29e654 Remove glBlitFramebuffer (#801) 2025-11-06 14:36:30 +02:00
slprimeandMartin Robertz ef8a7d8bd5 Create normalizeRecipeQueryStack (#772)
Co-authored-by: Martin Robertz <[email protected]>
2025-11-05 23:15:45 +02:00
slprimeandMartin Robertz adc5a5df16 Add GuiOverlapSlots for subpanels (#799)
Co-authored-by: Martin Robertz <[email protected]>
2025-11-05 21:55:33 +02:00
slprime a828ff227a Remove try/catch from static block (#797) 2025-11-05 19:08:55 +01:00
slprime 9b6f98330e Remove Permutations from Output (#777) 2025-11-05 19:14:48 +02:00
slprime 667c8cb5b6 Implement Dynamic Handler Height (#792) 2025-11-05 19:00:09 +02:00
slprimeandMartin Robertz a186f69444 Fix favorite state refresh (#787)
Co-authored-by: Martin Robertz <[email protected]>
2025-11-04 23:11:00 +01:00
slprime 16f4f20239 Fixed small mouse movement while double-clicking causing drop all items (#793) 2025-11-04 23:10:43 +01:00
slprime bac207cacb Change item slot size in GuiRecipe (#789) 2025-11-04 23:10:32 +01:00
slprime 630e856d83 Fix hotkeys when keyBinding disabled (#786) 2025-10-30 10:17:16 +02:00
slprime 42d96aed0c Show 'Delete Item' tooltip in Creative Mode (#785) 2025-10-29 21:47:34 +01:00
slprimeandsisyphussy bd6384bf24 Сalculate the height of the container before scrolling to the recipe (#782)
Co-authored-by: sisyphussy <[email protected]>
2025-10-29 07:52:33 +00:00
slprime af9726d356 Fixed shift+scroll of ingredients in the recipe GUI (#783) 2025-10-29 07:42:18 +00:00
Martin Robertz 1e1d2f1076 update 2025-10-29 07:54:19 +01:00
slprimeandWilhelm Schuster 7cb94fb22a Clear rawText before formatting (#780)
Co-authored-by: Wilhelm Schuster <[email protected]>
2025-10-25 15:20:28 +02:00
Martin Robertz 87aa4f9ed5 update 2025-10-25 14:18:58 +02:00
DarkShadow44andMartin Robertz 9760fd3eaf Fix another race condition, affecting IndustrialGrafter (#779)
Co-authored-by: Martin Robertz <[email protected]>
2025-10-25 14:11:49 +02:00
slprime 1054871982 Add Scroll to Recipe Catalysts (#770) 2025-10-21 12:28:14 +00:00
slprime d90a667f68 Fix Bookmarks Chain Tooltip Height (#773) 2025-10-19 21:33:46 +03:00
slprime 69e6df5848 Fix Button Texture (#771) 2025-10-19 19:56:23 +02:00
slprime 25fa7ce44e Add defaultbookmarkcontainers.cfg (#769) 2025-10-19 16:07:45 +03:00
slprime e3cd7b860d Fix recipe result count (#767) 2025-10-18 11:07:39 +00:00
slprime 2a3aabc073 Add recipe index to recipe handler height (#768) 2025-10-18 13:03:08 +02:00
110 changed files with 3946 additions and 2102 deletions

No files matched your search

+17
View File
@@ -0,0 +1,17 @@
name: Optimize images
on:
pull_request:
branches: [ master, main, release/** ]
paths:
- "**/*.png"
push:
branches: [ master, main, release/** ]
paths:
- "**/*.png"
jobs:
optimize-images:
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/optimize-images.yml@master
secrets: inherit
+4 -1
View File
@@ -2,7 +2,6 @@ compileJava {
options.encoding = "UTF-8"
}
generateGrammarSource {
maxHeapSize = "128m"
arguments += ['-package', 'codechicken.nei.search', '-visitor', '-no-listener']
@@ -12,6 +11,10 @@ generateGrammarSource {
compileJava.dependsOn generateGrammarSource
sourcesJar.dependsOn generateGrammarSource
sourcesJar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
sourceSets {
main {
java.srcDirs += ["build/generated/sources/search/antlr/"]
+2 -2
View File
@@ -1,8 +1,8 @@
// Add your dependencies here
dependencies {
api('com.github.GTNewHorizons:CodeChickenCore:1.4.7:dev')
implementation('com.github.GTNewHorizons:GTNHLib:0.7.0:dev')
api('com.github.GTNewHorizons:CodeChickenCore:1.4.10:dev')
devOnlyNonPublishable('com.github.GTNewHorizons:GTNHLib:0.9.13:dev')
shadowImplementation('org.apache.commons:commons-csv:1.10.0')
+39 -4
View File
@@ -39,9 +39,33 @@ remoteMappings = https\://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/co
# `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE.
developmentEnvironmentUserName = Developer
# Enables using modern Java syntax (up to version 17) via Jabel, while still targeting JVM 8.
# See https://github.com/bsideup/jabel for details on how this works.
enableModernJavaSyntax = true
# Enables modern Java syntax support. Valid values:
# - false: No modern syntax, Java 8 only
# - jabel: Jabel syntax-only support, compiles to J8 bytecode
# - jvmDowngrader: Full modern Java via JVM Downgrader (syntax + stdlib APIs)
# - modern: Native modern Java bytecode, no downgrading
enableModernJavaSyntax = jabel
# If set, ignores the above setting and compiles with the given toolchain. This may cause unexpected issues,
# and should *not* be used in most situations. -1 disables this.
# forceToolchainVersion = -1
# Target JVM version for JVM Downgrader bytecode downgrading.
# Only used when enableModernJavaSyntax = jvmDowngrader
# downgradeTargetVersion = 8
# Comma-separated list of Java versions for multi-release jar support (JVM Downgrader only).
# Classes will be available in META-INF/versions/N/ for each version N in this list.
# Default: "21,25" (J25+ gets native classes, J21-24 gets partial downgrade, J8-20 gets full downgrade).
# jvmDowngraderMultiReleaseVersions = 21,25
# Specifies how JVM Downgrader API stubs are provided. Options:
# - shade: Shade minimized stubs into the jar
# - gtnhlib: GTNHLib provides stubs at runtime (adds version constraint)
# - external: Another dependency provides stubs (no constraint, no warning)
# - (empty): Warning reminding you to configure stubs
# Note: 'shade' option requires you to verify license compliance, see: https://github.com/unimined/JvmDowngrader/blob/main/LICENSE.md
# jvmDowngraderStubsProvider =
# Enables injecting missing generics into the decompiled source code for a better coding experience.
# Turns most publicly visible List, Map, etc. into proper List<E>, Map<K, V> types.
@@ -96,7 +120,9 @@ usesMixinDebug = false
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
mixinPlugin =
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
# Specify the package that contains all of your Mixins. The package must exist or
# the build will fail. If you have a package property defined in your mixins.<modid>.json,
# it must match with this or the build will fail.
mixinsPackage =
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
@@ -172,6 +198,12 @@ curseForgeRelations = requiredDependency\:codechickencore-unofficial
# projects. New projects should not use this parameter.
# customArchiveBaseName =
# Optional parameter to customize the default working directory used by the runClient* tasks. Relative to the project directory.
# runClientWorkingDirectory = run/client
# Optional parameter to customize the default working directory used by the runServer* tasks. Relative to the project directory.
# runServerWorkingDirectory = run/server
# Optional parameter to have the build automatically fail if an illegal version is used.
# This can be useful if you e.g. only want to allow versions in the form of '1.1.xxx'.
# The check is ONLY performed if the version is a git tag.
@@ -201,3 +233,6 @@ curseForgeRelations = requiredDependency\:codechickencore-unofficial
# This is meant to be set in $HOME/.gradle/gradle.properties.
# ideaCheckSpotlessOnBuild = true
# Non-GTNH properties
org.gradle.configuration-cache = true
org.gradle.parallel = true
+12
View File
@@ -0,0 +1,12 @@
#This file is generated by updateDaemonJvm
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c5ee947fbfb70bc347d8d531e3a578c4/redirect
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/5ee463876563a46fff651cce1bc53a4c/redirect
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c5ee947fbfb70bc347d8d531e3a578c4/redirect
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/5ee463876563a46fff651cce1bc53a4c/redirect
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/e1118b4c7c2858d28154d086dbff010e/redirect
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/faa12903720d410b387cc69ccafb1a74/redirect
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c5ee947fbfb70bc347d8d531e3a578c4/redirect
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/5ee463876563a46fff651cce1bc53a4c/redirect
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/a4c09dd2e2d7079373d30e524bbc2829/redirect
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/b96cb7670c095245220e7d01d5927b58/redirect
toolchainVersion=25
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+3 -6
View File
@@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -114,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -172,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -212,8 +210,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
Vendored
+1 -2
View File
@@ -70,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
+1 -1
View File
@@ -17,7 +17,7 @@ pluginManagement {
}
plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.44'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.24'
}
@@ -5,7 +5,9 @@ import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.ShortcutInputHandler;
import codechicken.nei.drawable.DrawableBuilder;
import codechicken.nei.drawable.DrawableResource;
@@ -19,6 +21,7 @@ public abstract class AbstractSubpanel<T extends ItemsGrid<? extends ItemsGridSl
protected int mouseDownItemIndex = -1;
protected int splittingLineColor = 0xffffffff;
protected int linePaddingStart = 0;
protected T grid;
public boolean isEmpty() {
@@ -51,19 +54,30 @@ public abstract class AbstractSubpanel<T extends ItemsGrid<? extends ItemsGridSl
return this.grid.getSlotMouseOver(mousex, mousey);
}
protected void updateLinePadding() {
GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
this.linePaddingStart = 0;
while (GuiInfo
.hideItemPanelSlot(guiContainer, new Rectangle4i(this.x + this.linePaddingStart, this.y - 1, 10, 2))) {
this.linePaddingStart += 10;
}
}
protected void drawSplittingLine() {
float alpha = (this.splittingLineColor >> 24 & 255) / 255.0F;
float red = (this.splittingLineColor >> 16 & 255) / 255.0F;
float green = (this.splittingLineColor >> 8 & 255) / 255.0F;
float blue = (this.splittingLineColor & 255) / 255.0F;
int width = this.grid.columns * ItemsGrid.SLOT_SIZE;
int width = this.grid.columns * ItemsGrid.SLOT_SIZE - this.linePaddingStart;
int repeat = width / 6;
int shiftX = this.x + (this.w - width) / 2;
int shiftX = this.x + this.linePaddingStart + (this.w - width) / 2;
GL11.glColor4f(red, green, blue, alpha);
for (int i = 0; i < repeat; i++) {
DASH.draw(shiftX + i * 6, y);
DASH.draw(shiftX + i * 6, this.y);
}
GL11.glColor4f(1, 1, 1, 1);
}
@@ -29,6 +29,7 @@ import codechicken.nei.api.IBookmarkContainerHandler;
import codechicken.nei.bookmark.BookmarkGrid;
import codechicken.nei.bookmark.BookmarkGroup;
import codechicken.nei.bookmark.BookmarkItem;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.bookmark.BookmarkStorage;
import codechicken.nei.bookmark.BookmarksGridSlot;
import codechicken.nei.bookmark.GroupingItem;
@@ -184,8 +185,8 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
final boolean existsRecipe = recipeId != null
&& this.grid.existsRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID);
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(itemStack);
long factor = nbTag.getInteger("Count");
long count = factor;
long count = nbTag.getInteger("Count");
long factor = existsRecipe ? Math.max(count, 1) : 1;
if (existsRecipe) {
for (int i = 0; i < this.grid.size(); i++) {
@@ -196,12 +197,13 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
}
}
if (factor == 0) {
factor = nbTag.hasKey("gtFluidName") ? Math.min(144, nbTag.getInteger("Count")) : 1;
}
this.grid.addItem(
BookmarkItem.of(groupId, StackInfo.withAmount(itemStack, count), factor, recipeId, false),
BookmarkItem.of(
groupId,
StackInfo.withAmount(itemStack, count),
factor,
recipeId,
existsRecipe ? BookmarkItemType.RESULT : BookmarkItemType.ITEM),
true);
return true;
}
@@ -244,7 +246,8 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
if (stack != null && uniqueRecipe.add(recipeId)) {
this.grid.addItem(
BookmarkItem.of(groupId, stack, StackInfo.getAmount(stack), recipeId, false),
BookmarkItem
.of(groupId, stack, StackInfo.getAmount(stack), recipeId, BookmarkItemType.ITEM),
true);
uniqueStack.add(stack);
}
@@ -304,7 +307,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
}
final int groupId = slot.getGroupId();
final RecipeId recipeId = slot.getRecipeId();
final RecipeId recipeId = slot.getType() == BookmarkItemType.ITEM ? null : slot.getRecipeId();
final BookmarkGroup group = slot.getGroup();
if (group.crafting != null && group.collapsed) {
@@ -368,7 +371,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
public RecipeId getRecipeId(int itemIndex) {
BookmarkItem meta = this.grid.getCalculatedItem(itemIndex);
return meta.isIngredient ? null : meta.recipeId;
return meta.type == BookmarkItemType.INGREDIENT ? null : meta.recipeId;
}
public boolean existsRecipe(RecipeId recipeId, int groupId) {
@@ -506,31 +509,31 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
}
}
public Rectangle4i calculateBounds() {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
final int width = (gui.width - gui.xSize) / 2 - PADDING * 2;
final Rectangle4i bounds = new Rectangle4i(
PADDING,
PADDING,
(gui.width - 176) / 2 - PADDING * 2,
gui.height - PADDING * 2);
@Override
public Rectangle4i calculateBounds(GuiContainer gui) {
final int maxWidth = (gui.width - 176) / 2 - PADDING * 2;
final int maxHeight = gui.height - PADDING * 2;
final int freeSpace = (gui.width - gui.xSize) / 2 - PADDING * 2;
int paddingLeft = (int) Math
.ceil(bounds.w * NEIClientConfig.getSetting("world.panels.bookmarks.left").getIntValue() / 100000.0);
int paddingTop = (int) Math
.ceil(bounds.h * NEIClientConfig.getSetting("world.panels.bookmarks.top").getIntValue() / 100000.0);
int paddingRight = (int) Math
.ceil(bounds.w * NEIClientConfig.getSetting("world.panels.bookmarks.right").getIntValue() / 100000.0);
int paddingBottom = (int) Math
.ceil(bounds.h * NEIClientConfig.getSetting("world.panels.bookmarks.bottom").getIntValue() / 100000.0);
final int paddingLeft = (int) Math
.ceil(maxWidth * NEIClientConfig.getSetting("world.panels.bookmarks.left").getIntValue() / 100000.0);
final int paddingTop = (int) Math
.ceil(maxHeight * NEIClientConfig.getSetting("world.panels.bookmarks.top").getIntValue() / 100000.0);
final int paddingRight = (int) Math
.ceil(maxWidth * NEIClientConfig.getSetting("world.panels.bookmarks.right").getIntValue() / 100000.0);
final int paddingBottom = (int) Math
.ceil(maxHeight * NEIClientConfig.getSetting("world.panels.bookmarks.bottom").getIntValue() / 100000.0);
bounds.h = Math.max(ItemsGrid.SLOT_SIZE, bounds.h - paddingTop - paddingBottom);
bounds.y = bounds.y + Math.min(paddingTop, bounds.h - ItemsGrid.SLOT_SIZE);
final int width = Math.max(
ItemsGrid.SLOT_SIZE,
snapDownToMultiple(
Math.min(freeSpace - paddingLeft, maxWidth - paddingLeft - paddingRight)
- BookmarkGrid.GROUP_PANEL_WIDTH,
ItemsGrid.SLOT_SIZE))
+ BookmarkGrid.GROUP_PANEL_WIDTH;
final int height = Math.max(ItemsGrid.SLOT_SIZE, maxHeight - paddingTop - paddingBottom);
bounds.w = Math.max(ItemsGrid.SLOT_SIZE, Math.min(bounds.w - paddingLeft - paddingRight, width - paddingLeft));
bounds.x = bounds.x + Math.min(paddingLeft, bounds.w - ItemsGrid.SLOT_SIZE);
return bounds;
return new Rectangle4i(paddingLeft + PADDING, paddingTop + PADDING, width, height);
}
protected ItemStack getDraggedStackWithQuantity(ItemStack itemStack) {
@@ -922,7 +925,8 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
if (slot != null) {
if (slot.isIngredient() && slot.getRecipeId() != null && slot.getBookmarkItem().permutations.size() > 1) {
if (slot.getType() == BookmarkItemType.INGREDIENT && slot.getRecipeId() != null
&& slot.getBookmarkItem().permutations.size() > 1) {
RecipeId recipeId = slot.getRecipeId();
if (recipeId == null) {
@@ -992,7 +996,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
@Override
public boolean onMouseWheel(int shift, int mousex, int mousey) {
if (!inEditingState() && new Rectangle4i(
if ((!inEditingState() || this.sortableGroup != null) && new Rectangle4i(
namespacePrev.x,
namespacePrev.y,
namespaceNext.x + namespaceNext.w - namespacePrev.x,
@@ -1020,7 +1024,8 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
if (NEIClientUtils.altKey()) {
multiplier = NEIClientConfig.showItemQuantityWidget() ? NEIClientConfig.getItemQuantity() : 0;
if (multiplier == 0) {
multiplier = slot.getItemStack().getMaxStackSize();
multiplier = StackInfo.itemStackToNBT(slot.getItemStack()).hasKey("gtFluidName") ? 144
: slot.getItemStack().getMaxStackSize();
}
}
@@ -1182,7 +1187,15 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
}
if (!items.isEmpty()) {
containerHandler.pullBookmarkItemsFromContainer(guiContainer, items);
final int helmStackIndex = FastTransferManager.dropHeldItem(guiContainer);
if (guiContainer.mc.thePlayer.inventory.getItemStack() == null) {
containerHandler.pullBookmarkItemsFromContainer(guiContainer, items);
if (helmStackIndex != -1) {
FastTransferManager.clickSlot(guiContainer, helmStackIndex, 0, 0);
}
}
}
return true;
@@ -1253,7 +1266,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
@Deprecated
public BookmarkRecipeId getBookmarkRecipeId(int itemIndex) {
BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
return item == null || item.isIngredient || item.recipeId == null ? null
return item == null || item.type == BookmarkItemType.INGREDIENT || item.recipeId == null ? null
: new BookmarkRecipeId(item.recipeId.getHandleName(), item.recipeId.getIngredients());
}
@@ -24,6 +24,7 @@ import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiErrorScreen;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiSelectWorld;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.resources.IResource;
import net.minecraft.entity.Entity;
@@ -42,7 +43,6 @@ import com.google.common.collect.Lists;
import codechicken.core.ClassDiscoverer;
import codechicken.core.ClientUtils;
import codechicken.core.GuiModListScroll;
import codechicken.lib.packet.PacketCustom;
import codechicken.nei.api.API;
import codechicken.nei.api.IConfigureNEI;
@@ -153,6 +153,7 @@ public class ClientHandler {
loadHiddenHandlers();
loadEnableAutoFocus();
loadGuiCraftablesBlacklist();
loadDefaultBookmarkContainers();
ItemInfo.preInit();
StackInfo.loadGuidFilters();
}
@@ -253,6 +254,20 @@ public class ClientHandler {
lines -> ItemCraftablesPanel.guiBlacklist = lines.collect(Collectors.toList()));
}
public static void loadDefaultBookmarkContainers() {
loadSettingsFile("defaultbookmarkcontainers.cfg", lines -> {
for (String clazz : lines.collect(Collectors.toList())) {
try {
API.registerBookmarkContainerHandler(
(Class<? extends GuiContainer>) Class.forName(clazz),
new DefaultBookmarkContainerHandler());
} catch (Exception e) {
NEIClientConfig.logger.error("Failed to load class '{}' for defaultbookmarkcontainers.cfg", clazz);
}
}
});
}
public static void loadHiddenItems() {
loadSettingsFile("hiddenitems.cfg", lines -> lines.forEach(API::hideItem));
}
@@ -260,7 +275,6 @@ public class ClientHandler {
public static void load() {
instance = new ClientHandler();
GuiModListScroll.register("NotEnoughItems");
PacketCustom.assignHandler(NEICPH.channel, new NEICPH());
FMLCommonHandler.instance().bus().register(instance);
MinecraftForge.EVENT_BUS.register(instance);
@@ -1,9 +1,10 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import codechicken.nei.api.IBookmarkContainerHandler;
@@ -12,36 +13,18 @@ public class DefaultBookmarkContainerHandler implements IBookmarkContainerHandle
@Override
public void pullBookmarkItemsFromContainer(GuiContainer guiContainer, ArrayList<ItemStack> bookmarkItems) {
FastTransferManager manager = new FastTransferManager();
LinkedList<ItemStack> containerStacks = manager.saveContainer(guiContainer.inventorySlots);
final List<Slot> slots = guiContainer.inventorySlots.inventorySlots;
final FastTransferManager manager = new FastTransferManager();
for (ItemStack bookmarkItem : bookmarkItems) {
int bookmarkSizeBackup = bookmarkItem.stackSize;
for (int i = 0; i < containerStacks.size() - 4 * 9; i++) { // Last 36 slots are player inventory
ItemStack containerItem = containerStacks.get(i);
if (containerItem == null) {
continue;
}
if (bookmarkItem.isItemEqual(containerItem)) {
if (bookmarkItem.stackSize <= 0) {
break;
}
int transferAmount = Math.min(bookmarkItem.stackSize, containerItem.stackSize);
for (int i = 0; i < slots.size() - 4 * 9; i++) {
final Slot slot = slots.get(i);
if (slot.getHasStack() && bookmarkItem.isItemEqual(slot.getStack())) {
final int transferAmount = Math.min(bookmarkItem.stackSize, slot.getStack().stackSize);
manager.transferItems(guiContainer, i, transferAmount);
bookmarkItem.stackSize -= transferAmount;
if (bookmarkItem.stackSize == 0) {
break;
}
}
}
bookmarkItem.stackSize = bookmarkSizeBackup;
}
}
}
@@ -9,7 +9,9 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
@@ -281,6 +283,27 @@ public class FastTransferManager {
GuiContainerManager.getManager(window).handleSlotClick(slotIndex, button, modifier);
}
public static int dropHeldItem(GuiContainer window) {
final EntityPlayerSP player = window.mc.thePlayer;
final ItemStack held = player.inventory.getItemStack();
if (held == null) return -1;
for (int i = 0; held != null && i < window.inventorySlots.inventorySlots.size(); i++) {
final Slot slot = window.inventorySlots.inventorySlots.get(i);
if (slot.inventory instanceof InventoryPlayer && !slot.getHasStack() && slot.isItemValid(held)) {
clickSlot(window, i, 0, 0);
if (player.inventory.getItemStack() == null) {
return i;
}
}
}
return -1;
}
private boolean fillZoneWithHeldItem(GuiContainer window, int zoneIndex) {
for (int transferTo : slotZones.get(zoneIndex)) {
ItemStack held = NEIClientUtils.getHeldItem();
@@ -8,39 +8,142 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Objects;
import java.util.Set;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import org.apache.commons.io.IOUtils;
import com.google.common.io.Files;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import codechicken.core.CommonUtils;
import codechicken.nei.api.API;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.ICraftingHandler;
import codechicken.nei.recipe.IRecipeHandler;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.RecipeHandlerRef;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.FavoriteStorage;
import codechicken.nei.util.NBTJson;
public class FavoriteRecipes {
private static final Set<NBTTagCompound> tools = new HashSet<>();
private static final Map<NBTTagCompound, RecipeId> items = new HashMap<>();
private static final Map<String, RecipeId> fluids = new HashMap<>();
protected static final class FastKey {
public final ItemStack stack;
private int hash;
public FastKey(ItemStack stack) {
this.stack = stack;
this.hash = 31 + Item.getIdFromItem(stack.getItem());
this.hash = 31 * this.hash + stack.getItemDamage();
}
@Override
public int hashCode() {
return this.hash;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o instanceof FastKey k && this.stack.getItem() == k.stack.getItem()
&& this.stack.getItemDamage() == k.stack.getItemDamage()) {
return this.stack == k.stack || Objects.equals(this.stack.stackTagCompound, k.stack.stackTagCompound);
}
return false;
}
}
private static final RestartableTask singleRecipeFavoritesTask = new RestartableTask(
"Generate Single-Recipe Favorites") {
@Override
public void execute() {
final List<ICraftingHandler> handlers = GuiCraftingRecipe.getCraftingHandlers("all");
final Map<FastKey, RecipeHandlerRef> autogeneratedRecipes = new HashMap<>();
final Set<FastKey> whitelistItems = new HashSet<>(ItemList.items.size());
final FavoriteStorage storage = new FavoriteStorage();
for (ItemStack stack : ItemList.items) {
whitelistItems.add(new FastKey(stack));
}
if (interrupted()) return;
for (ICraftingHandler handler : handlers) {
if (!GuiRecipeTab.getHandlerInfo(handler).getShowFavoritesButton()) continue;
for (int i = 0; i < handler.numRecipes(); i++) {
RecipeHandlerRef ref = null;
for (PositionedStack result : getOutputs(handler, i)) {
ItemStack stack = StackInfo.getItemStackWithMinimumDamage(result.items);
final FastKey key = new FastKey(stack);
if (!whitelistItems.contains(key)) continue;
if (autogeneratedRecipes.get(key) == null) {
if (ref == null) {
ref = RecipeHandlerRef.of(handler, i);
}
autogeneratedRecipes.put(key, ref);
} else {
autogeneratedRecipes.remove(key);
whitelistItems.remove(key);
}
}
}
if (interrupted()) return;
}
final Map<RecipeHandlerRef, RecipeId> recipesCache = new HashMap<>();
for (Map.Entry<FastKey, RecipeHandlerRef> entry : autogeneratedRecipes.entrySet()) {
final RecipeId recipeId = recipesCache
.computeIfAbsent(entry.getValue(), r -> RecipeId.of(r.handler, r.recipeIndex));
storage.add(entry.getKey().stack, recipeId);
}
FavoriteRecipes.autoFavorites = storage;
updateSubsetVisibility();
}
protected List<PositionedStack> getOutputs(IRecipeHandler handler, int recipeIndex) {
final PositionedStack pStackResult = handler.getResultStack(recipeIndex);
return pStackResult != null ? Collections.singletonList(pStackResult) : handler.getOtherStacks(recipeIndex);
}
};
public static final String FAVORITE_ITEM = "FavoriteItem";
private static final FavoriteStorage manualFavorites = new FavoriteStorage();
private static FavoriteStorage autoFavorites = new FavoriteStorage();
private static File favoriteFile;
private static int revision = 0;
static {
API.addSubset("Favorites", FavoriteRecipes::contains);
API.addSubset("Favorites.Manual", manualFavorites::contains);
API.addSubset("Favorites.Generated", stack -> FavoriteRecipes.autoFavorites.contains(stack));
}
private FavoriteRecipes() {}
@@ -66,7 +169,6 @@ public class FavoriteRecipes {
final File defaultFavorites = configFavorites.exists() ? configFavorites : globalFavorites;
if (defaultFavorites.exists()) {
try {
if (favoriteFile.createNewFile()) {
InputStream src = new FileInputStream(defaultFavorites);
@@ -101,7 +203,9 @@ public class FavoriteRecipes {
}
final JsonParser parser = new JsonParser();
items.clear();
boolean hasErrors = false;
manualFavorites.clear();
for (String itemStr : itemStrings) {
@@ -121,103 +225,135 @@ public class FavoriteRecipes {
continue;
}
final String fluidKey = getFluidKey(stack);
if (fluidKey != null) {
fluids.put(fluidKey, recipeId);
if (FAVORITE_ITEM.equals(recipeId.getHandleName()) || RecipeHandlerRef.of(recipeId) != null) {
manualFavorites.add(stack, recipeId);
} else {
hasErrors = true;
}
items.put(itemStackNBT, recipeId);
if (NEIServerUtils.isItemTool(stack)) {
tools.add(itemStackNBT);
}
}
} catch (Exception e) {
NEIClientConfig.logger.error("Failed to load favorite from json string: {}", itemStr);
hasErrors = true;
}
}
SubsetWidget.updateHiddenItems();
if (hasErrors) {
try {
Files.copy(
favoriteFile,
new File(favoriteFile.getAbsolutePath() + ".backup-" + System.currentTimeMillis()));
NEIClientConfig.logger.info("Backed up invalid favorite file to {}", favoriteFile);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to backup invalid favorite file to {}", favoriteFile, e);
}
save();
}
loadAutoGeneratedRecipes();
}
public static RecipeId getGeneratedFavorite(ItemStack stack) {
if (NEIClientConfig.favoritesEnabled() && stack != null) {
return autoFavorites.getRecipeId(stack);
}
return null;
}
public static ItemStack getGeneratedFavorite(RecipeId recipeId) {
if (NEIClientConfig.favoritesEnabled() && recipeId != null) {
return autoFavorites.getItemStack(recipeId);
}
return null;
}
public static RecipeId getManualFavorite(ItemStack stack) {
if (NEIClientConfig.favoritesEnabled() && stack != null) {
return manualFavorites.getRecipeId(stack);
}
return null;
}
public static ItemStack getManualFavorite(RecipeId recipeId) {
if (NEIClientConfig.favoritesEnabled() && recipeId != null) {
return manualFavorites.getItemStack(recipeId);
}
return null;
}
public static RecipeId getFavorite(ItemStack stack) {
if (NEIClientConfig.favoritesEnabled() && stack != null) {
RecipeId recipeId = items.get(StackInfo.itemStackToNBT(stack, false));
if (recipeId == null) {
recipeId = fluids.get(getFluidKey(stack));
}
if (recipeId != null) {
return recipeId;
}
if (NEIServerUtils.isItemTool(stack)
&& (stack.stackTagCompound == null || !stack.stackTagCompound.hasKey("GT.ToolStats"))) {
for (NBTTagCompound nbt : tools) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(stack, StackInfo.loadFromNBT(nbt))) {
return items.get(nbt);
}
}
}
final RecipeId recipeId = manualFavorites.getRecipeId(stack);
return recipeId != null ? recipeId : autoFavorites.getRecipeId(stack);
}
return null;
}
public static ItemStack getFavorite(RecipeId recipeId) {
if (NEIClientConfig.favoritesEnabled()) {
final Optional<Map.Entry<NBTTagCompound, RecipeId>> result = items.entrySet().stream()
.filter(entry -> entry.getValue().equals(recipeId)).findAny();
if (result.isPresent()) {
return StackInfo.loadFromNBT(result.get().getKey());
}
if (NEIClientConfig.favoritesEnabled() && recipeId != null) {
final ItemStack stack = manualFavorites.getItemStack(recipeId);
return stack != null ? stack : autoFavorites.getItemStack(recipeId);
}
return null;
}
public static int size() {
return manualFavorites.size() + autoFavorites.size();
}
public static void reload() {
save();
load();
}
public static boolean containsManual(ItemStack stack) {
return getManualFavorite(stack) != null;
}
public static boolean contains(ItemStack stack) {
return getFavorite(stack) != null;
}
public static void setFavorite(ItemStack stack, RecipeId recipeId) {
final NBTTagCompound itemStackNBT = StackInfo.itemStackToNBT(stack, false);
final String fluidKey = getFluidKey(stack);
if (stack == null) return;
items.entrySet().removeIf(entry -> entry.getKey().equals(itemStackNBT) || entry.getValue().equals(recipeId));
fluids.entrySet().removeIf(entry -> entry.getKey().equals(fluidKey) || entry.getValue().equals(recipeId));
manualFavorites.removeItemStack(stack);
if (recipeId != null) {
items.put(itemStackNBT, recipeId);
if (NEIServerUtils.isItemTool(stack)) {
tools.add(itemStackNBT);
}
if (fluidKey != null) {
fluids.put(fluidKey, recipeId);
}
manualFavorites.removeRecipeId(recipeId);
manualFavorites.add(stack, recipeId);
}
SubsetWidget.updateHiddenItems();
ItemList.updateFilter.restart();
updateSubsetVisibility();
}
private static String getFluidKey(ItemStack stack) {
final FluidStack fluid = StackInfo.getFluid(stack);
public static void loadAutoGeneratedRecipes() {
if (ItemList.loadFinished
&& NEIClientConfig.getBooleanSetting("inventory.favorites.generateSingleRecipeFavorites")) {
singleRecipeFavoritesTask.restart();
} else {
singleRecipeFavoritesTask.stop();
autoFavorites.clear();
if (fluid != null) {
return FluidRegistry.getFluidName(fluid);
updateSubsetVisibility();
}
}
return null;
protected static void updateSubsetVisibility() {
SubsetWidget.updateHiddenItems();
FavoriteRecipes.revision++;
}
public static int getRevision() {
return revision;
}
public static void save() {
@@ -228,7 +364,7 @@ public class FavoriteRecipes {
final List<String> strings = new ArrayList<>();
for (Map.Entry<NBTTagCompound, RecipeId> entry : items.entrySet()) {
for (Map.Entry<NBTTagCompound, RecipeId> entry : manualFavorites.getAllFavorites()) {
try {
final JsonObject line = new JsonObject();
@@ -61,6 +61,11 @@ public class FormattedTextField extends GuiTextField {
super.setFocused(focus);
}
@Override
public void setText(String rawText) {
super.setText(EnumChatFormatting.getTextWithoutFormattingCodes(rawText));
}
@Override
public void setSelectionPos(int p_146199_1_) {
String text = this.getText();
@@ -273,7 +278,7 @@ public class FormattedTextField extends GuiTextField {
}
Tessellator tessellator = Tessellator.instance;
GL11.glColor4f(0.0F, 0.0F, 255.0F, 255.0F);
GL11.glColor4f(0.0F, 0.0F, 1.0F, 1.0F);
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_COLOR_LOGIC_OP);
GL11.glLogicOp(GL11.GL_OR_REVERSE);
@@ -36,7 +36,8 @@ public class HeldItemHandler implements IContainerInputHandler, IContainerToolti
if (contains(mousex, mousey)) {
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")) {
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")
|| NEIClientUtils.mc().playerController.isInCreativeMode()) {
if (button == 1) {
NEIClientUtils.decreaseSlotStack(-999);
} else {
@@ -101,7 +102,8 @@ public class HeldItemHandler implements IContainerInputHandler, IContainerToolti
if (contains(mousex, mousey)) {
currenttip.clear();
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")) {
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")
|| NEIClientUtils.mc().playerController.isInCreativeMode()) {
currenttip.add(EnumChatFormatting.RED + translate("itempanel.deleteItem"));
}
}
@@ -0,0 +1,147 @@
package codechicken.nei;
import net.minecraft.client.gui.GuiRepair;
import net.minecraft.client.gui.inventory.GuiBrewingStand;
import net.minecraft.client.gui.inventory.GuiCrafting;
import net.minecraft.client.gui.inventory.GuiFurnace;
import net.minecraft.client.gui.inventory.GuiInventory;
import net.minecraft.nbt.NBTTagCompound;
import codechicken.nei.api.API;
import codechicken.nei.recipe.BrewingOverlayHandler;
import codechicken.nei.recipe.BrewingRecipeHandler;
import codechicken.nei.recipe.DefaultOverlayHandler;
import codechicken.nei.recipe.FireworkRecipeHandler;
import codechicken.nei.recipe.FuelRecipeHandler;
import codechicken.nei.recipe.FurnaceRecipeHandler;
import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.recipe.ProfilerRecipeHandler;
import codechicken.nei.recipe.RepairOverlayHandler;
import codechicken.nei.recipe.RepairRecipeHandler;
import codechicken.nei.recipe.ShapedRecipeHandler;
import codechicken.nei.recipe.ShapelessRecipeHandler;
import cpw.mods.fml.common.event.FMLInterModComms;
public class IMCForNEI {
public static void IMCSender() {
API.registerRecipeHandler(new ShapedRecipeHandler());
API.registerUsageHandler(new ShapedRecipeHandler());
sendHandler("codechicken.nei.recipe.ShapedRecipeHandler", "minecraft:crafting_table");
API.registerRecipeHandler(new ShapelessRecipeHandler());
API.registerUsageHandler(new ShapelessRecipeHandler());
sendHandler("codechicken.nei.recipe.ShapelessRecipeHandler", "minecraft:crafting_table");
API.registerRecipeHandler(new FireworkRecipeHandler());
API.registerUsageHandler(new FireworkRecipeHandler());
sendHandler("codechicken.nei.recipe.FireworkRecipeHandler", "minecraft:fireworks");
API.registerRecipeHandler(new FurnaceRecipeHandler());
API.registerUsageHandler(new FurnaceRecipeHandler());
sendHandler("codechicken.nei.recipe.FurnaceRecipeHandler", "minecraft:furnace");
API.registerRecipeHandler(new BrewingRecipeHandler());
API.registerUsageHandler(new BrewingRecipeHandler());
sendHandler("codechicken.nei.recipe.BrewingRecipeHandler", "minecraft:brewing_stand");
API.registerRecipeHandler(new FuelRecipeHandler());
API.registerUsageHandler(new FuelRecipeHandler());
sendFuelRecipeHandler();
API.registerRecipeHandler(new InformationHandler());
API.registerUsageHandler(new InformationHandler());
sendInformationHandler();
API.registerRecipeHandler(new RepairRecipeHandler());
API.registerUsageHandler(new RepairRecipeHandler());
sendRepairHandler();
sendCatalyst("repair", "minecraft:anvil");
API.registerGuiOverlay(GuiCrafting.class, "crafting");
API.registerGuiOverlay(GuiInventory.class, "crafting2x2", 63, 20);
API.registerGuiOverlay(GuiFurnace.class, "smelting");
API.registerGuiOverlay(GuiFurnace.class, "fuel");
API.registerGuiOverlay(GuiBrewingStand.class, "brewing");
API.registerGuiOverlay(GuiRepair.class, "repair", 2, 37);
API.registerGuiOverlayHandler(GuiCrafting.class, new DefaultOverlayHandler(), "crafting");
API.registerGuiOverlayHandler(GuiInventory.class, new DefaultOverlayHandler(63, 20), "crafting2x2");
API.registerGuiOverlayHandler(GuiBrewingStand.class, new BrewingOverlayHandler(), "brewing");
API.registerGuiOverlayHandler(GuiRepair.class, new RepairOverlayHandler(), "repair");
API.registerRecipeHandler(new ProfilerRecipeHandler(true));
API.registerUsageHandler(new ProfilerRecipeHandler(false));
}
private static void sendHandler(String aName, String aBlock) {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handler", aName);
aNBT.setString("modName", "Minecraft");
aNBT.setString("modId", "minecraft");
aNBT.setString("itemName", aBlock);
aNBT.setInteger("handlerWidth", 166);
aNBT.setInteger("handlerHeight", 65);
aNBT.setBoolean("multipleWidgetsAllowed", true);
aNBT.setInteger("yShift", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
}
private static void sendRepairHandler() {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handler", "codechicken.nei.recipe.RepairRecipeHandler");
aNBT.setString("modName", "Minecraft");
aNBT.setString("modId", "minecraft");
aNBT.setString("itemName", "minecraft:anvil");
aNBT.setInteger("handlerHeight", 39);
aNBT.setInteger("handlerWidth", 166);
aNBT.setBoolean("multipleWidgetsAllowed", true);
aNBT.setBoolean("showFavoritesButton", false);
aNBT.setInteger("yShift", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
}
private static void sendFuelRecipeHandler() {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handler", "codechicken.nei.recipe.FuelRecipeHandler");
aNBT.setString("modName", "Minecraft");
aNBT.setString("modId", "minecraft");
aNBT.setString("imageResource", "nei:textures/nei_tabbed_sprites.png");
aNBT.setInteger("imageX", 80);
aNBT.setInteger("imageY", 0);
aNBT.setInteger("imageWidth", 14);
aNBT.setInteger("imageHeight", 14);
aNBT.setInteger("handlerHeight", 65);
aNBT.setInteger("handlerWidth", 166);
aNBT.setBoolean("multipleWidgetsAllowed", true);
aNBT.setInteger("yShift", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
}
private static void sendInformationHandler() {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handler", "codechicken.nei.recipe.InformationHandler");
aNBT.setString("modName", "Not Enough Items");
aNBT.setString("modId", "nei");
aNBT.setString("imageResource", "nei:textures/nei_tabbed_sprites.png");
aNBT.setInteger("imageX", 96);
aNBT.setInteger("imageY", 0);
aNBT.setInteger("imageWidth", 16);
aNBT.setInteger("imageHeight", 16);
aNBT.setInteger("handlerHeight", 65);
aNBT.setInteger("handlerWidth", 166);
aNBT.setBoolean("multipleWidgetsAllowed", true);
aNBT.setInteger("yShift", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
}
private static void sendCatalyst(String aName, String aStack) {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handlerID", aName);
aNBT.setString("itemName", aStack);
aNBT.setInteger("priority", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerCatalystInfo", aNBT);
}
}
@@ -2,10 +2,11 @@ package codechicken.nei;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import net.minecraft.client.gui.inventory.GuiContainer;
@@ -90,6 +91,7 @@ public class ItemCraftablesPanel
private GuiContainer lastGuiContainer = null;
private ItemStackAmount lastPlayerInventory = null;
private long lastPlayerInventorySync = 0;
private int lastFavoritesCount = 0;
public ItemCraftablesPanel() {
this.grid = new ItemsGrid<>() {
@@ -106,28 +108,43 @@ public class ItemCraftablesPanel
public List<CraftablesGridSlot> getMask() {
if (this.gridMask == null) {
int maxSlotIndex = this.rows * this.columns;
final AtomicInteger slotIndex = new AtomicInteger(0);
final int maxSlotIndex = this.rows * this.columns;
final List<CraftablesGridSlot> gridMask = new ArrayList<>();
this.realItems.clear();
if (!ItemCraftablesPanel.this.availableRecipes.isEmpty()) {
ItemCraftablesPanel.this.availableRecipes.entrySet().stream()
.sorted(Map.Entry.comparingByKey(ItemSorter.instance)).forEach(entry -> {
this.realItems.add(entry.getKey());
gridMask.add(
new CraftablesGridSlot(
slotIndex.get(),
slotIndex.get(),
entry.getKey(),
entry.getValue()));
slotIndex.incrementAndGet();
});
final List<Map.Entry<ItemStack, RecipeId>> entries = ItemCraftablesPanel.this.availableRecipes
.entrySet().stream()
.sorted(
Map.Entry.comparingByKey(
Comparator.comparing(FavoriteRecipes::containsManual)
.thenComparing(FavoriteRecipes::contains).reversed()
.thenComparing(ItemSorter.instance)))
.limit(maxSlotIndex).collect(Collectors.toList());
int slotIndex = 0;
int itemIndex = 0;
this.gridMask = gridMask.subList(0, Math.min(gridMask.size(), maxSlotIndex));
for (Map.Entry<ItemStack, RecipeId> entry : entries) {
if (!isInvalidSlot(slotIndex)) {
this.realItems.add(entry.getKey());
gridMask.add(
new CraftablesGridSlot(
slotIndex,
itemIndex++,
entry.getKey(),
entry.getValue()));
}
if (slotIndex++ >= maxSlotIndex) {
break;
}
}
this.gridMask = gridMask;
} else {
this.gridMask = Collections.emptyList();
}
ItemCraftablesPanel.this.updateLinePadding();
}
return this.gridMask;
@@ -192,11 +209,16 @@ public class ItemCraftablesPanel
this.lastPlayerInventorySync = System.currentTimeMillis();
if (firstGui != null && !ItemCraftablesPanel.guiBlacklist.contains(firstGui.getClass().getName())) {
final boolean showOnlyFavorites = NEIClientConfig
.getBooleanSetting("inventory.craftables.favoritesOnly");
final ItemStackAmount inv = AutoCraftingManager.getInventoryItems(firstGui);
if (this.lastGuiContainer != (this.lastGuiContainer = firstGui)
if (this.lastGuiContainer != firstGui
|| showOnlyFavorites && this.lastFavoritesCount != FavoriteRecipes.size()
|| !inv.equals(this.lastPlayerInventory)) {
this.lastPlayerInventory = inv;
this.lastGuiContainer = firstGui;
this.lastFavoritesCount = FavoriteRecipes.size();
this.availableRecipes = generateCraftables(firstGui);
this.grid.onGridChanged();
}
@@ -251,12 +273,14 @@ public class ItemCraftablesPanel
private Map<ItemStack, RecipeId> filterHandlerRecipes(IRecipeHandler handler, GuiContainer firstGui,
List<ItemStack> invStacks) {
final Map<ItemStack, RecipeId> availableRecipes = new HashMap<>();
final boolean showOnlyFavorites = NEIClientConfig.getBooleanSetting("inventory.craftables.favoritesOnly");
IntStream.range(0, handler.numRecipes()).parallel().forEach(recipeIndex -> {
if (existsIngredients(firstGui, handler.getIngredientStacks(recipeIndex), invStacks)) {
final Recipe recipe = Recipe.of(handler, recipeIndex);
if (!recipe.getResults().isEmpty()) {
if (!recipe.getResults().isEmpty()
&& (!showOnlyFavorites || FavoriteRecipes.getFavorite(recipe.getRecipeId()) != null)) {
synchronized (availableRecipes) {
availableRecipes.put(recipe.getResult(), recipe.getRecipeId());
}
@@ -40,9 +40,15 @@ public class ItemHistoryPanel extends AbstractSubpanel<ItemsGrid<ItemHistoryPane
if (this.gridMask == null) {
this.gridMask = new ArrayList<>();
for (int slotIndex = 0; slotIndex < Math.min(size(), this.rows * this.columns); slotIndex++) {
this.gridMask.add(new HistoryGridSlot(slotIndex, slotIndex, getItem(slotIndex)));
int itemIndex = 0;
for (int slotIndex = 0; slotIndex < this.rows * this.columns && itemIndex < size(); slotIndex++) {
if (!isInvalidSlot(slotIndex)) {
this.gridMask.add(new HistoryGridSlot(slotIndex, itemIndex, getItem(itemIndex)));
itemIndex++;
}
}
ItemHistoryPanel.this.updateLinePadding();
}
return this.gridMask;
+14 -1
View File
@@ -16,6 +16,7 @@ import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import net.minecraft.client.Minecraft;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
@@ -30,6 +31,8 @@ import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.recipe.RecipeHandlerRef;
import codechicken.nei.recipe.RepairRecipeHandler;
import codechicken.nei.search.TooltipFilter;
import codechicken.nei.util.ItemUntranslator;
import cpw.mods.fml.common.FMLLog;
@@ -308,7 +311,13 @@ public class ItemList {
action.run();
if (stack.hasTagCompound() && hashOld != stack.stackTagCompound.hashCode()) {
FMLLog.warning("NEI: Forced tag update with reason (" + reason + ") for " + stack);
FMLLog.warning(
"NEI: Forced tag update with reason (" + reason
+ ") for "
+ stack
+ "("
+ stack.getItem()
+ ")");
}
}
@@ -330,6 +339,7 @@ public class ItemList {
runChecked(stack, () -> item.getToolClasses(stack), "getToolClasses");
runChecked(stack, () -> item.getUnlocalizedNameInefficiently(stack), "getUnlocalizedNameInefficiently");
runChecked(stack, () -> item.hasEffect(stack), "hasEffect");
runChecked(stack, () -> item.getDigSpeed(stack, Blocks.stone, 0), "getDigSpeed");
/*
* unused... for now runChecked(stack, () -> GameRegistry.getFuelValue(stack), "getFuelValue");
@@ -424,6 +434,9 @@ public class ItemList {
loadFinished = true;
RepairRecipeHandler.findRepairRecipesOnceParallel();
RecipeHandlerRef.clearCache();
FavoriteRecipes.reload();
SubsetWidget.updateHiddenItems();
ItemPanels.bookmarkPanel.load();
updateFilter.restart();
+250 -69
View File
@@ -1,8 +1,10 @@
package codechicken.nei;
import java.util.HashMap;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
@@ -15,6 +17,7 @@ import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityMobSpawner;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IIcon;
@@ -26,10 +29,27 @@ import cpw.mods.fml.relauncher.SideOnly;
public class ItemMobSpawner extends ItemBlock {
private static final Map<Integer, EntityLiving> entityHashMap = new HashMap<>();
private static final Map<Integer, String> IDtoNameMap = new HashMap<>();
public static int idPig;
private static boolean loaded;
private static final Map<Integer, EntityLiving> entityHashMap = new ConcurrentHashMap<>();
private static final Map<Integer, String> IDtoNameMap = new ConcurrentHashMap<>();
private static final Map<Class<? extends Entity>, String> ENTITY_CLASS_TO_NAME_CACHE = new ConcurrentHashMap<>();
public static int idPig = 90;
private static volatile boolean loaded = false;
// For asm
public static int placedX;
public static int placedY;
public static int placedZ;
public static void setLastPlacedPosition(int x, int y, int z) {
placedX = x;
placedY = y;
placedZ = z;
}
public static int[] getLastPlacedPosition() {
return new int[] { placedX, placedY, placedZ };
}
public ItemMobSpawner() {
super(Blocks.mob_spawner);
@@ -37,99 +57,260 @@ public class ItemMobSpawner extends ItemBlock {
MinecraftForgeClient.registerItemRenderer(this, new SpawnerRenderer());
}
/**
* These are ASM translated from BlockMobSpawner
*/
public static int placedX;
public static int placedY;
public static int placedZ;
@Override
public IIcon getIconFromDamage(int par1) {
public IIcon getIconFromDamage(int meta) {
return Blocks.mob_spawner.getBlockTextureFromSide(0);
}
public boolean onItemUse(ItemStack itemstack, EntityPlayer entityplayer, World world, int x, int y, int z, int par7,
float par8, float par9, float par10) {
if (super.onItemUse(itemstack, entityplayer, world, x, y, z, par7, par8, par9, par10) && world.isRemote) {
TileEntityMobSpawner tileentitymobspawner = (TileEntityMobSpawner) world
.getTileEntity(placedX, placedY, placedZ);
if (tileentitymobspawner != null) {
setDefaultTag(itemstack);
String mobtype = IDtoNameMap.get(itemstack.getItemDamage());
if (mobtype != null) {
NEICPH.sendMobSpawnerID(placedX, placedY, placedZ, mobtype);
tileentitymobspawner.func_145881_a().setEntityName(mobtype);
@Override
public boolean onItemUse(ItemStack itemstack, EntityPlayer entityplayer, World world, int x, int y, int z, int side,
float hitX, float hitY, float hitZ) {
placedX = x;
placedY = y;
placedZ = z;
boolean placed = super.onItemUse(itemstack, entityplayer, world, x, y, z, side, hitX, hitY, hitZ);
if (placed && !world.isRemote) {
TileEntity tileEntity = world.getTileEntity(x, y, z);
if (tileEntity instanceof TileEntityMobSpawner) {
TileEntityMobSpawner spawner = (TileEntityMobSpawner) tileEntity;
String mobType = getMobTypeFromItemStack(itemstack);
if (mobType != null) {
spawner.func_145881_a().setEntityName(mobType);
world.markBlockForUpdate(x, y, z);
NEICPH.sendMobSpawnerID(x, y, z, mobType);
}
}
return true;
}
return false;
return placed;
}
private String getMobTypeFromItemStack(ItemStack stack) {
int meta = getValidMetaData(stack);
return IDtoNameMap.get(meta);
}
private int getValidMetaData(ItemStack stack) {
int meta = stack.getItemDamage();
if (meta == 0 || !IDtoNameMap.containsKey(meta)) {
return idPig;
}
return meta;
}
@SideOnly(Side.CLIENT)
@Override
public void addInformation(ItemStack itemstack, EntityPlayer par2EntityPlayer, List<String> list, boolean par4) {
setDefaultTag(itemstack);
int meta = itemstack.getItemDamage();
if (meta == 0) {
meta = idPig;
public void addInformation(ItemStack itemstack, EntityPlayer player, List<String> tooltip, boolean advanced) {
int meta = getValidMetaData(itemstack);
EntityLiving entity = getEntity(meta);
String mobName = IDtoNameMap.get(meta);
if (entity != null && mobName != null) {
EnumChatFormatting color = (entity instanceof IMob) ? EnumChatFormatting.DARK_RED
: EnumChatFormatting.DARK_AQUA;
tooltip.add(color + mobName);
}
Entity e = getEntity(meta);
list.add(
(e instanceof IMob ? EnumChatFormatting.DARK_RED : EnumChatFormatting.DARK_AQUA)
+ IDtoNameMap.get(meta));
}
public static EntityLiving getEntity(int ID) {
EntityLiving e = entityHashMap.get(ID);
if (e == null) {
loadSpawners();
Class<?> clazz = EntityList.IDtoClassMapping.get(ID);
World world = NEIClientUtils.mc().theWorld;
try {
e = (EntityLiving) clazz.getConstructor(new Class[] { World.class }).newInstance(world);
} catch (Throwable t) {
if (clazz == null)
NEIClientConfig.logger.error("Null class for entity (" + ID + ", " + IDtoNameMap.get(ID));
else NEIClientConfig.logger.error("Error creating instance of entity: " + clazz.getName(), t);
e = getEntity(idPig);
}
entityHashMap.put(ID, e);
public static EntityLiving getEntity(int id) {
EntityLiving cached = entityHashMap.get(id);
if (cached != null) {
return cached;
}
return e;
loadSpawners();
Class<?> entityClass = EntityList.IDtoClassMapping.get(id);
World world = NEIClientUtils.mc() != null ? NEIClientUtils.mc().theWorld : null;
if (isInvalidEntityClass(entityClass)) {
return cacheFallback(id);
}
EntityLiving entity = createEntityInstance(entityClass, world, id);
if (entity != null) {
entityHashMap.put(id, entity);
}
return entity;
}
private static boolean isInvalidEntityClass(Class<?> entityClass) {
if (entityClass == null) {
return true;
}
int modifiers = entityClass.getModifiers();
if (Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers)) {
NEIClientConfig.logger.warn("Skipping abstract/interface entity class: {}", entityClass.getName());
return true;
}
if (!EntityLiving.class.isAssignableFrom(entityClass)) {
NEIClientConfig.logger.warn("Skipping non-EntityLiving class: {}", entityClass.getName());
return true;
}
return false;
}
@SuppressWarnings("unchecked")
private static EntityLiving createEntityInstance(Class<?> entityClass, World world, int id) {
if (entityClass == null || world == null) {
NEIClientConfig.logger.debug("World or entity class is null, using fallback for ID: {}", id);
return getFallbackEntity(id);
}
try {
Class<? extends EntityLiving> livingClass = (Class<? extends EntityLiving>) entityClass;
return livingClass.getConstructor(World.class).newInstance(world);
} catch (Throwable t) {
logEntityCreationError(entityClass, id, t);
return getFallbackEntity(id);
}
}
private static void logEntityCreationError(Class<?> entityClass, int id, Throwable t) {
String entityName = IDtoNameMap.getOrDefault(id, "unknown");
if (entityClass == null) {
NEIClientConfig.logger
.error("Failed to create entity instance: Class is null for ID {}, Name {}", id, entityName, t);
} else {
NEIClientConfig.logger.error(
"Failed to create instance of entity: Class {}, ID {}, Name {}",
entityClass.getName(),
id,
entityName,
t);
}
}
private static EntityLiving cacheFallback(int id) {
EntityLiving fallback = getFallbackEntity(id);
if (fallback != null) {
entityHashMap.put(id, fallback);
}
return fallback;
}
private static EntityLiving getFallbackEntity(int originalId) {
EntityLiving pig = entityHashMap.get(idPig);
if (pig == null) {
World world = NEIClientUtils.mc() != null ? NEIClientUtils.mc().theWorld : null;
if (world != null) {
try {
pig = new EntityPig(world);
entityHashMap.put(idPig, pig);
NEIClientConfig.logger.debug("Created fallback pig entity for ID: {}", originalId);
} catch (Exception e) {
NEIClientConfig.logger
.error("Failed to create fallback pig entity for original ID: {}", originalId, e);
}
} else {
NEIClientConfig.logger.warn("World is null, cannot create fallback entity for ID: {}", originalId);
}
}
return pig;
}
public static void clearEntityReferences() {
entityHashMap.clear();
NEIClientConfig.logger.debug("Cleared all entity references from cache");
}
private void setDefaultTag(ItemStack itemstack) {
if (!IDtoNameMap.containsKey(itemstack.getItemDamage())) itemstack.setItemDamage(idPig);
}
@SuppressWarnings("unchecked")
public static void loadSpawners() {
if (loaded) return;
loaded = true;
for (Map.Entry<Class<? extends Entity>, String> entry : EntityList.classToStringMapping.entrySet()) {
final Class<? extends Entity> clazz = entry.getKey();
if (EntityLiving.class.isAssignableFrom(clazz)) {
Integer id = (Integer) EntityList.classToIDMapping.get(clazz);
if (id == null) continue;
String name = entry.getValue();
if (name == null) continue;
if (name.equals("EnderDragon")) continue;
if (name.equals("Pig")) idPig = id;
if (clazz != EntityPig.class || name.equals("Pig")) {
IDtoNameMap.put(id, name);
if (loaded) {
return;
}
synchronized (ItemMobSpawner.class) {
try {
for (Map.Entry<Class<? extends Entity>, String> entry : ((Map<Class<? extends Entity>, String>) EntityList.classToStringMapping)
.entrySet()) {
Class<? extends Entity> clazz = entry.getKey();
String name = entry.getValue();
if (shouldRegisterEntity(clazz, name)) {
Integer id = (Integer) EntityList.classToIDMapping.get(clazz);
if (id != null) {
IDtoNameMap.put(id, name);
ENTITY_CLASS_TO_NAME_CACHE.put(clazz, name);
if ("Pig".equals(name)) {
idPig = id;
NEIClientConfig.logger.debug("Set pig entity ID to: {}", id);
}
}
}
}
loaded = true;
NEIClientConfig.logger.info("Loaded {} spawner entity mappings", IDtoNameMap.size());
} catch (Exception e) {
NEIClientConfig.logger.error("Error loading spawners from entity list", e);
}
}
}
private static boolean shouldRegisterEntity(Class<? extends Entity> clazz, String name) {
if (clazz == null || name == null || name.trim().isEmpty()) {
return false;
}
if (!EntityLiving.class.isAssignableFrom(clazz)) {
return false;
}
if ("EnderDragon".equals(name) || "Giant".equals(name)) {
return false;
}
return true;
}
@Override
public void getSubItems(Item item, CreativeTabs tab, List<ItemStack> list) {
if (!NEIClientConfig.hasSMPCounterPart()) list.add(new ItemStack(item));
else for (int i : IDtoNameMap.keySet()) list.add(new ItemStack(item, 1, i));
if (!NEIClientConfig.hasSMPCounterPart()) {
list.add(new ItemStack(item));
} else {
loadSpawners();
for (int id : IDtoNameMap.keySet()) {
ItemStack stack = new ItemStack(item, 1, id);
list.add(stack);
}
}
}
public static String getEntityNameForMeta(int meta) {
loadSpawners();
return IDtoNameMap.getOrDefault(meta, IDtoNameMap.getOrDefault(idPig, "Pig"));
}
public static boolean isValidEntityMeta(int meta) {
loadSpawners();
return IDtoNameMap.containsKey(meta) || meta == 0;
}
public static Map<Integer, String> getRegisteredSpawnerEntities() {
loadSpawners();
return Collections.unmodifiableMap(IDtoNameMap);
}
public static boolean isEntityValidForSpawner(Class<? extends Entity> entityClass) {
if (entityClass == null) return false;
String name = ENTITY_CLASS_TO_NAME_CACHE.get(entityClass);
if (name == null) {
name = (String) EntityList.classToStringMapping.get(entityClass);
}
return name != null && shouldRegisterEntity(entityClass, name);
}
}
+27 -23
View File
@@ -75,7 +75,13 @@ public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
}
public static void updateItemList(ArrayList<ItemStack> newItems) {
ItemPanels.itemPanel.getGrid().setItems(newItems);
final ItemsPanelGrid grid = ItemPanels.itemPanel.getGrid();
if (grid.rawItems.size() != newItems.size()) {
grid.setPage(0);
}
grid.setItems(newItems);
ItemPanels.itemPanel.realItems = newItems;
}
@@ -115,31 +121,29 @@ public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
return String.format("%d/%d", getPage(), Math.max(1, getNumPages()));
}
public Rectangle4i calculateBounds() {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
final int width = (gui.width - gui.xSize) / 2 - PADDING * 2;
final Rectangle4i bounds = new Rectangle4i(
(gui.width + gui.xSize) / 2 + PADDING,
PADDING,
(gui.width - 176) / 2 - PADDING * 2,
gui.height - PADDING * 2);
@Override
public Rectangle4i calculateBounds(GuiContainer gui) {
final int maxWidth = (gui.width - 176) / 2 - PADDING * 2;
final int maxHeight = gui.height - PADDING * 2;
final int freeSpace = (gui.width - gui.xSize) / 2 - PADDING * 2;
int paddingLeft = (int) Math
.ceil(bounds.w * NEIClientConfig.getSetting("world.panels.items.left").getIntValue() / 100000.0);
int paddingTop = (int) Math
.ceil(bounds.h * NEIClientConfig.getSetting("world.panels.items.top").getIntValue() / 100000.0);
int paddingRight = (int) Math
.ceil(bounds.w * NEIClientConfig.getSetting("world.panels.items.right").getIntValue() / 100000.0);
int paddingBottom = (int) Math
.ceil(bounds.h * NEIClientConfig.getSetting("world.panels.items.bottom").getIntValue() / 100000.0);
final int paddingLeft = (int) Math
.ceil(maxWidth * NEIClientConfig.getSetting("world.panels.items.left").getIntValue() / 100000.0);
final int paddingTop = (int) Math
.ceil(maxHeight * NEIClientConfig.getSetting("world.panels.items.top").getIntValue() / 100000.0);
final int paddingRight = (int) Math
.ceil(maxWidth * NEIClientConfig.getSetting("world.panels.items.right").getIntValue() / 100000.0);
final int paddingBottom = (int) Math
.ceil(maxHeight * NEIClientConfig.getSetting("world.panels.items.bottom").getIntValue() / 100000.0);
bounds.h = Math.max(ItemsGrid.SLOT_SIZE, bounds.h - paddingTop - paddingBottom);
bounds.y = bounds.y + Math.min(paddingTop, bounds.h - ItemsGrid.SLOT_SIZE);
final int width = Math.max(
ItemsGrid.SLOT_SIZE,
snapDownToMultiple(
Math.min(freeSpace - paddingRight, maxWidth - paddingLeft - paddingRight),
ItemsGrid.SLOT_SIZE));
final int height = Math.max(ItemsGrid.SLOT_SIZE, maxHeight - paddingTop - paddingBottom);
bounds.w = Math.max(ItemsGrid.SLOT_SIZE, Math.min(bounds.w - paddingLeft - paddingRight, width - paddingRight));
bounds.x = bounds.x + Math.max(0, width - bounds.w - paddingRight);
return bounds;
return new Rectangle4i(gui.width - width - PADDING - paddingRight, paddingTop + PADDING, width, height);
}
@Override
@@ -15,7 +15,6 @@ import net.minecraft.client.shader.Framebuffer;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL30;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.api.GuiInfo;
@@ -85,21 +84,6 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
} else {
this.framebuffer.framebufferClear();
}
// copy depth buffer from MC (fix Angelica)
OpenGlHelper.func_153171_g(GL30.GL_READ_FRAMEBUFFER, minecraft.getFramebuffer().framebufferObject);
OpenGlHelper.func_153171_g(GL30.GL_DRAW_FRAMEBUFFER, this.framebuffer.framebufferObject);
GL30.glBlitFramebuffer(
0,
0,
minecraft.displayWidth,
minecraft.displayHeight,
0,
0,
minecraft.displayWidth,
minecraft.displayHeight,
GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT,
GL11.GL_NEAREST);
}
public void renderCapturedScreen() {
@@ -70,7 +70,7 @@ public class ItemsPanelGrid extends ItemsGrid<ItemsPanelGrid.ItemsPanelGridSlot,
}
public ArrayList<ItemStack> newItems;
public ArrayList<ItemStack> rawItems;
public ArrayList<ItemStack> rawItems = new ArrayList<>();
protected List<ItemsPanelGridSlot> gridMask;
protected final Map<Integer, Integer> itemToGroup = new HashMap<>();
@@ -70,8 +70,8 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
}
public void setActiveStack(ItemStack activeStack) {
final ItemStack realStack = items.stream()
.filter(stack -> NEIClientUtils.areStacksSameTypeWithNBT(stack, activeStack)).findFirst().orElse(null);
final ItemStack realStack = items.stream().filter(stack -> NEIClientUtils.areStacksSameType(stack, activeStack))
.findFirst().orElse(null);
this.activeStackIndex = items.indexOf(realStack);
}
@@ -66,9 +66,9 @@ import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.guihook.IContainerObjectHandler;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.recipe.AutoCraftingManager;
import codechicken.nei.recipe.DebugHandlerWidget;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.RecipeCatalysts;
import codechicken.nei.recipe.debug.DebugHandlerWidget;
public class LayoutManager implements IContainerInputHandler, IContainerTooltipHandler, IContainerDrawHandler,
IContainerObjectHandler, IKeyStateTracker {
@@ -92,7 +92,6 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public static SubsetWidget dropDown;
public static SearchField searchField;
public static ItemZoom itemZoom;
public static DebugHandlerWidget recipeHandlerWidget;
public static ButtonCycled options;
public static ButtonCycled bookmarksButton;
@@ -104,7 +103,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public static Button delete;
public static ButtonCycled gamemode;
public static Button rain;
public static Button magnet;
public static ButtonCycled magnet;
public static Button[] timeButtons = new Button[4];
public static Button heal;
@@ -406,8 +405,6 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
itemZoom = new ItemZoom();
recipeHandlerWidget = new DebugHandlerWidget();
dropDown = new SubsetWidget();
searchField = new SearchField("search");
API.addItemFilter(searchField);
@@ -600,7 +597,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
return getStateTip("rain", state);
}
};
magnet = new Button() {
magnet = new ButtonCycled(2) {
@Override
public boolean onButtonPress(boolean rightclick) {
@@ -786,8 +783,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
addWidget(dropDown);
}
addWidget(recipeHandlerWidget);
recipeHandlerWidget.setVisible();
addWidget(DebugHandlerWidget.instance);
}
public static LayoutStyle getLayoutStyle(int id) {
@@ -907,6 +903,9 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
final int ty2 = ty + 20 - h2 - te;
final int tx2 = 200 - w2 - te;
final boolean is2DTexture = GL11.glGetBoolean(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_TEXTURE_2D);
changeTexture("textures/gui/widgets.png");
drawTexturedModalRect(x, y, tx1, ty1, w1, h1); // top left
drawTexturedModalRect(x, y2, tx1, ty2, w1, h2); // bottom left
@@ -919,6 +918,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
drawTexturedModalRect(x2, y, tx2, ty1, w2, h1); // top right
drawTexturedModalRect(x2, y2, tx2, ty2, w2, h2); // bottom right
if (!is2DTexture) GL11.glDisable(GL11.GL_TEXTURE_2D);
}
public static void drawItemPresenceOverlay(int slotX, int slotY, boolean isPresent, boolean slotHighlight) {
@@ -31,7 +31,8 @@ public class LayoutStyleMinecraft extends LayoutStyle {
LayoutManager.gamemode.icons[0] = new Image(132, 12, 12, 12);
LayoutManager.gamemode.icons[1] = new Image(156, 12, 12, 12);
LayoutManager.gamemode.icons[2] = new Image(168, 12, 12, 12);
LayoutManager.magnet.icon = new Image(180, 24, 12, 12);
LayoutManager.magnet.icons[0] = new Image(180, 24, 12, 12);
LayoutManager.magnet.icons[1] = new Image(180, 36, 12, 12);
LayoutManager.timeButtons[0].icon = new Image(132, 24, 12, 12);
LayoutManager.timeButtons[1].icon = new Image(120, 24, 12, 12);
LayoutManager.timeButtons[2].icon = new Image(144, 24, 12, 12);
@@ -86,6 +87,7 @@ public class LayoutStyleMinecraft extends LayoutStyle {
LayoutManager.options.index = NEIClientConfig.getCheatMode();
LayoutManager.magnet.state = 0x4 | (NEIClientConfig.getMagnetMode() ? 1 : 0);
LayoutManager.magnet.index = (LayoutManager.magnet.state & 0x1) != 0 ? 1 : 0;
if (NEIClientConfig.canPerformAction("delete")) {
layoutButton(LayoutManager.delete);
@@ -56,12 +56,10 @@ import codechicken.nei.config.OptionToggleButtonBoubs;
import codechicken.nei.config.OptionUtilities;
import codechicken.nei.config.preset.GuiPresetList;
import codechicken.nei.event.NEIConfigsLoadedEvent;
import codechicken.nei.recipe.DebugHandlerWidget;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.IRecipeHandler;
import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.recipe.RecipeCatalysts;
import codechicken.nei.recipe.RecipeInfo;
import codechicken.nei.util.ItemUntranslator;
import codechicken.nei.util.NEIKeyboardUtils;
import codechicken.obfuscator.ObfuscationRun;
@@ -149,6 +147,7 @@ public class NEIClientConfig {
API.addOption(new OptionToggleButton("inventory.widgetsenabled"));
tag.getTag("findFuelsParallel").getBooleanValue(true);
tag.getTag("showRepairOnlyForDamageableItems").getBooleanValue(true);
tag.getTag("inventory.autocrafting").getBooleanValue(true);
tag.getTag("inventory.dynamicFontSize").getBooleanValue(true);
@@ -225,13 +224,17 @@ public class NEIClientConfig {
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.bookmarks.bookmarkItemsWithRecipe", true));
tag.getTag("inventory.bookmarks.bookmarkRecipeWithCount").setComment("Bookmark recipe with count")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.bookmarks.bookmarkRecipeWithCount", true));
tag.getTag("inventory.guirecipe.jeiStyleTabs").setComment("Enable/disable JEI Style Tabs")
.getBooleanValue(true);
API.addOption(new OptionToggleButtonBoubs("inventory.guirecipe.jeiStyleTabs", true));
tag.getTag("inventory.guirecipe.jeiStyleRecipeCatalyst").setComment("Enable/disable JEI Style Recipe Catalysts")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.guirecipe.jeiStyleRecipeCatalyst", true));
tag.getTag("inventory.guirecipe.jeiStyleRecipeCatalyst")
.setComment("JEI Style Recipe Catalysts (0 - none, 1 - grid, 2 - scroll)").getIntValue(1);
API.addOption(new OptionCycled("inventory.guirecipe.jeiStyleRecipeCatalyst", 3, true));
tag.getTag("inventory.guirecipe.cycledIngredientsTooltip").setComment("Show cycled ingredients tooltip")
.getBooleanValue(true);
@@ -292,6 +295,10 @@ public class NEIClientConfig {
tag.getTag("inventory.craftables.useRows").setComment("Rows used in craftables areas").getIntValue(2);
API.addOption(new OptionIntegerField("inventory.craftables.useRows", 1, 5));
tag.getTag("inventory.craftables.favoritesOnly").setComment("Show Only Favorites Recipes")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.craftables.favoritesOnly", true));
tag.getTag("inventory.collapsibleItems.enabled").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.collapsibleItems.enabled", true) {
@@ -774,8 +781,7 @@ public class NEIClientConfig {
@Override
public boolean onClick(int button) {
super.onClick(button);
FavoriteRecipes.save();
FavoriteRecipes.load();
FavoriteRecipes.reload();
return true;
}
});
@@ -788,7 +794,19 @@ public class NEIClientConfig {
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.favorites.showRecipeTooltipInGui", true));
tag.getTag("inventory.favorites.depth").setComment("Bookmark creation depth").getIntValue(3);
tag.getTag("inventory.favorites.generateSingleRecipeFavorites")
.setComment("Automatically generate favorites for items with only one recipe").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.favorites.generateSingleRecipeFavorites", true) {
@Override
public boolean onClick(int button) {
super.onClick(button);
FavoriteRecipes.loadAutoGeneratedRecipes();
return true;
}
});
tag.getTag("inventory.favorites.depth").setComment("Bookmark creation depth").getIntValue(9);
API.addOption(new OptionIntegerField("inventory.favorites.depth", 0, 100));
}
@@ -808,6 +826,7 @@ public class NEIClientConfig {
API.addHashBind("gui.search", Keyboard.KEY_F);
API.addKeyBind("gui.bookmark", Keyboard.KEY_A);
API.addHashBind("gui.favorite", Keyboard.KEY_F + NEIClientUtils.SHIFT_HASH);
API.addKeyBind("gui.favorite_item", Keyboard.KEY_F);
API.addHashBind("gui.remove_recipe", Keyboard.KEY_A + NEIClientUtils.SHIFT_HASH);
API.addKeyBind("gui.bookmark_pull_items", Keyboard.KEY_V);
API.addKeyBind("gui.overlay", Keyboard.KEY_S);
@@ -843,24 +862,27 @@ public class NEIClientConfig {
}
public static void loadWorld(String worldPath) {
final File specificDir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
final boolean newWorld = !specificDir.exists();
unloadWorld();
setInternalEnabled(true);
if (!worldPath.equals(NEIClientConfig.worldPath)) {
if (!worldPath.equals(NEIClientConfig.worldPath) || newWorld) {
NEIClientConfig.worldPath = worldPath;
logger.debug("Loading " + (Minecraft.getMinecraft().isSingleplayer() ? "Local" : "Remote") + " World");
final File specificDir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
final boolean newWorld = !specificDir.exists();
if (newWorld) {
specificDir.mkdirs();
}
world = new ConfigSet(new File(specificDir, "NEI.dat"), new ConfigFile(new File(specificDir, "NEI.cfg")));
if (newWorld && Minecraft.getMinecraft().isSingleplayer()) {
world.config.getTag("inventory.cheatmode")
.setIntValue(NEIClientUtils.mc().playerController.isInCreativeMode() ? 2 : 0);
}
bootNEI();
onWorldLoad(newWorld);
onWorldLoad();
}
}
@@ -868,7 +890,7 @@ public class NEIClientConfig {
return NEIClientConfig.worldPath;
}
private static void onWorldLoad(boolean newWorld) {
private static void onWorldLoad() {
world.config.setComment(
"World based configuration of NEI.\nMost of these options can be changed ingame.\nDeleting any element will restore it to it's default value");
@@ -876,12 +898,6 @@ public class NEIClientConfig {
creativeInv = new ItemStack[54];
LayoutManager.searchField.setText(getSearchExpression());
LayoutManager.quantity.setText(Integer.toString(getItemQuantity()));
if (newWorld && Minecraft.getMinecraft().isSingleplayer()) {
world.config.getTag("inventory.cheatmode")
.setIntValue(NEIClientUtils.mc().playerController.isInCreativeMode() ? 2 : 0);
}
NEIInfo.load(ClientUtils.getWorld());
}
@@ -906,12 +922,7 @@ public class NEIClientConfig {
SubsetWidget.saveHidden();
FavoriteRecipes.save();
CollapsibleItems.saveStates();
if (world != null) {
world.saveNBT();
NEIClientConfig.worldPath = null;
world = null;
}
world.saveNBT();
}
private static final Map<String, String> keySettings = new HashMap<>();
@@ -966,7 +977,6 @@ public class NEIClientConfig {
// main NEI config loading
ItemInfo.load();
GuiInfo.load();
RecipeInfo.load();
HeldItemHandler.load();
LayoutManager.load();
NEIController.load();
@@ -998,7 +1008,6 @@ public class NEIClientConfig {
SubsetWidget.loadHidden();
CollapsibleItems.load();
ItemSorter.loadConfig();
FavoriteRecipes.load();
// Set pluginNEIConfigLoaded here before posting the NEIConfigsLoadedEvent. This used to be the
// other way around, but apparently if your modpack includes 800 mods the event poster might not
@@ -1007,8 +1016,6 @@ public class NEIClientConfig {
// API. I don't expect any handler to do this, but who knows what modders have come up with...
pluginNEIConfigLoaded = true;
MinecraftForge.EVENT_BUS.post(new NEIConfigsLoadedEvent());
DebugHandlerWidget.loadHandlerInfoPatch();
ItemList.loadItems.restart();
}
}.start();
@@ -1105,8 +1112,8 @@ public class NEIClientConfig {
return getBooleanSetting("inventory.guirecipe.slotHighlightPresent");
}
public static boolean areJEIStyleRecipeCatalystsVisible() {
return getBooleanSetting("inventory.guirecipe.jeiStyleRecipeCatalyst");
public static int getJEIStyleRecipeCatalysts() {
return getIntSetting("inventory.guirecipe.jeiStyleRecipeCatalyst");
}
public static boolean useCreativeTabStyle() {
@@ -11,7 +11,6 @@ import static codechicken.nei.NEIClientConfig.world;
import java.awt.Color;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
@@ -47,6 +46,7 @@ import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import com.google.common.collect.Iterables;
import com.gtnewhorizon.gtnhlib.util.numberformatting.NumberFormatUtil;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.inventory.InventoryRange;
@@ -126,16 +126,22 @@ public class NEIClientUtils extends NEIServerUtils {
});
}
public static String formatNumbers(BigInteger aNumber) {
public static String formatNumber(long aNumber) {
if (NEIModContainer.isGTNHLibLoaded()) {
return NumberFormatUtil.formatNumber(aNumber);
}
return getDecimalFormat().format(aNumber);
}
public static String formatNumbers(long aNumber) {
return getDecimalFormat().format(aNumber);
}
public static String formatFluid(long aNumber) {
public static String formatNumbers(double aNumber) {
return getDecimalFormat().format(aNumber);
if (NEIModContainer.isGTNHLibLoaded()) {
return NumberFormatUtil.formatFluid(aNumber);
}
return getDecimalFormat().format(aNumber) + " L";
}
public static void deleteHeldItem() {
@@ -198,7 +204,7 @@ public class NEIClientUtils extends NEIServerUtils {
public static void cheatItem(ItemStack stack, int button, int mode) {
if (!canCheatItem(stack)) return;
if (mode == -1 && button == 0 && shiftKey() && NEIClientConfig.hasSMPCounterPart()) {
if (mode == -1 && button == 0 && controlKey() && NEIClientConfig.hasSMPCounterPart()) {
for (IInfiniteItemHandler handler : ItemInfo.infiniteHandlers) {
if (!handler.canHandleItem(stack)) continue;
@@ -413,18 +419,11 @@ public class NEIClientUtils extends NEIServerUtils {
if (textWidth > containerWidth) {
int dots = fontRenderer.getStringWidth("...");
if (containerWidth > dots) {
textWidth += dots;
while (textWidth > containerWidth) {
textWidth -= fontRenderer.getCharWidth(text.charAt(text.length() - 1));
text = text.substring(0, text.length() - 1);
}
return text + "...";
if (containerWidth <= dots) {
return "...";
}
return "...";
return fontRenderer.trimStringToWidth(text, containerWidth - dots) + "...";
}
return text;
@@ -14,6 +14,7 @@ import net.minecraft.item.ItemStack;
import net.minecraftforge.client.ClientCommandHandler;
import codechicken.core.CommonUtils;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.api.API;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.IInfiniteItemHandler;
@@ -156,20 +157,32 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
if (GuiInfo.hasCustomSlots(gui)) return false;
if (slotIndex >= 0 && NEIClientUtils.shiftKey()
&& NEIClientUtils.getHeldItem() != null
&& !slot.getHasStack()) {
ItemStack held = NEIClientUtils.getHeldItem();
manager.handleSlotClick(slot.slotNumber, button, 0);
if (slot.isItemValid(held) && !ItemInfo.fastTransferExemptions.contains(slot.getClass()))
fastTransferManager.performMassTransfer(gui, pickedUpFromSlot, slotIndex, held);
if (NEIClientUtils.shiftKey()) {
// fix small mouse movement while clicking causing slotIndex to be -999
if (slotIndex == -999) {
final Point mouse = GuiDraw.getMousePosition();
slot = gui.getSlotAtPosition(mouse.x, mouse.y);
return true;
}
if (slot != null) {
slotIndex = slot.slotNumber;
}
}
if (slotIndex == -999 && NEIClientUtils.shiftKey() && button == 0) {
fastTransferManager.throwAll(gui, pickedUpFromSlot);
return true;
if (slotIndex >= 0 && NEIClientUtils.getHeldItem() != null && !slot.getHasStack()) {
final ItemStack held = NEIClientUtils.getHeldItem();
manager.handleSlotClick(slot.slotNumber, button, 0);
if (slot.isItemValid(held) && !ItemInfo.fastTransferExemptions.contains(slot.getClass())) {
fastTransferManager.performMassTransfer(gui, pickedUpFromSlot, slotIndex, held);
}
return true;
}
if (slotIndex == -999 && button == 0) {
fastTransferManager.throwAll(gui, pickedUpFromSlot);
return true;
}
}
return false;
@@ -7,8 +7,7 @@ import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import net.minecraft.util.EnumChatFormatting;
import java.util.concurrent.CopyOnWriteArrayList;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
@@ -18,6 +17,7 @@ import codechicken.core.launch.CodeChickenCorePlugin;
import codechicken.nei.api.IConfigureNEI;
import codechicken.nei.asm.NEICorePlugin;
import codechicken.nei.config.IMCHandler;
import codechicken.nei.guihook.HideousLinkedList;
import codechicken.nei.recipe.GuiRecipeTab;
import cpw.mods.fml.client.FMLFileResourcePack;
import cpw.mods.fml.client.FMLFolderResourcePack;
@@ -31,13 +31,15 @@ import cpw.mods.fml.common.event.FMLInterModComms;
import cpw.mods.fml.common.event.FMLLoadCompleteEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.event.FMLServerAboutToStartEvent;
import cpw.mods.fml.common.versioning.ArtifactVersion;
import cpw.mods.fml.common.versioning.VersionParser;
import cpw.mods.fml.common.versioning.VersionRange;
@SuppressWarnings("UnstableApiUsage")
public class NEIModContainer extends DummyModContainer {
public static LinkedList<IConfigureNEI> plugins = new LinkedList<>();
public static final LinkedList<IConfigureNEI> plugins = new HideousLinkedList<>(new CopyOnWriteArrayList<>());
private static boolean gregTech5Loaded;
private static boolean gtnhLibLoaded;
@@ -46,7 +48,6 @@ public class NEIModContainer extends DummyModContainer {
public NEIModContainer() {
super(getModMetadata());
loadMetadata();
}
private static ModMetadata getModMetadata() {
@@ -54,7 +55,7 @@ public class NEIModContainer extends DummyModContainer {
modMetadata.name = "NotEnoughItems";
modMetadata.modId = "NotEnoughItems";
modMetadata.version = Tags.VERSION;
modMetadata.authorList = Arrays.asList("ChickenBones", "mitchej123");
modMetadata.authorList = Arrays.asList("ChickenBones", "mitchej123", "SLPrime");
modMetadata.url = "https://github.com/GTNewHorizons/NotEnoughItems";
modMetadata.description = "Recipe Viewer, Inventory Manager, Item Spawner, Cheats and more; GTNH Version includes many enhancements.";
return modMetadata;
@@ -79,36 +80,12 @@ public class NEIModContainer extends DummyModContainer {
public List<ArtifactVersion> getDependencies() {
List<ArtifactVersion> deps = new ArrayList<>();
deps.add(VersionParser.parseVersionReference("CodeChickenCore@[" + codechicken.core.asm.Tags.VERSION + ",)"));
deps.add(VersionParser.parseVersionReference("gtnhlib@[0.6.0,)"));
deps.add(VersionParser.parseVersionReference("gtnhlib@[0.9.6,)"));
return deps;
}
private String description;
private void loadMetadata() {
description = super.getMetadata().description.replace("Supporters:", EnumChatFormatting.AQUA + "Supporters:");
}
@Override
public ModMetadata getMetadata() {
StringBuilder s_plugins = new StringBuilder();
if (plugins.size() == 0) {
s_plugins.append(EnumChatFormatting.RED).append("No installed plugins.");
} else {
s_plugins.append(EnumChatFormatting.GREEN).append("Installed plugins: ");
for (int i = 0; i < plugins.size(); i++) {
if (i > 0) s_plugins.append(", ");
IConfigureNEI plugin = plugins.get(i);
s_plugins.append(plugin.getName()).append(" ").append(plugin.getVersion());
}
s_plugins.append(".");
}
ModMetadata meta = super.getMetadata();
meta.description = description.replace("<plugins>", s_plugins.toString());
return meta;
}
@Override
public boolean registerBus(EventBus bus, LoadController controller) {
bus.register(this);
@@ -125,8 +102,10 @@ public class NEIModContainer extends DummyModContainer {
@Subscribe
public void init(FMLInitializationEvent event) {
if (CommonUtils.isClient()) ClientHandler.load();
if (CommonUtils.isClient()) {
ClientHandler.load();
IMCForNEI.IMCSender();
}
ServerHandler.load();
}
@@ -147,6 +126,11 @@ public class NEIModContainer extends DummyModContainer {
}
}
@Subscribe
public void onServerAboutToStart(FMLServerAboutToStartEvent event) {
NEIServerConfig.resetFirstLoad();
}
@Subscribe
public void handleIMCMessages(FMLInterModComms.IMCEvent event) {
IMCHandler.processIMC(event.getMessages());
@@ -18,7 +18,6 @@ import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.permission.PermissionLevel;
@@ -37,21 +36,23 @@ import codechicken.lib.packet.PacketCustom;
public class NEIServerConfig {
private static MinecraftServer server;
private static boolean firstLoad;
public static Logger logger = LogManager.getLogger("NotEnoughItems");
public static File saveDir;
public static ConfigFile serverConfig;
public static Map<Integer, NBTTagCompound> dimTags = new HashMap<>();
public static HashMap<String, PlayerSave> playerSaves = new HashMap<>();
public static ItemStackMap<Set<String>> bannedItems = new ItemStackMap<>();
private static boolean doesPermAPIExist = false;
public static void resetFirstLoad() {
firstLoad = true;
}
public static void load(World world) {
if (MinecraftServer.getServer() != server) {
if (firstLoad) {
firstLoad = false;
logger.debug("Loading NEI Server");
server = MinecraftServer.getServer();
saveDir = new File(DimensionManager.getCurrentSaveRootDirectory(), "NEI");
dimTags.clear();
@@ -51,15 +51,18 @@ import cpw.mods.fml.relauncher.ReflectionHelper;
public class NEIServerUtils {
private static Class<?> gtMetaBaseItem;
private static class GTMetaBaseItemHolder {
static {
try {
final ClassLoader loader = NEIServerUtils.class.getClassLoader();
NEIServerUtils.gtMetaBaseItem = ReflectionHelper
.getClass(loader, "gregtech.api.items.MetaBaseItem", "gregtech.api.items.GT_MetaBase_Item");
} catch (Exception ignored) {
/* Do nothing */
private static final Class<?> gtMetaBaseItem = loadMetaBaseItem();
private static Class<?> loadMetaBaseItem() {
try {
final ClassLoader loader = NEIServerUtils.class.getClassLoader();
return ReflectionHelper
.getClass(loader, "gregtech.api.items.MetaBaseItem", "gregtech.api.items.GT_MetaBase_Item");
} catch (Exception ignored) {
return null;
}
}
}
@@ -180,7 +183,7 @@ public class NEIServerUtils {
public static boolean areStacksSameTypeWithNBT(ItemStack stack1, ItemStack stack2) {
return stack1 != null && stack2 != null
&& stack1.getItem() == stack2.getItem()
&& (!stack2.getHasSubtypes() || stack2.getItemDamage() == stack1.getItemDamage())
&& (stack2.isItemStackDamageable() || stack2.getItemDamage() == stack1.getItemDamage())
&& NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound());
}
@@ -231,7 +234,8 @@ public class NEIServerUtils {
* @return
*/
public static boolean isItemTool(ItemStack stack) {
return NEIServerUtils.gtMetaBaseItem != null && NEIServerUtils.gtMetaBaseItem.isInstance(stack.getItem());
return GTMetaBaseItemHolder.gtMetaBaseItem != null
&& GTMetaBaseItemHolder.gtMetaBaseItem.isInstance(stack.getItem());
}
/**
@@ -82,10 +82,14 @@ public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ?
public abstract String getLabelText();
public abstract Rectangle4i calculateBounds();
public abstract Rectangle4i calculateBounds(GuiContainer gui);
protected static int snapDownToMultiple(int value, int multiple) {
return (value / multiple) * multiple;
}
public void resize(GuiContainer gui) {
final Rectangle4i bounds = calculateBounds();
final Rectangle4i bounds = calculateBounds(gui);
x = bounds.x;
y = bounds.y;
@@ -104,7 +104,7 @@ public class PositionedStack {
items = filteringPermutations(items, GuiRecipe.getSearchItemFilter());
items = filteringPermutations(items, additionalFilter);
items.sort(Comparator.comparing(FavoriteRecipes::contains).reversed());
items.sort(Comparator.comparing(FavoriteRecipes::containsManual).reversed());
return items;
}
@@ -117,7 +117,7 @@ public class PositionedStack {
public int getPermutationIndex(ItemStack stack) {
for (int index = 0; index < this.items.length; index++) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(items[index], stack)) {
if (NEIServerUtils.areStacksSameType(items[index], stack)) {
return index;
}
}
@@ -146,7 +146,7 @@ public class PositionedStack {
}
public boolean contains(int mx, int my) {
return this.relx <= mx && this.rely <= my && this.relx + 16 >= mx && this.rely + 16 >= my;
return mx >= this.relx - 1 && mx < this.relx + 17 && my >= this.rely - 1 && my < this.rely + 17;
}
public boolean contains(ItemStack ingredient) {
+12 -5
View File
@@ -222,7 +222,6 @@ public class SearchField extends TextField implements ItemFilterProvider {
public void onTextChange(String oldText) {
final String newText = text();
if (!newText.equals(oldText)) {
if (newText.length() > 0) NEIClientConfig.logger.debug("Searching for " + newText);
NEIClientConfig.setSearchExpression(newText);
ItemList.updateFilter.restart();
}
@@ -315,6 +314,9 @@ public class SearchField extends TextField implements ItemFilterProvider {
public static String getEscapedSearchText(String text) {
text = EnumChatFormatting.getTextWithoutFormattingCodes(text);
boolean addQuotes = text.contains(" ")
&& NEIClientConfig.getBooleanSetting("inventory.search.quoteDropItemName");
switch (NEIClientConfig.getIntSetting("inventory.search.patternMode")) {
case 1:
text = text.replaceAll("[\\?|\\*]", "\\\\$0");
@@ -323,14 +325,19 @@ public class SearchField extends TextField implements ItemFilterProvider {
text = text.replaceAll("[{}()\\[\\].+*?^$\\\\|]", "\\\\$0");
break;
case 3:
text = text.replaceAll("\"", "\\\\$0");
text = "\"" + text + "\"";
return text;
// In extended+ quotes require only quotes to be escaped
if (addQuotes) {
text = text.replaceAll("\"", "\\\\$0");
} else {
String prefixes = searchParser.getPrefixes();
text = text.replaceAll("[-<>^{}|/\\\\\"" + Pattern.quote(prefixes) + "]", "\\\\$0");
}
break;
default:
break;
}
if (text.contains(" ") && NEIClientConfig.getBooleanSetting("inventory.search.quoteDropItemName")) {
if (addQuotes) {
text = "\"" + text + "\"";
}
@@ -468,7 +468,7 @@ public class SearchTokenParser {
return tokens;
}
private String getPrefixes() {
public String getPrefixes() {
if (this.prefixes == null) {
final StringBuilder builder = new StringBuilder();
@@ -21,10 +21,8 @@ import cpw.mods.fml.common.gameevent.TickEvent.Phase;
public class ServerHandler {
private static ServerHandler instance;
public static void load() {
instance = new ServerHandler();
ServerHandler instance = new ServerHandler();
PacketCustom.assignHandler(NEICPH.channel, new NEISPH());
FMLCommonHandler.instance().bus().register(instance);
+61 -107
View File
@@ -10,9 +10,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -53,9 +50,7 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
protected static final int MARGIN = 2;
protected static final char PREFIX = '%';
protected static ReentrantReadWriteLock hiddenItemLock = new ReentrantReadWriteLock();
protected static Lock hiddenWriteLock = hiddenItemLock.writeLock();
protected static Lock hiddenReadLock = hiddenItemLock.readLock();
private static final Object hiddenLock = new Object();
public static class SubsetTag {
@@ -377,11 +372,18 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
}
final AnyMultiItemFilter filter = new AnyMultiItemFilter();
final Set<ItemStack> filteredItems = new HashSet<>();
final List<SubsetTag> snapshot;
for (SubsetTag tag : tags.values()) {
synchronized (tags) {
snapshot = new ArrayList<>(tags.values());
}
for (SubsetTag tag : snapshot) {
if (tag.filter != null && matches(tag.path, searchText, pattern)) {
filteredItems.addAll(tag.items);
filter.filters.add(tag.filter);
synchronized (tag.items) {
filteredItems.addAll(tag.items);
filter.filters.add(tag.filter);
}
}
}
@@ -414,6 +416,7 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
* All operations on this variable should be synchronised.
*/
private static final ItemStackSet hiddenItems = new ItemStackSet();
private static final Map<String, SubsetTag> tags = new HashMap<>();
private static final SubsetTag root = new SubsetTag("");
protected static boolean enableSearchBySubsets = false;
@@ -436,6 +439,7 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
}
updateHiddenItems();
SearchField.searchParser.clearCache();
}
}
@@ -447,24 +451,14 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
parentpath -> parentpath.equals(path.toLowerCase())
|| parentpath.startsWith(path.toLowerCase() + "."));
updateHiddenItems();
SearchField.searchParser.clearCache();
}
}
public static boolean isHidden(ItemStack item) {
try {
if (hiddenReadLock.tryLock(5, TimeUnit.SECONDS)) {
try {
return hiddenItems.contains(item);
} finally {
hiddenReadLock.unlock();
}
} else {
NEIClientConfig.logger.error("Unable to obtain read lock in 'isHidden'");
}
} catch (InterruptedException e) {
e.printStackTrace();
synchronized (hiddenLock) {
return hiddenItems.contains(item);
}
return false;
}
private static List<ItemStack> getItems(SubsetTag tag, List<ItemStack> items) {
@@ -478,90 +472,45 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
}
public static void showOnly(SubsetTag tag) {
try {
if (hiddenWriteLock.tryLock(5, TimeUnit.SECONDS)) {
try {
hiddenItems.clear();
hiddenItems.addAll(getItems(root, new ArrayList<>()));
hiddenItems.removeAll(getItems(tag, new ArrayList<>()));
} finally {
hiddenWriteLock.unlock();
}
} else {
NEIClientConfig.logger.error("Unable to obtain write lock in 'showOnly'");
}
calculateVisibility();
} catch (InterruptedException e) {
e.printStackTrace();
synchronized (hiddenLock) {
hiddenItems.clear();
hiddenItems.addAll(getItems(root, new ArrayList<>()));
hiddenItems.removeAll(getItems(tag, new ArrayList<>()));
}
calculateVisibility();
}
public static void setHidden(SubsetTag tag, boolean hidden) {
try {
if (hiddenWriteLock.tryLock(5, TimeUnit.SECONDS)) {
try {
List<ItemStack> tagItems = getItems(tag, new ArrayList<>());
synchronized (hiddenLock) {
final List<ItemStack> tagItems = getItems(tag, new ArrayList<>());
if (hidden) {
hiddenItems.addAll(tagItems);
} else {
hiddenItems.removeAll(tagItems);
}
} finally {
hiddenWriteLock.unlock();
}
if (hidden) {
hiddenItems.addAll(tagItems);
} else {
NEIClientConfig.logger.error("Unable to obtain write lock in 'setHidden'");
hiddenItems.removeAll(tagItems);
}
calculateVisibility();
} catch (InterruptedException e) {
e.printStackTrace();
}
calculateVisibility();
}
public static void setHidden(ItemStack item, boolean hidden) {
try {
if (hiddenWriteLock.tryLock(5, TimeUnit.SECONDS)) {
try {
if (hidden) {
hiddenItems.add(item);
} else {
hiddenItems.remove(item);
}
} finally {
hiddenWriteLock.unlock();
}
synchronized (hiddenLock) {
if (hidden) {
hiddenItems.add(item);
} else {
NEIClientConfig.logger.error("Unable to obtain write lock in 'setHidden'");
hiddenItems.remove(item);
}
calculateVisibility();
} catch (InterruptedException e) {
e.printStackTrace();
}
calculateVisibility();
}
public static void unhideAll() {
try {
if (hiddenWriteLock.tryLock(5, TimeUnit.SECONDS)) {
try {
hiddenItems.clear();
} finally {
hiddenWriteLock.unlock();
}
} else {
NEIClientConfig.logger.error("Unable to obtain write lock in 'unhideAll'");
}
calculateVisibility();
} catch (InterruptedException e) {
e.printStackTrace();
synchronized (hiddenLock) {
hiddenItems.clear();
}
calculateVisibility();
}
public static void updateHiddenItems() {
@@ -646,29 +595,20 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
return;
}
try {
if (hiddenWriteLock.tryLock(5, TimeUnit.SECONDS)) {
try {
hiddenItems.clear();
hiddenItems.addAll(itemList);
} finally {
hiddenWriteLock.unlock();
}
} else {
NEIClientConfig.logger.error("Unable to obtain second write lock in 'loadHidden'");
}
} catch (InterruptedException e) {
e.printStackTrace();
synchronized (hiddenLock) {
hiddenItems.clear();
hiddenItems.addAll(itemList);
}
}
public static void saveHidden() {
if (NEIClientConfig.world == null) return;
final NBTTagList list = new NBTTagList();
for (ItemStack stack : hiddenItems.values()) {
list.appendTag(stack.writeToNBT(new NBTTagCompound()));
synchronized (hiddenLock) {
for (ItemStack stack : hiddenItems.values()) {
list.appendTag(stack.writeToNBT(new NBTTagCompound()));
}
}
NEIClientConfig.world.nbt.setTag("hiddenItems", list);
@@ -686,14 +626,22 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
public void execute() {
try {
final List<SubsetTag> list = new ArrayList<>(tags.values());
final List<SubsetTag> list;
synchronized (tags) {
list = new ArrayList<>(tags.values());
}
root.clearCache();
list.parallelStream().forEach(tag -> {
tag.clearCache();
ItemList.items.stream().filter(tag.filter::matches)
.collect(Collectors.toCollection(() -> tag.items));
if (!(tag.filter instanceof NothingItemFilter)) {
ItemList.items.stream().filter(tag.filter::matches)
.collect(Collectors.toCollection(() -> tag.items));
}
});
for (SubsetTag tag : list) {
@@ -729,6 +677,7 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
e.printStackTrace();
}
SearchField.searchParser.clearCache();
}
}
@@ -745,6 +694,11 @@ public class SubsetWidget extends Button implements ItemFilterProvider {
if (NEIClientConfig.subsetWidgetOnTop()) {
return NEIClientUtils.translate("inventory.item_subsets");
} else {
final String translated = NEIClientUtils.translate("gui.button.label.subset");
if (!translated.startsWith("nei.")) { // Optional localization string for resource packs
return translated;
}
return EnumChatFormatting.DARK_PURPLE + String.valueOf(SearchField.searchParser.getRedefinedPrefix(PREFIX))
+ EnumChatFormatting.RESET;
}
+1 -1
View File
@@ -89,7 +89,7 @@ public abstract class TextField extends Widget {
onTextChange(oldText);
}
return handled;
return handled || keyID == Keyboard.KEY_SPACE;
}
public abstract void onTextChange(String oldText);
@@ -15,7 +15,7 @@ public interface IBookmarkContainerHandler {
for (int i = 0; i < slots.size() - 4 * 9; i++) {
if (slots.get(i).getHasStack()) {
stacks.add(slots.get(i).getStack());
stacks.add(slots.get(i).getStack().copy());
}
}
@@ -18,6 +18,10 @@ public interface IStackStringifyHandler {
return null;
}
default ItemStack normalizeRecipeQueryStack(ItemStack stack) {
return null;
}
default void pauseItemDamageSound(boolean pause) {}
}
@@ -27,6 +27,7 @@ import codechicken.nei.SearchField;
import codechicken.nei.bookmark.BookmarkGrid;
import codechicken.nei.bookmark.BookmarkGroup;
import codechicken.nei.bookmark.BookmarkItem;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.bookmark.BookmarksGridSlot;
import codechicken.nei.recipe.AutoCraftingManager;
import codechicken.nei.recipe.GuiCraftingRecipe;
@@ -233,12 +234,12 @@ public abstract class ShortcutInputHandler {
if (recipe != null) {
math = RecipeChainMath.of(recipe, 1);
}
} else if (slot.getRecipeId() != null && !slot.isIngredient()) {
} else if (slot.getRecipeId() != null && slot.getType() != BookmarkItemType.INGREDIENT) {
if (slot.getGroup().crafting == null) {
final Recipe recipe = Recipe.of(slot.getRecipeId());
if (recipe != null) {
math = RecipeChainMath.of(recipe, slot != null ? slot.getMultiplier() : 1);
math = RecipeChainMath.of(recipe, Math.max(1, slot != null ? slot.getMultiplier() : 1));
}
} else {
math = ItemPanels.bookmarkPanel.getGrid()
@@ -312,11 +313,14 @@ public abstract class ShortcutInputHandler {
private static boolean saveRecipeInBookmark(ItemStack stackover, boolean saveIngredients, boolean saveStackSize) {
final Point mousePos = GuiDraw.getMousePosition();
// If no slot was removed from the bookmark panel on click:
if (!ItemPanels.bookmarkPanel.removeSlot(mousePos.x, mousePos.y, saveIngredients)) {
final Recipe recipe = getFocusedRecipe(stackover, mousePos.x, mousePos.y, saveIngredients);
// --- Case 1: saving a recipe (with ingredients) ---
if (recipe != null && saveIngredients) {
// If the recipe is not already bookmarked, add it
if (!ItemPanels.bookmarkPanel.removeRecipe(recipe.getRecipeId(), BookmarkGrid.DEFAULT_GROUP_ID)) {
final Recipe singleRecipe = Recipe.of(
Arrays.asList(recipe.getResult(stackover)),
@@ -324,18 +328,30 @@ public abstract class ShortcutInputHandler {
recipe.getIngredients());
singleRecipe.setCustomRecipeId(recipe.getRecipeId());
ItemPanels.bookmarkPanel
.addRecipe(singleRecipe, saveStackSize ? 1 : 0, BookmarkGrid.DEFAULT_GROUP_ID);
ItemPanels.bookmarkPanel.addRecipe(
singleRecipe,
// Determine if stack size should be saved
saveStackSize
|| NEIClientConfig.getBooleanSetting("inventory.bookmarks.bookmarkRecipeWithCount")
? 1
: 0,
BookmarkGrid.DEFAULT_GROUP_ID);
}
// --- Case 2: saving an item only ---
} else {
final RecipeId recipeId = recipe != null ? recipe.getRecipeId() : null;
// Determine if the item is associated with a recipe and should be saved with it
final boolean existsRecipe = recipeId != null
&& ItemPanels.bookmarkPanel.existsRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID)
|| NEIClientConfig.getBooleanSetting("inventory.bookmarks.bookmarkItemsWithRecipe");
// If the item was not removed from the bookmarks, add it
if (!ItemPanels.bookmarkPanel
.removeItem(stackover, existsRecipe ? recipeId : null, BookmarkGrid.DEFAULT_GROUP_ID)) {
// Determine whether to preserve the item count
saveStackSize = saveStackSize || saveIngredients
|| ItemPanels.bookmarkPanel.existsRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID);
@@ -469,7 +485,7 @@ public abstract class ShortcutInputHandler {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.remove_recipe"));
} else if (slot.getRecipeId() == null) {
} else if (slot.getRecipeId() == null || slot.getType() == BookmarkItemType.ITEM) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate("bookmark.remove_item"));
@@ -484,7 +500,7 @@ public abstract class ShortcutInputHandler {
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
if (slot.isIngredient()) {
if (slot.getType() == BookmarkItemType.INGREDIENT) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate("bookmark.remove_item"));
@@ -497,7 +513,8 @@ public abstract class ShortcutInputHandler {
if (ItemPanels.bookmarkPanel.getGrid().createChainItems(groupId).values().stream()
.noneMatch(
m -> !m.isIngredient && !m.equals(item) && item.equalsRecipe(m))) {
m -> m.type == BookmarkItemType.RESULT && !m.equals(item)
&& item.equalsRecipe(m))) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate("bookmark.remove_recipe"));
@@ -568,6 +585,9 @@ public abstract class ShortcutInputHandler {
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_RMB),
NEIClientUtils.translate("itempanel.open_usage"));
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.CTRL_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("itempanel.infinite_item"));
} else {
hotkeys.put(
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB),
@@ -647,7 +667,7 @@ public abstract class ShortcutInputHandler {
BookmarksGridSlot slot) {
if (slot != null) {
return slot.isIngredient() ? null : slot.getRecipeId();
return slot.getType() == BookmarkItemType.INGREDIENT ? null : slot.getRecipeId();
}
ItemsGridSlot itemSlot = ItemPanels.itemPanel.getSlotMouseOver(mousex, mousey);
@@ -30,6 +30,7 @@ import codechicken.nei.ItemsGrid.MouseContext;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
@@ -88,7 +89,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
public static final Color PLACEHOLDER_COLOR = new Color(0x66222222, true);
public static final int DEFAULT_GROUP_ID = 0;
protected static final int GROUP_PANEL_WIDTH = 7;
public static final int GROUP_PANEL_WIDTH = 7;
protected static final float SCALE_SPEED = 0.1f;
protected List<BookmarkItem> bookmarkItems = new ArrayList<>();
@@ -367,19 +368,26 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
}
for (BookmarkItem item : this.bookmarkItems) {
if (item.groupId == groupId && item.recipeId != null) {
if (item.recipeId == null && item.type != BookmarkItemType.ITEM) {
item.type = BookmarkItemType.ITEM;
} else if (item.groupId == groupId && item.recipeId != null && item.type != BookmarkItemType.ITEM) {
recipeState.put(
item.recipeId,
recipeState.getOrDefault(item.recipeId, 0) | (item.isIngredient ? 1 : 2));
recipeState.getOrDefault(item.recipeId, 0)
| (item.type == BookmarkItemType.INGREDIENT ? 1 : 2));
}
}
for (BookmarkItem item : this.bookmarkItems) {
if (item.groupId == groupId && item.isIngredient
&& (item.recipeId == null || recipeState.getOrDefault(item.recipeId, 1) == 1)) {
if (item.groupId == groupId && item.type != BookmarkItemType.ITEM
&& recipeState.getOrDefault(item.recipeId, 0) != 3) {
if (item.type == BookmarkItemType.INGREDIENT) {
item.recipeId = null;
}
recipeState.remove(item.recipeId);
item.isIngredient = false;
item.recipeId = null;
item.type = BookmarkItemType.ITEM;
}
}
@@ -405,7 +413,8 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
for (int index = itemIndex; index < size; index++) {
if (item.equalsRecipe(this.bookmarkItems.get(index))) {
sortingRank.put(index, this.bookmarkItems.get(index).isIngredient ? 1 : -1);
sortingRank
.put(index, this.bookmarkItems.get(index).type == BookmarkItemType.INGREDIENT ? 1 : -1);
items.add(index);
}
}
@@ -632,6 +641,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
if (group.crafting == null) {
for (BookmarkItem item : chainItems) {
item.type = BookmarkItemType.ITEM;
item.recipeId = null;
}
}
@@ -761,6 +771,25 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
int absoluteSlotIndex = absoluteRowIndex * this.columns;
int overGroupId = getRowGroupId(overRowIndex);
// move group to same grid
if (this != sortableGroup.grid) {
final BookmarkGroup sourceGroup = sortableGroup.grid.getGroup(sortableGroup.groupId);
final List<BookmarkItem> itemsToMove = sortableGroup.getBookmarkItems();
sortableGroup.grid.removeGroup(sortableGroup.groupId);
final int groupId = this.addGroup(sourceGroup);
for (BookmarkItem item : itemsToMove) {
item.groupId = groupId;
this.bookmarkItems.add(item);
}
sortableGroup.grid = this;
sortableGroup.groupId = groupId;
this.onItemsChanged();
this.getMask();// force generate grid
}
if (sortableGroup.groupId == overGroupId) {
return;
}
@@ -820,7 +849,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
for (int itemIndex = 0; itemIndex < this.bookmarkItems.size(); itemIndex++) {
final BookmarkItem item = this.bookmarkItems.get(itemIndex);
if (item.groupId == groupId && item.isIngredient == ingredient
if (item.groupId == groupId && ingredient == (item.type == BookmarkItemType.INGREDIENT)
&& (recipeId == item.recipeId || recipeId != null && recipeId.equals(item.recipeId))
&& StackInfo.equalItemAndNBT(stackA, item.itemStack, true)) {
return itemIndex;
@@ -876,7 +905,12 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
for (ItemStack stack : ItemStackAmount.of(results).values()) {
long factor = StackInfo.getAmount(stack);
this.addItem(
BookmarkItem.of(groupId, StackInfo.withAmount(stack, factor * multiplier), factor, recipeId, false),
BookmarkItem.of(
groupId,
StackInfo.withAmount(stack, factor * multiplier),
factor,
recipeId,
BookmarkItemType.RESULT),
true);
}
@@ -888,7 +922,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
StackInfo.withAmount(stack, factor * multiplier),
factor,
recipeId,
true,
BookmarkItemType.INGREDIENT,
BookmarkItem.generatePermutations(stack, recipe)),
true);
}
@@ -901,12 +935,12 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
return;
}
if (!removeFullRecipe && item.recipeId != null && !item.isIngredient) {
if (!removeFullRecipe && item.recipeId != null && item.type == BookmarkItemType.RESULT) {
removeFullRecipe = this.bookmarkItems.stream()
.noneMatch(m -> !m.isIngredient && !m.equals(item) && item.equalsRecipe(m));
.noneMatch(m -> m.type == BookmarkItemType.RESULT && !m.equals(item) && item.equalsRecipe(m));
}
if (item.recipeId != null && removeFullRecipe) {
if (item.recipeId != null && item.type != BookmarkItemType.ITEM && removeFullRecipe) {
removeRecipe(item.recipeId, item.groupId);
} else if (itemIndex >= 0) {
this.bookmarkItems.remove(itemIndex);
@@ -925,7 +959,8 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
}
public boolean existsRecipe(RecipeId recipeId, int groupId) {
return this.bookmarkItems.stream().anyMatch(item -> item.equalsRecipe(recipeId, groupId));
return this.bookmarkItems.stream()
.anyMatch(item -> item.type != BookmarkItemType.ITEM && item.equalsRecipe(recipeId, groupId));
}
public RecipeId getRecipeId(int itemIndex) {
@@ -1028,8 +1063,14 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
}
if (bookmarkItem != null && (group.crafting != null && group.viewMode == BookmarkViewMode.DEFAULT
|| group.viewMode == BookmarkViewMode.TODO_LIST && !sortableItem.bookmarkItem.isIngredient)) {
while (sortIndex > 0 && bookmarkItem.equalsRecipe(getCalculatedItem(sortedIndexes.get(sortIndex - 1)))) {
|| group.viewMode == BookmarkViewMode.TODO_LIST
&& sortableItem.bookmarkItem.type == BookmarkItemType.RESULT)) {
BookmarkItem prevBookmarkItem = sortIndex > 1 ? getCalculatedItem(sortedIndexes.get(sortIndex - 1)) : null;
while (sortIndex > 0 && prevBookmarkItem != null
&& prevBookmarkItem.type != BookmarkItemType.ITEM
&& bookmarkItem.equalsRecipe(prevBookmarkItem)) {
prevBookmarkItem = sortIndex > 1 ? getCalculatedItem(sortedIndexes.get(sortIndex - 1)) : null;
sortIndex--;
}
@@ -1058,7 +1099,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
if (nextSortIndex < sortedIndexes.size()) {
final int nextItemIndex = sortedIndexes.get(nextSortIndex);
if (group.viewMode == BookmarkViewMode.TODO_LIST && !target.isIngredient
if (group.viewMode == BookmarkViewMode.TODO_LIST && target.type == BookmarkItemType.RESULT
&& target.equalsRecipe(getCalculatedItem(nextItemIndex))) {
return -1;
}
@@ -1149,7 +1190,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
if (group.collapsed) {
shiftGroupAmount(targetItem.groupId, shift);
} else if (targetItem.recipeId != null) {
} else if (targetItem.recipeId != null && targetItem.type != BookmarkItemType.ITEM) {
final RecipeId recipeId = this.gridGenerator.itemToRecipe
.getOrDefault(targetItemIndex, targetItem.recipeId);
final boolean recipeInMiddle = group.crafting != null && group.crafting.recipeInMiddle.contains(recipeId);
@@ -11,6 +11,7 @@ import java.util.stream.Collectors;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.ItemSorter;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.bookmark.RecipeChainDetails.BookmarkChainItem;
import codechicken.nei.bookmark.RecipeChainDetails.CalculatedType;
import codechicken.nei.recipe.Recipe.RecipeId;
@@ -165,7 +166,7 @@ public class BookmarkGridGenerator {
break;
}
if (!bookmarkItem.isIngredient
if (bookmarkItem.type != BookmarkItemType.INGREDIENT
&& (group.crafting == null || group.crafting.calculatedItems.containsKey(itemIndex))) {
results.add(itemIndex);
}
@@ -193,7 +194,7 @@ public class BookmarkGridGenerator {
bookmarkItem.itemStack,
1,
bookmarkItem.recipeId,
isIngredient,
isIngredient ? BookmarkItemType.INGREDIENT : BookmarkItemType.RESULT,
Collections.emptyMap());
if ((absoluteSlotIndex = nextSlotIndex(
@@ -227,7 +228,7 @@ public class BookmarkGridGenerator {
index = Math.max(0, index);
while (j++ < maxIndex) {
boolean isFirstColumn = (index % gridColumns) == 0;
final boolean isFirstColumn = (index % gridColumns) == 0;
if (this.grid.isInvalidSlot(index % maxIndex)) {
index++;
@@ -238,17 +239,22 @@ public class BookmarkGridGenerator {
return index;
} else if (isFirstColumn && (meta.recipeId == null || previousMeta == null
|| previousMeta.groupId != meta.groupId
|| meta.type != BookmarkItemType.INGREDIENT
|| !meta.recipeId.equals(previousMeta.recipeId)
|| index + 1 < maxIndex && this.grid.isInvalidSlot((index + 1) % maxIndex))) {
// In first column must be an item without recipe, a recipe result, or an ingredient
// if the second column is occupied
return index;
} else
if (!isFirstColumn && meta.recipeId != null && meta.recipeId.equals(previousMeta.recipeId)) {
return index;
} else {
index++;
}
if (!isFirstColumn && meta.type != BookmarkItemType.ITEM
&& previousMeta.type != BookmarkItemType.ITEM
&& meta.groupId == previousMeta.groupId
&& meta.recipeId != null
&& meta.recipeId.equals(previousMeta.recipeId)) {
return index;
} else {
index++;
}
}
@@ -17,6 +17,21 @@ import codechicken.nei.recipe.StackInfo;
public class BookmarkItem {
public enum BookmarkItemType {
INGREDIENT,
RESULT,
ITEM;
public static BookmarkItemType fromInt(int type) {
return type == 0 ? ITEM : type == 1 ? RESULT : INGREDIENT;
}
public int toInt() {
return this == ITEM ? 0 : this == RESULT ? 1 : 2;
}
}
private static Map<ItemStack, String> fuzzyPermutations = new HashMap<>();
public int groupId;
@@ -28,10 +43,10 @@ public class BookmarkItem {
public long factor;
public RecipeId recipeId;
public boolean isIngredient = false;
public BookmarkItemType type = BookmarkItemType.ITEM;
protected BookmarkItem(int groupId, long amount, int fluidCellAmount, ItemStack itemStack,
Map<String, ItemStack> permutations, long factor, RecipeId recipeId, boolean isIngredient) {
Map<String, ItemStack> permutations, long factor, RecipeId recipeId, BookmarkItemType type) {
this.groupId = groupId;
this.amount = amount;
@@ -41,10 +56,10 @@ public class BookmarkItem {
this.factor = factor;
this.recipeId = recipeId;
this.isIngredient = isIngredient;
this.type = type == null ? BookmarkItemType.ITEM : type;
}
public static BookmarkItem of(int groupId, ItemStack stack, long factor, RecipeId recipeId, boolean isIngredient,
public static BookmarkItem of(int groupId, ItemStack stack, long factor, RecipeId recipeId, BookmarkItemType type,
Map<String, ItemStack> permutations) {
final FluidStack fluidStack = StackInfo.getFluid(stack);
int fluidCellAmount = 1;
@@ -65,18 +80,29 @@ public class BookmarkItem {
permutations,
factor * fluidCellAmount,
recipeId,
isIngredient);
type);
}
public static BookmarkItem of(int groupId, ItemStack stack, long factor, RecipeId recipeId, boolean isIngredient) {
return of(groupId, stack, factor, recipeId, isIngredient, generatePermutations(stack, recipeId, isIngredient));
public static BookmarkItem of(int groupId, ItemStack stack, long factor, RecipeId recipeId, BookmarkItemType type) {
return of(
groupId,
stack,
factor,
recipeId,
type,
generatePermutations(stack, recipeId, type == BookmarkItemType.INGREDIENT));
}
public static BookmarkItem of(int groupId, ItemStack stack) {
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(stack);
final long factor = nbTag.hasKey("gtFluidName") ? Math.min(144, nbTag.getInteger("Count")) : 1;
return BookmarkItem
.of(groupId, stack, factor, null, false, Collections.singletonMap(getItemGUID(stack), stack));
return BookmarkItem.of(
groupId,
stack,
factor,
null,
BookmarkItemType.ITEM,
Collections.singletonMap(getItemGUID(stack), stack));
}
public BookmarkItem copyWithAmount(long amount) {
@@ -88,7 +114,7 @@ public class BookmarkItem {
this.permutations,
this.factor,
this.recipeId,
this.isIngredient);
this.type);
}
public BookmarkItem copy() {
@@ -186,14 +212,14 @@ public class BookmarkItem {
@Override
public int hashCode() {
return Objects.hash(this.groupId, this.fluidCellAmount, this.isIngredient, this.recipeId);
return Objects.hash(this.groupId, this.fluidCellAmount, this.type.toInt(), this.recipeId);
}
@Override
public boolean equals(Object object) {
if (object instanceof BookmarkItem item) {
return this.groupId == item.groupId && this.isIngredient == item.isIngredient
return this.groupId == item.groupId && this.type == item.type
&& this.fluidCellAmount == item.fluidCellAmount
&& StackInfo.equalItemAndNBT(this.itemStack, item.itemStack, true)
&& (this.recipeId == item.recipeId || this.recipeId != null && this.recipeId.equals(item.recipeId));
@@ -7,7 +7,6 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -16,6 +15,7 @@ import net.minecraft.nbt.NBTTagCompound;
import org.apache.commons.io.IOUtils;
import com.google.common.io.Files;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -25,6 +25,7 @@ import com.google.gson.JsonSyntaxException;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
@@ -136,6 +137,7 @@ public class BookmarkStorage {
NBTTagCompound navigation = new NBTTagCompound();
namespaces.add(new BookmarkGrid());
BookmarkGrid grid = namespaces.get(0);
boolean wasError = false;
if (NEIClientConfig.world.nbt.hasKey("bookmark")) {
navigation = NEIClientConfig.world.nbt.getCompoundTag("bookmark");
@@ -150,17 +152,19 @@ public class BookmarkStorage {
}
if (itemStr.startsWith("; ")) {
JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
if (grid.size() > 0) {
// do not create empty namespaces
grid = new BookmarkGrid();
if (navigation.hasKey("namespacePage." + namespaces.size())) {
grid.setPage(navigation.getInteger("namespacePage." + namespaces.size()));
}
namespaces.add(grid);
}
if (navigation.hasKey("namespacePage." + (namespaces.size() - 1))) {
grid.setPage(navigation.getInteger("namespacePage." + (namespaces.size() - 1)));;
}
final JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
if (settings.get("viewmode") != null) {
grid.groups.get(BookmarkGrid.DEFAULT_GROUP_ID).viewMode = BookmarkViewMode
@@ -195,17 +199,28 @@ public class BookmarkStorage {
}
if (!addItemToGrid(grid, parser.parse(itemStr).getAsJsonObject())) {
wasError = true;
NEIClientConfig.logger.warn(
"Failed to load bookmarked ItemStack from json string, the item no longer exists:\n{}",
itemStr);
}
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
} catch (Exception e) {
wasError = true;
NEIClientConfig.logger.error("Failed to load bookmarked ItemStack from json string:\n{}", itemStr);
}
}
prepareOldRecipeFormat(namespaces);
if (wasError) {
try {
Files.copy(
bookmarkFile,
new File(bookmarkFile.getAbsolutePath() + ".backup-" + System.currentTimeMillis()));
NEIClientConfig.logger.info("Backed up invalid bookmark file to {}", bookmarkFile);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to backup invalid bookmark file to {}", bookmarkFile, e);
}
}
for (BookmarkGrid gr : namespaces) {
gr.onItemsChanged();
@@ -239,7 +254,15 @@ public class BookmarkStorage {
int groupId = jsonObject.has("groupId") ? jsonObject.get("groupId").getAsInt()
: BookmarkGrid.DEFAULT_GROUP_ID;
int factor = jsonObject.has("factor") ? Math.abs(jsonObject.get("factor").getAsInt()) : (isFluid ? 144 : 1);
boolean isIngredient = jsonObject.has("ingredient") && jsonObject.get("ingredient").getAsBoolean();
BookmarkItemType type = jsonObject.has("type") ? BookmarkItemType.fromInt(jsonObject.get("type").getAsInt())
: null;
if (type == null) {
// old format
type = jsonObject.has("ingredient") && jsonObject.get("ingredient").getAsBoolean()
? BookmarkItemType.INGREDIENT
: BookmarkItemType.RESULT;
}
if (jsonObject.get("recipeId") instanceof JsonObject recipeJson) {
recipeId = RecipeId.of(recipeJson);
@@ -249,51 +272,12 @@ public class BookmarkStorage {
groupId = BookmarkGrid.DEFAULT_GROUP_ID;
}
grid.addItem(BookmarkItem.of(groupId, itemStack, factor, recipeId, isIngredient), false);
grid.addItem(BookmarkItem.of(groupId, itemStack, factor, recipeId, type), false);
}
return itemStack != null;
}
private void prepareOldRecipeFormat(List<BookmarkGrid> namespaces) {
for (BookmarkGrid grid : namespaces) {
if (grid.bookmarkItems.stream()
.noneMatch(item -> item.recipeId != null && item.recipeId.getResult() == null)) {
continue;
}
final Map<String, RecipeId> recipes = new HashMap<>();
for (BookmarkItem item : grid.bookmarkItems) {
if (item.recipeId != null && !item.isIngredient && item.recipeId.getResult() == null) {
final JsonObject recipeJson = item.recipeId.toJsonObject();
final String recipeGUID = item.groupId + ":" + NBTJson.toJson(recipeJson);
if (!recipes.containsKey(recipeGUID)) {
recipeJson.add("result", NBTJson.toJsonObject(StackInfo.itemStackToNBT(item.itemStack)));
recipes.put(recipeGUID, item.recipeId = RecipeId.of(recipeJson));
}
}
}
for (BookmarkItem item : grid.bookmarkItems) {
if (item.recipeId != null && item.recipeId.getResult() == null) {
final JsonObject recipeJson = item.recipeId.toJsonObject();
final String recipeGUID = item.groupId + ":" + NBTJson.toJson(recipeJson);
if (recipes.containsKey(recipeGUID)) {
item.recipeId = recipes.get(recipeGUID).copy();
item.permutations = BookmarkItem
.generatePermutations(item.itemStack, item.recipeId, item.isIngredient);
} else {
item.recipeId = null;
}
}
}
}
}
public void save() {
if (this.bookmarkFile == null) {
@@ -338,7 +322,7 @@ public class BookmarkStorage {
row.add("item", NBTJson.toJsonObject(StackInfo.itemStackToNBT(item.getItemStack())));
row.add("factor", new JsonPrimitive(item.getFactor()));
row.add("ingredient", new JsonPrimitive(item.isIngredient));
row.add("type", new JsonPrimitive(item.type.toInt()));
if (item.groupId != BookmarkGrid.DEFAULT_GROUP_ID) {
row.add("groupId", new JsonPrimitive(item.groupId));
@@ -15,6 +15,7 @@ import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIClientUtils.Alignment;
import codechicken.nei.bookmark.BookmarkGrid.BookmarkMouseContext;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.bookmark.RecipeChainDetails.CalculatedType;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.GuiRecipeTab;
@@ -89,7 +90,7 @@ public class BookmarksGridSlot extends ItemsGridSlot {
this.realType = this.group.crafting.calculatedItems.get(this.itemIndex).calculatedType
== CalculatedType.INGREDIENT ? CalculatedType.INGREDIENT : CalculatedType.RESULT;
} else {
this.realType = this.bookmarkItem.isIngredient
this.realType = this.bookmarkItem.type == BookmarkItemType.INGREDIENT
|| this.group.crafting != null && this.bookmarkItem.recipeId == null ? CalculatedType.INGREDIENT
: CalculatedType.RESULT;
}
@@ -97,9 +98,10 @@ public class BookmarksGridSlot extends ItemsGridSlot {
final BookmarkGrid grid = ItemPanels.bookmarkPanel.getGrid();
final BookmarkItem prevItem = grid.getCalculatedItem(
grid.gridGenerator.slotToItem.getOrDefault(grid.gridGenerator.itemToSlot.get(this.itemIndex) - 1, -1));
this.isFirstOutput = this.itemIndex >= 0 && !this.bookmarkItem.isIngredient
this.isFirstOutput = this.itemIndex >= 0 && this.bookmarkItem.type == BookmarkItemType.RESULT
&& ((this.slotIndex % grid.getColumns()) == 0 || group.viewMode == BookmarkViewMode.DEFAULT)
&& (prevItem == null || prevItem.isIngredient || !this.bookmarkItem.equalsRecipe(prevItem));
&& (prevItem == null || prevItem.type == BookmarkItemType.INGREDIENT
|| !this.bookmarkItem.equalsRecipe(prevItem));
this.rowIndex = this.slotIndex / grid.getColumns();
}
@@ -116,8 +118,8 @@ public class BookmarksGridSlot extends ItemsGridSlot {
return this.bookmarkItem.recipeId;
}
public boolean isIngredient() {
return this.bookmarkItem.isIngredient;
public BookmarkItemType getType() {
return this.bookmarkItem.type;
}
public BookmarkGroup getGroup() {
@@ -151,11 +153,17 @@ public class BookmarksGridSlot extends ItemsGridSlot {
return false;
}
if (this.group.crafting != null) {
if (this.slotIndex == mouseContext.slotIndex || this.group.crafting != null) {
return true;
}
return this.bookmarkItem.equalsRecipe(mouseContext.recipeId, mouseContext.groupId);
if (this.bookmarkItem.type == BookmarkItemType.ITEM && this.group.viewMode == BookmarkViewMode.TODO_LIST
&& mouseContext.rowIndex == this.rowIndex) {
return true;
}
return this.bookmarkItem.type != BookmarkItemType.ITEM
&& this.bookmarkItem.equalsRecipe(mouseContext.recipeId, mouseContext.groupId);
}
protected boolean showRealItem(BookmarkMouseContext mouseContext) {
@@ -173,7 +181,8 @@ public class BookmarksGridSlot extends ItemsGridSlot {
return true;
}
if (this.bookmarkItem.equalsRecipe(mouseContext.recipeId, mouseContext.groupId)) {
if (this.bookmarkItem.type != BookmarkItemType.ITEM
&& this.bookmarkItem.equalsRecipe(mouseContext.recipeId, mouseContext.groupId)) {
return true;
}
@@ -212,7 +221,7 @@ public class BookmarksGridSlot extends ItemsGridSlot {
}
if (!this.bookmarkItem.isIngredient && this.bookmarkItem.recipeId != null
if (this.bookmarkItem.type != BookmarkItemType.INGREDIENT && this.bookmarkItem.recipeId != null
&& calculatedType == null
&& showMarker
&& (mouseContext == null || mouseContext.slotIndex != this.slotIndex)) {
@@ -259,7 +268,7 @@ public class BookmarksGridSlot extends ItemsGridSlot {
drawStackSize(rect, shownItemType);
if (this.bookmarkItem.isIngredient || this.bookmarkItem.recipeId == null) {
if (this.bookmarkItem.type == BookmarkItemType.INGREDIENT || this.bookmarkItem.recipeId == null) {
return;
}
@@ -283,18 +292,17 @@ public class BookmarksGridSlot extends ItemsGridSlot {
NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue(),
Alignment.TopLeft);
}
}
if (NEIClientConfig.getBooleanSetting("inventory.bookmarks.showRecipeHandlerIcon")
&& getHandlerInfo() != null) {
drawHandlerIcon(rect);
} else if (NEIClientConfig.showRecipeMarkerMode() == 1) {
drawMarker(
rect,
"R",
NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue(),
Alignment.TopRight);
}
if (this.isFirstOutput || NEIClientConfig.showRecipeMarkerMode() == 1) {
drawRecipeMarker(rect);
}
}
protected void drawRecipeMarker(Rectangle4i rect) {
if (NEIClientConfig.getBooleanSetting("inventory.bookmarks.showRecipeHandlerIcon")
&& getHandlerInfo() != null) {
drawHandlerIcon(rect);
} else if (NEIClientConfig.showRecipeMarkerMode() == 1) {
drawMarker(
rect,
@@ -302,7 +310,6 @@ public class BookmarksGridSlot extends ItemsGridSlot {
NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue(),
Alignment.TopRight);
}
}
protected void drawHandlerIcon(Rectangle4i rect) {
@@ -7,6 +7,7 @@ import java.util.Map;
import java.util.Set;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.recipe.Recipe.RecipeId;
public class GroupingItem {
@@ -124,7 +125,7 @@ public class GroupingItem {
final BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
if (item.recipeId != null) {
if (item.recipeId != null && item.type != BookmarkItemType.ITEM) {
final List<Integer> sortedItems = this.grid.getSortedItems();
final BookmarkGroup group = this.grid.getGroup(item.groupId);
final boolean isCollapsedGroup = group.collapsed
@@ -139,7 +140,8 @@ public class GroupingItem {
for (Integer rItemIndex : sortedItems) {
final BookmarkItem rItem = this.grid.getCalculatedItem(rItemIndex);
if (rItem.groupId == item.groupId && (isCollapsedGroup || recipeRelations.contains(rItem.recipeId))) {
if (rItem.groupId == item.groupId && (isCollapsedGroup
|| rItem.type != BookmarkItemType.ITEM && recipeRelations.contains(rItem.recipeId))) {
return this.grid.getAbsoluteSlotIndex(rItemIndex) / this.grid.getColumns();
}
}
@@ -160,7 +162,7 @@ public class GroupingItem {
final BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
if (item.recipeId != null) {
if (item.recipeId != null && item.type != BookmarkItemType.ITEM) {
final List<Integer> sortedItems = this.grid.getSortedItems();
final BookmarkGroup group = this.grid.getGroup(item.groupId);
final boolean isCollapsedGroup = group.collapsed
@@ -176,7 +178,8 @@ public class GroupingItem {
final int rItemIndex = sortedItems.get(index);
final BookmarkItem rItem = this.grid.getCalculatedItem(rItemIndex);
if (rItem.groupId == item.groupId && (isCollapsedGroup || recipeRelations.contains(rItem.recipeId))) {
if (rItem.groupId == item.groupId && (isCollapsedGroup
|| rItem.type != BookmarkItemType.ITEM && recipeRelations.contains(rItem.recipeId))) {
return this.grid.getAbsoluteSlotIndex(rItemIndex) / this.grid.getColumns();
}
}
@@ -12,6 +12,7 @@ import java.util.stream.Collectors;
import net.minecraft.item.ItemStack;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.recipe.chain.RecipeChainMath;
@@ -69,7 +70,7 @@ public class RecipeChainDetails {
item,
item.amount,
item.amount,
item.isIngredient ? CalculatedType.INGREDIENT : CalculatedType.RESULT);
item.type == BookmarkItemType.INGREDIENT ? CalculatedType.INGREDIENT : CalculatedType.RESULT);
}
public ItemStack getItemStack(long amount) {
@@ -217,11 +218,12 @@ public class RecipeChainDetails {
for (BookmarkChainItem value : items) {
int itemIndex = sortingChainItems.get(value.getItem());
if (value.getItem().isIngredient || !recipeId.equals(value.getItem().recipeId)) {
if (value.getItem().type == BookmarkItemType.INGREDIENT || !recipeId.equals(value.getItem().recipeId)) {
itemIndex *= -1;
}
if (!value.getItem().isIngredient && !math.outputRecipes.containsKey(value.getItem().recipeId)) {
if (value.getItem().type == BookmarkItemType.RESULT
&& !math.outputRecipes.containsKey(value.getItem().recipeId)) {
value.calculatedType = CalculatedType.REMAINDER;
}
@@ -251,7 +253,7 @@ public class RecipeChainDetails {
for (BookmarkChainItem value : items) {
int itemIndex = sortingChainItems.get(value.getItem());
if (value.getItem().isIngredient || !recipeId.equals(value.getItem().recipeId)) {
if (value.getItem().type == BookmarkItemType.INGREDIENT || !recipeId.equals(value.getItem().recipeId)) {
itemIndex *= -1;
}
@@ -348,22 +350,20 @@ public class RecipeChainDetails {
private Set<RecipeId> getRecipeParents(RecipeChainMath math, RecipeId recipeId, Set<RecipeId> parents,
Set<RecipeId> visited) {
final Set<RecipeId> recipeIds = math.preferredItems.entrySet().stream()
.filter(
entry -> entry.getValue() != null && recipeId.equals(entry.getValue().recipeId)
&& !visited.contains(entry.getKey().recipeId))
.filter(entry -> entry.getValue() != null && recipeId.equals(entry.getValue().recipeId))
.map(entry -> entry.getKey().recipeId).collect(Collectors.toSet());
visited.addAll(recipeIds);
if (recipeIds.isEmpty()) {
parents.add(recipeId);
} else {
for (RecipeId ingrRecipeId : recipeIds) {
if (math.outputRecipes.containsKey(ingrRecipeId)) {
parents.add(ingrRecipeId);
} else {
getRecipeParents(math, ingrRecipeId, parents, visited);
if (visited.add(ingrRecipeId)) {
if (math.outputRecipes.containsKey(ingrRecipeId)) {
parents.add(ingrRecipeId);
} else {
getRecipeParents(math, ingrRecipeId, parents, visited);
}
}
}
@@ -9,6 +9,7 @@ import java.util.Map;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.ItemsGrid;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.bookmark.RecipeChainDetails.BookmarkChainItem;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.Recipe.RecipeId;
@@ -30,10 +31,10 @@ public class SortableItem {
this.grid = grid;
this.bookmarkItem = bookmarkItem.copy();
this.moveRecipe = bookmarkItem.recipeId != null && !bookmarkItem.isIngredient
this.moveRecipe = bookmarkItem.recipeId != null && bookmarkItem.type == BookmarkItemType.RESULT
&& (group.viewMode == BookmarkViewMode.TODO_LIST || group.crafting != null);
this.crossGroup = !group.collapsed && group.viewMode == BookmarkViewMode.TODO_LIST
&& !this.bookmarkItem.isIngredient;
&& bookmarkItem.type != BookmarkItemType.INGREDIENT;
this.isCollapsedRecipe = group.crafting != null && group.crafting.itemToRecipe.values().stream()
.anyMatch(recipeId -> this.bookmarkItem.equalsRecipe(recipeId, this.bookmarkItem.groupId));
@@ -86,13 +86,15 @@ public class IMCHandler {
info.setYShift(yShift);
try {
final int imageHeight = tag.hasKey("handlerHeight") ? tag.getInteger("handlerHeight")
final int handlerHeight = tag.hasKey("handlerHeight") ? tag.getInteger("handlerHeight")
: HandlerInfo.DEFAULT_HEIGHT;
final int imageWidth = tag.hasKey("handlerWidth") ? tag.getInteger("handlerWidth")
final int handlerWidth = tag.hasKey("handlerWidth") ? tag.getInteger("handlerWidth")
: HandlerInfo.DEFAULT_WIDTH;
final int maxRecipesPerPage = tag.hasKey("maxRecipesPerPage") ? tag.getInteger("maxRecipesPerPage")
: HandlerInfo.DEFAULT_MAX_PER_PAGE;
info.setHandlerDimensions(imageHeight, imageWidth, maxRecipesPerPage);
final boolean multipleWidgetsAllowed = tag.hasKey("multipleWidgetsAllowed")
? tag.getBoolean("multipleWidgetsAllowed")
: tag.hasKey("maxRecipesPerPage") && tag.getInteger("maxRecipesPerPage") > 1;
info.setHandlerDimensions(handlerWidth, handlerHeight);
info.setMultipleWidgetsAllowed(multipleWidgetsAllowed);
} catch (NumberFormatException ignored) {
NEIClientConfig.logger.info("Error setting handler dimensions for {}", handler);
}
@@ -16,6 +16,7 @@ import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.function.IntFunction;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -164,7 +165,7 @@ public class GuiContainerManager {
* @return A list of Strings representing the text to be displayed on each line of the tool tip.
*/
public static List<String> itemDisplayNameMultiline(ItemStack stack, GuiContainer gui, boolean includeHandlers) {
List<String> namelist = null;
List<String> namelist;
try {
namelist = stack.getTooltip(
Minecraft.getMinecraft().thePlayer,
@@ -199,26 +200,27 @@ public class GuiContainerManager {
}
@Nullable
public static String countDetails(int stackSize, int maxStackSize, String fullPattern, String shortPattern) {
public static String countDetails(int stackSize, int maxStackSize, String fullPattern, String shortPattern,
IntFunction<String> valueFormatter) {
if (maxStackSize > 1 && stackSize > maxStackSize) {
final int remainder = stackSize % maxStackSize;
final int units = stackSize / maxStackSize;
if (remainder > 0) {
return String.format(
fullPattern,
NEIClientUtils.formatNumbers(stackSize),
NEIClientUtils.formatNumbers(stackSize / maxStackSize),
NEIClientUtils.formatNumbers(maxStackSize),
NEIClientUtils.formatNumbers(remainder));
valueFormatter.apply(stackSize),
NEIClientUtils.formatNumber(units),
valueFormatter.apply(maxStackSize),
valueFormatter.apply(remainder));
} else {
return String.format(
shortPattern,
NEIClientUtils.formatNumbers(stackSize),
NEIClientUtils.formatNumbers(stackSize / maxStackSize),
NEIClientUtils.formatNumbers(maxStackSize));
valueFormatter.apply(stackSize),
NEIClientUtils.formatNumber(units),
valueFormatter.apply(maxStackSize));
}
}
return null;
}
@@ -232,7 +234,8 @@ public class GuiContainerManager {
stack.stackSize,
stack.getMaxStackSize(),
translate("inventory.tooltip.count.item", "%s = %s * %s + %s"),
translate("inventory.tooltip.count.item", "%s = %s * %s"));
translate("inventory.tooltip.count.item", "%s = %s * %s"),
NEIClientUtils::formatNumber);
}
}
@@ -247,8 +250,9 @@ public class GuiContainerManager {
return countDetails(
amount,
144,
translate("inventory.tooltip.count.fluid", "%s L = %s * %s L + %s L"),
translate("inventory.tooltip.count.fluid", "%s L = %s * %s L"));
translate("inventory.tooltip.count.fluid", "%s = %s * %s + %s"),
translate("inventory.tooltip.count.fluid", "%s = %s * %s"),
NEIClientUtils::formatFluid);
}
/**
@@ -664,12 +668,12 @@ public class GuiContainerManager {
}
}
hotkeys.remove(null);
hotkeys.remove("");
if (!hotkeys.isEmpty()) {
List<String> hotkeystips = new ArrayList<>();
Map<String, List<String>> messages = new HashMap<>();
hotkeys.remove(null);
hotkeys.remove("");
for (Map.Entry<String, String> entry : hotkeys.entrySet()) {
messages.computeIfAbsent(entry.getValue(), m -> new ArrayList<>()).add(entry.getKey());
@@ -704,13 +708,19 @@ public class GuiContainerManager {
}
} else if (NEIClientConfig.getBooleanSetting("inventory.hotkeysHelpText")) {
Map<String, String> hotkeys = new HashMap<>();
boolean existsHotkeys = false;
synchronized (instanceTooltipHandlers) {
for (IContainerTooltipHandler handler : instanceTooltipHandlers) {
if (!handler.handleHotkeys(window, mousex, mousey, new HashMap<>()).isEmpty()) {
existsHotkeys = true;
break;
if (!(hotkeys = handler.handleHotkeys(window, mousex, mousey, hotkeys)).isEmpty()) {
hotkeys.remove("");
hotkeys.remove(null);
if (!hotkeys.isEmpty()) {
existsHotkeys = true;
break;
}
}
}
}
@@ -19,12 +19,12 @@ import java.util.stream.Stream;
*
* @param <E>
*/
final class HideousLinkedList<E> extends LinkedList<E> {
public final class HideousLinkedList<E> extends LinkedList<E> {
private static final long serialVersionUID = -8504433551965776915L;
private final List<E> backing;
HideousLinkedList(List<E> backing) {
public HideousLinkedList(List<E> backing) {
this.backing = backing;
}
@@ -31,7 +31,7 @@ public class AcceptsFollowingTooltipLineHandler extends ItemsTooltipLineHandler
ItemStack activeStack, int maxRows) {
if (items.size() > 1) {
items.sort(Comparator.comparing(FavoriteRecipes::contains).reversed());
items.sort(Comparator.comparing(FavoriteRecipes::containsManual).reversed());
return new AcceptsFollowingTooltipLineHandler(tooltipGUID, items, activeStack, maxRows);
}
@@ -42,7 +42,7 @@ public class AcceptsFollowingTooltipLineHandler extends ItemsTooltipLineHandler
protected void drawItem(int x, int y, ItemStack drawStack, String stackSize) {
super.drawItem(x, y, drawStack, stackSize);
if (FavoriteRecipes.contains(drawStack)) {
if (FavoriteRecipes.containsManual(drawStack)) {
NEIClientUtils.drawNEIOverlayText("F", x, y);
}
}
@@ -1,646 +0,0 @@
package codechicken.nei.recipe;
import java.awt.Point;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.stream.Collectors;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.inventory.GuiContainer;
import org.apache.commons.io.IOUtils;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.Button;
import codechicken.nei.ClientHandler;
import codechicken.nei.FormattedTextField;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.TextField;
import codechicken.nei.Widget;
import codechicken.nei.drawable.DrawableBuilder;
import codechicken.nei.drawable.DrawableResource;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.recipe.TemplateRecipeHandler.RecipeTransferRect;
public class DebugHandlerWidget extends Widget implements IContainerInputHandler {
private static abstract class IntegerField extends TextField {
protected int defaultValue = 0;
public IntegerField(String ident, int defaultValue) {
super(ident);
this.defaultValue = defaultValue;
this.h = LINE_HEIGHT;
this.z = 2;
((FormattedTextField) field).setPlaceholder(Integer.toString(this.defaultValue));
}
@Override
protected void initInternalTextField() {
field = new FormattedTextField(Minecraft.getMinecraft().fontRenderer, 0, 0, 0, 0) {
@Override
public String getText() {
String text = super.getText();
return !isFocused() && this.placeholder.equals(text) ? "" : text;
}
@Override
protected boolean beforeWrite(String text) {
if (text == null || text.isEmpty()) return true;
try {
return Integer.parseInt(text) >= 0;
} catch (NumberFormatException e) {
return false;
}
}
@Override
public boolean textboxKeyTyped(char keyChar, int keyID) {
if (!isFocused()) return false;
if (super.textboxKeyTyped(keyChar, keyID)) {
return true;
} else if (keyID == Keyboard.KEY_DOWN) {
setText(Integer.toString(getInteger() - 1));
return true;
} else if (keyID == Keyboard.KEY_UP) {
setText(Integer.toString(getInteger() + 1));
return true;
}
return false;
}
};
field.setMaxStringLength(maxSearchLength);
field.setCursorPositionZero();
}
protected int getInteger() {
try {
return Integer.parseInt(text());
} catch (NumberFormatException nfe) {
return this.defaultValue;
}
}
@Override
public boolean onMouseWheel(int i, int mx, int my) {
if (!contains(mx, my)) return false;
setText(Integer.toString(getInteger() + i));
return true;
}
}
private final int[] COLORS = new int[] { 0x2200FF00, 0x22FF0000, 0x220000FF, 0x2200FFFF, 0x22FF00FF, 0x22FFFF00 };
private IRecipeHandler handler;
private HandlerInfo handlerInfo;
private static final int WINDOW_WIDTH = 176;
private static final int LINE_HEIGHT = 16;
private static final int INLINE_PADDING = 6;
private static final int LABEL_WIDTH = 50;
private IntegerField order;
private IntegerField yShift;
private IntegerField handlerHeight;
private IntegerField handlerWidth;
private IntegerField maxRecipesPerPage;
private Button useCustomScroll;
private Point dragPoint = null;
public boolean showWidget = false;
private static final int BORDER_PADDING = 6;
private final DrawableResource BG_TEXTURE = new DrawableBuilder("nei:textures/gui/recipebg.png", 0, 0, 176, 166)
.build();
public DebugHandlerWidget() {
GuiContainerManager.addInputHandler(this);
this.order = new IntegerField("order", 0) {
@Override
public void onTextChange(String oldText) {
if (NEIClientConfig.handlerOrdering.get(handler.getOverlayIdentifier()) != null) {
if (getInteger() != NEIClientConfig.handlerOrdering.get(handler.getOverlayIdentifier())) {
updatePatch(5, getInteger(), this.defaultValue);
}
} else if (NEIClientConfig.handlerOrdering.get(handler.getHandlerId()) != null) {
if (getInteger() != NEIClientConfig.handlerOrdering.get(handler.getHandlerId())) {
updatePatch(5, getInteger(), this.defaultValue);
}
}
}
};
this.yShift = new IntegerField("yShift", 0) {
@Override
public void onTextChange(String oldText) {
if (getInteger() != handlerInfo.getYShift()) {
handlerInfo.setYShift(getInteger());
updatePatch(1, getInteger(), this.defaultValue);
}
}
};
this.maxRecipesPerPage = new IntegerField("maxRecipesPerPage", HandlerInfo.DEFAULT_MAX_PER_PAGE) {
@Override
public void onTextChange(String oldText) {
if (getInteger() != handlerInfo.getMaxRecipesPerPage()) {
handlerInfo.setHandlerDimensions(handlerInfo.getHeight(), handlerInfo.getWidth(), getInteger());
updatePatch(4, getInteger(), this.defaultValue);
}
}
};
this.handlerHeight = new IntegerField("handlerHeight", HandlerInfo.DEFAULT_HEIGHT) {
@Override
public void draw(int mx, int my) {
this.field.setEnabled(handler.getRecipeHeight() <= 0);
super.draw(mx, my);
}
@Override
public void onTextChange(String oldText) {
if (getInteger() != handlerInfo.getHeight()) {
handlerInfo.setHandlerDimensions(
getInteger(),
handlerInfo.getWidth(),
handlerInfo.getMaxRecipesPerPage());
updatePatch(2, getInteger(), this.defaultValue);
}
}
};
this.handlerWidth = new IntegerField("handlerWidth", HandlerInfo.DEFAULT_WIDTH) {
@Override
public void onTextChange(String oldText) {
if (getInteger() != handlerInfo.getWidth()) {
handlerInfo.setHandlerDimensions(
handlerInfo.getHeight(),
getInteger(),
handlerInfo.getMaxRecipesPerPage());
updatePatch(3, getInteger(), this.defaultValue);
}
}
};
this.useCustomScroll = new Button() {
{
this.h = LINE_HEIGHT;
this.z = 2;
}
public String getRenderLabel() {
return handlerInfo.getUseCustomScroll() ? "On" : "Off";
}
@Override
public boolean onButtonPress(boolean rightclick) {
handlerInfo.setUseCustomScroll(!handlerInfo.getUseCustomScroll());
updatePatch(6, handlerInfo.getUseCustomScroll() ? 1 : 0, 0);
return true;
}
};
this.w = WINDOW_WIDTH;
this.h = 10 + 13 * LINE_HEIGHT;
this.x = 10;
this.y = 50;
this.z = 1;
}
private void updatePatch(int key, int value, int defaultValue) {
final String handlerKey = getHandlerID(handler);
if (!patches.containsKey(handlerKey)) {
patches.put(handlerKey, new String[] { handlerKey, null, null, null, null, null, null });
}
if (value == defaultValue) {
patches.get(handlerKey)[key] = null;
} else {
patches.get(handlerKey)[key] = String.valueOf(value);
}
saveHandlerInfoPatch();
if (NEIClientUtils.getGuiContainer() instanceof GuiRecipe<?>recipe) {
recipe.forceRefreshPage();
}
}
private void drawKeyLabel(String keyLabel, int topShift) {
GuiDraw.drawString(
NEIClientUtils.cropText(GuiDraw.fontRenderer, keyLabel, LABEL_WIDTH),
this.x + INLINE_PADDING,
topShift,
0x66555555,
false);
GuiDraw.drawString(":", this.x + INLINE_PADDING + LABEL_WIDTH, topShift, 0x66555555, false);
}
private void drawDetail(String keyLabel, String valueLabel, int topShift, int spaceWidth) {
drawKeyLabel(keyLabel, topShift);
GuiDraw.drawString(
NEIClientUtils.cropText(
GuiDraw.fontRenderer,
valueLabel,
this.w - INLINE_PADDING * 2 - LABEL_WIDTH - spaceWidth),
this.x + INLINE_PADDING + LABEL_WIDTH + spaceWidth,
topShift,
0xffffff);
}
private void drawControl(String keyLabel, Widget field, int topShift, int spaceWidth) {
drawKeyLabel(keyLabel, topShift);
field.x = this.x + INLINE_PADDING + LABEL_WIDTH + spaceWidth;
field.y = topShift - 4;
field.w = this.w - INLINE_PADDING * 2 - LABEL_WIDTH - spaceWidth;
}
@Override
public void draw(int mx, int my) {
if (this.handler != null) {
final int spaceWidth = GuiDraw.fontRenderer.getStringWidth(": ");
int topShift = this.y + BORDER_PADDING + 12 + 6;
GL11.glColor4f(1F, 1F, 1F, 1F);
GL11.glScaled(1, 1, 2f);
GL11.glDisable(GL11.GL_DEPTH_TEST);
BG_TEXTURE.draw(
this.x,
this.y,
this.w,
this.h,
BORDER_PADDING,
BORDER_PADDING,
BORDER_PADDING,
BORDER_PADDING);
GuiDraw.drawRect(
this.x + INLINE_PADDING,
this.y + BORDER_PADDING,
this.w - INLINE_PADDING * 2,
12,
0x30000000);
GuiDraw.drawStringC("Debug Recipe Handler", this.x + this.w / 2, this.y + BORDER_PADDING + 2, 0xffffff);
for (Map.Entry<String, String> entry : getDetailsInfo().entrySet()) {
drawDetail(entry.getKey(), entry.getValue(), topShift, spaceWidth);
topShift += LINE_HEIGHT;
}
drawControl("Order", this.order, topShift, spaceWidth);
topShift += LINE_HEIGHT;
drawControl("yShift", this.yShift, topShift, spaceWidth);
topShift += LINE_HEIGHT;
drawControl("Per Page", this.maxRecipesPerPage, topShift, spaceWidth);
topShift += LINE_HEIGHT;
drawControl("Height", this.handlerHeight, topShift, spaceWidth);
topShift += LINE_HEIGHT;
drawControl("Width", this.handlerWidth, topShift, spaceWidth);
topShift += LINE_HEIGHT;
drawControl("Use Custom Scroll", this.useCustomScroll, topShift, spaceWidth);
topShift += LINE_HEIGHT;
GL11.glScaled(1, 1, 1 / 2f);
}
}
private Map<String, String> getDetailsInfo() {
final Map<String, String> lines = new LinkedHashMap<>();
final boolean isHeightHackApplied = NEIClientConfig.heightHackHandlerRegex.stream()
.map(pattern -> pattern.matcher(this.handler.getHandlerId())).anyMatch(Matcher::matches);
lines.put("Name", this.handler.getRecipeName());
lines.put("ID", this.handler.getOverlayIdentifier());
lines.put("Key", this.handler.getHandlerId());
lines.put("H.Hack", String.valueOf(isHeightHackApplied));
lines.put("Mod Name", this.handlerInfo.getModName());
lines.put("Mod ID", this.handlerInfo.getModId());
return lines;
}
public void setVisible() {
if (showWidget && this.handler != null) {
LayoutManager.addWidget(this.order);
LayoutManager.addWidget(this.yShift);
LayoutManager.addWidget(this.handlerHeight);
LayoutManager.addWidget(this.handlerWidth);
LayoutManager.addWidget(this.maxRecipesPerPage);
LayoutManager.addWidget(this.useCustomScroll);
}
}
@Override
public void update() {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
if (showWidget && gui instanceof GuiRecipe recipe) {
if (this.handler != recipe.getHandler()) {
this.handler = recipe.getHandler();
this.handlerInfo = GuiRecipeTab.getHandlerInfo(handler);
this.order.setText(String.valueOf(NEIClientConfig.getHandlerOrder(this.handler)));
this.yShift.setText(String.valueOf(this.handlerInfo.getYShift()));
this.handlerHeight.setText(String.valueOf(this.handlerInfo.getHeight()));
this.handlerWidth.setText(String.valueOf(this.handlerInfo.getWidth()));
this.maxRecipesPerPage.setText(String.valueOf(this.handlerInfo.getMaxRecipesPerPage()));
}
} else {
this.handler = null;
this.handlerInfo = null;
showWidget = false;
}
}
@Override
public List<String> handleTooltip(int mx, int my, List<String> tooltip) {
if (this.handler != null) {
final int spaceWidth = GuiDraw.fontRenderer.getStringWidth(": ");
final int leftShift = this.x + INLINE_PADDING;
if (mx >= leftShift && mx < this.x + WINDOW_WIDTH - INLINE_PADDING) {
int topShift = this.y + BORDER_PADDING + 12 + 6;
for (Map.Entry<String, String> entry : getDetailsInfo().entrySet()) {
if (my >= topShift && my < topShift + LINE_HEIGHT) {
if (mx < leftShift + LABEL_WIDTH + spaceWidth) {
tooltip.add(String.valueOf(entry.getKey()));
} else {
tooltip.add(String.valueOf(entry.getValue()));
}
break;
}
topShift += LINE_HEIGHT;
}
}
}
return tooltip;
}
@Override
public boolean keyTyped(GuiContainer gui, char keyChar, int keyCode) {
if (NEIClientConfig.getBooleanSetting("inventory.guirecipe.handlerInfo") && showWidget
&& keyCode == Keyboard.KEY_C
&& NEIClientUtils.controlKey()) {
final int spaceWidth = GuiDraw.fontRenderer.getStringWidth(": ");
final Point mouse = GuiDraw.getMousePosition();
if (mouse.x >= this.x + INLINE_PADDING + LABEL_WIDTH + spaceWidth
&& mouse.x < this.x + WINDOW_WIDTH - INLINE_PADDING) {
int topShift = this.y + BORDER_PADDING + 12 + 6;
for (Map.Entry<String, String> entry : getDetailsInfo().entrySet()) {
if (mouse.y >= topShift && mouse.y < topShift + LINE_HEIGHT) {
GuiScreen.setClipboardString(entry.getValue());
return true;
}
topShift += LINE_HEIGHT;
}
}
}
return false;
}
@Override
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
return false;
}
@Override
public void onKeyTyped(GuiContainer gui, char keyChar, int keyID) {}
@Override
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
if (NEIClientConfig.getBooleanSetting("inventory.guirecipe.handlerInfo") && keyID == Keyboard.KEY_D
&& NEIClientUtils.shiftKey()) {
showWidget = !showWidget;
return true;
} else if (this.handler != null) {
return this.order.focused() || this.yShift.focused()
|| this.handlerHeight.focused()
|| this.handlerWidth.focused()
|| this.maxRecipesPerPage.focused();
}
return false;
}
@Override
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
if (this.handler != null
&& new Rectangle4i(this.x + INLINE_PADDING, this.y + BORDER_PADDING, this.w - INLINE_PADDING * 2, 12)
.contains(mousex, mousey)) {
this.dragPoint = new Point(mousex, mousey);
}
}
@Override
public boolean contains(int px, int py) {
return this.handler != null && super.contains(px, py);
}
@Override
public void onMouseUp(GuiContainer gui, int mousex, int mousey, int button) {
this.dragPoint = null;
}
@Override
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
return false;
}
@Override
public void onMouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {}
@Override
public boolean handleClickExt(int mx, int my, int button) {
return false;
}
@Override
public void onMouseDragged(GuiContainer gui, int mousex, int mousey, int button, long heldTime) {
if (this.dragPoint != null) {
this.x -= this.dragPoint.x - mousex;
this.y -= this.dragPoint.y - mousey;
this.dragPoint.move(mousex, mousey);
}
}
public void drawGuiPlaceholder(NEIRecipeWidget widget) {
if (!showWidget) return;
NEIClientUtils.gl2DRenderContext(() -> {
// background
GuiDraw.drawRect(
widget.x,
widget.y,
widget.w,
widget.h,
COLORS[widget.handlerRef.recipeIndex % COLORS.length]);
// blue-line-top (grid-top)
GuiDraw.drawRect(widget.x + 14, widget.y + 5, widget.w - 38, 1, 0xff0000aa);
// blue-line-bottom {grid-bottom}
GuiDraw.drawRect(widget.x + 14, widget.y + widget.h - 7, widget.w - 38, 1, 0xff0000aa);
// blue-left (grid start)
GuiDraw.drawRect(widget.x + 24, widget.y + (widget.h - 16) / 2, 1, 16, 0xffaa00aa);
// purple (before favorite)
GuiDraw.drawRect(
widget.x + Math.min(168, widget.w) - 27,
widget.y + widget.h - 6 - GuiRecipeButton.BUTTON_HEIGHT * 2 - 4,
GuiRecipeButton.BUTTON_WIDTH,
1,
0xffaa00aa);
// green ()
GuiDraw.drawRect(
widget.x + Math.min(168, widget.w) - 35,
widget.y + widget.h - 6 - GuiRecipeButton.BUTTON_HEIGHT - 3,
20,
1,
0xff00aa00);
// purple space before bottom grid
GuiDraw.drawRect(
widget.x + 14,
widget.y + widget.h - 7 - GuiRecipeButton.BUTTON_WIDTH / 2,
38,
1,
0xffaa00aa);
if (widget.handlerRef.handler instanceof TemplateRecipeHandler handler) {
int yShift = widget.getHandlerInfo().getYShift();
for (RecipeTransferRect rect : handler.transferRects) {
GuiDraw.drawRect(
widget.x + rect.rect.x,
widget.y + yShift + rect.rect.y,
rect.rect.width,
rect.rect.height,
0x40ff0000);
}
}
});
}
private static Map<String, String[]> patches = new HashMap<>();
public static void loadHandlerInfoPatch() {
ClientHandler.loadSettingsFile("handlers.patch", lines -> {
for (String line : lines.collect(Collectors.toCollection(HashSet::new))) {
final String[] parts = line.split(",");
final String handler = parts[0];
if (GuiRecipeTab.handlerMap.containsKey(handler)) {
final HandlerInfo info = GuiRecipeTab.handlerMap.get(handler);
final int yShift = intOrDefault(parts[1], info.getYShift());
final int height = intOrDefault(parts[2], info.getHeight());
final int width = intOrDefault(parts[3], info.getWidth());
final int maxRecipesPerPage = intOrDefault(parts[4], info.getMaxRecipesPerPage());
final int order = intOrDefault(parts[5], NEIClientConfig.handlerOrdering.getOrDefault(handler, 0));
final boolean useCustomScroll = intOrDefault(parts[6], info.getUseCustomScroll() ? 1 : 0) == 1;
info.setYShift(yShift);
info.setHandlerDimensions(height, width, maxRecipesPerPage);
info.setUseCustomScroll(useCustomScroll);
NEIClientConfig.handlerOrdering.put(handler, order);
}
patches.put(handler, parts);
}
});
}
private static void saveHandlerInfoPatch() {
final List<String> lines = new ArrayList<>();
for (String[] line : patches.values()) {
lines.add(String.join(",", line));
}
final File path = new File(NEIClientConfig.configDir, "handlers.patch");
try (FileOutputStream output = new FileOutputStream(path)) {
IOUtils.writeLines(lines, "\n", output, StandardCharsets.UTF_8);
} catch (IOException e) {}
}
private static int intOrDefault(String str, int defaultValue) {
if (str == null || str.equals("")) return defaultValue;
try {
return Integer.parseInt(str);
} catch (NumberFormatException e) {
return defaultValue;
}
}
private static String getHandlerID(IRecipeHandler handler) {
if (GuiRecipeTab.handlerMap.containsKey(handler.getHandlerId())) {
return handler.getHandlerId();
} else if (handler instanceof TemplateRecipeHandler) {
return handler.getOverlayIdentifier();
}
return null;
}
}
@@ -6,10 +6,10 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minecraft.client.entity.EntityClientPlayerMP;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.inventory.SlotCrafting;
@@ -50,17 +50,17 @@ public class DefaultOverlayHandler implements IOverlayHandler {
public Slot[] slots;
}
public DefaultOverlayHandler(int x, int y) {
offsetx = x;
offsety = y;
}
public int offsetx;
public int offsety;
public DefaultOverlayHandler() {
this(5, 11);
}
public int offsetx;
public int offsety;
public DefaultOverlayHandler(int x, int y) {
this.offsetx = x;
this.offsety = y;
}
@Override
public void overlayRecipe(GuiContainer gui, IRecipeHandler handler, int recipeIndex, boolean maxTransfer) {
@@ -72,7 +72,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
final List<PositionedStack> ingredients = handler.getIngredientStacks(recipeIndex);
final List<DistributedIngred> ingredStacks = getPermutationIngredients(ingredients);
if (!clearIngredients(gui)) return 0;
if (!clearIngredients(gui, handler)) return 0;
findInventoryQuantities(gui, ingredStacks);
@@ -98,13 +98,22 @@ public class DefaultOverlayHandler implements IOverlayHandler {
&& presenceOverlay(firstGui, handler, recipeIndex).stream().allMatch(state -> state.isPresent());
}
@Override
public boolean craft(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, int multiplier) {
final EntityClientPlayerMP thePlayer = NEIClientUtils.mc().thePlayer;
boolean craft = false;
protected Slot getCraftingResultSlot(GuiContainer gui) {
return gui.inventorySlots.inventorySlots.stream().filter(slot -> slot instanceof SlotCrafting).findFirst()
.orElse(null);
}
@Override
public boolean craft(GuiContainer firstGui, IRecipeHandler handler, int recipeIndex, int multiplier) {
final Slot craftingSlot = getCraftingResultSlot(firstGui);
if (craftingSlot == null) {
return false;
}
boolean craft = false;
while (multiplier > 0) {
final int transfer = transferRecipe(firstGui, recipe, recipeIndex, multiplier);
final int transfer = transferRecipe(firstGui, handler, recipeIndex, multiplier);
if (transfer <= 0) {
break;
@@ -112,43 +121,89 @@ public class DefaultOverlayHandler implements IOverlayHandler {
multiplier -= transfer;
for (Slot slot : firstGui.inventorySlots.inventorySlots) {
if (slot.getHasStack() && slot instanceof SlotCrafting && slot.canTakeStack(thePlayer)) {
FastTransferManager.clickSlot(firstGui, slot.slotNumber, 0, 1);
craft = true;
break;
}
if (craftingSlot.getHasStack() && craftingSlot.canTakeStack(firstGui.mc.thePlayer)) {
FastTransferManager.clickSlot(firstGui, craftingSlot.slotNumber, 0, 1);
craft = true;
}
}
clearIngredients(firstGui);
clearIngredients(firstGui, handler);
return craft;
}
private boolean clearIngredients(GuiContainer gui) {
final EntityClientPlayerMP thePlayer = NEIClientUtils.mc().thePlayer;
protected boolean clearIngredients(GuiContainer gui, IRecipeHandler handler) {
for (Slot slot : gui.inventorySlots.inventorySlots) {
if (slot.getHasStack() && !canMoveFrom(slot, gui)
&& !(slot instanceof SlotCrafting)
&& slot.canTakeStack(thePlayer)) {
for (Slot slot : getCraftMatrixSlots(gui, handler)) {
if (slot.canTakeStack(gui.mc.thePlayer)) {
FastTransferManager.clickSlot(gui, slot.slotNumber, 0, 1);
if (slot.getHasStack()) return false;
}
}
return dropOffMouseStack(thePlayer, gui);
FastTransferManager.dropHeldItem(gui);
return gui.mc.thePlayer.inventory.getItemStack() == null;
}
/**
* Gets the slots in the crafting matrix for the given GUI and recipe handler.
*
* @param gui
* @param handler
* @return
*/
protected Set<Slot> getCraftMatrixSlots(GuiContainer gui, IRecipeHandler handler) {
final PositionedStack firstIngr = handler.getIngredientStacks(0).get(0);
final Map<Integer, Slot> grid = new HashMap<>();
final Set<Slot> ingredSlots = new HashSet<>();
for (Slot slot : gui.inventorySlots.inventorySlots) {
final int key = (slot.xDisplayPosition - this.offsetx) * 10_000 + (slot.yDisplayPosition - this.offsety);
grid.put(key, slot);
}
int left = firstIngr.relx;
int top = firstIngr.rely;
int right = left;
int bottom = top;
while (grid.containsKey((left - 18) * 10_000 + firstIngr.rely)) {
left -= 18;
}
while (grid.containsKey((right + 18) * 10_000 + firstIngr.rely)) {
right += 18;
}
while (grid.containsKey(firstIngr.relx * 10_000 + (top - 18))) {
top -= 18;
}
while (grid.containsKey(firstIngr.relx * 10_000 + (bottom + 18))) {
bottom += 18;
}
for (int x = left; x <= right; x += 18) {
for (int y = top; y <= bottom; y += 18) {
final Slot slot = grid.get(x * 10_000 + y);
if (slot != null && !(slot.inventory instanceof InventoryPlayer)) {
ingredSlots.add(slot);
}
}
}
return ingredSlots;
}
private void moveIngredients(GuiContainer gui, List<IngredientDistribution> assignedIngredients, int multiplier) {
final EntityClientPlayerMP thePlayer = NEIClientUtils.mc().thePlayer;
final Slot craftingSlot = getCraftingResultSlot(gui);
for (Slot slot : gui.inventorySlots.inventorySlots) {
if (slot instanceof SlotCrafting || !slot.getHasStack()
if (slot == craftingSlot || !slot.getHasStack()
|| !canMoveFrom(slot, gui)
|| !slot.canTakeStack(thePlayer))
|| !slot.canTakeStack(gui.mc.thePlayer))
continue;
ItemStack stack = slot.getStack();
int slotTransferCap = stack.getMaxStackSize();
@@ -186,7 +241,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
}
if (thePlayer.inventory.getItemStack() != null) {
if (gui.mc.thePlayer.inventory.getItemStack() != null) {
FastTransferManager.clickSlot(gui, slot.slotNumber);
}
}
@@ -194,33 +249,6 @@ public class DefaultOverlayHandler implements IOverlayHandler {
}
}
protected boolean dropOffMouseStack(EntityPlayer entityPlayer, GuiContainer gui) {
if (entityPlayer.inventory.getItemStack() == null) {
return true;
}
for (int i = 0; i < gui.inventorySlots.inventorySlots.size(); i++) {
Slot slot = gui.inventorySlots.inventorySlots.get(i);
if (slot.inventory == entityPlayer.inventory) {
ItemStack mouseItem = entityPlayer.inventory.getItemStack();
ItemStack slotStack = slot.getStack();
if (slotStack == null || NEIClientUtils.areStacksSameType(mouseItem, slotStack)) {
FastTransferManager.clickSlot(gui, i, 0, 0);
}
if (entityPlayer.inventory.getItemStack() == null) {
return true;
}
}
}
return entityPlayer.inventory.getItemStack() == null;
}
private int calculateRecipeQuantity(List<IngredientDistribution> assignedIngredients) {
int quantity = Integer.MAX_VALUE;
@@ -399,8 +427,8 @@ public class DefaultOverlayHandler implements IOverlayHandler {
return null;
}
protected boolean canStack(ItemStack stack1, ItemStack stack2) {
if (stack1 == null || stack2 == null) return true;
return NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack1, stack2);
protected boolean canStack(ItemStack dst, ItemStack src) {
if (dst == null || src == null) return true;
return NEIClientUtils.areStacksSameTypeCraftingWithNBT(dst, src);
}
}
@@ -18,9 +18,10 @@ import codechicken.nei.ItemPanels;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.bookmark.BookmarksGridSlot;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.stackinfo.GTFluidStackStringifyHandler;
import codechicken.nei.recipe.TemplateRecipeHandler.RecipeTransferRect;
public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
@@ -36,10 +37,13 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
final Minecraft mc = NEIClientUtils.mc();
final RecipeId recipeId;
if ("item".equals(outputId)) {
for (int i = 0; i < results.length; i++) {
results[i] = normalizeItemStack((ItemStack) results[i]);
for (int i = 0; i < results.length; i++) {
if (results[i] instanceof ItemStack stack) {
results[i] = StackInfo.normalizeRecipeQueryStack(stack.copy());
}
}
if ("item".equals(outputId)) {
recipeId = getRecipeId(mc.currentScreen, (ItemStack) results[0]);
} else if ("recipeId".equals(outputId)) {
recipeId = (RecipeId) results[1];
@@ -74,7 +78,9 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
ArrayList<ICraftingHandler> serialCraftingHandlers = GuiCraftingRecipe.serialCraftingHandlers;
UnaryOperator<ICraftingHandler> recipeHandlerFunction;
if ("recipeId".equals(outputId)) {
if ("all".equals(outputId)) {
recipeHandlerFunction = GuiCraftingRecipe::buildAllRecipesHandler;
} else if ("recipeId".equals(outputId)) {
ItemStack stack = (ItemStack) results[0];
RecipeId recipeId = (RecipeId) results[1];
craftinghandlers = filterByHandlerName(craftinghandlers, recipeId.getHandleName());
@@ -95,6 +101,24 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
return recipeQuery.runWithProfiling(NEIClientUtils.translate("recipe.concurrent.crafting"));
}
private static ICraftingHandler buildAllRecipesHandler(ICraftingHandler handler) {
if (handler instanceof TemplateRecipeHandler templateHandler) {
TemplateRecipeHandler allHandler = templateHandler.newInstance();
if (allHandler.transferRects.isEmpty()) {
allHandler.loadCraftingRecipes("all");
return allHandler;
}
for (RecipeTransferRect rect : allHandler.transferRects) {
if (allHandler.specifyTransferRect() == null
|| allHandler.specifyTransferRect().equals(rect.outputId)) {
allHandler.loadCraftingRecipes(rect.outputId, rect.results);
return allHandler;
}
}
}
return handler.getRecipeHandler("all");
}
private static ArrayList<ICraftingHandler> filterByHandlerName(ArrayList<ICraftingHandler> craftinghandlers,
String handlerName) {
return craftinghandlers.stream().filter(h -> getHandlerName(h).equals(handlerName))
@@ -105,13 +129,6 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
return GuiRecipeTab.getHandlerInfo(handler).getHandlerName();
}
private static ItemStack normalizeItemStack(ItemStack stack) {
GTFluidStackStringifyHandler.replaceAE2FCFluidDrop = true;
stack = StackInfo.loadFromNBT(StackInfo.itemStackToNBT(stack));
GTFluidStackStringifyHandler.replaceAE2FCFluidDrop = false;
return stack;
}
public static RecipeId getRecipeId(GuiScreen gui, ItemStack stackover) {
if (gui instanceof GuiRecipe guiRecipe) {
@@ -126,7 +143,8 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
final BookmarksGridSlot panelSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
if (panelSlot != null) {
return panelSlot.isIngredient() || panelSlot.getRecipeId() == null ? FavoriteRecipes.getFavorite(stackover)
return panelSlot.getType() == BookmarkItemType.INGREDIENT || panelSlot.getRecipeId() == null
? FavoriteRecipes.getFavorite(stackover)
: panelSlot.getRecipeId();
}
@@ -54,7 +54,7 @@ public class GuiFavoriteButton extends GuiRecipeButton {
super(handlerRef, x, y, BUTTON_ID_START + handlerRef.recipeIndex, "❤");
this.recipe = Recipe.of(this.handlerRef);
ItemStack stack = FavoriteRecipes.getFavorite(this.recipe.getRecipeId());
ItemStack stack = FavoriteRecipes.getManualFavorite(this.recipe.getRecipeId());
this.favorite = stack != null;
if (stack == null) {
@@ -72,7 +72,7 @@ public class GuiFavoriteButton extends GuiRecipeButton {
}
public boolean isFavorite() {
return favorite;
return this.favorite;
}
public void toggleFavorite() {
@@ -86,6 +86,11 @@ public class GuiFavoriteButton extends GuiRecipeButton {
.setFavorite(this.favoriteResult.getItemStack(), this.favorite ? this.recipe.getRecipeId() : null);
}
@Override
public void update() {
this.favorite = this.favorite && FavoriteRecipes.getManualFavorite(this.recipe.getRecipeId()) != null;
}
@Override
protected void drawContent(Minecraft minecraft, int y, int x, boolean mouseOver) {
final DrawableResource icon = isFavorite() ? ICON_STATE_ON : ICON_STATE_OFF;
@@ -141,7 +146,6 @@ public class GuiFavoriteButton extends GuiRecipeButton {
@Override
public List<String> handleTooltip(List<String> currenttip) {
currenttip.add(translate("recipe.favorite"));
return currenttip;
}
@@ -173,7 +177,7 @@ public class GuiFavoriteButton extends GuiRecipeButton {
this.selectedResult = results.get(nextIndex);
this.favorite = StackInfo.equalItemAndNBT(
results.get(nextIndex).getItemStack(),
FavoriteRecipes.getFavorite(this.recipe.getRecipeId()),
FavoriteRecipes.getManualFavorite(this.recipe.getRecipeId()),
true);
return true;
@@ -201,29 +205,47 @@ public class GuiFavoriteButton extends GuiRecipeButton {
if (stack == null) {
stack = ingr.getItemStack();
RecipeId recipeId = FavoriteRecipes.getFavorite(stack);
RecipeId recipeId = FavoriteRecipes.getManualFavorite(stack);
if (recipeId == null) {
for (ItemStack permStack : permutations) {
if ((recipeId = FavoriteRecipes.getFavorite(permStack)) != null) {
if ((recipeId = FavoriteRecipes.getManualFavorite(permStack)) != null) {
stack = permStack;
break;
}
}
}
Recipe recipe = Recipe.of(recipeId);
if (recipeId == null) {
recipeId = FavoriteRecipes.getGeneratedFavorite(stack);
}
if (recipe == null) {
stack = null;
} else {
items.add(stack);
if (depth >= 0) {
result.add(recipe);
localLoop.add(recipe);
if (recipeId == null) {
for (ItemStack permStack : permutations) {
if ((recipeId = FavoriteRecipes.getGeneratedFavorite(permStack)) != null) {
stack = permStack;
break;
}
}
}
if (recipeId != null && FavoriteRecipes.FAVORITE_ITEM.contains(recipeId.getHandleName())) {
items.add(stack);
} else {
Recipe recipe = Recipe.of(recipeId);
if (recipe == null) {
stack = null;
} else {
items.add(stack);
if (depth >= 0) {
result.add(recipe);
localLoop.add(recipe);
}
}
}
}
if (stack != null) {
@@ -3,7 +3,6 @@ package codechicken.nei.recipe;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import net.minecraft.client.Minecraft;
@@ -97,9 +96,11 @@ public class GuiOverlayButton extends GuiRecipeButton {
super(handlerRef, x, y, handlerRef.recipeIndex + BUTTON_ID_SHIFT, "+");
this.firstGui = firstGui != null && firstGui.inventorySlots != null ? firstGui : null;
this.canUseOverlayRenderer = this.firstGui != null && handlerRef.getRecipeOverlayRenderer(firstGui) != null;
this.canFillCraftingGrid = this.firstGui != null && handlerRef.getOverlayHandler(firstGui) != null;
this.hasOverlay = this.canUseOverlayRenderer || this.canFillCraftingGrid;
if (this.firstGui != null) {
this.canUseOverlayRenderer = this.handlerRef.getRecipeOverlayRenderer(this.firstGui) != null;
this.canFillCraftingGrid = this.handlerRef.canFillCraftingGrid(this.firstGui);
this.hasOverlay = this.canUseOverlayRenderer || this.handlerRef.getOverlayHandler(this.firstGui) != null;
}
setRequireShiftForOverlayRecipe(NEIClientConfig.requireShiftForOverlayRecipe());
ingredientsOverlay();
@@ -107,16 +108,20 @@ public class GuiOverlayButton extends GuiRecipeButton {
@Override
public List<String> handleTooltip(List<String> currenttip) {
currenttip.add(NEIClientUtils.translate("recipe.overlay"));
if (!this.enabled && requireShiftForOverlayRecipe() && canFillCraftingGrid()) {
currenttip.set(currenttip.size() - 1, currenttip.get(currenttip.size() - 1) + GuiDraw.TOOLTIP_LINESPACE);
currenttip.add(
EnumChatFormatting.RED + NEIClientUtils.translate("recipe.overlay.mismatch")
+ EnumChatFormatting.RESET);
} else if (this.missedMaterialsTooltipLineHandler != null) {
if (!this.enabled || this.missedMaterialsTooltipLineHandler != null && this.canFillCraftingGrid) {
currenttip.add(NEIClientUtils.translate("recipe.overlay") + GuiDraw.TOOLTIP_LINESPACE);
} else {
currenttip.add(NEIClientUtils.translate("recipe.overlay"));
}
if ((!requireShiftForOverlayRecipe() || NEIClientUtils.shiftKey()) && canFillCraftingGrid()) {
if (!this.enabled) {
currenttip.add(EnumChatFormatting.RED + NEIClientUtils.translate("recipe.overlay.mismatch"));
}
if (this.missedMaterialsTooltipLineHandler != null && this.canFillCraftingGrid) {
if (!requireShiftForOverlayRecipe() || NEIClientUtils.shiftKey()) {
this.missedMaterialsTooltipLineHandler.setLabelColor(EnumChatFormatting.RED);
} else {
this.missedMaterialsTooltipLineHandler.setLabelColor(EnumChatFormatting.GRAY);
@@ -174,7 +179,7 @@ public class GuiOverlayButton extends GuiRecipeButton {
protected void drawContent(Minecraft minecraft, int y, int x, boolean mouseOver) {
DrawableResource icon = ICON_OVERLAY;
if (hasOverlay() && (!requireShiftForOverlayRecipe() || NEIClientUtils.shiftKey())) {
if (this.canFillCraftingGrid && (!requireShiftForOverlayRecipe() || NEIClientUtils.shiftKey())) {
icon = this.missedMaterialsTooltipLineHandler == null ? ICON_FILL : ICON_FILL_ERROR;
}
@@ -212,10 +217,12 @@ public class GuiOverlayButton extends GuiRecipeButton {
if (this.itemPresenceCache.size() != ingredients.size()) {
this.itemPresenceCache.clear();
if (canFillCraftingGrid()) {
if (this.firstGui != null) {
this.itemPresenceCache.addAll(this.handlerRef.getPresenceOverlay(this.firstGui));
} else if (this.firstGui != null) {
this.itemPresenceCache.addAll(presenceOverlay(ingredients));
if (this.itemPresenceCache.isEmpty()) {
this.itemPresenceCache.addAll(presenceOverlay(ingredients));
}
}
final List<ItemStack> items = this.itemPresenceCache.stream().filter(state -> !state.isPresent())
@@ -230,6 +237,8 @@ public class GuiOverlayButton extends GuiRecipeButton {
} else {
this.missedMaterialsTooltipLineHandler = null;
}
updateEnabled();
}
return this.itemPresenceCache;
@@ -237,7 +246,12 @@ public class GuiOverlayButton extends GuiRecipeButton {
public void setRequireShiftForOverlayRecipe(boolean require) {
this.requireShiftForOverlayRecipe = require;
this.enabled = hasOverlay() && (this.requireShiftForOverlayRecipe || canFillCraftingGrid());
updateEnabled();
}
private void updateEnabled() {
this.enabled = hasOverlay() || this.canFillCraftingGrid
&& (this.requireShiftForOverlayRecipe || this.missedMaterialsTooltipLineHandler == null);
}
public void setCanUseOverlayRenderer(boolean use) {
@@ -253,7 +267,7 @@ public class GuiOverlayButton extends GuiRecipeButton {
}
public boolean canFillCraftingGrid() {
return this.missedMaterialsTooltipLineHandler == null || this.handlerRef.canFillCraftingGrid(this.firstGui);
return this.canFillCraftingGrid && this.missedMaterialsTooltipLineHandler == null;
}
public boolean hasOverlay() {
@@ -265,7 +279,7 @@ public class GuiOverlayButton extends GuiRecipeButton {
}
protected List<ItemOverlayState> presenceOverlay(List<PositionedStack> ingredients) {
final List<ItemOverlayState> itemPresenceSlots = new ArrayList<>();
final List<ItemOverlayState> states = new ArrayList<>();
final List<ItemStack> invStacks = this.firstGui.inventorySlots.inventorySlots.stream()
.filter(
s -> s != null && s.getStack() != null
@@ -275,28 +289,29 @@ public class GuiOverlayButton extends GuiRecipeButton {
.map(s -> s.getStack().copy()).collect(Collectors.toCollection(ArrayList::new));
for (PositionedStack stack : ingredients) {
Optional<ItemStack> used = invStacks.stream().filter(is -> is.stackSize > 0 && stack.contains(is))
.findAny();
boolean found = false;
itemPresenceSlots.add(new ItemOverlayState(stack, used.isPresent()));
if (used.isPresent()) {
ItemStack is = used.get();
is.stackSize -= 1;
for (ItemStack is : invStacks) {
if (is.stackSize > 0 && stack.contains(is)) {
is.stackSize--;
found = true;
break;
}
}
states.add(new ItemOverlayState(stack, found));
}
return itemPresenceSlots;
return states;
}
public void overlayRecipe(boolean shift) {
if (!hasOverlay()) return;
if (!requireShiftForOverlayRecipe() || shift) {
if (canFillCraftingGrid()) {
if (this.canFillCraftingGrid) {
this.handlerRef.fillCraftingGrid(this.firstGui, 0);
}
} else if (useOverlayRenderer()) {
} else if (hasOverlay() && useOverlayRenderer()) {
this.handlerRef.useOverlayRenderer(this.firstGui);
}
@@ -313,8 +328,11 @@ public class GuiOverlayButton extends GuiRecipeButton {
final Recipe recipe = getRecipe();
if (!ItemPanels.bookmarkPanel.removeRecipe(recipe.getRecipeId(), BookmarkGrid.DEFAULT_GROUP_ID)) {
ItemPanels.bookmarkPanel
.addRecipe(recipe, NEIClientUtils.controlKey() ? 1 : 0, BookmarkGrid.DEFAULT_GROUP_ID);
ItemPanels.bookmarkPanel.addRecipe(
recipe,
NEIClientUtils.controlKey()
|| NEIClientConfig.getBooleanSetting("inventory.bookmarks.bookmarkRecipeWithCount") ? 1 : 0,
BookmarkGrid.DEFAULT_GROUP_ID);
}
}
@@ -17,6 +17,7 @@ import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
@@ -52,29 +53,31 @@ import codechicken.nei.scroll.ScrollBar;
import codechicken.nei.scroll.ScrollBar.OverflowType;
import codechicken.nei.scroll.ScrollBar.ScrollPlace;
import codechicken.nei.scroll.ScrollContainer;
import codechicken.nei.util.NEIMouseUtils;
import codechicken.nei.util.SlotInaccessible;
public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer implements IGuiContainerOverlay,
IGuiClientSide, IGuiHandleMouseWheel, IContainerTooltipHandler, INEIGuiHandler {
private static final int BORDER_PADDING = 5;
private final DrawableResource BG_TEXTURE = new DrawableBuilder("nei:textures/gui/recipebg.png", 0, 0, 176, 166)
.build();
private static final int TRANSPARENCY_BORDER = 4;
private final DrawableResource BG_TEXTURE = new DrawableBuilder(
"nei:textures/gui/recipebg.png",
0,
0,
176 + TRANSPARENCY_BORDER * 2,
166 + TRANSPARENCY_BORDER * 2).build();
private static final int BUTTON_WIDTH = 13;
private static final int BUTTON_HEIGHT = 12;
protected static final ScrollBar VERTICAL_SCROLLBAR = new ScrollBar().setScrollbarSize(14)
.setOverflowType(OverflowType.AUTO).setScrollPlace(ScrollPlace.OUTSIDE)
protected static final ScrollBar VERTICAL_SCROLLBAR = new ScrollBar().setTrackWidth(14)
.setOverflowType(OverflowType.AUTO).setScrollPlace(ScrollPlace.END)
.setTrackTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 42, 90, 13, 21).build(), 9, 9)
.setThumbTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 21, 96, 8, 9).build(), 3, 2)
.setThumbPadding(6);
.setThumbTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 22, 96, 6, 9).build(), 3, 2)
.setThumbPadding(1, 6, 0, 6);
public static final List<IRecipeFilterProvider> recipeFilterers = new LinkedList<>();
protected AcceptsFollowingTooltipLineHandler acceptsFollowingTooltipLineHandler;
// some mods reflect this properties
public ArrayList<H> currenthandlers = new ArrayList<>();
public int page;
@@ -89,12 +92,12 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
private GuiButton prevtype;
private GuiButton nexttype;
protected String recipePageCacheKey = "";
private int lastPage = -1;
private final GuiRecipeTabs recipeTabs;
private final GuiRecipeCatalyst recipeCatalyst;
private SearchRecipeHandler<H> handler;
private HandlerInfo handlerInfo;
private RecipePageManager handlerPages;
protected static final RestartableTask updateFilter = new RestartableTask("NEI Recipe Filtering") {
@@ -109,7 +112,6 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
if (GuiRecipe.searchField.text().isEmpty()) {
searchHandler.setSearchIndices(null);
guiRecipe.changePage(0);
} else {
final IRecipeFilter filter = GuiRecipe.searchField.getRecipeFilter();
final List<Integer> filtered = searchHandler.getSearchResult(filter);
@@ -120,10 +122,8 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
if (interrupted()) return;
searchHandler.setSearchIndices(filtered);
guiRecipe.changePage(0);
}
guiRecipe.recipePageCacheKey = "";
}
}
@@ -137,7 +137,8 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
@Override
protected boolean noResults() {
final GuiScreen currentScreen = NEIClientUtils.mc().currentScreen;
return !(currentScreen instanceof GuiRecipe) || ((GuiRecipe<?>) currentScreen).numRecipes() > 0;
return !(currentScreen instanceof GuiRecipe)
|| ((GuiRecipe<?>) currentScreen).handlerPages.getNumRecipes() > 0;
}
@Override
@@ -199,6 +200,36 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
this.firstGui = gui.getFirstScreen();
this.firstGuiGeneral = gui.getFirstScreenGeneral();
}
this.prevtype = new GuiNEIButton(0, 0, 0, BUTTON_WIDTH, BUTTON_HEIGHT, "<") {
@Override
public void mouseReleased(int mouseX, int mouseY) {
prevType();
}
};
this.nexttype = new GuiNEIButton(1, 0, 0, BUTTON_WIDTH, BUTTON_HEIGHT, ">") {
@Override
public void mouseReleased(int mouseX, int mouseY) {
nextType();
}
};
this.prevpage = new GuiNEIButton(2, 0, 0, BUTTON_WIDTH, BUTTON_HEIGHT, "<") {
@Override
public void mouseReleased(int mouseX, int mouseY) {
prevPage();
}
};
this.nextpage = new GuiNEIButton(3, 0, 0, BUTTON_WIDTH, BUTTON_HEIGHT, ">") {
@Override
public void mouseReleased(int mouseX, int mouseY) {
nextPage();
}
};
}
/**
@@ -272,7 +303,19 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
}
private ScrollContainer container = new ScrollContainer();
private ScrollContainer container = new ScrollContainer() {
@Override
public Widget getWidgetUnderMouse(int mousex, int mousey) {
if (handlerInfo.getUseCustomScroll() && !this.widgets.isEmpty()) {
return this.widgets.get(0);
}
return super.getWidgetUnderMouse(mousex, mousey);
}
};
@Override
public void initGui() {
@@ -292,35 +335,18 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
final int rightButtonX = this.guiLeft + this.xSize - BORDER_PADDING - BUTTON_WIDTH + 1;
final int leftButtonX = this.guiLeft + BORDER_PADDING;
this.prevtype = new GuiNEIButton(0, leftButtonX, guiTop + 3, BUTTON_WIDTH, BUTTON_HEIGHT, "<") {
this.prevtype.xPosition = leftButtonX;
this.prevtype.yPosition = guiTop + 3;
this.nexttype.xPosition = rightButtonX;
this.nexttype.yPosition = guiTop + 3;
this.prevpage.xPosition = leftButtonX;
this.prevpage.yPosition = guiTop + 17;
this.nextpage.xPosition = rightButtonX;
this.nextpage.yPosition = guiTop + 17;
@Override
public void mouseReleased(int mouseX, int mouseY) {
prevType();
}
};
this.nexttype = new GuiNEIButton(1, rightButtonX, guiTop + 3, BUTTON_WIDTH, BUTTON_HEIGHT, ">") {
@Override
public void mouseReleased(int mouseX, int mouseY) {
nextType();
}
};
this.prevpage = new GuiNEIButton(2, leftButtonX, guiTop + 17, BUTTON_WIDTH, BUTTON_HEIGHT, "<") {
@Override
public void mouseReleased(int mouseX, int mouseY) {
prevPage();
}
};
this.nextpage = new GuiNEIButton(3, rightButtonX, guiTop + 17, BUTTON_WIDTH, BUTTON_HEIGHT, ">") {
@Override
public void mouseReleased(int mouseX, int mouseY) {
nextPage();
}
};
this.container.x = this.guiLeft + 3;
this.container.y = this.guiTop + 32;
this.container.h = this.ySize - 32 - 5;
GuiRecipe.toggleSearch.icon = new DrawableBuilder("nei:textures/nei_sprites.png", 0, 76, 10, 10).build();
GuiRecipe.toggleSearch.w = GuiRecipe.toggleSearch.h = 12;
@@ -333,9 +359,8 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
GuiRecipe.searchField.h = 14;
this.buttonList.addAll(Arrays.asList(this.prevtype, this.nexttype, this.prevpage, this.nextpage));
this.recipePageCacheKey = "";
if (currenthandlers.size() == 1) {
if (this.currenthandlers.size() == 1) {
this.prevtype.visible = false;
this.nexttype.visible = false;
}
@@ -343,34 +368,11 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
this.recipeTabs.update(this);
}
private void updateRecipePage() {
final List<Integer> indices = getRecipeIndices();
final String cacheKey = indices.isEmpty() ? "empty"
: handlerInfo.getHandlerName() + ":" + indices.get(0) + ":" + indices.get(indices.size() - 1);
protected void refreshContainer() {
if (!cacheKey.equals(this.recipePageCacheKey)) {
this.recipePageCacheKey = cacheKey;
final boolean expandVertically = this.handlerInfo.expandVertically();
final List<Widget> widgets = new ArrayList<>();
int shiftY = 0;
for (int recipeIndex : indices) {
final NEIRecipeWidget widget = RecipeHandlerRef.of(this.handler.original, recipeIndex)
.getRecipeWidget();
widget.setLocation(Math.max(0, (this.container.w - widget.w) / 2), shiftY);
if (expandVertically) {
widget.h = Math.min(
this.handlerInfo.getHeight() + this.handlerInfo.getYShift(),
this.container.getVisibleHeight());
}
widgets.add(widget);
shiftY += widget.h;
}
this.container.setWidgets(widgets);
if (this.handlerPages.rebuildPages() || this.lastPage != this.handlerPages.getCurrentPageIndex()) {
this.lastPage = this.handlerPages.getCurrentPageIndex();
this.container.setWidgets(this.handlerPages.getCurrentPageWidgets());
if (this.handlerInfo.getUseCustomScroll()) {
this.container.setVerticalScroll(null);
@@ -379,10 +381,12 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
} else {
this.container.setVerticalScroll(
ScrollBar.defaultVerticalBar().setOverflowType(OverflowType.OVERLAY)
.setScrollPlace(ScrollPlace.OUTSIDE));
.setTrackPadding(-8, 0, 0, 0));
}
}
this.recipeCatalyst.setCatalysts(RecipeCatalysts.getRecipeCatalysts(this.handler.original));
this.container.update();
}
public static IRecipeFilter getRecipeListFilter() {
@@ -408,24 +412,20 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
return GuiRecipe.searchField.getFilter();
}
public void setRecipePage(int idx) {
setRecipePage(idx, 0);
}
public void setRecipePage(int idx, int refIndex) {
protected void setRecipePage(int idx) {
this.recipetype = (this.currenthandlers.size() + idx) % this.currenthandlers.size();
this.handler = new SearchRecipeHandler<>(this.currenthandlers.get(this.recipetype));
this.handlerInfo = GuiRecipeTab.getHandlerInfo(this.handler.original);
this.container.w = Math.max(this.xSize - 6, this.handlerInfo.getWidth());
this.handlerPages = new RecipePageManager(this.handler, this.handlerInfo, this.container);
this.prevpage.enabled = this.nextpage.enabled = this.handlerPages.getNumPages() > 1;
this.lastPage = -1;
GuiRecipe.searchField.setText("");
GuiRecipe.searchField.setVisible(false);
GuiRecipe.toggleSearch.state = 0;
this.container.setVerticalScrollOffset(0);
this.container.setHorizontalScrollOffset(0);
this.page = Math.min(Math.max(0, refIndex), this.numRecipes() - 1) / getRecipesPerPage();
changePage(0);
this.recipeTabs.update(this);
}
@@ -455,7 +455,8 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
}
setRecipePage(recipetype, Math.max(0, refIndex));
setRecipePage(recipetype);
this.handlerPages.gotoRefIndex(Math.max(0, refIndex));
return refIndex;
}
@@ -520,20 +521,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
public List<Integer> getRecipeIndices() {
final int recipesPerPage = getRecipesPerPage();
final int minIndex = this.page * recipesPerPage;
final int maxIndex = Math.min(this.numRecipes(), (this.page + 1) * recipesPerPage);
final List<Integer> range = new ArrayList<>();
for (int index = minIndex; index < maxIndex; index++) {
range.add(this.handler.ref(index));
}
return range;
}
private int numRecipes() {
return this.handler == null ? 0 : this.handler.numRecipes();
return this.handlerPages.getRecipeIndices();
}
@Override
@@ -616,6 +604,15 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
return;
}
if (button == 0 && isHandlerTitleHovered(mousex, mousey)) {
if (this instanceof GuiCraftingRecipe) {
GuiCraftingRecipe.openRecipeGui("all");
} else if (this instanceof GuiUsageRecipe) {
GuiUsageRecipe.openRecipeGui("all");
}
return;
}
super.mouseClicked(mousex, mousey, button);
}
@@ -699,20 +696,13 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
public void updateScreen() {
super.updateScreen();
this.container.x = this.guiLeft + 3;
this.container.y = this.guiTop + 32;
this.container.w = Math.max(this.xSize - 6, this.handlerInfo.getWidth());
this.container.h = this.ySize - 32 - 5;
this.handler.original.onUpdate();
refreshPage();
this.container.update();
refreshContainer();
this.recipeCatalyst.setAvailableHeight(this.container.h);
this.recipeCatalyst.update();
this.recipeCatalyst.setAvailableHeight(this.ySize - 5);
this.recipeCatalyst.y = this.guiTop;
this.recipeCatalyst.x = this.guiLeft - this.recipeCatalyst.w + 6;
this.recipeCatalyst.x = this.guiLeft - this.recipeCatalyst.w + 4;
this.recipeCatalyst.update();
}
@Override
@@ -728,12 +718,16 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
this.recipeTabs.handleTooltip(mousex, mousey, currenttip);
if (currenttip.isEmpty() && isHandlerTitleHovered(mousex, mousey)) {
currenttip.add(NEIClientUtils.translate("recipe.tab.view_all.tooltip"));
}
if (currenttip.isEmpty() && GuiRecipe.searchField.isVisible()
&& new Rectangle(GuiRecipe.searchField.x + GuiRecipe.searchField.w, 15, 44, 16)
.contains(mousex - this.guiLeft, mousey - this.guiTop)) {
final String pageInfo = String
.format("%d/%d", page + 1, Math.max(1, this.numRecipes() - 1) / getRecipesPerPage() + 1);
.format("%d/%d", this.handlerPages.getCurrentPageIndex() + 1, this.handlerPages.getNumPages());
if (this.fontRendererObj.getStringWidth(pageInfo) >= 45) {
currenttip.add(pageInfo);
@@ -752,30 +746,6 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
currenttip = recipeWidget.handleItemTooltip(itemstack, mousex, mousey, currenttip);
}
if (NEIClientConfig.showCycledIngredientsTooltip() && itemstack != null) {
PositionedStack hovered = null;
if (activeWidget instanceof NEIRecipeWidget recipeWidget) {
hovered = recipeWidget.getPositionedStackMouseOver(mousex, mousey);
}
if (hovered == null || hovered.items.length <= 1) {
this.acceptsFollowingTooltipLineHandler = null;
} else if (this.acceptsFollowingTooltipLineHandler == null
|| this.acceptsFollowingTooltipLineHandler.tooltipGUID != hovered) {
this.acceptsFollowingTooltipLineHandler = AcceptsFollowingTooltipLineHandler
.of(hovered, hovered.getFilteredPermutations(), hovered.item);
}
} else if (this.acceptsFollowingTooltipLineHandler != null) {
this.acceptsFollowingTooltipLineHandler = null;
}
if (this.acceptsFollowingTooltipLineHandler != null) {
this.acceptsFollowingTooltipLineHandler
.setActiveStack(((PositionedStack) this.acceptsFollowingTooltipLineHandler.tooltipGUID).item);
currenttip.add(GuiDraw.TOOLTIP_HANDLER + GuiDraw.getTipLineId(this.acceptsFollowingTooltipLineHandler));
}
return currenttip;
}
@@ -790,23 +760,15 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
hotkeys = this.container.handleHotkeys(mousex, mousey, hotkeys);
}
if (this.acceptsFollowingTooltipLineHandler != null) {
hotkeys.put(
NEIClientUtils.getKeyName(
NEIClientUtils.SHIFT_HASH,
NEIMouseUtils.MOUSE_BTN_NONE + NEIMouseUtils.MOUSE_SCROLL),
NEIClientUtils.translate("recipe.accepts.scroll"));
}
return hotkeys;
}
private void nextPage() {
changePage(1);
this.handlerPages.changePage(1);
}
private void prevPage() {
changePage(-1);
this.handlerPages.changePage(-1);
}
protected void nextType() {
@@ -817,73 +779,48 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
setRecipePage(--recipetype);
}
protected void changePage(int shift) {
final int recipesPerPage = getRecipesPerPage();
final int numRecipes = this.numRecipes();
final int oldPage = this.page;
if (numRecipes > 0) {
final int numPages = (int) Math.ceil(numRecipes / (float) recipesPerPage);
this.page = Math.min(Math.max(0, this.page), numPages);
this.page = (numPages + this.page + shift) % numPages;
} else {
this.page = 0;
}
if (this.page != oldPage) {
this.container.setVerticalScrollOffset(0);
this.container.setHorizontalScrollOffset(0);
}
}
public GuiRecipeCatalyst getRecipeCatalystWidget() {
return this.recipeCatalyst;
}
public void forceRefreshPage() {
this.buttonList.removeIf(Arrays.asList(this.overlayButtons)::contains);
this.overlayButtons = new GuiOverlayButton[0];
this.currenthandlers.sort(NEIClientConfig.HANDLER_COMPARATOR);
this.recipePageCacheKey = "";
refreshPage();
}
public void refreshPage() {
changePage(0);
final int recipesPerPage = getRecipesPerPage();
final boolean multiplepages = this.numRecipes() > recipesPerPage;
final int currentPage = this.handlerPages.getCurrentPageIndex();
setRecipePage(this.recipetype);
this.handlerPages.changePage(currentPage);
this.prevpage.enabled = this.nextpage.enabled = multiplepages;
this.recipeCatalyst.setCatalysts(RecipeCatalysts.getRecipeCatalysts(this.handler.original));
updateRecipePage();
refreshContainer();
}
@Override
public void drawGuiContainerForegroundLayer(int mouseX, int mouseY) {
GL11.glTranslatef(-guiLeft, -guiTop, 0);
this.container.draw(mouseX, mouseY);
if (NEIClientConfig.getJEIStyleRecipeCatalysts() != 0 && this.recipeCatalyst.isShowWidget()) {
this.recipeCatalyst.draw(mouseX, mouseY);
}
GL11.glTranslatef(guiLeft, guiTop, 0);
}
@Override
public void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY) {
BG_TEXTURE.draw(
this.guiLeft,
this.guiTop,
this.xSize,
this.ySize,
BORDER_PADDING,
BORDER_PADDING,
BORDER_PADDING,
BORDER_PADDING);
this.guiLeft - TRANSPARENCY_BORDER,
this.guiTop - TRANSPARENCY_BORDER,
this.xSize + TRANSPARENCY_BORDER * 2,
this.ySize + TRANSPARENCY_BORDER * 2,
BORDER_PADDING + TRANSPARENCY_BORDER,
BORDER_PADDING + TRANSPARENCY_BORDER,
BORDER_PADDING + TRANSPARENCY_BORDER,
BORDER_PADDING + TRANSPARENCY_BORDER);
drawJEITabs(mouseX, mouseY);
}
private void drawJEITabs(int mouseX, int mouseY) {
final int recipesPerPage = getRecipesPerPage();
final int textMiddle = (BUTTON_WIDTH - this.fontRendererObj.FONT_HEIGHT) / 2;
drawRect(
@@ -899,9 +836,11 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
this.prevpage.yPosition + BUTTON_HEIGHT,
0x30000000);
final String handlerTitle = this.handler.original.getRecipeName().trim();
final String titleColorCode = getHandlerTitleColorCode(isHandlerTitleHovered(mouseX, mouseY));
drawCenteredString(
this.fontRendererObj,
this.handler.original.getRecipeName().trim(),
titleColorCode + handlerTitle + EnumChatFormatting.RESET,
this.guiLeft + this.xSize / 2,
this.prevtype.yPosition + textMiddle,
0xffffff);
@@ -917,7 +856,10 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
if (GuiRecipe.searchField.isVisible()) {
final String recipePage = NEIClientUtils.cropText(
this.fontRendererObj,
String.format("%d/%d", this.page + 1, Math.max(0, numRecipes() - 1) / recipesPerPage + 1),
String.format(
"%d/%d",
this.handlerPages.getCurrentPageIndex() + 1,
this.handlerPages.getNumPages()),
45);
drawCenteredString(
this.fontRendererObj,
@@ -926,8 +868,10 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
this.prevpage.yPosition + textMiddle,
0xffffff);
} else {
final String recipePage = NEIClientUtils
.translate("recipe.page", this.page + 1, Math.max(0, numRecipes() - 1) / recipesPerPage + 1);
final String recipePage = NEIClientUtils.translate(
"recipe.page",
this.handlerPages.getCurrentPageIndex() + 1,
this.handlerPages.getNumPages());
drawCenteredString(
this.fontRendererObj,
recipePage,
@@ -940,15 +884,28 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
RenderHelper.enableGUIStandardItemLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
this.recipeTabs.draw(mouseX, mouseY);
if (NEIClientConfig.areJEIStyleRecipeCatalystsVisible()) {
this.recipeCatalyst.draw(mouseX, mouseY);
}
RenderHelper.disableStandardItemLighting();
}
}
private boolean isHandlerTitleHovered(int mousex, int mousey) {
final String handlerTitle = this.handler.original.getRecipeName().trim();
final int titleWidth = this.fontRendererObj.getStringWidth(handlerTitle);
final int textMiddle = (BUTTON_WIDTH - this.fontRendererObj.FONT_HEIGHT) / 2;
final int titleX = this.guiLeft + (this.xSize - titleWidth) / 2;
final int titleY = this.prevtype.yPosition + textMiddle;
return new Rectangle(titleX, titleY, titleWidth, this.fontRendererObj.FONT_HEIGHT).contains(mousex, mousey);
}
private String getHandlerTitleColorCode(boolean hovered) {
final String key = hovered ? "recipe.title.color.hover" : "recipe.title.color.normal";
final String translated = NEIClientUtils.translate(key);
if (!translated.startsWith("nei.")) { // Optional localization string for resource packs
return translated;
}
return hovered ? EnumChatFormatting.YELLOW.toString() : EnumChatFormatting.WHITE.toString();
}
@Override
public GuiContainer getFirstScreen() {
return this.firstGui;
@@ -959,19 +916,6 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
return this.firstGuiGeneral;
}
private int getRecipesPerPage() {
if (this.handlerInfo.getMaxRecipesPerPage() <= 1) {
return 1;
}
if (NEIClientConfig.getBooleanSetting("inventory.guirecipe.infiniteScroll")) {
return Math.max(1, this.handler.numRecipes());
}
return Math.max(this.container.h / (this.handlerInfo.getHeight() + this.handlerInfo.getYShift()), 1);
}
public Point getRecipePosition(int recipe) {
return getRefIndexPosition(getRecipeIndices().indexOf(recipe));
}
@@ -1027,20 +971,16 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
final Rectangle4i rect = new Rectangle4i(x, y, w, h);
// Because some of the handlers *cough avaritia* are oversized
if (this.recipeCatalyst.isShowWidget() && this.recipeCatalyst.bounds().intersects(rect)) {
if (this.recipeCatalyst.isShowWidget() && this.recipeCatalyst.boundsOutside().intersects(rect)) {
return true;
}
if (getRecipesPerPage() == 1 && !this.container.getWidgets().isEmpty()) {
return this.container.getWidgets().get(0).bounds().intersects(rect);
}
return this.container.boundsOutside().intersects(rect);
}
protected static RecipeId getCurrentRecipeId(GuiScreen gui) {
if (gui instanceof GuiRecipe<?>gRecipe && gRecipe.handler.numRecipes() > 0) {
if (gui instanceof GuiRecipe<?>gRecipe && gRecipe.handlerPages.getNumRecipes() > 0) {
final List<Integer> indices = gRecipe.getRecipeIndices();
final int curRecipe = indices.isEmpty() ? 0 : indices.get(0);
final Recipe recipe = Recipe.of(gRecipe.handler.original, curRecipe);
@@ -61,6 +61,10 @@ public abstract class GuiRecipeButton extends GuiNEIButton {
public abstract void drawItemOverlay();
public void update() {
}
public boolean mouseScrolled(int scroll) {
return false;
}
@@ -3,13 +3,10 @@ package codechicken.nei.recipe;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIServerUtils;
import codechicken.nei.PositionedStack;
@@ -18,32 +15,74 @@ import codechicken.nei.api.ShortcutInputHandler;
import codechicken.nei.drawable.DrawableBuilder;
import codechicken.nei.drawable.DrawableResource;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.scroll.ScrollBar;
import codechicken.nei.scroll.ScrollContainer;
public class GuiRecipeCatalyst extends Widget {
public class GuiRecipeCatalyst extends ScrollContainer {
protected static class ItemStackWidget extends Widget {
private final PositionedStack pStack;
public ItemStackWidget(PositionedStack pStack) {
this.pStack = pStack;
this.x = pStack.relx;
this.y = pStack.rely;
this.w = SLOT_SIZE;
this.h = SLOT_SIZE;
}
@Override
public void draw(int mx, int my) {
GuiContainerManager.drawItem(this.x, this.y, this.pStack.item);
if (contains(mx, my)) {
NEIClientUtils.gl2DRenderContext(() -> GuiDraw.drawRect(this.x, this.y, this.w, this.h, 0x80FFFFFF));
}
}
@Override
public boolean handleClick(int mx, int my, int button) {
return ShortcutInputHandler.handleMouseClick(this.pStack.item);
}
}
private static final int SLOT_SIZE = 16;
private static final int BORDER_PADDING = 6;
private static final int TRANSPARENCY_BORDER = 4;
private static final DrawableResource BG_TEXTURE = new DrawableBuilder(
"nei:textures/catalyst_tab.png",
0,
0,
28,
28).setTextureSize(28, 28).build();
28 + TRANSPARENCY_BORDER * 2,
28 + TRANSPARENCY_BORDER * 2).setTextureSize(28 + TRANSPARENCY_BORDER * 2, 28 + TRANSPARENCY_BORDER * 2)
.build();
private static final DrawableResource FG_TEXTURE = new DrawableBuilder("nei:textures/slot.png", 0, 0, 18, 18)
.setTextureSize(18, 18).build();
private final List<PositionedStack> items = new ArrayList<>();
private int availableHeight = 0;
private static final ScrollBar VERTICAL_SCROLLBAR = ScrollBar.defaultVerticalBar()
.setOverflowType(ScrollBar.OverflowType.AUTO).setTrackPadding(0, BORDER_PADDING, -13, BORDER_PADDING)
.setScrollPlace(ScrollBar.ScrollPlace.START);
private PositionedStack[] items = new PositionedStack[0];
private boolean showWidget = false;
private int availableHeight = 0;
public GuiRecipeCatalyst() {
setPaddingBlock(BORDER_PADDING + 1, BORDER_PADDING + 1);
}
public void setCatalysts(List<PositionedStack> items) {
this.items.clear();
this.items.addAll(items);
this.items = items.toArray(new PositionedStack[0]);
createWidgets();
}
public void setAvailableHeight(int height) {
this.availableHeight = height;
if (this.availableHeight != height) {
this.availableHeight = height;
createWidgets();
}
}
public int getAvailableHeight() {
@@ -55,106 +94,95 @@ public class GuiRecipeCatalyst extends Widget {
}
public int getColumnCount() {
final int maxItemsPerColumn = Math.max(0, this.availableHeight - 2 - BORDER_PADDING * 2) / SLOT_SIZE;
return maxItemsPerColumn > 0 ? NEIServerUtils.divideCeil(this.items.size(), maxItemsPerColumn) : 0;
if (NEIClientConfig.getJEIStyleRecipeCatalysts() == 1) {
final int maxItemsPerColumn = Math.max(0, this.availableHeight - 2 - BORDER_PADDING * 2) / SLOT_SIZE;
return maxItemsPerColumn > 0 ? NEIServerUtils.divideCeil(this.items.length, maxItemsPerColumn) : 0;
}
return 1;
}
public int getRowCount() {
final int columnCount = getColumnCount();
return columnCount > 0 ? NEIServerUtils.divideCeil(this.items.size(), columnCount) : 0;
return columnCount > 0 ? NEIServerUtils.divideCeil(this.items.length, columnCount) : 0;
}
@Override
public void update() {
protected void createWidgets() {
final int columns = getColumnCount();
final int rows = getRowCount();
setVerticalScroll(null);
setPaddingInline(BORDER_PADDING + 1, BORDER_PADDING - 3);
this.h = rows * SLOT_SIZE + this.paddingBlockStart + this.paddingBlockEnd;
this.w = columns * SLOT_SIZE + this.paddingInlineStart + this.paddingInlineEnd;
if (NEIClientConfig.getJEIStyleRecipeCatalysts() == 2
&& rows * SLOT_SIZE + this.paddingBlockStart + this.paddingBlockEnd > this.availableHeight) {
this.h = Math.min(this.h, this.availableHeight);
this.w += VERTICAL_SCROLLBAR.getTrackWidth();
setVerticalScroll(VERTICAL_SCROLLBAR);
setPaddingInline(BORDER_PADDING + 1 + VERTICAL_SCROLLBAR.getTrackWidth(), this.paddingInlineEnd);
}
this.showWidget = rows * columns > 0;
this.w = columns * SLOT_SIZE + 2 + BORDER_PADDING * 2;
this.h = rows * SLOT_SIZE + 2 + BORDER_PADDING * 2;
if (rows == 0 || columns == 0) {
return;
}
final int visibleWidth = getVisibleWidth();
final List<Widget> widgets = new ArrayList<>();
int index = 0;
for (PositionedStack pStack : this.items) {
if (pStack.items.length > 1) {
final int stackIndex = (pStack.items.length + pStack.getPermutationIndex(pStack.item) + 1)
% pStack.items.length;
pStack.setPermutationToRender(stackIndex);
}
pStack.relx = this.w - BORDER_PADDING - 1 - SLOT_SIZE - (index / rows) * SLOT_SIZE;
pStack.rely = BORDER_PADDING + 1 + (index % rows) * SLOT_SIZE;
pStack.relx = visibleWidth - SLOT_SIZE - (index / rows) * SLOT_SIZE;
pStack.rely = (index % rows) * SLOT_SIZE;
index++;
widgets.add(new ItemStackWidget(pStack));
}
setWidgets(widgets);
}
@Override
public void draw(int mx, int my) {
if (!this.showWidget) return;
GL11.glTranslatef(this.x, this.y, 0);
GL11.glColor4f(1, 1, 1, 1);
BG_TEXTURE.draw(0, 0, this.w, this.h, BORDER_PADDING, BORDER_PADDING, BORDER_PADDING, BORDER_PADDING);
BG_TEXTURE.draw(
this.x - TRANSPARENCY_BORDER,
this.y - TRANSPARENCY_BORDER,
this.w + TRANSPARENCY_BORDER * 2,
this.h + TRANSPARENCY_BORDER * 2,
BORDER_PADDING + TRANSPARENCY_BORDER,
BORDER_PADDING + TRANSPARENCY_BORDER,
BORDER_PADDING + TRANSPARENCY_BORDER,
BORDER_PADDING + TRANSPARENCY_BORDER);
FG_TEXTURE.draw(
BORDER_PADDING,
BORDER_PADDING,
this.w - BORDER_PADDING * 2,
this.h - BORDER_PADDING * 2,
this.x + this.paddingInlineStart - 1,
this.y + this.paddingBlockStart - 1,
this.w - this.paddingInlineStart - this.paddingInlineEnd + 2,
this.h - this.paddingBlockStart - this.paddingBlockEnd + 2,
1,
1,
1,
1);
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
RenderHelper.enableGUIStandardItemLighting();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
for (PositionedStack pStack : this.items) {
GuiContainerManager.drawItem(pStack.relx, pStack.rely, pStack.item);
if (pStack.contains(mx - this.x, my - this.y)) {
NEIClientUtils.gl2DRenderContext(
() -> GuiDraw.drawRect(pStack.relx, pStack.rely, SLOT_SIZE, SLOT_SIZE, -2130706433));
}
}
GL11.glPopAttrib();
GL11.glTranslatef(-this.x, -this.y, 0);
super.draw(mx, my);
}
public PositionedStack getPositionedStackMouseOver(int mx, int my) {
final Widget widget = getWidgetUnderMouse(mx, my);
for (PositionedStack pStack : this.items) {
if (pStack.contains(mx - this.x, my - this.y)) {
return pStack;
}
if (widget instanceof ItemStackWidget stackWidget) {
return stackWidget.pStack;
}
return null;
}
@Override
public ItemStack getStackMouseOver(int mx, int my) {
final PositionedStack pStack = getPositionedStackMouseOver(mx, my);
if (pStack != null) {
return pStack.item;
}
return null;
}
@Override
public boolean handleClick(int mx, int my, int button) {
return ShortcutInputHandler.handleMouseClick(getStackMouseOver(mx, my));
}
@Deprecated
public static final int ingredientSize = 16;
@Deprecated
@@ -33,6 +33,7 @@ import codechicken.nei.Widget;
import codechicken.nei.drawable.DrawableResource;
import codechicken.nei.event.NEIRegisterHandlerInfosEvent;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.debug.DebugHandlerWidget;
import cpw.mods.fml.common.Loader;
public abstract class GuiRecipeTab extends Widget {
@@ -255,12 +256,11 @@ public abstract class GuiRecipeTab extends Widget {
if (yShift != null && !yShift.equals("")) info.setYShift(Integer.parseInt(yShift));
try {
final int imageHeight = intOrDefault(record.get("handlerHeight"), HandlerInfo.DEFAULT_HEIGHT);
final int imageWidth = intOrDefault(record.get("handlerWidth"), HandlerInfo.DEFAULT_WIDTH);
final int maxRecipesPerPage = intOrDefault(
record.get("maxRecipesPerPage"),
HandlerInfo.DEFAULT_MAX_PER_PAGE);
info.setHandlerDimensions(imageHeight, imageWidth, maxRecipesPerPage);
final int handlerHeight = intOrDefault(record.get("handlerHeight"), HandlerInfo.DEFAULT_HEIGHT);
final int handlerWidth = intOrDefault(record.get("handlerWidth"), HandlerInfo.DEFAULT_WIDTH);
final boolean multipleWidgetsAllowed = intOrDefault(record.get("maxRecipesPerPage"), 1) > 1;
info.setHandlerDimensions(handlerWidth, handlerHeight);
info.setMultipleWidgetsAllowed(multipleWidgetsAllowed);
} catch (NumberFormatException ignored) {
NEIClientConfig.logger.info("Error setting handler dimensions for " + handler);
}
@@ -294,14 +294,12 @@ public abstract class GuiRecipeTab extends Widget {
}
NEIClientConfig.logger.info("Sending {}", NEIRegisterHandlerInfosEvent.class.getSimpleName());
MinecraftForge.EVENT_BUS.post(new NEIRegisterHandlerInfosEvent());
DebugHandlerWidget.instance.loadHandlerInfoPatch();
}
private static HandlerInfo getDefaultHandlerInfo() {
final HandlerInfo info = new HandlerInfo("Unknown", "Unknown", "Unknown", false, "");
info.setHandlerDimensions(
HandlerInfo.DEFAULT_HEIGHT,
HandlerInfo.DEFAULT_WIDTH,
HandlerInfo.DEFAULT_MAX_PER_PAGE);
info.setHandlerDimensions(HandlerInfo.DEFAULT_WIDTH, HandlerInfo.DEFAULT_HEIGHT);
return info;
}
@@ -12,7 +12,7 @@ import codechicken.nei.ItemPanels;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.stackinfo.GTFluidStackStringifyHandler;
import codechicken.nei.recipe.TemplateRecipeHandler.RecipeTransferRect;
public class GuiUsageRecipe extends GuiRecipe<IUsageHandler> {
@@ -22,9 +22,9 @@ public class GuiUsageRecipe extends GuiRecipe<IUsageHandler> {
public static boolean openRecipeGui(String inputId, Object... ingredients) {
if ("item".equals(inputId)) {
for (int i = 0; i < ingredients.length; i++) {
ingredients[i] = normalizeItemStack((ItemStack) ingredients[i]);
for (int i = 0; i < ingredients.length; i++) {
if (ingredients[i] instanceof ItemStack stack) {
ingredients[i] = StackInfo.normalizeRecipeQueryStack(stack.copy());
}
}
@@ -39,12 +39,10 @@ public class GuiUsageRecipe extends GuiRecipe<IUsageHandler> {
&& ingredients[0] instanceof ItemStack stack) {
ItemPanels.itemPanel.historyPanel.addItem(stack);
}
mc.displayGuiScreen(gui);
gui.openTargetRecipe(recipeId);
return true;
}
return false;
}
@@ -56,21 +54,36 @@ public class GuiUsageRecipe extends GuiRecipe<IUsageHandler> {
public static ArrayList<IUsageHandler> getUsageHandlers(String inputId, Object... ingredients) {
final RecipeHandlerQuery<IUsageHandler> recipeQuery = new RecipeHandlerQuery<>(
h -> getUsageOrCatalystHandler(h, inputId, ingredients),
"all".equals(inputId) ? GuiUsageRecipe::buildAllRecipesHandler
: h -> getUsageOrCatalystHandler(h, inputId, ingredients),
GuiUsageRecipe.usagehandlers,
GuiUsageRecipe.serialUsageHandlers,
"Error while looking up usage recipe",
"inputId: " + inputId,
"ingredients: " + Arrays.toString(ingredients));
return recipeQuery.runWithProfiling(NEIClientUtils.translate("recipe.concurrent.usage"));
ArrayList<IUsageHandler> handlers = recipeQuery
.runWithProfiling(NEIClientUtils.translate("recipe.concurrent.usage"));
return handlers;
}
private static ItemStack normalizeItemStack(ItemStack stack) {
GTFluidStackStringifyHandler.replaceAE2FCFluidDrop = true;
stack = StackInfo.loadFromNBT(StackInfo.itemStackToNBT(stack));
GTFluidStackStringifyHandler.replaceAE2FCFluidDrop = false;
return stack;
private static IUsageHandler buildAllRecipesHandler(IUsageHandler handler) {
if (handler instanceof TemplateRecipeHandler templateHandler) {
TemplateRecipeHandler allHandler = templateHandler.newInstance();
if (allHandler.transferRects.isEmpty()) {
allHandler.loadCraftingRecipes("all");
return allHandler;
}
for (RecipeTransferRect rect : allHandler.transferRects) {
if (allHandler.specifyTransferRect() == null
|| allHandler.specifyTransferRect().equals(rect.outputId)) {
allHandler.loadCraftingRecipes(rect.outputId, rect.results);
return allHandler;
}
}
}
return handler.getUsageHandler("all");
}
public static void registerUsageHandler(IUsageHandler handler) {
@@ -99,7 +112,7 @@ public class GuiUsageRecipe extends GuiRecipe<IUsageHandler> {
private static IUsageHandler getUsageOrCatalystHandler(IUsageHandler handler, String inputId,
Object... ingredients) {
boolean skipCatalyst = NEIClientUtils.controlKey();
if (NEIClientConfig.areJEIStyleRecipeCatalystsVisible() && !skipCatalyst) {
if (NEIClientConfig.getJEIStyleRecipeCatalysts() != 0 && !skipCatalyst) {
return handler.getUsageAndCatalystHandler(inputId, ingredients);
} else {
return handler.getUsageHandler(inputId, ingredients);
@@ -12,6 +12,8 @@ public class HandlerInfo {
public static int DEFAULT_HEIGHT = 65;
public static int DEFAULT_WIDTH = 166;
@Deprecated
public static int DEFAULT_MAX_PER_PAGE = 1;
private String handlerName;
@@ -24,7 +26,8 @@ public class HandlerInfo {
private int yShift = 0;
private int height = DEFAULT_HEIGHT;
private int width = DEFAULT_WIDTH;
private int maxRecipesPerPage = DEFAULT_MAX_PER_PAGE;
private boolean multipleWidgetsAllowed = false;
private boolean showFavoritesButton = true;
private boolean showOverlayButton = true;
private boolean useCustomScroll = false;
@@ -40,10 +43,15 @@ public class HandlerInfo {
this.excludedModId = excludedModId;
}
@Deprecated
public void setHandlerDimensions(int height, int width, int maxRecipesPerPage) {
setHandlerDimensions(width, height);
setMultipleWidgetsAllowed(maxRecipesPerPage > 1);
}
public void setHandlerDimensions(int width, int height) {
this.height = height;
this.width = width;
this.maxRecipesPerPage = maxRecipesPerPage;
}
public boolean setItem(String itemId, String nbtString) {
@@ -89,8 +97,17 @@ public class HandlerInfo {
return this.width;
}
@Deprecated
public int getMaxRecipesPerPage() {
return Math.max(this.maxRecipesPerPage, 1);
return this.multipleWidgetsAllowed ? Integer.MAX_VALUE : 1;
}
public void setMultipleWidgetsAllowed(boolean multipleWidgetsAllowed) {
this.multipleWidgetsAllowed = multipleWidgetsAllowed;
}
public boolean isMultipleWidgetsAllowed() {
return this.multipleWidgetsAllowed;
}
public int getYShift() {
@@ -133,10 +150,6 @@ public class HandlerInfo {
this.useCustomScroll = useCustomScroll;
}
public boolean expandVertically() {
return this.useCustomScroll && this.maxRecipesPerPage <= 1;
}
public static class Builder {
private final HandlerInfo info;
@@ -150,52 +163,72 @@ public class HandlerInfo {
this(handlerClazz.getName(), modName, modId);
}
public Builder setDisplayStack(String itemId, String nbtString) {
return setDisplayStack(NEIServerUtils.getModdedItem(itemId, nbtString));
}
public Builder setDisplayStack(ItemStack stack) {
info.image = null;
info.itemStack = stack;
this.info.image = null;
this.info.itemStack = stack;
return this;
}
public Builder setDisplayImage(DrawableResource drawable) {
info.itemStack = null;
info.image = drawable;
this.info.itemStack = null;
this.info.image = drawable;
return this;
}
public Builder setDisplayImage(ResourceLocation location, int imageX, int imageY, int imageWidth,
int imageHeight) {
info.itemStack = null;
info.setImage(location.toString(), imageX, imageY, imageWidth, imageHeight);
this.info.itemStack = null;
this.info.setImage(location.toString(), imageX, imageY, imageWidth, imageHeight);
return this;
}
public Builder setUseCustomScroll(boolean useCustomScroll) {
info.setUseCustomScroll(useCustomScroll);
this.info.setUseCustomScroll(useCustomScroll);
return this;
}
public Builder setShiftY(int shiftY) {
info.setYShift(shiftY);
this.info.setYShift(shiftY);
return this;
}
public Builder setWidth(int width) {
info.setHandlerDimensions(info.height, width, info.maxRecipesPerPage);
this.info.width = width;
return this;
}
public Builder setHeight(int height) {
info.setHandlerDimensions(height, info.width, info.maxRecipesPerPage);
this.info.height = height;
return this;
}
public Builder setShowOverlayButton(boolean showOverlayButton) {
this.info.showOverlayButton = showOverlayButton;
return this;
}
public Builder setShowFavoritesButton(boolean showFavoritesButton) {
this.info.showFavoritesButton = showFavoritesButton;
return this;
}
@Deprecated
public Builder setMaxRecipesPerPage(int maxRecipesPerPage) {
info.setHandlerDimensions(info.height, info.width, maxRecipesPerPage);
this.info.multipleWidgetsAllowed = maxRecipesPerPage > 1;
return this;
}
public Builder setMultipleWidgetsAllowed(boolean multipleWidgetsAllowed) {
this.info.multipleWidgetsAllowed = multipleWidgetsAllowed;
return this;
}
public HandlerInfo build() {
return info;
return this.info;
}
}
}
@@ -44,7 +44,7 @@ public interface IRecipeHandler {
return getRecipeName();
}
default int getRecipeHeight() {
default int getRecipeHeight(int recipe) {
return 0;
}
@@ -10,6 +10,9 @@ import net.minecraft.client.gui.FontRenderer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.StatCollector;
import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ClientHandler;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
@@ -34,13 +37,12 @@ public class InformationHandler extends TemplateRecipeHandler {
@Override
public void drawExtras(int recipe) {
CachedInfoPage page = (CachedInfoPage) this.arecipes.get(recipe);
drawWrappedText(StatCollector.translateToLocal(page.getPage().info).replace("\\n", "\n"), 4, 24);
final CachedInfoPage page = (CachedInfoPage) this.arecipes.get(recipe);
drawWrappedText(page.getLines(), 4, 24);
}
private void drawWrappedText(String text, int x, int y) {
FontRenderer font = Minecraft.getMinecraft().fontRenderer;
List<String> lines = font.listFormattedStringToWidth(text, 156);
private void drawWrappedText(List<String> lines, int x, int y) {
final FontRenderer font = Minecraft.getMinecraft().fontRenderer;
for (String line : lines) {
font.drawString(line, x, y, 0);
y += 10;
@@ -82,14 +84,30 @@ public class InformationHandler extends TemplateRecipeHandler {
return "nei:textures/gui/recipebg.png";
}
@Override
public void drawBackground(int recipe) {
GL11.glColor4f(1, 1, 1, 1);
GuiDraw.changeTexture(getGuiTexture());
GuiDraw.drawTexturedModalRect(0, 0, 7, 13, 166, 65);
}
@Override
public int getRecipeHeight(int recipe) {
final CachedInfoPage page = (CachedInfoPage) this.arecipes.get(recipe);
return 24 + page.getLines().size() * 10;
}
private class CachedInfoPage extends CachedRecipe {
private final InformationPage page;
private final PositionedStack stack;
private final List<String> lines;
public CachedInfoPage(InformationPage page) {
this.page = page;
stack = new PositionedStack(page.items, 75, 2);
final FontRenderer font = Minecraft.getMinecraft().fontRenderer;
final String info = StatCollector.translateToLocal(page.info).replace("\\n", "\n");
this.lines = font.listFormattedStringToWidth(info, 156);
this.stack = new PositionedStack(page.items, 75, 2);
}
@Override
@@ -102,8 +120,8 @@ public class InformationHandler extends TemplateRecipeHandler {
return Collections.singletonList(this.stack);
}
public InformationPage getPage() {
return page;
public List<String> getLines() {
return lines;
}
}
@@ -2,6 +2,7 @@ package codechicken.nei.recipe;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -12,6 +13,7 @@ import java.util.stream.Stream;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
@@ -20,22 +22,28 @@ import org.lwjgl.opengl.GL12;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.FavoriteRecipes;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIServerUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.Widget;
import codechicken.nei.api.IGuiContainerOverlay;
import codechicken.nei.api.ShortcutInputHandler;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.GuiRecipeButton.UpdateRecipeButtonsEvent;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.debug.DebugHandlerWidget;
import codechicken.nei.util.NEIMouseUtils;
public class NEIRecipeWidget extends Widget {
protected final WeakHashMap<PositionedStack, List<ItemStack>> permutations = new WeakHashMap<>();
protected boolean needUpdate = true;
protected AcceptsFollowingTooltipLineHandler acceptsFollowingTooltipLineHandler;
protected final Map<PositionedStack, Integer> favoriteIndexes = new WeakHashMap<>();
protected final Map<PositionedStack, List<ItemStack>> permutations = new WeakHashMap<>();
protected int favoriteRevision = -1;
protected boolean update = true;
protected int cycleticks = 0;
protected int lastcycle = 0;
protected int lastcycle = -1;
protected final RecipeHandlerRef handlerRef;
protected final HandlerInfo handlerInfo;
@@ -55,25 +63,21 @@ public class NEIRecipeWidget extends Widget {
}
public void update() {
this.w = Math.max(166, this.handlerInfo.getWidth());
if (this.showAsWidget || !this.handlerInfo.expandVertically()) {
this.h = this.handlerRef.handler.getRecipeHeight() > 0 ? this.handlerRef.handler.getRecipeHeight()
: this.handlerInfo.getHeight();
if (this.showAsWidget || !this.handlerInfo.getUseCustomScroll()) {
final int recipeHeight = this.handlerRef.handler.getRecipeHeight(this.handlerRef.recipeIndex);
this.w = Math.max(166, this.handlerInfo.getWidth());
this.h = recipeHeight > 0 ? recipeHeight : this.handlerInfo.getHeight();
this.h += this.handlerInfo.getYShift();
}
if (!this.needUpdate && !NEIClientUtils.shiftKey() && (this.cycleticks++) / 20 != this.lastcycle) {
this.lastcycle = this.cycleticks / 20;
this.needUpdate = true;
}
this.update = true;
}
public List<GuiRecipeButton> getRecipeButtons() {
if (this.recipeButtons == null) {
if (this.handlerRef.handler.getResultStack(this.handlerRef.recipeIndex) != null
|| !this.handlerRef.handler.getOtherStacks(this.handlerRef.recipeIndex).isEmpty()) {
if (!getOutputs().isEmpty()) {
this.recipeButtons = initButtons();
} else {
this.recipeButtons = Collections.emptyList();
@@ -123,18 +127,18 @@ public class NEIRecipeWidget extends Widget {
final UpdateRecipeButtonsEvent.Post postEvent = new UpdateRecipeButtonsEvent.Post(
guiRecipe,
this,
getDefatulButtons());
getDefaultButtons());
MinecraftForge.EVENT_BUS.post(postEvent);
return postEvent.buttonList;
}
} else {
return getDefatulButtons();
return getDefaultButtons();
}
}
protected List<GuiRecipeButton> getDefatulButtons() {
protected List<GuiRecipeButton> getDefaultButtons() {
GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
final List<GuiRecipeButton> buttons = new ArrayList<>();
final boolean showFavorites = NEIClientConfig.favoritesEnabled() && handlerInfo.getShowFavoritesButton();
@@ -162,9 +166,17 @@ public class NEIRecipeWidget extends Widget {
public void draw(int mouseX, int mouseY) {
final int yShift = this.handlerInfo.getYShift();
if (this.needUpdate) {
this.needUpdate = false;
updatePermutations();
if (this.update) {
this.update = false;
if (!NEIClientUtils.shiftKey() && ((this.cycleticks++) / 20) != this.lastcycle || this.lastcycle == -1) {
this.lastcycle = this.cycleticks / 20;
updatePermutations();
}
for (GuiRecipeButton button : getRecipeButtons()) {
button.update();
}
}
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
@@ -178,28 +190,37 @@ public class NEIRecipeWidget extends Widget {
GuiContainerManager.enableMatrixStackLogging();
for (PositionedStack pStack : this.handlerRef.handler.getIngredientStacks(this.handlerRef.recipeIndex)) {
for (PositionedStack pStack : getInputs()) {
if (!this.permutations.containsKey(pStack)) {
updatePermutationsFor(pStack);
}
GuiContainerManager.drawItem(pStack.relx, pStack.rely, pStack.item);
if (pStack.contains(mouseX - this.x, mouseY - this.y - yShift)) {
NEIClientUtils.gl2DRenderContext(() -> GuiDraw.drawRect(pStack.relx, pStack.rely, 16, 16, -2130706433));
NEIClientUtils.gl2DRenderContext(() -> GuiDraw.drawRect(pStack.relx, pStack.rely, 16, 16, 0x80FFFFFF));
}
}
for (PositionedStack pStack : this.handlerRef.handler.getOtherStacks(this.handlerRef.recipeIndex)) {
for (PositionedStack pStack : getCatalysts()) {
if (!this.permutations.containsKey(pStack)) {
updatePermutationsFor(pStack);
}
GuiContainerManager.drawItem(pStack.relx, pStack.rely, pStack.item);
if (pStack.contains(mouseX - this.x, mouseY - this.y - yShift)) {
NEIClientUtils.gl2DRenderContext(() -> GuiDraw.drawRect(pStack.relx, pStack.rely, 16, 16, -2130706433));
NEIClientUtils.gl2DRenderContext(() -> GuiDraw.drawRect(pStack.relx, pStack.rely, 16, 16, 0x80FFFFFF));
}
}
final PositionedStack pStackResult = this.handlerRef.handler.getResultStack(this.handlerRef.recipeIndex);
if (pStackResult != null) {
GuiContainerManager.drawItem(pStackResult.relx, pStackResult.rely, pStackResult.item);
if (pStackResult.contains(mouseX - this.x, mouseY - this.y - yShift)) {
NEIClientUtils.gl2DRenderContext(
() -> GuiDraw.drawRect(pStackResult.relx, pStackResult.rely, 16, 16, -2130706433));
for (PositionedStack pStack : getOutputs()) {
GuiContainerManager.drawItem(pStack.relx, pStack.rely, pStack.item);
if (pStack.contains(mouseX - this.x, mouseY - this.y - yShift)) {
NEIClientUtils.gl2DRenderContext(() -> GuiDraw.drawRect(pStack.relx, pStack.rely, 16, 16, 0x80FFFFFF));
}
}
@@ -207,13 +228,13 @@ public class NEIRecipeWidget extends Widget {
this.handlerRef.handler.drawForeground(this.handlerRef.recipeIndex);
final GuiRecipeButton overlayButton = getRecipeButtons().stream()
.filter(
b -> this.showAsWidget ? b instanceof GuiOverlayButton
: b.contains(mouseX - this.x, mouseY - this.y - yShift))
.findAny().orElse(null);
final GuiRecipeButton overlayButton = forEachButtons(
button -> (this.showAsWidget ? button instanceof GuiOverlayButton : button.contains(mouseX, mouseY))
? button
: null,
(GuiRecipeButton) null);
if (overlayButton != null && overlayButton.enabled) {
if (overlayButton != null) {
NEIClientUtils.gl2DRenderContext(() -> overlayButton.drawItemOverlay());
}
@@ -231,11 +252,43 @@ public class NEIRecipeWidget extends Widget {
}
}
LayoutManager.recipeHandlerWidget.drawGuiPlaceholder(this);
DebugHandlerWidget.instance.drawGuiPlaceholder(this);
}
@Override
public boolean handleKeyPress(int keyID, char keyChar) {
if (NEIClientConfig.favoritesEnabled() && NEIClientUtils.shiftKey()
&& NEIClientConfig.isKeyHashDown("gui.favorite_item")) {
final Point mouse = GuiDraw.getMousePosition();
final int yShift = this.handlerInfo.getYShift();
PositionedStack pStackOver = null;
for (PositionedStack pStack : getInputs()) {
if (pStack.contains(mouse.x - this.x, mouse.y - this.y - yShift)) {
pStackOver = pStack;
break;
}
}
if (pStackOver != null) {
if (FavoriteRecipes.containsManual(pStackOver.item)) {
FavoriteRecipes.setFavorite(pStackOver.item, null);
} else {
FavoriteRecipes.setFavorite(
pStackOver.item,
RecipeId.of(
pStackOver.item,
FavoriteRecipes.FAVORITE_ITEM,
Arrays.asList(new ItemStack(Blocks.fire, 1), pStackOver.item)));
}
return true;
}
}
return false;
}
@@ -311,14 +364,70 @@ public class NEIRecipeWidget extends Widget {
return tooltip;
}
return this.handlerRef.handler.handleItemTooltip(guiRecipe, itemstack, tooltip, this.handlerRef.recipeIndex);
tooltip = this.handlerRef.handler.handleItemTooltip(guiRecipe, itemstack, tooltip, this.handlerRef.recipeIndex);
if (NEIClientConfig.showCycledIngredientsTooltip() && itemstack != null) {
final int yShift = this.handlerInfo.getYShift();
PositionedStack hovered = null;
for (PositionedStack pStack : getInputs()) {
if (pStack.contains(mousex - this.x, mousey - this.y - yShift)) {
hovered = pStack;
break;
}
}
if (hovered == null) {
for (PositionedStack pStack : getCatalysts()) {
if (pStack.contains(mousex - this.x, mousey - this.y - yShift)) {
hovered = pStack;
break;
}
}
}
if (hovered == null || this.permutations.getOrDefault(hovered, Collections.emptyList()).size() <= 1) {
this.acceptsFollowingTooltipLineHandler = null;
} else if (this.acceptsFollowingTooltipLineHandler == null
|| this.acceptsFollowingTooltipLineHandler.tooltipGUID != hovered) {
this.acceptsFollowingTooltipLineHandler = AcceptsFollowingTooltipLineHandler
.of(hovered, this.permutations.get(hovered), hovered.item);
}
} else if (this.acceptsFollowingTooltipLineHandler != null) {
this.acceptsFollowingTooltipLineHandler = null;
}
if (this.acceptsFollowingTooltipLineHandler != null) {
tooltip.add(GuiDraw.TOOLTIP_HANDLER + GuiDraw.getTipLineId(this.acceptsFollowingTooltipLineHandler));
}
return tooltip;
}
@Override
public Map<String, String> handleHotkeys(int mouseX, int mouseY, Map<String, String> hotkeys) {
return forEachButtons(
final int yShift = this.handlerInfo.getYShift();
final Map<String, String> buttonHotkeys = forEachButtons(
button -> button.contains(mouseX, mouseY) ? button.handleHotkeys(mouseX, mouseY, hotkeys) : null,
hotkeys);
if (this.acceptsFollowingTooltipLineHandler != null) {
buttonHotkeys.put(
NEIClientUtils.getKeyName(
NEIClientUtils.SHIFT_HASH,
NEIMouseUtils.MOUSE_BTN_NONE + NEIMouseUtils.MOUSE_SCROLL),
NEIClientUtils.translate("recipe.accepts.scroll"));
}
if (getInputs().stream().anyMatch(
pStack -> this.permutations.getOrDefault(pStack, Collections.emptyList()).size() > 1
&& pStack.contains(mouseX - this.x, mouseY - this.y - yShift))) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.favorite_item", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("recipe.favorite.toggle"));
}
return buttonHotkeys;
}
@Override
@@ -342,23 +451,34 @@ public class NEIRecipeWidget extends Widget {
if (!NEIClientUtils.shiftKey()) return false;
final PositionedStack overStack = getPositionedStackMouseOver(mx, my);
if (overStack != null && overStack.items.length > 1) {
final List<ItemStack> items = overStack.getFilteredPermutations();
final int stackIndex = overStack.getPermutationIndex(overStack.item);
if (overStack != null && this.permutations.getOrDefault(overStack, Collections.emptyList()).size() > 1) {
final List<ItemStack> items = this.permutations.get(overStack);
final int stackIndex = indexOf(items, overStack.item);
final ItemStack stack = items.get((items.size() - scroll + stackIndex) % items.size());
Stream.concat(
this.handlerRef.handler.getIngredientStacks(this.handlerRef.recipeIndex).stream(),
this.handlerRef.handler.getOtherStacks(this.handlerRef.recipeIndex).stream())
.filter(pStack -> pStack.containsWithNBT(stack))
Stream.concat(getInputs().stream(), getCatalysts().stream()).filter(pStack -> pStack.containsWithNBT(stack))
.forEach(pStack -> pStack.setPermutationToRender(stack));
if (this.acceptsFollowingTooltipLineHandler != null) {
this.acceptsFollowingTooltipLineHandler
.setActiveStack(((PositionedStack) this.acceptsFollowingTooltipLineHandler.tooltipGUID).item);
}
return true;
}
return false;
}
protected int indexOf(List<ItemStack> list, ItemStack stack) {
for (int i = 0; i < list.size(); i++) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(list.get(i), stack)) {
return i;
}
}
return -1;
}
protected <R> R forEachButtons(Function<GuiRecipeButton, R> callback, R defaultValue) {
for (GuiRecipeButton button : getRecipeButtonsIfInit()) {
@@ -381,12 +501,7 @@ public class NEIRecipeWidget extends Widget {
public boolean isFocusedRecipe(int mx, int my) {
final int yShift = this.handlerInfo.getYShift();
final PositionedStack pStackResult = this.handlerRef.handler.getResultStack(this.handlerRef.recipeIndex);
if (pStackResult != null && pStackResult.contains(mx - this.x, my - this.y - yShift)) {
return true;
}
for (PositionedStack pStackOver : this.handlerRef.handler.getOtherStacks(this.handlerRef.recipeIndex)) {
for (PositionedStack pStackOver : getOutputs()) {
if (pStackOver.contains(mx - this.x, my - this.y - yShift)) {
return true;
}
@@ -398,21 +513,22 @@ public class NEIRecipeWidget extends Widget {
public PositionedStack getPositionedStackMouseOver(int mx, int my) {
final int yShift = this.handlerInfo.getYShift();
for (PositionedStack pStack : this.handlerRef.handler.getIngredientStacks(this.handlerRef.recipeIndex)) {
for (PositionedStack pStack : getInputs()) {
if (pStack.contains(mx - this.x, my - this.y - yShift)) {
return pStack;
}
}
for (PositionedStack pStack : this.handlerRef.handler.getOtherStacks(this.handlerRef.recipeIndex)) {
for (PositionedStack pStack : getCatalysts()) {
if (pStack.contains(mx - this.x, my - this.y - yShift)) {
return pStack;
}
}
final PositionedStack pStackResult = this.handlerRef.handler.getResultStack(this.handlerRef.recipeIndex);
if (pStackResult != null && pStackResult.contains(mx - this.x, my - this.y - yShift)) {
return pStackResult;
for (PositionedStack pStack : getOutputs()) {
if (pStack.contains(mx - this.x, my - this.y - yShift)) {
return pStack;
}
}
return null;
@@ -445,30 +561,75 @@ public class NEIRecipeWidget extends Widget {
}
protected void updatePermutations() {
final int rev = FavoriteRecipes.getRevision();
for (PositionedStack pStack : this.handlerRef.handler.getIngredientStacks(this.handlerRef.recipeIndex)) {
if (pStack.items.length > 1) {
final List<ItemStack> permutations = this.permutations
.computeIfAbsent(pStack, stack -> stack.getFilteredPermutations(FavoriteRecipes::contains));
pStack.setPermutationToRender(permutations.get(this.lastcycle % permutations.size()));
}
if (this.favoriteRevision != rev) {
this.favoriteRevision = rev;
this.acceptsFollowingTooltipLineHandler = null;
this.favoriteIndexes.clear();
this.permutations.clear();
}
for (PositionedStack pStack : this.handlerRef.handler.getOtherStacks(this.handlerRef.recipeIndex)) {
if (pStack.items.length > 1) {
final List<ItemStack> permutations = this.permutations
.computeIfAbsent(pStack, stack -> stack.getFilteredPermutations(FavoriteRecipes::contains));
pStack.setPermutationToRender(permutations.get(this.lastcycle % permutations.size()));
}
for (PositionedStack pStack : getInputs()) {
updatePermutationsFor(pStack);
}
final PositionedStack pStackResult = this.handlerRef.handler.getResultStack(this.handlerRef.recipeIndex);
if (pStackResult != null && pStackResult.items.length > 1) {
final List<ItemStack> permutations = this.permutations
.computeIfAbsent(pStackResult, stack -> stack.getFilteredPermutations(FavoriteRecipes::contains));
pStackResult.setPermutationToRender(permutations.get(this.lastcycle % permutations.size()));
for (PositionedStack pStack : getCatalysts()) {
updatePermutationsFor(pStack);
}
if (this.acceptsFollowingTooltipLineHandler != null) {
this.acceptsFollowingTooltipLineHandler
.setActiveStack(((PositionedStack) this.acceptsFollowingTooltipLineHandler.tooltipGUID).item);
}
}
private void updatePermutationsFor(PositionedStack pStack) {
List<ItemStack> perms = this.permutations.get(pStack);
int favoriteIndex = this.favoriteIndexes.getOrDefault(pStack, -1);
boolean needsUpdate = false;
if (perms == null) {
perms = pStack.getFilteredPermutations();
favoriteIndex = -1;
if (perms.size() > 1) {
for (ItemStack item : perms) {
if (!FavoriteRecipes.containsManual(item)) break;
favoriteIndex++;
}
}
this.permutations.put(pStack, perms);
this.favoriteIndexes.put(pStack, favoriteIndex);
needsUpdate = true;
}
if (perms.size() > 1 || needsUpdate) {
final int size = favoriteIndex != -1 ? favoriteIndex + 1 : perms.size();
if (size > 0) {
pStack.setPermutationToRender(perms.get(this.lastcycle % size));
}
}
}
protected List<PositionedStack> getInputs() {
return this.handlerRef.handler.getIngredientStacks(this.handlerRef.recipeIndex);
}
protected List<PositionedStack> getOutputs() {
final PositionedStack pStackResult = this.handlerRef.handler.getResultStack(this.handlerRef.recipeIndex);
return pStackResult != null ? Arrays.asList(pStackResult)
: this.handlerRef.handler.getOtherStacks(this.handlerRef.recipeIndex);
}
protected List<PositionedStack> getCatalysts() {
if (this.handlerRef.handler.getResultStack(this.handlerRef.recipeIndex) == null) {
return Collections.emptyList();
}
return this.handlerRef.handler.getOtherStacks(this.handlerRef.recipeIndex);
}
}
@@ -18,6 +18,7 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIServerUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.api.ItemInfo;
@@ -50,6 +51,24 @@ public class Recipe {
return new RecipeId(extractItem(result), handlerName, extractIngredients(ingredients));
}
public static RecipeId of(IRecipeHandler handler, int recipeIndex) {
final List<PositionedStack> ingredients = handler.getIngredientStacks(recipeIndex);
final String handlerName = GuiRecipeTab.getHandlerInfo(handler).getHandlerName();
PositionedStack pStackResult = handler.getResultStack(recipeIndex);
if (pStackResult == null) {
for (PositionedStack otherStack : handler.getOtherStacks(recipeIndex)) {
if (!FluidContainerRegistry.isContainer(otherStack.items[0])
|| StackInfo.getFluid(otherStack.items[0]) != null) {
pStackResult = otherStack;
break;
}
}
}
return new RecipeId(extractItem(pStackResult), handlerName, extractIngredients(ingredients));
}
public static RecipeId of(JsonObject json) {
String handlerName = null;
List<ItemStack> ingredients = new ArrayList<>();
@@ -235,7 +254,8 @@ public class Recipe {
return false;
}
if (this.result != null && anRecipeId.result != null
if (isShapedRecipe() && this.result != null
&& anRecipeId.result != null
&& !StackInfo.equalItemAndNBT(this.result, anRecipeId.result, true)) {
return false;
}
@@ -311,7 +331,8 @@ public class Recipe {
}
public boolean contains(ItemStack stackA) {
return getPermutations().stream().anyMatch(stackB -> StackInfo.equalItemAndNBT(stackA, stackB, true));
return getPermutations().stream()
.anyMatch(stackB -> NEIClientUtils.areStacksSameTypeWithNBT(stackB, stackA));
}
public List<ItemStack> getPermutations() {
@@ -52,6 +52,11 @@ public class RecipeHandlerRef {
return null;
}
public static void clearCache() {
recipeRefCache.clear();
transferAlghoritmCache.clear();
}
private GuiContainer prepareGui(GuiContainer firstGui) {
if (firstGui instanceof GuiRecipe gui) {
@@ -4,16 +4,11 @@ import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
import net.minecraft.client.gui.inventory.GuiBrewingStand;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.gui.inventory.GuiCrafting;
import net.minecraft.client.gui.inventory.GuiFurnace;
import net.minecraft.client.gui.inventory.GuiInventory;
import com.google.common.base.Objects;
import codechicken.nei.OffsetPositioner;
import codechicken.nei.api.API;
import codechicken.nei.api.IOverlayHandler;
import codechicken.nei.api.IStackPositioner;
@@ -96,33 +91,4 @@ public class RecipeInfo {
return offset == null ? new int[] { 5, 11 } : offset;
}
public static void load() {
API.registerRecipeHandler(new ShapedRecipeHandler());
API.registerUsageHandler(new ShapedRecipeHandler());
API.registerRecipeHandler(new ShapelessRecipeHandler());
API.registerUsageHandler(new ShapelessRecipeHandler());
API.registerRecipeHandler(new FireworkRecipeHandler());
API.registerUsageHandler(new FireworkRecipeHandler());
API.registerRecipeHandler(new FurnaceRecipeHandler());
API.registerUsageHandler(new FurnaceRecipeHandler());
API.registerRecipeHandler(new BrewingRecipeHandler());
API.registerUsageHandler(new BrewingRecipeHandler());
API.registerRecipeHandler(new FuelRecipeHandler());
API.registerUsageHandler(new FuelRecipeHandler());
API.registerRecipeHandler(new InformationHandler());
API.registerUsageHandler(new InformationHandler());
API.registerGuiOverlay(GuiCrafting.class, "crafting");
API.registerGuiOverlay(GuiInventory.class, "crafting2x2", 63, 20);
API.registerGuiOverlay(GuiFurnace.class, "smelting");
API.registerGuiOverlay(GuiFurnace.class, "fuel");
API.registerGuiOverlay(GuiBrewingStand.class, "brewing");
API.registerGuiOverlayHandler(GuiCrafting.class, new DefaultOverlayHandler(), "crafting");
API.registerGuiOverlayHandler(GuiInventory.class, new DefaultOverlayHandler(63, 20), "crafting2x2");
API.registerGuiOverlayHandler(GuiBrewingStand.class, new BrewingOverlayHandler(), "brewing");
API.registerRecipeHandler(new ProfilerRecipeHandler(true));
API.registerUsageHandler(new ProfilerRecipeHandler(false));
}
}
@@ -14,6 +14,7 @@ import codechicken.nei.ItemPanels;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.api.ShortcutInputHandler;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.bookmark.BookmarksGridSlot;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
@@ -81,7 +82,7 @@ public class RecipeItemInputHandler implements IContainerInputHandler, IContaine
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mousex, mousey);
if (slot != null && slot.getRecipeId() != null
&& !slot.isIngredient()
&& slot.getType() != BookmarkItemType.INGREDIENT
&& NEIClientConfig.getRecipeTooltipsMode() != 0) {
final int tooltipMode = NEIClientConfig.getRecipeTooltipsMode();
final BookmarkViewMode viewMode = slot.getGroup().viewMode;
@@ -0,0 +1,158 @@
package codechicken.nei.recipe;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.Widget;
import codechicken.nei.scroll.ScrollContainer;
public class RecipePageManager {
private SearchRecipeHandler<?> handler;
private ScrollContainer container;
private HandlerInfo handlerInfo;
private String cacheKey = "";
private int currentPageIndex = -1;
private List<Integer> recipeIndices = new ArrayList<>();
private List<List<Widget>> pageWidgets = new ArrayList<>();
public RecipePageManager(SearchRecipeHandler<?> handler, HandlerInfo handlerInfo, ScrollContainer container) {
this.handler = handler;
this.handlerInfo = handlerInfo;
this.container = container;
rebuildPages();
}
public boolean rebuildPages() {
final String cacheKey = handlerInfo.getHandlerName() + ":"
+ getNumRecipes()
+ ":"
+ this.container.getVisibleHeight()
+ ":"
+ GuiRecipe.searchField.text();
if (cacheKey.equals(this.cacheKey)) {
return false;
}
this.cacheKey = cacheKey;
this.pageWidgets.clear();
final boolean useCustomScroll = this.handlerInfo.getUseCustomScroll();
final int handlerHeight = this.handlerInfo.getHeight() + this.handlerInfo.getYShift();
final boolean multipleWidgetsAllowed = !useCustomScroll && handlerInfo.isMultipleWidgetsAllowed();
final boolean infiniteScroll = !useCustomScroll
&& NEIClientConfig.getBooleanSetting("inventory.guirecipe.infiniteScroll");
final int heightAvailable = this.container.getVisibleHeight();
final int width = Math.max(166, this.handlerInfo.getWidth());
final int numRecipes = getNumRecipes();
List<Widget> widgets = new ArrayList<>();
int shiftY = 0;
for (int i = 0; i < numRecipes; i++) {
final int recipeIndex = this.handler.ref(i);
final NEIRecipeWidget widget = RecipeHandlerRef.of(this.handler.original, recipeIndex).getRecipeWidget();
widget.w = width;
if (useCustomScroll) {
widget.h = Math.min(handlerHeight, heightAvailable);
}
if (!widgets.isEmpty()
&& (!multipleWidgetsAllowed || !infiniteScroll && shiftY + widget.h > heightAvailable)) {
this.pageWidgets.add(widgets);
widgets = new ArrayList<>();
shiftY = 0;
}
widgets.add(widget);
shiftY += widget.h;
}
if (!widgets.isEmpty()) {
this.pageWidgets.add(widgets);
}
changePage(0);
return true;
}
public boolean isMultipleWidgetsAllowed() {
return !this.handlerInfo.getUseCustomScroll() && this.handlerInfo.isMultipleWidgetsAllowed();
}
public int getNumRecipes() {
return this.handler.numRecipes();
}
public int getCurrentPageIndex() {
return this.currentPageIndex;
}
public int getNumPages() {
return this.pageWidgets.size();
}
public void changePage(int delta) {
final int numPages = getNumPages();
final int page = numPages > 0 ? (numPages + Math.max(0, this.currentPageIndex) + delta) % numPages : 0;
if (this.currentPageIndex == page) {
return;
}
this.currentPageIndex = page;
this.recipeIndices = new ArrayList<>();
for (Widget widget : getCurrentPageWidgets()) {
if (widget instanceof NEIRecipeWidget recipeWidget) {
this.recipeIndices.add(recipeWidget.getRecipeHandlerRef().recipeIndex);
}
}
this.container.setVerticalScrollOffset(0);
}
public void gotoRefIndex(int refIndex) {
int page = 0;
for (int i = 0; i < this.pageWidgets.size(); i++) {
refIndex -= this.pageWidgets.get(i).size();
if (refIndex < 0) {
page = i;
break;
}
}
changePage(page);
}
public List<Widget> getCurrentPageWidgets() {
if (this.pageWidgets.isEmpty()) {
return Collections.emptyList();
}
List<Widget> currentWidgets = this.pageWidgets.get(this.currentPageIndex);
int shiftY = 0;
for (Widget widget : currentWidgets) {
if (widget instanceof NEIRecipeWidget recipeWidget) {
recipeWidget.setLocation(2, shiftY);
}
shiftY += widget.h;
}
return currentWidgets;
}
public List<Integer> getRecipeIndices() {
return this.recipeIndices;
}
}
@@ -17,12 +17,13 @@ import codechicken.nei.scroll.GuiHelper;
public class RecipeTooltipLineHandler implements ITooltipLineHandler {
private static final int BG_PADDING = 5;
private static final DrawableResource BG_TEXTURE = new DrawableBuilder(
private static final int TRANSPARENCY_BORDER = 4;
private final DrawableResource BG_TEXTURE = new DrawableBuilder(
"nei:textures/gui/recipebg.png",
0,
0,
176,
166).build();
176 + TRANSPARENCY_BORDER * 2,
166 + TRANSPARENCY_BORDER * 2).build();
protected long lastUpdate = System.currentTimeMillis();
protected String recipeName = "";
@@ -88,7 +89,15 @@ public class RecipeTooltipLineHandler implements ITooltipLineHandler {
GuiContainerManager.enable2DRender();
GL11.glColor4f(1, 1, 1, 1);
BG_TEXTURE.draw(0, 0, size.width, size.height, BG_PADDING, BG_PADDING, BG_PADDING, BG_PADDING);
BG_TEXTURE.draw(
-TRANSPARENCY_BORDER,
-TRANSPARENCY_BORDER,
size.width + TRANSPARENCY_BORDER * 2,
size.height + TRANSPARENCY_BORDER * 2,
BG_PADDING + TRANSPARENCY_BORDER,
BG_PADDING + TRANSPARENCY_BORDER,
BG_PADDING + TRANSPARENCY_BORDER,
BG_PADDING + TRANSPARENCY_BORDER);
GL11.glEnable(GL11.GL_ALPHA_TEST);
@@ -0,0 +1,24 @@
package codechicken.nei.recipe;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.inventory.Slot;
import codechicken.nei.PositionedStack;
public class RepairOverlayHandler extends DefaultOverlayHandler {
@Override
public boolean canCraft(GuiContainer firstGui, IRecipeHandler handler, int recipeIndex) {
return false;
}
@Override
public Slot[][] mapIngredSlots(GuiContainer gui, List<PositionedStack> ingredients) {
final List<Slot> slots = gui.inventorySlots.inventorySlots;
return new Slot[][] { { slots.get(0) }, { slots.get(1) } };
}
}
@@ -0,0 +1,233 @@
package codechicken.nei.recipe;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import net.minecraft.client.gui.GuiRepair;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import codechicken.nei.ItemList;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.RestartableTask;
import codechicken.nei.drawable.DrawableBuilder;
import codechicken.nei.drawable.DrawableResource;
public class RepairRecipeHandler extends TemplateRecipeHandler {
private final DrawableResource BG_TEXTURE = new DrawableBuilder("nei:textures/gui/repair.png", 0, 0, 168, 36)
.setTextureSize(168, 36).build();
private static final RestartableTask reloadRepairRecipesTask = new RestartableTask("NEI Repair Recipe Reloading") {
@Override
public void execute() {
new RepairRecipeHandler().buildCache();
}
};
private static class ItemStackKey {
private final ItemStack stack;
public ItemStackKey(ItemStack stack) {
this.stack = stack;
}
@Override
public int hashCode() {
return stack.getItem().hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj instanceof ItemStackKey objeKey) {
return NEIClientUtils.areStacksSameTypeWithNBT(stack, objeKey.stack);
}
return false;
}
}
private static class DamagablePositionedStack extends PositionedStack {
public DamagablePositionedStack(Object item, int x, int y) {
super(item, x, y);
}
@Override
public boolean contains(ItemStack ingredient) {
return ingredient.getItemDamage() > 0 && NEIClientUtils.areStacksSameTypeWithNBT(this.item, ingredient);
}
}
private static List<RepairPair> cachedRecipes;
private static final int LEFT_X = 25;
private static final int RIGHT_X = 74;
private static final int OUTPUT_X = 132;
private static final int SLOT_Y = 10;
public class RepairPair extends CachedRecipe {
final List<PositionedStack> ingredients = new ArrayList<>(2);
final PositionedStack result;
RepairPair(ItemStack left, Object right, ItemStack result) {
ingredients.add(new DamagablePositionedStack(left, LEFT_X, SLOT_Y));
ingredients.add(new PositionedStack(right, RIGHT_X, SLOT_Y));
this.result = new PositionedStack(result, OUTPUT_X, SLOT_Y);
}
@Override
public List<PositionedStack> getIngredients() {
return this.ingredients;
}
@Override
public PositionedStack getResult() {
return this.result;
}
}
public static void findRepairRecipesOnceParallel() {
reloadRepairRecipesTask.restart();
}
private void buildCache() {
final Map<ItemStackKey, RepairPair> recipes = new HashMap<>();
for (ItemStack itemstack1 : ItemList.items) {
recipes.computeIfAbsent(new ItemStackKey(itemstack1), key -> this.getRepairRecipe(key.stack));
}
cachedRecipes = recipes.values().stream().filter(recipe -> recipe != null).collect(Collectors.toList());
}
private RepairPair getRepairRecipe(ItemStack itemstack1) {
if (!itemstack1.isItemStackDamageable()) return null;
final List<ItemStack> permutations = new ArrayList<>();
for (ItemStack itemstack2 : ItemList.items) {
if (itemstack1.getItem().getIsRepairable(itemstack1, itemstack2)) {
final ItemStack right = itemstack2.copy();
right.stackSize = 4;
permutations.add(right);
}
}
if (permutations.isEmpty()) return null;
final int maxDamage = itemstack1.getMaxDamage();
final ItemStack result = itemstack1.copy();
final ItemStack left = itemstack1.copy();
left.setItemDamage(maxDamage - 1);
result.setItemDamage(left.getItemDamageForDisplay() - (maxDamage / 4) * 4);
return new RepairPair(left, permutations, result);
}
@Override
public TemplateRecipeHandler newInstance() {
if (cachedRecipes == null) {
buildCache();
}
return super.newInstance();
}
@Override
public void loadCraftingRecipes(String outputId, Object... results) {
if (outputId.equals(getOverlayIdentifier()) && getClass() == RepairRecipeHandler.class) {
arecipes.addAll(cachedRecipes);
} else if (!NEIClientConfig.getBooleanSetting("showRepairOnlyForDamageableItems")) {
super.loadCraftingRecipes(outputId, results);
}
}
@Override
public void loadCraftingRecipes(ItemStack result) {
for (RepairPair recipe : cachedRecipes) {
if (recipe.getResult().contains(result)) arecipes.add(recipe);
}
}
@Override
public void loadUsageRecipes(String inputId, Object... ingredients) {
if (inputId.equals(getOverlayIdentifier()) && getClass() == RepairRecipeHandler.class) {
loadCraftingRecipes(getOverlayIdentifier());
} else {
super.loadUsageRecipes(inputId, ingredients);
}
}
@Override
public void loadUsageRecipes(ItemStack ingredient) {
final boolean showRepairOnlyForDamageableItems = NEIClientConfig
.getBooleanSetting("showRepairOnlyForDamageableItems");
for (RepairPair recipe : cachedRecipes) {
final List<PositionedStack> ingredients = recipe.getIngredients();
if (ingredients.get(0).contains(ingredient)) {
arecipes.add(recipe);
} else if (!showRepairOnlyForDamageableItems && ingredients.get(1).contains(ingredient)) {
arecipes.add(new RepairPair(ingredients.get(0).item, ingredient, recipe.getResult().item));
}
}
if (arecipes.isEmpty()) {
final RepairPair recipe = getRepairRecipe(ingredient);
if (recipe != null) {
arecipes.add(recipe);
}
}
}
@Override
public void loadTransferRects() {
transferRects.add(new RecipeTransferRect(new Rectangle(100, 11, 22, 15), getOverlayIdentifier()));
}
@Override
public String getRecipeName() {
return NEIClientUtils.translate("recipe.repair");
}
@Override
public String getGuiTexture() {
return "nei:textures/gui/repair.png";
}
@Override
public String getOverlayIdentifier() {
return "repair";
}
@Override
public Class<? extends GuiContainer> getGuiClass() {
return GuiRepair.class;
}
@Override
public void drawBackground(int recipe) {
BG_TEXTURE.draw(0, 0);
}
@Override
public void drawForeground(int recipe) {}
}
@@ -76,6 +76,16 @@ public class StackInfo {
return stack;
}
public static ItemStack normalizeRecipeQueryStack(ItemStack stack) {
ItemStack result = null;
for (int i = stackStringifyHandlers.size() - 1; i >= 0 && result == null; i--) {
result = stackStringifyHandlers.get(i).normalizeRecipeQueryStack(stack);
}
return result == null ? stack : result;
}
public static void pauseItemDamageSound(boolean pause) {
if (isPausedItemDamageSound != (isPausedItemDamageSound = pause)) {
for (IStackStringifyHandler handler : stackStringifyHandlers) {
@@ -256,6 +256,10 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
return rect.hashCode();
}
public Rectangle getRect() {
return rect;
}
Rectangle rect;
String outputId;
Object[] results;
@@ -16,6 +16,7 @@ import net.minecraft.nbt.NBTTagCompound;
import codechicken.nei.ItemStackAmount;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.bookmark.BookmarkItem;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.Recipe.RecipeIngredient;
@@ -52,20 +53,12 @@ public class RecipeChainMath {
private final List<ItemStack> containerItemsBlacklist = new ArrayList<>();
private RecipeChainMath(List<BookmarkItem> recipeItems, Set<RecipeId> collapsedRecipes) {
final Map<RecipeId, Integer> recipeState = new HashMap<>();
final Map<RecipeId, Long> multipliers = new HashMap<>();
for (BookmarkItem item : recipeItems) {
if (item.recipeId != null) {
recipeState
.put(item.recipeId, recipeState.getOrDefault(item.recipeId, 0) | (item.isIngredient ? 1 : 2));
}
}
for (BookmarkItem item : recipeItems) {
if (recipeState.getOrDefault(item.recipeId, 0) != 3) {
if (item.recipeId == null || item.type == BookmarkItemType.ITEM) {
this.initialItems.add(item.copy());
} else if (item.isIngredient) {
} else if (item.type == BookmarkItemType.INGREDIENT) {
this.recipeIngredients.add(item.copyWithAmount(0));
} else {
this.recipeResults.add(item.copyWithAmount(0));
@@ -209,7 +202,7 @@ public class RecipeChainMath {
item.getItemStack(amount),
item.getStackSize(amount),
ROOT_RECIPE_ID,
true,
BookmarkItemType.INGREDIENT,
BookmarkItem.generatePermutations(item.itemStack, null)));
}
}
@@ -217,7 +210,7 @@ public class RecipeChainMath {
this.outputRecipes.clear();
this.outputRecipes.put(ROOT_RECIPE_ID, 1L);
this.recipeResults.removeIf(item -> ROOT_RECIPE_ID.equals(item.recipeId));
this.recipeResults.add(BookmarkItem.of(-1, ROOT_ITEM, 1, ROOT_RECIPE_ID, false));
this.recipeResults.add(BookmarkItem.of(-1, ROOT_ITEM, 1, ROOT_RECIPE_ID, BookmarkItemType.RESULT));
this.recipeIngredients.addAll(rootIngredients);
return ROOT_RECIPE_ID;
@@ -236,7 +229,7 @@ public class RecipeChainMath {
final RecipeId recipeId = recipe.getRecipeId();
final ItemStack result = recipe.getResult();
chainItems.add(BookmarkItem.of(-1, result, StackInfo.getAmount(result), recipeId, false));
chainItems.add(BookmarkItem.of(-1, result, StackInfo.getAmount(result), recipeId, BookmarkItemType.RESULT));
for (RecipeIngredient ingr : recipe.getIngredients()) {
chainItems.add(
@@ -245,7 +238,7 @@ public class RecipeChainMath {
ingr.getItemStack(),
ingr.getAmount(),
recipeId,
true,
BookmarkItemType.INGREDIENT,
BookmarkItem.generatePermutations(ingr.getItemStack(), recipe)));
}
@@ -36,6 +36,7 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
protected ItemsTooltipLineHandler inputs;
protected ItemsTooltipLineHandler outputs;
protected ItemsTooltipLineHandler remainder;
protected ItemsTooltipLineHandler craftingNeeded;
protected boolean lastShiftKey = false;
protected boolean lastControlKey = false;
@@ -54,6 +55,7 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
final List<ItemStack> inputs = new ArrayList<>();
final List<ItemStack> outputs = new ArrayList<>();
final List<ItemStack> remainder = new ArrayList<>();
final List<ItemStack> craftingNeeded = new ArrayList<>();
final ItemStackAmount inventory = new ItemStackAmount();
final GuiContainer currentGui = NEIClientUtils.getGuiContainer();
@@ -167,6 +169,12 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
}
}
if (this.lastShiftKey) {
for (Map.Entry<BookmarkItem, Long> item : this.math.requiredAmount.entrySet()) {
if (item.getKey().type == BookmarkItem.BookmarkItemType.RESULT && item.getValue() != 0)
craftingNeeded.add(item.getKey().getItemStack(item.getValue()));
}
}
inputs.sort(
Comparator.comparing((ItemStack stack) -> StackInfo.getFluid(stack) != null)
@@ -203,11 +211,20 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
true,
Integer.MAX_VALUE);
this.craftingNeeded = new ItemsTooltipLineHandler(
NEIClientUtils.translate("bookmark.crafting_chain.needed"),
craftingNeeded,
true,
Integer.MAX_VALUE);
if (this.lastShiftKey) {
this.inputs.setLabelColor(EnumChatFormatting.RED);
this.available.setLabelColor(EnumChatFormatting.GREEN);
this.craftingNeeded.setLabelColor(EnumChatFormatting.BLUE);
}
this.size.height = this.size.width = 0;
if (!this.inputs.isEmpty() || !this.outputs.isEmpty()
|| !this.remainder.isEmpty()
|| !this.available.isEmpty()) {
@@ -215,18 +232,18 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
if (!this.math.outputRecipes.isEmpty()) {
this.size.height = 2 + GuiDraw.fontRenderer.FONT_HEIGHT;
}
this.size.width = Math.max(
this.inputs.getSize().width,
Math.max(
this.outputs.getSize().width,
Math.max(this.remainder.getSize().width, this.available.getSize().width)));
Math.max(
this.remainder.getSize().width,
Math.max(this.available.getSize().width, this.craftingNeeded.getSize().width))));
this.size.height += this.inputs.getSize().height + this.outputs.getSize().height
+ this.remainder.getSize().height
+ this.available.getSize().height;
} else {
this.size.height = this.size.width = 0;
+ this.available.getSize().height
+ this.craftingNeeded.getSize().height;
}
}
@@ -258,7 +275,6 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
}
if (NEIClientConfig.recipeChainDir() == 0) {
if (!this.inputs.isEmpty()) {
this.inputs.draw(x, y);
y += this.inputs.getSize().height;
@@ -269,6 +285,11 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
y += this.available.getSize().height;
}
if (!this.craftingNeeded.isEmpty()) {
this.craftingNeeded.draw(x, y);
y += this.craftingNeeded.getSize().height;
}
if (!this.outputs.isEmpty()) {
this.outputs.draw(x, y);
y += this.outputs.getSize().height;
@@ -286,6 +307,11 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
y += this.inputs.getSize().height;
}
if (!this.craftingNeeded.isEmpty()) {
this.craftingNeeded.draw(x, y);
y += this.craftingNeeded.getSize().height;
}
if (!this.available.isEmpty()) {
this.available.draw(x, y);
y += this.available.getSize().height;
@@ -0,0 +1,37 @@
package codechicken.nei.recipe.debug;
import java.util.function.Consumer;
import codechicken.nei.Button;
import codechicken.nei.NEIClientUtils;
public class CheckboxWidget extends Button implements IUpdatableWidget {
protected Consumer<CheckboxWidget> onChange;
protected boolean value;
public CheckboxWidget(Consumer<CheckboxWidget> onChange) {
super();
this.onChange = onChange;
this.h = 16;
this.z = 2;
}
@Override
public String getRenderLabel() {
return this.value ? NEIClientUtils.translate("debug.RecipeHandler.checkbox.on")
: NEIClientUtils.translate("debug.RecipeHandler.checkbox.off");
}
@Override
public boolean onButtonPress(boolean rightclick) {
this.value = !this.value;
onChange.accept(this);
return true;
}
public void updateValue(String newValue) {
this.value = Boolean.parseBoolean(newValue);
}
}
@@ -0,0 +1,618 @@
package codechicken.nei.recipe.debug;
import java.awt.Point;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.stream.Collectors;
import net.minecraft.client.gui.inventory.GuiContainer;
import org.apache.commons.io.IOUtils;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ClientHandler;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.Widget;
import codechicken.nei.drawable.DrawableBuilder;
import codechicken.nei.drawable.DrawableResource;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.GuiRecipeButton;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.HandlerInfo;
import codechicken.nei.recipe.IRecipeHandler;
import codechicken.nei.recipe.NEIRecipeWidget;
import codechicken.nei.recipe.TemplateRecipeHandler;
import codechicken.nei.recipe.TemplateRecipeHandler.RecipeTransferRect;
import codechicken.nei.scroll.ScrollContainer;
public class DebugHandlerWidget extends Widget {
private static class HandlerInfoRecord {
public String handlerKey;
public int yShift;
public int width;
public int height;
public boolean multiWidgets;
public int order;
public boolean useCustomScroll;
public boolean showFavorites;
public boolean showOverlay;
private String csvLine;
public HandlerInfoRecord(String handlerKey, HandlerInfo info) {
this.handlerKey = handlerKey;
this.yShift = info.getYShift();
this.width = info.getWidth();
this.height = info.getHeight();
this.multiWidgets = info.isMultipleWidgetsAllowed();
this.order = NEIClientConfig.handlerOrdering.getOrDefault(handlerKey, 0);
this.useCustomScroll = info.getUseCustomScroll();
this.showFavorites = info.getShowFavoritesButton();
this.showOverlay = info.getShowOverlayButton();
this.csvLine = toCsvLine();
}
public void applyTo(HandlerInfo info) {
info.setYShift(this.yShift);
info.setHandlerDimensions(this.width, this.height);
info.setMultipleWidgetsAllowed(this.multiWidgets);
info.setUseCustomScroll(this.useCustomScroll);
info.setShowFavoritesButton(this.showFavorites);
info.setShowOverlayButton(this.showOverlay);
NEIClientConfig.handlerOrdering.put(this.handlerKey, this.order);
}
public String toCsvLine() {
return String.join(
",",
handlerKey,
String.valueOf(yShift),
String.valueOf(height),
String.valueOf(width),
String.valueOf(multiWidgets ? 1 : 0),
String.valueOf(order),
String.valueOf(useCustomScroll ? 1 : 0),
String.valueOf(showFavorites ? 1 : 0),
String.valueOf(showOverlay ? 1 : 0));
}
public boolean isUnmodified() {
return this.csvLine.equals(this.toCsvLine());
}
}
private static final int WINDOW_WIDTH = 176;
private static final int LINE_HEIGHT = 16;
private static final int INLINE_PADDING = 6;
private static final int LABEL_WIDTH = 50;
private static final String TOOLTIP_PREFIX = "debug.RecipeHandler.";
private static final String HEADER = "HandlerId,YShift,Height,Width,MultiWidgets,Order,UseCustomScroll,ShowFavorites,ShowOverlay";
private final int[] COLORS = new int[] { 0x2200FF00, 0x22FF0000, 0x220000FF, 0x2200FFFF, 0x22FF00FF, 0x22FFFF00 };
public static DebugHandlerWidget instance = new DebugHandlerWidget();
private ScrollContainer container = new ScrollContainer();
private final Map<String, IUpdatableWidget> values = new LinkedHashMap<>();
private Map<String, HandlerInfoRecord> patches = new HashMap<>();
private IRecipeHandler handler;
private HandlerInfo handlerInfo;
private HandlerInfoRecord record;
private Point dragPoint = null;
private boolean showWidget = false;
private final DrawableResource BG_TEXTURE = new DrawableBuilder(
"nei:textures/gui/recipebg.png",
0,
0,
176 + TRANSPARENCY_BORDER * 2,
166 + TRANSPARENCY_BORDER * 2).build();
private static final int BORDER_PADDING = 6;
private static final int TRANSPARENCY_BORDER = 4;
public DebugHandlerWidget() {
this.w = WINDOW_WIDTH;
this.x = 10;
this.y = 50;
this.z = 4;
this.container.x = this.x + INLINE_PADDING;
this.container.y = this.y + 5 + LINE_HEIGHT;
this.container.w = this.w - INLINE_PADDING * 2;
int y = 0;
y = addInfoWidget("Name", y);
y = addInfoWidget("Id", y);
y = addInfoWidget("Key", y);
y = addInfoWidget("HHack", y);
y = addInfoWidget("ModName", y);
y = addInfoWidget("ModId", y);
y = addInfoWidget("Override", y);
y = addTextFieldWidget("Order", 0, (field, oldText) -> {
if (field.getInteger() != record.order) {
record.order = field.getInteger();
saveHandlerInfoPatch();
}
}, y);
y = addTextFieldWidget("yShift", 0, (field, oldText) -> {
if (field.getInteger() != handlerInfo.getYShift()) {
handlerInfo.setYShift(field.getInteger());
record.yShift = field.getInteger();
saveHandlerInfoPatch();
}
}, y);
y = addCheckboxWidget("MultiWidgets", button -> {
handlerInfo.setMultipleWidgetsAllowed(button.value);
record.multiWidgets = button.value;
saveHandlerInfoPatch();
}, y);
final LabelWidget readonly = new LabelWidget(0xffffff, true);
readonly.y = y;
readonly.w = 57;
readonly.x = this.w - INLINE_PADDING * 2 - readonly.w;
this.values.put("height_readonly", readonly);
y = addTextFieldWidget("Height", HandlerInfo.DEFAULT_HEIGHT, (field, oldText) -> {
if (field.getInteger() != handlerInfo.getHeight()) {
handlerInfo.setHandlerDimensions(handlerInfo.getWidth(), field.getInteger());
record.height = field.getInteger();
saveHandlerInfoPatch();
}
}, y);
y = addTextFieldWidget("Width", HandlerInfo.DEFAULT_WIDTH, (field, oldText) -> {
if (field.getInteger() != handlerInfo.getWidth()) {
handlerInfo.setHandlerDimensions(field.getInteger(), handlerInfo.getHeight());
record.width = field.getInteger();
saveHandlerInfoPatch();
}
}, y);
y = addCheckboxWidget("UseCustomScroll", button -> {
handlerInfo.setUseCustomScroll(button.value);
record.useCustomScroll = button.value;
saveHandlerInfoPatch();
}, y);
y = addCheckboxWidget("ShowFavorites", button -> {
handlerInfo.setShowFavoritesButton(button.value);
record.showFavorites = button.value;
saveHandlerInfoPatch();
}, y);
y = addCheckboxWidget("ShowOverlay", button -> {
handlerInfo.setShowOverlayButton(button.value);
record.showOverlay = button.value;
saveHandlerInfoPatch();
}, y);
this.h = 10 + LINE_HEIGHT + y;
this.container.h = this.h - INLINE_PADDING * 2 - LINE_HEIGHT;
}
private int addInfoWidget(String key, int y) {
final LabelWidget label = new LabelWidget(0x888888, false);
final LabelWidget value = new LabelWidget(0xffffff, true);
label.y = value.y = y;
label.w = LABEL_WIDTH;
value.x = LABEL_WIDTH + 5;
value.w = this.w - INLINE_PADDING * 2 - value.x;
label.updateValue(NEIClientUtils.translate(TOOLTIP_PREFIX + key));
this.container.addWidget(label);
this.container.addWidget(value);
this.values.put(key.toLowerCase(), value);
return y + value.h + 1;
}
private int addTextFieldWidget(String key, int defaultValue, BiConsumer<IntegerField, String> onChange, int y) {
final LabelWidget label = new LabelWidget(0x888888, false);
final IntegerField value = new IntegerField(key, onChange, defaultValue);
label.y = value.y = y;
value.w = 60;
value.x = this.w - INLINE_PADDING * 2 - value.w;
label.w = value.x;
label.updateValue(NEIClientUtils.translate(TOOLTIP_PREFIX + key));
this.container.addWidget(label);
this.container.addWidget(value);
this.values.put(key.toLowerCase(), value);
return y + value.h + 1;
}
private int addCheckboxWidget(String key, Consumer<CheckboxWidget> onChange, int y) {
final LabelWidget label = new LabelWidget(0x888888, false);
final CheckboxWidget value = new CheckboxWidget(onChange);
label.y = value.y = y;
value.w = 58;
value.x = this.w - INLINE_PADDING * 2 - value.w - 1;
label.w = value.x;
label.updateValue(NEIClientUtils.translate(TOOLTIP_PREFIX + key));
this.container.addWidget(label);
this.container.addWidget(value);
this.values.put(key.toLowerCase(), value);
return y + value.h + 1;
}
@Override
public void draw(int mx, int my) {
if (this.handler != null) {
GL11.glColor4f(1F, 1F, 1F, 1F);
GL11.glScaled(1, 1, 2f);
GL11.glDisable(GL11.GL_DEPTH_TEST);
BG_TEXTURE.draw(
this.x - TRANSPARENCY_BORDER,
this.y - TRANSPARENCY_BORDER,
this.w + TRANSPARENCY_BORDER * 2,
this.h + TRANSPARENCY_BORDER * 2,
BORDER_PADDING + TRANSPARENCY_BORDER,
BORDER_PADDING + TRANSPARENCY_BORDER,
BORDER_PADDING + TRANSPARENCY_BORDER,
BORDER_PADDING + TRANSPARENCY_BORDER);
GuiDraw.drawRect(
this.x + INLINE_PADDING,
this.y + BORDER_PADDING,
this.w - INLINE_PADDING * 2,
12,
0x30000000);
GuiDraw.drawStringC(
NEIClientUtils.translate("debug.RecipeHandler.title"),
this.x + this.w / 2,
this.y + BORDER_PADDING + 2,
0xffffff);
this.container.draw(mx, my);
GL11.glScaled(1, 1, 1 / 2f);
}
}
@Override
public void update() {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
if (this.showWidget && gui instanceof GuiRecipe recipe) {
if (this.handler != recipe.getHandler()) {
this.handler = recipe.getHandler();
this.handlerInfo = GuiRecipeTab.getHandlerInfo(handler);
this.record = this.patches.computeIfAbsent(
getHandlerID(handler),
handlerKey -> new HandlerInfoRecord(handlerKey, handlerInfo));
final boolean isHeightHackApplied = NEIClientConfig.heightHackHandlerRegex.stream()
.map(pattern -> pattern.matcher(this.handler.getHandlerId())).anyMatch(Matcher::matches);
this.values.get("name").updateValue(this.handler.getRecipeName());
this.values.get("id").updateValue(this.handler.getOverlayIdentifier());
this.values.get("key").updateValue(this.handler.getHandlerId());
this.values.get("hhack").updateValue(
isHeightHackApplied ? NEIClientUtils.translate("debug.RecipeHandler.yes")
: NEIClientUtils.translate("debug.RecipeHandler.no"));
this.values.get("modname").updateValue(this.handlerInfo.getModName());
this.values.get("modid").updateValue(this.handlerInfo.getModId());
this.values.get("order").updateValue(String.valueOf(this.record.order));
this.values.get("yshift").updateValue(String.valueOf(this.record.yShift));
this.values.get("height").updateValue(String.valueOf(this.record.height));
this.values.get("height_readonly").updateValue(String.valueOf(this.record.height));
this.values.get("width").updateValue(String.valueOf(this.record.width));
this.values.get("multiwidgets").updateValue(String.valueOf(this.record.multiWidgets));
this.values.get("usecustomscroll").updateValue(String.valueOf(this.record.useCustomScroll));
this.values.get("showfavorites").updateValue(String.valueOf(this.record.showFavorites));
this.values.get("showoverlay").updateValue(String.valueOf(this.record.showOverlay));
this.values.get("override").updateValue(
this.record.isUnmodified() ? NEIClientUtils.translate("debug.RecipeHandler.no")
: NEIClientUtils.translate("debug.RecipeHandler.yes"));
this.container.removeIf(
widget -> this.values.get("height") == widget || this.values.get("height_readonly") == widget);
if (handler.getRecipeHeight(0) > 0) {
this.container.addWidget((Widget) this.values.get("height_readonly"));
} else {
this.container.addWidget((Widget) this.values.get("height"));
}
}
} else {
this.handler = null;
this.record = null;
this.handlerInfo = null;
this.showWidget = false;
}
this.container.update();
}
@Override
public List<String> handleTooltip(int mx, int my, List<String> tooltip) {
return this.handler != null ? this.container.handleTooltip(mx, my, tooltip) : tooltip;
}
@Override
public Map<String, String> handleHotkeys(int mousex, int mousey, Map<String, String> hotkeys) {
return this.handler != null ? this.container.handleHotkeys(mousex, mousey, hotkeys) : hotkeys;
}
@Override
public boolean handleKeyPress(int keyID, char keyChar) {
if (NEIClientConfig.getBooleanSetting("inventory.guirecipe.handlerInfo") && keyID == Keyboard.KEY_D
&& NEIClientUtils.shiftKey()) {
this.showWidget = !this.showWidget;
return true;
} else if (this.handler != null) {
if (this.container.handleKeyPress(keyID, keyChar)) {
return true;
}
this.container.lastKeyTyped(keyID, keyChar);
return this.container.isFocused();
}
return false;
}
@Override
public void onGuiClick(int mx, int my) {
if (this.handler != null) {
this.container.onGuiClick(mx, my);
}
}
@Override
public boolean handleClick(int mx, int my, int button) {
if (this.handler != null) {
if (new Rectangle4i(this.x + INLINE_PADDING, this.y + BORDER_PADDING, this.w - INLINE_PADDING * 2, 12)
.contains(mx, my)) {
this.dragPoint = new Point(mx, my);
}
this.container.handleClick(mx, my, button);
}
return this.handler != null;
}
@Override
public boolean contains(int px, int py) {
return this.handler != null && super.contains(px, py);
}
@Override
public void mouseUp(int mx, int my, int button) {
this.dragPoint = null;
if (this.handler != null) {
this.container.mouseUp(mx, my, button);
}
}
@Override
public boolean onMouseWheel(int scrolled, int mousex, int mousey) {
if (this.handler != null && contains(mousex, mousey)) {
this.container.onMouseWheel(scrolled, mousex, mousey);
return true;
}
return false;
}
@Override
public boolean handleClickExt(int mx, int my, int button) {
return this.handler != null && this.container.handleClickExt(mx, my, button);
}
@Override
public void mouseDragged(int mx, int my, int button, long heldTime) {
if (this.dragPoint != null) {
this.x -= this.dragPoint.x - mx;
this.y -= this.dragPoint.y - my;
this.container.y = this.y + INLINE_PADDING + LINE_HEIGHT;
this.container.x = this.x + INLINE_PADDING;
this.dragPoint.move(mx, my);
}
}
public void drawGuiPlaceholder(NEIRecipeWidget widget) {
if (!this.showWidget) return;
NEIClientUtils.gl2DRenderContext(() -> {
// background
GuiDraw.drawRect(
widget.x,
widget.y,
widget.w,
widget.h,
COLORS[widget.getRecipeHandlerRef().recipeIndex % COLORS.length]);
// center cross
GuiDraw.drawRect(widget.x + widget.w / 2 - 1, widget.y, 1, widget.h, 0x88ffffff);
GuiDraw.drawRect(widget.x, widget.y + widget.h / 2 - 1, widget.w, 1, 0x88ffffff);
// blue-line-top (grid-top)
GuiDraw.drawRect(widget.x + 14, widget.y + 5, widget.w - 38, 1, 0xff0000aa);
// blue-line-bottom {grid-bottom}
GuiDraw.drawRect(widget.x + 14, widget.y + widget.h - 7, widget.w - 38, 1, 0xff0000aa);
// blue-left (grid start)
GuiDraw.drawRect(widget.x + 24, widget.y + (widget.h - 16) / 2, 1, 16, 0xffaa00aa);
// purple (before favorite)
GuiDraw.drawRect(
widget.x + Math.min(168, widget.w) - 27,
widget.y + widget.h - 6 - GuiRecipeButton.BUTTON_HEIGHT * 2 - 4,
GuiRecipeButton.BUTTON_WIDTH,
1,
0xffaa00aa);
// green ()
GuiDraw.drawRect(
widget.x + Math.min(168, widget.w) - 35,
widget.y + widget.h - 6 - GuiRecipeButton.BUTTON_HEIGHT - 3,
20,
1,
0xff00aa00);
// purple space before bottom grid
GuiDraw.drawRect(
widget.x + 14,
widget.y + widget.h - 7 - GuiRecipeButton.BUTTON_WIDTH / 2,
38,
1,
0xffaa00aa);
if (widget.getRecipeHandlerRef().handler instanceof TemplateRecipeHandler handler) {
int yShift = widget.getHandlerInfo().getYShift();
for (RecipeTransferRect rect : handler.transferRects) {
GuiDraw.drawRect(
widget.x + rect.getRect().x,
widget.y + yShift + rect.getRect().y,
rect.getRect().width,
rect.getRect().height,
0x40ff0000);
}
}
});
}
public void loadHandlerInfoPatch() {
ClientHandler.loadSettingsFile("handlers.patch", lines -> {
for (String line : lines.collect(Collectors.toCollection(HashSet::new))) {
if (HEADER.equals(line)) continue;
final String[] parts = Arrays.copyOf((line + ",null,null,null,null,null,null,null,null").split(","), 9);
final String handler = parts[0];
if (GuiRecipeTab.handlerMap.containsKey(handler)) {
final HandlerInfo info = GuiRecipeTab.handlerMap.get(handler);
final HandlerInfoRecord record = patches
.computeIfAbsent(handler, handlerKey -> new HandlerInfoRecord(handler, info));
record.yShift = intOrDefault(parts[1], info.getYShift());
record.height = intOrDefault(parts[2], info.getHeight());
record.width = intOrDefault(parts[3], info.getWidth());
record.multiWidgets = intOrDefault(parts[4], info.isMultipleWidgetsAllowed() ? 1 : 0) == 1;
record.order = intOrDefault(parts[5], NEIClientConfig.handlerOrdering.getOrDefault(handler, 0));
record.useCustomScroll = intOrDefault(parts[6], info.getUseCustomScroll() ? 1 : 0) == 1;
record.showFavorites = intOrDefault(parts[7], info.getShowFavoritesButton() ? 1 : 0) == 1;
record.showOverlay = intOrDefault(parts[8], info.getShowOverlayButton() ? 1 : 0) == 1;
record.applyTo(info);
}
}
});
}
private void saveHandlerInfoPatch() {
final List<String> lines = new ArrayList<>();
lines.add(HEADER);
for (HandlerInfoRecord record : patches.values()) {
if (!record.csvLine.equals(record.toCsvLine())) {
lines.add(record.toCsvLine());
}
}
final File path = new File(NEIClientConfig.configDir, "handlers.patch");
try (FileOutputStream output = new FileOutputStream(path)) {
IOUtils.writeLines(lines, "\n", output, StandardCharsets.UTF_8);
} catch (IOException e) {}
if (this.record != null) {
this.values.get("override").updateValue(
this.record.isUnmodified() ? NEIClientUtils.translate("debug.RecipeHandler.no")
: NEIClientUtils.translate("debug.RecipeHandler.yes"));
}
if (NEIClientUtils.getGuiContainer() instanceof GuiRecipe<?>recipe) {
recipe.forceRefreshPage();
}
}
private int intOrDefault(String str, int defaultValue) {
if (str == null || str.isEmpty()) return defaultValue;
try {
return Integer.parseInt(str);
} catch (NumberFormatException e) {
return defaultValue;
}
}
private String getHandlerID(IRecipeHandler handler) {
if (GuiRecipeTab.handlerMap.containsKey(handler.getHandlerId())) {
return handler.getHandlerId();
} else if (handler instanceof TemplateRecipeHandler) {
return handler.getOverlayIdentifier();
}
return handler.getHandlerId();
}
}
@@ -0,0 +1,7 @@
package codechicken.nei.recipe.debug;
public interface IUpdatableWidget {
public void updateValue(String newValue);
}
@@ -0,0 +1,94 @@
package codechicken.nei.recipe.debug;
import java.util.function.BiConsumer;
import net.minecraft.client.Minecraft;
import org.lwjgl.input.Keyboard;
import codechicken.nei.FormattedTextField;
import codechicken.nei.TextField;
public class IntegerField extends TextField implements IUpdatableWidget {
protected int defaultValue = 0;
protected BiConsumer<IntegerField, String> onChange;
public IntegerField(String ident, BiConsumer<IntegerField, String> onChange, int defaultValue) {
super(ident);
this.onChange = onChange;
this.defaultValue = defaultValue;
this.h = 16;
this.z = 2;
((FormattedTextField) field).setPlaceholder(Integer.toString(this.defaultValue));
}
@Override
protected void initInternalTextField() {
field = new FormattedTextField(Minecraft.getMinecraft().fontRenderer, 0, 0, 0, 0) {
@Override
public String getText() {
final String text = super.getText();
return !isFocused() && this.placeholder.equals(text) ? "" : text;
}
@Override
protected boolean beforeWrite(String text) {
if (text == null || text.isEmpty()) return true;
try {
Integer.parseInt(text);
return true;
} catch (NumberFormatException e) {
return false;
}
}
@Override
public boolean textboxKeyTyped(char keyChar, int keyID) {
if (!isFocused()) return false;
if (super.textboxKeyTyped(keyChar, keyID)) {
return true;
} else if (keyID == Keyboard.KEY_DOWN) {
setText(Integer.toString(getInteger() - 1));
return true;
} else if (keyID == Keyboard.KEY_UP) {
setText(Integer.toString(getInteger() + 1));
return true;
}
return false;
}
};
field.setMaxStringLength(maxSearchLength);
field.setCursorPositionZero();
}
protected int getInteger() {
try {
return Integer.parseInt(text());
} catch (NumberFormatException nfe) {
return this.defaultValue;
}
}
@Override
public boolean onMouseWheel(int i, int mx, int my) {
if (!contains(mx, my)) return false;
setText(Integer.toString(getInteger() + i));
return true;
}
public void updateValue(String newValue) {
setText(newValue);
}
@Override
public void onTextChange(String oldText) {
onChange.accept(this, oldText);
}
}
@@ -0,0 +1,74 @@
package codechicken.nei.recipe.debug;
import java.awt.Point;
import java.util.List;
import java.util.Map;
import net.minecraft.client.gui.GuiScreen;
import org.lwjgl.input.Keyboard;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.Widget;
import codechicken.nei.util.NEIMouseUtils;
public class LabelWidget extends Widget implements IUpdatableWidget {
protected int color;
protected boolean shadow;
protected String value = "";
protected String croppedValue;
public LabelWidget(int color, boolean shadow) {
this.color = color;
this.shadow = shadow;
this.h = 16;
this.z = 2;
}
@Override
public void draw(int mx, int my) {
GuiDraw.drawString(this.croppedValue, this.x, this.y + (this.h - 8) / 2, this.color, this.shadow);
}
public void updateValue(String newValue) {
this.value = newValue;
this.croppedValue = NEIClientUtils.cropText(GuiDraw.fontRenderer, this.value, this.w);
}
@Override
public List<String> handleTooltip(int mx, int my, List<String> tooltip) {
if (contains(mx, my)) {
tooltip.add(this.value);
}
return tooltip;
}
@Override
public boolean handleKeyPress(int keyID, char keyChar) {
final Point mouse = GuiDraw.getMousePosition();
if (contains(mouse.x, mouse.y) && Keyboard.KEY_C == keyID && NEIClientUtils.controlKey()) {
GuiScreen.setClipboardString(this.value);
return true;
}
return false;
}
@Override
public Map<String, String> handleHotkeys(int mousex, int mousey, Map<String, String> hotkeys) {
if (contains(mousex, mousey)) {
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.CTRL_HASH + Keyboard.KEY_C, NEIMouseUtils.MOUSE_BTN_NONE),
NEIClientUtils.translate("debug.RecipeHandler.copy"));
}
return hotkeys;
}
}
@@ -19,9 +19,8 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler {
protected static Class<?> itemFluidDisplay = null;
protected static Method getFluidDisplayStack = null;
protected static Method getFluidFromDisplayStack = null;
public static boolean replaceAE2FCFluidDrop = false;
private static Class<?> gtMetaGeneratedTool = null;
private static Field playSound = null;
protected static Class<?> gtMetaGeneratedTool = null;
protected static Field playSound = null;
static {
try {
@@ -48,7 +47,7 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler {
public NBTTagCompound convertItemStackToNBT(ItemStack stack, boolean saveStackSize) {
if (replaceAE2FCFluidDrop || stack.getItem() != GameRegistry.findItem("ae2fc", "fluid_drop")) {
if (stack.getItem() != GameRegistry.findItem("ae2fc", "fluid_drop")) {
final FluidStack fluidStack = getFluid(stack);
if (fluidStack != null) {
@@ -69,14 +68,11 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler {
final Fluid fluid = FluidRegistry.getFluid(fluidName);
final int amount = nbtTag.getInteger("Count");
try {
final Object obj = getFluidDisplayStack.invoke(null, new FluidStack(fluid, amount), true);
if (obj != null) {
return (ItemStack) obj;
}
} catch (Exception e) {}
if (fluid != null) {
try {
return (ItemStack) getFluidDisplayStack.invoke(null, new FluidStack(fluid, amount), true);
} catch (Exception e) {}
}
}
return null;
@@ -114,6 +110,22 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler {
return null;
}
public ItemStack normalizeRecipeQueryStack(ItemStack stack) {
if (stack.getItem() == GameRegistry.findItem("ae2fc", "fluid_drop")
|| stack.getItem() == GameRegistry.findItem("ae2fc", "fluid_packet")) {
final FluidStack fluidStack = getFluid(stack);
if (fluidStack != null) {
try {
return (ItemStack) getFluidDisplayStack.invoke(null, fluidStack, true);
} catch (Exception e) {}
}
}
return null;
}
@Override
public void pauseItemDamageSound(boolean pause) {
if (playSound != null) {
@@ -31,18 +31,26 @@ public class ScrollBar {
}
public enum ScrollPlace {
INSIDE,
OUTSIDE
START,
END
}
private ScrollType scrollType = ScrollType.VERTICAL;
private OverflowType overflowType = OverflowType.SCROLL;
private ScrollPlace scrollPlace = ScrollPlace.INSIDE;
private ScrollPlace scrollPlace = ScrollPlace.END;
private float handleClickOffset = -1;
private int scrollbarSize = 6;
private int thumbPadding = 0;
private int margin = 0;
private int trackWidth = 6;
private int thumbPaddingLeft = 0;
private int thumbPaddingRight = 0;
private int thumbPaddingTop = 0;
private int thumbPaddingBottom = 0;
private int trackPaddingLeft = 0;
private int trackPaddingRight = 0;
private int trackPaddingTop = 0;
private int trackPaddingBottom = 0;
private DrawableResource thumbTexture;
private int thumbSliceStart;
@@ -57,41 +65,65 @@ public class ScrollBar {
}
public static ScrollBar defaultVerticalBar() {
return new ScrollBar().setScrollbarSize(8)
.setTrackTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 29, 95, 12, 11).build(), 3, 4)
.setThumbTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 21, 96, 8, 9).build(), 3, 2)
.setThumbPadding(1);
return new ScrollBar().setTrackWidth(8)
.setTrackTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 29, 95, 8, 11).build(), 3, 4)
.setThumbTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 22, 96, 6, 9).build(), 3, 2)
.setThumbPadding(1, 1, 1, 1);
}
public static ScrollBar defaultHorizontalBar() {
return new ScrollBar().setScrollbarSize(8).setOverflowType(OverflowType.SCROLL)
.setScrollPlace(ScrollPlace.INSIDE)
return new ScrollBar().setTrackWidth(8).setOverflowType(OverflowType.SCROLL)
.setTrackTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 0, 97, 11, 8).build(), 3, 4)
.setThumbTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 12, 97, 9, 7).build(), 3, 2)
.setThumbPadding(1);
.setThumbTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 12, 98, 9, 6).build(), 3, 2)
.setThumbPadding(1, 1, 1, 1);
}
public ScrollBar setScrollbarSize(int scrollbarSize) {
this.scrollbarSize = scrollbarSize;
/**
* Sets the size of the scrollbar without texture in the non-scrolling axis (width for vertical, height for
* horizontal).
*
* @param trackWidth
* @return
*/
public ScrollBar setTrackWidth(int trackWidth) {
this.trackWidth = trackWidth;
return this;
}
public ScrollBar setThumbPadding(int thumbPadding) {
this.thumbPadding = thumbPadding;
public ScrollBar setTrackPadding(int left, int top, int right, int bottom) {
this.trackPaddingLeft = left;
this.trackPaddingRight = right;
this.trackPaddingTop = top;
this.trackPaddingBottom = bottom;
return this;
}
public ScrollBar setMargin(int margin) {
this.margin = margin;
public ScrollBar setThumbPadding(int left, int top, int right, int bottom) {
this.thumbPaddingLeft = left;
this.thumbPaddingRight = right;
this.thumbPaddingTop = top;
this.thumbPaddingBottom = bottom;
return this;
}
public int getMargin() {
return this.margin;
public int getTrackWidth() {
if (this.trackTexture != null) {
return this.scrollType == ScrollType.HORIZONTAL ? this.trackTexture.getHeight()
: this.trackTexture.getWidth();
}
return this.trackWidth;
}
public int getScrollbarSize() {
return this.scrollbarSize;
protected int getThumbWidth() {
if (this.thumbTexture != null) {
return this.scrollType == ScrollType.HORIZONTAL ? this.thumbTexture.getHeight()
: this.thumbTexture.getWidth();
}
return getTrackWidth();
}
public ScrollBar setThumbTexture(DrawableResource texture, int sliceStart, int sliceEnd) {
@@ -148,27 +180,18 @@ public class ScrollBar {
}
private int getMaxThumbSize(ScrollContainer container) {
return getMaxTrackSize(container) - this.thumbPadding * 2;
if (this.scrollType == ScrollType.HORIZONTAL) {
return getMaxTrackSize(container) - this.thumbPaddingLeft - this.thumbPaddingRight;
} else {
return getMaxTrackSize(container) - this.thumbPaddingTop - this.thumbPaddingBottom;
}
}
private int getMaxTrackSize(ScrollContainer container) {
if (this.scrollType == ScrollType.HORIZONTAL) {
int visibleSize = container.w;
if (container.canScrollVertical() && container.getVerticalScroll().getScrollPlace() == ScrollPlace.INSIDE) {
visibleSize -= container.getVerticalScroll().getScrollbarSize();
}
return visibleSize;
return container.w - this.trackPaddingLeft - this.trackPaddingRight;
} else {
int visibleSize = container.h;
if (container.canScrollHorizontal()
&& container.getHorizontalScroll().getScrollPlace() == ScrollPlace.INSIDE) {
visibleSize -= container.getHorizontalScroll().getScrollbarSize();
}
return visibleSize;
return container.h - this.trackPaddingTop - this.trackPaddingBottom;
}
}
@@ -205,23 +228,22 @@ public class ScrollBar {
}
public Rectangle4i trackBounds(ScrollContainer container) {
int trackWidth = getTrackWidth();
if (this.scrollType == ScrollType.HORIZONTAL) {
return new Rectangle4i(
container.x,
container.y + container.h
+ this.margin
- (this.scrollPlace == ScrollPlace.INSIDE ? scrollbarSize : 0),
getMaxTrackSize(container),
scrollbarSize);
final int y = this.scrollPlace == ScrollPlace.START ? container.y - trackWidth - this.trackPaddingBottom
: container.y + container.h + this.trackPaddingTop;
return new Rectangle4i(container.x + this.trackPaddingLeft, y, getMaxTrackSize(container), trackWidth);
} else {
return new Rectangle4i(
container.x + container.w
+ this.margin
- (this.scrollPlace == ScrollPlace.INSIDE ? scrollbarSize : 0),
container.y,
scrollbarSize,
getMaxTrackSize(container));
final int x = this.scrollPlace == ScrollPlace.START ? container.x - trackWidth - this.trackPaddingRight
: container.x + container.w + this.trackPaddingLeft;
return new Rectangle4i(x, container.y + this.trackPaddingTop, trackWidth, getMaxTrackSize(container));
}
}
public Rectangle4i thumbBounds(ScrollContainer container) {
@@ -230,9 +252,25 @@ public class ScrollBar {
final Rectangle4i bounds = trackBounds(container);
if (this.scrollType == ScrollType.HORIZONTAL) {
return new Rectangle4i(bounds.x + this.thumbPadding + offset, bounds.y, mainAxisSize, bounds.h);
final int y = this.scrollPlace == ScrollPlace.START
? bounds.y + bounds.h - getThumbWidth() - this.thumbPaddingBottom
: bounds.y + this.thumbPaddingTop;
return new Rectangle4i(
bounds.x + this.thumbPaddingLeft + offset,
y,
mainAxisSize,
bounds.h - this.thumbPaddingTop - this.thumbPaddingBottom);
} else {
return new Rectangle4i(bounds.x, bounds.y + this.thumbPadding + offset, bounds.w, mainAxisSize);
final int x = this.scrollPlace == ScrollPlace.START
? bounds.x + bounds.w - getThumbWidth() - this.thumbPaddingRight
: bounds.x + this.thumbPaddingLeft;
return new Rectangle4i(
x,
bounds.y + this.thumbPaddingTop + offset,
bounds.w - this.thumbPaddingLeft - this.thumbPaddingRight,
mainAxisSize);
}
}
@@ -253,7 +291,7 @@ public class ScrollBar {
final Rectangle4i thumbBounds = thumbBounds(container);
if (this.scrollType == ScrollType.HORIZONTAL) {
final int relativeX = mx - bounds.x - this.thumbPadding;
final int relativeX = mx - bounds.x - this.thumbPaddingLeft;
if (mx < thumbBounds.x || mx > thumbBounds.x + thumbBounds.w) {
this.handleClickOffset = mainAxisSize / 2;
@@ -265,7 +303,7 @@ public class ScrollBar {
* (container.getActualWidth() - container.getVisibleWidth())) / thumbSize;
container.setHorizontalScrollOffset((int) newOffset);
} else {
final int relativeY = my - bounds.y - this.thumbPadding;
final int relativeY = my - bounds.y - this.thumbPaddingTop;
if (my < thumbBounds.y || my > thumbBounds.y + thumbBounds.h) {
this.handleClickOffset = mainAxisSize / 2f;
@@ -293,12 +331,12 @@ public class ScrollBar {
final float thumbSize = getMaxThumbSize(container) - mainAxisSize;
if (this.scrollType == ScrollType.HORIZONTAL) {
final int relativeX = mx - bounds.x - this.thumbPadding;
final int relativeX = mx - bounds.x - this.thumbPaddingLeft;
final float newOffset = ((relativeX - this.handleClickOffset)
* (container.getActualWidth() - container.getVisibleWidth())) / thumbSize;
container.setHorizontalScrollOffset((int) newOffset);
} else {
int relativeY = my - bounds.y - this.thumbPadding;
int relativeY = my - bounds.y - this.thumbPaddingTop;
final float newOffset = ((relativeY - this.handleClickOffset)
* (container.getActualHeight() - container.getVisibleHeight())) / thumbSize;
@@ -354,7 +392,7 @@ public class ScrollBar {
}
private void drawTrackRect(ScrollContainer container, Rectangle4i bounds, float opacity) {
final float trackSize = scrollbarSize / 3f;
final float trackSize = this.trackWidth / 3f;
final Color trackColor = new Color(
BACKGROUND_COLOR.getRed(),
BACKGROUND_COLOR.getGreen(),
@@ -2,6 +2,7 @@ package codechicken.nei.scroll;
import java.awt.Point;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.function.Predicate;
@@ -14,7 +15,6 @@ import codechicken.nei.NEIClientUtils;
import codechicken.nei.Widget;
import codechicken.nei.WidgetContainer;
import codechicken.nei.scroll.ScrollBar.OverflowType;
import codechicken.nei.scroll.ScrollBar.ScrollPlace;
import codechicken.nei.scroll.ScrollBar.ScrollType;
public class ScrollContainer extends WidgetContainer {
@@ -34,10 +34,12 @@ public class ScrollContainer extends WidgetContainer {
protected int actualWidth = 0;
protected int actualHeight = 0;
protected int marginInline = 0;
protected int marginBlock = 0;
protected int paddingInlineStart = 0;
protected int paddingInlineEnd = 0;
protected int paddingBlockStart = 0;
protected int paddingBlockEnd = 0;
protected final Map<Widget, Point> relativePostion = new HashMap<>();
protected final Map<Widget, Point> relativePosition = new HashMap<>();
protected ScrollBar horizontalScrollBar;
protected ScrollBar verticalScrollBar;
protected int fade = 0;
@@ -45,78 +47,88 @@ public class ScrollContainer extends WidgetContainer {
public Rectangle4i boundsOutside() {
int width = this.w;
int height = this.h;
int x = this.x;
int y = this.y;
if (canScrollVertical() && (this.verticalScrollBar.getOverflowType() == OverflowType.SCROLL
|| this.verticalScrollBar.getOverflowType() == OverflowType.AUTO)) {
width += this.verticalScrollBar.getMargin();
if (this.verticalScrollBar.getScrollPlace() == ScrollPlace.OUTSIDE) {
width += this.verticalScrollBar.getScrollbarSize();
}
final Rectangle4i trackBounds = this.verticalScrollBar.trackBounds(this);
x = Math.min(x, trackBounds.x);
y = Math.min(y, trackBounds.y);
height = Math.max(this.y + height, trackBounds.y + trackBounds.h) - y;
width = Math.max(this.x + width, trackBounds.x + trackBounds.w) - x;
}
if (canScrollHorizontal() && (this.horizontalScrollBar.getOverflowType() == OverflowType.SCROLL
|| this.horizontalScrollBar.getOverflowType() == OverflowType.AUTO)) {
height += this.horizontalScrollBar.getMargin();
if (this.horizontalScrollBar.getScrollPlace() == ScrollPlace.OUTSIDE) {
height += this.horizontalScrollBar.getScrollbarSize();
}
final Rectangle4i trackBounds = this.horizontalScrollBar.trackBounds(this);
x = Math.min(x, trackBounds.x);
y = Math.min(y, trackBounds.y);
height = Math.max(this.y + height, trackBounds.y + trackBounds.h) - y;
width = Math.max(this.x + width, trackBounds.x + trackBounds.w) - x;
}
return new Rectangle4i(x, y, width, height);
}
public Rectangle4i boundsInside() {
return new Rectangle4i(x, y, getVisibleWidth(), getVisibleHeight());
return new Rectangle4i(
x + this.paddingInlineStart,
y + this.paddingBlockStart,
getVisibleWidth(),
getVisibleHeight());
}
@Override
public void clear() {
for (Map.Entry<Widget, Point> entry : this.relativePosition.entrySet()) {
entry.getKey().x = entry.getValue().x;
entry.getKey().y = entry.getValue().y;
}
super.clear();
this.relativePostion.clear();
this.relativePosition.clear();
}
@Override
public boolean removeIf(Predicate<Widget> filter) {
this.relativePostion.keySet().removeIf(filter);
final Iterator<Map.Entry<Widget, Point>> it = this.relativePosition.entrySet().iterator();
while (it.hasNext()) {
final Map.Entry<Widget, Point> entry = it.next();
if (filter.test(entry.getKey())) {
entry.getKey().x = entry.getValue().x;
entry.getKey().y = entry.getValue().y;
it.remove();
}
}
return super.removeIf(filter);
}
public void addWidget(Widget widget) {
super.addWidget(widget);
this.relativePostion.put(widget, new Point(widget.x, widget.y));
this.relativePosition.put(widget, new Point(widget.x, widget.y));
}
public Point getWidgetPosition(Widget widget) {
return this.relativePostion.get(widget);
return this.relativePosition.get(widget);
}
public void setMarginInline(int marginInline) {
this.marginInline = marginInline;
public void setPaddingInline(int start, int end) {
this.paddingInlineStart = start;
this.paddingInlineEnd = end;
}
public void setMarginBlock(int marginBlock) {
this.marginBlock = marginBlock;
}
public int getMarginInline() {
return this.marginInline;
}
public int getMarginBlock() {
return this.marginBlock;
public void setPaddingBlock(int start, int end) {
this.paddingBlockStart = start;
this.paddingBlockEnd = end;
}
public int getVisibleWidth() {
if (canScrollVertical() && this.verticalScrollBar.getScrollPlace() == ScrollPlace.INSIDE
&& (this.verticalScrollBar.getOverflowType() == OverflowType.SCROLL
|| this.verticalScrollBar.getOverflowType() == OverflowType.AUTO)) {
return this.w - this.verticalScrollBar.getScrollbarSize();
}
return this.w;
return this.w - this.paddingInlineStart - this.paddingInlineEnd;
}
public int getActualWidth() {
@@ -125,7 +137,7 @@ public class ScrollContainer extends WidgetContainer {
public boolean setHorizontalScrollOffset(int offset) {
if (!canScrollHorizontal() && this.w < getActualWidth()) {
if (!canScrollHorizontal() && getVisibleWidth() < getActualWidth()) {
offset = 0;
}
@@ -150,9 +162,9 @@ public class ScrollContainer extends WidgetContainer {
}
public boolean canScrollHorizontal() {
return this.horizontalScrollBar != null
&& (this.horizontalScrollBar.getOverflowType() != OverflowType.NONE && this.w < getActualWidth()
|| this.horizontalScrollBar.getOverflowType() == OverflowType.SCROLL);
return this.horizontalScrollBar != null && (this.horizontalScrollBar.getOverflowType() != OverflowType.NONE
&& getVisibleWidth() < getActualWidth()
|| this.horizontalScrollBar.getOverflowType() == OverflowType.SCROLL);
}
public ScrollBar getHorizontalScroll() {
@@ -174,14 +186,7 @@ public class ScrollContainer extends WidgetContainer {
}
public int getVisibleHeight() {
if (canScrollHorizontal() && this.horizontalScrollBar.getScrollPlace() == ScrollPlace.INSIDE
&& (this.horizontalScrollBar.getOverflowType() == OverflowType.SCROLL
|| this.horizontalScrollBar.getOverflowType() == OverflowType.AUTO)) {
return this.h - this.horizontalScrollBar.getScrollbarSize();
}
return this.h;
return this.h - this.paddingBlockStart - this.paddingBlockEnd;
}
public int getActualHeight() {
@@ -190,7 +195,7 @@ public class ScrollContainer extends WidgetContainer {
public boolean setVerticalScrollOffset(int offset) {
if (!canScrollVertical() && this.h < getActualHeight()) {
if (!canScrollVertical() && getVisibleHeight() < getActualHeight()) {
offset = 0;
}
@@ -215,9 +220,9 @@ public class ScrollContainer extends WidgetContainer {
}
public boolean canScrollVertical() {
return this.verticalScrollBar != null
&& (this.verticalScrollBar.getOverflowType() != OverflowType.NONE && this.h < getActualHeight()
|| this.verticalScrollBar.getOverflowType() == OverflowType.SCROLL);
return this.verticalScrollBar != null && (this.verticalScrollBar.getOverflowType() != OverflowType.NONE
&& getVisibleHeight() < getActualHeight()
|| this.verticalScrollBar.getOverflowType() == OverflowType.SCROLL);
}
public ScrollBar getVerticalScroll() {
@@ -245,10 +250,10 @@ public class ScrollContainer extends WidgetContainer {
if (canScrollVertical || canScrollHorizontal) {
GuiHelper.useScissor(
this.x,
this.y,
getVisibleWidth(),
getVisibleHeight(),
this.x + this.paddingInlineStart,
this.y + this.paddingBlockStart,
this.w - this.paddingInlineStart - this.paddingInlineEnd,
this.h - this.paddingBlockStart - this.paddingBlockEnd,
() -> drawContent(mousex, mousey));
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
@@ -288,19 +293,22 @@ public class ScrollContainer extends WidgetContainer {
this.actualHeight = 0;
this.actualWidth = 0;
for (Map.Entry<Widget, Point> entry : this.relativePostion.entrySet()) {
for (Map.Entry<Widget, Point> entry : this.relativePosition.entrySet()) {
entry.getKey().x = entry.getValue().x;
entry.getKey().y = entry.getValue().y;
}
super.update();
for (Widget widget : this.widgets) {
this.actualWidth = Math.max(this.actualWidth, widget.x + widget.w + this.marginInline * 2);
this.actualHeight = Math.max(this.actualHeight, widget.y + widget.h + this.marginBlock * 2);
final int x = this.x + this.paddingInlineStart - this.xScroll;
final int y = this.y + this.paddingBlockStart - this.yScroll;
widget.x += this.marginInline + this.x - this.xScroll;
widget.y += this.marginBlock + this.y - this.yScroll;
for (Widget widget : this.widgets) {
this.actualWidth = Math.max(this.actualWidth, widget.x + widget.w);
this.actualHeight = Math.max(this.actualHeight, widget.y + widget.h);
widget.x += x;
widget.y += y;
}
if (this.fade > 0) {
@@ -395,6 +403,10 @@ public class ScrollContainer extends WidgetContainer {
@Override
public boolean handleKeyPress(int keyCode, char keyChar) {
if (super.handleKeyPress(keyCode, keyChar)) {
return true;
}
if (this.isFocused()) {
switch (keyCode) {
case Keyboard.KEY_UP:
@@ -412,7 +424,7 @@ public class ScrollContainer extends WidgetContainer {
}
}
return super.handleKeyPress(keyCode, keyChar);
return false;
}
}
@@ -0,0 +1,141 @@
package codechicken.nei.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import codechicken.nei.NEIServerUtils;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
public class FavoriteStorage {
protected final Map<NBTTagCompound, RecipeId> itemStackToRecipeId = new HashMap<>();
protected final Map<RecipeId, NBTTagCompound> recipeIdToItemStack = new HashMap<>();
protected final Map<Fluid, RecipeId> fluidToRecipeId = new IdentityHashMap<>();
protected final Map<Long, RecipeId> itemHashToRecipeId = new HashMap<>();
protected final Map<RecipeId, Long> recipeIdToItemHash = new HashMap<>();
protected final Map<Long, ItemStack> itemHashToItemStack = new HashMap<>();
public void clear() {
this.itemStackToRecipeId.clear();
this.fluidToRecipeId.clear();
this.recipeIdToItemStack.clear();
this.itemHashToRecipeId.clear();
this.recipeIdToItemHash.clear();
this.itemHashToItemStack.clear();
}
public int size() {
return this.itemStackToRecipeId.size() + this.itemHashToRecipeId.size();
}
public void removeItemStack(ItemStack stack) {
final RecipeId recipeId = getRecipeId(stack);
if (recipeId != null) {
removeRecipeId(recipeId);
}
}
public void removeRecipeId(RecipeId recipeId) {
this.recipeIdToItemStack.remove(recipeId);
this.fluidToRecipeId.values().removeIf(recipeId::equals);
this.itemStackToRecipeId.values().removeIf(recipeId::equals);
this.itemHashToRecipeId.values().removeIf(recipeId::equals);
this.itemHashToItemStack.remove(this.recipeIdToItemHash.get(recipeId));
this.recipeIdToItemHash.remove(recipeId);
}
public void add(ItemStack stack, RecipeId recipeId) {
if (!stack.hasTagCompound() || NEIServerUtils.isItemTool(stack)) {
long key = getItemKey(stack);
this.itemHashToRecipeId.put(key, recipeId);
this.recipeIdToItemHash.put(recipeId, key);
this.itemHashToItemStack.put(key, stack);
} else {
final NBTTagCompound itemStackNBT = StackInfo.itemStackToNBT(stack, false);
final Fluid fluidKey = getFluidKey(stack);
if (fluidKey != null) {
this.fluidToRecipeId.put(fluidKey, recipeId);
}
this.itemStackToRecipeId.put(itemStackNBT, recipeId);
this.recipeIdToItemStack.put(recipeId, itemStackNBT);
}
}
private long getItemKey(ItemStack stack) {
return ((long) Item.getIdFromItem(stack.getItem()) << 32) | (stack.getItemDamage() & 0xFFFFFFFFL);
}
private Fluid getFluidKey(ItemStack stack) {
final FluidStack fluid = StackInfo.getFluid(stack);
if (fluid != null) {
return fluid.getFluid();
}
return null;
}
public RecipeId getRecipeId(ItemStack stack) {
RecipeId recipeId = this.itemHashToRecipeId.get(getItemKey(stack));
if (recipeId == null) {
recipeId = this.itemStackToRecipeId.get(StackInfo.itemStackToNBT(stack, false));
}
if (recipeId == null) {
recipeId = this.fluidToRecipeId.get(getFluidKey(stack));
}
return recipeId;
}
public ItemStack getItemStack(RecipeId recipeId) {
NBTTagCompound itemStackNBT = this.recipeIdToItemStack.get(recipeId);
if (itemStackNBT == null) {
final Long key = this.recipeIdToItemHash.get(recipeId);
if (key != null) {
return this.itemHashToItemStack.get(key);
}
}
if (itemStackNBT != null) {
return StackInfo.loadFromNBT(itemStackNBT);
}
return null;
}
public boolean contains(ItemStack stack) {
return getRecipeId(stack) != null;
}
public List<Map.Entry<NBTTagCompound, RecipeId>> getAllFavorites() {
final List<Map.Entry<NBTTagCompound, RecipeId>> entries = new ArrayList<>(this.itemStackToRecipeId.entrySet());
for (Map.Entry<Long, RecipeId> entry : this.itemHashToRecipeId.entrySet()) {
final ItemStack stack = this.itemHashToItemStack.get(entry.getKey());
if (stack != null) {
entries.add(new HashMap.SimpleEntry<>(StackInfo.itemStackToNBT(stack, false), entry.getValue()));
}
}
return entries;
}
}
@@ -131,10 +131,6 @@ public class ItemUntranslator {
private final Map<String, String> secondNames = new HashMap<>();
private final Map<String, String> processedNames = new HashMap<>();
static {
API.addSubset("Untranslated", item -> instance.getItemStackDisplayName(item).isEmpty());
}
private ItemUntranslator() {}
public static ItemUntranslator getInstance() {
@@ -363,12 +359,14 @@ public class ItemUntranslator {
this.secondNames.clear();
LanguageRegistryPatch.secondLanguageListCache = null;
this.processedNames.clear();
SubsetWidget.removeTag("Untranslated");
}
public void load() {
unload();
this.secondNames.clear();
LanguageRegistryPatch.secondLanguageListCache = null;
this.processedNames.clear();
if (ClientHandler.loadSettingsFile(CONFIG_FILE, null, this::parseStream)
|| ClientHandler.loadSettingsResource(CONFIG_FILE, this::parseStream)) {
@@ -380,7 +378,7 @@ public class ItemUntranslator {
this.secondNames.clear();
}
SubsetWidget.updateHiddenItems();
API.addSubset("Untranslated", item -> instance.getItemStackDisplayName(item).isEmpty());
}
private void parseStream(Stream<String> lines) {
@@ -0,0 +1,5 @@
# This file contains a list of GUIs that can use the DefaultBookmarkContainerHandler for bookmarks.
# It serves as an alternative to API.registerBookmarkContainerHandler and is intended for cases
# where you can't modify the mod itself and its GUI doesn't have custom slots.
# Each line in this file should either be a comment (starting with '#') or a guiContainer class name.
# If you delete this file, it will be regenerated with the default bookmark containers list.
@@ -1,4 +1,5 @@
# Each line in this file should either be a comment (line starts with '#'), handler name or handler id.
# This file contains a list of GUIs for which craftable item panels will not work.
# Each line in this file should either be a comment (line starts with '#'), or guiContainer class name.
# If you delete this file, it will be regenerated with the default handlers list.
appeng.client.gui.implementations.GuiPatternTerm
appeng.client.gui.implementations.GuiPatternTermEx
+10 -17
View File
@@ -1,11 +1,4 @@
handler,modName,itemName,nbtInfo,modId,modRequired,excludedModId,yShift,handlerHeight,handlerWidth,maxRecipesPerPage,imageResource,imageX,imageY,imageWidth,imageHeight,itemNotes,useCustomScroll
codechicken.nei.recipe.BrewingRecipeHandler,Minecraft,minecraft:brewing_stand,,minecraft,FALSE,,,65,166,5,,,,,,,
codechicken.nei.recipe.FireworkRecipeHandler,Minecraft,minecraft:fireworks,,minecraft,FALSE,,,65,166,5,,,,,,,
codechicken.nei.recipe.FurnaceRecipeHandler,Minecraft,minecraft:furnace,,minecraft,FALSE,,,65,166,5,,,,,,,
codechicken.nei.recipe.ShapedRecipeHandler,Minecraft,minecraft:crafting_table,,minecraft,FALSE,,,65,166,5,,,,,,,
codechicken.nei.recipe.ShapelessRecipeHandler,Minecraft,minecraft:crafting_table,,minecraft,FALSE,,,65,166,5,,,,,,,
codechicken.nei.recipe.FuelRecipeHandler,Minecraft,,,minecraft,FALSE,,,65,166,5,nei:textures/nei_tabbed_sprites.png,80,0,14,14,,
codechicken.nei.recipe.InformationHandler,Not Enough Items,,,nei,FALSE,,,65,166,1,nei:textures/nei_tabbed_sprites.png,96,0,16,16,,
advsolar.client.nei.MTRecipeHandler,Advanced Solar Panels,AdvancedSolarPanel:BlockMolecularTransformer,,AdvancedSolarPanel,TRUE,,,68,,5,,,,,,,
appeng.integration.modules.NEIHelpers.NEIAEShapedRecipeHandler,Applied Energistics 2,appliedenergistics2:item.ItemMultiPart:380,,appliedenergistics2,TRUE,,,65,,5,,,,,,,
appeng.integration.modules.NEIHelpers.NEIAEShapelessRecipeHandler,Applied Energistics 2,appliedenergistics2:item.ItemMultiPart:380,,appliedenergistics2,TRUE,,,65,,5,,,,,,,
@@ -13,8 +6,8 @@ appeng.integration.modules.NEIHelpers.NEIFacadeRecipeHandler,Applied Energistics
appeng.integration.modules.NEIHelpers.NEIGrinderRecipeHandler,Applied Energistics 2,appliedenergistics2:tile.BlockGrinder,,appliedenergistics2,TRUE,,,,,,,,,,,,
appeng.integration.modules.NEIHelpers.NEIInscriberRecipeHandler,Applied Energistics 2,appliedenergistics2:tile.BlockInscriber,,appliedenergistics2,TRUE,,,70,,5,,,,,,,
appeng.integration.modules.NEIHelpers.NEIWorldCraftingHandler,Applied Energistics 2,appliedenergistics2:item.ItemMultiMaterial:9,,appliedenergistics2,TRUE,,,85,,5,,,,,,There's only some explanatory text for fluix crystals and QEDs,
appeng.integration.modules.NEIHelpers.NEICellViewHandler,Applied Energistics 2,appliedenergistics2:item.ItemBasicStorageCell.64k,,appliedenergistics2,TRUE,,,180,,1,,,,,,,,
com.glodblock.github.nei.NEICellViewHandler,AE2 Fluid Crafting,ae2fc:multi_fluid_storage64,,ae2fc,TRUE,,,,,1,,,,,,,,
appeng.integration.modules.NEIHelpers.NEICellViewHandler,Applied Energistics 2,appliedenergistics2:item.ItemBasicStorageCell.64k,,appliedenergistics2,TRUE,,,180,,1,,,,,,,
com.glodblock.github.nei.NEICellViewHandler,AE2 Fluid Crafting,ae2fc:multi_fluid_storage64,,ae2fc,TRUE,,,,,1,,,,,,,
aroma1997.core.recipes.nei.ShapedAromicRecipeHandler,AromaBackup,minecraft:crafting_table,,AromaBackup,TRUE,,,65,,5,,,,,,,
aroma1997.core.recipes.nei.ShapelessAromicRecipeHandler,AromaBackup,minecraft:crafting_table,,AromaBackup,TRUE,,,,,,,,,,,,
fox.spiteful.avaritia.compat.nei.CompressionHandler,Avaritia,Avaritia:Neutronium_Compressor,,Avaritia,TRUE,,,50,,6,,,,,,,
@@ -95,7 +88,7 @@ gt.recipe.alloysmelter,GregTech,gregtech:gt.blockmachines:201,,gregtech,TRUE,gre
gt.recipe.arcfurnace,GregTech,gregtech:gt.blockmachines:651,,gregtech,TRUE,gregapi_post,6,135,166,2,,,,,,,
gt.recipe.assembler,GregTech,gregtech:gt.blockmachines:211,,gregtech,TRUE,gregapi_post,6,145,166,2,,,,,,,
gt.recipe.autoclave,GregTech,gregtech:gt.blockmachines:571,,gregtech,TRUE,gregapi_post,6,135,166,2,,,,,,,
gt.recipe.blastfurnace,GregTech,gregtech:gt.blockmachines:1000,,gregtech,TRUE,gregapi_post,6,135,166,2,,,,,,,
gt.recipe.blastfurnace,GregTech,gregtech:gt.blockmachines:1000,,gregtech,TRUE,gregapi_post,6,135,166,2,nei:textures/multiblocks/electric_blast_furnace.png,80,0,14,18,,
gt.recipe.brewer,GregTech,gregtech:gt.blockmachines:491,,gregtech,TRUE,gregapi_post,6,135,166,2,,,,,,,
gt.recipe.byproductlist,GregTech,gregtech:gt.metaitem.01:2019,,gregtech,TRUE,gregapi_post,6,135,166,2,,,,,,,
gt.recipe.canner,GregTech,gregtech:gt.blockmachines:231,,gregtech,TRUE,gregapi_post,6,135,166,2,,,,,,,
@@ -161,7 +154,7 @@ gt.recipe.thermalcentrifuge,GregTech,gregtech:gt.blockmachines:381,,gregtech,TRU
gt.recipe.thermalgeneratorfuel,GregTech,IC2:blockGenerator:1,,gregtech,TRUE,gregapi_post,6,135,166,2,,,,,,,
gt.recipe.unpackager,GregTech,gregtech:gt.blockmachines:411,,gregtech,TRUE,gregapi_post,6,135,166,2,,,,,,,
gt.recipe.uuamplifier,GregTech,gregtech:gt.blockmachines:471,,gregtech,TRUE,gregapi_post,6,135,166,2,,,,,,,
gt.recipe.vacuumfreezer,GregTech,gregtech:gt.blockmachines:1002,,gregtech,TRUE,gregapi_post,6,135,166,2,,,,,,,
gt.recipe.vacuumfreezer,GregTech,gregtech:gt.blockmachines:1002,,gregtech,TRUE,gregapi_post,6,135,166,2,nei:textures/multiblocks/vacuum_freezer.png,80,0,12,12,,
gt.recipe.wiremill,GregTech,gregtech:gt.blockmachines:351,,gregtech,TRUE,gregapi_post,6,135,166,2,,,,,,,
ic.recipe.recycler,GregTech,gregtech:gt.blockmachines:331,,gregtech,TRUE,gregapi_post,6,135,166,2,,,,,,,
pers.gwyog.gtneioreplugin.plugin.gregtech5.PluginGT5SmallOreStat,GregTech,gregtech:gt.blockores:85,,gregtech,TRUE,,,145,,2,,,,,,,
@@ -358,7 +351,7 @@ vazkii.botania.client.integration.nei.recipe.RecipeHandlerRunicAltar,Botania,Bot
vazkii.botania.client.integration.nei.recipe.RecipeHandlerManaPool,Botania,Botania:pool,,Botania,TRUE,,,90,137,4,,,,,,,
vazkii.botania.client.integration.nei.recipe.RecipeHandlerElvenTrade,Botania,Botania:alfheimPortal,,Botania,TRUE,,,90,130,4,,,,,,,
vazkii.botania.client.integration.nei.recipe.RecipeHandlerBrewery,Botania,Botania:brewery,,Botania,TRUE,,,,,4,,,,,,,
vazkii.botania.client.integration.nei.recipe.RecipeHandlerPureDaisy,Botania,Botania:specialFlower,"{type:puredaisy}",Botania,TRUE,,,,,4,,,,,,,
vazkii.botania.client.integration.nei.recipe.RecipeHandlerPureDaisy,Botania,Botania:specialFlower,{type:puredaisy},Botania,TRUE,,,,,4,,,,,,,
vazkii.botania.client.integration.nei.recipe.RecipeHandlerLexicaBotania,Botania,Botania:lexicon,,Botania,TRUE,,,,,,,,,,,,
com.jaquadro.minecraft.storagedrawers.integration.notenoughitems.UpgradeItemRecipeHandler,Storage Drawers,minecraft:crafting_table,,StorageDrawers,TRUE,,,65,166,5,,,,,,,
ieArcFurnace,Immersive Engineering,ImmersiveEngineering:graphiteElectrode,,ImmersiveEngineering,TRUE,,,65,166,5,,,,,,,
@@ -535,7 +528,7 @@ vazkii.botania.client.integration.nei.RecipeHandlerRunicAltar,Botania,Botania:ru
vazkii.botania.client.integration.nei.RecipeHandlerManaPool,Botania,Botania:pool,,Botania,TRUE,,,90,137,4,,,,,,,
vazkii.botania.client.integration.nei.RecipeHandlerElvenTrade,Botania,Botania:alfheimPortal,,Botania,TRUE,,,90,130,4,,,,,,,
vazkii.botania.client.integration.nei.RecipeHandlerBrewery,Botania,Botania:brewery,,Botania,TRUE,,,,,4,,,,,,,
vazkii.botania.client.integration.nei.RecipeHandlerPureDaisy,Botania,Botania:specialFlower,"{type:puredaisy}",Botania,TRUE,,,,,4,,,,,,,
vazkii.botania.client.integration.nei.RecipeHandlerPureDaisy,Botania,Botania:specialFlower,{type:puredaisy},Botania,TRUE,,,,,4,,,,,,,
vazkii.botania.client.integration.nei.RecipeHandlerLexicaBotania,Botania,Botania:lexicon,,Botania,TRUE,,,,,,,,,,,,
neiplugins.forge.OreDictionaryList,NEIPlugins,minecraft:book,,NEIPlugins,TRUE,,,,,,,,,,,,
neiplugins.forge.FluidRegistryList,NEIPlugins,minecraft:bucket,,NEIPlugins,TRUE,,,,,,,,,,,,
@@ -611,7 +604,7 @@ com.cout970.magneticraft.compat.nei.CraftingGrinder,Magneticraft,Magneticraft:gr
com.cout970.magneticraft.compat.nei.CraftingPolymerizer,Magneticraft,Magneticraft:polimerizer_control,,Magneticraft,TRUE,,,,,,,,,,,,
com.cout970.magneticraft.compat.nei.CraftingBiomassBurner,Magneticraft,Magneticraft:biomassburner,,Magneticraft,TRUE,,,,,,,,,,,,
com.cout970.magneticraft.compat.nei.CraftingSifter,Magneticraft,Magneticraft:sifter_control,,Magneticraft,TRUE,,,,,,,,,,,,
pneumaticCraft.common.thirdparty.nei.NEIRefineryManager,PneumaticCraft,PneumaticCraft:refinery,,PneumaticCraft,TRUE,,"",80,,4,,,,,,,
pneumaticCraft.common.thirdparty.nei.NEIRefineryManager,PneumaticCraft,PneumaticCraft:refinery,,PneumaticCraft,TRUE,,,80,,4,,,,,,,
pneumaticCraft.common.thirdparty.nei.NEIPlasticMixerManager,PneumaticCraft,PneumaticCraft:plasticMixer,,PneumaticCraft,TRUE,,,,,,,,,,,,
pneumaticCraft.common.thirdparty.nei.NEIAmadronTradeManager,PneumaticCraft,PneumaticCraft:amadronTablet,,PneumaticCraft,TRUE,,,,,,,,,,,,
pneumaticCraft.common.thirdparty.nei.NEIUVLightBoxManager,PneumaticCraft,PneumaticCraft:uvLightBox,,PneumaticCraft,TRUE,,,,,,,,,,,,
@@ -621,7 +614,7 @@ pneumaticCraft.common.thirdparty.nei.NEIAssemblyControllerRecipeManager,Pneumati
pneumaticCraft.common.thirdparty.nei.NEIPressureChamberRecipeManager,PneumaticCraft,PneumaticCraft:pressureChamberInterface,,PneumaticCraft,TRUE,,,130,,2,,,,,,,
exter.foundry.integration.nei.InductionCrucibleFurnaceRecipeHandler,Foundry,foundry:foundryMachine:0,,foundry,TRUE,,,,,,,,,,,,
exter.foundry.integration.nei.AlloyMixerRecipeHandler,Foundry,foundry:foundryMachine:2,,foundry,TRUE,,,,,,,,,,,,
exter.foundry.integration.nei.MetalCasterRecipeHandler,Foundry,foundry:foundryMachine:1,"",foundry,TRUE,,,,,,,,,,,,
exter.foundry.integration.nei.MetalCasterRecipeHandler,Foundry,foundry:foundryMachine:1,,foundry,TRUE,,,,,,,,,,,,
exter.foundry.integration.nei.InfuserRecipeHandler,Foundry,foundry:foundryMachine:3,,foundry,TRUE,,,,,,,,,,,,
exter.foundry.integration.nei.InfuserSubstanceRecipeHandler,Foundry,foundry:foundryMachine:3,,foundry,TRUE,,,,,,,,,,,,
exter.foundry.integration.nei.AlloyFurnaceRecipeHandler,Foundry,foundry:alloyFurnace,,foundry,TRUE,,,,,,,,,,,,
@@ -633,7 +626,7 @@ net.dries007.tfcnei.recipeHandlers.LoomRecipeHandler,TerraFirmaCraft,terrafirmac
net.dries007.tfcnei.recipeHandlers.KnappingRecipeHandler,TerraFirmaCraft,terrafirmacraft:item.LooseRock,,terrafirmacraft,TRUE,,,96,166,3,,,,,,,
net.dries007.tfcnei.recipeHandlers.BarrelRecipeHandler,TerraFirmaCraft,terrafirmacraft:Barrel,,terrafirmacraft,TRUE,,,65,166,5,,,,,,,
net.dries007.tfcnei.recipeHandlers.AlloyRecipeHandler,TerraFirmaCraft,terrafirmacraft:Crucible,,terrafirmacraft,TRUE,,,65,166,5,,,,,,,
net.dries007.tfcnei.recipeHandlers.HeatRecipeHandler,TerraFirmaCraft,terrafirmacraft:Firepit,,terrafirmacraft,TRUE,,,65,166,5,"",,,,,,
net.dries007.tfcnei.recipeHandlers.HeatRecipeHandler,TerraFirmaCraft,terrafirmacraft:Firepit,,terrafirmacraft,TRUE,,,65,166,5,,,,,,,
techreborn.compat.nei.FustionReacorRecipeHandler,TechReborn,techreborn:fusioncontrolcomputer,,techreborn,TRUE,,,,,,,,,,,,
techreborn.compat.nei.recipes.VacuumFreezerRecipeHandler,TechReborn,techreborn:vacuumfreezer,,techreborn,TRUE,,,,,,,,,,,,
techreborn.compat.nei.recipes.ImplosionCompressorRecipeHandler,TechReborn,techreborn:implosioncompressor,,techreborn,TRUE,,,,,,,,,,,,
@@ -656,4 +649,4 @@ straywolfe.cookingwithtfc.client.nei.CookingPotRecipeHandler,Cooking with TFC,co
straywolfe.cookingwithtfc.client.nei.ClayOvenRecipeHandler,Cooking with TFC,cookingwithtfc:item.clayOvenWall,,cookingwithtfc,TRUE,,,,,,,,,,,,
factorization.nei.RecipeMixer,Factorization,factorization:FzBlock:18,,factorization,TRUE,,,,,,,,,,,,
ua.pp.shurgent.tfctech.nei.WireDrawBenchRecipeHandler,Shurgent's TFCTech Addon,tfctech:item.Wire Draw Bench,,tfctech,TRUE,,,,,,,,,,,,
mekanism.client.nei.ElectrolyticSeparatorRecipeHandler,Mekanism,Mekanism:MachineBlock2:4,,Mekanism,TRUE,,,,,,,,,,,,
mekanism.client.nei.ElectrolyticSeparatorRecipeHandler,Mekanism,Mekanism:MachineBlock2:4,,Mekanism,TRUE,,,,,,,,,,,,
1 handler modName itemName nbtInfo modId modRequired excludedModId yShift handlerHeight handlerWidth maxRecipesPerPage imageResource imageX imageY imageWidth imageHeight itemNotes useCustomScroll
codechicken.nei.recipe.BrewingRecipeHandler Minecraft minecraft:brewing_stand minecraft FALSE 65 166 5
codechicken.nei.recipe.FireworkRecipeHandler Minecraft minecraft:fireworks minecraft FALSE 65 166 5
codechicken.nei.recipe.FurnaceRecipeHandler Minecraft minecraft:furnace minecraft FALSE 65 166 5
codechicken.nei.recipe.ShapedRecipeHandler Minecraft minecraft:crafting_table minecraft FALSE 65 166 5
codechicken.nei.recipe.ShapelessRecipeHandler Minecraft minecraft:crafting_table minecraft FALSE 65 166 5
codechicken.nei.recipe.FuelRecipeHandler Minecraft minecraft FALSE 65 166 5 nei:textures/nei_tabbed_sprites.png 80 0 14 14
codechicken.nei.recipe.InformationHandler Not Enough Items nei FALSE 65 166 1 nei:textures/nei_tabbed_sprites.png 96 0 16 16
2 advsolar.client.nei.MTRecipeHandler Advanced Solar Panels AdvancedSolarPanel:BlockMolecularTransformer AdvancedSolarPanel TRUE 68 5
3 appeng.integration.modules.NEIHelpers.NEIAEShapedRecipeHandler Applied Energistics 2 appliedenergistics2:item.ItemMultiPart:380 appliedenergistics2 TRUE 65 5
4 appeng.integration.modules.NEIHelpers.NEIAEShapelessRecipeHandler Applied Energistics 2 appliedenergistics2:item.ItemMultiPart:380 appliedenergistics2 TRUE 65 5
6 appeng.integration.modules.NEIHelpers.NEIGrinderRecipeHandler Applied Energistics 2 appliedenergistics2:tile.BlockGrinder appliedenergistics2 TRUE
7 appeng.integration.modules.NEIHelpers.NEIInscriberRecipeHandler Applied Energistics 2 appliedenergistics2:tile.BlockInscriber appliedenergistics2 TRUE 70 5
8 appeng.integration.modules.NEIHelpers.NEIWorldCraftingHandler Applied Energistics 2 appliedenergistics2:item.ItemMultiMaterial:9 appliedenergistics2 TRUE 85 5 There's only some explanatory text for fluix crystals and QEDs
9 appeng.integration.modules.NEIHelpers.NEICellViewHandler Applied Energistics 2 appliedenergistics2:item.ItemBasicStorageCell.64k appliedenergistics2 TRUE 180 1
10 com.glodblock.github.nei.NEICellViewHandler AE2 Fluid Crafting ae2fc:multi_fluid_storage64 ae2fc TRUE 1
11 aroma1997.core.recipes.nei.ShapedAromicRecipeHandler AromaBackup minecraft:crafting_table AromaBackup TRUE 65 5
12 aroma1997.core.recipes.nei.ShapelessAromicRecipeHandler AromaBackup minecraft:crafting_table AromaBackup TRUE
13 fox.spiteful.avaritia.compat.nei.CompressionHandler Avaritia Avaritia:Neutronium_Compressor Avaritia TRUE 50 6
88 gt.recipe.arcfurnace GregTech gregtech:gt.blockmachines:651 gregtech TRUE gregapi_post 6 135 166 2
89 gt.recipe.assembler GregTech gregtech:gt.blockmachines:211 gregtech TRUE gregapi_post 6 145 166 2
90 gt.recipe.autoclave GregTech gregtech:gt.blockmachines:571 gregtech TRUE gregapi_post 6 135 166 2
91 gt.recipe.blastfurnace GregTech gregtech:gt.blockmachines:1000 gregtech TRUE gregapi_post 6 135 166 2 nei:textures/multiblocks/electric_blast_furnace.png 80 0 14 18
92 gt.recipe.brewer GregTech gregtech:gt.blockmachines:491 gregtech TRUE gregapi_post 6 135 166 2
93 gt.recipe.byproductlist GregTech gregtech:gt.metaitem.01:2019 gregtech TRUE gregapi_post 6 135 166 2
94 gt.recipe.canner GregTech gregtech:gt.blockmachines:231 gregtech TRUE gregapi_post 6 135 166 2
154 gt.recipe.thermalgeneratorfuel GregTech IC2:blockGenerator:1 gregtech TRUE gregapi_post 6 135 166 2
155 gt.recipe.unpackager GregTech gregtech:gt.blockmachines:411 gregtech TRUE gregapi_post 6 135 166 2
156 gt.recipe.uuamplifier GregTech gregtech:gt.blockmachines:471 gregtech TRUE gregapi_post 6 135 166 2
157 gt.recipe.vacuumfreezer GregTech gregtech:gt.blockmachines:1002 gregtech TRUE gregapi_post 6 135 166 2 nei:textures/multiblocks/vacuum_freezer.png 80 0 12 12
158 gt.recipe.wiremill GregTech gregtech:gt.blockmachines:351 gregtech TRUE gregapi_post 6 135 166 2
159 ic.recipe.recycler GregTech gregtech:gt.blockmachines:331 gregtech TRUE gregapi_post 6 135 166 2
160 pers.gwyog.gtneioreplugin.plugin.gregtech5.PluginGT5SmallOreStat GregTech gregtech:gt.blockores:85 gregtech TRUE 145 2
351 vazkii.botania.client.integration.nei.recipe.RecipeHandlerManaPool Botania Botania:pool Botania TRUE 90 137 4
352 vazkii.botania.client.integration.nei.recipe.RecipeHandlerElvenTrade Botania Botania:alfheimPortal Botania TRUE 90 130 4
353 vazkii.botania.client.integration.nei.recipe.RecipeHandlerBrewery Botania Botania:brewery Botania TRUE 4
354 vazkii.botania.client.integration.nei.recipe.RecipeHandlerPureDaisy Botania Botania:specialFlower {type:puredaisy} Botania TRUE 4
355 vazkii.botania.client.integration.nei.recipe.RecipeHandlerLexicaBotania Botania Botania:lexicon Botania TRUE
356 com.jaquadro.minecraft.storagedrawers.integration.notenoughitems.UpgradeItemRecipeHandler Storage Drawers minecraft:crafting_table StorageDrawers TRUE 65 166 5
357 ieArcFurnace Immersive Engineering ImmersiveEngineering:graphiteElectrode ImmersiveEngineering TRUE 65 166 5
528 vazkii.botania.client.integration.nei.RecipeHandlerManaPool Botania Botania:pool Botania TRUE 90 137 4
529 vazkii.botania.client.integration.nei.RecipeHandlerElvenTrade Botania Botania:alfheimPortal Botania TRUE 90 130 4
530 vazkii.botania.client.integration.nei.RecipeHandlerBrewery Botania Botania:brewery Botania TRUE 4
531 vazkii.botania.client.integration.nei.RecipeHandlerPureDaisy Botania Botania:specialFlower {type:puredaisy} Botania TRUE 4
532 vazkii.botania.client.integration.nei.RecipeHandlerLexicaBotania Botania Botania:lexicon Botania TRUE
533 neiplugins.forge.OreDictionaryList NEIPlugins minecraft:book NEIPlugins TRUE
534 neiplugins.forge.FluidRegistryList NEIPlugins minecraft:bucket NEIPlugins TRUE
604 com.cout970.magneticraft.compat.nei.CraftingPolymerizer Magneticraft Magneticraft:polimerizer_control Magneticraft TRUE
605 com.cout970.magneticraft.compat.nei.CraftingBiomassBurner Magneticraft Magneticraft:biomassburner Magneticraft TRUE
606 com.cout970.magneticraft.compat.nei.CraftingSifter Magneticraft Magneticraft:sifter_control Magneticraft TRUE
607 pneumaticCraft.common.thirdparty.nei.NEIRefineryManager PneumaticCraft PneumaticCraft:refinery PneumaticCraft TRUE 80 4
608 pneumaticCraft.common.thirdparty.nei.NEIPlasticMixerManager PneumaticCraft PneumaticCraft:plasticMixer PneumaticCraft TRUE
609 pneumaticCraft.common.thirdparty.nei.NEIAmadronTradeManager PneumaticCraft PneumaticCraft:amadronTablet PneumaticCraft TRUE
610 pneumaticCraft.common.thirdparty.nei.NEIUVLightBoxManager PneumaticCraft PneumaticCraft:uvLightBox PneumaticCraft TRUE
614 pneumaticCraft.common.thirdparty.nei.NEIPressureChamberRecipeManager PneumaticCraft PneumaticCraft:pressureChamberInterface PneumaticCraft TRUE 130 2
615 exter.foundry.integration.nei.InductionCrucibleFurnaceRecipeHandler Foundry foundry:foundryMachine:0 foundry TRUE
616 exter.foundry.integration.nei.AlloyMixerRecipeHandler Foundry foundry:foundryMachine:2 foundry TRUE
617 exter.foundry.integration.nei.MetalCasterRecipeHandler Foundry foundry:foundryMachine:1 foundry TRUE
618 exter.foundry.integration.nei.InfuserRecipeHandler Foundry foundry:foundryMachine:3 foundry TRUE
619 exter.foundry.integration.nei.InfuserSubstanceRecipeHandler Foundry foundry:foundryMachine:3 foundry TRUE
620 exter.foundry.integration.nei.AlloyFurnaceRecipeHandler Foundry foundry:alloyFurnace foundry TRUE
626 net.dries007.tfcnei.recipeHandlers.KnappingRecipeHandler TerraFirmaCraft terrafirmacraft:item.LooseRock terrafirmacraft TRUE 96 166 3
627 net.dries007.tfcnei.recipeHandlers.BarrelRecipeHandler TerraFirmaCraft terrafirmacraft:Barrel terrafirmacraft TRUE 65 166 5
628 net.dries007.tfcnei.recipeHandlers.AlloyRecipeHandler TerraFirmaCraft terrafirmacraft:Crucible terrafirmacraft TRUE 65 166 5
629 net.dries007.tfcnei.recipeHandlers.HeatRecipeHandler TerraFirmaCraft terrafirmacraft:Firepit terrafirmacraft TRUE 65 166 5
630 techreborn.compat.nei.FustionReacorRecipeHandler TechReborn techreborn:fusioncontrolcomputer techreborn TRUE
631 techreborn.compat.nei.recipes.VacuumFreezerRecipeHandler TechReborn techreborn:vacuumfreezer techreborn TRUE
632 techreborn.compat.nei.recipes.ImplosionCompressorRecipeHandler TechReborn techreborn:implosioncompressor techreborn TRUE
649 straywolfe.cookingwithtfc.client.nei.ClayOvenRecipeHandler Cooking with TFC cookingwithtfc:item.clayOvenWall cookingwithtfc TRUE
650 factorization.nei.RecipeMixer Factorization factorization:FzBlock:18 factorization TRUE
651 ua.pp.shurgent.tfctech.nei.WireDrawBenchRecipeHandler Shurgent's TFCTech Addon tfctech:item.Wire Draw Bench tfctech TRUE
652 mekanism.client.nei.ElectrolyticSeparatorRecipeHandler Mekanism Mekanism:MachineBlock2:4 Mekanism TRUE
+42 -2
View File
@@ -47,6 +47,7 @@ nei.bookmark.crafting_chain.input=Ingredients
nei.bookmark.crafting_chain.missing=Missing Items
nei.bookmark.crafting_chain.output=Results
nei.bookmark.crafting_chain.remainder=Remainders
nei.bookmark.crafting_chain.needed=Required Crafts
nei.bookmark.crafting_chain.available=Available Items
nei.inventory.search.placeholder=Search...
nei.itempanel.quantity.default=One stack
@@ -63,6 +64,7 @@ nei.itempanel.fill_crafting_grid=Fill Crafting Grid
nei.itempanel.fill_crafting_grid_quantity=Fill Crafting Grid With Quantity
nei.itempanel.open_crafting=Recipe to make this item
nei.itempanel.open_usage=Recipes that use this item
nei.itempanel.infinite_item=Give Infinite Item
nei.itempanel.copy_name=Copy Item Name
nei.itempanel.copy_oredict=Copy Item OreDictionary
nei.itempanel.copy_id=Copy Item ID
@@ -200,6 +202,7 @@ nei.options.keys.gui.itemzoom_hold=Hold to Display Item Zoom
nei.options.keys.gui.itemzoom_zoom_in=Item Zoom In
nei.options.keys.gui.itemzoom_zoom_out=Item Zoom Out
nei.options.keys.gui.favorite=Add Favorite
nei.options.keys.gui.favorite_item=Toggle Favorite
nei.options.keys.world=World
nei.options.keys.world.chunkoverlay=Chunk Boundary Overlay
nei.options.keys.world.moboverlay=Mob Spawn Overlay
@@ -247,6 +250,9 @@ nei.options.inventory.bookmarks.worldSpecific.false=No
nei.options.inventory.bookmarks.bookmarkItemsWithRecipe=Bookmark items with recipe
nei.options.inventory.bookmarks.bookmarkItemsWithRecipe.true=Yes
nei.options.inventory.bookmarks.bookmarkItemsWithRecipe.false=No
nei.options.inventory.bookmarks.bookmarkRecipeWithCount=Bookmark recipe with count
nei.options.inventory.bookmarks.bookmarkRecipeWithCount.true=Yes
nei.options.inventory.bookmarks.bookmarkRecipeWithCount.false=No
nei.options.inventory.favorites=Favorites
nei.options.inventory.favorites.enabled=Visibility
nei.options.inventory.favorites.enabled.true=Visible
@@ -261,6 +267,9 @@ nei.options.inventory.favorites.showRecipeTooltipInGui=Show Recipe Tooltips in R
nei.options.inventory.favorites.showRecipeTooltipInGui.true=Yes
nei.options.inventory.favorites.showRecipeTooltipInGui.false=No
nei.options.inventory.favorites.depth=Depth
nei.options.inventory.favorites.generateSingleRecipeFavorites=Generate Single-Recipe Favorites
nei.options.inventory.favorites.generateSingleRecipeFavorites.true=Yes
nei.options.inventory.favorites.generateSingleRecipeFavorites.false=No
nei.options.inventory.hotkeysHelpText=Show Hotkeys Help Text
nei.options.inventory.hotkeysHelpText.true=Yes
nei.options.inventory.hotkeysHelpText.false=No
@@ -282,12 +291,14 @@ nei.options.inventory.guirecipe.infiniteScroll=Use Infinite Scroll
nei.options.inventory.guirecipe.infiniteScroll.true=Yes
nei.options.inventory.guirecipe.infiniteScroll.false=No
nei.options.inventory.guirecipe.jeiStyleRecipeCatalyst=JEI Style Recipe Catalysts
nei.options.inventory.guirecipe.jeiStyleRecipeCatalyst.true=Yes
nei.options.inventory.guirecipe.jeiStyleRecipeCatalyst.false=No
nei.options.inventory.guirecipe.jeiStyleRecipeCatalyst.0=None
nei.options.inventory.guirecipe.jeiStyleRecipeCatalyst.1=Grid
nei.options.inventory.guirecipe.jeiStyleRecipeCatalyst.2=Scroll
nei.options.inventory.guirecipe.cycledIngredientsTooltip=Cycled Ingredients Tooltip
nei.options.inventory.guirecipe.cycledIngredientsTooltip.true=Show
nei.options.inventory.guirecipe.cycledIngredientsTooltip.false=Hide
nei.options.inventory.guirecipe.handlerInfo=Handler Info Widget
nei.options.inventory.guirecipe.handlerInfo.tip=Use shift+d while in the Recipes GUI
nei.options.inventory.guirecipe.handlerInfo.true=Enabled
nei.options.inventory.guirecipe.handlerInfo.false=Disabled
nei.options.inventory.guirecipe.maxHeight=Max Height
@@ -417,6 +428,9 @@ nei.options.inventory.craftables.enabled.true=Enabled
nei.options.inventory.craftables.enabled.false=Disabled
nei.options.inventory.craftables.color=Color
nei.options.inventory.craftables.useRows=Rows
nei.options.inventory.craftables.favoritesOnly=Show Favorites Only
nei.options.inventory.craftables.favoritesOnly.true=Yes
nei.options.inventory.craftables.favoritesOnly.false=No
nei.options.inventory.subsets=Subsets Widget
nei.options.inventory.subsets.enabled=Subsets Visibility
nei.options.inventory.subsets.enabled.true=Enabled
@@ -510,8 +524,31 @@ nei.options.tools.dump.handlers.dumped=handlers were dumped to %s
nei.options.tools.dump.handlers.mode.0=CSV
nei.options.tools.dump.handlers.mode.1=Json
nei.debug.RecipeHandler.title=Debug Recipe Handler
nei.debug.RecipeHandler.copy=Copy
nei.debug.RecipeHandler.Name=Name
nei.debug.RecipeHandler.Id=ID
nei.debug.RecipeHandler.Key=Key
nei.debug.RecipeHandler.HHack=H.Hack
nei.debug.RecipeHandler.ModName=Mod Name
nei.debug.RecipeHandler.ModId=Mod ID
nei.debug.RecipeHandler.Order=Order
nei.debug.RecipeHandler.yShift=yShift
nei.debug.RecipeHandler.MultiWidgets=Multi Widgets
nei.debug.RecipeHandler.Height=Height
nei.debug.RecipeHandler.Width=Width
nei.debug.RecipeHandler.ShowFavorites=Show Favorites
nei.debug.RecipeHandler.ShowOverlay=Show Overlays
nei.debug.RecipeHandler.UseCustomScroll=Use Custom Scroll
nei.debug.RecipeHandler.Override=Override
nei.debug.RecipeHandler.checkbox.on=On
nei.debug.RecipeHandler.checkbox.off=Off
nei.debug.RecipeHandler.yes=Yes
nei.debug.RecipeHandler.no=No
nei.recipe.page=Page %s/%s
nei.recipe.tooltip=Recipes
nei.recipe.tab.view_all.tooltip=View all categories
nei.recipe.shaped=Shaped Crafting
nei.recipe.shapeless=Shapeless Crafting
nei.recipe.furnace=Smelting
@@ -527,6 +564,7 @@ nei.recipe.firework=Fireworks
nei.recipe.firework.tooltip0=Dyes add colours to the charges
nei.recipe.firework.tooltip1=Recolouring adds fade colours to the charge
nei.recipe.firework.tooltip2=Multiple charges can be spawned from one rocket
nei.recipe.repair=Repair
nei.recipe.brewing=Brewing
nei.recipe.profiler.crafting=Crafting Profiling
nei.recipe.profiler.usage=Usage Profiling
@@ -546,6 +584,7 @@ nei.recipe.overlay.bookmarkRecipeAndCount=Save with Recipe & Count
nei.recipe.favorite=Favorite
nei.recipe.favorite.bookmark_recipe=Save Recipe Tree
nei.recipe.favorite.change_result_index=Change Output
nei.recipe.favorite.toggle=Toggle Favorite
nei.recipe.information=Information
@@ -594,6 +633,7 @@ nei.subsets.Items.Tools.Shovels=Shovels
nei.subsets.Items.Weapons=Weapons
nei.subsets.Items.Weapons.Ranged=Ranged
nei.subsets.Items.Weapons.Swords=Swords
nei.subsets.Untranslated=Untranslated
nei.subsets.Mod=Mod
nei.presets.new=New Preset
@@ -199,8 +199,9 @@ nei.options.inventory.guirecipe.slotHighlightPresent=Подсвечивать п
nei.options.inventory.guirecipe.slotHighlightPresent.true=Да
nei.options.inventory.guirecipe.slotHighlightPresent.false=Нет
nei.options.inventory.guirecipe.jeiStyleRecipeCatalyst=Катализаторы рецептов в стиле JEI
nei.options.inventory.guirecipe.jeiStyleRecipeCatalyst.true=Да
nei.options.inventory.guirecipe.jeiStyleRecipeCatalyst.false=Нет
nei.options.inventory.guirecipe.jeiStyleRecipeCatalyst.0=Нет
nei.options.inventory.guirecipe.jeiStyleRecipeCatalyst.1=Грид
nei.options.inventory.guirecipe.jeiStyleRecipeCatalyst.2=Скролл
nei.options.inventory.guirecipe.cycledIngredientsTooltip=Подсказка циклических ингредиентов
nei.options.inventory.guirecipe.cycledIngredientsTooltip.true=Показывать
nei.options.inventory.guirecipe.cycledIngredientsTooltip.false=Скрыть
@@ -136,8 +136,6 @@ nei.options.inventory.guirecipe.jeiStyleTabs=JEI标签页
nei.options.inventory.guirecipe.jeiStyleTabs.true=是
nei.options.inventory.guirecipe.jeiStyleTabs.false=否 [不会吧]
nei.options.inventory.guirecipe.jeiStyleRecipeCatalyst=JEI风格可执行合成表机器显示[测试中]
nei.options.inventory.guirecipe.jeiStyleRecipeCatalyst.true=是
nei.options.inventory.guirecipe.jeiStyleRecipeCatalyst.false=否
nei.options.inventory.bookmarks.animation=REI风格书签动画
nei.options.inventory.bookmarks.animation.true=是
nei.options.inventory.bookmarks.animation.false=否
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Loaded 100 of 110 files, more files were not shown because too many files have changed in this diff. Show more