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
slprimeandMartin Robertz 76db43c835 Optimize permutations (#761)
Co-authored-by: Martin Robertz <[email protected]>
2025-10-17 22:23:10 +03:00
slprimeandMartin Robertz 40e53eea7a Fixing HUD flickering (#762)
Co-authored-by: Martin Robertz <[email protected]>
2025-10-17 21:36:30 +03:00
Martin Robertz 6c4d16d6b9 update 2025-10-17 12:50:52 +02:00
RealSilverMoon 4a2abe9fd7 Add a function to copy item name and meta (#758) 2025-10-17 10:54:47 +03:00
sisyphussy d47417302e Fix recipe tooltip lighting (#757) 2025-10-14 17:09:02 +03:00
115 changed files with 4093 additions and 2187 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.43'
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);
@@ -42,13 +42,11 @@ public class HUDRenderer implements IKeyStateTracker {
&& mc.objectMouseOver != null
&& mc.objectMouseOver.typeOfHit == MovingObjectType.BLOCK) {
World world = mc.theWorld;
ItemStack[] items = ItemInfo.getIdentifierItems(world, mc.thePlayer, mc.objectMouseOver)
.toArray(new ItemStack[0]);
final List<ItemStack> items = ItemInfo.getIdentifierItems(world, mc.thePlayer, mc.objectMouseOver);
if (items.length == 0) return;
ItemStack stack = StackInfo.getItemStackWithMinimumDamage(items);
if (items.isEmpty()) return;
final ItemStack stack = StackInfo.getItemStackWithMinimumDamage(items.toArray(new ItemStack[0]));
renderOverlay(stack, ItemInfo.getText(stack, world, mc.thePlayer, mc.objectMouseOver), getPositioning());
}
}
@@ -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,7 +70,7 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
}
public void setActiveStack(ItemStack activeStack) {
final ItemStack realStack = items.stream().filter(stack -> StackInfo.equalItemAndNBT(stack, activeStack, true))
final ItemStack realStack = items.stream().filter(stack -> NEIClientUtils.areStacksSameType(stack, activeStack))
.findFirst().orElse(null);
this.activeStackIndex = items.indexOf(realStack);
}
@@ -107,7 +107,7 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
final int xTranslation = x;
final int yTranslation = y + fontRenderer.FONT_HEIGHT + 2;
final int zTranslation = 400;
final int zTranslation = GuiContainerManager.TOOLTIP_Z_OFFSET;
GL11.glTranslatef(xTranslation, yTranslation, zTranslation);
int indexShift = 0;
@@ -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,17 +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.jeiStyleCycledIngredients").setComment("JEI styled cycled ingredients")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.guirecipe.jeiStyleCycledIngredients", 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);
@@ -296,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) {
@@ -778,8 +781,7 @@ public class NEIClientConfig {
@Override
public boolean onClick(int button) {
super.onClick(button);
FavoriteRecipes.save();
FavoriteRecipes.load();
FavoriteRecipes.reload();
return true;
}
});
@@ -792,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));
}
@@ -812,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);
@@ -838,6 +853,7 @@ public class NEIClientConfig {
API.addKeyBind("world.creative", 0);
API.addHashBind("gui.copy_name", Keyboard.KEY_C + NEIClientUtils.CTRL_HASH);
API.addHashBind("gui.copy_oredict", Keyboard.KEY_D + NEIClientUtils.CTRL_HASH);
API.addHashBind("gui.copy_id", Keyboard.KEY_X + NEIClientUtils.CTRL_HASH);
API.addHashBind("gui.chat_link_item", Keyboard.KEY_L + NEIClientUtils.CTRL_HASH);
}
@@ -846,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();
}
}
@@ -871,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");
@@ -879,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());
}
@@ -909,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<>();
@@ -969,7 +977,6 @@ public class NEIClientConfig {
// main NEI config loading
ItemInfo.load();
GuiInfo.load();
RecipeInfo.load();
HeldItemHandler.load();
LayoutManager.load();
NEIController.load();
@@ -1001,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
@@ -1010,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();
@@ -1108,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() {
@@ -1128,10 +1132,6 @@ public class NEIClientConfig {
return getBooleanSetting("inventory.optimize_gui_overlap_computation");
}
public static boolean useJEIStyledCycledIngredients() {
return getBooleanSetting("inventory.guirecipe.jeiStyleCycledIngredients");
}
public static boolean showCycledIngredientsTooltip() {
return getBooleanSetting("inventory.guirecipe.cycledIngredientsTooltip");
}
@@ -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) {}
}
+19 -11
View File
@@ -421,30 +421,38 @@ public class ItemInfo {
Block mouseoverBlock = world.getBlock(x, y, z);
ArrayList<ItemStack> items = new ArrayList<>();
ArrayList<IHighlightHandler> handlers = new ArrayList<>();
if (highlightIdentifiers.containsKey(null)) handlers.addAll(highlightIdentifiers.get(null));
if (highlightIdentifiers.containsKey(mouseoverBlock)) handlers.addAll(highlightIdentifiers.get(mouseoverBlock));
for (IHighlightHandler ident : handlers) {
ItemStack item = ident.identifyHighlight(world, player, hit);
final ItemStack item = ident.identifyHighlight(world, player, hit);
if (item != null) items.add(item);
}
if (items.size() > 0) return items;
if (!items.isEmpty()) return items;
ItemStack pick = mouseoverBlock.getPickBlock(hit, world, x, y, z, player);
if (pick != null) items.add(pick);
try {
final ItemStack pick = mouseoverBlock.getPickBlock(hit, world, x, y, z, player);
if (pick != null) items.add(pick);
} catch (Exception ignored) {}
if (!items.isEmpty()) return items;
if (mouseoverBlock instanceof IShearable shearable) {
if (shearable.isShearable(new ItemStack(Items.shears), world, x, y, z)) {
items.addAll(shearable.onSheared(new ItemStack(Items.shears), world, x, y, z, 0));
}
}
if (!items.isEmpty()) return items;
try {
items.addAll(mouseoverBlock.getDrops(world, x, y, z, world.getBlockMetadata(x, y, z), 0));
} catch (Exception ignored) {}
if (mouseoverBlock instanceof IShearable) {
IShearable shearable = (IShearable) mouseoverBlock;
if (shearable.isShearable(new ItemStack(Items.shears), world, x, y, z))
items.addAll(shearable.onSheared(new ItemStack(Items.shears), world, x, y, z, 0));
}
if (items.size() == 0) items.add(0, new ItemStack(mouseoverBlock, 1, world.getBlockMetadata(x, y, z)));
if (items.isEmpty()) items.add(new ItemStack(mouseoverBlock, 1, world.getBlockMetadata(x, y, z)));
return items;
}
@@ -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;
@@ -42,6 +43,31 @@ import codechicken.nei.util.NEIMouseUtils;
public abstract class ShortcutInputHandler {
private static class HotkeysCache {
public int mousex;
public int mousey;
public ItemStack stack;
public int groupId;
public Map<String, String> hotkeys = new HashMap<>();
public boolean matches(int mousex, int mousey, ItemStack stack, int groupId) {
return Math.abs(this.mousex - mousex) < 16 && Math.abs(this.mousey - mousey) < 16
&& (this.stack == null ? stack == null && this.groupId == groupId
: stack != null && NEIClientUtils.areStacksSameTypeWithNBT(stack, this.stack));
}
public void update(int mousex, int mousey, ItemStack stack, int groupId, Map<String, String> hotkeys) {
this.mousex = mousex;
this.mousey = mousey;
this.stack = stack != null ? stack.copy() : null;
this.groupId = groupId;
this.hotkeys = hotkeys;
}
}
private static HotkeysCache hotkeysCache = new HotkeysCache();
public static boolean handleKeyEvent(ItemStack stackover) {
if (!NEIClientConfig.isLoaded()) {
@@ -98,6 +124,9 @@ public abstract class ShortcutInputHandler {
if (NEIClientConfig.isKeyHashDown("gui.copy_name")) {
return copyItemStackName(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.copy_id")) {
return copyItemStackID(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.copy_oredict")) {
return copyItemStackOreDictionary(stackover);
@@ -159,6 +188,14 @@ public abstract class ShortcutInputHandler {
return true;
}
private static boolean copyItemStackID(ItemStack stackover) {
if (stackover == null || stackover.getItem() == null) return false;
GuiScreen.setClipboardString(
stackover.getItem().delegate.name()
+ (stackover.getItemDamage() != 0 ? "/" + stackover.getItemDamage() : ""));
return true;
}
private static boolean sendItemStackChatLink(ItemStack stackover) {
if (stackover == null) return false;
@@ -197,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()
@@ -276,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)),
@@ -288,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);
@@ -380,8 +432,13 @@ public abstract class ShortcutInputHandler {
}
public static Map<String, String> handleHotkeys(int mousex, int mousey, ItemStack stack) {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
final int groupId = ItemPanels.bookmarkPanel.getHoveredGroupId(true);
if (hotkeysCache.matches(mousex, mousey, stack, groupId)) {
return hotkeysCache.hotkeys;
}
final GuiContainer gui = NEIClientUtils.getGuiContainer();
final Map<String, String> hotkeys = new HashMap<>();
if (groupId != -1) {
@@ -408,9 +465,13 @@ public abstract class ShortcutInputHandler {
NEIClientConfig.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.craft_all"));
}
hotkeysCache.update(mousex, mousey, stack, groupId, hotkeys);
return hotkeys;
}
if (stack == null) {
hotkeysCache.update(mousex, mousey, stack, groupId, hotkeys);
return hotkeys;
}
@@ -424,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"));
@@ -439,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"));
@@ -452,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"));
@@ -511,6 +573,7 @@ public abstract class ShortcutInputHandler {
hotkeys.put(NEIClientConfig.getKeyName("gui.copy_name"), NEIClientUtils.translate("itempanel.copy_name"));
hotkeys.put(NEIClientConfig.getKeyName("gui.copy_oredict"), NEIClientUtils.translate("itempanel.copy_oredict"));
hotkeys.put(NEIClientConfig.getKeyName("gui.copy_id"), NEIClientUtils.translate("itempanel.copy_id"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.chat_link_item"),
NEIClientUtils.translate("itempanel.chat_link_item"));
@@ -522,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),
@@ -570,6 +636,8 @@ public abstract class ShortcutInputHandler {
}
hotkeysCache.update(mousex, mousey, stack, groupId, hotkeys);
return hotkeys;
}
@@ -599,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;
@@ -82,6 +83,9 @@ public class GuiContainerManager {
public static final LinkedList<IContainerSlotClickHandler> slotClickHandlers = new HideousLinkedList<>(
new CopyOnWriteArrayList<>());
// Any item rendered with this z offset should render it on top of every other gui element
public static final int TOOLTIP_Z_OFFSET = 400;
static {
addSlotClickHandler(new DefaultSlotClickHandler());
}
@@ -161,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,
@@ -196,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;
}
@@ -229,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);
}
}
@@ -244,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);
}
/**
@@ -661,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());
@@ -701,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;
}
@@ -11,7 +11,7 @@ import codechicken.nei.NEIClientUtils;
public class AcceptsFollowingTooltipLineHandler extends ItemsTooltipLineHandler {
protected static final int DEFAULT_MAX_ROWS = 5;
protected static final int DEFAULT_MAX_ROWS = 4;
public Object tooltipGUID;
@@ -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,640 +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 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);
}
}
@@ -27,7 +27,7 @@ public class FurnaceRecipeHandler extends TemplateRecipeHandler {
}
public List<PositionedStack> getIngredients() {
return getCycledIngredients(cycleticks / 48, Collections.singletonList(ingred));
return Collections.singletonList(ingred);
}
public PositionedStack getResult() {
@@ -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,35 +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 recipeGrow = this.handlerInfo.getUseCustomScroll()
&& this.handlerInfo.getMaxRecipesPerPage() <= 1;
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 (recipeGrow) {
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);
@@ -380,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() {
@@ -409,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);
}
@@ -456,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;
}
@@ -521,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
@@ -617,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);
}
@@ -700,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
@@ -729,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);
@@ -753,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;
}
@@ -791,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() {
@@ -818,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(
@@ -900,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);
@@ -918,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,
@@ -927,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,
@@ -941,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;
@@ -960,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));
}
@@ -1028,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_ALL_ATTRIB_BITS);
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() {
@@ -146,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,6 +44,10 @@ public interface IRecipeHandler {
return getRecipeName();
}
default int getRecipeHeight(int recipe) {
return 0;
}
/**
*
* @return The number of recipes that this handler contains.
@@ -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
@@ -99,11 +117,11 @@ public class InformationHandler extends TemplateRecipeHandler {
@Override
public List<PositionedStack> getIngredients() {
return getCycledIngredients(cycleticks / 20, Collections.singletonList(this.stack));
return Collections.singletonList(this.stack);
}
public InformationPage getPage() {
return page;
public List<String> getLines() {
return lines;
}
}
@@ -2,14 +2,18 @@ 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;
import java.util.WeakHashMap;
import java.util.function.Function;
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;
@@ -17,25 +21,35 @@ import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.LayoutManager;
import codechicken.nei.FavoriteRecipes;
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 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 = -1;
protected final RecipeHandlerRef handlerRef;
protected final HandlerInfo handlerInfo;
protected boolean showAsWidget = false;
protected List<GuiRecipeButton> recipeButtons = null;
protected boolean firstDraw = true;
protected boolean needUpdate = true;
public NEIRecipeWidget(RecipeHandlerRef handlerRef) {
this.handlerRef = handlerRef;
@@ -49,21 +63,21 @@ public class NEIRecipeWidget extends Widget {
}
public void update() {
this.w = this.handlerInfo.getWidth();
if (this.showAsWidget || !this.handlerInfo.getUseCustomScroll()
|| this.handlerInfo.getMaxRecipesPerPage() > 1) {
this.h = this.handlerInfo.getHeight() + this.handlerInfo.getYShift();
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();
}
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();
@@ -113,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();
@@ -152,7 +166,20 @@ public class NEIRecipeWidget extends Widget {
public void draw(int mouseX, int mouseY) {
final int yShift = this.handlerInfo.getYShift();
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
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);
GL11.glTranslatef(this.x, this.y + yShift, 0);
this.handlerRef.handler.drawBackground(this.handlerRef.recipeIndex);
@@ -161,31 +188,53 @@ public class NEIRecipeWidget extends Widget {
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
GL11.glColor4f(1, 1, 1, 1);
if (this.firstDraw) {
this.firstDraw = false;
for (PositionedStack pStack : this.handlerRef.handler.getIngredientStacks(this.handlerRef.recipeIndex)) {
pStack.setPermutationToRender(pStack.getFilteredPermutations().get(0));
}
}
GuiContainerManager.enableMatrixStackLogging();
for (PositionedStack pStack : getInputs()) {
if (!this.permutations.containsKey(pStack)) {
updatePermutationsFor(pStack);
}
for (PositionedStack pStack : getItems(!this.needUpdate)) {
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));
}
}
this.needUpdate = false;
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, 0x80FFFFFF));
}
}
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));
}
}
GuiContainerManager.disableMatrixStackLogging();
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());
}
@@ -203,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;
}
@@ -283,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
@@ -300,12 +437,48 @@ public class NEIRecipeWidget extends Widget {
return true;
}
if (scrollPermutations(scroll, mx, my)) {
return true;
}
final GuiRecipe<?> guiRecipe = getGuiRecipe();
return guiRecipe != null
&& this.handlerRef.handler.mouseScrolled(guiRecipe, scroll, this.handlerRef.recipeIndex);
}
protected boolean scrollPermutations(int scroll, int mx, int my) {
if (!NEIClientUtils.shiftKey()) return false;
final PositionedStack overStack = getPositionedStackMouseOver(mx, my);
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(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()) {
@@ -328,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;
}
@@ -345,7 +513,19 @@ public class NEIRecipeWidget extends Widget {
public PositionedStack getPositionedStackMouseOver(int mx, int my) {
final int yShift = this.handlerInfo.getYShift();
for (PositionedStack pStack : getItems(true)) {
for (PositionedStack pStack : getInputs()) {
if (pStack.contains(mx - this.x, my - this.y - yShift)) {
return pStack;
}
}
for (PositionedStack pStack : getCatalysts()) {
if (pStack.contains(mx - this.x, my - this.y - yShift)) {
return pStack;
}
}
for (PositionedStack pStack : getOutputs()) {
if (pStack.contains(mx - this.x, my - this.y - yShift)) {
return pStack;
}
@@ -380,20 +560,76 @@ public class NEIRecipeWidget extends Widget {
return guiContainer;
}
protected List<PositionedStack> getItems(boolean disableCycledIngredients) {
final PositionedStack pStackResult = this.handlerRef.handler.getResultStack(this.handlerRef.recipeIndex);
final List<PositionedStack> itemStacks = new ArrayList<>();
protected void updatePermutations() {
final int rev = FavoriteRecipes.getRevision();
TemplateRecipeHandler.disableCycledIngredients = disableCycledIngredients;
itemStacks.addAll(this.handlerRef.handler.getIngredientStacks(this.handlerRef.recipeIndex));
itemStacks.addAll(this.handlerRef.handler.getOtherStacks(this.handlerRef.recipeIndex));
TemplateRecipeHandler.disableCycledIngredients = true;
if (pStackResult != null) {
itemStacks.add(pStackResult);
if (this.favoriteRevision != rev) {
this.favoriteRevision = rev;
this.acceptsFollowingTooltipLineHandler = null;
this.favoriteIndexes.clear();
this.permutations.clear();
}
return itemStacks;
for (PositionedStack pStack : getInputs()) {
updatePermutationsFor(pStack);
}
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 = "";
@@ -80,15 +81,23 @@ public class RecipeTooltipLineHandler implements ITooltipLineHandler {
final Dimension size = getSize();
GL11.glPushMatrix();
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
GL11.glTranslatef(x, y, 0);
GL11.glScaled(1, 1, 3);
final int zTranslation = GuiContainerManager.TOOLTIP_Z_OFFSET;
GL11.glTranslatef(x, y, zTranslation);
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);
@@ -103,7 +112,7 @@ public class RecipeTooltipLineHandler implements ITooltipLineHandler {
() -> { this.widget.draw(0, 0); });
GL11.glPopAttrib();
GL11.glPopMatrix();
GL11.glTranslatef(-x, -y, -zTranslation);
}
}
@@ -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) {}
}
@@ -54,7 +54,7 @@ public class ShapedRecipeHandler extends TemplateRecipeHandler {
@Override
public List<PositionedStack> getIngredients() {
return getCycledIngredients(cycleticks / 20, ingredients);
return ingredients;
}
public PositionedStack getResult() {
@@ -64,7 +64,7 @@ public class ShapelessRecipeHandler extends ShapedRecipeHandler {
@Override
public List<PositionedStack> getIngredients() {
return getCycledIngredients(cycleticks / 20, ingredients);
return ingredients;
}
@Override
@@ -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) {
@@ -9,13 +9,11 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.init.Blocks;
@@ -31,8 +29,6 @@ import org.lwjgl.opengl.GL11;
import com.google.common.base.Stopwatch;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.FavoriteRecipes;
import codechicken.nei.ItemList;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
@@ -178,43 +174,16 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
return null;
}
/**
* This will perform default cycling of ingredients, mulitItem capable
*
* @param cycle Current cycle step
* @param ingredients List of ItemStacks to cycle
* @return The provided list of ingredients, with their permutations cycled to a different permutation, if one
* is available
*/
@Deprecated
public List<PositionedStack> getCycledIngredients(int cycle, List<PositionedStack> ingredients) {
if (!NEIClientUtils.shiftKey() && !disableCycledIngredients) {
randomRenderPermutation(ingredients, cycle);
}
return ingredients;
}
public void randomRenderPermutation(List<PositionedStack> stacks, long cycle) {
cycle = NEIClientConfig.useJEIStyledCycledIngredients() ? cycle
: Math.abs(new Random(cycle + offset).nextInt());
for (PositionedStack pStack : stacks) {
if (pStack.items.length <= 1) continue;
final List<ItemStack> items = pStack.getFilteredPermutations(FavoriteRecipes::contains);
pStack.setPermutationToRender(items.get((int) (cycle % items.size())));
}
}
@Deprecated
public void randomRenderPermutation(List<PositionedStack> stacks, long cycle) {}
@Deprecated
public void randomRenderPermutation(PositionedStack stack, long cycle) {
cycle = NEIClientConfig.useJEIStyledCycledIngredients() ? cycle
: Math.abs(new Random(cycle + offset).nextInt());
if (stack.items.length <= 1) return;
final List<ItemStack> items = stack.getFilteredPermutations(FavoriteRecipes::contains);
stack.setPermutationToRender(items.get((int) (cycle % items.size())));
}
public void randomRenderPermutation(PositionedStack stack, long cycle) {}
public void setIngredientPermutation(Collection<PositionedStack> ingredients, ItemStack ingredient) {
for (PositionedStack stack : ingredients) {
@@ -287,6 +256,10 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
return rect.hashCode();
}
public Rectangle getRect() {
return rect;
}
Rectangle rect;
String outputId;
Object[] results;
@@ -406,8 +379,6 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
*/
public LinkedList<RecipeTransferRect> transferRects = new LinkedList<>();
public static boolean disableCycledIngredients = true;
public TemplateRecipeHandler() {
loadTransferRects();
RecipeTransferRectHandler.registerRectsToGuis(getRecipeTransferRectGuis(), transferRects);
@@ -641,7 +612,7 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
}
public void onUpdate() {
if (!NEIClientUtils.shiftKey()) cycleticks++;
cycleticks++;
}
public boolean hasOverlay(GuiContainer gui, Container container, int recipe) {
@@ -700,49 +671,9 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
@Override
public boolean mouseScrolled(GuiRecipe<?> gui, int scroll, int recipe) {
if (!NEIClientUtils.shiftKey()) return false;
final Point pos = GuiDraw.getMousePosition();
final Point offset = gui.getRecipePosition(recipe);
final Point relMouse = new Point(pos.x - gui.guiLeft - offset.x, pos.y - gui.guiTop - offset.y);
final PositionedStack overStack = getIngredientMouseOver(relMouse.x, relMouse.y, recipe);
if (overStack != null && overStack.items.length > 1) {
final List<ItemStack> items = overStack.getFilteredPermutations();
final int stackIndex = getPermutationIndex(overStack.item, items);
final ItemStack stack = items.get((items.size() - scroll + stackIndex) % items.size());
if (NEIClientConfig.useJEIStyledCycledIngredients()) {
Stream.concat(getIngredientStacks(recipe).stream(), getOtherStacks(recipe).stream())
.filter(pStack -> pStack.containsWithNBT(stack))
.forEach(pStack -> pStack.setPermutationToRender(stack));
} else {
overStack.setPermutationToRender(stack);
}
return true;
}
return false;
}
private int getPermutationIndex(ItemStack stack, List<ItemStack> items) {
for (int index = 0; index < items.size(); index++) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(items.get(index), stack)) {
return index;
}
}
return -1;
}
private PositionedStack getIngredientMouseOver(int mousex, int mousey, int recipe) {
return Stream.concat(getIngredientStacks(recipe).stream(), getOtherStacks(recipe).stream())
.filter(pStack -> new Rectangle4i(pStack.relx, pStack.rely, 18, 18).contains(mousex, mousey))
.findFirst().orElse(null);
}
private boolean transferRect(GuiRecipe<?> gui, int recipe, boolean usage) {
Point offset = gui.getRecipePosition(recipe);
return transferRect(gui, transferRects, offset.x, offset.y, usage);
@@ -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,13 +250,13 @@ 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_ALL_ATTRIB_BITS);
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
if (canScrollVertical) {
this.verticalScrollBar.draw(this, mousex, mousey, getScrollBarOpacity());
@@ -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
Loaded 100 of 115 files, more files were not shown because too many files have changed in this diff. Show more