Compare commits

...
137 Commits
Author SHA1 Message Date
Maya 5383e0891a update 2025-05-13 19:14:13 -05:00
slprimeandslprime 6142d4cc6d Subset: Memory Optimization (#626)
Co-authored-by: slprime <[email protected]>
2025-05-13 19:13:17 -05:00
Maya 6aa6b2e6d2 update 2025-05-12 09:46:11 -05:00
koolkrafter5andMaya 29ade6f327 Make the "Accepts following:" tooltip work for otherStacks (#625)
Co-authored-by: Maya <[email protected]>
2025-05-12 14:45:57 +00:00
slprimeandslprime 5ad6095c43 Filtering the input in the ItemQuantityField (#623)
Co-authored-by: slprime <[email protected]>
2025-05-12 09:40:42 -05:00
Martin Robertz 8ae3304861 update 2025-04-25 13:38:04 +02:00
0dc7bc1228 Create Favorites Widget; More hotkeys; More Tooltips; (#617)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Maya <[email protected]>
2025-04-24 17:48:40 +02:00
Maya 19d8b42993 update 2025-04-08 23:53:43 -05:00
Kogepan229 3b7eae67af Add AE2 Cell View handlers (#621) 2025-04-08 23:51:52 -05:00
Glease 64a747e4bd prevent empty pages from being produced (#615) 2025-03-25 15:06:45 +01:00
Martin Robertz 4f60928b61 update 2025-03-24 16:05:00 +01:00
8dba2ff4c1 Add option to adjust FPS rendering of items (#612)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
2025-03-24 15:01:41 +00:00
eb40e3b112 Add Hotkeys Widget Settings (#613)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
2025-03-24 15:48:11 +01:00
Martin Robertz 98c8981f05 update 2025-03-19 16:45:47 +01:00
Spacebuilder2020 1ed35c8357 Implement Forge Essentials Permission Checking (#611) 2025-03-18 08:15:30 -07:00
Martin Robertz 6249bab886 update 2025-03-14 19:04:03 +01:00
azodandThéo Jacquelin b525760dd3 feature: Overlays Settings GUI (Keep overlays through dimensions) (#610)
Signed-off-by: AzodFR <[email protected]>
Co-authored-by: Théo Jacquelin <[email protected]>
2025-03-13 17:48:25 +00:00
Jason Mitchell 83b4855f5e Use the updated ASMDataTable (with interfaces) when JarJar is present (#608) 2025-03-13 07:04:41 -07:00
Maya 75352caf11 update 2025-02-08 12:14:10 -06:00
475f5811f6 Add loadPluginsInParallel Option (#604)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Maya <[email protected]>
2025-02-08 18:11:17 +00:00
slprimeandslprime 7503e1dfcb Fix NC marker in recipe after fluid pattern terminal (#603)
Co-authored-by: slprime <[email protected]>
2025-02-08 12:08:36 -06:00
Martin Robertz 9d1f475941 update 2025-01-27 08:06:08 +01:00
slprimeandslprime ac50d1b27e Added hotkey utils methods (#599)
Co-authored-by: slprime <[email protected]>
2025-01-26 12:59:16 -06:00
Maya 48934d621f update 2025-01-25 13:17:03 -06:00
slprimeandslprime 0bbb889f39 Change Permutation Filter (#598)
Co-authored-by: slprime <[email protected]>
2025-01-25 13:16:28 -06:00
Martin Robertz af55a6b191 update
(cherry picked from commit bd7e8d05fa)
2025-01-21 17:55:50 +01:00
slprimeandslprime b3e1f23683 Restore Issue 583 (#593)
Co-authored-by: slprime <[email protected]>
2025-01-21 10:50:16 -06:00
slprimeandslprime 39578a4419 Update Render Cache after window resize (#592)
Co-authored-by: slprime <[email protected]>
2025-01-19 11:33:26 -06:00
e3574800c0 Subset Widget Improvement (#577)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: Caedis <[email protected]>
Co-authored-by: Maya <[email protected]>
2025-01-16 21:12:26 +01:00
Martin Robertz 5cd7556e6a update 2025-01-16 12:44:42 +01:00
80c2cba778 Created Grid Rendering Cache Mode (#573)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: Caedis <[email protected]>
2025-01-15 23:23:16 -06:00
Glease 31173a1fbd fix memory leak fixes not working for MP (#590)
#258 addresses the memory leak in ItemMobSpawner. Unfortunately the clean up handler is not consistently called on every world unloaded. This PR fixes this issue by moving the call out of that if block
2025-01-10 17:11:52 +08:00
Caedis fd08a93554 Fix NPE in ItemsTooltipLineHandler (#589) 2025-01-10 10:42:23 +02:00
Martin Robertz 4dace1f6e5 update 2025-01-09 21:05:10 +01:00
0c0cf37eb0 Add 'Hide Item List Until Searching' option (#572)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: Maya <[email protected]>
2025-01-09 07:53:27 +00:00
Chris Stone 3ec4f8dd68 Add mod handlers for mods in Per Fabrica Ad Astra modpack (#587) 2025-01-08 12:30:34 -06:00
lailani-fandlailani-f e0dd6847cb Item List Sort: Ensure access to shared private field is atomic (#584)
Co-authored-by: lailani-f <>
2025-01-04 14:03:53 +00:00
slprimeandslprime 6374c162ba Fixed NEI reload when changing dimension (#583)
Co-authored-by: slprime <[email protected]>
2024-12-31 19:33:21 +01:00
8dd36f1c4a Add RenderTooltipEvent Compat (#574)
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: Maya <[email protected]>
2024-12-28 23:00:02 -06:00
4613ade468 Change OptionIntegerField Width (#575)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Maya <[email protected]>
2024-12-29 02:36:53 +00:00
ca7030df72 Add Space Mode Settings to Search (#571)
Co-authored-by: slprime <[email protected]>
Co-authored-by: boubou19 <[email protected]>
2024-12-23 10:21:28 +00:00
Martin Robertz b32f25c2ce update 2024-12-22 11:38:38 +01:00
4be7a30578 Fix Accept Folowing for custom recipe handlers (#570)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
2024-12-22 03:01:44 +01:00
Martin Robertz 7ac3e32635 update 2024-12-17 20:36:35 +01:00
Martin Robertz 088d37a11a update 2024-12-17 20:36:29 +01:00
slprime 6a787dd5b7 Clear Search Filter Cache after Change Settings (#569) 2024-12-17 13:15:41 -06:00
c305649b95 Optimize TooltipItemFilter; ItemFilter limited cache (#565)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
2024-12-07 15:29:09 +01:00
slprimeandslprime b5d2815eab Fix CME in registerRectsToGuis during plugin loading (#566)
Co-authored-by: slprime <[email protected]>
2024-12-07 10:32:00 +01:00
slprimeandslprime 6049d0e9c3 Fix restoring collapsible items state (#564)
Co-authored-by: slprime <[email protected]>
2024-12-05 20:25:17 +01:00
9288fc4575 Fix Zoom Position in Right Panel (#559)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Ethryan <[email protected]>
2024-12-03 06:52:51 +01:00
Alexdoru ec749ecc8e Fix mob spawners spawning mobs at world 0 0 0 (#563) 2024-12-03 02:39:34 +01:00
Alexdoru 7471a82bca fix the handlerordering.csv being empty when created (#561) 2024-12-01 16:56:02 +01:00
kstvr32 3f3c1791cb Fix handler ordering config (#560) 2024-11-29 20:28:13 +00:00
a0e16835c2 Fix Presets Scroll; Fix Placeholder position in the quantity field; Hide rendering error in chat; (#555)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
2024-11-17 16:31:10 +01:00
Martin Robertz e9ce5cf72b update 2024-11-16 15:32:06 +01:00
slprimeandslprime fac011b67e Fix Zoom Position (#554)
Co-authored-by: slprime <[email protected]>
2024-11-15 10:20:32 +01:00
Worive f9c8ac504e Fix typo for cycledIngredientsTooltip.false in English(#553) 2024-11-14 14:27:14 +00:00
Maya f97711a33a add issue templates 2024-11-11 04:43:49 -06:00
kurrycat b2934c4910 replace GL immediate draw with Tessellator calls for chunk bounds rendering (#549) 2024-10-22 09:29:00 +02:00
Dream Master 759ea69c9f update 2024-10-13 22:01:17 +02:00
36a2cafdac Small Fixes (#543)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
2024-10-13 22:00:06 +02:00
Maya 6100012f5b Add Helioflare Power Forge (Gorge) to smelting catalysts (#544) 2024-10-13 21:48:11 +02:00
slprimeandslprime 2e5781beb5 fix catalysts in multiblock structure recipes when shown bookmarks recipe tooltip (#542)
Co-authored-by: slprime <[email protected]>
2024-10-06 12:10:05 +02:00
Alexdoru 43918f3bb1 give names to NEI threads (#540) 2024-10-04 21:46:29 +02:00
AtHisF1nestandMarcin Siekierski a41299dfca fix issue #17509 (#539)
Co-authored-by: Marcin Siekierski <[email protected]>
2024-10-02 17:21:50 +02:00
slprimeandslprime ee060b9253 Small Fixes (#536)
* Small Fixes

* fix shift+v

* fix subset zindex

---------

Co-authored-by: slprime <[email protected]>
2024-09-28 18:05:06 +02:00
Jon 82a2273995 Update en_US.lang (#534) 2024-09-15 22:10:18 +02:00
06fadcc362 Try fix Item Render & GuiRecipeHandler (#528)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
2024-09-15 16:57:55 +02:00
slprimeandslprime b328fd3db1 Fix DraggedStack in Bookmarks (#527)
Co-authored-by: slprime <[email protected]>
2024-09-12 18:14:00 +02:00
Martin Robertz 9563ebfe5a update 2024-09-07 18:18:02 +02:00
slprimeandslprime d9143c584e Rename GT Classes; Correct show Meta Keys (#525)
Co-authored-by: slprime <[email protected]>
2024-09-07 14:49:46 +02:00
slprimeandslprime 65652e5896 Small fixes & changes (#523)
* fix hotkeys

* code cleanup

* fix recipe tooltip overlay

* search item by original name

* overlay button refactoring

* fix subset filter

* change keyname; issue 524

* cleanup code

* move overlayformat logic

---------

Co-authored-by: slprime <[email protected]>
2024-09-01 22:19:12 +02:00
slprimeandslprime bd5e991a84 NEI Optimization (#519)
* NEI Optimization

* save setting after death

---------

Co-authored-by: slprime <[email protected]>
2024-08-29 22:14:52 +02:00
glowredman 165afa2910 Small Cleanup (#518)
* Deobfuscate parameters

* Fix generics

* Replace deprecated methods

* Add `serialVersionUID`s

* Fix static access

* Add default switch case

* Close OutputStreams

* Fix wrong variable usage

* Explicitly declare exceptions
2024-08-29 20:07:14 +02:00
glowredman 2507634196 Allow any Character to be used as Search-Prefix (#522)
* Allow any character to be used as prefix

* Enable Jabel

* Add back search mode settings and add ingame setting for prefixes

* Implement prefix redefinitions
2024-08-29 08:17:00 +02:00
slprimeandslprime e0171adc65 Show Delete Item Tooltip only in creative (#517)
Co-authored-by: slprime <[email protected]>
2024-08-18 09:27:57 +02:00
72ad8aa2e7 More QOL (#510)
* ItemZoom, hotkeys & more tooltips

* fix tooltips

* fix hover crash to unnamed item

* fix bookmark group with groupIds bigger than 127

---------

Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
2024-08-17 22:24:27 +02:00
Dream Master f0a554bcc1 update 2024-08-08 12:02:41 +07:00
cutiegin 65781a1649 Update ru_RU.lang (#512)
* Update ru_RU.lang

* Update ru_RU.lang
2024-08-08 11:50:46 +07:00
Dream Master 6ad8f05323 update 2024-07-26 22:48:08 +07:00
slprimeandslprime d61a545d9d Collapsibleitems (#506)
* Create Collapsible Items; Presets refactoring

* change lang

* fix preset settings

* fix .top

* fix tooltip

---------

Co-authored-by: slprime <[email protected]>
2024-07-26 22:44:54 +07:00
chochem 1774685af6 improve advanced search defaults (#498) 2024-07-26 22:42:42 +07:00
slprimeandslprime a63a227c3c Add Create Groups Method to Bookmarks (#497)
* Add Create Groups Method to Bookmarks

* fix dnd with empty handleName

---------

Co-authored-by: slprime <[email protected]>
2024-07-26 07:41:15 +07:00
Dream Master 0f115d5439 update 2024-07-08 13:04:31 +07:00
Jason Mitchell 0fad93fb3b Update CCL Dep (#501) 2024-07-03 09:41:26 -07:00
b1a34c761b Create JEI-like Advanced Search (#485)
* Create JEI like Search

* add subfilter

* fix extended search pattern

* fix search crash without prefixes

* fix unicode case in search

* add regexp to extended patternMode

* move autofocus config to seatch widget panel

* code refactoring

* add matching language to searh parser

* fix type

* fix modname search

* clean cache after add new provider

---------

Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
2024-06-27 17:03:50 +02:00
Martin Robertz cc9715d9f2 update 2024-06-18 20:33:08 +02:00
Jason Mitchell be253a00d2 Broaden visibility (#495)
Fixes #473
2024-06-18 20:25:26 +02:00
OvermindDL1 5dde3b2e2f More inventory interaction enhancements - autofocus-quickclose (#493)
* Added option (default on because it just feels so much better) to instantly close the inventory when it was just opened with it when pressing the inventory close key is the first input the screen receives, letting you flash open and close it again as is common when inspecting inventory

* Forgot to add the vanilla survival inventory to the autofocus allowlist defaults (should this be hardcoded instead?)  Added missing loadEnableAutoFocus() call.

* Removed logging entry, added a new autofocus default that tests successful (and it overwrites the vanilla inventory gui so needed anyway for it), shortened config comment.
2024-06-11 20:18:49 +02:00
OvermindDL1andMartin Robertz 8da541460f Added ability to have the NEI search be auto-focused on open. (#492)
* Added open to have the NEI search be auto-focused on open.  It will automatically blue if the mouse is moved before typing anything so immediate 'r' and such use works as expected.

* Added open to have the NEI search be auto-focused on open.  It will automatically blue if the mouse is moved before typing anything so immediate 'r' and such use works as expected.

* Add an allowlist for what classnames to allow the search auto-focus to work on

* sa

* Add `INEIAutoFocusSearchEnable` interface for opting in to autofocus search box by a mod.  Moved the autofocus list from config into a standalone file at the loss of live-updating.

* Remove now-superfluous lang entries for search focus prefix allowlist

* Undo intellij automatic star-imports...

---------

Co-authored-by: Martin Robertz <[email protected]>
2024-06-10 22:19:25 +02:00
Lasm Gratel dc4426d9c9 fix #479 (#483) 2024-05-27 14:25:19 +02:00
Martin Robertz d05a9eafb3 update 2024-05-04 13:54:08 +02:00
Lasm Gratel 5056fe5437 Concurrent recipe profiler (#478)
* concurrent recipe profiler

* eliminate NPE by giving nulls a name
2024-05-04 13:50:56 +02:00
slprimeandslprime 9fd9aad357 Fix Bookmarks DnD (#476)
Co-authored-by: slprime <[email protected]>
2024-04-24 21:25:46 +02:00
Martin Robertz acaead41ee update 2024-04-22 12:51:44 +02:00
D-Cysteine 951f1b0d0d Add Railcraft NEI handlers to height hack (#475) 2024-04-21 21:52:54 +02:00
Martin Robertz daab313288 update 2024-03-21 20:35:30 +01:00
MalTeeez 25eaa492f7 Update icon (#471) 2024-03-21 20:32:17 +01:00
Caedis 1b34b24495 Adjust readability and padding of item panel footer size (#470) 2024-03-07 05:32:08 -06:00
Martin Robertz b9cd48f8f9 Update settings.gradle (#469) 2024-03-07 11:08:51 +01:00
Caedis b2afc8c9e0 Fix history being hidden when search is centered and item quantity bar is disabled (#468) 2024-03-07 11:01:02 +01:00
Martin Robertz dc400ea560 update 2024-03-02 00:30:18 +01:00
slprimeandslprime ea03cfa17d Correctly find the recipeId under mouse when using the search (#465)
* Correctly find the recipeId under mouse when using the search

* optimize

---------

Co-authored-by: slprime <[email protected]>
2024-03-01 19:36:15 +01:00
slprimeandslprime 94676e0934 DnD big ItemStack; Show green slot highlighting overlay (#463)
* DnD big ItemStack; Show green slot highlighting overlay

* change config

* spotless

* remove system.log

* remove system.log

* show formatted stacksize

* fix draw handler foreground

---------

Co-authored-by: slprime <[email protected]>
2024-02-22 00:26:41 +01:00
slprimeandslprime f7ba34c0af Migrate NEI-Utilities (#461)
Co-authored-by: slprime <[email protected]>
2024-02-21 17:12:28 +01:00
Caedis db1fd255bb Slot Highlighting Overlay Option (#458)
* Add option to highlight the entire slot instead of showing an icon for recipe overlay

* Move skip to full slot highlight only
2024-02-19 13:12:01 +01:00
Martin Robertz 94ca7f3134 update 2024-02-15 19:21:14 +01:00
Jason Mitchell dea024173f Less StringBuilder allocation nonsense (#455)
* Less StringBuilder allocation nonsense
2024-02-15 09:51:48 -08:00
Raven Szewczyk af320a6c9f [ci skip] upgraded build system 2024-02-04 20:00:44 +00:00
Martin Robertz dcb10bb79d update bs+deps 2024-02-04 15:08:35 +01:00
Martin Robertz d3b6603d06 update bs+properties
(cherry picked from commit ceae486a31)
2024-02-04 15:08:05 +01:00
slprimeandslprime adf2065305 Create Bookmarks Groups; Search Recipe (#451)
* Create Bookmarks Groups; Search Recipe

* fix crash after DnD; add remove group function

* change hiddenhandler handlerId

* Pull all Bookmarked Items: use groups

* Optimize Chain Algorithm

* remove println

* fix input V in ME terminal

* Add Search Recipe Icon

* fix recipe extra information

* Change Search Recipe Algorithm

* fixed rounding in chain calculation

* fix creating groups for 2-line recipes

* fix fast DnD and recipe tooltip

* Bookmarks Recipe Chains: fluid canner

* Bookmarks Recipe Chains: fluid cell

* Open GuiRecipe: normalizeItemStack

---------

Co-authored-by: slprime <[email protected]>
2024-02-04 13:09:24 +01:00
bombcarandMartin Robertz e30f6a41ad undo dependencies removal, it's loadbearing (#449)
* undo dependencies removal, it's loadbearing

* update bs, dependencies, and settings.gradle

* cleaned too much

* cleaner

---------

Co-authored-by: Martin Robertz <[email protected]>
2024-01-10 00:28:27 +01:00
Martin Robertz b1a45d0305 update bs 2024-01-08 23:13:51 +01:00
Raven Szewczyk 566d1b095d [ci skip] upgraded build system 2024-01-08 21:28:03 +00:00
Caedis f35a92a101 Add chat message to chunk overlay key press (#450)
* Add chat message to chunk overlay key

* spotless
2024-01-08 13:36:16 -06:00
bombcar fdf130f741 Update bs and dependencies (#447)
* Update bs and dependencies

* remove dependencies.info

* updatedate
2024-01-06 16:58:20 +01:00
Martin Robertz 064f31f8db update gradle+bs+deps 2023-12-03 17:10:11 +01:00
slprimeandslprime 9b081ed2a7 fix bookmarks Infinite loop in todo list (#442)
Co-authored-by: slprime <[email protected]>
2023-12-03 17:07:54 +01:00
miozune 2fc2ecf082 Suppress warning for recipe catalyst item from config not being found (#441) 2023-11-09 18:38:50 +09:00
miozune bc7efcfce5 Improve the way catalyst info is loaded via API (#434) 2023-11-08 18:34:14 +09:00
miozune 0c5af2b892 Add method to directly set DrawableResource for HandlerInfo builder (#440) 2023-11-08 18:03:42 +09:00
Martin Robertz 0c61e559ec update bs 2023-11-08 08:19:08 +01:00
miozune b94bd11e64 Move handler info load to LoadCompleteEvent (#439) 2023-11-07 22:44:13 +09:00
miozune 151a9957de Add another method for handler info event (#438) 2023-11-07 22:44:04 +09:00
Nico Spiske b011024164 Fix TiCo Crafting Stations not working with compressed chests (#435)
* [major] fixes compressed chests not working with the tico crafting station

* [minor] comply with review + bs
2023-11-03 17:19:51 +09:00
Martin Robertz 74d98a86f3 update bs 2023-10-30 08:31:09 +01:00
Ryan Nasers bd5946f5bf Fix the case where the bookmark key is the same key that is used to close a GUI. (#433)
* This should fix the case where the bookmark key is the same key that is used to close a GUI

* Spotless
2023-10-30 08:17:53 +01:00
miozune 1647e8765f Fix DefaultStackStringifyHandler not using short for item id (#430) 2023-10-15 16:12:39 +09:00
Martin Robertz 744b2ffc64 update bs 2023-10-14 13:03:15 +02:00
ghostflyby e88348aabf fix non-centered searchfield considering gui space (#429) 2023-10-14 13:02:11 +02:00
Martin Robertz 4766d90db0 missing imports 2023-09-25 00:36:46 +02:00
Martin Robertz 1dc02a3730 sa 2023-09-25 00:35:24 +02:00
Martin Robertz a6a5e19e80 add missing imports 2023-09-25 00:34:42 +02:00
Martin Robertz e9ab2eba9e sa+wci 2023-09-24 23:02:09 +02:00
Martin Robertz 0e3ff1ee06 update bs 2023-09-24 22:37:31 +02:00
ghostflyby 95e9ac3c89 New: scroll on ItemQuantityField (#421) 2023-09-24 13:18:11 +02:00
177 changed files with 18827 additions and 6537 deletions

No files matched your search

+62
View File
@@ -0,0 +1,62 @@
name: Report Bug
description: "Report a bug."
body:
- type: markdown
attributes:
value: "A bug/crash report with sufficient information and logs to reproduce and track down."
- type: input
id: discord
attributes:
label: Your GTNH Discord Username
description: Leave empty if you don't have one, but this will make it harder to contact you if we need additional info.
placeholder: "Example: Fake#1234"
- type: input
id: version
attributes:
label: Mod Version
description: "What version of the Mod are you using?"
placeholder: "Example: 1.0.0"
validations:
required: true
- type: textarea
id: report
attributes:
label: Bug Report
description: "Relevant information, as well as relevant logs attached such as `logs/fml-client-latest.log."
placeholder: "Example: https://mclo.gs/ OR submit the file to github by dragging it to this textbox."
validations:
required: true
- type: dropdown
id: java
attributes:
label: Java Version
description: What Java version are you using? It's worth mentioning that if you play on Java9+ you should try update to latest minor release (e.g. prefer Java 17.0.6 over 17.0.2) of that version.
options:
- Java 8
- Java 9
- Java 11
- Java 17
- Java 19
- Java 20
- Java 21
- Other (Please Specify)
validations:
required: true
- type: textarea
id: modlist
attributes:
label: Mod List or GTNH Pack Version
description: "List of mods, ideally a minimal reproducible set (can be retrieved from latest.log). If using GTNH please indicate pack version and any changed mods, not the entire modlist."
placeholder: "List of mods or GTNH Pack version goes here"
validations:
required: true
- type: checkboxes
id: final
attributes:
label: Final Checklist
description: Certify that you read things
options:
- label: "I have searched the issues and haven't found a similar issue."
required: true
@@ -0,0 +1,28 @@
name: Feature Request
description: "Request a feature."
body:
- type: markdown
attributes:
value: "Please use this form to request features. We ask you check if it was already requested though"
- type: input
id: discord
attributes:
label: Your GTNH Discord Username
description: Leave empty if you don't have one, but this will make it harder to contact you if we need additional info.
placeholder: "Example: Wumpus#1234"
- type: textarea
id: request
attributes:
label: Feature Request
description: "Relevant information, as well as relevant images"
placeholder: "Example: https://mclo.gs/ OR submit the file to github by dragging it to this textbox."
validations:
required: true
- type: checkboxes
id: final
attributes:
label: Final Checklist
description: Certify that you read things
options:
- label: "I have searched the issues and haven't found a similar issue."
required: true
+1
View File
@@ -35,3 +35,4 @@ addon.local.gradle
addon.local.gradle.kts
addon.late.local.gradle
addon.late.local.gradle.kts
layout.json
+1 -1
View File
@@ -29,7 +29,7 @@ If you have issues with NEI outside of the GTNH modpack you may report them in t
## License
GTNH Modifications Copyright (c) 2019-2022 mitchej123 and the GTNH Team
GTNH Modifications Copyright (c) 2019-2024 mitchej123 and the GTNH Team
Licensed under LGPL-3.0 or later - use this however you want, but please give back any modifications
+2 -1588
View File
File diff suppressed because it is too large. Load diff
+5 -2
View File
@@ -1,7 +1,10 @@
// Add your dependencies here
dependencies {
api('com.github.GTNewHorizons:CodeChickenLib:1.1.8:dev')
api('com.github.GTNewHorizons:CodeChickenCore:1.1.11:dev')
api('com.github.GTNewHorizons:CodeChickenCore:1.4.2:dev')
implementation('com.github.GTNewHorizons:GTNHLib:0.6.22:dev')
shadowImplementation('org.apache.commons:commons-csv:1.10.0')
compileOnly 'maven.modrinth:forge-essentials:7.5.1'
}
+145 -40
View File
@@ -1,90 +1,148 @@
# ExampleMod tag to use as Blowdryer (Spotless, etc.) settings version, leave empty to disable.
# LOCAL to test local config updates.
gtnh.settings.blowdryerTag = 0.2.0
# Human-readable mod name, available for mcmod.info population.
modName = NotEnoughItems
# This is a case-sensitive string to identify your mod. Convention is to use lower case.
# Case-sensitive identifier string, available for mcmod.info population and used for automatic mixin JSON generation.
# Conventionally lowercase.
modId = NotEnoughItems
# Root package of the mod, used to find various classes in other properties,
# mcmod.info substitution, enabling assertions in run tasks, etc.
modGroup = codechicken.nei
# WHY is there no version field?
# The build script relies on git to provide a version via tags. It is super easy and will enable you to always know the
# code base or your binary. Check out this tutorial: https://blog.mattclemente.com/2017/10/13/versioning-with-git-tags/
# Whether to use modGroup as the maven publishing group.
# When false, com.github.GTNewHorizons is used.
useModGroupForPublishing = false
# Will update your build.gradle automatically whenever an update is available
# Updates your build.gradle and settings.gradle automatically whenever an update is available.
autoUpdateBuildScript = false
# Version of Minecraft to target
minecraftVersion = 1.7.10
# Version of Minecraft Forge to target
forgeVersion = 10.13.4.1614
# Select a username for testing your mod with breakpoints. You may leave this empty for a random username each time you
# restart Minecraft in development. Choose this dependent on your mod:
# Do you need consistent player progressing (for example Thaumcraft)? -> Select a name
# Do you need to test how your custom blocks interacts with a player that is not the owner? -> leave name empty
# Specify an MCP channel for dependency deobfuscation and the deobfParams task.
channel = stable
# Specify an MCP mappings version for dependency deobfuscation and the deobfParams task.
mappingsVersion = 12
# Defines other MCP mappings for dependency deobfuscation.
remoteMappings = https\://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/
# Select a default username for testing your mod. You can always override this per-run by running
# `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE.
developmentEnvironmentUserName = Developer
# Define a source file of your project with:
# public static final String VERSION = "GRADLETOKEN_VERSION";
# The string's content will be replaced with your mod's version when compiled. You should use this to specify your mod's
# version in @Mod([...], version = VERSION, [...])
# Leave these properties empty to skip individual token replacements
# Generate a class with String fields for the mod id, name, version and group name named with the fields below
# 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 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.
enableGenericInjection = true
# Generate a class with a String field for the mod version named as defined below.
# If generateGradleTokenClass is empty or not missing, no such class will be generated.
# If gradleTokenVersion is empty or missing, the field will not be present in the class.
generateGradleTokenClass = codechicken.nei.Tags
gradleTokenModId = MODID
gradleTokenModName = MODNAME
# Name of the token containing the project's current version to generate/replace.
gradleTokenVersion = VERSION
gradleTokenGroupName = GROUPNAME
# [DEPRECATED] Mod ID replacement token.
gradleTokenModId =
# [DEPRECATED] Mod name replacement token.
gradleTokenModName =
# [DEPRECATED] Mod Group replacement token.
gradleTokenGroupName =
# [DEPRECATED]
# Multiple source files can be defined here by providing a comma-seperated list: Class1.java,Class2.java,Class3.java
# Multiple source files can be defined here by providing a comma-separated list: Class1.java,Class2.java,Class3.java
# public static final String VERSION = "GRADLETOKEN_VERSION";
# The string's content will be replaced with your mod's version when compiled. You should use this to specify your mod's
# version in @Mod([...], version = VERSION, [...])
# Leave these properties empty to skip individual token replacements
# version in @Mod([...], version = VERSION, [...]).
# Leave these properties empty to skip individual token replacements.
replaceGradleTokenInFile =
# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can
# leave this property empty.
# Example value: apiPackage = api + modGroup = com.myname.mymodid -> com.myname.mymodid.api
# Example value: (apiPackage = api) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.api
apiPackage =
# Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/META-INF/
# Example value: mymodid_at.cfg
# There can be multiple files in a space-separated list.
# Example value: mymodid_at.cfg nei_at.cfg
accessTransformersFile = nei_at.cfg
# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled!
usesMixins = false
# Specify the location of your implementation of IMixinPlugin. Leave it empty otherwise.
# Set to a non-empty string to configure mixins in a separate source set under src/VALUE, instead of src/main.
# This can speed up compile times thanks to not running the mixin annotation processor on all input sources.
# Mixin classes will have access to "main" classes, but not the other way around.
separateMixinSourceSet =
# Adds some debug arguments like verbose output and class export.
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!
mixinsPackage =
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
# This parameter is for legacy compatibility only
# Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin
# Example value: (coreModClass = asm.FMLPlugin) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.asm.FMLPlugin
coreModClass = asm.NEICorePlugin
# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class
# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false!
containsMixinsAndOrCoreModOnly = true
# If enabled, you may use 'shadowImplementation' for dependencies. They will be integrated in your jar. It is your
# responsibility check the licence and request permission for distribution, if required.
# Enables Mixins even if this mod doesn't use them, useful if one of the dependencies uses mixins.
forceEnableMixins = false
# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated into your jar. It is your
# responsibility to check the license and request permission for distribution if required.
usesShadowedDependencies = true
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
# If disabled, won't remove unused classes from shadowed dependencies. Some libraries use reflection to access
# their own classes, making the minimization unreliable.
minimizeShadowedDependencies = true
# The project's numeric ID on CurseForge. You can find this in the About Project box.
# Leave this empty if you don't want to publish on CurseForge.
curseForgeProjectId = 358228
# If disabled, won't rename the shadowed classes.
relocateShadowedDependencies = true
# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge.
# Syntax: type1:name1;type2:name2;...
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
# and the name is the CurseForge project id of the other mod.
curseForgeRelations = requiredDependency:codechickencore-unofficial;requiredDependency:codechickenlib-unofficial
# Adds CurseMaven, Modrinth, and some more well-known 1.7.10 repositories.
includeWellKnownRepositories = true
# A list of repositories to exclude from the includeWellKnownRepositories setting. Should be a space separated
# list of strings, with the acceptable keys being(case does not matter):
# cursemaven
# modrinth
excludeWellKnownRepositories =
# Publishing to modrinth requires you to set the MODRINTH_TOKEN environment variable to your current modrinth API token.
# Change these to your Maven coordinates if you want to publish to a custom Maven repository instead of the default GTNH Maven.
# Authenticate with the MAVEN_USER and MAVEN_PASSWORD environment variables.
# If you need a more complex setup disable maven publishing here and add a publishing repository to addon.gradle.
usesMavenPublishing = true
# Maven repository to publish the mod to.
# mavenPublishUrl = https\://nexus.gtnewhorizons.com/repository/releases/
# Publishing to Modrinth requires you to set the MODRINTH_TOKEN environment variable to your current Modrinth API token.
#
# The project's ID on Modrinth. Can be either the slug or the ID.
# Leave this empty if you don't want to publish on Modrinth.
# Leave this empty if you don't want to publish to Modrinth.
modrinthProjectId = notenoughitems-unofficial
# The project's relations on Modrinth. You can use this to refer to other projects on Modrinth.
@@ -92,7 +150,54 @@ modrinthProjectId = notenoughitems-unofficial
# Where scope can be one of [required, optional, incompatible, embedded],
# type can be one of [project, version],
# and the name is the Modrinth project or version slug/id of the other mod.
# Example: required-project:fplib;optional-project:gasstation;incompatible-project:gregtech
# Note: GTNH Mixins is automatically set as a required dependency if usesMixins = true
modrinthRelations = required-project\:codechickencore-unofficial
modrinthRelations = required-project:codechickenlib-unofficial;required-project:codechickencore-unofficial
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
#
# The project's numeric ID on CurseForge. You can find this in the About Project box.
# Leave this empty if you don't want to publish on CurseForge.
curseForgeProjectId = 358228
# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge.
# Syntax: type1:name1;type2:name2;...
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
# and the name is the CurseForge project slug of the other mod.
# Example: requiredDependency:railcraft;embeddedLibrary:cofhlib;incompatible:buildcraft
# Note: UniMixins is automatically set as a required dependency if usesMixins = true.
curseForgeRelations = requiredDependency\:codechickencore-unofficial
# Optional parameter to customize the produced artifacts. Use this to preserve artifact naming when migrating older
# projects. New projects should not use this parameter.
# customArchiveBaseName =
# 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.
# Note: the specified string must be escaped, so e.g. 1\\.1\\.\\d+ instead of 1\.1\.\d+
# versionPattern =
# Uncomment to prevent the source code from being published.
# noPublishedSources = true
# Uncomment this to disable Spotless checks.
# This should only be uncommented to keep it easier to sync with upstream/other forks.
# That is, if there is no other active fork/upstream, NEVER change this.
# disableSpotless = true
# Uncomment this to disable Checkstyle checks (currently wildcard import check).
# disableCheckstyle = true
# Override the IDEA build type. Valid values are: "" (leave blank, do not override), "idea" (force use native IDEA build), "gradle"
# (force use delegated build).
# This is meant to be set in $HOME/.gradle/gradle.properties.
# e.g. add "systemProp.org.gradle.project.ideaOverrideBuildType=idea" will override the build type to be native build.
# WARNING: If you do use this option, it will overwrite whatever you have in your existing projects. This might not be what you want!
# Usually there is no need to uncomment this here as other developers do not necessarily use the same build type as you.
# ideaOverrideBuildType = idea
# Whether IDEA should run spotless checks when pressing the Build button.
# This is meant to be set in $HOME/.gradle/gradle.properties.
# ideaCheckSpotlessOnBuild = true
Binary file not shown.
+2 -1
View File
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+16 -10
View File
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/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/.
@@ -83,7 +85,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -130,10 +133,13 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
@@ -141,7 +147,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@@ -149,7 +155,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -198,11 +204,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
Vendored
+12 -10
View File
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
+4
View File
@@ -1,4 +1,8 @@
// Add any additional repositiroes for your dependencies here
repositories {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
+5 -10
View File
@@ -4,10 +4,10 @@ pluginManagement {
maven {
// RetroFuturaGradle
name "GTNH Maven"
url "http://jenkins.usrv.eu:8081/nexus/content/groups/public/"
allowInsecureProtocol = true
url "https://nexus.gtnewhorizons.com/repository/public/"
mavenContent {
includeGroup("com.gtnewhorizons.retrofuturagradle")
includeGroup("com.gtnewhorizons")
includeGroupByRegex("com\\.gtnewhorizons\\..+")
}
}
gradlePluginPortal()
@@ -17,15 +17,10 @@ pluginManagement {
}
plugins {
id 'com.diffplug.blowdryerSetup' version '1.6.0'
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.4.0' // Provides java toolchains
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.38'
}
blowdryerSetup {
repoSubfolder 'gtnhShared'
github('GTNewHorizons/ExampleMod1.7.10', 'tag', '0.2.0')
//devLocal '.' // Use this when testing config updates locally
}
rootProject.name = "NotEnoughItems"
@@ -0,0 +1,125 @@
package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.getMousePosition;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.settings.GameSettings;
import org.lwjgl.input.Keyboard;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
public class AutoFocusWidget implements IContainerInputHandler {
/**
* Implement this interface on a GuiContainer to enable the autofocus search in NEI (if the autofocus option is
* enabled) without needing to add the classname to the config file .
*/
public interface INEIAutoFocusSearchEnable {
}
public static AutoFocusWidget instance = new AutoFocusWidget();
public static List<String> enableAutoFocusPrefixes = new ArrayList<>();
protected boolean autofocus = false;
protected Point mouse;
public AutoFocusWidget() {
GuiContainerManager.addInputHandler(this);
}
public void load(GuiContainer gui) {
this.autofocus = LayoutManager.searchField.isVisible() && NEIClientConfig.searchWidgetAutofocus() != 0
&& isAllowedGuiAutoSearchFocus(gui);
this.mouse = getMousePosition();
}
@Override
public boolean keyTyped(GuiContainer gui, char keyChar, int keyCode) {
if (this.autofocus) {
this.autofocus = false;
if (!this.mouse.equals(getMousePosition())) {
return false;
}
if (NEIClientConfig.searchWidgetAutofocus() == 2
&& GameSettings.isKeyDown(Minecraft.getMinecraft().gameSettings.keyBindInventory)) {
return false;
}
if (keyCode == Keyboard.KEY_RETURN || keyCode == Keyboard.KEY_NUMPADENTER
|| keyCode == Keyboard.KEY_ESCAPE) {
return false;
}
LayoutManager.searchField.setFocus(true);
LayoutManager.searchField.handleKeyPress(keyCode, keyChar);
return true;
}
return false;
}
@Override
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
return false;
}
@Override
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
this.autofocus = false;
return false;
}
@Override
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
this.autofocus = false;
return false;
}
@Override
public void onKeyTyped(GuiContainer gui, char keyChar, int keyID) {}
@Override
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
this.autofocus = false;
}
@Override
public void onMouseDragged(GuiContainer gui, int mousex, int mousey, int button, long heldTime) {
this.autofocus = false;
}
@Override
public void onMouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
this.autofocus = false;
}
@Override
public void onMouseUp(GuiContainer gui, int mousex, int mousey, int button) {
this.autofocus = false;
}
protected boolean isAllowedGuiAutoSearchFocus(GuiContainer gui) {
if (gui instanceof INEIAutoFocusSearchEnable) {
return true;
}
String guiClassName = gui.getClass().getName();
for (String prefix : enableAutoFocusPrefixes) {
if (guiClassName.startsWith(prefix)) {
return true;
}
}
return false;
}
}
@@ -22,7 +22,10 @@ public class BookmarkContainerInfo {
}
public static IBookmarkContainerHandler getBookmarkContainerHandler(GuiContainer gui) {
return handlerMap.get(gui.getClass());
if (gui != null) {
return handlerMap.get(gui.getClass());
}
return null;
}
public static void load() {
File diff suppressed because it is too large. Load diff
+122 -91
View File
@@ -1,19 +1,19 @@
package codechicken.nei;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
@@ -28,38 +28,37 @@ import net.minecraft.entity.item.EntityItem;
import net.minecraft.world.World;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.WorldEvent;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.io.IOUtils;
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;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.StackInfo;
import cpw.mods.fml.client.CustomModLoadingErrorDisplayException;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModClassLoader;
import cpw.mods.fml.common.discovery.ASMDataTable;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class ClientHandler {
private static String[] defaultHandlerOrdering = {
"# Each line in this file should either be a comment (starts with '#') or an ordering.",
"# Ordering lines are <handler ID>,<ordering number>.",
"# Handlers will be sorted in order of number ascending, so smaller numbers first.",
"# Any handlers that are missing from this file will be assigned to 0.", "# Negative numbers are fine.",
"# If you delete this file, it will be regenerated with all registered handler IDs.", };
private static ClientHandler instance;
private ArrayList<EntityItem> SMPmagneticItems = new ArrayList<>();
private final ArrayList<EntityItem> SMPmagneticItems = new ArrayList<>();
private World lastworld;
private GuiScreen lastGui;
@@ -144,57 +143,77 @@ public class ClientHandler {
public static void preInit() {
loadSerialHandlers();
loadHiddenItems();
loadHeightHackHandlers();
loadHiddenHandlers();
loadEnableAutoFocus();
ItemInfo.preInit();
StackInfo.loadGuidFilters();
}
public static void loadSerialHandlers() {
File file = NEIClientConfig.serialHandlersFile;
public static void loadSettingsFile(String resource, Consumer<Stream<String>> callback) {
loadSettingsFile(resource, (file, writer) -> {
String folder = resource.substring(resource.lastIndexOf(".") + 1);
URL defaultResource = ClientHandler.class.getResource("/assets/nei/" + folder + "/" + resource);
if (defaultResource != null) {
try {
IOUtils.copy(defaultResource.openStream(), writer);
} catch (IOException e) {}
}
}, callback);
}
public static void loadSettingsFile(String resource, BiConsumer<File, FileWriter> createDefault,
Consumer<Stream<String>> callback) {
File file = new File(NEIClientConfig.configDir, resource);
if (!file.exists()) {
try (FileWriter writer = new FileWriter(file)) {
NEIClientConfig.logger.info("Creating default serial handlers list {}", file);
URL defaultSerialHandlersResource = ClientHandler.class
.getResource("/assets/nei/cfg/serialhandlers.cfg");
if (defaultSerialHandlersResource != null) {
IOUtils.copy(defaultSerialHandlersResource.openStream(), writer);
}
NEIClientConfig.logger.info("Creating default '{}' {}", resource, file);
createDefault.accept(file, writer);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to save default serial handlers list to file {}", file, e);
NEIClientConfig.logger.error("Failed to save default '{}' to file {}", resource, file, e);
}
}
try (FileReader reader = new FileReader(file)) {
NEIClientConfig.logger.info("Loading serial handlers from file {}", file);
NEIClientConfig.serialHandlers = IOUtils.readLines(reader).stream().filter((line) -> !line.startsWith("#"))
.collect(Collectors.toCollection(HashSet::new));
NEIClientConfig.logger.info("Loading '{}' file {}", resource, file);
callback.accept(
IOUtils.readLines(reader).stream().filter(line -> !line.startsWith("#") && !line.trim().isEmpty()));
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load serial handlers from file {}", file, e);
NEIClientConfig.logger.error("Failed to load '{}' file {}", resource, file, e);
}
}
public static void loadHeightHackHandlers() {
File file = NEIClientConfig.heightHackHandlersFile;
if (!file.exists()) {
try (FileWriter writer = new FileWriter(file)) {
NEIClientConfig.logger.info("Creating default height hack handlers list {}", file);
URL defaultHeightHackHandlersResource = ClientHandler.class
.getResource("/assets/nei/cfg/heighthackhandlers.cfg");
if (defaultHeightHackHandlersResource != null) {
IOUtils.copy(defaultHeightHackHandlersResource.openStream(), writer);
}
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to save default height hack handlers list to file {}", file, e);
}
}
public static void loadSerialHandlers() {
loadSettingsFile(
"serialhandlers.cfg",
lines -> NEIClientConfig.serialHandlers = lines.collect(Collectors.toCollection(HashSet::new)));
}
try (FileReader reader = new FileReader(file)) {
NEIClientConfig.logger.info("Loading height hack handlers from file {}", file);
NEIClientConfig.heightHackHandlerRegex = IOUtils.readLines(reader).stream()
.filter((line) -> !line.startsWith("#")).map(Pattern::compile)
.collect(Collectors.toCollection(HashSet::new));
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load height hack handlers from file {}", file, e);
}
public static void loadHeightHackHandlers() {
loadSettingsFile(
"heighthackhandlers.cfg",
lines -> NEIClientConfig.heightHackHandlerRegex = lines.map(Pattern::compile)
.collect(Collectors.toCollection(HashSet::new)));
}
public static void loadHiddenHandlers() {
loadSettingsFile(
"hiddenhandlers.cfg",
lines -> NEIClientConfig.hiddenHandlers = lines.collect(Collectors.toCollection(HashSet::new)));
}
public static void loadEnableAutoFocus() {
loadSettingsFile(
"enableautofocus.cfg",
lines -> AutoFocusWidget.enableAutoFocusPrefixes = lines
.collect(Collectors.toCollection(ArrayList::new)));
}
public static void loadHiddenItems() {
loadSettingsFile("hiddenitems.cfg", lines -> lines.forEach(API::hideItem));
}
public static void load() {
@@ -211,53 +230,55 @@ public class ClientHandler {
}
public static void postInit() {
loadHandlerOrdering();
GuiContainerManager.registerReloadResourceListener();
}
public static void loadHandlerOrdering() {
File file = NEIClientConfig.handlerOrderingFile;
if (!file.exists()) {
try (FileWriter writer = new FileWriter(file)) {
NEIClientConfig.logger.info("Creating default handler ordering CSV {}", file);
List<String> toWrite = Lists.newArrayList(defaultHandlerOrdering);
GuiRecipeTab.handlerMap.keySet().stream().sorted()
.forEach(handlerId -> toWrite.add(String.format("%s,0", handlerId)));
final String COMMA_DELIMITER = ",";
final String[] defaultHandlerOrdering = {
"# Each line in this file should either be a comment (starts with '#') or an ordering.",
"# Ordering lines are <handler ID>,<ordering number>.",
"# Handlers will be sorted in order of number ascending, so smaller numbers first.",
"# Any handlers that are missing from this file will be assigned to 0.", "# Negative numbers are fine.",
"# If you delete this file, it will be regenerated with all registered handler IDs.", };
loadSettingsFile("handlerordering.csv", (file, writer) -> {
List<String> toWrite = Lists.newArrayList(defaultHandlerOrdering);
GuiRecipeTab.handlerMap.keySet().stream().sorted()
.forEach(handlerId -> toWrite.add(String.format("%s" + COMMA_DELIMITER + "0", handlerId)));
try {
IOUtils.writeLines(toWrite, "\n", writer);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to save default handler ordering to file {}", file, e);
}
}
} catch (IOException e) {}
}, lines -> lines.map(line -> line.split(COMMA_DELIMITER)).filter(parts -> parts.length == 2).forEach(parts -> {
String handlerId = parts[0];
int ordering = Integer.parseInt(parts[1]);
NEIClientConfig.handlerOrdering.put(handlerId, ordering);
}));
}
URL url;
try {
url = file.toURI().toURL();
} catch (MalformedURLException e) {
NEIClientConfig.logger.info("Invalid URL for handler ordering CSV.");
e.printStackTrace();
return;
}
public static void loadPluginsList() {
if (!Loader.isModLoaded("jarjar")) {
// Do the old style class discovery
final ClassDiscoverer classDiscoverer = new ClassDiscoverer(
test -> test.startsWith("NEI") && test.endsWith("Config.class"),
IConfigureNEI.class);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) {
NEIClientConfig.logger.info("Loading handler ordering from file {}", file);
CSVParser csvParser = CSVFormat.EXCEL.withCommentMarker('#').parse(reader);
for (CSVRecord record : csvParser) {
final String handlerId = record.get(0);
int ordering;
NEIClientConfig.pluginsList.addAll(classDiscoverer.findClasses());
} else {
// If JarJar's loaded, the ASMDataTable now includes interfaces in addition to Annotations, so use that
// instead Includes a small change in behavior of no longer requiring the class to start with NEI and end
// with Config; This could easily be changed if desired, but the previous behavior was likely to speed
// things up by limiting the scope when looking at all of the jars and classes in the classpath.
final ASMDataTable dataTable = NEIModContainer.getAsmDataTable();
final ModClassLoader modClassLoader = (ModClassLoader) Loader.instance().getModClassLoader();
for (ASMDataTable.ASMData asmData : dataTable.getAll(IConfigureNEI.class.getName().replace('.', '/'))) {
final String className = asmData.getClassName().replace('/', '.');
try {
ordering = Integer.parseInt(record.get(1));
} catch (NumberFormatException e) {
NEIClientConfig.logger.error("Error parsing CSV record {}: {}", record, e);
continue;
NEIClientConfig.pluginsList.add(Class.forName(className, true, modClassLoader));
} catch (ClassNotFoundException e) {
NEIClientConfig.logger.error("Failed to load plugin class {}", className, e);
}
NEIClientConfig.handlerOrdering.put(handlerId, ordering);
}
} catch (Exception e) {
NEIClientConfig.logger.info("Error parsing CSV");
e.printStackTrace();
}
}
@@ -305,20 +326,29 @@ public class ClientHandler {
if (NEIClientConfig.isEnabled()) WorldOverlayRenderer.render(event.partialTicks);
}
@SideOnly(Side.CLIENT)
@SubscribeEvent
public void onWorldUnload(WorldEvent.Unload event) {
Minecraft mc = Minecraft.getMinecraft();
if (event.world == mc.theWorld) {
NEIClientConfig.unloadWorld();
}
}
public void loadWorld(World world, boolean fromServer) {
if (world != lastworld) {
SMPmagneticItems.clear();
WorldOverlayRenderer.reset();
if (!NEIClientConfig.getBooleanSetting("world.overlays.lock")) {
WorldOverlayRenderer.reset();
}
if (!fromServer) {
NEIClientConfig.setHasSMPCounterPart(false);
NEIClientConfig.setInternalEnabled(false);
if (!Minecraft.getMinecraft().isSingleplayer()) // wait for server to initiate in singleplayer
NEIClientConfig.loadWorld("remote/" + ClientUtils.getServerIP().replace(':', '~'));
ItemMobSpawner.clearEntityReferences(world);
}
ItemMobSpawner.clearEntityReferences(world);
lastworld = world;
}
@@ -346,9 +376,10 @@ public class ClientHandler {
}
};
@SuppressWarnings("serial")
CustomModLoadingErrorDisplayException e = new CustomModLoadingErrorDisplayException() {
private static final long serialVersionUID = -5593387489666663375L;
@Override
public void initGui(GuiErrorScreen errorScreen, FontRenderer fontRenderer) {
Minecraft.getMinecraft().displayGuiScreen(errorGui);
@@ -0,0 +1,251 @@
package codechicken.nei;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase.NBTPrimitive;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.StatCollector;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import codechicken.nei.ItemList.AnyMultiItemFilter;
import codechicken.nei.ItemList.EverythingItemFilter;
import codechicken.nei.ItemList.NothingItemFilter;
import codechicken.nei.PresetsList.Preset;
import codechicken.nei.PresetsList.PresetMode;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.util.ItemStackFilterParser;
public class CollapsibleItems {
protected static class GroupItem {
public String guid;
public ItemFilter filter;
public boolean expanded = false;
public String displayName = "";
public void setFilter(String filter) {
this.filter = ItemStackFilterParser.parse(filter.trim());
this.guid = this.filter != null ? UUID.nameUUIDFromBytes(filter.getBytes()).toString() : "";
}
public void setFilter(ItemFilter filter, String guid) {
this.filter = filter;
this.guid = guid;
}
public boolean matches(ItemStack stack) {
return this.filter.matches(stack);
}
}
private static final String STATE_KEY = "collapsibleitems";
protected static File statesFile;
protected static final List<GroupItem> groups = new ArrayList<>();
protected static final Map<ItemStack, Integer> cache = new ConcurrentHashMap<>();
private CollapsibleItems() {}
public static void load() {
CollapsibleItems.groups.clear();
CollapsibleItems.cache.clear();
for (int i = PresetsList.presets.size() - 1; i >= 0; i--) {
Preset preset = PresetsList.presets.get(i);
if (preset.enabled && preset.mode == PresetMode.GROUP) {
GroupItem group = new GroupItem();
group.setFilter(preset, UUID.nameUUIDFromBytes(preset.items.toString().getBytes()).toString());
group.displayName = preset.name;
addGroup(group);
}
}
if (NEIClientConfig.enableCollapsibleItems()) {
ClientHandler.loadSettingsFile(
"collapsibleitems.cfg",
lines -> parseFile(lines.collect(Collectors.toCollection(ArrayList::new))));
}
loadStates();
}
private static void parseFile(List<String> itemStrings) {
final JsonParser parser = new JsonParser();
GroupItem group = new GroupItem();
for (String itemStr : itemStrings) {
try {
if (itemStr.startsWith("; ")) {
JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
if (settings.get("displayName") != null) {
group.displayName = settings.get("displayName").getAsString();
}
if (settings.get("unlocalizedName") != null) {
String unlocalizedName = settings.get("unlocalizedName").getAsString();
String displayName = StatCollector.translateToLocal(unlocalizedName);
if (!displayName.equals(unlocalizedName)) {
group.displayName = displayName;
}
}
if (settings.get("expanded") != null) {
group.expanded = settings.get("expanded").getAsBoolean();
}
} else {
group.setFilter(itemStr);
}
if (group != null && group.filter != null) {
addGroup(group);
group = new GroupItem();
}
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
NEIClientConfig.logger.error("Failed to load collapsible items from json string:\n{}", itemStr);
}
}
}
private static void addGroup(GroupItem group) {
if (group == null || group.filter == null
|| group.filter instanceof EverythingItemFilter
|| group.filter instanceof NothingItemFilter)
return;
CollapsibleItems.groups.add(group);
}
public static boolean isEmpty() {
return CollapsibleItems.groups.isEmpty();
}
public static ItemFilter getItemFilter() {
AnyMultiItemFilter filter = new AnyMultiItemFilter();
for (GroupItem group : CollapsibleItems.groups) {
filter.filters.add(group.filter);
}
return filter;
}
public static void clearCache() {
CollapsibleItems.cache.clear();
}
public static void putItem(ItemStack stack) {
int groupIndex = -1;
for (int i = 0; i < CollapsibleItems.groups.size() && groupIndex == -1; i++) {
if (CollapsibleItems.groups.get(i).matches(stack)) {
groupIndex = i;
}
}
if (groupIndex != -1) {
CollapsibleItems.cache.put(stack, groupIndex);
}
}
public static int getGroupIndex(ItemStack stack) {
if (stack == null) {
return -1;
}
return CollapsibleItems.cache.getOrDefault(stack, -1);
}
public static String getDisplayName(int groupIndex) {
if (groupIndex < CollapsibleItems.groups.size()) {
return CollapsibleItems.groups.get(groupIndex).displayName;
}
return null;
}
public static boolean isExpanded(int groupIndex) {
if (groupIndex < CollapsibleItems.groups.size()) {
return CollapsibleItems.groups.get(groupIndex).expanded;
}
return true;
}
public static void setExpanded(int groupIndex, boolean expanded) {
if (groupIndex < CollapsibleItems.groups.size()) {
CollapsibleItems.groups.get(groupIndex).expanded = expanded;
}
}
public static void toggleGroups(Boolean expanded) {
if (expanded == null) {
expanded = CollapsibleItems.groups.stream().noneMatch(g -> g.expanded);
}
for (GroupItem group : CollapsibleItems.groups) {
group.expanded = expanded;
}
}
public static void saveStates() {
NBTTagCompound list = new NBTTagCompound();
for (GroupItem group : CollapsibleItems.groups) {
list.setBoolean(group.guid, group.expanded);
}
if (NEIClientConfig.world != null) {
NEIClientConfig.world.nbt.setTag(STATE_KEY, list);
}
}
private static void loadStates() {
try {
if (NEIClientConfig.world.nbt.hasKey(STATE_KEY)) {
NBTTagCompound states = NEIClientConfig.world.nbt.getCompoundTag(STATE_KEY);
@SuppressWarnings("unchecked")
final Map<String, NBTPrimitive> list = (Map<String, NBTPrimitive>) states.tagMap;
final Map<String, GroupItem> mapping = new HashMap<>();
for (GroupItem group : CollapsibleItems.groups) {
mapping.put(group.guid, group);
}
for (Map.Entry<String, NBTPrimitive> nbtEntry : list.entrySet()) {
if (mapping.containsKey(nbtEntry.getKey())) {
mapping.get(nbtEntry.getKey()).expanded = nbtEntry.getValue().func_150290_f() == 1;
}
}
}
} catch (Exception e) {
NEIClientConfig.logger.error("Error loading collapsible items states", e);
}
}
}
@@ -81,7 +81,6 @@ public class ContainerPotionCreator extends ContainerExtended {
public void markDirty() {
super.markDirty();
NEIClientConfig.global.nbt.setTag("potionStore", tag);
NEIClientConfig.global.saveNBT();
}
}
@@ -117,7 +116,6 @@ public class ContainerPotionCreator extends ContainerExtended {
if (!player.worldObj.isRemote) InventoryUtils.dropOnClose(player, potionInv);
}
@SuppressWarnings("unchecked")
@Override
public void handleServerPacket(PacketCustom packet) {
ItemStack potion = potionInv.getStackInSlot(0);
@@ -0,0 +1,228 @@
package codechicken.nei;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
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.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.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
public class FavoriteRecipes {
private static final Map<NBTTagCompound, RecipeId> items = new HashMap<>();
private static final Map<String, RecipeId> fluids = new HashMap<>();
private static File favoriteFile;
static {
API.addSubset("Favorites", FavoriteRecipes::contains);
}
private FavoriteRecipes() {}
public static void load() {
String worldPath = "global";
if (NEIClientConfig.getBooleanSetting("inventory.favorites.worldSpecific")) {
worldPath = NEIClientConfig.getWorldPath();
}
final File dir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
if (!dir.exists()) {
dir.mkdirs();
}
favoriteFile = new File(dir, "favorites.ini");
if (!favoriteFile.exists()) {
final File globalFavorites = new File(CommonUtils.getMinecraftDir(), "saves/NEI/global/favorites.ini");
final File configFavorites = new File(NEIClientConfig.configDir, "favorites.ini");
final File defaultFavorites = configFavorites.exists() ? configFavorites : globalFavorites;
if (defaultFavorites.exists()) {
try {
if (favoriteFile.createNewFile()) {
InputStream src = new FileInputStream(defaultFavorites);
OutputStream dst = new FileOutputStream(favoriteFile);
IOUtils.copy(src, dst);
src.close();
dst.close();
}
} catch (IOException e) {}
}
}
loadData();
}
private static void loadData() {
if (favoriteFile == null || !favoriteFile.exists()) {
return;
}
List<String> itemStrings;
try (FileInputStream reader = new FileInputStream(favoriteFile)) {
NEIClientConfig.logger.info("Loading favorites from file {}", favoriteFile);
itemStrings = IOUtils.readLines(reader, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load favorites from file {}", favoriteFile, e);
return;
}
final JsonParser parser = new JsonParser();
items.clear();
for (String itemStr : itemStrings) {
if (itemStr.isEmpty() || itemStr.startsWith("#")) {
continue;
}
try {
JsonObject jsonObject = parser.parse(itemStr).getAsJsonObject();
if (jsonObject.get("item") != null && jsonObject.get("recipeId") != null) {
final NBTTagCompound itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject.get("item"));
final RecipeId recipeId = RecipeId.of(jsonObject.getAsJsonObject("recipeId"));
final ItemStack stack = StackInfo.loadFromNBT(itemStackNBT);
if (stack != null) {
final String fluidKey = getFluidKey(stack);
if (fluidKey != null) {
fluids.put(fluidKey, recipeId);
}
}
items.put(itemStackNBT, recipeId);
}
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
NEIClientConfig.logger.error("Failed to load favorite from json string:\n{}", itemStr);
}
}
SubsetWidget.updateHiddenItems();
}
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));
}
return recipeId;
}
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());
}
}
return 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);
items.entrySet().removeIf(entry -> entry.getKey().equals(itemStackNBT) || entry.getValue().equals(recipeId));
fluids.entrySet().removeIf(entry -> entry.getKey().equals(fluidKey) || entry.getValue().equals(recipeId));
if (recipeId != null) {
items.put(itemStackNBT, recipeId);
if (fluidKey != null) {
fluids.put(fluidKey, recipeId);
}
}
SubsetWidget.updateHiddenItems();
ItemList.updateFilter.restart();
}
private static String getFluidKey(ItemStack stack) {
final FluidStack fluid = StackInfo.getFluid(stack);
if (fluid != null) {
return FluidRegistry.getFluidName(fluid);
}
return null;
}
public static void save() {
if (favoriteFile == null) {
return;
}
final List<String> strings = new ArrayList<>();
for (Map.Entry<NBTTagCompound, RecipeId> entry : items.entrySet()) {
try {
final JsonObject line = new JsonObject();
line.add("item", NBTJson.toJsonObject(entry.getKey()));
line.add("recipeId", entry.getValue().toJsonObject());
strings.add(NBTJson.toJson(line));
} catch (JsonSyntaxException e) {
NEIClientConfig.logger.error("Failed to stringify favorites ItemStack to json string");
}
}
try (FileOutputStream output = new FileOutputStream(favoriteFile)) {
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save favorites list to file {}", favoriteFile, e);
}
}
}
@@ -0,0 +1,308 @@
package codechicken.nei;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.ChatAllowedCharacters;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
public class FormattedTextField extends GuiTextField {
public static interface TextFormatter {
TextFormatter DEFAULT = (text) -> text;
public String format(String text);
}
protected FontRenderer fontRenderer;
protected String rawText = "";
protected String formattedText = "";
protected String placeholder = "";
protected boolean editable = true;
protected int editableColor = 14737632;
protected int notEditableColor = 7368816;
protected TextFormatter formatter = TextFormatter.DEFAULT;
protected int lineScrollOffset = 0;
protected int frame = 0;
public FormattedTextField(FontRenderer fontRenderer, int xPosition, int yPosition, int width, int height) {
super(fontRenderer, xPosition, yPosition, width, height);
this.fontRenderer = fontRenderer;
}
public void setFormatter(TextFormatter formatter) {
this.formatter = formatter;
}
public void setPlaceholder(String placeholder) {
this.placeholder = placeholder;
}
@Override
public void updateCursorCounter() {
super.updateCursorCounter();
++this.frame;
}
@Override
public void setFocused(boolean focus) {
if (focus && !this.isFocused()) {
this.frame = 0;
}
super.setFocused(focus);
}
@Override
public void setSelectionPos(int p_146199_1_) {
String text = this.getText();
int j = text.length();
super.setSelectionPos(p_146199_1_);
p_146199_1_ = Math.max(0, Math.min(p_146199_1_, j));
if (this.fontRenderer != null) {
if (this.lineScrollOffset > j) {
this.lineScrollOffset = j;
}
int k = this.getWidth();
String s = this.fontRenderer.trimStringToWidth(text.substring(this.lineScrollOffset), k);
int l = s.length() + this.lineScrollOffset;
if (p_146199_1_ == this.lineScrollOffset) {
this.lineScrollOffset -= this.fontRenderer.trimStringToWidth(text, k, true).length();
}
if (p_146199_1_ > l) {
this.lineScrollOffset += p_146199_1_ - l;
} else if (p_146199_1_ <= this.lineScrollOffset) {
this.lineScrollOffset -= this.lineScrollOffset - p_146199_1_;
}
this.lineScrollOffset = Math.max(0, Math.min(this.lineScrollOffset, j));
}
}
@Override
public void setTextColor(int p_146193_1_) {
super.setTextColor(p_146193_1_);
this.editableColor = p_146193_1_;
}
@Override
public void setDisabledTextColour(int p_146204_1_) {
super.setDisabledTextColour(p_146204_1_);
this.notEditableColor = p_146204_1_;
}
@Override
public void setEnabled(boolean p_146184_1_) {
super.setEnabled(p_146184_1_);
this.editable = p_146184_1_;
}
protected boolean beforeWrite(String text) {
return true;
}
@Override
public void writeText(String textPart) {
String newText = "";
String substr = ChatAllowedCharacters.filerAllowedCharacters(textPart);
int cursorPosition = getCursorPosition();
int maxStringLength = getMaxStringLength();
String text = getText();
if (text.isEmpty()) {
newText = substr.substring(0, Math.min(maxStringLength, substr.length()));
cursorPosition = newText.length();
} else {
int selectionEnd = getSelectionEnd();
String textStart = text.substring(0, Math.min(cursorPosition, selectionEnd));
String textEnd = text.substring(Math.max(cursorPosition, selectionEnd));
newText = textStart + substr + textEnd;
if (newText.length() > maxStringLength) {
newText = newText.substring(0, maxStringLength);
}
cursorPosition = Math.min(textStart.length() + substr.length(), newText.length());
}
if (beforeWrite(newText)) {
setText(newText);
setCursorPosition(cursorPosition);
}
}
@Override
public int getNthWordFromPos(int p_146183_1_, int p_146183_2_) {
return this.func_146197_a(p_146183_1_, p_146183_2_, true);
}
@Override
public void drawTextBox() {
if (!this.getVisible()) {
return;
}
if (this.getEnableBackgroundDrawing()) {
drawRect(
this.xPosition - 1,
this.yPosition - 1,
this.xPosition + this.width + 1,
this.yPosition + this.height + 1,
-6250336);
drawRect(
this.xPosition,
this.yPosition,
this.xPosition + this.width,
this.yPosition + this.height,
-16777216);
}
if (!this.rawText.equals(getText())) {
this.rawText = getText();
this.formattedText = this.formatter.format(this.rawText);
if (!EnumChatFormatting.getTextWithoutFormattingCodes(this.formattedText).toLowerCase()
.equals(this.rawText.toLowerCase())) {
this.formattedText = this.rawText;
}
}
if (!isFocused() && this.formattedText.isEmpty()) {
int x = getEnableBackgroundDrawing() ? this.xPosition + 4 : this.xPosition;
int y = getEnableBackgroundDrawing() ? this.yPosition + (this.height - 8) / 2 : this.yPosition;
this.fontRenderer.drawStringWithShadow(
this.fontRenderer.trimStringToWidth(this.placeholder, this.getWidth()),
x,
y,
this.notEditableColor);
return;
}
int firstCharacterIndex = getFormattedTextShift(this.lineScrollOffset);
String rawTextClipped = this.fontRenderer
.trimStringToWidth(this.rawText.substring(this.lineScrollOffset), this.getWidth());
String textClipped = this.formattedText
.substring(firstCharacterIndex, getFormattedTextShift(this.lineScrollOffset + rawTextClipped.length()));
int cursorPosition = getFormattedTextShift(getCursorPosition());
int selectionEnd = getFormattedTextShift(getSelectionEnd());
int color = this.editable ? this.editableColor : this.notEditableColor;
int cursorA = cursorPosition - firstCharacterIndex;
int cursorB = selectionEnd - firstCharacterIndex;
boolean flag = cursorA >= 0 && cursorA <= textClipped.length();
boolean flag1 = isFocused() && this.frame / 6 % 2 == 0 && flag;
boolean flag2 = getCursorPosition() < this.rawText.length() || this.rawText.length() >= getMaxStringLength();
int x = getEnableBackgroundDrawing() ? this.xPosition + 4 : this.xPosition;
int y = getEnableBackgroundDrawing() ? this.yPosition + (this.height - 8) / 2 : this.yPosition;
int x2 = x;
if (cursorB > textClipped.length()) {
cursorB = textClipped.length();
}
if (textClipped.length() > 0) {
String s1 = flag ? textClipped.substring(0, cursorA) : textClipped;
String colorA = getPreviousColor(firstCharacterIndex);
x2 = this.fontRenderer.drawStringWithShadow(colorA + s1, x, y, color);
}
int k1 = x2;
if (!flag) {
k1 = cursorA > 0 ? x + this.width : x;
} else if (flag2) {
k1 = x2 - 1;
--x2;
}
if (textClipped.length() > 0 && flag && cursorA < textClipped.length()) {
String colorB = getPreviousColor(firstCharacterIndex + cursorA);
this.fontRenderer.drawStringWithShadow(colorB + textClipped.substring(cursorA), x2, y, color);
}
if (flag1) {
if (flag2) {
Gui.drawRect(k1, y - 1, k1 + 1, y + 1 + this.fontRenderer.FONT_HEIGHT, -3092272);
} else {
this.fontRenderer.drawStringWithShadow("_", k1, y, color);
}
}
if (cursorB != cursorA) {
int l1 = x + this.fontRenderer.getStringWidth(textClipped.substring(0, cursorB));
drawCursorVertical(k1, y - 1, l1 - 1, y + 1 + this.fontRenderer.FONT_HEIGHT);
}
}
private void drawCursorVertical(int x1, int y1, int x2, int y2) {
int i1;
if (x1 < x2) {
i1 = x1;
x1 = x2;
x2 = i1;
}
if (y1 < y2) {
i1 = y1;
y1 = y2;
y2 = i1;
}
if (x2 > this.xPosition + this.width) {
x2 = this.xPosition + this.width;
}
if (x1 > this.xPosition + this.width) {
x1 = this.xPosition + this.width;
}
Tessellator tessellator = Tessellator.instance;
GL11.glColor4f(0.0F, 0.0F, 255.0F, 255.0F);
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_COLOR_LOGIC_OP);
GL11.glLogicOp(GL11.GL_OR_REVERSE);
tessellator.startDrawingQuads();
tessellator.addVertex((double) x1, (double) y2, 0.0D);
tessellator.addVertex((double) x2, (double) y2, 0.0D);
tessellator.addVertex((double) x2, (double) y1, 0.0D);
tessellator.addVertex((double) x1, (double) y1, 0.0D);
tessellator.draw();
GL11.glDisable(GL11.GL_COLOR_LOGIC_OP);
GL11.glEnable(GL11.GL_TEXTURE_2D);
}
private int getFormattedTextShift(int position) {
int shift = 0;
for (int i = 0; i < position; i++) {
while (this.formattedText.length() > i + shift && this.formattedText.charAt(i + shift) == '\u00a7') {
shift += 2;
}
}
return position + shift;
}
private String getPreviousColor(int position) {
while (position >= 0) {
if (this.formattedText.charAt(position) == '\u00a7') {
return this.formattedText.substring(position, position + 2);
}
position--;
}
return "";
}
}
@@ -62,7 +62,6 @@ public class GuiEnchantmentModifier extends GuiContainer {
public static void toggleEnchantmentValidation() {
NEIClientConfig.world.nbt.setBoolean("validateenchantments", !validateEnchantments());
NEIClientConfig.world.saveNBT();
}
protected void actionPerformed(GuiButton guibutton) {
@@ -12,10 +12,11 @@ import org.lwjgl.opengl.GL11;
import codechicken.lib.render.CCRenderState;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.AutoFocusWidget.INEIAutoFocusSearchEnable;
import codechicken.nei.api.INEIGuiHandler;
import codechicken.nei.api.TaggedInventoryArea;
public class GuiExtendedCreativeInv extends GuiContainer implements INEIGuiHandler {
public class GuiExtendedCreativeInv extends GuiContainer implements INEIGuiHandler, INEIAutoFocusSearchEnable {
public GuiExtendedCreativeInv(Container par1Container) {
super(par1Container);
@@ -59,13 +60,13 @@ public class GuiExtendedCreativeInv extends GuiContainer implements INEIGuiHandl
}
@Override
protected void handleMouseClick(Slot p_146984_1_, int p_146984_2_, int p_146984_3_, int p_146984_4_) {
protected void handleMouseClick(Slot slotIn, int slotId, int clickedButton, int clickType) {
// Hack for armor slots, because they are outside the container
if (p_146984_1_ != null && p_146984_4_ == 4 && p_146984_1_.xDisplayPosition < 0) {
p_146984_4_ = 0;
if (slotIn != null && clickType == 4 && slotIn.xDisplayPosition < 0) {
clickType = 0;
}
super.handleMouseClick(p_146984_1_, p_146984_2_, p_146984_3_, p_146984_4_);
super.handleMouseClick(slotIn, slotId, clickedButton, clickType);
}
}
+24 -23
View File
@@ -15,14 +15,13 @@ public class GuiNEIButton extends GuiButton {
super(i, j, k, l, i1, s);
}
public void drawButton(Minecraft minecraft, int i, int j) {
public void drawButton(Minecraft minecraft, int x, int y) {
if (!visible) return;
FontRenderer fontrenderer = minecraft.fontRenderer;
minecraft.renderEngine.bindTexture(guiTex);
GL11.glColor4f(1, 1, 1, 1);
boolean flag = i >= xPosition && j >= yPosition && i < xPosition + width && j < yPosition + height;
int k = getHoverState(flag);
boolean mouseOver = x >= xPosition && y >= yPosition && x < xPosition + width && y < yPosition + height;
int k = getHoverState(mouseOver);
drawTexturedModalRect(xPosition, yPosition, 0, 46 + k * 20, width / 2, height / 2); // top left
drawTexturedModalRect(xPosition + width / 2, yPosition, 200 - width / 2, 46 + k * 20, width / 2, height / 2); // top
// right
@@ -40,25 +39,27 @@ public class GuiNEIButton extends GuiButton {
46 + k * 20 + 20 - height / 2,
width / 2,
height / 2); // bottom right
mouseDragged(minecraft, i, j);
mouseDragged(minecraft, x, y);
if (!enabled) drawCenteredString(
fontrenderer,
displayString,
xPosition + width / 2,
yPosition + (height - 8) / 2,
0xffa0a0a0);
else if (flag) drawCenteredString(
fontrenderer,
displayString,
xPosition + width / 2,
yPosition + (height - 8) / 2,
0xffffa0);
else drawCenteredString(
fontrenderer,
displayString,
xPosition + width / 2,
yPosition + (height - 8) / 2,
0xe0e0e0);
drawContent(minecraft, x, y, mouseOver);
}
protected int getTextColour(boolean mouseOver) {
int color = 0xe0e0e0;
if (!enabled) {
color = 0xffa0a0a0;
} else if (mouseOver) {
color = 0xffffa0;
}
return color;
}
protected void drawContent(Minecraft minecraft, int y, int x, boolean mouseOver) {
FontRenderer fontrenderer = minecraft.fontRenderer;
int color = getTextColour(mouseOver);
drawCenteredString(fontrenderer, displayString, xPosition + width / 2, yPosition + (height - 8) / 2, color);
}
}
@@ -0,0 +1,112 @@
package codechicken.nei;
import static codechicken.nei.NEIClientUtils.translate;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.util.EnumChatFormatting;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.recipe.AutoCraftingManager;
public class HeldItemHandler implements IContainerInputHandler, IContainerTooltipHandler {
protected HeldItemHandler() {
}
public static void load() {
HeldItemHandler instance = new HeldItemHandler();
GuiContainerManager.addInputHandler(instance);
GuiContainerManager.addTooltipHandler(instance);
}
protected boolean contains(int mousex, int mousey) {
return NEIClientUtils.getHeldItem() != null && !ItemPanels.bookmarkPanel.inEditingState()
&& !AutoCraftingManager.processing()
&& (ItemPanels.bookmarkPanel.contains(mousex, mousey) || ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey));
}
@Override
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
if (contains(mousex, mousey)) {
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")) {
if (button == 1) {
NEIClientUtils.decreaseSlotStack(-999);
} else {
NEIClientUtils.deleteHeldItem();
}
} else {
NEIClientUtils.dropHeldItem();
}
return true;
}
return false;
}
@Override
public boolean keyTyped(GuiContainer gui, char keyChar, int keyCode) {
return false;
}
@Override
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
return false;
}
@Override
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
return false;
}
@Override
public void onKeyTyped(GuiContainer gui, char keyChar, int keyID) {
}
@Override
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
}
@Override
public void onMouseDragged(GuiContainer gui, int mousex, int mousey, int button, long heldTime) {
}
@Override
public void onMouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
}
@Override
public void onMouseUp(GuiContainer gui, int mousex, int mousey, int button) {
}
@Override
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
if (contains(mousex, mousey)) {
currenttip.clear();
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")) {
currenttip.add(EnumChatFormatting.RED + translate("itempanel.deleteItem"));
}
}
return currenttip;
}
}
@@ -0,0 +1,217 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.ItemsGrid.MouseContext;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.GuiUsageRecipe;
import codechicken.nei.recipe.StackInfo;
public class ItemHistoryPanel extends Widget implements IContainerTooltipHandler {
protected int mouseDownItemIndex = -1;
protected ItemsGrid<ItemsGridSlot, MouseContext> grid = new ItemsGrid<>() {
protected List<ItemsGridSlot> gridMask;
@Override
protected void onGridChanged() {
this.gridMask = null;
super.onGridChanged();
}
@Override
public List<ItemsGridSlot> getMask() {
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 ItemsGridSlot(slotIndex, slotIndex, getItem(slotIndex)));
}
}
return this.gridMask;
}
@Override
protected MouseContext getMouseContext(int mousex, int mousey) {
final ItemsGridSlot hovered = getSlotMouseOver(mousex, mousey);
if (hovered != null) {
return new MouseContext(
hovered.slotIndex,
hovered.slotIndex / this.columns,
hovered.slotIndex % this.columns);
}
return null;
}
};
public boolean isEmpty() {
return grid.isEmpty();
}
public void draw(int mousex, int mousey) {
if (NEIClientConfig.getIntSetting("inventory.history.splittingMode") == 0) {
GuiDraw.drawRect(x, y, w, h, NEIClientConfig.getSetting("inventory.history.historyColor").getHexValue());
} else {
drawSplittingArea(x, y, w, h, NEIClientConfig.getSetting("inventory.history.historyColor").getHexValue());
}
this.grid.draw(mousex, mousey);
}
public void update() {
this.grid.update();
}
public void addItem(ItemStack stack) {
if (stack != null) {
ItemStack is = StackInfo.loadFromNBT(StackInfo.itemStackToNBT(stack), 0);
this.grid.realItems.removeIf(historyStack -> StackInfo.equalItemAndNBT(historyStack, stack, true));
this.grid.realItems.add(0, is);
if (this.grid.realItems.size() > Math.max(50, this.grid.rows * this.grid.columns)) {
this.grid.realItems.remove(this.grid.realItems.size() - 1);
}
this.grid.onItemsChanged();
}
}
public void resize(GuiContainer gui) {
this.grid.setGridSize(x, y + 4, w, h - 8);
this.grid.refresh(gui);
}
@Override
public ItemStack getStackMouseOver(int mousex, int mousey) {
final ItemsGridSlot slot = getSlotMouseOver(mousex, mousey);
return slot == null ? null : slot.getItemStack();
}
public ItemsGridSlot getSlotMouseOver(int mousex, int mousey) {
return grid.getSlotMouseOver(mousex, mousey);
}
private void drawSplittingArea(int x, int y, int width, int height, int color) {
float alpha = (color >> 24 & 255) / 255.0F;
float red = (color >> 16 & 255) / 255.0F;
float green = (color >> 8 & 255) / 255.0F;
float blue = (color & 255) / 255.0F;
GL11.glPushMatrix();
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_LINE_STIPPLE);
GL11.glColor4f(red, green, blue, alpha);
GL11.glLineWidth(2F);
GL11.glLineStipple(2, (short) 0x00FF);
GL11.glBegin(GL11.GL_LINE_LOOP);
GL11.glVertex2i(x, y);
GL11.glVertex2i(x + width, y);
GL11.glVertex2i(x + width, y + height);
GL11.glVertex2i(x, y + height);
GL11.glEnd();
GL11.glLineStipple(1, (short) 0xFFFF);
GL11.glLineWidth(1F);
GL11.glDisable(GL11.GL_LINE_STIPPLE);
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glColor4f(1F, 1F, 1F, 1F);
GL11.glPopMatrix();
}
@Override
public void mouseDragged(int mousex, int mousey, int button, long heldTime) {
if (this.mouseDownItemIndex >= 0 && ItemPanels.itemPanel.draggedStack == null
&& NEIClientUtils.getHeldItem() == null
&& NEIClientConfig.hasSMPCounterPart()) {
final ItemsGridSlot mouseOverSlot = getSlotMouseOver(mousex, mousey);
if (mouseOverSlot == null || mouseOverSlot.itemIndex != this.mouseDownItemIndex || heldTime > 500) {
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(
this.grid.getItem(this.mouseDownItemIndex));
this.mouseDownItemIndex = -1;
}
}
}
@Override
public boolean handleClick(int mousex, int mousey, int button) {
if (handleClickExt(mousex, mousey, button)) return true;
final ItemsGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
if (hoverSlot != null) {
if (button == 2) {
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(hoverSlot.getItemStack());
} else {
mouseDownItemIndex = hoverSlot.itemIndex;
}
return true;
}
return false;
}
protected ItemStack getDraggedStackWithQuantity(ItemStack itemStack) {
return ItemQuantityField.prepareStackWithQuantity(itemStack, 0);
}
public ItemStack getStackMouseOverWithQuantity(int mousex, int mousey) {
final ItemStack hoverSlot = getStackMouseOver(mousex, mousey);
return hoverSlot != null ? getDraggedStackWithQuantity(hoverSlot) : null;
}
@Override
public void mouseUp(int mousex, int mousey, int button) {
final ItemsGridSlot hoverSlot = getSlotMouseOver(mousex, mousey);
if (hoverSlot != null && hoverSlot.itemIndex == this.mouseDownItemIndex
&& ItemPanels.itemPanel.draggedStack == null) {
if (NEIController.manager.window instanceof GuiRecipe || NEIClientUtils.shiftKey()
|| !NEIClientConfig.canCheatItem(hoverSlot.getItemStack())) {
if (button == 0) {
GuiCraftingRecipe.openRecipeGui("item", hoverSlot.getItemStack().copy());
} else if (button == 1) {
GuiUsageRecipe.openRecipeGui("item", hoverSlot.getItemStack().copy());
}
} else {
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.getItemStack()), button, -1);
}
}
this.mouseDownItemIndex = -1;
}
}
+189 -45
View File
@@ -1,16 +1,24 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import net.minecraft.client.Minecraft;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IIcon;
import com.google.common.collect.ArrayListMultimap;
@@ -20,7 +28,7 @@ import codechicken.nei.ThreadOperationTimer.TimeoutException;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.search.TooltipFilter;
public class ItemList {
@@ -36,11 +44,11 @@ public class ItemList {
* Updates to this should be synchronised on this
*/
public static final List<ItemFilterProvider> itemFilterers = new LinkedList<>();
public static final List<ItemsLoadedCallback> loadCallbacks = new LinkedList<>();
private static final HashSet<Item> erroredItems = new HashSet<>();
private static final HashSet<String> stackTraces = new HashSet<>();
private static Map<ItemStack, Integer> ordering = new HashMap<>();
/**
* Unlike {@link LayoutManager#itemsLoaded}, this indicates whether item loading is actually finished or not.
*/
@@ -62,6 +70,20 @@ public class ItemList {
}
}
public static class NegatedItemFilter implements ItemFilter {
public ItemFilter filter;
public NegatedItemFilter(ItemFilter filter) {
this.filter = filter;
}
@Override
public boolean matches(ItemStack item) {
return this.filter == null || !this.filter.matches(item);
}
}
public static class PatternItemFilter implements ItemFilter {
public Pattern pattern;
@@ -72,7 +94,20 @@ public class ItemList {
@Override
public boolean matches(ItemStack item) {
return pattern.matcher(ItemInfo.getSearchName(item)).find();
String displayName = EnumChatFormatting.getTextWithoutFormattingCodes(item.getDisplayName());
if (displayName != null && !displayName.isEmpty() && pattern.matcher(displayName).find()) {
return true;
}
if (item.hasDisplayName()) {
displayName = EnumChatFormatting
.getTextWithoutFormattingCodes(item.getItem().getItemStackDisplayName(item));
return displayName != null && !displayName.isEmpty() && pattern.matcher(displayName).find();
}
return false;
}
}
@@ -84,6 +119,10 @@ public class ItemList {
this.filters = filters;
}
public AllMultiItemFilter(ItemFilter... filters) {
this(new LinkedList<>(Arrays.asList(filters)));
}
public AllMultiItemFilter() {
this(new LinkedList<>());
}
@@ -91,9 +130,10 @@ public class ItemList {
@Override
public boolean matches(ItemStack item) {
for (ItemFilter filter : filters) try {
if (!filter.matches(item)) return false;
if (filter != null && !filter.matches(item)) return false;
} catch (Exception e) {
NEIClientConfig.logger.error("Exception filtering " + item + " with " + filter, e);
NEIClientConfig.logger
.error("Exception filtering " + item + " with " + filter + " (" + e.getMessage() + ")", e);
}
return true;
@@ -115,9 +155,10 @@ public class ItemList {
@Override
public boolean matches(ItemStack item) {
for (ItemFilter filter : filters) try {
if (filter.matches(item)) return true;
if (filter != null && filter.matches(item)) return true;
} catch (Exception e) {
NEIClientConfig.logger.error("Exception filtering " + item + " with " + filter, e);
NEIClientConfig.logger
.error("Exception filtering " + item + " with " + filter + " (" + e.getMessage() + ")", e);
}
return false;
@@ -132,9 +173,10 @@ public class ItemList {
public static boolean itemMatchesAll(ItemStack item, List<ItemFilter> filters) {
for (ItemFilter filter : filters) {
try {
if (!filter.matches(item)) return false;
if (filter != null && !filter.matches(item)) return false;
} catch (Exception e) {
NEIClientConfig.logger.error("Exception filtering " + item + " with " + filter, e);
NEIClientConfig.logger
.error("Exception filtering " + item + " with " + filter + " (" + e.getMessage() + ")", e);
}
}
@@ -156,7 +198,9 @@ public class ItemList {
public static List<ItemFilter> getItemFilters() {
LinkedList<ItemFilter> filters = new LinkedList<>();
synchronized (itemFilterers) {
for (ItemFilterProvider p : itemFilterers) filters.add(p.getFilter());
for (ItemFilterProvider p : itemFilterers) {
filters.add(p.getFilter());
}
}
return filters;
}
@@ -168,10 +212,9 @@ public class ItemList {
for (int damage = 0; damage < 16; damage++) try {
ItemStack itemstack = new ItemStack(item, 1, damage);
IIcon icon = item.getIconIndex(itemstack);
String name = GuiContainerManager.concatenatedDisplayName(itemstack, false);
String name = getTooltip(itemstack);
String s = name + "@" + (icon == null ? 0 : icon.hashCode());
if (!damageIconSet.contains(s)) {
damageIconSet.add(s);
if (damageIconSet.add(s)) {
permutations.add(itemstack);
}
} catch (TimeoutException t) {
@@ -185,43 +228,125 @@ public class ItemList {
}
}
private String getTooltip(ItemStack stack) {
try {
return String.join("\n", stack.getTooltip(Minecraft.getMinecraft().thePlayer, false));
} catch (Throwable ignored) {}
return "";
}
private void updateOrdering(List<ItemStack> items) {
final Map<ItemStack, Integer> newOrdering = new HashMap<>();
ItemSorter.sort(items);
if (!CollapsibleItems.isEmpty()) {
final HashMap<Integer, Integer> groups = new HashMap<>();
int orderIndex = 0;
for (ItemStack stack : items) {
final int groupIndex = CollapsibleItems.getGroupIndex(stack);
if (groupIndex == -1) {
newOrdering.put(stack, orderIndex++);
} else {
if (!groups.containsKey(groupIndex)) {
groups.put(groupIndex, orderIndex++);
}
newOrdering.put(stack, groups.get(groupIndex));
}
}
} else {
int orderIndex = 0;
for (ItemStack stack : items) {
newOrdering.put(stack, orderIndex++);
}
}
ItemList.ordering = newOrdering;
}
private List<ItemStack> getPermutations(Item item) {
final List<ItemStack> permutations = new LinkedList<>(ItemInfo.itemOverrides.get(item));
if (permutations.isEmpty()) {
item.getSubItems(item, null, permutations);
}
if (permutations.isEmpty()) {
damageSearch(item, permutations);
}
permutations.addAll(ItemInfo.itemVariants.get(item));
return permutations.stream()
.filter(
stack -> stack.getItem() != null && stack.getItem().delegate.name() != null
&& !ItemInfo.isHidden(stack))
.collect(Collectors.toList());
}
// For optimization it generate itemslist, permutations, orders & collapsibleitems
@Override
@SuppressWarnings("unchecked")
public void execute() {
// System.out.println("Executing NEI Item Loading");
if (!NEIClientConfig.isEnabled()) return;
ThreadOperationTimer timer = getTimer(NEIClientConfig.getItemLoadingTimeout());
LayoutManager.itemsLoaded = true;
loadFinished = false;
LinkedList<ItemStack> items = new LinkedList<>();
LinkedList<ItemStack> permutations = new LinkedList<>();
SearchField.searchParser.clearCache();
ItemSorter.instance.ordering.clear();
CollapsibleItems.clearCache();
TooltipFilter.clearCache();
List<ItemStack> items = new ArrayList<>();
ListMultimap<Item, ItemStack> itemMap = ArrayListMultimap.create();
ItemStackSet unique = new ItemStackSet();
timer.setLimit(NEIClientConfig.getItemLoadingTimeout());
for (Item item : (Iterable<Item>) Item.itemRegistry) {
if (interrupted()) return;
if (item == null || erroredItems.contains(item)) continue;
StreamSupport.stream(((Iterable<Item>) Item.itemRegistry).spliterator(), true).forEach(item -> {
if (item == null || item.delegate.name() == null || erroredItems.contains(item)) return;
try {
timer.reset(item);
permutations.clear();
permutations.addAll(ItemInfo.itemOverrides.get(item));
if (permutations.isEmpty()) item.getSubItems(item, null, permutations);
if (permutations.isEmpty()) damageSearch(item, permutations);
permutations.addAll(ItemInfo.itemVariants.get(item));
List<ItemStack> permutations = getPermutations(item);
timer.reset();
items.addAll(permutations);
itemMap.putAll(item, permutations);
for (ItemStack stack : permutations) {
if (!unique.contains(stack)) {
synchronized (unique) {
unique.add(stack);
}
synchronized (items) {
items.add(stack);
}
CollapsibleItems.putItem(stack);
TooltipFilter.getSearchTooltip(stack);
}
}
synchronized (itemMap) {
itemMap.putAll(item, permutations);
}
} catch (Throwable t) {
NEIServerConfig.logger.error("Removing item: " + item + " from list.", t);
NEIServerConfig.logger.error("Removing item: {} from list.", item, t);
erroredItems.add(item);
}
});
int index = 0;
for (Item item : (Iterable<Item>) Item.itemRegistry) {
for (ItemStack stack : itemMap.get(item)) {
ItemSorter.instance.ordering.put(stack, index++);
}
}
if (interrupted()) return;
@@ -229,32 +354,48 @@ public class ItemList {
ItemList.itemMap = itemMap;
for (ItemsLoadedCallback callback : loadCallbacks) callback.itemsLoaded();
updateFilter.restart();
if (interrupted()) return;
updateOrdering(ItemList.items);
loadFinished = true;
SubsetWidget.updateHiddenItems();
ItemPanels.bookmarkPanel.load();
updateFilter.restart();
}
};
public static ForkJoinPool getPool(int poolSize) {
public static ForkJoinPool forkJoinPool;
static {
final ForkJoinPool.ForkJoinWorkerThreadFactory factory = new ForkJoinPool.ForkJoinWorkerThreadFactory() {
private int workerId;
@Override
public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);
worker.setName("NEI-worker-thread-" + workerId++);
return worker;
}
};
int poolSize = Runtime.getRuntime().availableProcessors() * 2 / 3;
if (poolSize < 1) poolSize = 1;
return new ForkJoinPool(poolSize);
forkJoinPool = new ForkJoinPool(poolSize, factory, null, false);
}
public static final int numProcessors = Runtime.getRuntime().availableProcessors();
public static ForkJoinPool forkJoinPool = getPool(numProcessors * 2 / 3);
public static final RestartableTask updateFilter = new RestartableTask("NEI Item Filtering") {
@Override
public void execute() {
// System.out.println("Executing NEI Item Filtering");
ArrayList<ItemStack> filtered;
if (!loadFinished) return;
ItemFilter filter = getItemListFilter();
ArrayList<ItemStack> filtered;
try {
filtered = ItemList.forkJoinPool.submit(
() -> items.parallelStream().filter(PresetsWidget::matches).filter(filter::matches)
() -> items.parallelStream().filter(filter::matches)
.collect(Collectors.toCollection(ArrayList::new)))
.get();
} catch (InterruptedException | ExecutionException e) {
@@ -264,8 +405,11 @@ public class ItemList {
}
if (interrupted()) return;
ItemSorter.sort(filtered);
filtered.sort(Comparator.comparingInt(ItemList.ordering::get));
if (interrupted()) return;
ItemPanel.updateItemList(filtered);
}
};
@@ -66,7 +66,7 @@ public class ItemMobSpawner extends ItemBlock {
}
@Override
public void addInformation(ItemStack itemstack, EntityPlayer par2EntityPlayer, List list, boolean par4) {
public void addInformation(ItemStack itemstack, EntityPlayer par2EntityPlayer, List<String> list, boolean par4) {
setDefaultTag(itemstack);
int meta = itemstack.getItemDamage();
if (meta == 0) {
@@ -106,9 +106,10 @@ public class ItemMobSpawner extends ItemBlock {
public static void loadSpawners(World world) {
if (loaded) return;
loaded = true;
HashMap<Class<Entity>, String> classToStringMapping = (HashMap<Class<Entity>, String>) EntityList.classToStringMapping;
HashMap<Class<Entity>, Integer> classToIDMapping = (HashMap<Class<Entity>, Integer>) EntityList.classToIDMapping;
for (Class<Entity> eclass : classToStringMapping.keySet()) {
Map<Class<? extends Entity>, String> classToStringMapping = EntityList.classToStringMapping;
@SuppressWarnings("unchecked")
Map<Class<? extends Entity>, Integer> classToIDMapping = (Map<Class<? extends Entity>, Integer>) EntityList.classToIDMapping;
for (Class<? extends Entity> eclass : classToStringMapping.keySet()) {
if (!EntityLiving.class.isAssignableFrom(eclass)) continue;
try {
EntityLiving entityliving = (EntityLiving) eclass.getConstructor(new Class[] { World.class })
@@ -131,7 +132,7 @@ public class ItemMobSpawner extends ItemBlock {
}
@Override
public void getSubItems(Item item, CreativeTabs tab, List list) {
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));
}
+138 -119
View File
@@ -1,17 +1,17 @@
package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.drawRect;
import java.util.ArrayList;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import codechicken.lib.vec.Rectangle4i;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ItemsPanelGrid.ItemsPanelGridSlot;
import codechicken.nei.util.NEIMouseUtils;
public class ItemPanel extends PanelWidget {
public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
/**
* Backwards compat :-/
@@ -31,66 +31,49 @@ public class ItemPanel extends PanelWidget {
return super.getStackMouseOver(mousex, mousey);
}
public Button more;
public Button less;
public ItemQuantityField quantity;
public ItemHistoryPanel historyPanel = new ItemHistoryPanel();
public Button toggleGroups;
public static class ItemPanelSlot {
@Deprecated
public static class ItemPanelSlot extends ItemsPanelGridSlot {
public ItemStack item;
public int slotIndex;
public ItemPanelSlot(int idx, ItemStack stack) {
slotIndex = idx;
item = stack;
@Deprecated
public ItemPanelSlot(int idx, ItemStack item) {
this(idx, 0, item);
}
@Deprecated
public ItemPanelSlot(int idx) {
this(idx, ItemPanels.itemPanel.getGrid().getItem(idx));
}
}
protected static class ItemPanelGrid extends ItemsGrid {
public ArrayList<ItemStack> newItems;
public void setItems(ArrayList<ItemStack> items) {
newItems = items;
this(idx, 0, ItemPanels.itemPanel.getGrid().getItem(idx));
}
public void refresh(GuiContainer gui) {
private ItemPanelSlot(int slotIndex, int itemIndex, ItemStack item) {
super(slotIndex, itemIndex, item);
}
if (newItems != null) {
realItems = newItems;
newItems = null;
onGridChanged();
protected static ItemPanelSlot of(ItemsPanelGridSlot slot) {
if (slot != null) {
ItemPanelSlot customSlot = new ItemPanelSlot(slot.slotIndex, slot.itemIndex, slot.item);
customSlot.groupIndex = slot.groupIndex;
customSlot.displayName = slot.displayName;
customSlot.bgItemStack = slot.bgItemStack;
customSlot.groupSize = slot.groupSize;
customSlot.extended = slot.extended;
customSlot.bgColor = slot.bgColor;
return customSlot;
}
super.refresh(gui);
}
@Override
protected void drawSlotOutline(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {
if (PresetsWidget.inEditMode()) {
if (!PresetsWidget.isHidden(getItem(slotIdx))) drawRect(rect.x, rect.y, rect.w, rect.h, 0xee555555);
} else {
super.drawSlotOutline(focused, slotIdx, rect);
}
}
@Override
public String getMessageOnEmpty() {
return ItemList.loadFinished ? null : NEIClientUtils.translate("itempanel.loading");
return null;
}
}
public ItemPanel() {
grid = new ItemPanelGrid();
this.grid = new ItemsPanelGrid();
}
public static void updateItemList(ArrayList<ItemStack> newItems) {
((ItemPanelGrid) ItemPanels.itemPanel.getGrid()).setItems(newItems);
ItemPanels.itemPanel.getGrid().setItems(newItems);
ItemPanels.itemPanel.realItems = newItems;
}
@@ -98,51 +81,31 @@ public class ItemPanel extends PanelWidget {
public void init() {
super.init();
more = new Button("+") {
toggleGroups = new Button("G") {
@Override
public boolean onButtonPress(boolean rightclick) {
if (rightclick) return false;
int modifier = NEIClientUtils.controlKey() ? 64 : NEIClientUtils.shiftKey() ? 10 : 1;
int quantity = NEIClientConfig.getItemQuantity() + modifier;
if (quantity < 0) {
quantity = 0;
}
ItemPanels.itemPanel.quantity.setText(Integer.toString(quantity));
return true;
public String getButtonTip() {
return NEIClientUtils.translate("itempanel.collapsed.button.tip");
}
};
less = new Button("-") {
@Override
public boolean onButtonPress(boolean rightclick) {
if (rightclick) return false;
int modifier = NEIClientUtils.controlKey() ? -64 : NEIClientUtils.shiftKey() ? -10 : -1;
int quantity = NEIClientConfig.getItemQuantity() + modifier;
if (quantity < 0) {
quantity = 0;
}
ItemPanels.itemPanel.quantity.setText(Integer.toString(quantity));
CollapsibleItems.toggleGroups(rightclick ? false : null);
ItemList.updateFilter.restart();
return true;
}
};
quantity = new ItemQuantityField("quantity");
}
@Deprecated
public void scroll(int i) {
grid.shiftPage(i);
@Override
public ItemPanelSlot getSlotMouseOver(int mousex, int mousey) {
// use ItemPanelSlot for Backwards compat
return ItemPanelSlot.of(this.grid.getSlotMouseOver(mousex, mousey));
}
public String getLabelText() {
return String.format("(%d/%d)", getPage(), Math.max(1, getNumPages()));
return String.format("%d/%d", getPage(), Math.max(1, getNumPages()));
}
protected String getPositioningSettingName() {
@@ -165,59 +128,115 @@ public class ItemPanel extends PanelWidget {
return gui.height - getMarginTop(gui) - PADDING;
}
@Override
protected int resizeHeader(GuiContainer gui) {
int marginTop = super.resizeHeader(gui);
toggleGroups.w = pageNext.w;
toggleGroups.h = pageNext.h;
toggleGroups.y = pageNext.y;
toggleGroups.x = pageNext.x - toggleGroups.w - 2;
return marginTop;
}
protected int resizeFooter(GuiContainer gui) {
if (!NEIClientConfig.showItemQuantityWidget() && NEIClientConfig.isSearchWidgetCentered()) return 0;
final int BUTTON_SIZE = 20;
more.w = less.w = BUTTON_SIZE;
quantity.h = BUTTON_SIZE;
if (NEIClientConfig.isSearchWidgetCentered()) {
more.h = less.h = BUTTON_SIZE;
more.x = x + w - BUTTON_SIZE;
more.y = less.y = quantity.y = y + h - BUTTON_SIZE;
less.x = x;
quantity.x = x + BUTTON_SIZE + 2;
quantity.w = more.x - quantity.x - 2;
} else {
quantity.x = (int) (x + (w * 0.7)) + 3;
quantity.y = y + h - BUTTON_SIZE;
quantity.w = (int) ((w * 0.3) - BUTTON_SIZE - 1);
more.h = less.h = BUTTON_SIZE / 2;
more.y = y + h - (more.h * 2);
less.x = more.x = quantity.x + quantity.w;
less.y = more.y + more.h;
if (!NEIClientConfig.showItemQuantityWidget() && NEIClientConfig.isSearchWidgetCentered()
&& !NEIClientConfig.showHistoryPanelWidget()) {
return 0;
}
return BUTTON_SIZE + 2;
if (NEIClientConfig.showHistoryPanelWidget()) {
historyPanel.x = x;
historyPanel.w = w;
historyPanel.h = 8 + ItemsGrid.SLOT_SIZE * NEIClientConfig.getIntSetting("inventory.history.useRows");
if (NEIClientConfig.showItemQuantityWidget() || !NEIClientConfig.isSearchWidgetCentered()) {
historyPanel.y = LayoutManager.quantity.y - historyPanel.h - PanelWidget.PADDING;
return LayoutManager.quantity.h + historyPanel.h + PanelWidget.PADDING * 2;
} else {
historyPanel.y = y + h - historyPanel.h;
return historyPanel.h + PanelWidget.PADDING;
}
}
return LayoutManager.quantity.h + PanelWidget.PADDING;
}
@Override
public void setVisible() {
super.setVisible();
if (grid.getPerPage() > 0 && NEIClientConfig.showItemQuantityWidget()) {
LayoutManager.addWidget(more);
LayoutManager.addWidget(less);
LayoutManager.addWidget(quantity);
}
}
protected ItemStack getDraggedStackWithQuantity(int mouseDownSlot) {
ItemStack stack = grid.getItem(mouseDownSlot);
if (stack != null) {
int amount = NEIClientConfig.showItemQuantityWidget() ? NEIClientConfig.getItemQuantity() : 0;
if (amount == 0) {
amount = stack.getMaxStackSize();
if (grid.getPerPage() > 0) {
if (!CollapsibleItems.isEmpty() && !grid.isEmpty()) {
LayoutManager.addWidget(toggleGroups);
}
return NEIServerUtils.copyStack(stack, amount);
if (NEIClientConfig.showHistoryPanelWidget() && (!grid.isEmpty() || !historyPanel.isEmpty())) {
LayoutManager.addWidget(historyPanel);
}
}
}
@Override
public void resize(GuiContainer gui) {
super.resize(gui);
historyPanel.resize(gui);
}
protected ItemStack getDraggedStackWithQuantity(ItemStack itemStack) {
return ItemQuantityField.prepareStackWithQuantity(itemStack, 0);
}
@Override
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
List<String> currenttip) {
if (!this.grid.forceExpand && !currenttip.isEmpty()) {
final ItemsPanelGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
if (hoverSlot != null && hoverSlot.groupIndex >= 0
&& NEIClientConfig.getBooleanSetting("inventory.collapsibleItems.customName")
&& !hoverSlot.extended
&& !"".equals(hoverSlot.displayName)) {
currenttip.clear();
currenttip.add(hoverSlot.displayName + GuiDraw.TOOLTIP_LINESPACE);
}
}
return null;
return super.handleItemTooltip(gui, itemstack, mousex, mousey, currenttip);
}
@Override
public boolean handleClick(int mousex, int mousey, int button) {
if (button == 0 && !this.grid.forceExpand && NEIClientUtils.altKey()) {
final ItemsPanelGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
if (hoverSlot != null && hoverSlot.groupIndex >= 0) {
CollapsibleItems.setExpanded(hoverSlot.groupIndex, !hoverSlot.extended);
this.grid.setItems(this.grid.rawItems);
NEIClientUtils.playClickSound();
return true;
}
}
return super.handleClick(mousex, mousey, button);
}
@Override
public Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
final ItemsPanelGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
if (!this.grid.forceExpand && hoverSlot != null && hoverSlot.groupIndex >= 0 && hoverSlot.groupSize > 1) {
final String message = hoverSlot.extended ? "itempanel.collapsed.hint.collapse"
: "itempanel.collapsed.hint.expand";
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.ALT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate(message, hoverSlot.groupSize));
}
return hotkeys;
}
}
@@ -1,6 +1,11 @@
package codechicken.nei;
import static codechicken.nei.NEIClientUtils.translate;
import net.minecraft.client.Minecraft;
import net.minecraft.item.ItemStack;
import org.lwjgl.input.Keyboard;
import codechicken.nei.recipe.StackInfo;
public class ItemQuantityField extends TextField {
@@ -10,18 +15,84 @@ public class ItemQuantityField extends TextField {
field.setDisabledTextColour(0xFF303030);
}
public int intValue() {
return intValue(text());
@Override
protected void initInternalTextField() {
field = new FormattedTextField(Minecraft.getMinecraft().fontRenderer, 0, 0, 0, 0) {
{
setPlaceholder(NEIClientUtils.translate("itempanel.quantity.default"));
}
@Override
public String getText() {
String text = super.getText();
return !isFocused() && "0".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(Math.max(0, getInteger() - 1)));
return true;
} else if (keyID == Keyboard.KEY_UP) {
setText(Integer.toString(getInteger() + 1));
return true;
}
return false;
}
private int getInteger() {
try {
return Math.max(0, Integer.parseInt(text()));
} catch (NumberFormatException nfe) {
return 0;
}
}
};
field.setMaxStringLength(maxSearchLength);
field.setCursorPositionZero();
}
public int intValue(String s) {
private int getInteger() {
try {
return Math.max(0, Integer.parseInt(s));
return Math.max(0, Integer.parseInt(text()));
} catch (NumberFormatException nfe) {
return 0;
}
}
public static ItemStack prepareStackWithQuantity(ItemStack stack, long amount) {
if (stack == null) {
return null;
}
if (amount == 0) {
amount = NEIClientConfig.showItemQuantityWidget() ? NEIClientConfig.getItemQuantity() : 0;
if (amount == 0) {
amount = StackInfo.itemStackToNBT(stack).hasKey("gtFluidName") ? 144 : stack.getMaxStackSize();
}
}
return StackInfo.withAmount(stack, amount);
}
@Override
public void gainFocus() {
if (text().equals("0")) {
@@ -36,20 +107,22 @@ public class ItemQuantityField extends TextField {
@Override
public void onTextChange(String oldText) {
NEIClientUtils.setItemQuantity(intValue());
NEIClientUtils.setItemQuantity(getInteger());
}
@Override
public void draw(int mousex, int mousey) {
public boolean onMouseWheel(int i, int mx, int my) {
if (!contains(mx, my)) return false;
int multiplier = 1;
if (!focused() && intValue() == 0) {
field.setText(translate("itempanel.quantity.default"));
field.setEnabled(false);
super.draw(mousex, mousey);
field.setEnabled(true);
field.setText("0");
} else {
super.draw(mousex, mousey);
if (NEIClientUtils.shiftKey()) {
multiplier = 10;
} else if (NEIClientUtils.controlKey()) {
multiplier = 64;
}
setText(Integer.toString(Math.max(0, getInteger() + i * multiplier)));
return true;
}
}
+6 -17
View File
@@ -4,19 +4,19 @@ import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.StatCollector;
import codechicken.lib.config.ConfigTagParent;
import codechicken.nei.ItemList.ItemsLoadedCallback;
import codechicken.nei.api.API;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.config.GuiItemSorter;
import codechicken.nei.config.OptionOpenGui;
public class ItemSorter implements Comparator<ItemStack>, ItemsLoadedCallback {
public class ItemSorter implements Comparator<ItemStack> {
public static class SortEntry {
@@ -44,12 +44,10 @@ public class ItemSorter implements Comparator<ItemStack>, ItemsLoadedCallback {
public static final ItemSorter instance = new ItemSorter();
// optimisations
public HashMap<ItemStack, Integer> ordering = null;
public Map<ItemStack, Integer> ordering = new HashMap<>();
public static void sort(ArrayList<ItemStack> items) {
public static void sort(List<ItemStack> items) {
try {
// items = (ArrayList<ItemStack>)
// items.parallelStream().sorted(instance).collect(Collectors.toList());
items.sort(instance);
} catch (Exception e) {
NEIClientConfig.logger.error("Exception sorting item list", e);
@@ -65,14 +63,6 @@ public class ItemSorter implements Comparator<ItemStack>, ItemsLoadedCallback {
return 0;
}
@Override
public void itemsLoaded() {
HashMap<ItemStack, Integer> newMap = new HashMap<>();
int i = 0;
for (ItemStack stack : ItemList.items) newMap.put(stack, i++);
ordering = newMap;
}
public static SortEntry find(String name) {
for (SortEntry e : entries) if (e.name.equals(name)) return e;
@@ -123,8 +113,8 @@ public class ItemSorter implements Comparator<ItemStack>, ItemsLoadedCallback {
return compareInt(id1, id2);
});
API.addSortOption("nei.itemsort.name", (o1, o2) -> {
String name1 = ItemInfo.getSearchName(o1);
String name2 = ItemInfo.getSearchName(o2);
String name1 = o1.getDisplayName();
String name2 = o2.getDisplayName();
return name1.compareTo(name2);
});
tag.getTag("inventory.itemsort").setDefaultValue(getSaveString(list));
@@ -136,7 +126,6 @@ public class ItemSorter implements Comparator<ItemStack>, ItemsLoadedCallback {
list = fromSaveString(activeTag().getValue());
}
});
ItemList.loadCallbacks.add(instance);
}
public static String getSaveString(List<SortEntry> list) {
@@ -0,0 +1,133 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import codechicken.nei.recipe.StackInfo;
public class ItemStackAmount {
private final Map<NBTTagCompound, Long> itemMap = new LinkedHashMap<>();
public void putAll(ItemStackAmount amounts) {
for (Map.Entry<NBTTagCompound, Long> entry : amounts.itemMap.entrySet()) {
this.itemMap.put(entry.getKey(), entry.getValue() + this.itemMap.getOrDefault(entry.getKey(), 0L));
}
}
public void addAll(Iterable<ItemStack> items) {
for (ItemStack stack : items) {
add(stack);
}
}
public void add(ItemStack item) {
add(item, (long) StackInfo.getAmount(item));
}
public void add(ItemStack stack, Long value) {
if (stack == null || stack.getItem() == null) return;
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
if (key != null) {
this.itemMap.put(key, value + this.itemMap.getOrDefault(key, 0L));
}
}
public Long get(ItemStack stack) {
if (stack == null || stack.getItem() == null) return null;
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
return this.itemMap.get(key);
}
public void put(ItemStack stack, long value) {
if (stack == null || stack.getItem() == null) return;
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
if (key != null) {
this.itemMap.put(key, value);
}
}
public long getOrDefault(ItemStack stack, long defaultAmount) {
final Long e = get(stack);
return e == null ? defaultAmount : e;
}
public boolean contains(ItemStack stack) {
return get(stack) != null;
}
public void clear() {
this.itemMap.clear();
}
public Long remove(ItemStack stack) {
if (stack == null || stack.getItem() == null) return null;
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
return this.itemMap.remove(key);
}
public boolean removeIf(Predicate<Map.Entry<NBTTagCompound, Long>> predicate) {
return this.itemMap.entrySet().removeIf(predicate);
}
public Set<Map.Entry<NBTTagCompound, Long>> entrySet() {
return this.itemMap.entrySet();
}
public List<ItemStack> values() {
List<ItemStack> list = new ArrayList<>();
for (Map.Entry<NBTTagCompound, Long> entry : this.itemMap.entrySet()) {
list.add(StackInfo.loadFromNBT(entry.getKey(), Math.max(0, entry.getValue())));
}
return list;
}
public int size() {
return this.itemMap.size();
}
public boolean isEmpty() {
return this.itemMap.isEmpty();
}
public static ItemStackAmount of(ItemStackAmount map) {
ItemStackAmount result = new ItemStackAmount();
result.itemMap.putAll(map.itemMap);
return result;
}
public static ItemStackAmount of(ItemStackMap<Long> map) {
ItemStackAmount result = new ItemStackAmount();
for (ItemStackMap.Entry<Long> entry : map.entries()) {
result.put(entry.key, entry.value);
}
return result;
}
public static ItemStackAmount of(Iterable<ItemStack> items) {
ItemStackAmount result = new ItemStackAmount();
for (ItemStack stack : items) {
result.add(stack);
}
return result;
}
}
@@ -5,9 +5,11 @@ import static codechicken.lib.inventory.InventoryUtils.newItemStack;
import static net.minecraftforge.oredict.OreDictionary.WILDCARD_VALUE;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@@ -24,8 +26,13 @@ public class ItemStackMap<T> {
public final int damage;
public final NBTTagCompound tag;
private final int hashCode;
public StackMetaKey(int damage, NBTTagCompound tag) {
if (tag != null && tag.hasNoTags()) {
tag = null;
}
this.hashCode = Objects.hashCode(damage, tag);
this.damage = damage;
this.tag = tag;
}
@@ -35,7 +42,7 @@ public class ItemStackMap<T> {
}
public int hashCode() {
return Objects.hashCode(damage, tag);
return this.hashCode;
}
public boolean equals(Object o) {
@@ -191,7 +198,7 @@ public class ItemStackMap<T> {
WILDCARD_TAG.setBoolean("*", true);
}
private final HashMap<Item, DetailMap> itemMap = new HashMap<>();
private final Map<Item, DetailMap> itemMap = new LinkedHashMap<>();
private int size;
public T get(ItemStack key) {
@@ -203,6 +210,11 @@ public class ItemStackMap<T> {
return map == null ? null : map.get(key);
}
public T getOrDefault(ItemStack key, T defaultValue) {
T e = get(key);
return e == null ? defaultValue : e;
}
public void put(ItemStack key, T value) {
if (key == null || key.getItem() == null) return;
@@ -211,8 +223,22 @@ public class ItemStackMap<T> {
map.put(key, value);
}
public T computeIfAbsent(ItemStack key, Function<ItemStack, ? extends T> mappingFunction) {
T value;
if ((value = get(key)) == null) {
T newValue;
if ((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
}
return value;
}
public void clear() {
itemMap.clear();
size = 0;
}
public T remove(ItemStack key) {
@@ -27,6 +27,16 @@ public class ItemStackSet extends ItemStackMap<ItemStack> implements ItemFilter
put(item, item);
}
public ItemStackSet addAll(Iterable<ItemStack> items) {
for (ItemStack item : items) add(item);
return this;
}
public ItemStackSet removeAll(Iterable<ItemStack> items) {
for (ItemStack item : items) remove(item);
return this;
}
public boolean contains(ItemStack item) {
return get(item) != null;
}
+250
View File
@@ -0,0 +1,250 @@
package codechicken.nei;
import java.awt.Point;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.recipe.StackInfo;
public class ItemZoom extends Widget implements IContainerInputHandler {
public static final int MIN_ZOOM = 0;
public static final int MAX_ZOOM = 1000;
private static final int MIN_SCALE = 2;
private static final int SLOT_SIZE = 16;
private Boolean previousKeyboardRepeatEnabled = null;
private ItemStack stack = null;
private String displayName = "";
private int availableAreaWidth = 0;
private float xPosition = 0;
private float yPosition = 0;
private float scale = 1;
public ItemZoom() {
GuiContainerManager.addInputHandler(this);
}
@Override
public void draw(int mx, int my) {
if (this.stack != null
&& (NEIClientConfig.getBooleanSetting("inventory.itemzoom.enabled")
|| NEIClientConfig.isKeyHashDown("gui.itemzoom_hold"))
&& GuiContainerManager.shouldShowTooltip(NEIClientUtils.getGuiContainer())) {
final float inverseScaleFactor = 1.0f / this.scale;
final float screenScale = getScreenScale();
final float size = SLOT_SIZE * this.scale;
int shiftText = 10;
GL11.glPushMatrix();
GL11.glScaled(screenScale, screenScale, 1);
GL11.glScaled(this.scale, this.scale, 2);
GL11.glTranslated(this.xPosition * inverseScaleFactor, this.yPosition * inverseScaleFactor, 0);
GuiContainerManager.drawItem(0, 0, this.stack, false, "");
GL11.glPopMatrix();
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GuiContainerManager.enable2DRender();
if (NEIClientConfig.getBooleanSetting("inventory.itemzoom.showName")) {
String dispalyName = NEIClientUtils
.cropText(GuiDraw.fontRenderer, this.displayName, this.availableAreaWidth);
GuiDraw.drawStringC(
dispalyName,
(int) ((this.xPosition + size / 2) * screenScale),
(int) ((this.yPosition + size) * screenScale) + shiftText,
NEIClientConfig.getSetting("inventory.itemzoom.nameColor").getHexValue());
shiftText += GuiDraw.fontRenderer.FONT_HEIGHT;
}
if (NEIClientConfig.getBooleanSetting("inventory.itemzoom.enabled")
&& NEIClientConfig.getBooleanSetting("inventory.itemzoom.helpText")) {
String keyName = NEIClientConfig.getKeyName("gui.itemzoom_toggle");
if (keyName != null) {
String helpText = NEIClientUtils.translate("itemzoom.toggle", keyName);
List<String> lines = GuiDraw.fontRenderer
.listFormattedStringToWidth(helpText, this.availableAreaWidth);
for (String line : lines) {
GuiDraw.drawStringC(
line,
(int) ((this.xPosition + size / 2) * screenScale),
(int) ((this.yPosition + size) * screenScale) + 10 + shiftText,
0x66555555);
shiftText += GuiDraw.fontRenderer.FONT_HEIGHT;
}
}
}
GL11.glPopAttrib();
}
}
public void resize(GuiContainer gui) {
final ItemStack stack = getStackMouseOver(gui);
if (stack != null && (!NEIClientConfig.getBooleanSetting("inventory.itemzoom.onlySolid")
|| Block.getBlockFromItem(stack.getItem()).getMaterial().isSolid())) {
final float screenScale = 1.0f / getScreenScale();
final float availableAreaWidth = (gui.width - gui.xSize) / 2 * screenScale;
final float availableAreaHeight = gui.height * screenScale;
final Point mouse = GuiDraw.getMousePosition();
this.scale = Math.round(getZoomAmount(gui) * getPointSize(gui) / SLOT_SIZE);
this.yPosition = (availableAreaHeight - this.scale * SLOT_SIZE) / 2;
this.xPosition = (availableAreaWidth - this.scale * SLOT_SIZE) / 2;
this.availableAreaWidth = (int) (availableAreaWidth / screenScale);
if (availableAreaWidth / screenScale >= mouse.x) {
this.xPosition += gui.width * screenScale - availableAreaWidth;
}
try {
this.displayName = stack.getDisplayName();
} catch (Throwable ignored) {
this.displayName = "Unnamed";
}
this.stack = StackInfo.loadFromNBT(StackInfo.itemStackToNBT(stack), 0);
} else {
this.stack = null;
this.displayName = "";
}
}
private float getPointSize(GuiContainer gui) {
final float screenScale = 1.0f / getScreenScale();
final float availableAreaWidth = (gui.width - (gui.xSize + gui.width) / 2) * screenScale;
return availableAreaWidth / MAX_ZOOM;
}
private float getScreenScale() {
return Minecraft.getMinecraft().currentScreen.width * 1f / Minecraft.getMinecraft().displayWidth;
}
private int getZoomAmount(GuiContainer gui) {
return Math.max(
Math.round(SLOT_SIZE * MIN_SCALE / getPointSize(gui)),
NEIClientConfig.getIntSetting("inventory.itemzoom.zoom"));
}
private void increaseZoom(GuiContainer gui) {
final float pointSize = getPointSize(gui);
final float scale = Math.round(getZoomAmount(gui) * pointSize / SLOT_SIZE);
NEIClientConfig.setIntSetting(
"inventory.itemzoom.zoom",
Math.min(MAX_ZOOM, Math.round((scale + 1) / (pointSize / SLOT_SIZE))));
}
private void decreaseZoom(GuiContainer gui) {
final float pointSize = getPointSize(gui);
final float scale = Math.round(getZoomAmount(gui) * pointSize / SLOT_SIZE);
NEIClientConfig.setIntSetting(
"inventory.itemzoom.zoom",
Math.max(MIN_ZOOM, Math.round(Math.max(MIN_SCALE, scale - 1) / (pointSize / SLOT_SIZE))));
}
private ItemStack getStackMouseOver(GuiContainer gui) {
if (NEIClientConfig.getBooleanSetting("inventory.itemzoom.neiOnly")) {
final Point mouse = GuiDraw.getMousePosition();
ItemStack stack = ItemPanels.itemPanel.getStackMouseOver(mouse.x, mouse.y);
if (stack == null) {
stack = ItemPanels.bookmarkPanel.getStackMouseOver(mouse.x, mouse.y);
}
if (stack == null) {
stack = ItemPanels.itemPanel.historyPanel.getStackMouseOver(mouse.x, mouse.y);
}
return stack;
}
return GuiContainerManager.getStackMouseOver(gui);
}
@Override
public boolean keyTyped(GuiContainer gui, char keyChar, int keyCode) {
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.isKeyHashDown("gui.itemzoom_toggle")) {
NEIClientConfig.getSetting("inventory.itemzoom.enabled")
.setBooleanValue(!NEIClientConfig.getBooleanSetting("inventory.itemzoom.enabled"));
return true;
}
if (this.stack != null && NEIClientConfig.isKeyHashDown("gui.itemzoom_hold")) {
return true;
}
if (this.stack != null && NEIClientConfig.isKeyHashDown("gui.itemzoom_zoom_in")) {
increaseZoom(gui);
previousKeyboardRepeatEnabled = Keyboard.areRepeatEventsEnabled();
Keyboard.enableRepeatEvents(true);
return true;
}
if (this.stack != null && NEIClientConfig.isKeyHashDown("gui.itemzoom_zoom_out")) {
decreaseZoom(gui);
previousKeyboardRepeatEnabled = Keyboard.areRepeatEventsEnabled();
Keyboard.enableRepeatEvents(true);
return true;
}
if (previousKeyboardRepeatEnabled != null) {
Keyboard.enableRepeatEvents(previousKeyboardRepeatEnabled);
previousKeyboardRepeatEnabled = null;
}
return false;
}
@Override
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {}
@Override
public void onMouseUp(GuiContainer gui, int mousex, int mousey, int button) {}
@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 void onMouseDragged(GuiContainer gui, int mousex, int mousey, int button, long heldTime) {}
}
+349 -290
View File
@@ -1,42 +1,262 @@
package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.drawRect;
import static codechicken.lib.gui.GuiDraw.getMousePosition;
import java.awt.Point;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
import java.util.Objects;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.shader.Framebuffer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL30;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.BookmarkRecipeId;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.StackInfo;
public class ItemsGrid {
public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends ItemsGrid.MouseContext> {
public static final int SLOT_SIZE = 18;
protected static class ScreenCapture {
private long nextCacheRefresh = 0;
private Framebuffer framebuffer;
public ScreenCapture() {
this.framebuffer = new Framebuffer(1, 1, true);
this.framebuffer.setFramebufferColor(0.0F, 0.0F, 0.0F, 0.0F);
Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
}
protected int getGridRenderingCacheFPS(int mode) {
return mode == 1 ? NEIClientConfig.getIntSetting("inventory.gridRenderingCacheFPS") : 0;
}
public boolean needRefresh(int mode) {
final Minecraft minecraft = Minecraft.getMinecraft();
return this.nextCacheRefresh == 0 || this.framebuffer.framebufferWidth != minecraft.displayWidth
|| framebuffer.framebufferHeight != minecraft.displayHeight
|| getGridRenderingCacheFPS(mode) > 0 && this.nextCacheRefresh < System.currentTimeMillis();
}
public void refreshBuffer() {
this.nextCacheRefresh = 0;
}
public void captureScreen(Runnable callback, int mode) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
resetFramebuffer();
this.framebuffer.bindFramebuffer(false);
/* Set up some rendering state needed for items to work correctly */
GL11.glDisable(GL11.GL_BLEND);
GL11.glDepthMask(true);
OpenGlHelper.glBlendFunc(
GL11.GL_SRC_ALPHA,
GL11.GL_ONE_MINUS_SRC_ALPHA,
GL11.GL_SRC_ALPHA,
GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
callback.run();
GL11.glPopAttrib();
Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
this.nextCacheRefresh = System.currentTimeMillis() + (1000 / Math.max(1, getGridRenderingCacheFPS(mode)));
}
private void resetFramebuffer() {
final Minecraft minecraft = Minecraft.getMinecraft();
if (this.framebuffer.framebufferWidth != minecraft.displayWidth
|| framebuffer.framebufferHeight != minecraft.displayHeight) {
this.framebuffer.createBindFramebuffer(minecraft.displayWidth, minecraft.displayHeight);
this.framebuffer.setFramebufferFilter(GL11.GL_NEAREST);
} 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() {
this.framebuffer.bindFramebufferTexture();
final Tessellator tessellator = Tessellator.instance;
final Minecraft minecraft = Minecraft.getMinecraft();
final ScaledResolution scaledresolution = new ScaledResolution(
minecraft,
minecraft.displayWidth,
minecraft.displayHeight);
/* Set up some rendering state needed for items to work correctly */
GL11.glEnable(GL11.GL_BLEND);
OpenGlHelper
.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
GL11.glEnable(GL11.GL_TEXTURE_2D);
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(0, scaledresolution.getScaledHeight_double(), 0.0, 0, 0);
tessellator.addVertexWithUV(
scaledresolution.getScaledWidth_double(),
scaledresolution.getScaledHeight_double(),
0.0,
1,
0);
tessellator.addVertexWithUV(scaledresolution.getScaledWidth_double(), 0, 0.0, 1, 1);
tessellator.addVertexWithUV(0, 0, 0, 0, 1);
tessellator.draw();
this.framebuffer.unbindFramebufferTexture();
}
}
public static class ItemsGridSlot {
protected static final float DEFAULT_SLOT_SIZE = 18f;
protected static final float LINE_WIDTH = 0.75f;
public final ItemStack item;
public final int slotIndex;
public final int itemIndex;
public Color borderColor = Color.BLACK;
public boolean borderLeft = false;
public boolean borderTop = false;
public boolean borderRight = false;
public boolean borderBottom = false;
public ItemsGridSlot(int slotIndex, int itemIndex, ItemStack itemStack) {
this.slotIndex = slotIndex;
this.itemIndex = itemIndex;
this.item = itemStack;
}
public ItemStack getItemStack() {
return this.item;
}
public <M extends MouseContext> void beforeDraw(Rectangle4i rect, M mouseContext) {
if (mouseContext != null && mouseContext.slotIndex == this.slotIndex) {
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, HIGHLIGHT_COLOR);
}
}
public <M extends MouseContext> void afterDraw(Rectangle4i rect, M mouseContext) {}
public void drawItem(Rectangle4i rect) {
drawItem(getItemStack(), rect);
}
protected void drawItem(ItemStack stack, Rectangle4i rect) {
if (rect.w != DEFAULT_SLOT_SIZE) {
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
GL11.glTranslatef(rect.x + 1, rect.y + 1, 0);
GL11.glScaled(panelFactor, panelFactor, 1);
GuiContainerManager.drawItem(0, 0, stack, true, "");
GL11.glScaled(1f / panelFactor, 1f / panelFactor, 1);
GL11.glTranslatef(-1 * (rect.x + 1), -1 * (rect.y + 1), 0);
} else {
GuiContainerManager.drawItem(rect.x + 1, rect.y + 1, stack, true, "");
}
}
public void drawBorder(Rectangle4i rect) {
float halfLineWidth = LINE_WIDTH / 2f;
if (this.borderLeft) {
NEIClientUtils
.drawRect(rect.x - halfLineWidth, rect.y + halfLineWidth, LINE_WIDTH, rect.h, this.borderColor);
}
if (this.borderRight) {
NEIClientUtils.drawRect(
rect.x + rect.w - halfLineWidth,
rect.y - halfLineWidth,
LINE_WIDTH,
rect.h,
this.borderColor);
}
if (this.borderTop) {
NEIClientUtils
.drawRect(rect.x - halfLineWidth, rect.y - halfLineWidth, rect.w, LINE_WIDTH, this.borderColor);
}
if (this.borderBottom) {
NEIClientUtils.drawRect(
rect.x + halfLineWidth,
rect.y + rect.h - halfLineWidth,
rect.w,
LINE_WIDTH,
this.borderColor);
}
}
}
public static class MouseContext {
public final int slotIndex;
public final int columnIndex;
public final int rowIndex;
public MouseContext(int slotIndex, int rowIndex, int columnIndex) {
this.slotIndex = slotIndex;
this.rowIndex = rowIndex;
this.columnIndex = columnIndex;
}
@Override
public int hashCode() {
return Objects.hash(this.rowIndex, this.slotIndex, this.columnIndex);
}
public boolean equals(Object obj) {
if (obj instanceof MouseContext context) {
return this.columnIndex == context.columnIndex && this.rowIndex == context.rowIndex
&& this.slotIndex == context.slotIndex;
}
return false;
}
}
public static int SLOT_SIZE = 18;
public static final Color HIGHLIGHT_COLOR = new Color(0xee555555, true);
protected int width;
protected int height;
@@ -53,33 +273,33 @@ public class ItemsGrid {
protected int rows;
protected int columns;
protected boolean showRecipeTooltips = false;
protected boolean[] invalidSlotMap;
protected Label messageLabel = new Label(getMessageOnEmpty(), true);
@Nullable
private Framebuffer framebuffer = null;
protected boolean refreshBuffer = true;
protected ScreenCapture screenCapture = null;
public ArrayList<ItemStack> getItems() {
return realItems;
}
public ItemStack getItem(int idx) {
return realItems.get(idx);
public ItemStack getItem(int itemIndex) {
return realItems.get(itemIndex);
}
public int size() {
return realItems.size();
}
public boolean isEmpty() {
return realItems.isEmpty();
}
public int indexOf(ItemStack stackA, boolean useNBT) {
for (int idx = 0; idx < realItems.size(); idx++) {
if (StackInfo.equalItemAndNBT(stackA, getItem(idx), useNBT)) {
if (StackInfo.equalItemAndNBT(stackA, realItems.get(idx), useNBT)) {
return idx;
}
}
@@ -116,6 +336,14 @@ public class ItemsGrid {
return columns;
}
public int getLastRowIndex() {
final List<T> mask = getMask();
return this.columns > 0 && !mask.isEmpty()
? (int) Math.ceil((float) (mask.get(mask.size() - 1).slotIndex + 1) / this.columns) - 1
: 0;
}
public void setGridSize(int mleft, int mtop, int w, int h) {
marginLeft = mleft;
marginTop = mtop;
@@ -158,11 +386,13 @@ public class ItemsGrid {
}
protected void onGridChanged() {
refreshBuffer = true;
if (this.screenCapture != null) {
this.screenCapture.refreshBuffer();
}
}
public void setShowRecipeTooltips(boolean show) {
this.showRecipeTooltips = show;
public void onItemsChanged() {
onGridChanged();
}
public void refresh(GuiContainer gui) {
@@ -178,11 +408,13 @@ public class ItemsGrid {
invalidSlotMap = new boolean[rows * columns];
perPage = columns * rows;
if (NEIClientConfig.optimizeGuiOverlapComputation()) {
checkGuiOverlap(gui, 0, columns - 2, 1);
checkGuiOverlap(gui, columns - 1, 1, -1);
} else {
checkGuiOverlap(gui, 0, columns, 1);
if (gui != null) {
if (NEIClientConfig.optimizeGuiOverlapComputation()) {
checkGuiOverlap(gui, 0, columns - 2, 1);
checkGuiOverlap(gui, columns - 1, 1, -1);
} else {
checkGuiOverlap(gui, 0, columns, 1);
}
}
if (oldRows != rows || oldColumns != columns || !Arrays.equals(oldSlotMap, invalidSlotMap)) {
@@ -198,9 +430,9 @@ public class ItemsGrid {
for (int r = 0; r < rows; r++) {
final int idx = columns * r + c;
if (GuiInfo.hideItemPanelSlot(gui, getSlotRect(r, c)) && idx >= 0
&& idx < invalidSlotMap.length
&& !invalidSlotMap[idx]) {
if (idx >= 0 && idx < invalidSlotMap.length
&& !invalidSlotMap[idx]
&& GuiInfo.hideItemPanelSlot(gui, getSlotRect(r, c))) {
invalidSlotMap[idx] = true;
validColumn = false;
perPage--;
@@ -209,20 +441,37 @@ public class ItemsGrid {
}
}
public Rectangle4i getItemRect(int idx) {
final List<Integer> mask = getMask();
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) != null && idx == mask.get(i)) {
return getSlotRect(i);
}
public T getSlotMouseOver(int mousex, int mousey) {
if (!contains(mousex, mousey)) {
return null;
}
return null;
final int overRow = getRowIndex(mousey);
final int overColumn = getColumnIndex(mousex);
final int slt = columns * overRow + overColumn;
if (overRow >= rows || overColumn >= columns) {
return null;
}
return getSlotBySlotIndex(slt);
}
public Rectangle4i getSlotRect(int i) {
return getSlotRect(i / columns, i % columns);
public T getSlotBySlotIndex(int slotIndex) {
return getMask().stream().filter(item -> item.slotIndex == slotIndex).findAny().orElse(null);
}
public T getSlotByItemIndex(int itemIndex) {
return getMask().stream().filter(item -> item.itemIndex == itemIndex).findAny().orElse(null);
}
public Rectangle4i getItemRect(int itemIndex) {
final T item = getSlotByItemIndex(itemIndex);
return item != null ? getSlotRect(item.slotIndex) : null;
}
public Rectangle4i getSlotRect(int slotIndex) {
return getSlotRect(slotIndex / columns, slotIndex % columns);
}
public Rectangle4i getSlotRect(int row, int column) {
@@ -233,198 +482,49 @@ public class ItemsGrid {
SLOT_SIZE);
}
public int getRowIndex(int mousey) {
return (mousey - this.marginTop) / SLOT_SIZE;
}
public int getColumnIndex(int mousex) {
return (mousex - this.marginLeft - this.paddingLeft) / SLOT_SIZE;
}
public boolean isInvalidSlot(int index) {
return invalidSlotMap[index];
}
protected List<Integer> getMask() {
List<Integer> mask = new ArrayList<>();
public abstract List<T> getMask();
int idx = page * perPage;
for (int i = 0; i < rows * columns && idx < size(); i++) {
mask.add(isInvalidSlot(i) ? null : idx++);
protected abstract M getMouseContext(int mousex, int mousey);
protected void beforeDrawItems(int mousex, int mousey, M mouseContext) {
for (T item : getMask()) {
item.beforeDraw(getSlotRect(item.slotIndex), mouseContext);
}
return mask;
}
private void drawSlotOutlines(int mousex, int mousey) {
ItemPanelSlot focused = getSlotMouseOver(mousex, mousey);
final List<Integer> mask = getMask();
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) != null) {
drawSlotOutline(focused, mask.get(i), getSlotRect(i));
}
for (T item : getMask()) {
item.drawBorder(getSlotRect(item.slotIndex));
}
}
private int recipeTooltipSlotIdx = -1;
private int recipeTooltipLines = 2;
private Runnable recipeTooltipUpdater = null;
private GuiRecipe<?> recipeTooltipGui = null;
public void update() {
if (recipeTooltipUpdater != null) {
recipeTooltipUpdater.run();
recipeTooltipUpdater = null;
}
if (recipeTooltipGui != null) {
recipeTooltipGui.updateAsTooltip();
protected void afterDrawItems(int mousex, int mousey, M mouseContext) {
for (T item : getMask()) {
item.afterDraw(getSlotRect(item.slotIndex), mouseContext);
}
}
private static <T> List<T> listOrEmptyList(final List<T> listOrNull) {
return listOrNull == null ? Collections.emptyList() : listOrNull;
public void update() {}
protected void drawItems() {
for (T item : getMask()) {
item.drawItem(getSlotRect(item.slotIndex));
}
}
private void drawRecipeTooltip(int mousex, int mousey, List<String> itemTooltip) {
if (!NEIClientConfig.isLoaded()) {
return;
}
final Minecraft mc = Minecraft.getMinecraft();
ItemPanelSlot focused = getSlotMouseOver(mousex, mousey);
if (focused == null) {
recipeTooltipSlotIdx = -1;
recipeTooltipGui = null;
return;
}
final List<Integer> mask = getMask();
int slotIdx = -1;
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) == null) {
continue;
}
if (focused.slotIndex != mask.get(i)) {
continue;
}
slotIdx = i;
break;
}
if (slotIdx == -1) {
recipeTooltipSlotIdx = -1;
recipeTooltipGui = null;
return;
}
final Point mouseover = getMousePosition();
final ItemPanelSlot panelSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
final BookmarkRecipeId recipeId;
if (panelSlot != null) {
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(panelSlot.slotIndex);
} else {
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(focused.item);
}
if (recipeId == null) {
return;
}
if (slotIdx != recipeTooltipSlotIdx) {
recipeTooltipSlotIdx = slotIdx;
recipeTooltipGui = null;
recipeTooltipUpdater = () -> {
recipeTooltipGui = GuiCraftingRecipe.createRecipeGui("item", false, false, false, focused.item);
if (recipeTooltipGui != null) {
recipeTooltipGui.limitToOneRecipe();
recipeTooltipGui.initGui(true);
recipeTooltipGui.guiTop = 0;
recipeTooltipGui.guiLeft = 0;
}
recipeTooltipLines = Math.max(1, itemTooltip.size());
};
}
if (recipeTooltipGui == null) {
return;
}
GL11.glPushMatrix();
final float tooltipYOffset;
if (mousey - marginTop > height / 2) {
tooltipYOffset = mousey - recipeTooltipGui.getHeightAsWidget() + 8;
} else {
tooltipYOffset = mousey + ((recipeTooltipLines < 2) ? 1 : 3 + ((recipeTooltipLines - 1) * 10));
}
GL11.glTranslatef(mousex, tooltipYOffset, 500);
final GuiContainer gui;
if (mc.currentScreen instanceof GuiRecipe) {
gui = ((GuiRecipe<?>) mc.currentScreen).firstGui;
} else if (mc.currentScreen instanceof GuiContainer) {
gui = (GuiContainer) mc.currentScreen;
} else {
gui = null;
}
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
RenderHelper.disableStandardItemLighting();
recipeTooltipGui.drawGuiContainerBackgroundLayer(0.0f, -100, -100);
GL11.glPopAttrib();
if (recipeTooltipGui.slotcontainer != null) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
RenderHelper.enableGUIStandardItemLighting();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
@SuppressWarnings("unchecked")
List<Slot> slots = (List<Slot>) recipeTooltipGui.slotcontainer.inventorySlots;
for (Slot slot : slots) {
if (slot != null && slot.getStack() != null) {
GuiContainerManager.drawItem(slot.xDisplayPosition, slot.yDisplayPosition, slot.getStack());
}
}
GL11.glPopAttrib();
}
recipeTooltipGui.drawGuiContainerForegroundLayer(-100, -100);
for (GuiButton btn : recipeTooltipGui.getOverlayButtons()) {
btn.drawButton(mc, -100, -100);
}
GL11.glPopMatrix();
}
protected void drawSlotOutline(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {
if (focused != null && focused.slotIndex == slotIdx) {
drawRect(rect.x, rect.y, rect.w, rect.h, 0xee555555); // highlight
}
}
private void blitExistingBuffer() {
Minecraft minecraft = Minecraft.getMinecraft();
GL11.glEnable(GL11.GL_BLEND);
OpenGlHelper.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
getFrameBuffer().bindFramebufferTexture();
GL11.glEnable(GL11.GL_TEXTURE_2D);
ScaledResolution res = new ScaledResolution(minecraft, minecraft.displayWidth, minecraft.displayHeight);
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(0, res.getScaledHeight_double(), 0.0, 0, 0);
tessellator.addVertexWithUV(res.getScaledWidth_double(), res.getScaledHeight_double(), 0.0, 1, 0);
tessellator.addVertexWithUV(res.getScaledWidth_double(), 0, 0.0, 1, 1);
tessellator.addVertexWithUV(0, 0, 0, 0, 1);
tessellator.draw();
OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
}
private Framebuffer getFrameBuffer() {
if (framebuffer == null) {
framebuffer = new Framebuffer(1, 1, true);
framebuffer.setFramebufferColor(0.0F, 0.0F, 0.0F, 0.0F);
}
return framebuffer;
}
private void drawItems() {
GuiContainerManager.enableMatrixStackLogging();
final List<Integer> mask = getMask();
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) != null) {
drawItem(getSlotRect(i), mask.get(i));
}
}
GuiContainerManager.disableMatrixStackLogging();
protected int getGridRenderingCacheMode() {
return NEIClientConfig.getGridRenderingCacheMode();
}
public void draw(int mousex, int mousey) {
@@ -432,47 +532,33 @@ public class ItemsGrid {
return;
}
if (NEIClientConfig.shouldCacheItemRendering()) {
final int gridRenderingCacheMode = getGridRenderingCacheMode();
final M mouseContext = getMouseContext(mousex, mousey);
if (refreshBuffer) {
Minecraft minecraft = Minecraft.getMinecraft();
Framebuffer framebuffer = getFrameBuffer();
framebuffer.createBindFramebuffer(minecraft.displayWidth, minecraft.displayHeight);
framebuffer.framebufferClear();
framebuffer.bindFramebuffer(false);
beforeDrawItems(mousex, mousey, mouseContext);
/* Set up some rendering state needed for items to work correctly */
GL11.glDisable(GL11.GL_BLEND);
GL11.glDepthMask(true);
OpenGlHelper.glBlendFunc(
GL11.GL_SRC_ALPHA,
GL11.GL_ONE_MINUS_SRC_ALPHA,
GL11.GL_SRC_ALPHA,
GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
if (gridRenderingCacheMode > 0) {
drawItems();
Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
refreshBuffer = false;
if (this.screenCapture == null) {
this.screenCapture = new ScreenCapture();
}
drawSlotOutlines(mousex, mousey);
blitExistingBuffer();
if (this.screenCapture.needRefresh(gridRenderingCacheMode)) {
this.screenCapture.captureScreen(() -> {
GuiContainerManager.enableMatrixStackLogging();
drawItems();
GuiContainerManager.disableMatrixStackLogging();
}, gridRenderingCacheMode);
}
this.screenCapture.renderCapturedScreen();
} else {
drawSlotOutlines(mousex, mousey);
GuiContainerManager.enableMatrixStackLogging();
drawItems();
GuiContainerManager.disableMatrixStackLogging();
}
}
public void postDrawTooltips(int mousex, int mousey, List<String> tooltip) {
if (NEIClientConfig.showRecipeTooltips() && showRecipeTooltips) {
try {
drawRecipeTooltip(mousex, mousey, tooltip);
} catch (Exception e) {
NEIClientConfig.logger.warn("Cannot draw recipe tooltip", e);
}
}
afterDrawItems(mousex, mousey, mouseContext);
}
public void setVisible() {
@@ -481,45 +567,18 @@ public class ItemsGrid {
}
}
protected void drawItem(Rectangle4i rect, int idx) {
GuiContainerManager.drawItem(rect.x + 1, rect.y + 1, getItem(idx));
}
public ItemPanelSlot getSlotMouseOver(int mousex, int mousey) {
if (!contains(mousex, mousey)) {
return null;
}
final int overRow = (int) ((mousey - marginTop) / SLOT_SIZE);
final int overColumn = (int) ((mousex - marginLeft - paddingLeft) / SLOT_SIZE);
final int slt = columns * overRow + overColumn;
if (overRow >= rows || overColumn >= columns) {
return null;
}
final List<Integer> mask = getMask();
if (mask.size() > slt && mask.get(slt) != null) {
final int idx = mask.get(slt);
return new ItemPanelSlot(idx, getItem(idx));
}
return null;
}
public boolean contains(int px, int py) {
final Rectangle4i rect = new Rectangle4i(
marginLeft + paddingLeft,
marginTop,
columns * SLOT_SIZE,
rows * SLOT_SIZE);
if (!(new Rectangle4i(marginLeft + paddingLeft, marginTop, columns * SLOT_SIZE, height)).contains(px, py)) {
if (!rect.contains(px, py)) {
return false;
}
final int r = (int) ((py - marginTop) / SLOT_SIZE);
final int c = (int) ((px - marginLeft - paddingLeft) / SLOT_SIZE);
final int slt = columns * r + c;
return r >= rows || c >= columns || !isInvalidSlot(slt);
return !isInvalidSlot(columns * getRowIndex(py) + getColumnIndex(px));
}
public String getMessageOnEmpty() {
@@ -0,0 +1,239 @@
package codechicken.nei;
import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.guihook.GuiContainerManager;
public class ItemsPanelGrid extends ItemsGrid<ItemsPanelGrid.ItemsPanelGridSlot, ItemsPanelGrid.MouseContext> {
public static class ItemsPanelGridSlot extends ItemsGridSlot {
protected static final float LINE_WIDTH = 0.75f;
public int groupIndex = -1;
public String displayName = "";
public ItemStack bgItemStack;
public int groupSize = 1;
public boolean extended = false;
public Color bgColor = null;
public ItemsPanelGridSlot(int slotIndex, int itemIndex, ItemStack itemStack) {
super(slotIndex, itemIndex, itemStack);
}
public ItemStack getBGItem() {
return this.bgItemStack;
}
@Override
public void beforeDraw(Rectangle4i rect, MouseContext mouseContext) {
super.beforeDraw(rect, mouseContext);
if (this.bgColor != null) {
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, this.bgColor);
}
}
@Override
public void drawItem(Rectangle4i rect) {
if (!this.extended && getBGItem() != null) {
GuiContainerManager.drawItems.zLevel -= 10F;
super.drawItem(getBGItem(), rect.offset(1, -1));
GuiContainerManager.drawItems.zLevel += 10F;
super.drawItem(getItemStack(), rect.offset(-2, 2));
} else {
super.drawItem(rect);
}
}
}
public ArrayList<ItemStack> newItems;
public ArrayList<ItemStack> rawItems;
protected List<ItemsPanelGridSlot> gridMask;
protected final Map<Integer, Integer> itemToGroup = new HashMap<>();
protected final Map<Integer, List<ItemStack>> groupItems = new HashMap<>();
protected boolean forceExpand = false;
public void setItems(ArrayList<ItemStack> items) {
newItems = items;
}
public static void updateScale() {
SLOT_SIZE = 2 + (int) Math.ceil(8f * NEIClientConfig.getIntSetting("inventory.itempanelScale") / 100) * 2;
}
@Override
public void refresh(GuiContainer gui) {
if (this.newItems != null) {
this.groupItems.clear();
this.itemToGroup.clear();
this.forceExpand = false;
if (!CollapsibleItems.isEmpty() && !this.newItems.isEmpty()) {
final Set<Integer> groups = new HashSet<>();
boolean outsideGroup = false;
this.realItems = new ArrayList<>();
this.rawItems = new ArrayList<>(this.newItems);
for (ItemStack stack : this.newItems) {
final int groupIndex = CollapsibleItems.getGroupIndex(stack);
if (groupIndex == -1) {
this.realItems.add(stack);
outsideGroup = true;
} else {
if (!groups.contains(groupIndex) || CollapsibleItems.isExpanded(groupIndex)) {
this.itemToGroup.put(this.realItems.size(), groupIndex);
this.realItems.add(stack);
groups.add(groupIndex);
}
this.groupItems.computeIfAbsent(groupIndex, gi -> new ArrayList<>()).add(stack);
}
}
// automatically opens if there are elements from only one group
if (!outsideGroup && groups.size() == 1) {
final int groupIndex = groups.iterator().next();
this.realItems = new ArrayList<>(this.newItems);
this.itemToGroup.clear();
this.forceExpand = true;
for (int itemIndex = 0; itemIndex < this.realItems.size(); itemIndex++) {
this.itemToGroup.put(itemIndex, groupIndex);
}
}
} else {
this.realItems = new ArrayList<>(this.newItems);
}
this.newItems = null;
onItemsChanged();
}
super.refresh(gui);
}
@Override
protected void onGridChanged() {
this.gridMask = null;
super.onGridChanged();
}
@Override
public List<ItemsPanelGridSlot> getMask() {
if (this.gridMask == null) {
this.gridMask = new ArrayList<>();
int itemIndex = page * perPage;
for (int slotIndex = 0; slotIndex < rows * columns && itemIndex < size(); slotIndex++) {
if (!isInvalidSlot(slotIndex)) {
this.gridMask.add(new ItemsPanelGridSlot(slotIndex, itemIndex, getItem(itemIndex)));
itemIndex++;
}
}
calculateGroupBorders(this.gridMask);
}
return this.gridMask;
}
@Override
protected MouseContext getMouseContext(int mousex, int mousey) {
final ItemsPanelGridSlot hovered = getSlotMouseOver(mousex, mousey);
if (hovered != null) {
return new MouseContext(
hovered.slotIndex,
hovered.slotIndex / this.columns,
hovered.slotIndex % this.columns);
}
return null;
}
protected void calculateGroupBorders(List<ItemsPanelGridSlot> gridMask) {
if (gridMask.isEmpty() || this.groupItems.isEmpty()) {
return;
}
final Color collapsedBGColor = new Color(
NEIClientConfig.getSetting("inventory.collapsibleItems.collapsedColor").getHexValue(),
true);
final Color expandedBGColor = new Color(
NEIClientConfig.getSetting("inventory.collapsibleItems.expandedColor").getHexValue(),
true);
final Color collapsedBorderColor = darkerColor(collapsedBGColor);
final Color expandedBorderColor = darkerColor(expandedBGColor);
final Map<Integer, Integer> borderGrid = new HashMap<>();
for (ItemsPanelGridSlot item : gridMask) {
borderGrid.put(item.slotIndex, this.itemToGroup.getOrDefault(item.itemIndex, -1));
}
for (ItemsPanelGridSlot item : gridMask) {
final int groupIndex = borderGrid.get(item.slotIndex);
final List<ItemStack> groupItems = this.groupItems.get(groupIndex);
if (groupItems == null || groupItems.size() == 1) {
continue;
}
int column = item.slotIndex % this.columns;
int row = item.slotIndex / this.columns;
int prevSlotIndex = (row - 1) * this.columns + column;
int nextSlotIndex = (row + 1) * this.columns + column;
item.groupIndex = groupIndex;
item.groupSize = groupItems.size();
item.bgItemStack = groupItems.get(groupItems.size() - 1);
item.displayName = CollapsibleItems.getDisplayName(groupIndex);
item.extended = this.forceExpand || CollapsibleItems.isExpanded(groupIndex);
item.bgColor = item.extended ? expandedBGColor : collapsedBGColor;
item.borderColor = item.extended ? expandedBorderColor : collapsedBorderColor;
item.borderLeft = column == 0 || borderGrid.getOrDefault(item.slotIndex - 1, -1) != groupIndex;
item.borderRight = column + 1 == this.columns
|| borderGrid.getOrDefault(item.slotIndex + 1, -1) != groupIndex;
item.borderTop = borderGrid.getOrDefault(prevSlotIndex, -1) != groupIndex;
item.borderBottom = borderGrid.getOrDefault(nextSlotIndex, -1) != groupIndex;
}
}
private static Color darkerColor(Color color) {
return new Color(
color.getRed(),
color.getGreen(),
color.getBlue(),
Math.min((int) (color.getAlpha() + (255f / 5) * 2), 255));
}
@Override
public String getMessageOnEmpty() {
return ItemList.loadFinished ? null : NEIClientUtils.translate("itempanel.loading");
}
}
@@ -0,0 +1,172 @@
package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.fontRenderer;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.gui.GuiDraw.ITooltipLineHandler;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.ReadableNumberConverter;
public class ItemsTooltipLineHandler implements ITooltipLineHandler {
protected static final int SLOT_SIZE = 18;
protected static final int MAX_COLUMNS = 11;
protected static final int MARGIN_TOP = 2;
protected String label;
protected EnumChatFormatting labelColor = EnumChatFormatting.GRAY;
protected List<ItemStack> items;
protected int activeStackIndex = -1;
protected Dimension size = new Dimension();
protected boolean saveStackSize = false;
protected int columns = 0;
protected int count = 0;
protected int rows = 0;
protected int length = 0;
public ItemsTooltipLineHandler(String label, List<ItemStack> items) {
this(label, items, true, 5);
}
public ItemsTooltipLineHandler(String label, List<ItemStack> items, boolean saveStackSize, int maxRows) {
this.label = label;
this.items = groupingItemStacks(items);
this.saveStackSize = saveStackSize;
this.length = this.items.size();
if (this.length > 0) {
this.columns = Math.min(MAX_COLUMNS, this.length);
this.rows = Math.min(maxRows, (int) Math.ceil((float) this.length / this.columns));
this.size.width = Math.max(this.columns * SLOT_SIZE, fontRenderer.getStringWidth(this.label) + 15);
this.size.height = this.rows * SLOT_SIZE + fontRenderer.FONT_HEIGHT + 2 + MARGIN_TOP;
this.count = Math.min(
this.length,
Math.min(
this.columns * this.rows,
this.length > MAX_COLUMNS * maxRows ? (MAX_COLUMNS * maxRows) : Integer.MAX_VALUE));
if (this.items.size() > this.count) {
String text = "+" + (this.items.size() - this.count);
this.count -= (int) Math.ceil((float) (fontRenderer.getStringWidth(text) - 2) / SLOT_SIZE);
}
}
}
public void setActiveStack(ItemStack activeStack) {
final ItemStack realStack = items.stream().filter(stack -> StackInfo.equalItemAndNBT(stack, activeStack, true))
.findFirst().orElse(null);
this.activeStackIndex = items.indexOf(realStack);
}
public ItemStack getActiveStack() {
return this.activeStackIndex == -1 ? null : this.items.get(this.activeStackIndex);
}
public boolean isEmpty() {
return this.items.isEmpty();
}
@Override
public Dimension getSize() {
return this.size;
}
public void setLabelColor(EnumChatFormatting color) {
this.labelColor = color;
}
@Override
public void draw(int x, int y) {
if (this.length == 0) return;
y += MARGIN_TOP;
fontRenderer.drawStringWithShadow(this.labelColor + this.label + ":", x, y, 0);
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL11.glPushMatrix();
RenderHelper.enableGUIStandardItemLighting();
GL11.glScaled(1, 1, 3);
GL11.glTranslatef(x, y + fontRenderer.FONT_HEIGHT + 2, 0);
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
int indexShift = 0;
if (this.activeStackIndex != -1) {
indexShift = Math.max(0, Math.min(this.items.size() - this.count, this.activeStackIndex - this.count + 2));
}
for (int index = 0; index < this.count && index + indexShift < this.items.size(); index++) {
ItemStack drawStack = this.items.get(index + indexShift);
int col = index % this.columns;
int row = index / this.columns;
String stackSize = !this.saveStackSize || drawStack.stackSize == 0 ? ""
: ReadableNumberConverter.INSTANCE.toWideReadableForm(drawStack.stackSize);
if (this.activeStackIndex == index + indexShift) {
NEIClientUtils.gl2DRenderContext(
() -> GuiDraw.drawRect(col * SLOT_SIZE - 1, row * SLOT_SIZE - 1, 18, 18, 0x66555555));
}
drawItem(col * SLOT_SIZE, row * SLOT_SIZE, drawStack, stackSize);
}
if (this.count < this.items.size()) {
final String text = "+" + (this.items.size() - this.count);
NEIClientUtils.gl2DRenderContext(() -> {
fontRenderer.drawStringWithShadow(
text,
MAX_COLUMNS * SLOT_SIZE - fontRenderer.getStringWidth(text) - 2,
(this.rows - 1) * SLOT_SIZE + (SLOT_SIZE - fontRenderer.FONT_HEIGHT) / 2,
0xee555555);
});
}
GL11.glPopMatrix();
GL11.glPopAttrib();
}
protected void drawItem(int x, int y, ItemStack drawStack, String stackSize) {
GuiContainerManager.drawItem(x, y, drawStack, true, stackSize);
}
private List<ItemStack> groupingItemStacks(List<ItemStack> items) {
final List<ItemStack> result = new ArrayList<>();
for (Map.Entry<NBTTagCompound, Long> entry : ItemStackAmount.of(items).entrySet()) {
final ItemStack stack = StackInfo.loadFromNBT(entry.getKey(), Math.max(0, entry.getValue()));
if (entry.getKey().hasKey("gtFluidName")) {
stack.stackSize = 0;
}
result.add(stack);
}
if (result.isEmpty()) {
result.addAll(items);
}
return result;
}
}
@@ -0,0 +1,21 @@
package codechicken.nei;
import java.util.LinkedHashMap;
import java.util.Map;
// Simple LRUCache
public class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int capacity;
public LRUCache(int capacity) {
super(capacity, 0.75f, true);
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > capacity;
}
}
+184 -80
View File
@@ -14,7 +14,6 @@ import static codechicken.nei.NEIClientConfig.isEnabled;
import static codechicken.nei.NEIClientConfig.isHidden;
import static codechicken.nei.NEIClientConfig.showIDs;
import static codechicken.nei.NEIClientConfig.toggleBooleanSetting;
import static codechicken.nei.NEIClientConfig.world;
import static codechicken.nei.NEIClientUtils.cycleGamemode;
import static codechicken.nei.NEIClientUtils.decreaseSlotStack;
import static codechicken.nei.NEIClientUtils.deleteEverything;
@@ -32,8 +31,11 @@ import static codechicken.nei.NEIClientUtils.toggleMagnetMode;
import static codechicken.nei.NEIClientUtils.toggleRaining;
import static codechicken.nei.NEIClientUtils.translate;
import java.awt.Point;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import net.minecraft.client.Minecraft;
@@ -63,6 +65,7 @@ import codechicken.nei.guihook.IContainerDrawHandler;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.guihook.IContainerObjectHandler;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.recipe.AutoCraftingManager;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.RecipeCatalysts;
@@ -77,28 +80,23 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
/**
* Sorted bottom first
*/
private static TreeSet<Widget> drawWidgets = new TreeSet<>(new WidgetZOrder(false));
private static Set<Widget> drawWidgets = new TreeSet<>(new WidgetZOrder(false));
/**
* Sorted top first
*/
private static TreeSet<Widget> controlWidgets = new TreeSet<>(new WidgetZOrder(true));
private static Set<Widget> controlWidgets = new TreeSet<>(new WidgetZOrder(true));
public static ItemPanel itemPanel;
public static BookmarkPanel bookmarkPanel;
public static SubsetWidget dropDown;
public static PresetsWidget presetsPanel;
public static SearchField searchField;
public static ItemZoom itemZoom;
public static ButtonCycled options;
public static ButtonCycled bookmarksButton;
@Deprecated
public static Button more;
@Deprecated
public static Button less;
@Deprecated
public static ItemQuantityField quantity;
public static Button delete;
@@ -146,8 +144,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
gui.guiTop = (gui.height - gui.ySize) / 2;
if (gui instanceof GuiContainerCreative && gui.buttonList.size() >= 2) {
GuiButton button1 = (GuiButton) gui.buttonList.get(0);
GuiButton button2 = (GuiButton) gui.buttonList.get(1);
GuiButton button1 = gui.buttonList.get(0);
GuiButton button2 = gui.buttonList.get(1);
button1.xPosition = gui.guiLeft;
button2.xPosition = gui.guiLeft + gui.xSize - 20;
}
@@ -168,14 +166,18 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
if (isHidden()) return;
for (Widget widget : controlWidgets) widget.onGuiClick(mousex, mousey);
for (Widget widget : controlWidgets) {
widget.onGuiClick(mousex, mousey);
}
}
@Override
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
if (isHidden()) return false;
if (!isEnabled()) return options.contains(mousex, mousey) && options.handleClick(mousex, mousey, button);
if (!isEnabled()) {
return options.contains(mousex, mousey) && options.handleClick(mousex, mousey, button);
}
for (Widget widget : controlWidgets) {
widget.onGuiClick(mousex, mousey);
@@ -189,10 +191,22 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public boolean objectUnderMouse(GuiContainer gui, int mousex, int mousey) {
if (!isHidden() && isEnabled())
for (Widget widget : drawWidgets) if (widget.contains(mousex, mousey)) return true;
return getWidgetUnderMouse(mousex, mousey) != null;
}
return false;
public Widget getWidgetUnderMouse(int mousex, int mousey) {
if (isHidden() || !isEnabled()) {
return null;
}
for (Widget widget : controlWidgets) {
if (widget.contains(mousex, mousey)) {
return widget;
}
}
return null;
}
public boolean keyTyped(GuiContainer gui, char keyChar, int keyID) {
@@ -217,19 +231,14 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
}
if (NEIClientConfig.isKeyHashDown("gui.hide_bookmarks")) {
toggleBooleanSetting("inventory.bookmarksEnabled");
toggleBooleanSetting("inventory.bookmarks.enabled");
return true;
}
if (NEIClientConfig.isKeyHashDown("gui.next_tooltip")) {
GuiContainerManager.incrementTooltipPage();
if (NEIClientConfig.isKeyHashDown("gui.next_tooltip") && GuiContainerManager.incrementTooltipPage()) {
return true;
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark_pull_items")) {
return bookmarkPanel.pullBookmarkItems();
}
if (isEnabled() && !isHidden()) {
for (Widget widget : controlWidgets) if (inputFocused == null) widget.lastKeyTyped(keyID, keyChar);
}
@@ -252,12 +261,12 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public ItemStack getStackUnderMouse(GuiContainer gui, int mousex, int mousey) {
if (!isHidden() && isEnabled()) {
for (Widget widget : drawWidgets) {
ItemStack stack = widget.getStackMouseOver(mousex, mousey);
if (stack != null) return stack;
}
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused != null) {
return focused.getStackMouseOver(mousex, mousey);
}
return null;
}
@@ -286,16 +295,32 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public void postRenderTooltips(GuiContainer gui, int mousex, int mousey, List<String> tooltip) {
if (!isHidden() && isEnabled()) {
for (Widget widget : drawWidgets) widget.postDrawTooltips(mousex, mousey, tooltip);
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused != null) {
focused.postDrawTooltips(mousex, mousey, tooltip);
}
}
}
@Override
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
for (Widget widget : drawWidgets) currenttip = widget.handleTooltip(mousex, mousey, currenttip);
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused != null) {
currenttip = focused.handleTooltip(mousex, mousey, currenttip);
if (focused instanceof IContainerTooltipHandler tip) {
currenttip = tip.handleTooltip(gui, mousex, mousey, currenttip);
}
}
}
return currenttip;
}
@@ -312,29 +337,55 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
currenttip.set(0, mainname);
}
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
final Point mouse = GuiDraw.getMousePosition();
final Widget focused = getWidgetUnderMouse(mouse.x, mouse.y);
if (focused instanceof IContainerTooltipHandler tip) {
currenttip = tip.handleItemDisplayName(gui, stack, currenttip);
}
}
return currenttip;
}
@Override
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
List<String> currenttip) {
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused instanceof IContainerTooltipHandler tip) {
currenttip = tip.handleItemTooltip(gui, itemstack, mousex, mousey, currenttip);
}
}
return currenttip;
}
@Override
public Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused instanceof IContainerTooltipHandler tip) {
hotkeys = tip.handleHotkeys(gui, mousex, mousey, hotkeys);
}
}
return hotkeys;
}
public static void layout(GuiContainer gui) {
VisiblityData visiblity = new VisiblityData();
if (isHidden()) visiblity.showNEI = false;
if (isBookmarkPanelHidden()) visiblity.showBookmarkPanel = false;
if (gui.height - gui.ySize <= 40) visiblity.showSearchSection = false;
if (visiblity.showBookmarkPanel || gui.guiTop <= 20) visiblity.showSubsetDropdown = false;
if (!visiblity.showBookmarkPanel || gui.guiTop <= 20) visiblity.showPresetsDropdown = false;
if (gui.guiLeft - 4 < 76) visiblity.showWidgets = false;
visiblity.showNEI = !isHidden();
visiblity.showBookmarkPanel = !isBookmarkPanelHidden();
visiblity.showSearchSection = !(gui.height - gui.ySize <= 40 && NEIClientConfig.isSearchWidgetCentered());
visiblity.showSubsetDropdown = NEIClientConfig.showSubsetWidget()
&& (gui.guiTop > 20 || visiblity.showSearchSection && !NEIClientConfig.subsetWidgetOnTop());
visiblity.showWidgets = gui.guiLeft - 4 > 76;
try {
GuiInfo.readLock.lock();
@@ -357,9 +408,11 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
bookmarkPanel = ItemPanels.bookmarkPanel;
bookmarkPanel.init();
itemZoom = new ItemZoom();
dropDown = new SubsetWidget();
presetsPanel = new PresetsWidget();
searchField = new SearchField("search");
API.addItemFilter(searchField);
options = new ButtonCycled(3) {
@@ -381,7 +434,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public boolean onButtonPress(boolean rightclick) {
if (!rightclick) {
if (Keyboard.getEventKeyState() && getIsAccessibleControlEventKey()) {
if (Keyboard.getEventKeyState() && getIsAccessibleControlEventKey()
&& NEIClientConfig.canChangeCheatMode()) {
NEIClientConfig.cycleSetting("inventory.cheatmode", 3);
} else {
if (Keyboard.getEventKeyState() && (Keyboard.getEventKey() == Keyboard.KEY_LSHIFT
@@ -405,7 +459,10 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
else if (cheatMode == 2) modeColor = EnumChatFormatting.RED.toString();
String controlKeyLocalization = translate(Minecraft.isRunningOnMac ? "key.ctrl.mac" : "key.ctrl");
tooltip.add(modeColor + translate("inventory.options.tip.cheatmode." + cheatMode));
tooltip.add(modeColor + translate("inventory.options.tip.cheatmode.disable", controlKeyLocalization));
if (NEIClientConfig.canChangeCheatMode()) {
tooltip.add(
modeColor + translate("inventory.options.tip.cheatmode.disable", controlKeyLocalization));
}
}
@Override
@@ -424,7 +481,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public boolean onButtonPress(boolean rightclick) {
NEIClientConfig.toggleBooleanSetting("inventory.bookmarksEnabled");
NEIClientConfig.toggleBooleanSetting("inventory.bookmarks.enabled");
return true;
}
@@ -438,9 +495,43 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
}
};
more = ItemPanels.itemPanel.more;
less = ItemPanels.itemPanel.less;
quantity = ItemPanels.itemPanel.quantity;
more = new Button("+") {
@Override
public boolean onButtonPress(boolean rightclick) {
if (rightclick) return false;
int modifier = NEIClientUtils.controlKey() ? 64 : NEIClientUtils.shiftKey() ? 10 : 1;
int quantity = NEIClientConfig.getItemQuantity() + modifier;
if (quantity < 0) {
quantity = 0;
}
LayoutManager.quantity.setText(Integer.toString(quantity));
return true;
}
};
less = new Button("-") {
@Override
public boolean onButtonPress(boolean rightclick) {
if (rightclick) return false;
int modifier = NEIClientUtils.controlKey() ? -64 : NEIClientUtils.shiftKey() ? -10 : -1;
int quantity = NEIClientConfig.getItemQuantity() + modifier;
if (quantity < 0) {
quantity = 0;
}
LayoutManager.quantity.setText(Integer.toString(quantity));
return true;
}
};
quantity = new ItemQuantityField("quantity");
delete = new Button() {
@Override
@@ -616,12 +707,12 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
if (!itemsLoaded) {
ItemList.loadItems.restart();
itemsLoaded = true;
}
overlayRenderer = null;
overlayRenderer = null;
getLayoutStyle().init();
layout(gui);
AutoFocusWidget.instance.load(gui);
}
NEIController.load(gui);
@@ -653,14 +744,15 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
addWidget(options);
addWidget(bookmarksButton);
if (visiblity.showItemPanel && NEIClientConfig.showItemQuantityWidget()) {
addWidget(quantity);
addWidget(more);
addWidget(less);
}
if (visiblity.showItemPanel) {
if (PresetsWidget.inEditMode()) {
drawWidgets.add(itemPanel);
} else {
addWidget(itemPanel);
}
addWidget(itemPanel);
itemPanel.setVisible();
}
@@ -669,13 +761,13 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
bookmarkPanel.setVisible();
}
if (visiblity.showPresetsDropdown) {
addWidget(presetsPanel);
}
searchField.setVisible(visiblity.showSearchSection);
if (visiblity.showSearchSection) {
if (visiblity.showSearchSection && NEIClientConfig.isSearchWidgetCentered()
|| visiblity.showItemPanel && !NEIClientConfig.isSearchWidgetCentered()) {
searchField.setVisible(true);
addWidget(searchField);
} else {
searchField.setVisible(false);
searchField.setFocus(false);
}
if (visiblity.showUtilityButtons) {
@@ -690,6 +782,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
if (canPerformAction("delete")) addWidget(delete);
}
addWidget(itemZoom);
if (visiblity.showSubsetDropdown) {
// Bookmarks or Subset/dropdown
addWidget(dropDown);
@@ -724,7 +818,9 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
if (isHidden() || !isEnabled()) return false;
for (Widget widget : drawWidgets) if (widget.onMouseWheel(scrolled, mousex, mousey)) return true;
for (Widget widget : controlWidgets) {
if (widget.onMouseWheel(scrolled, mousex, mousey)) return true;
}
return false;
}
@@ -734,7 +830,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public boolean shouldShowTooltip(GuiContainer gui) {
return itemPanel.draggedStack == null && bookmarkPanel.sortedStackIndex == -1;
return itemPanel.draggedStack == null && !bookmarkPanel.inEditingState() && !AutoCraftingManager.processing();
}
/** Note: this method isn't actually used by this mod, but NEI add-ons might need it. */
@@ -757,17 +853,19 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public void renderSlotOverlay(GuiContainer window, Slot slot) {
ItemStack item = slot.getStack();
if (world.nbt.getBoolean("searchinventories") && (item == null ? !getSearchExpression().equals("")
: !((SearchField) searchField).getFilter().matches(item))) {
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glTranslatef(0, 0, 150);
drawRect(slot.xDisplayPosition, slot.yDisplayPosition, 16, 16, 0x80000000);
GL11.glTranslatef(0, 0, -150);
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_DEPTH_TEST);
if (SearchField.searchInventories()) {
ItemStack item = slot.getStack();
if (item == null ? !getSearchExpression().equals("") : !searchField.getFilter().matches(item)) {
NEIClientUtils.gl2DRenderContext(() -> {
GL11.glTranslatef(0, 0, 150);
drawRect(slot.xDisplayPosition, slot.yDisplayPosition, 16, 16, 0x80000000);
GL11.glTranslatef(0, 0, -150);
});
}
}
}
public static void drawIcon(int x, int y, Image image) {
@@ -823,9 +921,15 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
drawTexturedModalRect(x2, y2, tx2, ty2, w2, h2); // bottom right
}
public static void drawItemPresenceOverlay(int slotX, int slotY, boolean isPresent) {
Image icon = itemPresenceOverlays[isPresent ? 1 : 0];
drawIcon(slotX + 16 - icon.width, slotY + 16 - icon.height, icon);
public static void drawItemPresenceOverlay(int slotX, int slotY, boolean isPresent, boolean slotHighlight) {
if (slotHighlight) {
NEIClientUtils.gl2DRenderContext(() -> drawRect(slotX, slotY, 16, 16, isPresent ? 0x8000AA00 : 0x80AA0000));
} else {
Image icon = itemPresenceOverlays[isPresent ? 1 : 0];
drawIcon(slotX + 16 - icon.width, slotY + 16 - icon.height, icon);
}
}
public static LayoutManager instance() {
@@ -1,34 +1,20 @@
package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.drawStringC;
import static codechicken.nei.LayoutManager.bookmarkPanel;
import static codechicken.nei.LayoutManager.bookmarksButton;
import static codechicken.nei.LayoutManager.delete;
import static codechicken.nei.LayoutManager.dropDown;
import static codechicken.nei.LayoutManager.gamemode;
import static codechicken.nei.LayoutManager.heal;
import static codechicken.nei.LayoutManager.itemPanel;
import static codechicken.nei.LayoutManager.itemPresenceOverlays;
import static codechicken.nei.LayoutManager.magnet;
import static codechicken.nei.LayoutManager.options;
import static codechicken.nei.LayoutManager.presetsPanel;
import static codechicken.nei.LayoutManager.rain;
import static codechicken.nei.LayoutManager.searchField;
import static codechicken.nei.LayoutManager.timeButtons;
import static codechicken.nei.NEIClientConfig.canPerformAction;
import static codechicken.nei.NEIClientConfig.disabledActions;
import static codechicken.nei.NEIClientConfig.getMagnetMode;
import static codechicken.nei.NEIClientConfig.isEnabled;
import net.minecraft.client.gui.inventory.GuiContainer;
import org.lwjgl.opengl.GL11;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.api.LayoutStyle;
import codechicken.nei.drawable.DrawableBuilder;
public class LayoutStyleMinecraft extends LayoutStyle {
protected static final int BUTTON_SIZE = 20;
protected static final int MARGIN = 2;
public int buttonCount;
public int leftSize;
public int numButtons;
@@ -40,19 +26,21 @@ public class LayoutStyleMinecraft extends LayoutStyle {
@Override
public void init() {
delete.icon = new Image(144, 12, 12, 12);
rain.icon = new Image(120, 12, 12, 12);
gamemode.icons[0] = new Image(132, 12, 12, 12);
gamemode.icons[1] = new Image(156, 12, 12, 12);
gamemode.icons[2] = new Image(168, 12, 12, 12);
magnet.icon = new Image(180, 24, 12, 12);
timeButtons[0].icon = new Image(132, 24, 12, 12);
timeButtons[1].icon = new Image(120, 24, 12, 12);
timeButtons[2].icon = new Image(144, 24, 12, 12);
timeButtons[3].icon = new Image(156, 24, 12, 12);
heal.icon = new Image(168, 24, 12, 12);
itemPresenceOverlays[0] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 0, 40, 8, 8).build();
itemPresenceOverlays[1] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 8, 40, 8, 8).build();
LayoutManager.delete.icon = new Image(144, 12, 12, 12);
LayoutManager.rain.icon = new Image(120, 12, 12, 12);
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.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);
LayoutManager.timeButtons[3].icon = new Image(156, 24, 12, 12);
LayoutManager.heal.icon = new Image(168, 24, 12, 12);
LayoutManager.itemPresenceOverlays[0] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 0, 40, 8, 8)
.build();
LayoutManager.itemPresenceOverlays[1] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 8, 40, 8, 8)
.build();
}
@Override
@@ -65,89 +53,177 @@ public class LayoutStyleMinecraft extends LayoutStyle {
reset();
leftSize = ItemPanels.bookmarkPanel.getWidth(gui);
numButtons = Math.max(leftSize / 18, 1);
numButtons = Math.max(leftSize / 20, 1);
delete.state = 0x4;
if (NEIController.getDeleteMode()) delete.state |= 1;
else if (!visiblity.enableDeleteMode) delete.state |= 2;
rain.state = 0x4;
if (disabledActions.contains("rain")) rain.state |= 2;
else if (NEIClientUtils.isRaining()) rain.state |= 1;
gamemode.state = 0x4;
if (NEIClientUtils.getGamemode() != 0) {
gamemode.state |= 0x1;
gamemode.index = NEIClientUtils.getGamemode() - 1;
} else {
if (NEIClientUtils.isValidGamemode("creative")) gamemode.index = 0;
else if (NEIClientUtils.isValidGamemode("creative+")) gamemode.index = 1;
else if (NEIClientUtils.isValidGamemode("adventure")) gamemode.index = 2;
LayoutManager.delete.state = 0x4;
if (NEIController.getDeleteMode()) {
LayoutManager.delete.state |= 1;
} else if (!visiblity.enableDeleteMode) {
LayoutManager.delete.state |= 2;
}
bookmarksButton.index = NEIClientConfig.isBookmarkPanelHidden() ? 0 : 1;
options.index = NEIClientConfig.getCheatMode();
magnet.state = 0x4 | (getMagnetMode() ? 1 : 0);
LayoutManager.rain.state = 0x4;
if (NEIClientConfig.disabledActions.contains("rain")) {
LayoutManager.rain.state |= 2;
} else if (NEIClientUtils.isRaining()) {
LayoutManager.rain.state |= 1;
}
if (canPerformAction("delete")) layoutButton(delete);
if (canPerformAction("rain")) layoutButton(rain);
if (NEIClientUtils.isValidGamemode("creative") || NEIClientUtils.isValidGamemode("creative+")
|| NEIClientUtils.isValidGamemode("adventure"))
layoutButton(gamemode);
if (canPerformAction("magnet")) layoutButton(magnet);
if (canPerformAction("time")) {
for (int i = 0; i < 4; i++) {
timeButtons[i].state = disabledActions.contains(NEIActions.timeZones[i]) ? 2 : 0;
layoutButton(timeButtons[i]);
LayoutManager.gamemode.state = 0x4;
if (NEIClientUtils.getGamemode() != 0) {
LayoutManager.gamemode.state |= 0x1;
LayoutManager.gamemode.index = NEIClientUtils.getGamemode() - 1;
} else {
if (NEIClientUtils.isValidGamemode("creative")) {
LayoutManager.gamemode.index = 0;
} else if (NEIClientUtils.isValidGamemode("creative+")) {
LayoutManager.gamemode.index = 1;
} else if (NEIClientUtils.isValidGamemode("adventure")) {
LayoutManager.gamemode.index = 2;
}
}
if (canPerformAction("heal")) layoutButton(heal);
LayoutManager.bookmarksButton.index = NEIClientConfig.isBookmarkPanelHidden() ? 0 : 1;
LayoutManager.options.index = NEIClientConfig.getCheatMode();
itemPanel.resize(gui);
bookmarkPanel.resize(gui);
LayoutManager.magnet.state = 0x4 | (NEIClientConfig.getMagnetMode() ? 1 : 0);
options.x = isEnabled() ? 0 : 6;
options.y = isEnabled() ? gui.height - 22 : gui.height - 28;
options.w = 22;
options.h = 22;
if (NEIClientConfig.canPerformAction("delete")) {
layoutButton(LayoutManager.delete);
}
bookmarksButton.x = 24 + (isEnabled() ? 0 : 6);
bookmarksButton.y = isEnabled() ? gui.height - 22 : gui.height - 28;
bookmarksButton.w = 22;
bookmarksButton.h = 22;
if (NEIClientConfig.canPerformAction("rain")) {
layoutButton(LayoutManager.rain);
}
dropDown.h = 18;
dropDown.w = 150;
dropDown.y = 0;
dropDown.x = (gui.width - gui.xSize) / 2 + gui.xSize - dropDown.w;
if (NEIClientUtils.isValidGamemode("creative") || NEIClientUtils.isValidGamemode("creative+")
|| NEIClientUtils.isValidGamemode("adventure")) {
layoutButton(LayoutManager.gamemode);
}
presetsPanel.h = 16;
presetsPanel.w = 150;
presetsPanel.y = 2;
presetsPanel.x = (gui.width - gui.xSize) / 2 + gui.xSize - presetsPanel.w;
if (NEIClientConfig.canPerformAction("magnet")) {
layoutButton(LayoutManager.magnet);
}
searchField.h = 20;
if (NEIClientConfig.isSearchWidgetCentered()) {
searchField.w = 150;
searchField.x = (gui.width - searchField.w) / 2;
if (NEIClientConfig.canPerformAction("time")) {
for (int i = 0; i < 4; i++) {
LayoutManager.timeButtons[i].state = NEIClientConfig.disabledActions.contains(NEIActions.timeZones[i])
? 2
: 0;
layoutButton(LayoutManager.timeButtons[i]);
}
}
if (NEIClientConfig.canPerformAction("heal")) {
layoutButton(LayoutManager.heal);
}
layoutFooter(gui, visiblity);
LayoutManager.itemPanel.resize(gui);
LayoutManager.bookmarkPanel.resize(gui);
LayoutManager.itemZoom.resize(gui);
}
protected void layoutFooter(GuiContainer gui, VisiblityData visiblity) {
LayoutManager.options.x = MARGIN;
LayoutManager.options.y = gui.height - BUTTON_SIZE - MARGIN;
LayoutManager.options.w = LayoutManager.options.h = BUTTON_SIZE;
LayoutManager.bookmarksButton.x = LayoutManager.options.x + LayoutManager.options.w + MARGIN;
LayoutManager.bookmarksButton.y = gui.height - BUTTON_SIZE - MARGIN;
LayoutManager.bookmarksButton.w = LayoutManager.bookmarksButton.h = BUTTON_SIZE;
final Rectangle4i searchArea = getSearchFieldArea(gui);
final Rectangle4i quantityArea = getQuantityFieldArea(visiblity);
LayoutManager.searchField.x = searchArea.x;
LayoutManager.searchField.y = searchArea.y;
LayoutManager.searchField.w = searchArea.w;
LayoutManager.searchField.h = searchArea.h;
if (!NEIClientConfig.subsetWidgetOnTop() && visiblity.showSubsetDropdown) {
LayoutManager.dropDown.x = searchArea.x;
LayoutManager.dropDown.y = searchArea.y;
LayoutManager.dropDown.h = LayoutManager.dropDown.w = BUTTON_SIZE;
LayoutManager.searchField.x += BUTTON_SIZE;
LayoutManager.searchField.w -= BUTTON_SIZE;
} else {
searchField.w = (int) (itemPanel.w * (NEIClientConfig.showItemQuantityWidget() ? 0.7 : 1));
searchField.x = itemPanel.x;
LayoutManager.dropDown.h = 16;
LayoutManager.dropDown.w = 150;
LayoutManager.dropDown.y = MARGIN;
LayoutManager.dropDown.x = (gui.width - LayoutManager.dropDown.w) / 2;
}
searchField.y = gui.height - searchField.h - 2;
if (!visiblity.showItemSection) {
searchField.setFocus(false);
if (quantityArea.w == ItemPanels.itemPanel.w) {
LayoutManager.more.w = LayoutManager.less.w = BUTTON_SIZE;
LayoutManager.more.h = LayoutManager.less.h = LayoutManager.quantity.h = quantityArea.h;
LayoutManager.more.y = LayoutManager.less.y = LayoutManager.quantity.y = quantityArea.y;
LayoutManager.less.x = quantityArea.x;
LayoutManager.more.x = quantityArea.x2() - BUTTON_SIZE;
LayoutManager.quantity.x = LayoutManager.less.x + LayoutManager.less.w + 1;
LayoutManager.quantity.w = LayoutManager.more.x - LayoutManager.quantity.x - 1;
} else {
LayoutManager.quantity.x = quantityArea.x;
LayoutManager.quantity.w = quantityArea.w - 18;
LayoutManager.quantity.y = LayoutManager.more.y = quantityArea.y;
LayoutManager.quantity.h = quantityArea.h;
LayoutManager.more.w = LayoutManager.less.w = 18;
LayoutManager.more.x = LayoutManager.less.x = LayoutManager.quantity.x + LayoutManager.quantity.w;
LayoutManager.more.h = LayoutManager.less.h = LayoutManager.quantity.h / 2;
LayoutManager.less.y = LayoutManager.more.y + LayoutManager.more.h;
}
}
private Rectangle4i getSearchFieldArea(GuiContainer gui) {
final Rectangle4i area = new Rectangle4i(0, 0, 0, BUTTON_SIZE);
if (NEIClientConfig.isSearchWidgetCentered()) {
area.w = Math.min(gui.xSize, 176) - MARGIN * 2;
area.x = (gui.width - area.w) / 2;
area.y = gui.height - BUTTON_SIZE - MARGIN;
} else if (NEIClientConfig.showItemQuantityWidget()) {
area.w = ItemPanels.itemPanel.w - (int) Math.max(BUTTON_SIZE * 2.5f, ItemPanels.itemPanel.w * 0.3f) - 1;
area.x = ItemPanels.itemPanel.x;
area.y = ItemPanels.itemPanel.y + ItemPanels.itemPanel.h - BUTTON_SIZE;
} else {
area.w = ItemPanels.itemPanel.w;
area.x = ItemPanels.itemPanel.x;
area.y = ItemPanels.itemPanel.y + ItemPanels.itemPanel.h - BUTTON_SIZE;
}
return area;
}
private Rectangle4i getQuantityFieldArea(VisiblityData visiblity) {
final Rectangle4i area = new Rectangle4i(0, 0, 0, BUTTON_SIZE);
if (!visiblity.showSearchSection || NEIClientConfig.isSearchWidgetCentered()) {
area.w = ItemPanels.itemPanel.w;
area.x = ItemPanels.itemPanel.x;
} else {
area.w = (int) Math.max(BUTTON_SIZE * 2.5f, ItemPanels.itemPanel.w * 0.3f);
area.x = ItemPanels.itemPanel.x + ItemPanels.itemPanel.w - area.w;
}
area.y = ItemPanels.itemPanel.y + ItemPanels.itemPanel.h - BUTTON_SIZE;
return area;
}
public void layoutButton(Button button) {
button.x = 2 + (buttonCount % numButtons) * 19;
button.y = 2 + (buttonCount / numButtons) * 18;
button.h = 17;
button.w = button.contentWidth() + 6;
button.x = MARGIN + (buttonCount % numButtons) * (button.w + MARGIN);
button.y = MARGIN + (buttonCount / numButtons) * (button.h + MARGIN);
buttonCount++;
}
@@ -181,9 +257,16 @@ public class LayoutStyleMinecraft extends LayoutStyle {
@Override
public void drawSubsetTag(String text, int x, int y, int w, int h, int state, boolean mouseover) {
if (state == 1) GL11.glColor4f(0.65F, 0.65F, 0.65F, 1.0F);
else GL11.glColor4f(1, 1, 1, 1);
if (state == 1) {
GL11.glColor4f(0.65F, 0.65F, 0.65F, 1.0F);
} else {
GL11.glColor4f(1, 1, 1, 1);
}
LayoutManager.drawButtonBackground(x, y, w, h, false, state == 0 ? 0 : 1);
if (text != null) drawStringC(text, x, y, w, h, state == 2 ? 0xFFE0E0E0 : 0xFFA0A0A0);
if (text != null) {
drawStringC(text, x, y, w, h, mouseover ? 0xFFFFFFA0 : (state == 2 ? 0xFFE0E0E0 : 0xFFA0A0A0));
}
}
}
+2 -1
View File
@@ -1,6 +1,7 @@
package codechicken.nei;
import static codechicken.nei.PacketIDs.*;
import static codechicken.nei.PacketIDs.C2S;
import static codechicken.nei.PacketIDs.S2C;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiInventory;
File diff suppressed because it is too large. Load diff
+134 -26
View File
@@ -8,6 +8,7 @@ import static codechicken.nei.NEIClientConfig.hasSMPCounterPart;
import static codechicken.nei.NEIClientConfig.invCreativeMode;
import static codechicken.nei.NEIClientConfig.world;
import java.awt.Color;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigInteger;
@@ -25,43 +26,79 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
import java.util.stream.Collectors;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IChatComponent;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import com.google.common.collect.Iterables;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.inventory.InventoryRange;
import codechicken.lib.inventory.InventoryUtils;
import codechicken.lib.util.LangProxy;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.IInfiniteItemHandler;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.util.NEIKeyboardUtils;
import codechicken.nei.util.NEIMouseUtils;
public class NEIClientUtils extends NEIServerUtils {
public static class Alignment {
public final int x, y;
public static final Alignment TopLeft = new Alignment(-1, -1);
public static final Alignment TopCenter = new Alignment(0, -1);
public static final Alignment TopRight = new Alignment(1, -1);
public static final Alignment CenterLeft = new Alignment(-1, 0);
public static final Alignment Center = new Alignment(0, 0);
public static final Alignment CenterRight = new Alignment(1, 0);
public static final Alignment BottomLeft = new Alignment(-1, 1);
public static final Alignment BottomCenter = new Alignment(0, 1);
public static final Alignment BottomRight = new Alignment(1, 1);
public Alignment(int x, int y) {
this.x = x;
this.y = y;
}
public float getX(float parentWidth, float childWidth) {
final float x = (this.x + 1) / 2f;
return parentWidth * x - childWidth * x;
}
public float getY(float parentHeight, float childHeight) {
final float y = (this.y + 1) / 2f;
return parentHeight * y - childHeight * y;
}
}
public static LangProxy lang = new LangProxy("nei");
/** Formats a number with group separator and at most 2 fraction digits. */
private static final Map<Locale, DecimalFormat> decimalFormatters = new HashMap<>();
public static final int ALT_HASH = 1 << 27;
public static final int SHIFT_HASH = 1 << 26;
public static final int CTRL_HASH = 1 << 25;
public static final int ALT_HASH = NEIKeyboardUtils.ALT_HASH;
public static final int SHIFT_HASH = NEIKeyboardUtils.SHIFT_HASH;
public static final int CTRL_HASH = NEIKeyboardUtils.CTRL_HASH;
public static Minecraft mc() {
return Minecraft.getMinecraft();
@@ -308,7 +345,7 @@ public class NEIClientUtils extends NEIServerUtils {
}
public static void sendCommand(String command, Object... args) {
if (command.length() == 0) return;
if (command.isEmpty()) return;
NumberFormat numberformat = NumberFormat.getIntegerInstance();
numberformat.setGroupingUsed(false);
@@ -367,18 +404,23 @@ public class NEIClientUtils extends NEIServerUtils {
}
public static String cropText(FontRenderer fontRenderer, String text, int containerWidth) {
int textWidth = fontRenderer.getStringWidth(text);
if (textWidth > containerWidth) {
textWidth += fontRenderer.getStringWidth("...");
int dots = fontRenderer.getStringWidth("...");
while (textWidth > containerWidth) {
textWidth -= fontRenderer.getCharWidth(text.charAt(text.length() - 1));
text = text.substring(0, text.length() - 1);
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 + "...";
}
return text + "...";
return "...";
}
return text;
@@ -394,7 +436,6 @@ public class NEIClientUtils extends NEIServerUtils {
public static void setItemQuantity(int i) {
world.nbt.setInteger("quantity", i);
world.saveNBT();
}
public static GuiContainer getGuiContainer() {
@@ -434,11 +475,7 @@ public class NEIClientUtils extends NEIServerUtils {
if (Keyboard.getEventKeyState()) {
final int keycode = Keyboard.getEventKey();
if (keycode != Keyboard.KEY_LSHIFT && keycode != Keyboard.KEY_RSHIFT
&& keycode != Keyboard.KEY_LCONTROL
&& keycode != Keyboard.KEY_RCONTROL
&& keycode != Keyboard.KEY_LMENU
&& keycode != Keyboard.KEY_RMENU) {
if (!NEIKeyboardUtils.isHashKey(keycode)) {
return getMetaHash() + keycode;
}
}
@@ -446,6 +483,22 @@ public class NEIClientUtils extends NEIServerUtils {
return Keyboard.CHAR_NONE;
}
public static String getKeyName(int keyBind, int mouseBind) {
StringJoiner keyText = new StringJoiner(" + ");
String keyHash = keyBind == Keyboard.KEY_NONE ? "" : NEIKeyboardUtils.getKeyName(keyBind);
String mouseHash = mouseBind == NEIMouseUtils.MOUSE_BTN_NONE ? "" : NEIMouseUtils.getKeyName(mouseBind);
if (!keyHash.isEmpty()) {
keyText.add(keyHash);
}
if (!mouseHash.isEmpty()) {
keyText.add(mouseHash);
}
return keyText.toString();
}
public static void playClickSound() {
mc().getSoundHandler()
.playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F));
@@ -457,16 +510,9 @@ public class NEIClientUtils extends NEIServerUtils {
String stackTrace = cause + sw;
if (buffer.contains(stackTrace)) return;
System.err.println("Error while rendering: " + cause);
System.err.println("Error while rendering: " + cause + " (" + e.getMessage() + ")");
e.printStackTrace();
buffer.add(stackTrace);
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
if (player != null) {
IChatComponent chat = new ChatComponentTranslation("nei.chat.render.error");
chat.getChatStyle().setColor(EnumChatFormatting.RED);
player.addChatComponentMessage(chat);
}
}
public static void reportErrorBuffered(Throwable e, Set<String> buffer, ItemStack cause) {
@@ -476,4 +522,66 @@ public class NEIClientUtils extends NEIServerUtils {
reportErrorBuffered(e, buffer, "null");
}
}
public static void drawRect(double left, double top, double width, double height, Color color) {
Tessellator tessellator = Tessellator.instance;
GL11.glEnable(GL11.GL_BLEND);
GL11.glDisable(GL11.GL_TEXTURE_2D);
OpenGlHelper.glBlendFunc(770, 771, 1, 0);
GL11.glColor4f(color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
tessellator.startDrawingQuads();
tessellator.addVertex(left, top + height, 0.0D);
tessellator.addVertex(left + width, top + height, 0.0D);
tessellator.addVertex(left + width, top, 0.0D);
tessellator.addVertex(left, top, 0.0D);
tessellator.draw();
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_BLEND);
}
public static void drawNEIOverlayText(String text, Rectangle4i rect, float scale, int color, boolean shadow,
Alignment alignment) {
final float screenScale = mc().currentScreen.width * 1f / mc().displayWidth;
final double smallTextScale = Math
.max(screenScale, (Math.max(scale, 1f) * (GuiDraw.fontRenderer.getUnicodeFlag() ? 3F / 4F : 1F / 2F)));
NEIClientUtils.gl2DRenderContext(() -> {
final int width = GuiDraw.fontRenderer.getStringWidth(text);
final float partW = rect.w / 2f;
final float partH = rect.h / 2f;
final double offsetX = Math
.ceil(rect.x + partW + partW * alignment.x - (width / 2f * (alignment.x + 1)) * smallTextScale);
final double offsetY = Math.ceil(
rect.y + partH
+ partH * alignment.y
- (GuiDraw.fontRenderer.FONT_HEIGHT / 2f * (alignment.y + 1)) * smallTextScale);
GL11.glTranslated(offsetX, offsetY, 0);
GL11.glScaled(smallTextScale, smallTextScale, 1);
GuiDraw.fontRenderer.drawString(text, 0, 0, color, shadow);
GL11.glScaled(1 / smallTextScale, 1 / smallTextScale, 1);
GL11.glTranslated(-1 * offsetX, -1 * offsetY, 0);
});
}
public static void drawNEIOverlayText(String text, int x, int y) {
drawNEIOverlayText(text, new Rectangle4i(x, y, 16, 16), 0.5f, 0xFDD835, false, Alignment.TopLeft);
}
public static void gl2DRenderContext(Runnable callback) {
boolean isLighting = GL11.glGetBoolean(GL11.GL_LIGHTING);
boolean isDepthTest = GL11.glGetBoolean(GL11.GL_DEPTH_TEST);
boolean isAlphaTest = GL11.glGetBoolean(GL11.GL_ALPHA_TEST);
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_ALPHA_TEST);
GL11.glDisable(GL11.GL_DEPTH_TEST);
callback.run();
if (isLighting) GL11.glEnable(GL11.GL_LIGHTING);
if (isDepthTest) GL11.glEnable(GL11.GL_DEPTH_TEST);
if (!isAlphaTest) GL11.glDisable(GL11.GL_ALPHA_TEST);
}
}
@@ -1,7 +1,12 @@
package codechicken.nei;
import java.io.File;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import net.minecraft.util.EnumChatFormatting;
@@ -20,8 +25,10 @@ import cpw.mods.fml.common.DummyModContainer;
import cpw.mods.fml.common.LoadController;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModMetadata;
import cpw.mods.fml.common.discovery.ASMDataTable;
import cpw.mods.fml.common.event.FMLInitializationEvent;
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.versioning.ArtifactVersion;
@@ -33,6 +40,9 @@ public class NEIModContainer extends DummyModContainer {
public static LinkedList<IConfigureNEI> plugins = new LinkedList<>();
private static boolean gregTech5Loaded;
private static boolean gtnhLibLoaded;
private static ASMDataTable asmDataTable;
public NEIModContainer() {
super(getModMetadata());
@@ -54,16 +64,23 @@ public class NEIModContainer extends DummyModContainer {
return gregTech5Loaded;
}
public static boolean isGTNHLibLoaded() {
return gtnhLibLoaded;
}
@Override
public Set<ArtifactVersion> getRequirements() {
Set<ArtifactVersion> deps = new HashSet<>();
deps.add(VersionParser.parseVersionReference("CodeChickenCore@[" + CodeChickenCorePlugin.version + ",)"));
deps.add(VersionParser.parseVersionReference("CodeChickenCore@[" + codechicken.core.asm.Tags.VERSION + ",)"));
return deps;
}
@Override
public List<ArtifactVersion> getDependencies() {
return new LinkedList<>(getRequirements());
List<ArtifactVersion> deps = new ArrayList<>();
deps.add(VersionParser.parseVersionReference("CodeChickenCore@[" + codechicken.core.asm.Tags.VERSION + ",)"));
deps.add(VersionParser.parseVersionReference("gtnhlib@[0.6.0,)"));
return deps;
}
private String description;
@@ -101,7 +118,9 @@ public class NEIModContainer extends DummyModContainer {
@Subscribe
public void preInit(FMLPreInitializationEvent event) {
gregTech5Loaded = Loader.isModLoaded("gregtech") && !Loader.isModLoaded("gregapi_post");
gtnhLibLoaded = Loader.isModLoaded("gtnhlib");
if (CommonUtils.isClient()) ClientHandler.preInit();
asmDataTable = event.getAsmData();
}
@Subscribe
@@ -114,11 +133,20 @@ public class NEIModContainer extends DummyModContainer {
@Subscribe
public void postInit(FMLPostInitializationEvent event) {
if (CommonUtils.isClient()) {
GuiRecipeTab.loadHandlerInfo();
ClientHandler.postInit();
}
}
@Subscribe
public void loadComplete(FMLLoadCompleteEvent event) {
if (CommonUtils.isClient()) {
GuiRecipeTab.loadHandlerInfo();
ClientHandler.loadPluginsList();
ClientHandler.loadHandlerOrdering();
asmDataTable = null;
}
}
@Subscribe
public void handleIMCMessages(FMLInterModComms.IMCEvent event) {
IMCHandler.processIMC(event.getMessages());
@@ -138,4 +166,8 @@ public class NEIModContainer extends DummyModContainer {
public Class<?> getCustomResourcePackClass() {
return getSource().isDirectory() ? FMLFolderResourcePack.class : FMLFileResourcePack.class;
}
public static ASMDataTable getAsmDataTable() {
return asmDataTable;
}
}
+2 -1
View File
@@ -1,6 +1,7 @@
package codechicken.nei;
import static codechicken.nei.PacketIDs.*;
import static codechicken.nei.PacketIDs.C2S;
import static codechicken.nei.PacketIDs.S2C;
import java.util.LinkedList;
import java.util.Set;
@@ -21,6 +21,8 @@ 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;
import net.minecraftforge.permission.PermissionManager;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
@@ -44,6 +46,8 @@ public class NEIServerConfig {
public static HashMap<String, PlayerSave> playerSaves = new HashMap<>();
public static ItemStackMap<Set<String>> bannedItems = new ItemStackMap<>();
private static boolean doesPermAPIExist = false;
public static void load(World world) {
if (MinecraftServer.getServer() != server) {
logger.debug("Loading NEI Server");
@@ -53,6 +57,16 @@ public class NEIServerConfig {
dimTags.clear();
loadConfig();
loadBannedItems();
try {
Class.forName("net.minecraftforge.permission.PermissionManager");
doesPermAPIExist = true;
NEIActions.baseActions().forEach(
action -> {
PermissionManager.registerPermission("nei.permissions." + action, PermissionLevel.OP);
});
} catch (ClassNotFoundException ignored) {}
}
loadWorld(world);
}
@@ -121,7 +135,12 @@ public class NEIServerConfig {
}
public static boolean canPlayerPerformAction(String playername, String name) {
return isPlayerInList(playername, getPlayerList("permissions." + NEIActions.base(name)), true);
String node = "permissions." + NEIActions.base(name);
boolean hasPerm = doesPermAPIExist
? PermissionManager.checkPermission(ServerUtils.getPlayer(playername), "nei." + node)
: false;
return hasPerm || isPlayerInList(playername, getPlayerList(node), true);
}
public static boolean isPlayerInList(String playername, Set<String> list, boolean allowCards) {
@@ -197,7 +216,7 @@ public class NEIServerConfig {
FileReader r = new FileReader(file);
int line = 0;
for (String s : IOUtils.readLines(r)) {
if (s.charAt(0) == '#' || s.trim().length() == 0) continue;
if (s.charAt(0) == '#' || s.trim().isEmpty()) continue;
int delim = s.lastIndexOf('=');
if (delim < 0) {
logger.error("line " + line + ": Missing =");
@@ -89,9 +89,8 @@ public class NEIServerUtils {
else return player.inventory.getStackInSlot(slot);
}
@SuppressWarnings("unchecked")
public static void deleteAllItems(EntityPlayerMP player) {
for (Slot slot : (List<Slot>) player.openContainer.inventorySlots) slot.putStack(null);
for (Slot slot : player.openContainer.inventorySlots) slot.putStack(null);
player.sendContainerAndContentsToPlayer(player.openContainer, player.openContainer.getInventory());
}
+74 -86
View File
@@ -1,21 +1,24 @@
package codechicken.nei;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.INEIGuiHandler;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.GuiUsageRecipe;
public abstract class PanelWidget extends Widget {
public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ? extends ItemsGrid.MouseContext>>
extends Widget implements IContainerTooltipHandler {
protected static final int PADDING = 2;
@@ -26,47 +29,55 @@ public abstract class PanelWidget extends Widget {
public Button pageNext;
public Label pageLabel;
protected ItemsGrid grid;
protected T grid;
public ArrayList<ItemStack> getItems() {
return grid.getItems();
return this.grid.getItems();
}
public ItemsGrid getGrid() {
return grid;
public T getGrid() {
return this.grid;
}
public void init() {
pageLabel = new Label("0/0", true);
pagePrev = new Button("Prev") {
pagePrev = new Button("<") {
public boolean onButtonPress(boolean rightclick) {
if (!rightclick) {
if (rightclick) {
grid.setPage(0);
} else {
grid.shiftPage(-1);
return true;
}
return false;
return true;
}
@Override
public String getRenderLabel() {
return "<";
public void draw(int mousex, int mousey) {
this.state = grid.getNumPages() <= 1 ? 2 : 0;
super.draw(mousex, mousey);
}
};
pageNext = new Button("Next") {
pageNext = new Button(">") {
public boolean onButtonPress(boolean rightclick) {
if (!rightclick) {
if (rightclick) {
grid.setPage(grid.getNumPages() - 1);
} else {
grid.shiftPage(1);
return true;
}
return false;
return true;
}
@Override
public String getRenderLabel() {
return ">";
public void draw(int mousex, int mousey) {
this.state = grid.getNumPages() <= 1 ? 2 : 0;
super.draw(mousex, mousey);
}
};
}
@@ -90,9 +101,6 @@ public abstract class PanelWidget extends Widget {
getWidth(gui),
getHeight(gui));
final int minWidth = 5 * ItemsGrid.SLOT_SIZE;
final int minHeight = 9 * ItemsGrid.SLOT_SIZE;
final String settingName = getPositioningSettingName();
int paddingLeft = (int) Math
.ceil(margin.w * NEIClientConfig.getSetting(settingName + ".left").getIntValue() / 100000.0);
@@ -103,12 +111,12 @@ public abstract class PanelWidget extends Widget {
int paddingBottom = (int) Math
.ceil(margin.h * NEIClientConfig.getSetting(settingName + ".bottom").getIntValue() / 100000.0);
int deltaHeight = Math.min(0, margin.h - paddingTop - paddingBottom - minHeight) / 2;
int deltaHeight = Math.min(0, margin.h - paddingTop - paddingBottom - ItemsGrid.SLOT_SIZE) / 2;
paddingLeft = Math.min(paddingLeft, Math.max(0, margin.w - paddingRight - minWidth));
paddingRight = Math.min(paddingRight, Math.max(0, margin.w - paddingLeft - minWidth));
paddingTop = Math.min(margin.h - minHeight, Math.max(0, paddingTop + deltaHeight));
paddingBottom = Math.min(margin.h - paddingTop - minHeight, Math.max(0, paddingBottom - deltaHeight));
paddingLeft = Math.min(paddingLeft, Math.max(0, margin.w - paddingRight - ItemsGrid.SLOT_SIZE));
paddingRight = Math.min(paddingRight, Math.max(0, margin.w - paddingLeft - ItemsGrid.SLOT_SIZE));
paddingTop = Math.min(margin.h - ItemsGrid.SLOT_SIZE, Math.max(0, paddingTop + deltaHeight));
paddingBottom = Math.min(margin.h - paddingTop - ItemsGrid.SLOT_SIZE, Math.max(0, paddingBottom - deltaHeight));
x = margin.x + paddingLeft;
y = margin.y + paddingTop;
@@ -118,8 +126,8 @@ public abstract class PanelWidget extends Widget {
final int header = resizeHeader(gui);
final int footer = resizeFooter(gui);
grid.setGridSize(x, y + header, w, h - header - footer);
grid.refresh(gui);
this.grid.setGridSize(x, y + header, w, h - header - footer);
this.grid.refresh(gui);
}
protected int resizeHeader(GuiContainer gui) {
@@ -164,22 +172,22 @@ public abstract class PanelWidget extends Widget {
protected abstract int resizeFooter(GuiContainer gui);
public void setVisible() {
if (grid.getPerPage() > 0) {
if (this.grid.getPerPage() > 0 && !this.grid.isEmpty()) {
LayoutManager.addWidget(pagePrev);
LayoutManager.addWidget(pageNext);
LayoutManager.addWidget(pageLabel);
grid.setVisible();
this.grid.setVisible();
}
}
@Override
public void update() {
grid.update();
this.grid.update();
}
@Override
public void draw(int mousex, int mousey) {
grid.draw(mousex, mousey);
this.grid.draw(mousex, mousey);
}
@Override
@@ -191,60 +199,35 @@ public abstract class PanelWidget extends Widget {
}
}
@Override
public void postDrawTooltips(int mx, int my, List<String> tooltip) {
grid.postDrawTooltips(mx, my, tooltip);
}
@Override
public void mouseDragged(int mousex, int mousey, int button, long heldTime) {
if (this.grid.getSlotBySlotIndex(mouseDownSlot) == null) {
mouseDownSlot = -1;
}
if (mouseDownSlot >= 0 && draggedStack == null
&& NEIClientUtils.getHeldItem() == null
&& NEIClientConfig.hasSMPCounterPart()) {
ItemPanelSlot mouseOverSlot = getSlotMouseOver(mousex, mousey);
ItemsGridSlot mouseOverSlot = this.grid.getSlotMouseOver(mousex, mousey);
if (mouseOverSlot == null || mouseOverSlot.slotIndex != mouseDownSlot || heldTime > 500) {
draggedStack = getDraggedStackWithQuantity(mouseDownSlot);
draggedStack = getDraggedStackWithQuantity(this.grid.getSlotBySlotIndex(mouseDownSlot).getItemStack());
mouseDownSlot = -1;
}
}
}
protected abstract ItemStack getDraggedStackWithQuantity(int mouseDownSlot);
protected abstract ItemStack getDraggedStackWithQuantity(ItemStack itemStack);
@Override
public boolean handleClick(int mousex, int mousey, int button) {
if (handleClickExt(mousex, mousey, button)) return true;
if (NEIClientUtils.getHeldItem() != null) {
if (!grid.contains(mousex, mousey)) {
return false;
}
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")) {
if (button == 1) {
NEIClientUtils.decreaseSlotStack(-999);
} else {
NEIClientUtils.deleteHeldItem();
}
} else {
NEIClientUtils.dropHeldItem();
}
return true;
}
ItemPanelSlot hoverSlot = getSlotMouseOver(mousex, mousey);
ItemsGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
if (hoverSlot != null) {
if (button == 2) {
if (hoverSlot.item != null) {
draggedStack = getDraggedStackWithQuantity(hoverSlot.slotIndex);
}
draggedStack = getDraggedStackWithQuantity(hoverSlot.getItemStack());
} else {
mouseDownSlot = hoverSlot.slotIndex;
}
@@ -259,7 +242,7 @@ public abstract class PanelWidget extends Widget {
public boolean handleClickExt(int mouseX, int mouseY, int button) {
if (ItemPanels.itemPanel.draggedStack != null && ItemPanels.bookmarkPanel.contains(mouseX, mouseY)) {
ItemPanels.bookmarkPanel.addOrRemoveItem(ItemPanels.itemPanel.draggedStack, null, null, false, true);
ItemPanels.bookmarkPanel.addItem(ItemPanels.itemPanel.draggedStack);
ItemPanels.itemPanel.draggedStack = null;
return true;
}
@@ -325,24 +308,23 @@ public abstract class PanelWidget extends Widget {
@Override
public void mouseUp(int mousex, int mousey, int button) {
ItemPanelSlot hoverSlot = getSlotMouseOver(mousex, mousey);
final ItemsGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
if (hoverSlot != null && hoverSlot.slotIndex == mouseDownSlot && draggedStack == null) {
ItemStack item = hoverSlot.item;
if (NEIController.manager.window instanceof GuiRecipe || !NEIClientConfig.canCheatItem(item)) {
if (NEIController.manager.window instanceof GuiRecipe || NEIClientUtils.shiftKey()
|| !NEIClientConfig.canCheatItem(hoverSlot.getItemStack())) {
if (button == 0) {
GuiCraftingRecipe.openRecipeGui("item", item);
GuiCraftingRecipe.openRecipeGui("item", hoverSlot.getItemStack().copy());
} else if (button == 1) {
GuiUsageRecipe.openRecipeGui("item", item);
GuiUsageRecipe.openRecipeGui("item", hoverSlot.getItemStack().copy());
}
mouseDownSlot = -1;
return;
} else {
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.getItemStack()), button, -1);
}
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.slotIndex), button, -1);
}
mouseDownSlot = -1;
@@ -352,20 +334,22 @@ public abstract class PanelWidget extends Widget {
public boolean onMouseWheel(int i, int mousex, int mousey) {
if (!contains(mousex, mousey)) return false;
grid.shiftPage(-i);
this.grid.shiftPage(-i);
return true;
}
@Override
public boolean handleKeyPress(int keyID, char keyChar) {
final Point mouse = GuiDraw.getMousePosition();
if (!contains(mouse.x, mouse.y)) return false;
if (NEIClientConfig.isKeyHashDown("gui.next")) {
grid.shiftPage(1);
this.grid.shiftPage(1);
return true;
}
if (NEIClientConfig.isKeyHashDown("gui.prev")) {
grid.shiftPage(-1);
this.grid.shiftPage(-1);
return true;
}
@@ -374,24 +358,28 @@ public abstract class PanelWidget extends Widget {
@Override
public ItemStack getStackMouseOver(int mousex, int mousey) {
ItemPanelSlot slot = getSlotMouseOver(mousex, mousey);
return slot == null ? null : slot.item;
final ItemsGridSlot slot = this.grid.getSlotMouseOver(mousex, mousey);
return slot == null ? null : slot.getItemStack();
}
public ItemPanelSlot getSlotMouseOver(int mousex, int mousey) {
return grid.getSlotMouseOver(mousex, mousey);
public ItemStack getStackMouseOverWithQuantity(int mousex, int mousey) {
final ItemStack hoverSlot = getStackMouseOver(mousex, mousey);
return hoverSlot != null ? getDraggedStackWithQuantity(hoverSlot) : null;
}
abstract ItemsGridSlot getSlotMouseOver(int mousex, int mousey);
public int getPage() {
return grid.getPage();
return this.grid.getPage();
}
public int getNumPages() {
return grid.getNumPages();
return this.grid.getNumPages();
}
@Override
public boolean contains(int px, int py) {
return grid.contains(px, py);
return this.grid.contains(px, py);
}
}
@@ -1,13 +1,20 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.recipe.GuiRecipe;
/**
* Simply an {@link ItemStack} with position. Mainly used in the recipe handlers.
*/
@@ -26,8 +33,11 @@ public class PositionedStack {
relx = x;
rely = y;
if (genPerms) generatePermutations();
else setPermutationToRender(0);
if (genPerms) {
generatePermutations();
} else {
setPermutationToRender(0);
}
}
public PositionedStack(Object object, int x, int y) {
@@ -37,7 +47,7 @@ public class PositionedStack {
public void generatePermutations() {
if (permutated) return;
ArrayList<ItemStack> stacks = new ArrayList<>();
List<ItemStack> stacks = new ArrayList<>();
for (ItemStack item : items) {
if (item == null || item.getItem() == null) continue;
@@ -72,15 +82,57 @@ public class PositionedStack {
}
public PositionedStack copy() {
return new PositionedStack(items, relx, rely);
PositionedStack pStack = new PositionedStack(
Arrays.stream(this.items).map(ItemStack::copy).toArray(ItemStack[]::new),
relx,
rely,
false);
pStack.permutated = this.permutated;
return pStack;
}
public List<ItemStack> getFilteredPermutations() {
return getFilteredPermutations(null);
}
public List<ItemStack> getFilteredPermutations(ItemFilter additionalFilter) {
List<ItemStack> items = Arrays.asList(this.items);
items = filteringPermutations(items, item -> !ItemInfo.isHidden(item));
items = filteringPermutations(items, PresetsList.getItemFilter());
items = filteringPermutations(items, GuiRecipe.getSearchItemFilter());
items = filteringPermutations(items, additionalFilter);
items.sort(Comparator.comparing(FavoriteRecipes::contains).reversed());
return items;
}
private List<ItemStack> filteringPermutations(List<ItemStack> items, ItemFilter filter) {
if (filter == null) return items;
final List<ItemStack> filteredItems = items.stream().filter(filter::matches).collect(Collectors.toList());
return filteredItems.isEmpty() ? items : filteredItems;
}
public boolean setPermutationToRender(ItemStack ingredient) {
for (int index = 0; index < this.items.length; index++) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(this.items[index], ingredient)) {
setPermutationToRender(index);
return true;
}
}
return false;
}
public void setPermutationToRender(int index) {
item = items[index].copy();
if (item.getItem() == null) item = new ItemStack(Blocks.fire);
else if (item.getItemDamage() == OreDictionary.WILDCARD_VALUE && item.getItem() != null
&& item.getItem().isRepairable())
item.setItemDamage(0);
this.item = this.items[index].copy();
if (this.item.getItem() == null) {
this.item = new ItemStack(Blocks.fire);
} else if (this.item.getItemDamage() == OreDictionary.WILDCARD_VALUE && this.item.getItem().isRepairable()) {
this.item.setItemDamage(0);
}
}
public boolean contains(ItemStack ingredient) {
@@ -0,0 +1,249 @@
package codechicken.nei;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import net.minecraft.item.ItemStack;
import org.apache.commons.io.IOUtils;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import codechicken.core.CommonUtils;
import codechicken.nei.api.API;
import codechicken.nei.api.IRecipeFilter;
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.recipe.IRecipeHandler;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
public class PresetsList {
public enum PresetMode {
HIDE,
REMOVE,
GROUP;
}
public static class Preset implements ItemFilter {
public String name = "";
public boolean enabled = true;
public PresetMode mode = PresetMode.HIDE;
public Set<String> items = new HashSet<>();
public static String getIdentifier(ItemStack stack) {
return StackInfo.getItemStackGUID(stack);
}
@Override
public boolean matches(ItemStack item) {
return items.contains(Preset.getIdentifier(item));
}
public Preset copy() {
Preset preset = new Preset();
preset.name = name;
preset.enabled = enabled;
preset.mode = mode;
preset.items = new HashSet<>(items);
return preset;
}
}
protected static class RecipesFilter implements IRecipeFilterProvider, IRecipeFilter {
public Set<String> cache;
public IRecipeFilter getFilter() {
if (cache == null) {
cache = PresetsList.presets.stream().filter(p -> p.enabled && p.mode == PresetMode.REMOVE)
.flatMap(p -> p.items.stream()).collect(Collectors.toSet());
}
return cache.isEmpty() ? null : this;
}
@Override
public boolean matches(IRecipeHandler handler, List<PositionedStack> ingredients, PositionedStack result,
List<PositionedStack> others) {
if (matchPositionedStack(ingredients, false)) {
return false;
}
if (result != null && matchPositionedStack(result)) {
return true;
}
if (!others.isEmpty() && matchPositionedStack(others, true)) {
return true;
}
return result == null && others.isEmpty();
}
private boolean matchPositionedStack(List<PositionedStack> items, boolean dir) {
for (PositionedStack pStack : items) {
if (matchPositionedStack(pStack) == dir) {
return true;
}
}
return false;
}
private boolean matchPositionedStack(PositionedStack pStack) {
for (ItemStack stack : pStack.items) {
if (!cache.contains(Preset.getIdentifier(stack))) {
return true;
}
}
return false;
}
}
protected static class ItemPanelFilter implements ItemFilterProvider, ItemFilter {
public Set<String> cache;
public ItemFilter getFilter() {
if (cache == null) {
cache = PresetsList.presets.stream()
.filter(p -> p.enabled && (p.mode == PresetMode.HIDE || p.mode == PresetMode.REMOVE))
.flatMap(p -> p.items.stream()).collect(Collectors.toSet());
}
return cache.isEmpty() ? null : this;
}
@Override
public boolean matches(ItemStack stack) {
return !cache.contains(Preset.getIdentifier(stack));
}
}
public static final List<Preset> presets = new ArrayList<>();
protected static RecipesFilter recipeFilter = new RecipesFilter();
protected static ItemPanelFilter itemFilter = new ItemPanelFilter();
static {
API.addItemFilter(itemFilter);
API.addRecipeFilter(recipeFilter);
}
public static ItemFilter getItemFilter() {
return itemFilter.getFilter();
}
public static void load() {
final File presetsFile = new File(CommonUtils.getMinecraftDir(), "saves/NEI/global/presets.ini");
if (presetsFile == null || !presetsFile.exists()) {
return;
}
List<String> itemStrings;
try (FileInputStream reader = new FileInputStream(presetsFile)) {
NEIClientConfig.logger.info("Loading presets from file {}", presetsFile);
itemStrings = IOUtils.readLines(reader, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load presets from file {}", presetsFile, e);
return;
}
JsonParser parser = new JsonParser();
Preset preset = new Preset();
presets.clear();
for (String itemStr : itemStrings) {
try {
if (itemStr.isEmpty()) {
itemStr = "; {}";
}
if (itemStr.startsWith("; ")) {
JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
if (!preset.items.isEmpty()) {
// do not create empty namespaces
presets.add(preset);
preset = new Preset();
}
if (settings.has("name")) {
preset.name = settings.get("name").getAsString();
}
if (settings.has("enabled")) {
preset.enabled = settings.get("enabled").getAsBoolean();
}
if (settings.has("mode")) {
preset.mode = PresetMode.valueOf(settings.get("mode").getAsString());
}
} else {
preset.items.add(itemStr);
}
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
NEIClientConfig.logger.error("Failed to load presets ItemStack from json string:\n{}", itemStr);
}
}
if (!preset.items.isEmpty()) {
presets.add(preset);
}
}
public static void savePresets() {
final File presetsFile = new File(CommonUtils.getMinecraftDir(), "saves/NEI/global/presets.ini");
final List<String> strings = new ArrayList<>();
for (Preset preset : presets) {
JsonObject settings = new JsonObject();
settings.add("name", new JsonPrimitive(preset.name));
settings.add("enabled", new JsonPrimitive(preset.enabled));
settings.add("mode", new JsonPrimitive(preset.mode.toString()));
strings.add("; " + NBTJson.toJson(settings));
strings.addAll(preset.items);
}
try (FileOutputStream output = new FileOutputStream(presetsFile)) {
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save presets list to file {}", presetsFile, e);
}
recipeFilter.cache = null;
itemFilter.cache = null;
CollapsibleItems.saveStates();
CollapsibleItems.load();
LayoutManager.markItemsDirty();
}
}
@@ -1,922 +0,0 @@
package codechicken.nei;
import static codechicken.nei.NEIClientUtils.translate;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.item.ItemStack;
import org.apache.commons.io.IOUtils;
import org.lwjgl.input.Keyboard;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import codechicken.core.CommonUtils;
import codechicken.core.gui.GuiScrollSlot;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
import cpw.mods.fml.common.registry.GameRegistry;
public class PresetsWidget extends Widget {
public static class PresetTag implements ItemFilter {
public String filename = null;
public String displayName = "";
public boolean whitelist = true;
public HashSet<String> items;
public PresetTag(String displayName) {
this(displayName, new HashSet<>(), false, null);
}
public PresetTag(String displayName, HashSet<String> items) {
this(displayName, items, true, null);
}
public PresetTag(String displayName, HashSet<String> items, boolean whitelist, String filename) {
this.displayName = displayName;
this.items = items != null ? items : new HashSet<>();
this.whitelist = whitelist;
this.filename = filename;
}
public boolean matches(final ItemStack stack) {
return items.contains(StackInfo.getItemStackGUID(stack)) == whitelist;
}
public static PresetTag loadFromFile(File file) {
if (!file.isFile() || !file.exists() || file.getName().equals("selected.ini")) {
return null;
}
try {
List<String> itemStrings;
try (FileInputStream input = new FileInputStream(file)) {
NEIClientConfig.logger.info("Loading presets from file {}", file);
itemStrings = IOUtils.readLines(input, "UTF-8");
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load presets from file {}", file, e);
return null;
}
final JsonParser parser = new JsonParser();
final JsonObject metaObject = parser.parse(itemStrings.remove(0)).getAsJsonObject();
final String displayName = metaObject.get("displayName").getAsString();
final boolean whitelist = metaObject.get("whitelist").getAsBoolean();
final HashSet<String> items = new HashSet<>();
for (String itemStr : itemStrings) {
items.add(itemStr);
}
return new PresetTag(displayName, items, whitelist, file.getName());
} catch (Throwable th) {
NEIClientConfig.logger.error("Failed to load presets ItemStack from file", file);
}
return null;
}
public void deleteFile() {
if (presetsDir == null || filename == null) return;
final File tagFile = new File(presetsDir, filename);
if (tagFile.exists()) {
tagFile.delete();
}
}
public void saveToFile() {
if (presetsDir == null) return;
if (filename == null) {
final String sanitized = displayName.replaceAll("[^_\\-.0-9a-zA-Z]", "_");
int index = 1;
filename = sanitized + ".ini";
while ((new File(presetsDir, filename)).exists() || filename.equals("selected.ini")) {
filename = sanitized + " (" + index + ").ini";
index++;
}
}
final List<String> strings = new ArrayList<>();
final JsonObject row = new JsonObject();
row.add("displayName", new JsonPrimitive(displayName));
row.add("whitelist", new JsonPrimitive(whitelist));
strings.add(NBTJson.toJson(row));
try {
strings.addAll(items);
} catch (JsonSyntaxException e) {
NEIClientConfig.logger.error("Failed to stringify presets ItemStack to json string");
}
final File tagFile = new File(presetsDir, filename);
try (FileOutputStream output = new FileOutputStream(tagFile)) {
IOUtils.writeLines(strings, "\n", output, "UTF-8");
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save presets list to file {}", tagFile, e);
}
}
@SuppressWarnings("unchecked")
public PresetTag copy() {
return new PresetTag(displayName, (HashSet) items.clone(), whitelist, null);
}
}
protected static class SubsetListBox extends GuiScrollSlot {
protected final List<PresetTag> presets = new ArrayList<>();
protected final List<PresetTag> selected = new ArrayList<>();
protected int lastSelectedIndex = 0;
public SubsetListBox(File presetsDir) {
super(0, 0, 0, 0);
setSmoothScroll(false);
try {
presets.addAll(
ItemList.forkJoinPool.submit(
() -> Arrays.asList(presetsDir.listFiles()).parallelStream()
.map(f -> PresetTag.loadFromFile(f)).filter(p -> p != null)
.collect(Collectors.toCollection(ArrayList::new)))
.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return;
}
selected.addAll(loadSelFromFile(presetsDir, presets));
sort();
}
public SubsetListBox() {
super(0, 0, 0, 0);
setSmoothScroll(false);
}
public void addTag(final PresetTag tag, boolean sel) {
presets.add(tag);
if (sel) {
selected.add(tag);
}
}
protected List<PresetTag> getPresets() {
return presets;
}
protected List<PresetTag> getSelected() {
return selected;
}
public void replaceSeleted(final PresetTag tag) {
if (selected.size() == 1) {
selected.get(0).deleteFile();
presets.set(presets.indexOf(selected.get(0)), tag);
selected.set(0, tag);
} else {
presets.add(tag);
selected.add(tag);
}
tag.saveToFile();
saveSelToFile();
sort();
}
public void sort() {
presets.sort((o1, o2) -> o1.displayName.compareTo(o2.displayName));
}
public void clear() {
presets.clear();
selected.clear();
}
@Override
public int getSlotHeight(int slot) {
return 18;
}
@Override
protected int getNumSlots() {
return presets.size();
}
@Override
protected void slotClicked(int slot, int button, int mx, int my, int count) {
if (slot >= presets.size()) {
return;
}
final PresetTag tag = presets.get(slot);
final int width = windowBounds().width;
final Rectangle4i direction = new Rectangle4i(0, 0, 18, 18);
final Rectangle4i delete = new Rectangle4i(width - 18, 0, 18, 18);
final Rectangle4i option = new Rectangle4i(18, 0, width - 18 - 18, 18);
if (option.contains(mx, my)) {
final boolean sel = selected.contains(tag);
if (NEIClientUtils.controlKey()) {
if (sel) {
selected.remove(tag);
} else {
selected.add(tag);
}
} else if (NEIClientUtils.shiftKey()) {
selected.clear();
for (int i = Math.min(lastSelectedIndex, slot); i <= Math.max(lastSelectedIndex, slot); i++) {
if (!selected.contains(presets.get(i))) {
selected.add(presets.get(i));
}
}
} else {
final int size = selected.size();
selected.clear();
if (!sel || size > 1) {
selected.add(tag);
}
}
if (selected.isEmpty()) {
lastSelectedIndex = 0;
} else if (!NEIClientUtils.shiftKey()) {
lastSelectedIndex = slot;
}
} else if (delete.contains(mx, my)) {
presets.remove(tag);
selected.remove(tag);
tag.deleteFile();
} else if (direction.contains(mx, my)) {
tag.whitelist = !tag.whitelist;
tag.saveToFile();
}
saveSelToFile();
PresetsWidget.edit = null;
PresetsWidget.openListBox = !presets.isEmpty()
&& (NEIClientUtils.controlKey() || NEIClientUtils.shiftKey() || !option.contains(mx, my));
ItemList.updateFilter.restart();
}
@Override
protected void drawSlot(int slot, int x, int y, int mx, int my, float frame) {
if (slot >= presets.size()) {
return;
}
final int width = windowBounds().width;
final Rectangle4i direction = new Rectangle4i(x, y, 18, 18);
final Rectangle4i delete = new Rectangle4i(x + width - 18, y, 18, 18);
final Rectangle4i option = new Rectangle4i(x + 18, y, width - 18 - 18, 18);
final PresetTag tag = presets.get(slot);
final int optionState = selected.contains(tag) ? 0 : option.contains(x + mx, y + my) ? 1 : 2;
final int directionState = direction.contains(x + mx, y + my) ? 1 : 2;
final int deleteState = delete.contains(x + mx, y + my) ? 1 : 2;
final String displayName = NEIClientUtils
.cropText(PresetsWidget.fontRenderer, tag.displayName, option.w - 6);
final String dirName = tag.whitelist ? translate("presets.whitelist.label")
: translate("presets.blacklist.label");
// blacklist or whitelist
LayoutManager.getLayoutStyle()
.drawSubsetTag(null, direction.x, direction.y, direction.w, direction.h, directionState, false);
GuiDraw.drawString(dirName, direction.x + 6, direction.y + 5, directionState == 2 ? 0xFFE0E0E0 : 0xFFFFA0);
// option name
LayoutManager.getLayoutStyle()
.drawSubsetTag(null, option.x, option.y, option.w, option.h, optionState, false);
GuiDraw.drawString(displayName, option.x + 3, option.y + 5, optionState == 2 ? 0xFFE0E0E0 : 0xFFFFA0);
// remove icon
LayoutManager.getLayoutStyle()
.drawSubsetTag(null, delete.x, delete.y, delete.w, delete.h, deleteState, false);
GuiDraw.drawString("✕", delete.x + 6, delete.y + 5, deleteState == 2 ? 0xFFE0E0E0 : 0x601010);
}
@Override
public void drawOverlay(float frame) {}
@Override
public void drawBackground(float frame) {
drawRect(x, y, x + width, y + height, 0xFF202020);
}
@Override
public void drawScrollbar(float frame) {
if (hasScrollbar()) {
super.drawScrollbar(frame);
}
}
@Override
public int scrollbarGuideAlignment() {
return 0;
}
protected List<PresetTag> loadSelFromFile(File presetsDir, List<PresetTag> presets) {
final File file = new File(presetsDir, "selected.ini");
List<PresetTag> selected = new ArrayList<>();
if (file.exists()) {
try {
List<String> itemStrings;
try (FileInputStream input = new FileInputStream(file)) {
NEIClientConfig.logger.info("Loading presets selected from file {}", file);
itemStrings = IOUtils.readLines(input, "UTF-8");
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load presets selected from file {}", file, e);
return selected;
}
final HashMap<String, PresetTag> map = new HashMap<>();
for (PresetTag tag : presets) {
map.put(tag.filename, tag);
}
for (String filename : itemStrings) {
if (map.containsKey(filename)) {
selected.add(map.get(filename));
}
}
} catch (Throwable th) {
NEIClientConfig.logger.error("Failed to load presets selected from file", file);
}
}
return selected;
}
public void saveSelToFile() {
final File file = new File(presetsDir, "selected.ini");
final List<String> list = new ArrayList<>();
for (final PresetTag tag : selected) {
list.add(tag.filename);
}
try (FileOutputStream output = new FileOutputStream(file)) {
IOUtils.writeLines(list, "\n", output, "UTF-8");
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save presets selected list to file {}", file, e);
}
}
}
protected static class MouseSelection {
public int startX = -1;
public int startY = -1;
public int startIndex = -1;
public int endIndex = -1;
public HashSet<ItemStack> items = new HashSet<>();
public boolean append = true;
public MouseSelection(int slotIndex, boolean append) {
final ItemsGrid grid = ItemPanels.itemPanel.getGrid();
final Rectangle4i rec = grid.getItemRect(slotIndex);
this.append = append;
endIndex = slotIndex;
startIndex = slotIndex;
startX = rec.x;
startY = rec.y;
}
}
protected static final FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer;
protected static SubsetListBox listbox = new SubsetListBox();
protected static File presetsDir;
protected static boolean openListBox = false;
protected static PresetTag edit;
protected long lastclicktime;
protected static MouseSelection mouseSelection;
protected static final Button dropdown = new Button() {
public boolean onButtonPress(boolean rightclick) {
if (!rightclick) {
openListBox = !openListBox;
return true;
}
return false;
}
@Override
public String getRenderLabel() {
return "...";
}
};
protected static final Label selectedValue = new Label("", false) {
@Override
public void draw(int mousex, int mousey) {
final String text = NEIClientUtils.cropText(fontRenderer, this.text, w);
if (text.equals(this.text)) {
GuiDraw.drawString(text, x + w - fontRenderer.getStringWidth(text), y + (h - 8) / 2, colour);
} else {
GuiDraw.drawString(text, x, y + (h - 8) / 2, colour);
}
}
@Override
public List<String> handleTooltip(int mx, int my, List<String> tooltip) {
if (contains(mx, my) && listbox.getSelected().size() <= 1) {
tooltip.add(translate("presets.label.tooltip"));
}
return tooltip;
}
};
protected static final TextField selectedDisplayName = new TextField("") {
public void onTextChange(String oldText) {
if (edit != null) {
edit.displayName = text();
}
}
@Override
public void draw(int mousex, int mousey) {
super.draw(mousex, mousey);
if (text().isEmpty()) {
GuiDraw.drawGradientRect(x - 1, y - 1, 1, h + 2, 0xFFcc3300, 0xFFcc3300); // Left
GuiDraw.drawGradientRect(x - 1, y - 1, w + 2, 1, 0xFFcc3300, 0xFFcc3300); // Top
GuiDraw.drawGradientRect(x + w, y - 1, 1, h + 2, 0xFFcc3300, 0xFFcc3300); // Left
GuiDraw.drawGradientRect(x - 1, y + h, w + 2, 1, 0xFFcc3300, 0xFFcc3300); // Bottom
}
}
@Override
public List<String> handleTooltip(int mx, int my, List<String> tooltip) {
if (contains(mx, my) && listbox.getSelected().size() <= 1) {
tooltip.add(translate("presets.textfield.tooltip.1"));
tooltip.add(translate("presets.textfield.tooltip.2"));
}
return tooltip;
}
};
protected static final Button selectedState = new Button("B") {
public boolean onButtonPress(boolean rightclick) {
if (!rightclick && edit != null) {
edit.whitelist = !edit.whitelist;
return true;
}
return false;
}
@Override
public String getRenderLabel() {
return edit != null && edit.whitelist ? translate("presets.whitelist.label")
: translate("presets.blacklist.label");
}
@Override
public void addTooltips(List<String> tooltip) {
if (edit != null) {
tooltip.add(
edit.whitelist ? translate("presets.whitelist.tooltip")
: translate("presets.blacklist.tooltip"));
}
}
};
protected static void setEditedTag(final PresetTag tag) {
edit = tag;
openListBox = false;
selectedDisplayName.setText(tag != null ? tag.displayName : "");
ItemList.updateFilter.restart();
}
public static void addTag(final PresetTag tag) {
addTag(tag, false);
}
public static void addTag(final PresetTag tag, boolean sel) {
listbox.addTag(tag, sel);
}
public static boolean inEditMode() {
return edit != null;
}
public static boolean isHidden(final ItemStack item) {
if (edit != null) {
if (mouseSelection != null && mouseSelection.items.contains(item)) {
return mouseSelection.append != edit.whitelist;
}
return !edit.matches(item);
}
if (!listbox.getSelected().isEmpty()) {
final List<PresetTag> selected = listbox.getSelected();
for (int idx = 0; idx < selected.size(); idx++) {
if (!selected.get(idx).matches(item)) {
return true;
}
}
}
return false;
}
public static void setHidden(final ItemStack stack, final boolean append) {
if (edit == null) {
return;
}
if (NEIClientUtils.shiftKey()) {
final ArrayList<ItemStack> items = ItemPanels.itemPanel.getItems();
for (int i = 0; i < items.size(); i++) {
if (stack.getItem().equals(items.get(i).getItem())) {
hideItem(items.get(i), append);
}
}
} else if (NEIClientUtils.controlKey()) {
final String modId = getModId(stack);
if (modId == null) {
hideItem(stack, append);
} else {
final ArrayList<ItemStack> items = ItemPanels.itemPanel.getItems();
for (int i = 0; i < items.size(); i++) {
final String mod = getModId(items.get(i));
if (mod != null && mod.equals(modId)) {
hideItem(items.get(i), append);
}
}
}
} else {
hideItem(stack, append);
}
}
protected static void hideItem(final ItemStack stack, boolean append) {
final String guid = StackInfo.getItemStackGUID(stack);
if (append) {
edit.items.add(guid);
} else {
edit.items.remove(guid);
}
}
protected static String getModId(final ItemStack stack) {
try {
return GameRegistry.findUniqueIdentifierFor(stack.getItem()).modId;
} catch (Exception ignored) {}
return null;
}
public static void loadPresets(final String worldPath) {
final File dir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
presetsDir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath + "/presets");
if (!dir.exists()) {
dir.mkdirs();
}
if (!presetsDir.exists()) {
presetsDir.mkdirs();
}
listbox = new SubsetListBox(presetsDir);
edit = null;
openListBox = false;
selectedDisplayName.setText("");
ItemList.updateFilter.restart();
}
@Override
public void draw(int mx, int my) {
if (edit != null) {
selectedState.x = x;
selectedState.y = y;
selectedState.w = selectedState.h = h;
selectedState.draw(mx, my);
selectedDisplayName.y = y;
selectedDisplayName.h = h;
selectedDisplayName.x = selectedState.x + selectedState.w + 1;
selectedDisplayName.w = w - h * 2 - 5;
selectedDisplayName.draw(mx, my);
} else {
final List<PresetTag> selected = listbox.getSelected();
final int size = selected.size();
selectedValue.text = size > 1 ? translate("presets.label.selected", size)
: (size == 1 ? selected.get(0).displayName : "");
selectedValue.y = y;
selectedValue.h = h;
selectedValue.w = w - h - 4;
selectedValue.x = x;
selectedValue.draw(mx, my);
}
dropdown.y = y;
dropdown.w = dropdown.h = h;
dropdown.x = x + w - dropdown.w;
dropdown.state = edit != null || listbox.getNumSlots() == 0 ? 2 : 0;
dropdown.draw(mx, my);
if (openListBox) {
final int scrollbarWidth = listbox.hasScrollbar() ? listbox.scrollbarDim().width : 0;
listbox.setSize(
x,
y + h + 1,
w,
Math.min(((LayoutManager.searchField.y - h - y) / 18) * 18, listbox.contentHeight()));
listbox.setMargins(0, 0, scrollbarWidth, 0);
listbox.draw(mx, my, 0);
}
}
@Override
public boolean contains(int px, int py) {
return super.contains(px, py) || openListBox && listbox.contains(px, py);
}
@Override
public boolean handleClick(int mx, int my, int button) {
if (openListBox && listbox.contains(mx, my)) {
listbox.mouseClicked(mx, my, button);
return true;
}
if (edit != null) {
if (selectedState.contains(mx, my)) {
selectedState.handleClick(mx, my, button);
return true;
}
if (selectedDisplayName.contains(mx, my)) {
selectedDisplayName.handleClick(mx, my, button);
return true;
}
} else {
if (button == 0 && dropdown.contains(mx, my)) {
openListBox = !openListBox;
return true;
}
openListBox = false;
if (button == 0 && selectedValue.contains(mx, my)) {
if (System.currentTimeMillis() - lastclicktime < 400) { // double click
final List<PresetTag> selected = listbox.getSelected();
final int size = selected.size();
if (size <= 1) {
setEditedTag(size == 1 ? selected.get(0).copy() : new PresetTag(""));
}
}
lastclicktime = System.currentTimeMillis();
}
}
return contains(mx, my);
}
@Override
public boolean handleClickExt(int mx, int my, int button) {
if (edit != null && mouseSelection == null) {
ItemPanelSlot slot = ItemPanels.itemPanel.getSlotMouseOver(mx, my);
if (slot != null && button != 2) {
mouseSelection = new MouseSelection(slot.slotIndex, button == 0);
return true;
}
}
return false;
}
@Override
public boolean handleKeyPress(int keyID, char keyChar) {
if (keyID == Keyboard.KEY_ESCAPE) {
openListBox = false;
}
if (edit == null) {
return false;
}
if (selectedDisplayName.focused() && (keyID == Keyboard.KEY_RETURN || keyID == Keyboard.KEY_NUMPADENTER)
&& !selectedDisplayName.text().isEmpty()) {
selectedDisplayName.handleKeyPress(keyID, keyChar);
selectedDisplayName.setFocus(false);
listbox.replaceSeleted(edit);
setEditedTag(null);
return true;
} else if (selectedDisplayName.focused()) {
return selectedDisplayName.handleKeyPress(keyID, keyChar);
} else if (keyID == Keyboard.KEY_ESCAPE && !(NEIClientUtils.mc().currentScreen instanceof GuiRecipe)) {
setEditedTag(null);
return true;
}
return false;
}
@Override
public void mouseDragged(int mx, int my, int button, long heldTime) {
if (openListBox) {
listbox.mouseDragged(mx, my, button, heldTime);
}
if (edit != null && button != 2 && mouseSelection != null) {
final ItemPanelSlot slot = ItemPanels.itemPanel.getSlotMouseOver(mx, my);
if (slot != null && slot.slotIndex != mouseSelection.endIndex) {
final ItemsGrid grid = ItemPanels.itemPanel.getGrid();
mouseSelection.endIndex = slot.slotIndex;
mouseSelection.items.clear();
final Rectangle4i rec = grid.getItemRect(slot.slotIndex);
final Rectangle4i sel = new Rectangle4i(
Math.min(rec.x, mouseSelection.startX),
Math.min(rec.y, mouseSelection.startY),
Math.max(rec.x, mouseSelection.startX) - Math.min(rec.x, mouseSelection.startX),
Math.max(rec.y, mouseSelection.startY) - Math.min(rec.y, mouseSelection.startY));
for (int x = sel.x; x <= sel.x + sel.w; x += ItemsGrid.SLOT_SIZE) {
for (int y = sel.y; y <= sel.y + sel.h; y += ItemsGrid.SLOT_SIZE) {
ItemStack stack = ItemPanels.itemPanel.getStackMouseOver(x, y);
if (stack != null) {
mouseSelection.items.add(stack);
}
}
}
}
}
}
@Override
public void mouseUp(int mx, int my, int button) {
if (openListBox) {
listbox.mouseMovedOrUp(mx, my, button);
}
if (edit != null && mouseSelection != null) {
ItemPanelSlot hoverSlot = ItemPanels.itemPanel.getSlotMouseOver(mx, my);
if (hoverSlot != null && hoverSlot.slotIndex == mouseSelection.startIndex) {
setHidden(hoverSlot.item, button == 0);
} else if (!mouseSelection.items.isEmpty()) {
for (ItemStack stack : mouseSelection.items) {
hideItem(stack, mouseSelection.append);
}
}
mouseSelection = null;
}
}
@Override
public boolean onMouseWheel(int i, int mx, int my) {
if (openListBox && listbox.hasScrollbar() && listbox.contains(mx, my)) {
listbox.scroll(-i);
return true;
}
return false;
}
@Override
public void onGuiClick(int mx, int my) {
if (!contains(mx, my)) {
openListBox = false;
}
selectedDisplayName.onGuiClick(mx, my);
}
@Override
public List<String> handleTooltip(int mx, int my, List<String> tooltip) {
if (edit != null) {
if (selectedState.contains(mx, my)) {
return selectedState.handleTooltip(mx, my, tooltip);
}
if (selectedDisplayName.contains(mx, my)) {
return selectedDisplayName.handleTooltip(mx, my, tooltip);
}
} else {
if (selectedValue.contains(mx, my)) {
return selectedValue.handleTooltip(mx, my, tooltip);
}
}
return tooltip;
}
public static boolean matches(ItemStack stack) {
if (edit != null) {
return true;
}
final List<PresetTag> selected = listbox.getSelected();
for (int idx = 0; idx < selected.size(); idx++) {
if (!selected.get(idx).matches(stack)) {
return false;
}
}
return true;
}
}
@@ -0,0 +1,86 @@
package codechicken.nei;
import net.minecraft.util.EnumChatFormatting;
import codechicken.nei.SearchField.GuiSearchField;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.util.TextHistory;
public abstract class RecipeSearchField extends TextField {
private static final TextHistory history = new TextHistory();
public RecipeSearchField(String ident) {
super(ident);
this.field.setVisible(false);
}
@Override
protected void initInternalTextField() {
field = new GuiSearchField();
field.setMaxStringLength(maxSearchLength);
field.setCursorPositionZero();
}
public boolean isVisible() {
return this.field.getVisible();
}
public void setVisible(boolean visible) {
this.field.setVisible(visible);
}
protected abstract boolean noResults();
@Override
public int getTextColour() {
if (!text().isEmpty() && !noResults()) {
return focused() ? 0xFFcc3300 : 0xFF993300;
} else {
return focused() ? 0xFFE0E0E0 : 0xFF909090;
}
}
@Override
public void lastKeyTyped(int keyID, char keyChar) {
if (focused() && NEIClientConfig.isKeyHashDown("gui.getprevioussearch")) {
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
}
if (focused() && NEIClientConfig.isKeyHashDown("gui.getnextsearch")) {
handleNavigateHistory(TextHistory.Direction.NEXT);
}
}
@Override
public String filterText(String s) {
return EnumChatFormatting.getTextWithoutFormattingCodes(s);
}
public ItemFilter getFilter() {
return ((GuiSearchField) field).getFilter();
}
@Override
public void setFocus(boolean focus) {
final boolean previousFocus = field.isFocused();
if (previousFocus != focus) {
history.add(text());
}
super.setFocus(focus);
}
private boolean handleNavigateHistory(TextHistory.Direction direction) {
if (focused()) {
return history.get(direction, text()).map(newText -> {
setText(newText);
return true;
}).orElse(false);
}
return false;
}
}
+208 -48
View File
@@ -1,21 +1,24 @@
package codechicken.nei;
import static codechicken.nei.NEIClientConfig.world;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import net.minecraft.client.Minecraft;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import net.minecraftforge.fluids.FluidStack;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ItemList.AnyMultiItemFilter;
import codechicken.nei.ItemList.EverythingItemFilter;
import codechicken.nei.ItemList.PatternItemFilter;
import codechicken.nei.api.API;
import codechicken.nei.ItemList.NothingItemFilter;
import codechicken.nei.SearchTokenParser.ISearchParserProvider;
import codechicken.nei.SearchTokenParser.SearchMode;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.TextHistory;
public class SearchField extends TextField implements ItemFilterProvider {
@@ -23,6 +26,7 @@ public class SearchField extends TextField implements ItemFilterProvider {
/**
* Interface for returning a custom filter based on search field text
*/
@Deprecated
public static interface ISearchProvider {
/**
@@ -36,34 +40,100 @@ public class SearchField extends TextField implements ItemFilterProvider {
public ItemFilter getFilter(String searchText);
}
private static class DefaultSearchProvider implements ISearchProvider {
public static class SearchParserProvider implements ISearchParserProvider {
@Override
public boolean isPrimary() {
return false;
protected final Function<Pattern, ItemFilter> createFilter;
protected final String name;
protected final char prefix;
protected final EnumChatFormatting highlightedColor;
public SearchParserProvider(char prefix, String name, EnumChatFormatting highlightedColor,
Function<Pattern, ItemFilter> createFilter) {
this.prefix = prefix;
this.name = name;
this.highlightedColor = highlightedColor;
this.createFilter = createFilter;
}
@Override
public ItemFilter getFilter(String searchText) {
Pattern pattern = getPattern(searchText);
return pattern == null ? null : new PatternItemFilter(pattern);
Pattern pattern = SearchField.getPattern(searchText);
if (pattern != null) {
return this.createFilter(pattern);
}
return new NothingItemFilter();
}
protected ItemFilter createFilter(Pattern pattern) {
final ItemFilter filter = this.createFilter.apply(pattern);
return filter == null ? new NothingItemFilter() : filter;
}
@Override
public char getPrefix() {
return this.prefix;
}
@Override
public EnumChatFormatting getHighlightedColor() {
return this.highlightedColor;
}
@Override
public SearchMode getSearchMode() {
return SearchMode.fromInt(NEIClientConfig.getIntSetting("inventory.search." + this.name + "SearchMode"));
}
}
public static class GuiSearchField extends FormattedTextField {
protected final SearchTokenParser searchParser;
public GuiSearchField() {
this(SearchField.searchParser);
}
public GuiSearchField(SearchTokenParser searchParser) {
super(Minecraft.getMinecraft().fontRenderer, 0, 0, 0, 0);
this.searchParser = searchParser;
setFormatter(new SearchTextFormatter(searchParser));
setDisabledTextColour(0xFF303030);
setPlaceholder(NEIClientUtils.translate("inventory.search.placeholder"));
}
public ItemFilter getFilter() {
return getFilter(getText());
}
public ItemFilter getFilter(String filterText) {
return this.searchParser.getFilter(filterText);
}
}
@Deprecated
public static List<ISearchProvider> searchProviders = new LinkedList<>();
public static final SearchTokenParser searchParser = new SearchTokenParser();
private static final TextHistory history = new TextHistory();
private boolean isVisible = true;
long lastclicktime;
private long lastclicktime;
public SearchField(String ident) {
super(ident);
API.addItemFilter(this);
API.addSearchProvider(new DefaultSearchProvider());
}
@Override
protected void initInternalTextField() {
field = new GuiSearchField();
field.setMaxStringLength(maxSearchLength);
field.setCursorPositionZero();
}
public static boolean searchInventories() {
return world.nbt.getBoolean("searchinventories");
return NEIClientConfig.world.nbt.getBoolean("searchinventories");
}
public boolean isVisible() {
@@ -76,7 +146,8 @@ public class SearchField extends TextField implements ItemFilterProvider {
@Override
public int getTextColour() {
if (ItemPanels.itemPanel.getItems().isEmpty()) {
if (ItemPanels.itemPanel.getItems().isEmpty()
&& (!this.field.getText().isEmpty() || !NEIClientConfig.hideItemsUntilSearching())) {
return focused() ? 0xFFcc3300 : 0xFF993300;
} else {
return focused() ? 0xFFE0E0E0 : 0xFF909090;
@@ -85,14 +156,37 @@ public class SearchField extends TextField implements ItemFilterProvider {
@Override
public void draw(int mousex, int mousey) {
super.draw(mousex, mousey);
if (searchInventories()) {
GuiDraw.drawGradientRect(x - 1, y - 1, 1, h + 2, 0xFFFFFF00, 0xFFC0B000); // Left
GuiDraw.drawGradientRect(x - 1, y - 1, w + 2, 1, 0xFFFFFF00, 0xFFC0B000); // Top
GuiDraw.drawGradientRect(x + w, y - 1, 1, h + 2, 0xFFFFFF00, 0xFFC0B000); // Left
GuiDraw.drawGradientRect(x - 1, y + h, w + 2, 1, 0xFFFFFF00, 0xFFC0B000); // Bottom
GuiDraw.drawGradientRect(
field.xPosition - 1,
field.yPosition - 1,
1,
field.height + 2,
0xFFFFFF00,
0xFFC0B000); // Left
GuiDraw.drawGradientRect(
field.xPosition - 1,
field.yPosition - 1,
field.width + 2,
1,
0xFFFFFF00,
0xFFC0B000); // Top
GuiDraw.drawGradientRect(
field.xPosition + field.width,
field.yPosition - 1,
1,
field.height + 2,
0xFFFFFF00,
0xFFC0B000); // Left
GuiDraw.drawGradientRect(
field.xPosition - 1,
field.yPosition + field.height,
field.width + 2,
1,
0xFFFFFF00,
0xFFC0B000); // Bottom
}
}
@@ -101,7 +195,6 @@ public class SearchField extends TextField implements ItemFilterProvider {
if (button == 0) {
if (focused() && (System.currentTimeMillis() - lastclicktime < 400)) { // double click
NEIClientConfig.world.nbt.setBoolean("searchinventories", !searchInventories());
NEIClientConfig.world.saveNBT();
}
lastclicktime = System.currentTimeMillis();
}
@@ -111,10 +204,11 @@ public class SearchField extends TextField implements ItemFilterProvider {
@Override
public void onTextChange(String oldText) {
final String newText = text();
if (newText.length() > 0) NEIClientConfig.logger.debug("Searching for " + text());
NEIClientConfig.setSearchExpression(newText);
ItemList.updateFilter.restart();
if (!newText.equals(oldText)) {
if (newText.length() > 0) NEIClientConfig.logger.debug("Searching for " + newText);
NEIClientConfig.setSearchExpression(newText);
ItemList.updateFilter.restart();
}
}
@Override
@@ -123,11 +217,11 @@ public class SearchField extends TextField implements ItemFilterProvider {
if (isVisible() && NEIClientConfig.isKeyHashDown("gui.search")) {
setFocus(true);
}
if (NEIClientConfig.isKeyHashDown("gui.getprevioussearch") && focused()) {
if (focused() && NEIClientConfig.isKeyHashDown("gui.getprevioussearch")) {
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
}
if (NEIClientConfig.isKeyHashDown("gui.getnextsearch") && focused()) {
if (focused() && NEIClientConfig.isKeyHashDown("gui.getnextsearch")) {
handleNavigateHistory(TextHistory.Direction.NEXT);
}
}
@@ -138,36 +232,102 @@ public class SearchField extends TextField implements ItemFilterProvider {
}
public static Pattern getPattern(String search) {
switch (NEIClientConfig.getIntSetting("inventory.searchmode")) {
return getPattern(search, NEIClientConfig.getIntSetting("inventory.search.patternMode"));
}
public static Pattern getPattern(String search, int patternMode) {
switch (patternMode) {
case 0: // plain
search = "\\Q" + search + "\\E";
search = Pattern.quote(search);
break;
case 1:
search = search.replace(".", "").replace("?", ".").replace("*", ".+?");
case 1: // extended
if (search.length() >= 3 && search.startsWith("r/") && search.endsWith("/")) {
search = search.substring(2, search.length() - 1);
} else {
final Matcher matcher = Pattern.compile("(\\?|\\*)").matcher(search);
final StringBuilder cleanedString = new StringBuilder();
int lastEndIndex = 0;
while (matcher.find()) {
cleanedString.append(Pattern.quote(search.substring(lastEndIndex, matcher.start())));
switch (matcher.group(0).charAt(0)) {
case '?':
cleanedString.append(".");
break;
case '*':
cleanedString.append(".+?");
break;
default:
break;
}
lastEndIndex = matcher.end();
}
search = cleanedString + Pattern.quote(search.substring(lastEndIndex, search.length()));
}
break;
default:
break;
}
Pattern pattern = null;
try {
pattern = Pattern.compile(search);
} catch (PatternSyntaxException ignored) {}
return pattern == null || pattern.toString().length() == 0 ? null : pattern;
if (!search.isEmpty()) {
try {
return Pattern.compile(search, Pattern.MULTILINE | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
} catch (PatternSyntaxException ignored) {}
}
return null;
}
public static String getEscapedSearchText(ItemStack stack) {
final FluidStack fluidStack = StackInfo.getFluid(stack);
String displayName;
if (fluidStack != null) {
displayName = fluidStack.getLocalizedName();
} else {
displayName = stack.getDisplayName();
}
return getEscapedSearchText(displayName);
}
public static String getEscapedSearchText(String text) {
text = EnumChatFormatting.getTextWithoutFormattingCodes(text);
switch (NEIClientConfig.getIntSetting("inventory.search.patternMode")) {
case 1:
text = text.replaceAll("[\\?|\\*]", "\\\\$0");
break;
case 2:
text = text.replaceAll("[{}()\\[\\].+*?^$\\\\|]", "\\\\$0");
break;
default:
break;
}
if (text.contains(" ") && NEIClientConfig.getBooleanSetting("inventory.search.quoteDropItemName")) {
text = "\"" + text + "\"";
}
return text;
}
@Override
public ItemFilter getFilter() {
String s_filter = text().toLowerCase();
List<ItemFilter> primary = new LinkedList<>();
List<ItemFilter> secondary = new LinkedList<>();
for (ISearchProvider p : searchProviders) {
ItemFilter filter = p.getFilter(s_filter);
if (filter != null) (p.isPrimary() ? primary : secondary).add(filter);
if (field.getText().isEmpty() && NEIClientConfig.hideItemsUntilSearching()) {
return new NothingItemFilter();
}
if (!primary.isEmpty()) return new AnyMultiItemFilter(primary);
if (!secondary.isEmpty()) return new AnyMultiItemFilter(secondary);
return new EverythingItemFilter();
return ((GuiSearchField) field).getFilter();
}
public static ItemFilter getFilter(String filterText) {
return SearchField.searchParser.getFilter(filterText);
}
@Override
@@ -0,0 +1,66 @@
package codechicken.nei;
import java.util.List;
import java.util.StringJoiner;
import net.minecraft.util.EnumChatFormatting;
import codechicken.nei.FormattedTextField.TextFormatter;
import codechicken.nei.SearchTokenParser.SearchToken;
public class SearchTextFormatter implements TextFormatter {
protected final SearchTokenParser searchParser;
public SearchTextFormatter(SearchTokenParser searchParser) {
this.searchParser = searchParser;
}
public String format(String text) {
final String[] parts = (text + "| ").split("\\|");
StringJoiner formattedText = new StringJoiner(EnumChatFormatting.GRAY + "|");
for (int i = 0; i < parts.length - 1; i++) {
final String filterText = parts[i];
final List<SearchToken> tokens = searchParser.splitSearchText(filterText);
StringBuilder formattedPart = new StringBuilder();
int startIndex = 0;
for (SearchToken token : tokens) {
formattedPart.append(filterText.substring(startIndex, token.start));
EnumChatFormatting tokenColor = EnumChatFormatting.RESET;
if (token.firstChar != null) {
tokenColor = searchParser.getProvider(token.firstChar).getHighlightedColor();
}
if (token.ignore) {
formattedPart.append(EnumChatFormatting.BLUE + "-");
}
if (token.firstChar != null) {
formattedPart.append(tokenColor + String.valueOf(token.firstChar));
}
if (token.quotes) {
formattedPart.append(EnumChatFormatting.GOLD + "\"");
}
if (!token.rawText.isEmpty()) {
formattedPart.append(tokenColor + token.rawText);
}
if (token.quotes) {
formattedPart.append(EnumChatFormatting.GOLD + "\"");
}
startIndex = token.end;
}
formattedPart.append(filterText.substring(startIndex, filterText.length()));
formattedText.add(formattedPart);
}
return formattedText.toString();
}
}
@@ -0,0 +1,309 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.Language;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import codechicken.nei.ItemList.AllMultiItemFilter;
import codechicken.nei.ItemList.AnyMultiItemFilter;
import codechicken.nei.ItemList.EverythingItemFilter;
import codechicken.nei.ItemList.NegatedItemFilter;
import codechicken.nei.ItemList.NothingItemFilter;
import codechicken.nei.api.ItemFilter;
public class SearchTokenParser {
public enum SearchMode {
ALWAYS,
PREFIX,
NEVER;
public static SearchMode fromInt(int value) {
return switch (value) {
case 0 -> ALWAYS;
case 1 -> PREFIX;
default -> NEVER;
};
}
}
public static class SearchToken {
public boolean ignore = false;
public boolean quotes = false;
public Character firstChar = null;
public String[] words;
public String rawText = "";
public int start = 0;
public int end = 0;
}
public static interface ISearchParserProvider {
public ItemFilter getFilter(String searchText);
public static List<Language> getAllLanguages() {
return new ArrayList<>(Minecraft.getMinecraft().getLanguageManager().getLanguages());
}
default List<Language> getMatchingLanguages() {
return getAllLanguages();
}
public char getPrefix();
public EnumChatFormatting getHighlightedColor();
public SearchMode getSearchMode();
}
private static class ProvidersCache {
public String languageCode = null;
public List<ISearchParserProvider> providers = new ArrayList<>();
public void clear() {
this.languageCode = null;
this.providers.clear();
}
}
private static class IsRegisteredItemFilter implements ItemFilter {
public ItemFilter filter;
public IsRegisteredItemFilter(ItemFilter filter) {
this.filter = filter;
}
@Override
public boolean matches(ItemStack item) {
return item != null && item.getItem() != null
&& item.getItem().delegate.name() != null
&& this.filter.matches(item);
}
}
protected final LRUCache<String, ItemFilter> filtersCache = new LRUCache<>(20);
protected final List<ISearchParserProvider> searchProviders;
protected final ProvidersCache providersCache = new ProvidersCache();
protected final Map<Character, Character> prefixRedefinitions = new HashMap<>();
public SearchTokenParser(List<ISearchParserProvider> searchProviders) {
this.searchProviders = searchProviders;
}
public SearchTokenParser() {
this(new ArrayList<>());
}
public void addProvider(ISearchParserProvider provider) {
this.searchProviders.add(provider);
this.providersCache.clear();
this.filtersCache.clear();
}
public void clearCache() {
this.filtersCache.clear();
}
protected List<ISearchParserProvider> getProviders() {
Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage();
if (!currentLanguage.getLanguageCode().equals(providersCache.languageCode)) {
Map<Character, ISearchParserProvider> providers = new HashMap<>();
for (int index = this.searchProviders.size() - 1; index >= 0; index--) {
ISearchParserProvider provider = this.searchProviders.get(index);
if (!providers.containsKey(provider.getPrefix())
&& provider.getMatchingLanguages().contains(currentLanguage)) {
providers.put(provider.getPrefix(), provider);
}
}
providersCache.providers = new ArrayList<>(providers.values());
providersCache.languageCode = currentLanguage.getLanguageCode();
}
return providersCache.providers;
}
public ISearchParserProvider getProvider(char ch) {
return getProviders().stream()
.filter(
provider -> provider.getSearchMode() == SearchMode.PREFIX
&& getRedefinedPrefix(provider.getPrefix()) == ch)
.findFirst().orElse(null);
}
public synchronized ItemFilter getFilter(String filterText) {
filterText = EnumChatFormatting.getTextWithoutFormattingCodes(filterText).toLowerCase();
return this.filtersCache.computeIfAbsent(filterText, text -> {
final String[] parts = text.split("\\|");
final List<ItemFilter> searchTokens = Arrays.stream(parts).map(this::parseSearchText).filter(s -> s != null)
.collect(Collectors.toList());
if (searchTokens.isEmpty()) {
return new EverythingItemFilter();
} else if (searchTokens.size() == 1) {
return new IsRegisteredItemFilter(searchTokens.get(0));
} else {
return new IsRegisteredItemFilter(new AnyMultiItemFilter(searchTokens));
}
});
}
public List<SearchToken> splitSearchText(String filterText) {
if (filterText.isEmpty()) {
return Collections.emptyList();
}
final List<SearchToken> tokens = new ArrayList<>();
final String prefixes = getPrefixes();
final int spaceMode = NEIClientConfig.getIntSetting("inventory.search.spaceMode");
// The regular expression first tries to match a string that starts with a space or the beginning of the string,
// followed by a sequence of characters that do not contain special characters -"@#$%&, and ends with a space
// and the characters -"@#$%& or the end of the string.
final String patternPart1 = "(?<tokenA>(^|\\s+)(?:[^" + Pattern.quote(" -\"" + prefixes)
+ "]).+?(?=\\s+["
+ Pattern.quote("-\"" + prefixes)
+ "]|$))";
// If the first condition is not met, it tries to match a sequence of - characters, followed by @#$%&
// characters, then either a quoted string or non-space characters.
final String patternPart2 = "((?<ignore>-*)(?<firstChar>[" + Pattern.quote(prefixes)
+ "]*)(?<tokenB>\\\".*?(?:\\\"|$)|\\S+\\s*))";
final Pattern pattern = Pattern.compile(spaceMode == 0 ? patternPart2 : (patternPart1 + "|" + patternPart2));
final Matcher filterMatcher = pattern.matcher(filterText);
while (filterMatcher.find()) {
String firstChar = filterMatcher.group("firstChar");
SearchToken token = new SearchToken();
token.start = filterMatcher.start();
token.end = filterMatcher.end();
token.ignore = "-".equals(filterMatcher.group("ignore"));
token.rawText = spaceMode == 0 ? null : filterMatcher.group("tokenA");
if (firstChar != null && !firstChar.isEmpty()) {
token.firstChar = firstChar.charAt(0);
}
if (token.rawText == null) { // spaceMode == 0
token.rawText = filterMatcher.group("tokenB");
token.quotes = token.rawText.length() > 1 && token.rawText.startsWith("\"")
&& token.rawText.endsWith("\"");
if (token.quotes) {
token.rawText = token.rawText.substring(1, token.rawText.length() - 1);
}
token.words = new String[] { token.rawText.trim() };
} else if (spaceMode == 2) {
token.words = token.rawText.trim().split("\\s+");
} else {
token.words = new String[] { token.rawText.trim() };
}
tokens.add(token);
}
return tokens;
}
private String getPrefixes() {
StringBuilder prefixes = new StringBuilder().append('\0');
for (ISearchParserProvider provider : getProviders()) {
if (provider.getSearchMode() == SearchMode.PREFIX) {
prefixes.append(getRedefinedPrefix(provider.getPrefix()));
}
}
return prefixes.toString();
}
public char getRedefinedPrefix(char prefix) {
return this.prefixRedefinitions.getOrDefault(prefix, prefix);
}
private ItemFilter parseSearchText(String filterText) {
if (filterText.isEmpty()) {
return null;
}
final AllMultiItemFilter searchTokens = new AllMultiItemFilter();
final List<SearchToken> tokens = splitSearchText(filterText);
for (SearchToken token : tokens) {
if (!token.rawText.isEmpty()) {
ItemFilter result = parseToken(token);
if (token.ignore) {
searchTokens.filters.add(new NegatedItemFilter(result));
} else {
searchTokens.filters.add(result);
}
} else if (!token.ignore) {
searchTokens.filters.add(new NothingItemFilter());
}
}
return searchTokens;
}
private ItemFilter parseToken(SearchToken token) {
final ISearchParserProvider provider = token.firstChar == null ? null : this.getProvider(token.firstChar);
if (provider == null || provider.getSearchMode() == SearchMode.NEVER) {
final List<ItemFilter> filters = new ArrayList<>();
for (ISearchParserProvider _provider : getProviders()) {
if (_provider.getSearchMode() == SearchMode.ALWAYS) {
AllMultiItemFilter filter = generateFilters(_provider, token.words);
if (!filter.filters.isEmpty()) {
filters.add(filter);
}
}
}
return filters.isEmpty() ? new NothingItemFilter() : new AnyMultiItemFilter(filters);
} else {
return generateFilters(provider, token.words);
}
}
private AllMultiItemFilter generateFilters(ISearchParserProvider provider, String[] words) {
final AllMultiItemFilter filters = new AllMultiItemFilter();
for (String work : words) {
final ItemFilter filter = provider.getFilter(work);
if (filter != null) {
filters.filters.add(filter);
}
}
return filters;
}
}
@@ -64,7 +64,6 @@ public class SpawnerRenderer implements IItemRenderer {
BossStatus.hasColorModifier = bossHasColorModifier;
}
@SuppressWarnings("incomplete-switch")
@Override
public void renderItem(ItemRenderType type, ItemStack item, Object... data) {
switch (type) {
@@ -75,6 +74,8 @@ public class SpawnerRenderer implements IItemRenderer {
case ENTITY:
renderInventoryItem((RenderBlocks) data[0], item);
break;
default:
break;
}
}
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -9,7 +9,7 @@ public abstract class TextField extends Widget {
protected GuiTextField field;
private static final int maxSearchLength = 256;
protected static final int maxSearchLength = 256;
public boolean centered;
public String identifier;
@@ -6,9 +6,9 @@ import cpw.mods.fml.common.FMLCommonHandler;
public class ThreadOperationTimer extends Thread {
@SuppressWarnings("serial")
public static class TimeoutException extends RuntimeException {
private static final long serialVersionUID = -8621458005263888185L;
public final Object operation;
public TimeoutException(String msg, Object op) {
@@ -15,10 +15,6 @@ public class VisiblityData {
* Subset dropdown
*/
public boolean showSubsetDropdown = true;
/**
* Presets dropdown
*/
public boolean showPresetsDropdown = true;
/**
* Item and search section
*/
@@ -44,7 +40,6 @@ public class VisiblityData {
public void translateDependancies() {
if (!showNEI) showWidgets = false;
if (!showWidgets) showItemSection = showUtilityButtons = false;
if (!showItemSection)
showBookmarkPanel = showSubsetDropdown = showPresetsDropdown = showSearchSection = showItemPanel = false;
if (!showItemSection) showBookmarkPanel = showSubsetDropdown = showSearchSection = showItemPanel = false;
}
}
@@ -11,6 +11,6 @@ public class WidgetZOrder implements Comparator<Widget> {
}
public int compare(Widget w1, Widget w2) {
return w1.z != w2.z ? ((topfirst ? w1.z > w2.z : w1.z < w2.z) ? 1 : -1) : 1;
return w1.z != w2.z ? ((topfirst ? w1.z < w2.z : w1.z > w2.z) ? 1 : -1) : 1;
}
}
@@ -6,6 +6,7 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.entity.passive.EntityPig;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.ChatComponentText;
import net.minecraft.world.EnumSkyBlock;
import net.minecraft.world.SpawnerAnimals;
import net.minecraft.world.World;
@@ -16,6 +17,7 @@ import org.lwjgl.opengl.GL11;
import codechicken.lib.math.MathHelper;
import codechicken.nei.KeyManager.IKeyStateTracker;
import cpw.mods.fml.relauncher.ReflectionHelper;
public class WorldOverlayRenderer implements IKeyStateTracker {
@@ -25,12 +27,11 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
private static byte[] mobSpawnCache;
private static long mobOverlayUpdateTime;
private static String oregenPatternName;
private static boolean hasOregenPatternBeenSet = false;
public static void reset() {
mobOverlay = 0;
chunkOverlay = 0;
hasOregenPatternBeenSet = false;
oregenPatternName = null;
}
@Override
@@ -38,8 +39,13 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
if (Minecraft.getMinecraft().currentScreen != null) return;
if (KeyManager.keyStates.get("world.moboverlay").down) mobOverlay = (mobOverlay + 1) % 2;
if (KeyManager.keyStates.get("world.chunkoverlay").down)
if (KeyManager.keyStates.get("world.chunkoverlay").down) {
chunkOverlay = (chunkOverlay + 1) % (NEIModContainer.isGT5Loaded() ? 4 : 3);
// 0-2 (or 3 with gt)
NEIClientUtils.printChatMessage(
new ChatComponentText(NEIClientUtils.translate("chat.chunkoverlay." + chunkOverlay)));
}
}
public static void render(float frame) {
@@ -198,7 +204,9 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glLineWidth(1.5F);
GL11.glBegin(GL11.GL_LINES);
final Tessellator tess = Tessellator.instance;
tess.startDrawing(GL11.GL_LINES);
for (int cx = -4; cx <= 4; cx++) for (int cz = -4; cz <= 4; cz++) {
double x1 = ((entity.chunkCoordX + cx) << 4) - intOffsetX;
@@ -224,22 +232,22 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
double dist = Math.pow(1.5, -(cx * cx + cz * cz));
GL11.glColor4d(0.9, 0, 0, dist);
tess.setColorRGBA_F(0.9F, 0, 0, (float) dist);
if (cx >= 0 && cz >= 0) {
GL11.glVertex3d(x2, y1, z2);
GL11.glVertex3d(x2, y2, z2);
tess.addVertex(x2, y1, z2);
tess.addVertex(x2, y2, z2);
}
if (cx >= 0 && cz <= 0) {
GL11.glVertex3d(x2, y1, z1);
GL11.glVertex3d(x2, y2, z1);
tess.addVertex(x2, y1, z1);
tess.addVertex(x2, y2, z1);
}
if (cx <= 0 && cz >= 0) {
GL11.glVertex3d(x1, y1, z2);
GL11.glVertex3d(x1, y2, z2);
tess.addVertex(x1, y1, z2);
tess.addVertex(x1, y2, z2);
}
if (cx <= 0 && cz <= 0) {
GL11.glVertex3d(x1, y1, z1);
GL11.glVertex3d(x1, y2, z1);
tess.addVertex(x1, y1, z1);
tess.addVertex(x1, y2, z1);
}
if (cx == 0 && cz == 0) {
@@ -260,40 +268,31 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
y1 -= intOffsetY;
y2 -= intOffsetY;
GL11.glColor4d(0, 0.9, 0, 0.4);
tess.setColorRGBA_F(0, 0.9F, 0, 0.4F);
for (double y = (int) y1; y <= y2; y++) {
GL11.glVertex3d(x2, y, z1);
GL11.glVertex3d(x2, y, z2);
GL11.glVertex3d(x1, y, z1);
GL11.glVertex3d(x1, y, z2);
GL11.glVertex3d(x1, y, z2);
GL11.glVertex3d(x2, y, z2);
GL11.glVertex3d(x1, y, z1);
GL11.glVertex3d(x2, y, z1);
tess.addVertex(x2, y, z1);
tess.addVertex(x2, y, z2);
tess.addVertex(x1, y, z1);
tess.addVertex(x1, y, z2);
tess.addVertex(x1, y, z2);
tess.addVertex(x2, y, z2);
tess.addVertex(x1, y, z1);
tess.addVertex(x2, y, z1);
}
for (double h = 1; h <= 15; h++) {
GL11.glVertex3d(x1 + h, y1, z1);
GL11.glVertex3d(x1 + h, y2, z1);
GL11.glVertex3d(x1 + h, y1, z2);
GL11.glVertex3d(x1 + h, y2, z2);
GL11.glVertex3d(x1, y1, z1 + h);
GL11.glVertex3d(x1, y2, z1 + h);
GL11.glVertex3d(x2, y1, z1 + h);
GL11.glVertex3d(x2, y2, z1 + h);
tess.addVertex(x1 + h, y1, z1);
tess.addVertex(x1 + h, y2, z1);
tess.addVertex(x1 + h, y1, z2);
tess.addVertex(x1 + h, y2, z2);
tess.addVertex(x1, y1, z1 + h);
tess.addVertex(x1, y2, z1 + h);
tess.addVertex(x2, y1, z1 + h);
tess.addVertex(x2, y2, z1 + h);
}
} else if (chunkOverlay == 3) {
if (!hasOregenPatternBeenSet) {
try {
oregenPatternName = ((Enum<?>) Class.forName("gregtech.common.GT_Worldgenerator")
.getDeclaredField("oregenPattern").get(null)).name();
} catch (Exception ignored) {
oregenPatternName = "AXISSYMMETRICAL";
}
hasOregenPatternBeenSet = true;
}
int gx1;
int gz1;
if (oregenPatternName.equals("EQUAL_SPACING")) {
if (getOregenPatternName().equals("EQUAL_SPACING")) {
// gt oregen uses new regular pattern
gx1 = ((Math.floorDiv(entity.chunkCoordX, 3) * 3) << 4) - intOffsetX;
gz1 = ((Math.floorDiv(entity.chunkCoordZ, 3) * 3) << 4) - intOffsetZ;
@@ -313,55 +312,71 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
int gx2 = gx1 + 48;
int gz2 = gz1 + 48;
GL11.glColor4d(0, 0.9, 0, 0.4);
tess.setColorRGBA_F(0, 0.9F, 0, 0.4F);
for (double y = (int) y1; y <= y2; y++) {
GL11.glVertex3d(gx2, y, gz1);
GL11.glVertex3d(gx2, y, gz2);
GL11.glVertex3d(gx1, y, gz1);
GL11.glVertex3d(gx1, y, gz2);
GL11.glVertex3d(gx1, y, gz2);
GL11.glVertex3d(gx2, y, gz2);
GL11.glVertex3d(gx1, y, gz1);
GL11.glVertex3d(gx2, y, gz1);
tess.addVertex(gx2, y, gz1);
tess.addVertex(gx2, y, gz2);
tess.addVertex(gx1, y, gz1);
tess.addVertex(gx1, y, gz2);
tess.addVertex(gx1, y, gz2);
tess.addVertex(gx2, y, gz2);
tess.addVertex(gx1, y, gz1);
tess.addVertex(gx2, y, gz1);
}
for (double h = 4; h <= 44; h += 4) {
if (h % 16 == 0) {
continue;
}
GL11.glVertex3d(gx1 + h, y1, gz1);
GL11.glVertex3d(gx1 + h, y2, gz1);
GL11.glVertex3d(gx1 + h, y1, gz2);
GL11.glVertex3d(gx1 + h, y2, gz2);
GL11.glVertex3d(gx1, y1, gz1 + h);
GL11.glVertex3d(gx1, y2, gz1 + h);
GL11.glVertex3d(gx2, y1, gz1 + h);
GL11.glVertex3d(gx2, y2, gz1 + h);
tess.addVertex(gx1 + h, y1, gz1);
tess.addVertex(gx1 + h, y2, gz1);
tess.addVertex(gx1 + h, y1, gz2);
tess.addVertex(gx1 + h, y2, gz2);
tess.addVertex(gx1, y1, gz1 + h);
tess.addVertex(gx1, y2, gz1 + h);
tess.addVertex(gx2, y1, gz1 + h);
tess.addVertex(gx2, y2, gz1 + h);
}
GL11.glColor4d(0, 0, 0.9, 0.4);
tess.setColorRGBA_F(0, 0, 0.9F, 0.4F);
gx1 += 23;
gz1 += 23;
gx2 = gx1 + 1;
gz2 = gz1 + 1;
GL11.glVertex3d(gx1, y1, gz1);
GL11.glVertex3d(gx1, y2, gz1);
GL11.glVertex3d(gx2, y1, gz1);
GL11.glVertex3d(gx2, y2, gz1);
GL11.glVertex3d(gx1, y1, gz2);
GL11.glVertex3d(gx1, y2, gz2);
GL11.glVertex3d(gx2, y1, gz2);
GL11.glVertex3d(gx2, y2, gz2);
tess.addVertex(gx1, y1, gz1);
tess.addVertex(gx1, y2, gz1);
tess.addVertex(gx2, y1, gz1);
tess.addVertex(gx2, y2, gz1);
tess.addVertex(gx1, y1, gz2);
tess.addVertex(gx1, y2, gz2);
tess.addVertex(gx2, y1, gz2);
tess.addVertex(gx2, y2, gz2);
}
}
}
GL11.glEnd();
tess.draw();
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_BLEND);
}
private static String getOregenPatternName() {
if (oregenPatternName == null) {
try {
final ClassLoader loader = WorldOverlayRenderer.class.getClassLoader();
final Class<?> gtWorldGenerator = ReflectionHelper
.getClass(loader, "gregtech.common.GTWorldgenerator", "gregtech.common.GT_Worldgenerator");
oregenPatternName = ((Enum<?>) gtWorldGenerator.getDeclaredField("oregenPattern").get(null)).name();
} catch (Exception ignored) {
oregenPatternName = "AXISSYMMETRICAL";
}
}
return oregenPatternName;
}
public static void load() {
KeyManager.trackers.add(new WorldOverlayRenderer());
}
+39 -18
View File
@@ -25,13 +25,16 @@ import codechicken.nei.NEIClientConfig;
import codechicken.nei.OffsetPositioner;
import codechicken.nei.SearchField;
import codechicken.nei.SearchField.ISearchProvider;
import codechicken.nei.SearchTokenParser.ISearchParserProvider;
import codechicken.nei.SubsetWidget;
import codechicken.nei.SubsetWidget.SubsetTag;
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.config.Option;
import codechicken.nei.config.OptionKeyBind;
import codechicken.nei.recipe.CatalystInfo;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.GuiUsageRecipe;
import codechicken.nei.recipe.ICraftingHandler;
import codechicken.nei.recipe.IRecipeHandler;
@@ -39,6 +42,7 @@ import codechicken.nei.recipe.IUsageHandler;
import codechicken.nei.recipe.RecipeCatalysts;
import codechicken.nei.recipe.RecipeInfo;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.ItemStackFilterParser;
/**
* This is the main class that handles item property configuration. WARNING: DO NOT access this class until the world
@@ -148,6 +152,14 @@ public class API {
}
}
public static void hideItem(String rule) {
ItemFilter filter = ItemStackFilterParser.parse(rule);
if (filter != null) {
ItemInfo.hiddenItemsRules.filters.add(filter);
LayoutManager.markItemsDirty();
}
}
/**
* Add or replace the name normally shown on the item tooltip
*/
@@ -160,7 +172,7 @@ public class API {
/**
* Adds an item to the item panel. Any items added using this function will override the default search pattern.
*
*
* @param item an item with data
*/
public static void addItemListEntry(ItemStack item) {
@@ -183,7 +195,7 @@ public class API {
/**
* Add a custom KeyBinding to be configured in the Controls menu.
*
*
* @param ident An identifier for your key, eg "shoot"
* @param defaultKey The default value, commonly obtained from {@link Keyboard}
*/
@@ -195,7 +207,7 @@ public class API {
/**
* Add a custom KeyBinding to be configured in the Controls menu.
*
*
* @param ident An identifier for your key, eg "shoot"
* @param defaultKey The default value, commonly obtained from {@link Keyboard}
*/
@@ -210,7 +222,7 @@ public class API {
/**
* Add a new Layout Style for the NEI interface
*
*
* @param styleID The Unique ID to be used for storing your style in the config and cycling through avaliable styles
* @param style The style to add.
*/
@@ -220,7 +232,7 @@ public class API {
/**
* Registers a new Infinite Item Handler.
*
*
* @param handler The handler to be registered.
*/
public static void addInfiniteItemHandler(IInfiniteItemHandler handler) {
@@ -229,7 +241,7 @@ public class API {
/**
* Registers a new Infinite Item Handler.
*
*
* @param block The block to handle, null for all.
* @param handler The handler to be registered.
*/
@@ -239,7 +251,7 @@ public class API {
/**
* Tells NEI not to perform any Fast Transfer operations on slots of a particular class
*
*
* @param slotClass The class of slot to be exempted
*/
public static void addFastTransferExemptSlot(Class<? extends Slot> slotClass) {
@@ -248,7 +260,7 @@ public class API {
/**
* Register a new text handler for the block highlight tooltip with a layout specification (HEADER, BODY or FOOTER).
*
*
* @param handler The handler to be registered.
* @param layout A HUDAugmenterRegistry.Layout entry. HEADER is displayed before BODY which is displayed before
* FOOTER.
@@ -259,16 +271,22 @@ public class API {
/**
* Register a mode handler for overriding NEI recipe/utility/cheat mode settings.
*
*
* @param handler The handler to be registered.
*/
public static void registerModeHandler(INEIModeHandler handler) {
NEIInfo.modeHandlers.add(handler);
}
public static void addRecipeFilter(IRecipeFilterProvider filterProvider) {
synchronized (GuiRecipe.recipeFilterers) {
GuiRecipe.recipeFilterers.add(filterProvider);
}
}
/**
* Register a filter provider for the item panel.
*
*
* @param filterProvider The filter provider to be registered.
*/
public static void addItemFilter(ItemFilterProvider filterProvider) {
@@ -279,7 +297,7 @@ public class API {
/**
* Adds a new tag to the item subset dropdown.
*
*
* @param name The fully qualified name, Eg Blocks.MobSpawners. NOT case sensitive
* @param filter A filter for matching items that fit in this subset
*/
@@ -289,7 +307,7 @@ public class API {
/**
* Adds a new tag to the item subset dropdown.
*
*
* @param name The fully qualified name, Eg Blocks.MobSpawners. NOT case sensitive
* @param items An iterable of itemstacks to be added as a subset
*/
@@ -306,16 +324,19 @@ public class API {
SubsetWidget.addTag(tag);
}
@Deprecated
public static void addSearchProvider(ISearchProvider provider) {}
/**
* Adds a new search provider to the search field
*/
public static void addSearchProvider(ISearchProvider provider) {
SearchField.searchProviders.add(provider);
public static void addSearchProvider(ISearchParserProvider provider) {
SearchField.searchParser.addProvider(provider);
}
/**
* Adds a new sorting option to the item panel sort menu
*
*
* @param name A unique id for this sort option. Will be used in the config for saving and translated in the options
* gui. Note that if the translation key name.tip exists, it will be used for a tooltip
*/
@@ -326,7 +347,7 @@ public class API {
/**
* Adds an additional item list entry for an item, sorted after the rest of the items are found through the normal
* process
*
*
* @param item The item to add the variant for
* @param variant The stack to appear in the item panel
*/
@@ -345,7 +366,7 @@ public class API {
* Adds an association between an ingredient and what it can craft. (i.e. Furnace ItemStack -> Smelting and Fuel
* Recipes) Allows players to see what ingredient they need to craft in order to make recipes from a recipe
* category.
*
*
* @param stack the ingredient that can craft recipes (like a furnace or crafting table)
* @param handler the recipe category handled by the ingredient
* @param priority higher priority comes first, default to 0
@@ -366,7 +387,7 @@ public class API {
* Adds an association between an ingredient and what it can craft. (i.e. Furnace ItemStack -> Smelting and Fuel
* Recipes) Allows players to see what ingredient they need to craft in order to make recipes from a recipe
* category.
*
*
* @param stack the ingredient that can craft recipes (like a furnace or crafting table)
* @param handlerID recipe category identifier (see also {@link RecipeCatalysts#getRecipeID(IRecipeHandler)})
* @param priority higher priority comes first, default to 0
@@ -1,5 +1,7 @@
package codechicken.nei.api;
import static codechicken.lib.gui.GuiDraw.drawRect;
import java.util.ArrayList;
import java.util.List;
@@ -7,13 +9,14 @@ import net.minecraft.inventory.Slot;
import org.lwjgl.opengl.GL11;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.guihook.GuiContainerManager;
public class DefaultOverlayRenderer implements IRecipeOverlayRenderer {
public DefaultOverlayRenderer(List<PositionedStack> ai, IStackPositioner positioner) {
positioner = this.positioner = positioner;
this.positioner = positioner;
ingreds = new ArrayList<>();
for (PositionedStack stack : ai) ingreds.add(stack.copy());
ingreds = positioner.positionStacks(ingreds);
@@ -21,20 +24,22 @@ public class DefaultOverlayRenderer implements IRecipeOverlayRenderer {
@Override
public void renderOverlay(GuiContainerManager gui, Slot slot) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(770, 1);
GL11.glColor4d(0.6, 0.6, 0.6, 0.7);
GuiContainerManager.setColouredItemRender(true);
for (PositionedStack stack : ingreds) {
if (stack.relx == slot.xDisplayPosition && stack.rely == slot.yDisplayPosition)
if (stack.relx == slot.xDisplayPosition && stack.rely == slot.yDisplayPosition && !slot.getHasStack()) {
GuiContainerManager.drawItem(stack.relx, stack.rely, stack.item);
drawHover(stack.relx, stack.rely);
}
}
GuiContainerManager.setColouredItemRender(false);
GL11.glColor4f(1, 1, 1, 1);
GL11.glDisable(GL11.GL_BLEND);
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glPopAttrib();
}
private static void drawHover(int x, int y) {
NEIClientUtils.gl2DRenderContext(() -> drawRect(x, y, 16, 16, 0x66555555));
}
final IStackPositioner positioner;
@@ -1,11 +1,26 @@
package codechicken.nei.api;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
public interface IBookmarkContainerHandler {
default List<ItemStack> getStorageStacks(GuiContainer guiContainer) {
final List<Slot> slots = guiContainer.inventorySlots.inventorySlots;
final List<ItemStack> stacks = new ArrayList<>();
for (int i = 0; i < slots.size() - 4 * 9; i++) {
if (slots.get(i).getHasStack()) {
stacks.add(slots.get(i).getStack());
}
}
return stacks;
}
void pullBookmarkItemsFromContainer(GuiContainer guiContainer, ArrayList<ItemStack> realItems);
}
@@ -1,10 +1,60 @@
package codechicken.nei.api;
import net.minecraft.client.gui.inventory.GuiContainer;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import codechicken.nei.PositionedStack;
import codechicken.nei.recipe.GuiOverlayButton.ItemOverlayState;
import codechicken.nei.recipe.IRecipeHandler;
public interface IOverlayHandler {
void overlayRecipe(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, boolean shift);
void overlayRecipe(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, boolean maxTransfer);
default int transferRecipe(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, int multiplier) {
return 0;
}
default boolean canFillCraftingGrid(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex) {
return true;
}
default boolean craft(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, int multiplier) {
return false;
}
default boolean canCraft(GuiContainer firstGui, IRecipeHandler handler, int recipeIndex) {
return false;
}
default List<ItemOverlayState> presenceOverlay(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex) {
final List<ItemOverlayState> itemPresenceSlots = new ArrayList<>();
final List<PositionedStack> ingredients = recipe.getIngredientStacks(recipeIndex);
final List<ItemStack> invStacks = firstGui.inventorySlots.inventorySlots.stream()
.filter(
s -> s != null && s.getStack() != null
&& s.getStack().stackSize > 0
&& s.isItemValid(s.getStack())
&& s.canTakeStack(firstGui.mc.thePlayer))
.map(s -> s.getStack().copy()).collect(Collectors.toList());
for (PositionedStack stack : ingredients) {
Optional<ItemStack> used = invStacks.stream().filter(is -> is.stackSize > 0 && stack.contains(is))
.findAny();
itemPresenceSlots.add(new ItemOverlayState(stack, used.isPresent()));
if (used.isPresent()) {
ItemStack is = used.get();
is.stackSize -= 1;
}
}
return itemPresenceSlots;
}
}
@@ -0,0 +1,18 @@
package codechicken.nei.api;
import java.util.List;
import codechicken.nei.PositionedStack;
import codechicken.nei.recipe.IRecipeHandler;
public interface IRecipeFilter {
public static interface IRecipeFilterProvider {
public IRecipeFilter getFilter();
}
public boolean matches(IRecipeHandler handler, List<PositionedStack> ingredients, PositionedStack result,
List<PositionedStack> others);
}
+73 -132
View File
@@ -5,8 +5,8 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.block.Block;
import net.minecraft.client.resources.I18n;
@@ -44,12 +44,16 @@ import com.google.common.collect.ArrayListMultimap;
import codechicken.core.featurehack.GameDataManipulator;
import codechicken.nei.InfiniteStackSizeHandler;
import codechicken.nei.InfiniteToolHandler;
import codechicken.nei.ItemList;
import codechicken.nei.ItemList.AnyMultiItemFilter;
import codechicken.nei.ItemList.PatternItemFilter;
import codechicken.nei.ItemMobSpawner;
import codechicken.nei.ItemStackMap;
import codechicken.nei.ItemStackSet;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.PopupInputHandler;
import codechicken.nei.PresetsList;
import codechicken.nei.SearchField.SearchParserProvider;
import codechicken.nei.SearchTokenParser.SearchMode;
import codechicken.nei.config.ArrayDumper;
import codechicken.nei.config.HandlerDumper;
import codechicken.nei.config.ItemPanelDumper;
@@ -57,6 +61,10 @@ import codechicken.nei.config.RegistryDumper;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.BrewingRecipeHandler;
import codechicken.nei.recipe.RecipeItemInputHandler;
import codechicken.nei.search.IdentifierFilter;
import codechicken.nei.search.ModNameFilter;
import codechicken.nei.search.OreDictionaryFilter;
import codechicken.nei.search.TooltipFilter;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.registry.GameRegistry;
@@ -76,6 +84,7 @@ public class ItemInfo {
public static final ArrayListMultimap<Layout, IHighlightHandler> highlightHandlers = ArrayListMultimap.create();
public static final ItemStackMap<String> nameOverrides = new ItemStackMap<>();
public static final ItemStackSet hiddenItems = new ItemStackSet();
public static final AnyMultiItemFilter hiddenItemsRules = new AnyMultiItemFilter();
public static final ItemStackSet finiteItems = new ItemStackSet();
public static final ArrayListMultimap<Item, ItemStack> itemOverrides = ArrayListMultimap.create();
public static final ArrayListMultimap<Item, ItemStack> itemVariants = ArrayListMultimap.create();
@@ -86,40 +95,11 @@ public class ItemInfo {
public static final HashMap<Item, String> itemOwners = new HashMap<>();
private static class ItemStackKey {
public final ItemStack stack;
public ItemStackKey(ItemStack stack) {
this.stack = stack;
}
@Override
public int hashCode() {
if (this.stack == null) return 1;
int hashCode = 1;
hashCode = 31 * hashCode + stack.stackSize;
hashCode = 31 * hashCode + Item.getIdFromItem(stack.getItem());
hashCode = 31 * hashCode + stack.getItemDamage();
hashCode = 31 * hashCode + (!stack.hasTagCompound() ? 0 : stack.getTagCompound().hashCode());
return hashCode;
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof ItemStackKey)) return false;
return ItemStack.areItemStacksEqual(this.stack, ((ItemStackKey) o).stack);
}
}
// lookup optimisation
public static final ConcurrentHashMap<ItemStackKey, String> itemSearchNames = new ConcurrentHashMap<>();
public static boolean isHidden(ItemStack stack) {
return hiddenItems.contains(stack);
return hiddenItems.contains(stack) || hiddenItemsRules.matches(stack);
}
@Deprecated
public static boolean isHidden(Item item) {
return hiddenItems.containsAll(item);
}
@@ -154,27 +134,28 @@ public class ItemInfo {
addInfiniteHandlers();
addInputHandlers();
addIDDumps();
addHiddenItemFilter();
addSearchOptimisation();
addSearchProviders();
RecipeItemInputHandler.load();
PresetsList.load();
}
private static void addSearchOptimisation() {
ItemList.loadCallbacks.add(ItemInfo::populateSearchMap);
}
private static void addSearchProviders() {
API.addSearchProvider(
new SearchParserProvider('\0', "default", EnumChatFormatting.RESET, PatternItemFilter::new) {
private static void populateSearchMap() {
/* Create a snapshot of the current keys in the cache */
HashSet<ItemStackKey> oldItems = new HashSet<>(itemSearchNames.keySet());
for (ItemStack stack : ItemList.items) {
/* Populate each entry and remove it from the snapshot */
getSearchName(stack);
oldItems.remove(new ItemStackKey(stack));
}
itemSearchNames.keySet().removeAll(oldItems);
}
@Override
public SearchMode getSearchMode() {
return SearchMode.ALWAYS;
}
private static void addHiddenItemFilter() {
API.addItemFilter(() -> item -> !hiddenItems.contains(item));
});
API.addSearchProvider(
new SearchParserProvider('@', "modName", EnumChatFormatting.LIGHT_PURPLE, ModNameFilter::new));
API.addSearchProvider(
new SearchParserProvider('$', "oreDict", EnumChatFormatting.AQUA, OreDictionaryFilter::new));
API.addSearchProvider(new SearchParserProvider('#', "tooltip", EnumChatFormatting.YELLOW, TooltipFilter::new));
API.addSearchProvider(
new SearchParserProvider('&', "identifier", EnumChatFormatting.GOLD, IdentifierFilter::new));
}
private static void addIDDumps() {
@@ -209,7 +190,7 @@ public class ItemInfo {
public String[] dump(Block block, int id, String name) {
final Item item = Item.getItemFromBlock(block);
return new String[] { name, Integer.toString(id), Boolean.toString(item != null),
ItemInfo.itemOwners.get(block), block.getClass().getCanonicalName(),
ItemInfo.itemOwners.get(item), block.getClass().getCanonicalName(),
item != null ? EnumChatFormatting.getTextWithoutFormattingCodes(
GuiContainerManager.itemDisplayNameShort(new ItemStack(item))) : "null" };
}
@@ -288,7 +269,8 @@ public class ItemInfo {
@SuppressWarnings("unchecked")
private static void parseModItems() {
HashMap<String, ItemStackSet> modSubsets = new HashMap<>();
final Map<String, ItemStackSet> modSubsets = new HashMap<>();
for (Item item : (Iterable<Item>) Item.itemRegistry) {
UniqueIdentifier ident = null;
try {
@@ -300,14 +282,12 @@ public class ItemInfo {
continue;
}
String modId = ident.modId;
itemOwners.put(item, modId);
ItemStackSet itemset = modSubsets.get(modId);
if (itemset == null) modSubsets.put(modId, itemset = new ItemStackSet());
itemset.with(item);
itemOwners.put(item, ident.modId);
modSubsets.computeIfAbsent(ident.modId, i -> new ItemStackSet()).with(item);
}
API.addSubset("Mod.Minecraft", modSubsets.remove("minecraft"));
for (Entry<String, ItemStackSet> entry : modSubsets.entrySet()) {
ModContainer mc = FMLCommonHandler.instance().findContainerFor(entry.getKey());
if (mc == null) NEIClientConfig.logger.error("Missing container for " + entry.getKey());
@@ -316,7 +296,6 @@ public class ItemInfo {
}
private static void addInputHandlers() {
GuiContainerManager.addInputHandler(new RecipeItemInputHandler());
GuiContainerManager.addInputHandler(new PopupInputHandler());
}
@@ -344,44 +323,29 @@ public class ItemInfo {
}
private static void addDefaultDropDowns() {
final Item mob_spawner = Item.getItemFromBlock(Blocks.mob_spawner);
API.addSubset("Items", item -> Block.getBlockFromItem(item.getItem()) == Blocks.air);
API.addSubset("Blocks", item -> Block.getBlockFromItem(item.getItem()) != Blocks.air);
API.addSubset("Blocks.MobSpawners", ItemStackSet.of(Blocks.mob_spawner));
API.addSubset("Blocks.MobSpawners", item -> item.getItem() == mob_spawner);
}
@SuppressWarnings("unchecked")
private static void searchItems() {
ItemStackSet tools = new ItemStackSet();
ItemStackSet picks = new ItemStackSet();
ItemStackSet shovels = new ItemStackSet();
ItemStackSet axes = new ItemStackSet();
ItemStackSet hoes = new ItemStackSet();
ItemStackSet swords = new ItemStackSet();
ItemStackSet chest = new ItemStackSet();
ItemStackSet helmets = new ItemStackSet();
ItemStackSet legs = new ItemStackSet();
ItemStackSet boots = new ItemStackSet();
ItemStackSet other = new ItemStackSet();
ItemStackSet ranged = new ItemStackSet();
ItemStackSet food = new ItemStackSet();
ItemStackSet potioningredients = new ItemStackSet();
ArrayList<ItemStackSet> creativeTabRanges = new ArrayList<>(CreativeTabs.creativeTabArray.length);
List<ItemStack> stackList = new LinkedList<>();
final Map<Integer, ItemStackSet> creativeTabRanges = new HashMap<>();
final List<ItemStack> stackList = new LinkedList<>();
for (Item item : (Iterable<Item>) Item.itemRegistry) {
if (item == null) continue;
for (CreativeTabs itemTab : item.getCreativeTabs()) {
if (itemTab != null) {
while (itemTab.getTabIndex() >= creativeTabRanges.size()) creativeTabRanges.add(null);
ItemStackSet set = creativeTabRanges.get(itemTab.getTabIndex());
if (set == null) creativeTabRanges.set(itemTab.getTabIndex(), set = new ItemStackSet());
final ItemStackSet itemset = creativeTabRanges
.computeIfAbsent(itemTab.getTabIndex(), i -> new ItemStackSet());
try {
stackList.clear();
item.getSubItems(item, itemTab, stackList);
for (ItemStack stack : stackList) set.add(stack);
itemset.addAll(stackList);
} catch (Exception e) {
NEIClientConfig.logger
.error("Error loading sub-items for: " + item + ". Tab: " + itemTab.getTabLabel(), e);
@@ -389,41 +353,13 @@ public class ItemInfo {
}
}
if (item.isDamageable()) {
tools.with(item);
if (item instanceof ItemPickaxe) picks.with(item);
else if (item instanceof ItemSpade) shovels.with(item);
else if (item instanceof ItemAxe) axes.with(item);
else if (item instanceof ItemHoe) hoes.with(item);
else if (item instanceof ItemSword) swords.with(item);
else if (item instanceof ItemArmor) switch (((ItemArmor) item).armorType) {
case 0:
helmets.with(item);
break;
case 1:
chest.with(item);
break;
case 2:
legs.with(item);
break;
case 3:
boots.with(item);
break;
}
else if (item == Items.arrow || item == Items.bow) ranged.with(item);
else if (item == Items.fishing_rod || item == Items.flint_and_steel || item == Items.shears)
other.with(item);
}
if (item instanceof ItemFood) food.with(item);
try {
LinkedList<ItemStack> subItems = new LinkedList<>();
final List<ItemStack> subItems = new LinkedList<>();
item.getSubItems(item, null, subItems);
for (ItemStack stack : subItems) {
if (item.isPotionIngredient(stack) && item.getPotionEffect(stack) != null) {
BrewingRecipeHandler.ingredients.add(stack);
potioningredients.add(stack);
}
}
@@ -431,25 +367,33 @@ public class ItemInfo {
NEIClientConfig.logger.error("Error loading brewing ingredients for: " + item, e);
}
}
API.addSubset("Items.Tools.Pickaxes", picks);
API.addSubset("Items.Tools.Shovels", shovels);
API.addSubset("Items.Tools.Axes", axes);
API.addSubset("Items.Tools.Hoes", hoes);
API.addSubset("Items.Tools.Other", other);
API.addSubset("Items.Weapons.Swords", swords);
API.addSubset("Items.Weapons.Ranged", ranged);
API.addSubset("Items.Armor.Chestplates", chest);
API.addSubset("Items.Armor.Leggings", legs);
API.addSubset("Items.Armor.Helmets", helmets);
API.addSubset("Items.Armor.Boots", boots);
API.addSubset("Items.Food", food);
API.addSubset("Items.Potions.Ingredients", potioningredients);
API.addSubset("Items.Tools.Pickaxes", item -> item.getItem() instanceof ItemPickaxe);
API.addSubset("Items.Tools.Shovels", item -> item.getItem() instanceof ItemSpade);
API.addSubset("Items.Tools.Axes", item -> item.getItem() instanceof ItemAxe);
API.addSubset("Items.Tools.Hoes", item -> item.getItem() instanceof ItemHoe);
API.addSubset(
"Items.Tools.Other",
item -> item.getItem() == Items.fishing_rod || item.getItem() == Items.flint_and_steel
|| item.getItem() == Items.shears);
API.addSubset("Items.Weapons.Swords", item -> item.getItem() instanceof ItemSword);
API.addSubset("Items.Weapons.Ranged", item -> item.getItem() == Items.arrow || item.getItem() == Items.bow);
API.addSubset("Items.Armor.Helmets", item -> item.getItem() instanceof ItemArmor armor && armor.armorType == 0);
API.addSubset(
"Items.Armor.Chestplates",
item -> item.getItem() instanceof ItemArmor armor && armor.armorType == 1);
API.addSubset(
"Items.Armor.Leggings",
item -> item.getItem() instanceof ItemArmor armor && armor.armorType == 2);
API.addSubset("Items.Armor.Boots", item -> item.getItem() instanceof ItemArmor armor && armor.armorType == 3);
API.addSubset("Items.Food", item -> item.getItem() instanceof ItemFood);
API.addSubset("Items.Potions.Ingredients", BrewingRecipeHandler.ingredients);
for (CreativeTabs tab : CreativeTabs.creativeTabArray) {
if (tab.getTabIndex() >= creativeTabRanges.size()) continue;
ItemStackSet set = creativeTabRanges.get(tab.getTabIndex());
if (set != null && !set.isEmpty())
API.addSubset("CreativeTabs." + I18n.format(tab.getTranslatedTabLabel()), set);
final ItemStackSet itemset = creativeTabRanges.get(tab.getTabIndex());
if (itemset != null && !itemset.isEmpty()) {
API.addSubset("CreativeTabs." + I18n.format(tab.getTranslatedTabLabel()), itemset);
}
}
BrewingRecipeHandler.searchPotions();
@@ -460,7 +404,6 @@ public class ItemInfo {
addEntityEgg(EntityIronGolem.class, 0xC5C2C1, 0xffe1cc);
}
@SuppressWarnings("unchecked")
private static void addEntityEgg(Class<?> entity, int i, int j) {
int id = (Integer) EntityList.classToIDMapping.get(entity);
EntityList.entityEggs.put(id, new EntityEggInfo(id, i, j));
@@ -516,10 +459,8 @@ public class ItemInfo {
return retString;
}
@Deprecated
public static String getSearchName(ItemStack stack) {
return itemSearchNames.computeIfAbsent(
new ItemStackKey(stack),
key -> EnumChatFormatting.getTextWithoutFormattingCodes(
GuiContainerManager.concatenatedDisplayName(key.stack, true).toLowerCase()));
return GuiContainerManager.concatenatedDisplayName(stack, true).toLowerCase();
}
}
@@ -1,20 +1,41 @@
package codechicken.nei.api;
import java.awt.Point;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary;
import org.lwjgl.input.Mouse;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.BookmarkContainerInfo;
import codechicken.nei.FavoriteRecipes;
import codechicken.nei.ItemPanels;
import codechicken.nei.ItemQuantityField;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.SearchField;
import codechicken.nei.bookmark.BookmarkGrid;
import codechicken.nei.bookmark.BookmarkItem;
import codechicken.nei.bookmark.BookmarksGridSlot;
import codechicken.nei.recipe.AutoCraftingManager;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.GuiUsageRecipe;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.RecipeHandlerRef;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.recipe.chain.RecipeChainMath;
import codechicken.nei.util.NEIMouseUtils;
public abstract class ShortcutInputHandler {
@@ -24,22 +45,50 @@ public abstract class ShortcutInputHandler {
return false;
}
if (NEIClientConfig.isKeyHashDown("gui.overlay_hide")) {
return hideOverlayRecipe();
if (NEIClientConfig.isKeyHashDown("gui.overlay") && stackover == null
&& LayoutManager.overlayRenderer != null) {
LayoutManager.overlayRenderer = null;
return true;
}
if (stackover == null) {
final int groupId = ItemPanels.bookmarkPanel.getHoveredGroupId(true);
if (groupId != -1) {
if (NEIClientConfig.isKeyHashDown("gui.remove_recipe")) {
ItemPanels.bookmarkPanel.removeGroup(groupId);
return true;
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark_pull_items")) {
return ItemPanels.bookmarkPanel.pullBookmarkItems(groupId, NEIClientUtils.shiftKey());
}
if (NEIClientConfig.autocraftingEnabled() && ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)
&& NEIClientConfig.isKeyHashDown("gui.craft")) {
AutoCraftingManager
.runProcessing(ItemPanels.bookmarkPanel.getGrid().createRecipeChainMath(groupId));
return true;
}
}
return false;
}
stackover = stackover.copy();
if (NEIClientConfig.isKeyHashDown("gui.overlay")) {
return openOverlayRecipe(stackover, false);
return openOverlayRecipe(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.overlay_use")) {
return openOverlayRecipe(stackover, true);
if (NEIClientConfig.isKeyHashDown("gui.copy_name")) {
return copyItemStackName(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.copy_oredict")) {
return copyItemStackOreDictionary(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.recipe")) {
@@ -51,19 +100,15 @@ public abstract class ShortcutInputHandler {
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark")) {
return saveRecipeInBookmark(stackover, false, false);
return saveRecipeInBookmark(stackover, NEIClientUtils.shiftKey(), NEIClientUtils.controlKey());
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark_recipe")) {
return saveRecipeInBookmark(stackover, true, false);
if (NEIClientConfig.isKeyHashDown("gui.bookmark_pull_items")) {
return pullRecipeItems(stackover, NEIClientUtils.shiftKey());
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark_count")) {
return saveRecipeInBookmark(stackover, false, true);
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark_recipe_count")) {
return saveRecipeInBookmark(stackover, true, true);
if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft")) {
return runAutoCrafting(stackover);
}
return false;
@@ -77,7 +122,6 @@ public abstract class ShortcutInputHandler {
if (stackover != null) {
final int button = Mouse.getEventButton();
stackover = stackover.copy();
if (button == 0) {
return GuiCraftingRecipe.openRecipeGui("item", stackover);
@@ -89,43 +133,329 @@ public abstract class ShortcutInputHandler {
return false;
}
private static boolean hideOverlayRecipe() {
if (LayoutManager.overlayRenderer != null) {
LayoutManager.overlayRenderer = null;
return true;
}
return false;
private static boolean copyItemStackName(ItemStack stackover) {
GuiScreen.setClipboardString(SearchField.getEscapedSearchText(stackover));
return true;
}
private static boolean openOverlayRecipe(ItemStack stack, boolean shift) {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
private static boolean copyItemStackOreDictionary(ItemStack stackover) {
StringBuilder builder = new StringBuilder();
if (gui == null || gui instanceof GuiRecipe) {
return false;
for (int id : OreDictionary.getOreIDs(stackover)) {
String oreDictionaryName = OreDictionary.getOreName(id);
if (!"Unknown".equals(oreDictionaryName)) {
builder.append(oreDictionaryName).append(",");
}
}
return GuiCraftingRecipe.openRecipeGui("item", true, shift, stack);
if (builder.length() > 0) {
builder.deleteCharAt(builder.length() - 1);
}
GuiScreen.setClipboardString(builder.toString());
return true;
}
private static boolean saveRecipeInBookmark(ItemStack stack, boolean saveIngredients, boolean saveStackSize) {
private static boolean runAutoCrafting(ItemStack stackover) {
final RecipeId recipeId = GuiCraftingRecipe.getRecipeId(NEIClientUtils.getGuiContainer(), stackover);
if (stack != null) {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
List<PositionedStack> ingredients = null;
String handlerName = "";
if (recipeId != null) {
final Point mouseover = GuiDraw.getMousePosition();
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
RecipeChainMath math = null;
if (slot == null) {
final Recipe recipe = Recipe.of(recipeId);
if (recipe != null) {
math = RecipeChainMath.of(recipe, 1);
}
} else if (slot.getRecipeId() != null && !slot.isIngredient()) {
if (slot.getGroup().crafting == null) {
final Recipe recipe = Recipe.of(slot.getRecipeId());
if (recipe != null) {
math = RecipeChainMath.of(recipe, slot != null ? slot.getMultiplier() : 1);
}
} else {
math = ItemPanels.bookmarkPanel.getGrid()
.createRecipeChainMath(slot.getGroupId(), slot.getRecipeId());
}
if (gui instanceof GuiRecipe) {
ingredients = ((GuiRecipe<?>) gui).getFocusedRecipeIngredients();
handlerName = ((GuiRecipe<?>) gui).getHandlerName();
stack.stackSize = ((GuiRecipe<?>) gui).prepareFocusedRecipeResultStackSize(stack);
}
ItemPanels.bookmarkPanel.addOrRemoveItem(stack, handlerName, ingredients, saveIngredients, saveStackSize);
return true;
if (math != null) {
AutoCraftingManager.runProcessing(math);
return true;
}
}
return false;
}
private static boolean openOverlayRecipe(ItemStack stackover) {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
final RecipeId recipeId = GuiCraftingRecipe.getRecipeId(gui, stackover);
if (recipeId != null) {
final RecipeHandlerRef handlerRef = RecipeHandlerRef.of(recipeId);
if (handlerRef != null) {
if (NEIClientUtils.shiftKey() && handlerRef.canFillCraftingGrid(gui)) {
int multiplier = 0;
if (NEIClientUtils.controlKey()) {
final Point mouseover = GuiDraw.getMousePosition();
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel
.getSlotMouseOver(mouseover.x, mouseover.y);
multiplier = slot != null ? (int) Math.min(64, slot.getMultiplier()) : 1;
}
handlerRef.fillCraftingGrid(gui, multiplier);
} else if (!NEIClientUtils.shiftKey() && handlerRef.canUseOverlayRenderer(gui)) {
handlerRef.useOverlayRenderer(gui);
}
}
}
return false;
}
private static boolean saveRecipeInBookmark(ItemStack stackover, boolean saveIngredients, boolean saveStackSize) {
final Point mousePos = GuiDraw.getMousePosition();
if (!ItemPanels.bookmarkPanel.removeSlot(mousePos.x, mousePos.y, saveIngredients)) {
final Recipe recipe = getFocusedRecipe(stackover, mousePos.x, mousePos.y, saveIngredients);
if (recipe != null && saveIngredients) {
if (!ItemPanels.bookmarkPanel.removeRecipe(recipe.getRecipeId(), BookmarkGrid.DEFAULT_GROUP_ID)) {
final Recipe singleRecipe = Recipe.of(
Arrays.asList(recipe.getResult(stackover)),
recipe.getHandlerName(),
recipe.getIngredients());
singleRecipe.setCustomRecipeId(recipe.getRecipeId());
ItemPanels.bookmarkPanel.addRecipe(singleRecipe, BookmarkGrid.DEFAULT_GROUP_ID);
}
} else {
final RecipeId recipeId = recipe != null ? recipe.getRecipeId() : null;
final boolean existsRecipe = recipeId != null
&& ItemPanels.bookmarkPanel.existsRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID);
if (!ItemPanels.bookmarkPanel
.removeItem(stackover, existsRecipe ? recipeId : null, BookmarkGrid.DEFAULT_GROUP_ID)) {
saveStackSize = saveStackSize || saveIngredients
|| ItemPanels.bookmarkPanel.existsRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID);
if (!saveStackSize) {
stackover = StackInfo.withAmount(stackover, 0);
} else if (ItemPanels.itemPanel.contains(mousePos.x, mousePos.y)
|| ItemPanels.itemPanel.historyPanel.contains(mousePos.x, mousePos.y)) {
stackover = ItemQuantityField.prepareStackWithQuantity(stackover, 0);
}
ItemPanels.bookmarkPanel
.addItem(stackover, existsRecipe ? recipeId : null, BookmarkGrid.DEFAULT_GROUP_ID);
}
}
}
return true;
}
private static Recipe getFocusedRecipe(ItemStack stackover, int mousex, int mousey, boolean useFavorites) {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
Recipe recipe = null;
if (useFavorites && (ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey))) {
recipe = Recipe.of(FavoriteRecipes.getFavorite(stackover));
if (recipe != null) {
recipe.getIngredients().stream().forEach(ingr -> {
final List<ItemStack> permutations = ingr.getPermutations();
for (int index = 0; index < permutations.size(); index++) {
if (FavoriteRecipes.getFavorite(permutations.get(index)) != null) {
ingr.setActiveIndex(index);
break;
}
}
});
}
} else if (gui instanceof GuiRecipe guiRecipe) {
recipe = guiRecipe.getFocusedRecipe();
}
return recipe;
}
private static boolean pullRecipeItems(ItemStack stackover, boolean shift) {
final Point mousePos = GuiDraw.getMousePosition();
if (ItemPanels.bookmarkPanel.contains(mousePos.x, mousePos.y)) {
stackover = ItemPanels.bookmarkPanel.getStackMouseOverWithQuantity(mousePos.x, mousePos.y);
} else if (ItemPanels.itemPanel.contains(mousePos.x, mousePos.y)) {
stackover = ItemPanels.itemPanel.getStackMouseOverWithQuantity(mousePos.x, mousePos.y);
} else if (ItemPanels.itemPanel.historyPanel.contains(mousePos.x, mousePos.y)) {
stackover = ItemPanels.itemPanel.historyPanel.getStackMouseOverWithQuantity(mousePos.x, mousePos.y);
} else {
stackover = ItemQuantityField.prepareStackWithQuantity(stackover, 0);
}
final RecipeChainMath math = RecipeChainMath
.of(Arrays.asList(BookmarkItem.of(-3, stackover)), Collections.emptySet());
return ItemPanels.bookmarkPanel.pullBookmarkItems(math, shift);
}
public static Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, ItemStack stack) {
final int groupId = ItemPanels.bookmarkPanel.getHoveredGroupId(true);
final Map<String, String> hotkeys = new HashMap<>();
if (groupId != -1) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.remove_recipe"),
NEIClientUtils.translate("bookmark.group.remove_recipe"));
if (BookmarkContainerInfo.getBookmarkContainerHandler(gui) != null) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark_pull_items"),
NEIClientUtils.translate("bookmark.group.pull_items"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark_pull_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.pull_items_shift"));
}
if (NEIClientConfig.autocraftingEnabled() && ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)) {
hotkeys.put(NEIClientConfig.getKeyName("gui.craft"), NEIClientUtils.translate("bookmark.group.craft"));
}
}
if (stack == null) {
return hotkeys;
}
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mousex, mousey);
final RecipeId recipeId = getHotkeyRecipeId(gui, mousex, mousey, stack, slot);
if (slot != null) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate(slot.isIngredient() ? "bookmark.remove_item" : "bookmark.remove_recipe"));
if (slot.isIngredient()) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
}
if (BookmarkContainerInfo.getBookmarkContainerHandler(gui) != null) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark_pull_items"),
NEIClientUtils.translate("bookmark.group.pull_items"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark_pull_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.pull_items_shift"));
}
} else {
hotkeys.put(NEIClientConfig.getKeyName("gui.bookmark"), NEIClientUtils.translate("bookmark.add_item"));
if (StackInfo.getAmount(stack) > 0) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("bookmark.add_item_with_count"));
}
if (recipeId != null) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.add_item_with_recipe"));
}
}
hotkeys.put(NEIClientConfig.getKeyName("gui.recipe"), NEIClientUtils.translate("itempanel.open_crafting"));
hotkeys.put(NEIClientConfig.getKeyName("gui.usage"), NEIClientUtils.translate("itempanel.open_usage"));
hotkeys.put(NEIClientConfig.getKeyName("gui.copy_name"), NEIClientUtils.translate("itempanel.copy_name"));
hotkeys.put(NEIClientConfig.getKeyName("gui.copy_oredict"), NEIClientUtils.translate("itempanel.copy_oredict"));
if (!(gui instanceof GuiRecipe) && NEIClientConfig.canCheatItem(stack)) {
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("itempanel.open_crafting"));
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_RMB),
NEIClientUtils.translate("itempanel.open_usage"));
} else {
hotkeys.put(
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("itempanel.open_crafting"));
hotkeys.put(
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_RMB),
NEIClientUtils.translate("itempanel.open_usage"));
}
if (recipeId != null) {
final RecipeHandlerRef handlerRef = RecipeHandlerRef.of(recipeId);
if (handlerRef != null) {
if (handlerRef.canUseOverlayRenderer(gui)) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.overlay"),
NEIClientUtils.translate("itempanel.overlay_recipe"));
}
if (handlerRef.canFillCraftingGrid(gui)) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.overlay", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("itempanel.fill_crafting_grid"));
if (handlerRef.allowedTransferAlghoritm(gui)) {
hotkeys.put(
NEIClientConfig.getKeyName(
"gui.overlay",
NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("itempanel.fill_crafting_grid_quantity"));
}
}
if (NEIClientConfig.autocraftingEnabled()) {
hotkeys.put(NEIClientConfig.getKeyName("gui.craft"), NEIClientUtils.translate("itempanel.craft"));
}
}
}
return hotkeys;
}
private static RecipeId getHotkeyRecipeId(GuiContainer gui, int mousex, int mousey, ItemStack stack,
BookmarksGridSlot slot) {
if (slot != null) {
return slot.getRecipeId();
} else if (ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey)) {
return FavoriteRecipes.getFavorite(stack);
} else
if (gui instanceof GuiRecipe guiRecipe) {
final Recipe focusedRecipe = guiRecipe.getFocusedRecipe();
if (focusedRecipe != null) {
return focusedRecipe.getRecipeId();
}
}
return null;
}
}
@@ -6,7 +6,14 @@ import static codechicken.lib.asm.InsnComparator.getControlFlowLabels;
import static codechicken.lib.asm.InsnComparator.matches;
import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static org.objectweb.asm.ClassWriter.COMPUTE_MAXS;
import static org.objectweb.asm.Opcodes.*;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ACC_STATIC;
import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ASM5;
import static org.objectweb.asm.Opcodes.ILOAD;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.Opcodes.IRETURN;
import java.util.Map;
@@ -59,16 +66,6 @@ public class NEITransformer implements IClassTransformer {
"func_149689_a",
"(Lnet/minecraft/world/World;IIILnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;)V"),
asmblocks.get("spawnerPlaced")));
// Make MobSpawnerBaseLogic use getSpawnerWorld when creating new entities
transformer.add(
new MethodReplacer(
new ObfMapping(
"net/minecraft/tileentity/MobSpawnerBaseLogic",
"func_98281_h",
"()Lnet/minecraft/entity/Entity;"),
asmblocks.get("d_spawnerWorld"),
asmblocks.get("spawnerWorld")));
}
// Removes trailing seperators from NBTTagList/Compound.toString because OCD
@@ -1,6 +1,22 @@
package codechicken.nei.asm;
import static org.objectweb.asm.Opcodes.*;
import static org.objectweb.asm.Opcodes.ACC_FINAL;
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static org.objectweb.asm.Opcodes.ACC_STATIC;
import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ASTORE;
import static org.objectweb.asm.Opcodes.ATHROW;
import static org.objectweb.asm.Opcodes.CHECKCAST;
import static org.objectweb.asm.Opcodes.DUP;
import static org.objectweb.asm.Opcodes.GETSTATIC;
import static org.objectweb.asm.Opcodes.GOTO;
import static org.objectweb.asm.Opcodes.IFNONNULL;
import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.MONITORENTER;
import static org.objectweb.asm.Opcodes.MONITOREXIT;
import static org.objectweb.asm.Opcodes.NEW;
import static org.objectweb.asm.Opcodes.PUTSTATIC;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,384 @@
package codechicken.nei.bookmark;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.ItemSorter;
import codechicken.nei.bookmark.RecipeChainDetails.BookmarkChainItem;
import codechicken.nei.bookmark.RecipeChainDetails.CalculatedType;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
public class BookmarkGridGenerator {
protected final BookmarkGrid grid;
public List<BookmarksGridSlot> gridMask = null;
public final Map<Integer, Integer> rowToGroupId = new HashMap<>();
public final Map<Integer, RecipeId> itemToRecipe = new HashMap<>();
public final Map<Integer, Integer> slotToItem = new LinkedHashMap<>();
public final Map<Integer, Integer> itemToSlot = new LinkedHashMap<>();
public final Map<Integer, BookmarkChainItem> caclulatedItems = new HashMap<>();
public int pageCount = 0;
public int maxAbsoluteSlotIndex = 0;
public BookmarkGridGenerator(BookmarkGrid grid) {
this.grid = grid;
}
public int getRowGroupId(int rowIndex) {
final int absoluteRowIndex = rowIndex + (this.grid.getPage() - 1) * this.grid.getRows();
return rowToGroupId.getOrDefault(absoluteRowIndex, BookmarkGrid.DEFAULT_GROUP_ID);
}
public void generate() {
BookmarkItem prevBookmarkItem = null;
Map<Integer, String> borderGrid = new HashMap<>();
int gridColumns = this.grid.getColumns();
int size = this.grid.size();
int absoluteSlotIndex = -2;
int itemIndex = 0;
this.pageCount = 0;
this.maxAbsoluteSlotIndex = 0;
this.gridMask = new ArrayList<>();
this.itemToRecipe.clear();
this.caclulatedItems.clear();
this.slotToItem.clear();
this.itemToSlot.clear();
this.rowToGroupId.clear();
if (this.grid.isEmpty() || this.grid.getPerPage() == 0) {
return;
}
while (itemIndex < size && absoluteSlotIndex != -1) {
final BookmarkItem bookmarkItem = this.grid.getBookmarkItem(itemIndex);
final BookmarkGroup group = this.grid.getGroup(bookmarkItem.groupId);
if (group.crafting != null && (!group.crafting.calculatedItems.containsKey(itemIndex)
|| bookmarkItem.recipeId != null && !bookmarkItem.recipeId
.equals(group.crafting.itemToRecipe.getOrDefault(itemIndex, bookmarkItem.recipeId)))) {
itemIndex++;
} else if (group.collapsed) {
final List<Integer> results = getGroupResults(bookmarkItem.groupId, itemIndex, size);
final String groupKey = "group:" + bookmarkItem.groupId;
for (int index = 0; index < results.size(); index++) {
final int collapsedItemIndex = results.get(index);
final BookmarkItem item = this.grid.getBookmarkItem(collapsedItemIndex);
final int nextSlotIndex = nextSlotIndex(
absoluteSlotIndex + 1,
prevBookmarkItem,
item,
BookmarkViewMode.DEFAULT);
if (nextSlotIndex == -1 || index > 0 && (nextSlotIndex % gridColumns) == 0) {
break;
}
prevBookmarkItem = item;
absoluteSlotIndex = nextSlotIndex;
this.slotToItem.put(absoluteSlotIndex, collapsedItemIndex);
this.itemToSlot.put(collapsedItemIndex, absoluteSlotIndex);
this.caclulatedItems.put(collapsedItemIndex, getItem(group, collapsedItemIndex));
borderGrid.put(absoluteSlotIndex, groupKey);
}
while (itemIndex < size && this.grid.getBookmarkItem(itemIndex).groupId == bookmarkItem.groupId) {
itemIndex++;
}
} else if (group.crafting != null && group.viewMode == BookmarkViewMode.DEFAULT) {
final List<Integer> results = getGroupResults(bookmarkItem.groupId, itemIndex, size);
List<Integer> shadows;
for (int index = 0; index < results.size() && absoluteSlotIndex != -1; index++) {
final int collapsedItemIndex = results.get(index);
final BookmarkItem item = this.grid.getBookmarkItem(collapsedItemIndex);
if ((absoluteSlotIndex = nextSlotIndex(
absoluteSlotIndex + 1,
prevBookmarkItem,
item,
BookmarkViewMode.DEFAULT)) != -1) {
prevBookmarkItem = item;
this.slotToItem.put(absoluteSlotIndex, collapsedItemIndex);
this.itemToSlot.put(collapsedItemIndex, absoluteSlotIndex);
this.caclulatedItems.put(collapsedItemIndex, getItem(group, collapsedItemIndex));
if (!(shadows = getShadows(group, item.recipeId)).isEmpty()) {
borderGrid.put(absoluteSlotIndex, "recipe:" + shadows.get(0));
}
}
}
while (itemIndex < size && this.grid.getBookmarkItem(itemIndex).groupId == bookmarkItem.groupId) {
itemIndex++;
}
} else if (group.crafting != null && group.crafting.itemToRecipe.values().contains(bookmarkItem.recipeId)) {
absoluteSlotIndex = generateCollapsedRecipe(prevBookmarkItem, itemIndex, absoluteSlotIndex, borderGrid);
prevBookmarkItem = bookmarkItem;
while (itemIndex < size && bookmarkItem.equalsRecipe(this.grid.getBookmarkItem(itemIndex))) {
itemIndex++;
}
} else if ((absoluteSlotIndex = nextSlotIndex(
absoluteSlotIndex + 1,
prevBookmarkItem,
bookmarkItem,
group.viewMode)) != -1) {
prevBookmarkItem = bookmarkItem;
this.slotToItem.put(absoluteSlotIndex, itemIndex);
this.itemToSlot.put(itemIndex, absoluteSlotIndex);
this.caclulatedItems.put(itemIndex, getItem(group, itemIndex));
itemIndex++;
}
}
this.maxAbsoluteSlotIndex = this.slotToItem.keySet().stream().mapToInt(index -> index).max().orElse(-1) + 1;
generateGroups();
splitGridMask();
calculateGroupBorders(borderGrid);
}
private List<Integer> getGroupResults(int groupId, int itemIndex, int size) {
final BookmarkGroup group = this.grid.getGroup(groupId);
final List<Integer> results = new ArrayList<>();
while (itemIndex < size) {
final BookmarkItem bookmarkItem = this.grid.getBookmarkItem(itemIndex);
if (bookmarkItem == null || bookmarkItem.groupId != groupId) {
break;
}
if (!bookmarkItem.isIngredient
&& (group.crafting == null || group.crafting.calculatedItems.containsKey(itemIndex))) {
results.add(itemIndex);
}
itemIndex++;
}
return results;
}
private int generateCollapsedRecipe(BookmarkItem prevBookmarkItem, int itemIndex, int absoluteSlotIndex,
Map<Integer, String> borderGrid) {
final BookmarkItem bookmarkItem = this.grid.getBookmarkItem(itemIndex);
final BookmarkGroup group = this.grid.getGroup(bookmarkItem.groupId);
final List<Integer> shadows = getShadows(group, bookmarkItem.recipeId);
final String borderId = "recipe:" + shadows.get(0);
shadows.sort(generateSortingComparator(group.crafting.calculatedItems));
for (int shadowIndex : shadows) {
final boolean isIngredient = shadows.get(0) != shadowIndex
|| group.crafting.calculatedItems.get(shadowIndex).calculatedType == CalculatedType.INGREDIENT;
final BookmarkItem shadowBookmarkItem = BookmarkItem.of(
bookmarkItem.groupId,
bookmarkItem.itemStack,
1,
bookmarkItem.recipeId,
isIngredient,
Collections.emptyMap());
if ((absoluteSlotIndex = nextSlotIndex(
absoluteSlotIndex + 1,
prevBookmarkItem,
shadowBookmarkItem,
group.viewMode)) != -1) {
this.slotToItem.put(absoluteSlotIndex, shadowIndex);
this.itemToSlot.put(shadowIndex, absoluteSlotIndex);
this.caclulatedItems.put(shadowIndex, getItem(group, shadowIndex));
this.itemToRecipe.put(shadowIndex, bookmarkItem.recipeId);
borderGrid.put(absoluteSlotIndex, borderId);
prevBookmarkItem = shadowBookmarkItem;
}
}
return absoluteSlotIndex;
}
private List<Integer> getShadows(BookmarkGroup group, RecipeId recipeId) {
return group.crafting.itemToRecipe.entrySet().stream().filter(entry -> recipeId.equals(entry.getValue()))
.map(entry -> entry.getKey()).collect(Collectors.toList());
}
private int nextSlotIndex(int index, BookmarkItem previousMeta, BookmarkItem meta, BookmarkViewMode viewMode) {
int gridColumns = this.grid.getColumns();
int maxIndex = this.grid.getRows() * gridColumns;
int j = 0;
index = Math.max(0, index);
while (j++ < maxIndex) {
boolean isFirstColumn = (index % gridColumns) == 0;
if (this.grid.isInvalidSlot(index % maxIndex)) {
index++;
} else if (!isFirstColumn && (previousMeta == null || previousMeta.groupId != meta.groupId)) {
// new group must start on a new line
index++;
} else if (viewMode == BookmarkViewMode.DEFAULT) {
return index;
} else if (isFirstColumn && (meta.recipeId == null || previousMeta == null
|| previousMeta.groupId != meta.groupId
|| !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++;
}
}
return -1;
}
private void generateGroups() {
int gridColumns = this.grid.getColumns();
int previousGroupId = BookmarkGrid.DEFAULT_GROUP_ID;
for (int absoluteSlotIndex = 0; absoluteSlotIndex < this.maxAbsoluteSlotIndex; absoluteSlotIndex++) {
int absoluteRowIndex = absoluteSlotIndex / gridColumns;
if (this.rowToGroupId.getOrDefault(absoluteRowIndex, BookmarkGrid.DEFAULT_GROUP_ID)
== BookmarkGrid.DEFAULT_GROUP_ID) {
int groupId = BookmarkGrid.DEFAULT_GROUP_ID;
if (this.slotToItem.containsKey(absoluteSlotIndex)) {
groupId = this.caclulatedItems.get(this.slotToItem.get(absoluteSlotIndex)).getItem().groupId;
}
this.rowToGroupId.put(absoluteRowIndex, groupId);
if (groupId != BookmarkGrid.DEFAULT_GROUP_ID && previousGroupId == (previousGroupId = groupId)) {
while ((--absoluteRowIndex) >= 0
&& this.rowToGroupId.get(absoluteRowIndex) == BookmarkGrid.DEFAULT_GROUP_ID) {
this.rowToGroupId.put(absoluteRowIndex, groupId);
}
}
}
}
}
private Comparator<Integer> generateSortingComparator(Map<Integer, BookmarkChainItem> calculatedItems) {
return Comparator.comparingInt((Integer index) -> calculatedItems.get(index).calculatedType.toInt())
.thenComparing(index -> StackInfo.getFluid(calculatedItems.get(index).getItem().itemStack) != null)
.thenComparing(
(i1, i2) -> ItemSorter.instance.compare(
calculatedItems.get(i1).getItem().itemStack,
calculatedItems.get(i2).getItem().itemStack));
}
private void splitGridMask() {
int gridColumns = this.grid.getColumns();
int rows = this.grid.getRows();
int perPage = rows * gridColumns;
this.pageCount = (int) Math.ceil(this.maxAbsoluteSlotIndex / (float) perPage);
int page = Math.max(0, Math.min(this.grid.getPage(), this.pageCount) - 1);
for (int absoluteSlotIndex = page * perPage; absoluteSlotIndex
< Math.min(this.maxAbsoluteSlotIndex, (page + 1) * perPage); absoluteSlotIndex++) {
if (this.slotToItem.get(absoluteSlotIndex) != null) {
this.gridMask
.add(getBookmarkGridSlot(absoluteSlotIndex % perPage, this.slotToItem.get(absoluteSlotIndex)));
}
}
}
private BookmarkChainItem getItem(BookmarkGroup group, int itemIndex) {
if (group.crafting != null) {
return group.crafting.calculatedItems.get(itemIndex);
} else {
BookmarkChainItem item = BookmarkChainItem.of(this.grid.getBookmarkItem(itemIndex));
item.setRealAmount(item.getShiftAmount());
return item;
}
}
private BookmarksGridSlot getBookmarkGridSlot(int slotIndex, int itemIndex) {
final BookmarkChainItem chainItem = this.caclulatedItems.get(itemIndex);
final BookmarkGroup group = this.grid.getGroup(chainItem.getItem().groupId);
if (group.crafting == null) {
return new BookmarksGridSlot(
slotIndex,
itemIndex,
chainItem.getRealAmount(),
0,
0,
chainItem.getItem(),
null,
group);
} else {
return new BookmarksGridSlot(
slotIndex,
itemIndex,
chainItem.getRealAmount(),
chainItem.getShiftAmount(),
chainItem.getCalculatedAmount(),
chainItem.getItem(),
chainItem.calculatedType,
group);
}
}
protected void calculateGroupBorders(Map<Integer, String> borderGrid) {
int gridColumns = this.grid.getColumns();
int page = Math.max(1, Math.min(this.grid.getPage(), this.pageCount)) - 1;
int shiftIndex = page * this.grid.getRows() * gridColumns;
for (BookmarksGridSlot slot : this.gridMask) {
if (borderGrid.get(shiftIndex + slot.slotIndex) == null) {
continue;
}
String groupIndex = borderGrid.get(shiftIndex + slot.slotIndex);
int column = slot.slotIndex % gridColumns;
int row = slot.slotIndex / gridColumns;
int prevSlotIndex = shiftIndex + (row - 1) * gridColumns + column;
int nextSlotIndex = shiftIndex + (row + 1) * gridColumns + column;
BookmarkGroup group = slot.getGroup();
if (group.crafting == null) {
slot.borderColor = BookmarkGrid.GROUP_NONE_COLOR;
} else if (group.collapsed) {
slot.borderColor = BookmarkGrid.GROUP_CHAIN_COLOR;
} else {
slot.borderColor = BookmarkGrid.RECIPE_COLOR;
}
slot.borderLeft = column == 0 || !groupIndex.equals(borderGrid.get(shiftIndex + slot.slotIndex - 1));
slot.borderRight = column + 1 == gridColumns
|| !groupIndex.equals(borderGrid.get(shiftIndex + slot.slotIndex + 1));
slot.borderTop = !groupIndex.equals(borderGrid.get(prevSlotIndex));
slot.borderBottom = !groupIndex.equals(borderGrid.get(nextSlotIndex));
}
}
}
@@ -0,0 +1,58 @@
package codechicken.nei.bookmark;
import java.util.HashSet;
import java.util.Set;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.recipe.Recipe.RecipeId;
public class BookmarkGroup {
public RecipeChainDetails crafting = null;
public BookmarkViewMode viewMode;
public boolean collapsed = false;
public Set<RecipeId> collapsedRecipes = new HashSet<>();
public BookmarkGroup(BookmarkViewMode viewMode) {
this.viewMode = viewMode;
}
public BookmarkGroup(BookmarkViewMode viewMode, boolean crafting) {
this.viewMode = viewMode;
setCraftingMode(crafting);
}
public void toggleViewMode() {
if (this.viewMode == BookmarkViewMode.DEFAULT) {
this.viewMode = BookmarkViewMode.TODO_LIST;
} else {
this.viewMode = BookmarkViewMode.DEFAULT;
}
}
public void setCraftingMode(boolean crafting) {
if ((this.crafting != null) != crafting) {
this.crafting = crafting ? new RecipeChainDetails() : null;
}
}
public void toggleCraftingMode() {
setCraftingMode(this.crafting == null);
}
public void toggleCollapsedState() {
this.collapsed = !this.collapsed;
}
public void toggleCollapsedRecipe(RecipeId recipeId) {
if (this.collapsedRecipes.contains(recipeId)) {
this.collapsedRecipes.remove(recipeId);
} else {
this.collapsedRecipes.add(recipeId);
}
}
public BookmarkGroup copy() {
return new BookmarkGroup(this.viewMode);
}
}
@@ -0,0 +1,191 @@
package codechicken.nei.bookmark;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fluids.FluidStack;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.Recipe.RecipeIngredient;
import codechicken.nei.recipe.StackInfo;
public class BookmarkItem {
public int groupId;
public long amount = 0L;
public final int fluidCellAmount;
public ItemStack itemStack;
public Map<String, ItemStack> permutations;
public long factor;
public RecipeId recipeId;
public boolean isIngredient = false;
protected BookmarkItem(int groupId, long amount, int fluidCellAmount, ItemStack itemStack,
Map<String, ItemStack> permutations, long factor, RecipeId recipeId, boolean isIngredient) {
this.groupId = groupId;
this.amount = amount;
this.fluidCellAmount = fluidCellAmount;
this.itemStack = itemStack;
this.permutations = permutations;
this.factor = factor;
this.recipeId = recipeId;
this.isIngredient = isIngredient;
}
public static BookmarkItem of(int groupId, ItemStack stack, long factor, RecipeId recipeId, boolean isIngredient,
Map<String, ItemStack> permutations) {
final FluidStack fluidStack = StackInfo.getFluid(stack);
int fluidCellAmount = 1;
long amount;
if (fluidStack != null) {
amount = fluidStack.amount * (long) Math.max(0, stack.stackSize);
fluidCellAmount = Math.max(1, StackInfo.isFluidContainer(stack) ? fluidStack.amount : 1);
} else {
amount = StackInfo.getAmount(stack);
}
return new BookmarkItem(
groupId,
amount,
fluidCellAmount,
stack,
permutations,
factor * fluidCellAmount,
recipeId,
isIngredient);
}
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) {
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));
}
public BookmarkItem copyWithAmount(long amount) {
return new BookmarkItem(
this.groupId,
amount,
this.fluidCellAmount,
this.itemStack,
this.permutations,
this.factor,
this.recipeId,
this.isIngredient);
}
public BookmarkItem copy() {
return copyWithAmount(this.amount);
}
public static Map<String, ItemStack> generatePermutations(ItemStack stack, RecipeId recipeId,
boolean isIngredient) {
if (isIngredient && recipeId != null) {
return generatePermutations(stack, Recipe.of(recipeId));
}
return Collections.singletonMap(getItemGUID(stack), stack);
}
public static Map<String, ItemStack> generatePermutations(ItemStack stack, Recipe recipe) {
if (recipe != null) {
final RecipeIngredient ingr = recipe.getIngredients().stream()
.filter(ingredient -> ingredient.contains(stack)).findAny().orElse(null);
if (ingr != null) {
final Map<String, ItemStack> permutations = new HashMap<>();
for (ItemStack ingrStack : ingr.getPermutations()) {
permutations.put(getItemGUID(ingrStack), ingrStack);
}
return permutations;
}
}
return Collections.singletonMap(getItemGUID(stack), stack);
}
private static String getItemGUID(ItemStack stack) {
final FluidStack fluidStack = StackInfo.getFluid(stack);
if (fluidStack != null) {
return fluidStack.getFluid().getName() + ":" + fluidStack.tag;
} else {
return StackInfo.getItemStackGUID(stack);
}
}
public boolean containsItems(BookmarkItem item) {
return this.permutations.keySet().stream().anyMatch(item.permutations::containsKey);
}
public ItemStack getItemStack() {
return getItemStack(this.amount);
}
public ItemStack getItemStack(long amount) {
return StackInfo.withAmount(this.itemStack, getStackSize(amount));
}
public long getStackSize() {
return getStackSize(this.amount);
}
public long getStackSize(long amount) {
return (long) (this.factor > 0 ? Math.ceil(amount / (double) this.fluidCellAmount) : 0);
}
public long getMultiplier() {
return getMultiplier(this.amount);
}
public long getMultiplier(long amount) {
return (long) (this.factor > 0 ? Math.ceil(amount / (double) this.factor) : 0);
}
public long getFactor() {
return this.factor / this.fluidCellAmount;
}
public boolean equalsRecipe(BookmarkItem meta) {
return equalsRecipe(meta.recipeId, meta.groupId);
}
public boolean equalsRecipe(RecipeId recipeId, int groupId) {
return groupId == this.groupId && recipeId != null && recipeId.equals(this.recipeId);
}
@Override
public int hashCode() {
return Objects.hash(this.groupId, this.fluidCellAmount, this.isIngredient, this.recipeId);
}
@Override
public boolean equals(Object object) {
if (object instanceof BookmarkItem item) {
return this.groupId == item.groupId && this.isIngredient == item.isIngredient
&& this.fluidCellAmount == item.fluidCellAmount
&& StackInfo.equalItemAndNBT(this.itemStack, item.itemStack, true)
&& (this.recipeId == item.recipeId || this.recipeId != null && this.recipeId.equals(item.recipeId));
}
return false;
}
}
@@ -0,0 +1,366 @@
package codechicken.nei.bookmark;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
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;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import org.apache.commons.io.IOUtils;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
public class BookmarkStorage {
protected List<BookmarkGrid> namespaces = new ArrayList<>();
protected int activeNamespaceIndex = 0;
protected File bookmarkFile = null;
public BookmarkStorage() {
this.namespaces.add(new BookmarkGrid());
}
public boolean prevNamespace() {
getNamespaceSize();
removeEmptyNamespaces();
if (this.activeNamespaceIndex == 0) {
setNamespace(getNamespaceSize() - 1);
} else {
setNamespace(this.activeNamespaceIndex - 1);
}
return true;
}
public boolean nextNamespace() {
if (removeEmptyNamespaces()) {
return true;
}
if (this.activeNamespaceIndex == getNamespaceSize() - 1) {
setNamespace(0);
} else {
setNamespace(this.activeNamespaceIndex + 1);
}
return true;
}
private void setNamespace(int namespaceIndex) {
this.activeNamespaceIndex = Math.min(namespaceIndex, this.namespaces.size() - 1);
BookmarkGrid grid = this.namespaces.get(this.activeNamespaceIndex);
if (grid.size() == 0 && this.activeNamespaceIndex > 0) {
grid.setViewMode(
BookmarkGrid.DEFAULT_GROUP_ID,
this.namespaces.get(this.activeNamespaceIndex - 1).getViewMode(BookmarkGrid.DEFAULT_GROUP_ID));
}
}
public int getNamespaceSize() {
if (this.namespaces.get(this.namespaces.size() - 1).size() > 0) {
this.namespaces.add(new BookmarkGrid());
} else if (this.activeNamespaceIndex == this.namespaces.size() - 2 && getActiveGrid().size() == 0) {
this.namespaces.remove(this.namespaces.size() - 1);
}
return this.namespaces.size();
}
public boolean isEmpty() {
return this.namespaces.size() <= 1 && getActiveGrid().isEmpty();
}
public int getActiveIndex() {
return this.activeNamespaceIndex;
}
public BookmarkGrid getActiveGrid() {
return this.namespaces.get(this.activeNamespaceIndex);
}
private boolean removeEmptyNamespaces() {
if (this.activeNamespaceIndex != this.namespaces.size() - 1 && getActiveGrid().size() == 0) {
this.namespaces.remove(this.activeNamespaceIndex);
setNamespace(this.activeNamespaceIndex);
return true;
}
return false;
}
public void load(File bookmarkFile) {
if (bookmarkFile.equals(this.bookmarkFile)) {
return;
}
List<String> itemStrings = Collections.emptyList();
if (bookmarkFile.exists()) {
try (FileInputStream reader = new FileInputStream(bookmarkFile)) {
NEIClientConfig.logger.info("Loading bookmarks from file {}", bookmarkFile);
itemStrings = IOUtils.readLines(reader, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load bookmarks from file {}", bookmarkFile, e);
return;
}
}
final JsonParser parser = new JsonParser();
final List<BookmarkGrid> namespaces = new ArrayList<>();
NBTTagCompound navigation = new NBTTagCompound();
namespaces.add(new BookmarkGrid());
BookmarkGrid grid = namespaces.get(0);
if (NEIClientConfig.world.nbt.hasKey("bookmark")) {
navigation = NEIClientConfig.world.nbt.getCompoundTag("bookmark");
}
for (String itemStr : itemStrings) {
try {
if (itemStr.isEmpty()) {
itemStr = "; {}";
}
if (itemStr.startsWith("; ")) {
JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
if (grid.size() > 0) {
// do not create empty namespaces
grid = new BookmarkGrid();
namespaces.add(grid);
}
if (navigation.hasKey("namespacePage." + (namespaces.size() - 1))) {
grid.setPage(navigation.getInteger("namespacePage." + (namespaces.size() - 1)));;
}
if (settings.get("viewmode") != null) {
grid.groups.get(BookmarkGrid.DEFAULT_GROUP_ID).viewMode = BookmarkViewMode
.valueOf(settings.get("viewmode").getAsString());
} else if (settings.get("groups") instanceof JsonObject jsonObject) {
BookmarkGroup group;
for (Map.Entry<String, JsonElement> jsonEntry : jsonObject.entrySet()) {
if (jsonEntry.getValue() instanceof JsonObject value) {
group = new BookmarkGroup(
value.has("viewmode")
? BookmarkViewMode.valueOf(value.get("viewmode").getAsString())
: BookmarkViewMode.DEFAULT,
value.has("crafting") && value.get("crafting").getAsBoolean());
group.collapsed = value.has("collapsed") && value.get("collapsed").getAsBoolean();
if (value.has("collapsedRecipes")) {
for (JsonElement recipeId : value.get("collapsedRecipes").getAsJsonArray()) {
if (recipeId instanceof JsonObject item) {
group.collapsedRecipes.add(RecipeId.of(item));
}
}
}
grid.groups.put(Integer.valueOf(jsonEntry.getKey()), group);
}
}
}
continue;
}
if (!addItemToGrid(grid, parser.parse(itemStr).getAsJsonObject())) {
NEIClientConfig.logger.warn(
"Failed to load bookmarked ItemStack from json string, the item no longer exists:\n{}",
itemStr);
}
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
NEIClientConfig.logger.error("Failed to load bookmarked ItemStack from json string:\n{}", itemStr);
}
}
prepareOldRecipeFormat(namespaces);
for (BookmarkGrid gr : namespaces) {
gr.onItemsChanged();
}
this.namespaces = namespaces;
if (navigation.hasKey("namespaceIndex")) {
setNamespace(navigation.getInteger("namespaceIndex"));
} else {
setNamespace(0);
}
this.bookmarkFile = bookmarkFile;
}
private boolean addItemToGrid(BookmarkGrid grid, JsonObject jsonObject) {
NBTTagCompound itemStackNBT;
if (jsonObject.get("item") != null) {
itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject.get("item"));
} else { // old format
itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject);
}
ItemStack itemStack = StackInfo.loadFromNBT(itemStackNBT);
if (itemStack != null) {
RecipeId recipeId = null;
boolean isFluid = itemStackNBT.hasKey("gtFluidName");
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();
if (jsonObject.get("recipeId") instanceof JsonObject recipeJson) {
recipeId = RecipeId.of(recipeJson);
}
if (!grid.groups.containsKey(groupId)) {
groupId = BookmarkGrid.DEFAULT_GROUP_ID;
}
grid.addItem(BookmarkItem.of(groupId, itemStack, factor, recipeId, isIngredient), 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) {
return;
}
List<String> strings = new ArrayList<>();
NBTTagCompound navigation = new NBTTagCompound();
navigation.setInteger("namespaceIndex", this.activeNamespaceIndex);
for (int grpIdx = 0; grpIdx < namespaces.size(); grpIdx++) {
BookmarkGrid grid = namespaces.get(grpIdx);
JsonObject settings = new JsonObject();
JsonObject groups = new JsonObject();
for (int groupId : grid.groups.keySet()) {
BookmarkGroup group = grid.groups.get(groupId);
JsonObject groupJson = new JsonObject();
groupJson.add("viewmode", new JsonPrimitive(group.viewMode.toString()));
groupJson.add("crafting", new JsonPrimitive(group.crafting != null));
groupJson.add("collapsed", new JsonPrimitive(group.collapsed));
if (!group.collapsedRecipes.isEmpty()) {
JsonArray collapsedRecipes = new JsonArray();
for (RecipeId recipeId : group.collapsedRecipes) {
collapsedRecipes.add(recipeId.toJsonObject());
}
groupJson.add("collapsedRecipes", collapsedRecipes);
}
groups.add(String.valueOf(groupId), groupJson);
}
settings.add("groups", groups);
strings.add("; " + NBTJson.toJson(settings));
navigation.setInteger("namespacePage." + grpIdx, grid.getPage() - 1);
for (BookmarkItem item : grid.bookmarkItems) {
try {
JsonObject row = new JsonObject();
row.add("item", NBTJson.toJsonObject(StackInfo.itemStackToNBT(item.getItemStack())));
row.add("factor", new JsonPrimitive(item.getFactor()));
row.add("ingredient", new JsonPrimitive(item.isIngredient));
if (item.groupId != BookmarkGrid.DEFAULT_GROUP_ID) {
row.add("groupId", new JsonPrimitive(item.groupId));
}
if (item.recipeId != null) {
row.add("recipeId", item.recipeId.toJsonObject());
}
strings.add(NBTJson.toJson(row));
} catch (JsonSyntaxException e) {
NEIClientConfig.logger.error("Failed to stringify bookmarked ItemStack to json string");
}
}
}
try (FileOutputStream output = new FileOutputStream(bookmarkFile)) {
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
NEIClientConfig.world.nbt.setTag("bookmark", navigation);
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save bookmarks list to file {}", bookmarkFile, e);
}
}
}
@@ -0,0 +1,322 @@
package codechicken.nei.bookmark;
import java.awt.Color;
import net.minecraft.item.ItemStack;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.ItemPanels;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.ItemsGrid.MouseContext;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIClientUtils.Alignment;
import codechicken.nei.bookmark.BookmarkGrid.BookmarkMouseContext;
import codechicken.nei.bookmark.RecipeChainDetails.CalculatedType;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.ReadableNumberConverter;
public class BookmarksGridSlot extends ItemsGridSlot {
protected enum ShownItemType {
REAL,
SHIFT,
CALCULATED
}
protected static final float LINE_WIDTH = 0.75f;
protected static final Color INGREDIENTS_COLOR = new Color(0x6645DA75, true);
protected static final Color RESULTS_COLOR = new Color(0x9966CCFF, true);
protected static final Color RESULTS_BG_COLOR = new Color(0x3366CCFF, true);
protected static final Color RESULTS_BG_FLUID_COLOR = new Color(0x5566CCFF, true);
protected static final Color REMAINDER_COLOR = new Color(0x55A033A0, true);
protected static final Color REMAINDER_BG_COLOR = new Color(0x33A033A0, true);
protected static final Color REMAINDER_BG_FLUID_COLOR = new Color(0x44A033A0, true);
protected final ItemStack emptyItemStack;
protected final long realAmount;
protected final long shiftAmount;
protected final long calculatedAmount;
protected final long realMultiplier;
protected final long calculatedMultiplier;
protected final BookmarkGroup group;
protected final boolean isFluidDisplay;
protected final CalculatedType calculatedType;
protected final CalculatedType realType;
protected final BookmarkItem bookmarkItem;
protected final boolean isOutputRecipe;
protected final boolean isFirstOutput;
protected final int rowIndex;
public BookmarksGridSlot(int slotIndex, int itemIndex, long realAmount, long shiftAmount, long calculatedAmount,
BookmarkItem bookmarkItem, CalculatedType calculatedType, BookmarkGroup group) {
super(
slotIndex,
itemIndex,
calculatedType != null ? bookmarkItem.getItemStack(calculatedAmount)
: bookmarkItem.getItemStack(realAmount));
this.emptyItemStack = bookmarkItem.getItemStack(0);
this.realAmount = realAmount;
this.shiftAmount = shiftAmount;
this.calculatedAmount = calculatedAmount;
this.group = group;
this.calculatedType = calculatedType;
this.bookmarkItem = bookmarkItem;
this.isOutputRecipe = group.crafting != null && group.crafting.outputRecipes.contains(bookmarkItem.recipeId);
this.isFluidDisplay = StackInfo.itemStackToNBT(bookmarkItem.itemStack).hasKey("gtFluidName");
this.realMultiplier = bookmarkItem.getMultiplier(realAmount);
this.calculatedMultiplier = bookmarkItem.getMultiplier(calculatedAmount);
if (this.group.crafting != null && this.group.crafting.calculatedItems.containsKey(this.itemIndex)) {
this.realType = this.group.crafting.calculatedItems.get(this.itemIndex).calculatedType
== CalculatedType.INGREDIENT ? CalculatedType.INGREDIENT : CalculatedType.RESULT;
} else {
this.realType = this.bookmarkItem.isIngredient
|| this.group.crafting != null && this.bookmarkItem.recipeId == null ? CalculatedType.INGREDIENT
: CalculatedType.RESULT;
}
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.slotIndex % grid.getColumns()) == 0 || group.viewMode == BookmarkViewMode.DEFAULT)
&& (prevItem == null || prevItem.isIngredient || !this.bookmarkItem.equalsRecipe(prevItem));
this.rowIndex = this.slotIndex / grid.getColumns();
}
public long getMultiplier() {
return this.calculatedType != null ? this.calculatedMultiplier : this.realMultiplier;
}
public BookmarkItem getBookmarkItem() {
return this.bookmarkItem;
}
public RecipeId getRecipeId() {
return this.bookmarkItem.recipeId;
}
public boolean isIngredient() {
return this.bookmarkItem.isIngredient;
}
public BookmarkGroup getGroup() {
return this.group;
}
public int getGroupId() {
return this.bookmarkItem.groupId;
}
protected ShownItemType getShownItemType(BookmarkMouseContext mouseContext) {
if (mouseContext != null) {
if (this.showShiftItem(mouseContext)) {
return ShownItemType.SHIFT;
} else if (this.showRealItem(mouseContext)) {
return ShownItemType.REAL;
}
}
if (this.calculatedType != null) {
return ShownItemType.CALCULATED;
}
return null;
}
protected boolean showShiftItem(BookmarkMouseContext mouseContext) {
if (!mouseContext.shiftKey || this.bookmarkItem.groupId != mouseContext.groupId) {
return false;
}
if (this.group.crafting != null) {
return true;
}
return this.bookmarkItem.equalsRecipe(mouseContext.recipeId, mouseContext.groupId);
}
protected boolean showRealItem(BookmarkMouseContext mouseContext) {
if (!mouseContext.controlKey || this.bookmarkItem.groupId != mouseContext.groupId) {
return false;
}
if (this.slotIndex == mouseContext.slotIndex || this.group.collapsed) {
return true;
}
if (mouseContext.recipeId == null && this.group.viewMode == BookmarkViewMode.TODO_LIST
&& mouseContext.rowIndex == this.rowIndex) {
return true;
}
if (this.bookmarkItem.equalsRecipe(mouseContext.recipeId, mouseContext.groupId)) {
return true;
}
return this.group.crafting != null && mouseContext.recipeId != null
&& mouseContext.recipeId.equals(this.group.crafting.itemToRecipe.get(this.itemIndex));
}
@Override
public void drawItem(Rectangle4i rect) {
super.drawItem(this.emptyItemStack, rect);
}
@Override
public <M extends MouseContext> void beforeDraw(Rectangle4i rect, M mouseContext) {
final ShownItemType shownItemType = getShownItemType((BookmarkMouseContext) mouseContext);
boolean showMarker = NEIClientConfig.showRecipeMarkerMode() == 2;
CalculatedType calculatedType = null;
if (shownItemType == ShownItemType.REAL) {
calculatedType = this.realType;
} else if (shownItemType == ShownItemType.SHIFT) {
if (this.calculatedType != null) {
calculatedType = this.shiftAmount > 0 ? this.calculatedType : null;
showMarker = false;
} else if (group.crafting == null) {
calculatedType = this.realType;
}
}
if (!this.bookmarkItem.isIngredient && this.bookmarkItem.recipeId != null
&& calculatedType == null
&& showMarker
&& (mouseContext == null || mouseContext.slotIndex != this.slotIndex)) {
drawMerkerBackground(rect);
}
if (calculatedType == null || !drawBackground(rect, calculatedType)) {
super.beforeDraw(rect, mouseContext);
}
}
protected boolean drawBackground(Rectangle4i rect, CalculatedType calculatedType) {
switch (calculatedType) {
case INGREDIENT:
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, INGREDIENTS_COLOR);
break;
case RESULT:
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, RESULTS_COLOR);
break;
case REMAINDER:
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, REMAINDER_COLOR);
break;
default:
return false;
}
return true;
}
protected void drawMerkerBackground(Rectangle4i rect) {
Color color = this.isFluidDisplay ? RESULTS_BG_FLUID_COLOR : RESULTS_BG_COLOR;
if (this.shiftAmount > 0 && this.calculatedType == CalculatedType.REMAINDER) {
color = this.isFluidDisplay ? REMAINDER_BG_FLUID_COLOR : REMAINDER_BG_COLOR;
}
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, color);
}
@Override
public <M extends MouseContext> void afterDraw(Rectangle4i rect, M mouseContext) {
final ShownItemType shownItemType = getShownItemType((BookmarkMouseContext) mouseContext);
drawStackSize(rect, shownItemType);
if (this.bookmarkItem.isIngredient || this.bookmarkItem.recipeId == null) {
return;
}
if (this.isFirstOutput) {
if (shownItemType == ShownItemType.REAL) {
drawMarker(
rect,
"x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(this.realMultiplier),
0xFFFFFF);
} else if (shownItemType == ShownItemType.SHIFT) {
drawMarker(rect, "x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(getMultiplier()), 0xFFFFFF);
} else if (this.isOutputRecipe || this.realMultiplier > 1) {
drawMarker(
rect,
"x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(this.realMultiplier),
NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue());
} else if (NEIClientConfig.showRecipeMarkerMode() == 1) {
drawMarker(
rect,
"R",
NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue());
}
} else if (NEIClientConfig.showRecipeMarkerMode() == 1) {
drawMarker(rect, "R", NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue());
}
}
protected void drawMarker(Rectangle4i rect, String text, int color) {
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
NEIClientUtils.drawNEIOverlayText(
text,
new Rectangle4i(rect.x + 1, rect.y + 1, rect.w - 2, rect.h - 2),
panelFactor,
color,
true,
Alignment.TopLeft);
}
protected void drawStackSize(Rectangle4i rect, ShownItemType shownItemType) {
long amount = this.calculatedAmount;
if (shownItemType == null || shownItemType == ShownItemType.REAL || this.calculatedType == null) {
amount = this.realAmount;
} else if (shownItemType == ShownItemType.SHIFT) {
amount = this.shiftAmount;
}
if (amount > 0 || shownItemType == ShownItemType.REAL && this.bookmarkItem.factor > 0) {
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
final long stackSize = this.bookmarkItem.getStackSize(amount);
String amountString = "";
if (stackSize < 10_000) {
amountString = String.valueOf(stackSize);
} else {
amountString = ReadableNumberConverter.INSTANCE.toWideReadableForm(stackSize);
}
if (this.isFluidDisplay) {
amountString += "L";
}
NEIClientUtils.drawNEIOverlayText(
amountString,
new Rectangle4i(rect.x + 1, rect.y + 1, rect.w - 2, rect.h - 2),
panelFactor,
0xFFFFFF,
true,
this.isFluidDisplay ? Alignment.BottomLeft : Alignment.BottomRight);
}
}
}
@@ -0,0 +1,190 @@
package codechicken.nei.bookmark;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.recipe.Recipe.RecipeId;
public class GroupingItem {
public static class PointEntry {
public int cursorRowIndex;
public int topRowIndex;
public int bottomRowIndex;
public PointEntry(int clickSlotIndex, int topSlotIndex, int bottomSlotIndex) {
this.cursorRowIndex = clickSlotIndex;
this.topRowIndex = topSlotIndex;
this.bottomRowIndex = bottomSlotIndex;
}
}
public BookmarkGrid grid;
public int groupId = -1;
public PointEntry startPoint;
public PointEntry endPoint;
public GroupingItem(BookmarkGrid grid, int groupId, int overRowIndex) {
this.groupId = groupId;
this.grid = grid;
setStartPoint(overRowIndex);
}
public void setStartPoint(int overRowIndex) {
if (this.grid.getRowItemIndex(overRowIndex, true) != Integer.MIN_VALUE) {
this.startPoint = new PointEntry(
overRowIndex + getRowShift(),
getTopRowIndex(overRowIndex),
getBottomRowIndex(overRowIndex));
} else {
this.startPoint = new PointEntry(overRowIndex + getRowShift(), -1, -1);
}
}
public void setEndPoint(int overRowIndex) {
if (this.grid.getRowItemIndex(overRowIndex, true) != Integer.MIN_VALUE) {
this.endPoint = new PointEntry(
overRowIndex + getRowShift(),
getTopRowIndex(overRowIndex),
getBottomRowIndex(overRowIndex));
}
}
public int getStartSlotIndex() {
return this.startPoint.cursorRowIndex - getRowShift();
}
public int getEndSlotIndex() {
return this.endPoint != null ? this.endPoint.cursorRowIndex - getRowShift() : 0;
}
public boolean hasEndRow() {
return this.endPoint != null;
}
private int getRowShift() {
return (this.grid.getPage() - 1) * this.grid.getRows();
}
public Map<Integer, Integer> prepareGroups(Map<Integer, Integer> groups) {
final int topRowIndex = Math.min(this.startPoint.topRowIndex, this.endPoint.topRowIndex);
final int bottomRowIndex = Math.max(this.startPoint.bottomRowIndex, this.endPoint.bottomRowIndex);
groups = new HashMap<>(groups);
if (this.groupId != BookmarkGrid.DEFAULT_GROUP_ID) {
if (this.startPoint.cursorRowIndex > this.endPoint.cursorRowIndex) {
int rowIndex = this.endPoint.topRowIndex - 1;
while (groups.containsKey(rowIndex) && groups.get(rowIndex) == this.groupId) {
groups.put(rowIndex--, BookmarkGrid.DEFAULT_GROUP_ID);
}
} else if (this.startPoint.cursorRowIndex < this.endPoint.cursorRowIndex) {
int rowIndex = this.endPoint.bottomRowIndex + 1;
while (groups.containsKey(rowIndex) && groups.get(rowIndex) == this.groupId) {
groups.put(rowIndex++, BookmarkGrid.DEFAULT_GROUP_ID);
}
}
} else if (groups.containsKey(topRowIndex - 1)
&& groups.get(topRowIndex - 1).equals(groups.get(bottomRowIndex + 1))) {
int groupId = groups.get(bottomRowIndex);
int rowIndex = bottomRowIndex + 1;
while (groups.containsKey(rowIndex) && groups.get(rowIndex) == groupId) {
groups.put(rowIndex, -1 * groups.get(rowIndex));
rowIndex++;
}
}
for (int rowIndex = topRowIndex; rowIndex <= bottomRowIndex && groups.containsKey(rowIndex); rowIndex++) {
groups.put(rowIndex, this.groupId);
}
return groups;
}
protected int getTopRowIndex(int overRowIndex) {
final int rowShift = getRowShift();
int itemIndex = this.grid.getRowItemIndex(overRowIndex, true);
if (itemIndex == Integer.MIN_VALUE) {
return -1;
}
final BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
if (item.recipeId != null) {
final List<Integer> sortedItems = this.grid.getSortedItems();
final BookmarkGroup group = this.grid.getGroup(item.groupId);
final boolean isCollapsedGroup = group.collapsed
|| group.crafting != null && group.viewMode == BookmarkViewMode.DEFAULT;
final RecipeId recipeId = group.crafting != null
? group.crafting.itemToRecipe.getOrDefault(itemIndex, item.recipeId)
: item.recipeId;
final Set<RecipeId> recipeRelations = group.crafting != null
? group.crafting.recipeRelations.getOrDefault(recipeId, Collections.singleton(recipeId))
: Collections.singleton(recipeId);
for (Integer rItemIndex : sortedItems) {
final BookmarkItem rItem = this.grid.getCalculatedItem(rItemIndex);
if (rItem.groupId == item.groupId && (isCollapsedGroup || recipeRelations.contains(rItem.recipeId))) {
return this.grid.getAbsoluteSlotIndex(rItemIndex) / this.grid.getColumns();
}
}
return -1;
}
return rowShift + overRowIndex;
}
protected int getBottomRowIndex(int overRowIndex) {
final int rowShift = getRowShift();
final int itemIndex = this.grid.getRowItemIndex(overRowIndex, false);
if (itemIndex == Integer.MIN_VALUE) {
return -1;
}
final BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
if (item.recipeId != null) {
final List<Integer> sortedItems = this.grid.getSortedItems();
final BookmarkGroup group = this.grid.getGroup(item.groupId);
final boolean isCollapsedGroup = group.collapsed
|| group.crafting != null && group.viewMode == BookmarkViewMode.DEFAULT;
final RecipeId recipeId = group.crafting != null
? group.crafting.itemToRecipe.getOrDefault(itemIndex, item.recipeId)
: item.recipeId;
final Set<RecipeId> recipeRelations = group.crafting != null
? group.crafting.recipeRelations.getOrDefault(recipeId, Collections.singleton(recipeId))
: Collections.singleton(recipeId);
for (int index = sortedItems.size() - 1; index >= 0; index--) {
final int rItemIndex = sortedItems.get(index);
final BookmarkItem rItem = this.grid.getCalculatedItem(rItemIndex);
if (rItem.groupId == item.groupId && (isCollapsedGroup || recipeRelations.contains(rItem.recipeId))) {
return this.grid.getAbsoluteSlotIndex(rItemIndex) / this.grid.getColumns();
}
}
return -1;
}
return rowShift + overRowIndex;
}
}
@@ -0,0 +1,374 @@
package codechicken.nei.bookmark;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import net.minecraft.item.ItemStack;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.recipe.chain.RecipeChainMath;
public class RecipeChainDetails {
public enum CalculatedType {
INGREDIENT,
RESULT,
REMAINDER;
public int toInt() {
switch (this) {
case RESULT:
return 0;
case REMAINDER:
return 1;
case INGREDIENT:
return 2;
}
return -1;
}
}
public static class BookmarkChainItem {
private final BookmarkItem item;
private long realAmount = 0L;
private long shiftAmount = 0L;
private long calculatedAmount = 0L;
public CalculatedType calculatedType;
protected BookmarkChainItem(BookmarkItem item, long shiftItem, long calculatedItem,
CalculatedType calculatedType) {
this.item = item.copy();
this.shiftAmount = shiftItem;
this.calculatedAmount = calculatedItem;
this.calculatedType = calculatedType;
}
public static BookmarkChainItem of(BookmarkItem item, long shiftItem, long calculatedAmount,
CalculatedType calculatedType) {
return new BookmarkChainItem(item, shiftItem, calculatedAmount, calculatedType);
}
public static BookmarkChainItem of(BookmarkItem item, long shiftItem, CalculatedType calculatedType) {
return new BookmarkChainItem(item, shiftItem, item.amount, calculatedType);
}
public static BookmarkChainItem of(BookmarkItem item) {
return new BookmarkChainItem(
item,
item.amount,
item.amount,
item.isIngredient ? CalculatedType.INGREDIENT : CalculatedType.RESULT);
}
public ItemStack getItemStack(long amount) {
return this.item.getItemStack(amount);
}
public void setRealAmount(long amount) {
this.realAmount = amount;
}
public long getRealAmount() {
return this.realAmount;
}
public long getShiftAmount() {
return this.shiftAmount;
}
public long getCalculatedAmount() {
return this.calculatedAmount;
}
public BookmarkItem getItem() {
return this.item;
}
public void append(long amount, long calculatedAmount) {
this.shiftAmount += amount;
this.calculatedAmount += calculatedAmount;
this.item.amount = this.calculatedAmount;
}
}
public final Map<Integer, BookmarkChainItem> calculatedItems = new HashMap<>();
public final Map<Integer, RecipeId> itemToRecipe = new HashMap<>();
public final Set<RecipeId> outputRecipes = new HashSet<>();
public final Set<RecipeId> recipeInMiddle = new HashSet<>();
public final Map<RecipeId, Set<RecipeId>> recipeRelations = new HashMap<>();
public void refresh(Map<Integer, BookmarkItem> chainItems, Set<RecipeId> collapsedRecipes) {
final Map<BookmarkItem, Integer> sortingChainItems = new HashMap<>();
for (Map.Entry<Integer, BookmarkItem> entry : chainItems.entrySet()) {
sortingChainItems.put(entry.getValue(), entry.getKey());
}
this.itemToRecipe.clear();
this.outputRecipes.clear();
this.recipeInMiddle.clear();
this.calculatedItems.clear();
this.recipeRelations.clear();
final RecipeChainMath math = RecipeChainMath.of(new ArrayList<>(chainItems.values()), collapsedRecipes)
.refresh();
this.outputRecipes.addAll(math.outputRecipes.keySet());
for (BookmarkItem item : math.preferredItems.values()) {
if (item != null && item.recipeId != null) {
this.recipeInMiddle.add(item.recipeId);
}
}
for (BookmarkItem item : math.initialItems) {
this.calculatedItems.put(
sortingChainItems.get(item),
BookmarkChainItem.of(item, math.requiredAmount.getOrDefault(item, 0L), CalculatedType.INGREDIENT));
}
if (collapsedRecipes.isEmpty()) {
for (BookmarkItem item : math.recipeResults) {
generateResult(math, item, sortingChainItems.get(item));
}
for (BookmarkItem item : math.recipeIngredients) {
generateIngredient(math, item, sortingChainItems.get(item));
}
} else {
final Set<RecipeId> topLevelRecipes = findTopLevelRecipes(math, collapsedRecipes);
for (RecipeId recipeId : collapsedRecipes) {
this.recipeRelations.put(
recipeId,
getRecipeRelations(math, recipeId, topLevelRecipes, new HashSet<>(Arrays.asList(recipeId))));
generateCollapsedRecipe(math, recipeId, topLevelRecipes, sortingChainItems);
generateShadowItems(recipeId, chainItems.values(), sortingChainItems);
}
for (BookmarkItem item : math.recipeResults) {
if (!collapsedRecipes.contains(item.recipeId) && topLevelRecipes.contains(item.recipeId)) {
generateResult(math, item, sortingChainItems.get(item));
}
}
for (BookmarkItem item : math.recipeIngredients) {
if (!collapsedRecipes.contains(item.recipeId) && topLevelRecipes.contains(item.recipeId)) {
generateIngredient(math, item, sortingChainItems.get(item));
}
}
}
for (Map.Entry<Integer, BookmarkItem> entry : chainItems.entrySet()) {
final int itemIndex = entry.getKey();
if (itemIndex >= 0 && this.calculatedItems.containsKey(itemIndex)) {
final BookmarkItem item = entry.getValue();
if (this.recipeInMiddle.contains(item.recipeId)) {
this.calculatedItems.get(itemIndex).setRealAmount(item.amount);
} else {
this.calculatedItems.get(itemIndex).setRealAmount(Math.max(item.factor, item.amount));
}
}
}
}
private Set<RecipeId> getRecipeRelations(RecipeChainMath math, RecipeId recipeId, Set<RecipeId> topLevelRecipes,
Set<RecipeId> recipes) {
for (BookmarkItem item : math.recipeIngredients) {
if (item.recipeId.equals(recipeId)) {
final BookmarkItem prefItem = math.preferredItems.get(item);
if (prefItem != null && !topLevelRecipes.contains(prefItem.recipeId)
&& recipes.add(prefItem.recipeId)) {
getRecipeRelations(math, prefItem.recipeId, topLevelRecipes, recipes);
}
}
}
return recipes;
}
private void generateCollapsedRecipe(RecipeChainMath math, RecipeId recipeId, Set<RecipeId> topLevelRecipes,
Map<BookmarkItem, Integer> sortingChainItems) {
final List<BookmarkChainItem> items = collectItems(
math,
recipeId,
this.recipeRelations.get(recipeId),
topLevelRecipes);
for (BookmarkChainItem value : items) {
int itemIndex = sortingChainItems.get(value.getItem());
if (value.getItem().isIngredient || !recipeId.equals(value.getItem().recipeId)) {
itemIndex *= -1;
}
if (!value.getItem().isIngredient && !math.outputRecipes.containsKey(value.getItem().recipeId)) {
value.calculatedType = CalculatedType.REMAINDER;
}
this.itemToRecipe.put(itemIndex, recipeId);
this.calculatedItems.put(itemIndex, value);
}
}
private void generateShadowItems(RecipeId recipeId, Iterable<BookmarkItem> chainItems,
Map<BookmarkItem, Integer> sortingChainItems) {
final Set<RecipeId> recipeRelations = this.recipeRelations.get(recipeId);
final List<BookmarkItem> subChainItems = new ArrayList<>();
for (BookmarkItem item : chainItems) {
if (recipeRelations.contains(item.recipeId)) {
subChainItems.add(item.copyWithAmount(recipeId.equals(item.recipeId) ? item.amount : 0));
}
}
final RecipeChainMath math = RecipeChainMath.of(subChainItems, Collections.emptySet()).refresh();
final List<BookmarkChainItem> items = collectItems(
math,
recipeId,
this.recipeRelations.get(recipeId),
Collections.emptySet());
for (BookmarkChainItem value : items) {
int itemIndex = sortingChainItems.get(value.getItem());
if (value.getItem().isIngredient || !recipeId.equals(value.getItem().recipeId)) {
itemIndex *= -1;
}
if (this.calculatedItems.containsKey(itemIndex)) {
this.calculatedItems.get(itemIndex).setRealAmount(value.getShiftAmount());
}
}
}
private List<BookmarkChainItem> collectItems(RecipeChainMath math, RecipeId recipeId, Set<RecipeId> recipeRelations,
Set<RecipeId> topLevelRecipes) {
final Map<String, BookmarkChainItem> items = new HashMap<>();
final Map<RecipeId, Long> multiplier = new HashMap<>();
for (RecipeId relRecipeId : recipeRelations) {
for (BookmarkItem item : math.recipeResults) {
if (item.recipeId.equals(relRecipeId)) {
final long amount = item.amount - math.requiredAmount.getOrDefault(item, 0L);
if (item.recipeId.equals(recipeId)) {
multiplier.put(item.recipeId, item.getMultiplier());
items.computeIfAbsent(
StackInfo.getItemStackGUID(item.itemStack),
is -> BookmarkChainItem.of(item, 0, 0, CalculatedType.RESULT))
.append(amount, item.amount);
} else if (amount > 0) {
items.computeIfAbsent(
StackInfo.getItemStackGUID(item.itemStack),
is -> BookmarkChainItem.of(item, 0, 0, CalculatedType.RESULT)).append(amount, amount);
}
}
}
for (BookmarkItem item : math.recipeIngredients) {
if (item.recipeId.equals(relRecipeId)) {
final BookmarkItem prefItem = math.preferredItems.get(item);
final long amount = math.requiredAmount.containsKey(prefItem) ? 0
: math.requiredAmount.getOrDefault(item, item.amount);
final long refAmount = prefItem != null && !topLevelRecipes.contains(prefItem.recipeId)
? math.requiredAmount.getOrDefault(prefItem, 0L)
: 0;
if (amount != 0 || item.amount > refAmount && math.requiredAmount.containsKey(prefItem)
|| recipeId.equals(item.recipeId) && multiplier.get(recipeId) == 0) {
items.computeIfAbsent(
StackInfo.getItemStackGUID(item.itemStack),
is -> BookmarkChainItem.of(item, 0, 0, CalculatedType.INGREDIENT))
.append(amount, item.amount - refAmount);
}
}
}
}
return new ArrayList<>(items.values());
}
private void generateResult(RecipeChainMath math, BookmarkItem item, int itemIndex) {
final long amount = item.amount - math.requiredAmount.getOrDefault(item, 0L);
final CalculatedType calculatedType = math.outputRecipes.containsKey(item.recipeId) ? CalculatedType.RESULT
: CalculatedType.REMAINDER;
this.calculatedItems.put(itemIndex, BookmarkChainItem.of(item, amount, calculatedType));
}
private void generateIngredient(RecipeChainMath math, BookmarkItem item, int itemIndex) {
final BookmarkItem prefItem = math.preferredItems.get(item);
final long amount = math.requiredAmount.containsKey(prefItem) ? 0
: math.requiredAmount.getOrDefault(item, item.amount);
this.calculatedItems.put(itemIndex, BookmarkChainItem.of(item, amount, CalculatedType.INGREDIENT));
}
private Set<RecipeId> findTopLevelRecipes(RecipeChainMath math, Set<RecipeId> collapsedRecipes) {
final Set<RecipeId> result = new HashSet<>(math.outputRecipes.keySet());
for (BookmarkItem item : math.recipeResults) {
if (!result.contains(item.recipeId)) {
final Set<RecipeId> parents = getRecipeParents(
math,
item.recipeId,
new HashSet<>(),
new HashSet<>(Arrays.asList(item.recipeId)));
if (parents.size() != 1 || parents.stream().noneMatch(collapsedRecipes::contains)) {
result.add(item.recipeId);
}
}
}
return result;
}
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))
.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);
}
}
}
return parents;
}
}
@@ -0,0 +1,83 @@
package codechicken.nei.bookmark;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import org.lwjgl.opengl.GL11;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.guihook.GuiContainerManager;
public class SortableGroup {
public int groupId;
public BookmarkGrid grid;
public int shiftX = 0;
public int shiftY = 0;
public SortableGroup(BookmarkGrid grid, int groupId) {
this.grid = grid;
this.groupId = groupId;
}
public void postDraw(int mousex, int mousey) {
Point startRect = null;
GuiContainerManager.drawItems.zLevel += 100;
for (BookmarksGridSlot slot : this.grid.getMask()) {
if (slot.getGroupId() == this.groupId) {
final Rectangle4i rect = this.grid.getSlotRect(slot.slotIndex);
if (startRect == null) {
startRect = new Point(rect.x - this.shiftX, rect.y - this.shiftY);
}
GuiContainerManager.drawItem(
mousex + rect.x - startRect.x + 1,
mousey + rect.y - startRect.y + 1,
slot.getItemStack(),
true,
"");
}
}
if (startRect != null) {
int startRowIndex = -1;
int endRowIndex = 0;
for (int rowIndex = 0; rowIndex < this.grid.getRows(); rowIndex++) {
if (this.grid.getRowGroupId(rowIndex) == this.groupId) {
if (startRowIndex == -1) {
startRowIndex = rowIndex;
}
endRowIndex = rowIndex;
}
}
GL11.glPushMatrix();
GL11.glTranslated(mousex - startRect.x, mousey - startRect.y, 0);
this.grid.drawGroup(this.groupId, startRowIndex, endRowIndex);
GL11.glPopMatrix();
}
GuiContainerManager.drawItems.zLevel -= 100;
}
public List<BookmarkItem> getBookmarkItems() {
final List<BookmarkItem> items = new ArrayList<>();
for (BookmarkItem item : this.grid.bookmarkItems) {
if (item.groupId == this.groupId) {
items.add(item);
}
}
return items;
}
}
@@ -0,0 +1,250 @@
package codechicken.nei.bookmark;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.ItemsGrid;
import codechicken.nei.bookmark.RecipeChainDetails.BookmarkChainItem;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.Recipe.RecipeId;
public class SortableItem {
public final BookmarkGrid grid;
public final BookmarkItem bookmarkItem;
public final boolean moveRecipe;
public final boolean crossGroup;
public final boolean isCollapsedRecipe;
public List<Integer> items = new ArrayList<>();
public int shiftX = -8;
public int shiftY = -8;
public SortableItem(BookmarkGrid grid, BookmarkItem bookmarkItem) {
final BookmarkGroup group = grid.getGroup(bookmarkItem.groupId);
this.grid = grid;
this.bookmarkItem = bookmarkItem.copy();
this.moveRecipe = bookmarkItem.recipeId != null && !bookmarkItem.isIngredient
&& (group.viewMode == BookmarkViewMode.TODO_LIST || group.crafting != null);
this.crossGroup = !group.collapsed && group.viewMode == BookmarkViewMode.TODO_LIST
&& !this.bookmarkItem.isIngredient;
this.isCollapsedRecipe = group.crafting != null && group.crafting.itemToRecipe.values().stream()
.anyMatch(recipeId -> this.bookmarkItem.equalsRecipe(recipeId, this.bookmarkItem.groupId));
this.update();
}
public void postDraw(int mousex, int mousey) {
Point startRect = null;
GuiContainerManager.drawItems.zLevel += 100;
for (Integer itemIndex : this.grid.getSortedItems()) {
if (this.items.contains(itemIndex)) {
final BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
final int slotIndex = this.grid.gridGenerator.itemToSlot.get(itemIndex);
final Rectangle4i rect = this.grid
.getSlotRect(slotIndex % (this.grid.getRows() * this.grid.getColumns()));
if (startRect == null) {
startRect = new Point(rect.x - this.shiftX, rect.y - this.shiftY);
}
GuiContainerManager.drawItem(
mousex + rect.x - startRect.x + 1,
mousey + rect.y - startRect.y + 1,
item.getItemStack(),
true,
"");
}
}
GuiContainerManager.drawItems.zLevel -= 100;
}
public void update() {
final BookmarkGroup group = this.grid.getGroup(this.bookmarkItem.groupId);
this.items.clear();
if (group.collapsed) {
return;
}
for (Map.Entry<Integer, BookmarkChainItem> entry : this.grid.gridGenerator.caclulatedItems.entrySet()) {
if (containsItem(entry.getValue().getItem())) {
this.items.add(entry.getKey());
}
}
if (this.isCollapsedRecipe && group.crafting != null) {
for (Map.Entry<Integer, RecipeId> entry : group.crafting.itemToRecipe.entrySet()) {
if (this.bookmarkItem.equalsRecipe(entry.getValue(), this.bookmarkItem.groupId)) {
this.items.add(entry.getKey());
}
}
}
}
public boolean isEmpty() {
return this.items.isEmpty();
}
public int getItemIndex() {
return this.items.isEmpty() ? -1 : this.items.get(0);
}
private boolean canInsert(BookmarkGroup group) {
return group.viewMode == BookmarkViewMode.TODO_LIST && !group.collapsed;
}
public void mouseDragged(int mousex, int mousey) {
final BookmarkViewMode sortViewMode = this.grid.getViewMode(this.bookmarkItem.groupId);
BookmarksGridSlot mouseOverSlot = this.grid.getSlotMouseOver(mousex, mousey);
if (this.crossGroup) {
final Rectangle4i topLeftSlot = this.grid.getSlotRect(0);
mouseOverSlot = this.grid.getSlotMouseOver(topLeftSlot.x, mousey);
if (mouseOverSlot != null) {
float ySlot = (float) (mousey - topLeftSlot.y) / ItemsGrid.SLOT_SIZE;
int overRowIndex = (int) ySlot;
int beforeGroupId = this.grid.getRowGroupId(overRowIndex - 1);
int afterGroupId = this.grid.getRowGroupId(overRowIndex + 1);
int overGroupId = mouseOverSlot.getGroupId();
ySlot -= overRowIndex;
if (overGroupId == this.bookmarkItem.groupId && !this.items.contains(mouseOverSlot.itemIndex)) {
this.grid.moveItem(this, mouseOverSlot.itemIndex);
} else if (ySlot <= 0.25) {
final BookmarkGroup group = this.grid.getGroup(beforeGroupId);
if (beforeGroupId != overGroupId && canInsert(group)
&& !existsRecipe(this.bookmarkItem.recipeId, beforeGroupId)) {
this.grid.moveItem(this, overRowIndex, beforeGroupId, false);
}
} else if (ySlot > 0.25 && ySlot <= 0.5) {
if (beforeGroupId == overGroupId) {
return;
}
if (overGroupId != BookmarkGrid.DEFAULT_GROUP_ID
&& beforeGroupId != BookmarkGrid.DEFAULT_GROUP_ID) {
beforeGroupId = BookmarkGrid.DEFAULT_GROUP_ID;
}
if (overGroupId == BookmarkGrid.DEFAULT_GROUP_ID && beforeGroupId != BookmarkGrid.DEFAULT_GROUP_ID
&& afterGroupId != BookmarkGrid.DEFAULT_GROUP_ID) {
return;
}
if (canInsert(this.grid.getGroup(beforeGroupId))
&& !existsRecipe(this.bookmarkItem.recipeId, beforeGroupId)) {
this.grid.moveItem(this, overRowIndex, beforeGroupId, false);
}
} else if (ySlot > 0.5 && ySlot < 0.75) {
if (afterGroupId == overGroupId) {
return;
}
if (overGroupId != BookmarkGrid.DEFAULT_GROUP_ID && afterGroupId != BookmarkGrid.DEFAULT_GROUP_ID) {
afterGroupId = BookmarkGrid.DEFAULT_GROUP_ID;
}
if (overGroupId == BookmarkGrid.DEFAULT_GROUP_ID && beforeGroupId != BookmarkGrid.DEFAULT_GROUP_ID
&& afterGroupId != BookmarkGrid.DEFAULT_GROUP_ID) {
return;
}
if (canInsert(this.grid.getGroup(afterGroupId))
&& !existsRecipe(this.bookmarkItem.recipeId, afterGroupId)) {
this.grid.moveItem(this, overRowIndex, afterGroupId, true);
}
} else if (ySlot >= 0.75) {
final BookmarkGroup group = this.grid.getGroup(afterGroupId);
if (afterGroupId != overGroupId && canInsert(group)
&& !existsRecipe(this.bookmarkItem.recipeId, afterGroupId)) {
this.grid.moveItem(this, overRowIndex, afterGroupId, true);
}
}
} else {
final int overRowIndex = this.grid.getHoveredRowIndex(false);
final int overGroupId = this.grid.getRowGroupId(overRowIndex);
if (overRowIndex != -1 && overGroupId == this.bookmarkItem.groupId) {
final int absoluteSlotIndex = ((this.grid.getPage() - 1) * this.grid.getRows() + overRowIndex)
* this.grid.getColumns();
if (absoluteSlotIndex < this.grid.gridGenerator.itemToSlot.getOrDefault(getItemIndex(), -1)) {
this.grid.moveItem(this, overRowIndex, overGroupId, true);
} else {
this.grid.moveItem(this, overRowIndex, overGroupId, false);
}
}
}
} else if (mouseOverSlot != null && !this.items.contains(mouseOverSlot.itemIndex)
&& mouseOverSlot.getGroupId() == this.bookmarkItem.groupId
&& (sortViewMode == BookmarkViewMode.DEFAULT || sortViewMode == BookmarkViewMode.TODO_LIST
&& mouseOverSlot.getBookmarkItem().equalsRecipe(this.bookmarkItem))) {
this.grid.moveItem(this, mouseOverSlot.itemIndex);
}
}
private boolean existsRecipe(RecipeId recipeId, int groupId) {
if (recipeId == null) return false;
for (int itemIndex = 0; itemIndex < this.grid.bookmarkItems.size(); itemIndex++) {
if (!this.items.contains(itemIndex)
&& this.grid.bookmarkItems.get(itemIndex).equalsRecipe(recipeId, groupId)) {
return true;
}
}
return false;
}
public List<BookmarkItem> getBookmarkItems() {
final BookmarkGroup group = this.grid.getGroup(this.bookmarkItem.groupId);
final List<BookmarkItem> items = new ArrayList<>();
final List<RecipeId> recipeRelations = new ArrayList<>();
if (this.isCollapsedRecipe && group.crafting != null) {
recipeRelations.addAll(
group.crafting.recipeRelations.getOrDefault(this.bookmarkItem.recipeId, Collections.emptySet()));
}
for (BookmarkItem item : this.grid.bookmarkItems) {
if (containsItem(item)
|| item.groupId == this.bookmarkItem.groupId && recipeRelations.contains(item.recipeId)) {
items.add(item);
}
}
return items;
}
public boolean containsItem(BookmarkItem slotItem) {
return this.moveRecipe ? this.bookmarkItem.equalsRecipe(slotItem) : this.bookmarkItem.equals(slotItem);
}
}
@@ -113,8 +113,13 @@ public class GuiItemSorter extends GuiOptionPane {
if (nslot != list.indexOf(dragged.e)) {
list.remove(dragged.e);
list.add(nslot, dragged.e);
opt.getTag().setValue(ItemSorter.getSaveString(list));
if (opt.activeTag() == opt.getTag()) ItemSorter.list = new ArrayList<>(list);
LayoutManager.markItemsDirty();
if (opt.activeTag() == opt.getTag()) {
ItemSorter.list = new ArrayList<>(list);
}
}
}
}
@@ -1,9 +1,7 @@
package codechicken.nei.config;
import static codechicken.lib.gui.GuiDraw.getMousePosition;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderHelper;
@@ -14,6 +12,7 @@ import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.core.gui.GuiScreenWidget;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.render.CCRenderState;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemPanels;
@@ -114,8 +113,8 @@ public class GuiPanelSettings extends GuiScreenWidget {
}
protected int[] getPaddings() {
final int minWidth = 5 * ItemsGrid.SLOT_SIZE;
final int minHeight = 9 * ItemsGrid.SLOT_SIZE;
final int minWidth = ItemsGrid.SLOT_SIZE;
final int minHeight = ItemsGrid.SLOT_SIZE;
int paddingLeft = (int) Math.ceil(margin.w * opt.renderTag(name + ".left").getIntValue() / 100000.0);
int paddingTop = (int) Math.ceil(margin.h * opt.renderTag(name + ".top").getIntValue() / 100000.0);
@@ -123,7 +122,7 @@ public class GuiPanelSettings extends GuiScreenWidget {
int paddingBottom = (int) Math.ceil(margin.h * opt.renderTag(name + ".bottom").getIntValue() / 100000.0);
if (dragDir != null) {
final Point mouse = getMousePosition();
final Point mouse = GuiDraw.getMousePosition();
Point drag = new Point(mouse.x - dragDown.x, mouse.y - dragDown.y);
if (dragDir == "left") {
@@ -164,13 +163,12 @@ public class GuiPanelSettings extends GuiScreenWidget {
final int columns = w / ItemsGrid.SLOT_SIZE;
final int rows = (h - (PANEL_SIZE + 2) * 2) / ItemsGrid.SLOT_SIZE;
final int paddingLeft = (w % ItemsGrid.SLOT_SIZE) / 2;
final ArrayList<ItemStack> items = ItemPanels.itemPanel.getItems();
final List<ItemStack> items = ItemPanels.itemPanel.getItems();
if (items.isEmpty()) return;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
GuiContainerManager.drawItem(
drawItem(
x + paddingLeft + ItemsGrid.SLOT_SIZE * c + 1,
y + PANEL_SIZE + 2 + ItemsGrid.SLOT_SIZE * r + 1,
items.get((r * columns + c) % items.size()));
@@ -178,6 +176,21 @@ public class GuiPanelSettings extends GuiScreenWidget {
}
}
protected void drawItem(int x, int y, ItemStack stack) {
final float scale = ItemsGrid.SLOT_SIZE / 18f;
final float inverseScaleFactor = 1.0f / scale;
final float shiftX = x * inverseScaleFactor;
final float shiftY = y * inverseScaleFactor;
GL11.glScaled(scale, scale, 1);
GL11.glTranslated(shiftX, shiftY, 0);
GuiContainerManager.drawItem(0, 0, stack, true, "");
GL11.glTranslated(-1 * shiftX, -1 * shiftY, 0);
GL11.glScaled(inverseScaleFactor, inverseScaleFactor, 1);
}
public boolean contains(int pointX, int pointY) {
return (new Rectangle4i(x, y, w, h)).contains(pointX, pointY);
}
@@ -185,7 +198,7 @@ public class GuiPanelSettings extends GuiScreenWidget {
protected void mouseClicked(int x, int y, int button) {
if (contains(x, y)) {
dragDown = getMousePosition();
dragDown = GuiDraw.getMousePosition();
if (leftButton.contains(x, y)) {
dragDir = "left";
@@ -75,26 +75,25 @@ public abstract class OptionButton extends Option {
}
public String getTooltip() {
String tip = null;
if (tooltip != null) {
String s = translateN(tooltip);
if (!s.equals(namespaced(tooltip))) {
tip = s;
return s;
}
}
if (tip == null && getPrefix() != null) {
if (getPrefix() != null) {
final int width = getStringWidth(getPrefix());
final Rectangle b = buttonSize();
if (width >= b.x) {
tip = translateN(name);
return translateN(name);
}
}
return tip;
return null;
}
public void drawPrefix() {
@@ -29,6 +29,18 @@ public class OptionCycled extends OptionButton {
return prefixed ? translateN(name) : null;
}
@Override
public String getTooltip() {
String tooltip = name + "." + value() + ".tip";
String s = translateN(tooltip);
if (!s.equals(namespaced(tooltip))) {
return s;
}
return super.getTooltip();
}
@Override
public boolean onClick(int button) {
return cycle();
@@ -1,11 +1,15 @@
package codechicken.nei.config;
import codechicken.lib.gui.GuiDraw;
public class OptionIntegerField extends OptionTextField {
public final int min;
public final int max;
public static final long UNSIGNED_INT_MAX = 0xFFFFFFFFL;
public OptionIntegerField(String name, int min, int max) {
public final long min;
public final long max;
public OptionIntegerField(String name, long min, long max) {
super(name);
this.min = min;
this.max = max;
@@ -15,12 +19,26 @@ public class OptionIntegerField extends OptionTextField {
this(name, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
@Override
protected int getMaxInputWidth() {
if (renderTag().getValue().startsWith("0x")) {
return GuiDraw.getStringWidth("0x" + Long.toHexString(this.max).toUpperCase()) + 32;
}
return GuiDraw.getStringWidth(String.valueOf(this.max)) + 32;
}
@Override
public boolean isValidInput(String s) {
if (s.length() == 0) return true;
if (s.isEmpty()) return true;
try {
Integer.parseInt(s);
if (s.startsWith("0x")) {
Long.parseUnsignedLong(s.substring(2), 16);
} else {
Integer.parseInt(s);
}
return true;
} catch (NumberFormatException nfe) {
return false;
@@ -29,9 +47,15 @@ public class OptionIntegerField extends OptionTextField {
@Override
public boolean isValidValue(String s) {
if (s.length() == 0 || !isValidInput(s)) return false;
if (s.isEmpty() || !isValidInput(s)) return false;
long i = 0;
int i = Integer.parseInt(s);
return i >= min && i <= max;
if (s.startsWith("0x")) {
i = Long.parseUnsignedLong(s.substring(2), 16);
} else {
i = Integer.parseInt(s);
}
return i >= this.min && i <= this.max;
}
}
@@ -7,8 +7,8 @@ import java.awt.Rectangle;
import org.lwjgl.input.Keyboard;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.util.NEIKeyboardUtils;
public class OptionKeyBind extends OptionButton {
@@ -122,8 +122,12 @@ public class OptionKeyBind extends OptionButton {
@Override
public String getButtonText() {
final int metahash = Math.max(editing ? NEIClientUtils.getMetaHash() : getValue(), 0);
return NEIClientConfig.getKeyName(metahash, useHash, editing);
if (editing) {
return NEIKeyboardUtils.getHashName(NEIClientUtils.getMetaHash());
}
return NEIKeyboardUtils.getKeyName(Math.max(getValue(), 0));
}
@Override
@@ -1,6 +1,7 @@
package codechicken.nei.config;
import java.awt.*;
import java.awt.Dimension;
import java.awt.Rectangle;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
@@ -1,52 +1,46 @@
package codechicken.nei.config;
import static codechicken.lib.gui.GuiDraw.drawString;
import static codechicken.lib.gui.GuiDraw.getStringWidth;
import java.util.List;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.TextField;
import codechicken.nei.config.GuiOptionList.OptionScrollSlot;
public class OptionTextField extends Option {
private boolean focused = false;
private TextField textField = new TextField("test") {
protected final TextField textField = new TextField("option-text-field") {
@Override
public void onTextChange(String oldText) {
if (focused() && isValidValue(text())) if (!defaulting() || !text().equals(getTag().getValue())) // don't
// override
// global
// if text
// hasn't
// changed
getTag().setValue(text());
{
this.h = 20;
}
@Override
public boolean focused() {
return focused;
public void onTextChange(String oldText) {
// don't override global if text hasn't changed
if (focused() && isValidValue(text()) && (!defaulting() || !text().equals(getTag().getValue()))) {
getTag().setValue(text());
OptionTextField.this.onTextChange(text());
}
}
@Override
public void setFocus(boolean focus) {
if (!focus && !isValidValue(text())) setText(renderTag().getValue());
super.setFocus(focus);
}
focused = focus;
@Override
public void draw(int mousex, int mousey) {
this.field.setEnabled(isEnabled());
super.draw(mousex, mousey);
}
};
public OptionTextField(String name) {
super(name);
textField.h = 20;
}
@Override
public void onAdded(OptionScrollSlot slot) {
super.onAdded(slot);
}
public void onTextChange(String text) {}
@Override
public void update() {
@@ -58,23 +52,34 @@ public class OptionTextField extends Option {
return translateN(name);
}
protected int getMaxInputWidth() {
return slot.slotWidth();
}
public boolean isEnabled() {
return true;
}
@Override
public void draw(int mousex, int mousey, float frame) {
drawString(getPrefix(), 10, 6, -1);
GuiDraw.drawString(getPrefix(), 10, 6, -1);
textField.w = slot.slotWidth() - getStringWidth(getPrefix()) - 16;
textField.w = Math
.max(60, Math.min(getMaxInputWidth(), slot.slotWidth() - GuiDraw.getStringWidth(getPrefix())) - 16);
textField.x = slot.slotWidth() - textField.w;
textField.draw(mousex, mousey);
}
@Override
public void keyTyped(char c, int keycode) {
textField.handleKeyPress(keycode, c);
if (isEnabled()) {
textField.handleKeyPress(keycode, c);
}
}
@Override
public void mouseClicked(int mousex, int mousey, int button) {
if (textField.contains(mousex, mousey)) textField.handleClick(mousex, mousey, button);
if (isEnabled() && textField.contains(mousex, mousey)) textField.handleClick(mousex, mousey, button);
}
@Override
@@ -84,9 +89,9 @@ public class OptionTextField extends Option {
@Override
public List<String> handleTooltip(int mousex, int mousey, List<String> currenttip) {
if (new Rectangle4i(10, 0, textField.x - 10, 20).contains(mousex, mousey)) {
if (isEnabled() && new Rectangle4i(10, 0, textField.x - 10, 20).contains(mousex, mousey)) {
String tip = translateN(name + ".tip");
if (!tip.equals(name + ".tip")) currenttip.add(tip);
if (!tip.equals(namespaced(name + ".tip"))) currenttip.add(tip);
}
return currenttip;
}
@@ -17,6 +17,7 @@ public class OptionToggleButton extends OptionButton {
return renderTag().getBooleanValue();
}
@Override
public String getButtonText() {
return translateN(name + (state() ? ".true" : ".false"));
}
@@ -46,6 +46,8 @@ public class OptionUtilities extends OptionStringSet {
x += 24;
LayoutManager.drawIcon(x + 4, 4, new Image(132, 12, 12, 12));
x += 24;
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
RenderHelper.enableGUIStandardItemLighting();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
ItemStack sword = new ItemStack(Items.diamond_sword);
@@ -55,5 +57,6 @@ public class OptionUtilities extends OptionStringSet {
GuiContainerManager.drawItem(x + 2, 2, new ItemStack(Items.potionitem));
x += 24;
GuiContainerManager.drawItem(x + 2, 2, new ItemStack(Blocks.stone));
GL11.glPopAttrib();
}
}
@@ -10,6 +10,7 @@ public abstract class RegistryDumper<T> extends DataDumper {
super(name);
}
@SuppressWarnings("unchecked")
@Override
public Iterable<String[]> dump(int mode) {
LinkedList<String[]> list = new LinkedList<>();
@@ -0,0 +1,53 @@
package codechicken.nei.config.preset;
import static codechicken.lib.gui.GuiDraw.drawStringC;
import org.lwjgl.opengl.GL11;
import codechicken.nei.Button;
import codechicken.nei.LayoutManager;
public abstract class CheckboxButton extends Button {
protected boolean checked = false;
public CheckboxButton(String s) {
super(s);
}
public void setChecked(boolean checked) {
this.checked = checked;
this.onChange();
}
public boolean isChecked() {
return this.checked;
}
@Override
public void draw(int mousex, int mousey) {
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glColor4f(1, 1, 1, 1);
int tex;
if ((this.state & 0x3) == 2) {
tex = 0;
} else if ((this.state & 0x4) == 0 && contains(mousex, mousey) || (this.state & 0x3) == 1) {
tex = 2;
} else {
tex = 1;
}
int colour = tex == 2 ? 0xffffa0 : tex == 0 ? 0x601010 : 0xe0e0e0;
LayoutManager.drawButtonBackground(x, y, w, h, true, isChecked() ? 0 : tex);
drawStringC(getRenderLabel(), x + w / 2, y + (h - 8) / 2, colour);
}
public boolean onButtonPress(boolean rightclick) {
this.setChecked(!isChecked());
return true;
}
protected abstract void onChange();
}
@@ -0,0 +1,260 @@
package codechicken.nei.config.preset;
import static codechicken.lib.gui.GuiDraw.getStringWidth;
import java.awt.Rectangle;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
import codechicken.core.gui.GuiCCButton;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList;
import codechicken.nei.PresetsList.Preset;
import codechicken.nei.config.GuiOptionPane;
import codechicken.nei.config.Option;
public class GuiPresetList extends GuiOptionPane {
private final Option opt;
protected static final int SLOT_HEIGHT = 24;
protected static final int BUTTON_HEIGHT = 20;
protected GuiCCButton createButton;
protected GuiCCButton toggleButton;
protected int sortingItemIndex = -1;
public GuiPresetList(Option opt) {
this.opt = opt;
this.createButton = new GuiCCButton(0, 2, 0, 16, NEIClientUtils.translate("presets.new"))
.setActionCommand("create");
this.toggleButton = new GuiCCButton(0, 2, 0, 16, NEIClientUtils.translate("presets.toggle"))
.setActionCommand("toggle");
}
@Override
public void initGui() {
super.initGui();
this.createButton.width = getStringWidth(this.createButton.text) + 15;
this.createButton.x = width - this.createButton.width - 15;
this.toggleButton.width = getStringWidth(this.toggleButton.text) + 15;
this.toggleButton.x = width - this.toggleButton.width - 15 - this.createButton.width - 10;
}
@Override
public void addWidgets() {
super.addWidgets();
add(this.createButton);
add(this.toggleButton);
}
@Override
public void actionPerformed(String ident, Object... params) {
super.actionPerformed(ident, params);
if (ident.equals("create")) {
cretePreset();
}
if (ident.equals("toggle")) {
togglePreset();
}
}
@Override
protected void mouseMovedOrUp(int x, int y, int button) {
super.mouseMovedOrUp(x, y, button);
if (sortingItemIndex >= 0) {
PresetsList.savePresets();
} else if (button == 0) {
int slot = getSlotMouseOver(x, y);
if (slot != -1) {
Rectangle w = pane.windowBounds();
int mx = x - w.x;
if (mx <= BUTTON_HEIGHT) {
Preset preset = PresetsList.presets.get(slot);
preset.enabled = !preset.enabled;
PresetsList.savePresets();
} else if (mx >= 26 && mx <= w.width - 26 * 2) {
openPreset(slot);
} else if (mx >= w.width - BUTTON_HEIGHT) {
PresetsList.presets.remove(slot);
PresetsList.savePresets();
}
}
}
sortingItemIndex = -1;
}
@Override
protected void mouseClickMove(int x, int y, int button, long time) {
super.mouseClickMove(x, y, button, time);
if (sortingItemIndex == -1) {
Rectangle w = pane.windowBounds();
int mx = x - w.x;
if (mx >= 26 && mx <= w.width - 26 * 2) {
sortingItemIndex = getSlotMouseOver(x, y);
} else {
sortingItemIndex = -2;
}
} else if (sortingItemIndex >= 0) {
Rectangle w = pane.windowBounds();
if (y >= w.y && y <= w.y + w.height) {
int my = y + pane.scrolledPixels() - w.y;
int slot = my / SLOT_HEIGHT;
if (my % SLOT_HEIGHT < BUTTON_HEIGHT && slot < PresetsList.presets.size()
&& slot != -1
&& slot != sortingItemIndex) {
PresetsList.presets.add(slot, PresetsList.presets.remove(sortingItemIndex));
sortingItemIndex = slot;
}
}
}
}
protected int getSlotMouseOver(int x, int y) {
Rectangle w = pane.windowBounds();
if (x >= w.x && x <= w.x + w.width && y >= w.y && y <= w.y + w.height) {
int my = y + pane.scrolledPixels() - w.y;
int slot = my / SLOT_HEIGHT;
if (my % SLOT_HEIGHT < BUTTON_HEIGHT && slot < PresetsList.presets.size()) {
return slot;
}
}
return -1;
}
protected void cretePreset() {
Minecraft.getMinecraft().displayGuiScreen(new GuiPresetSettings(this, -1));
}
protected void togglePreset() {
boolean enabled = PresetsList.presets.stream().noneMatch(g -> g.enabled);
for (Preset preset : PresetsList.presets) {
preset.enabled = enabled;
}
PresetsList.savePresets();
}
protected void openPreset(int slot) {
Minecraft.getMinecraft().displayGuiScreen(new GuiPresetSettings(this, slot));
}
@Override
public int contentHeight() {
return PresetsList.presets.size() * SLOT_HEIGHT;
}
@Override
public void drawContent(int mx, int my, float frame) {
int scrolled = pane.scrolledPixels();
Rectangle w = pane.windowBounds();
int y = 0;
for (int slot = 0; slot < PresetsList.presets.size(); ++slot) {
if (y + SLOT_HEIGHT > scrolled && y < scrolled + w.height) {
if (sortingItemIndex != slot) {
drawSlot(w, slot, w.x, w.y + y - scrolled, mx, my - y);
}
}
y += SLOT_HEIGHT;
}
if (sortingItemIndex >= 0) {
drawSlot(w, sortingItemIndex, w.x, w.y + my - scrolled - BUTTON_HEIGHT / 2, mx, my - y);
}
}
protected void drawSlot(Rectangle w, int slot, int x, int y, int mx, int my) {
final Rectangle4i delete = new Rectangle4i(x + w.width - BUTTON_HEIGHT, y, BUTTON_HEIGHT, BUTTON_HEIGHT);
final Rectangle4i enabled = new Rectangle4i(x, y, BUTTON_HEIGHT, BUTTON_HEIGHT);
final Rectangle4i option = new Rectangle4i(x + 26, y, w.width - 26 * 2, BUTTON_HEIGHT);
final int enabledState = y + my >= w.y && y + my <= w.y + w.height && enabled.contains(x + mx, y + my) ? 2 : 1;
final int optionState = y + my >= w.y && y + my <= w.y + w.height && option.contains(x + mx, y + my) ? 2 : 1;
final int deleteState = y + my >= w.y && y + my <= w.y + w.height && delete.contains(x + mx, y + my) ? 2 : 1;
final Preset preset = PresetsList.presets.get(slot);
final String displayName = preset.name;
final String modeName;
switch (preset.mode) {
case HIDE:
modeName = EnumChatFormatting.GOLD + NEIClientUtils.translate("presets.mode.hide.char")
+ EnumChatFormatting.RESET;
break;
case REMOVE:
modeName = EnumChatFormatting.RED + NEIClientUtils.translate("presets.mode.remove.char")
+ EnumChatFormatting.RESET;
break;
case GROUP:
modeName = EnumChatFormatting.AQUA + NEIClientUtils.translate("presets.mode.group.char")
+ EnumChatFormatting.RESET;
break;
default:
modeName = "?";
break;
}
// enabled icon
GL11.glColor4f(1, 1, 1, 1);
LayoutManager.drawButtonBackground(
enabled.x,
enabled.y,
enabled.w,
enabled.h,
true,
preset.enabled ? 0 : enabledState);
GuiDraw.drawString("✔", enabled.x + 7, enabled.y + 6, enabledState == 2 ? 0xFFFFFFA0 : 0xFFE0E0E0);
// preset name
GL11.glColor4f(1, 1, 1, 1);
LayoutManager.drawButtonBackground(option.x, option.y, option.w, option.h, true, optionState);
GuiDraw.drawString("⋮⋮", option.x + 4, option.y + 5, optionState == 2 ? 0xFFFFFFA0 : 0xFFE0E0E0);
GuiDraw.drawString(
NEIClientUtils.cropText(this.fontRendererObj, modeName + " " + displayName, option.w - 16),
option.x + 6 + 4,
option.y + 6,
optionState == 2 ? 0xFFFFFFA0 : 0xFFE0E0E0);
// remove icon
GL11.glColor4f(1, 1, 1, 1);
LayoutManager.drawButtonBackground(delete.x, delete.y, delete.w, delete.h, true, deleteState);
GuiDraw.drawString("✕", delete.x + 7, delete.y + 6, deleteState == 2 ? 0xFFFFFFA0 : 0xFFE0E0E0);
}
@Override
public GuiScreen getParentScreen() {
return opt.slot.getGui();
}
@Override
public String getTitle() {
return opt.translateN(opt.name);
}
}
@@ -0,0 +1,228 @@
package codechicken.nei.config.preset;
import java.util.LinkedList;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.Tessellator;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.Rectangle;
import codechicken.core.gui.GuiScreenWidget;
import codechicken.nei.Button;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList;
import codechicken.nei.PresetsList.Preset;
import codechicken.nei.config.OptionScrollPane;
import codechicken.nei.guihook.GuiContainerManager;
public class GuiPresetSettings extends GuiScreenWidget {
protected final Preset preset;
protected final GuiScreen parent;
protected final int slotIndex;
public int marginleft;
public int margintop;
public int marginright;
public int marginbottom;
protected LeftPanel leftPanel;
protected RightPanel rightPanel;
protected Button backButton;
protected Button saveButton;
public GuiPresetSettings(GuiScreen parent, int slotIndex) {
this.parent = parent;
this.setMargins(6, 20, 6, 30);
this.slotIndex = slotIndex;
if (slotIndex == -1) {
preset = new Preset();
} else {
preset = PresetsList.presets.get(slotIndex).copy();
}
leftPanel = new LeftPanel(preset) {
@Override
protected void onItemsChanges() {
leftPanel.grid.restartFilter();
}
};
rightPanel = new RightPanel(preset, slotIndex) {
@Override
protected void onItemsChanges() {
leftPanel.grid.restartFilter();
}
};
backButton = new Button(NEIClientUtils.translate("options.back")) {
public boolean onButtonPress(boolean rightclick) {
Minecraft.getMinecraft().displayGuiScreen(parent);
return true;
}
};
saveButton = new Button(NEIClientUtils.translate("options.save")) {
public boolean onButtonPress(boolean rightclick) {
if (state == 0) {
if (slotIndex == -1) {
PresetsList.presets.add(preset);
} else {
PresetsList.presets.set(slotIndex, preset);
}
PresetsList.savePresets();
Minecraft.getMinecraft().displayGuiScreen(parent);
return true;
}
return false;
}
};
add(this.leftPanel);
add(this.rightPanel);
}
protected void setMargins(int left, int top, int right, int bottom) {
this.marginleft = left;
this.margintop = top;
this.marginright = right;
this.marginbottom = bottom;
}
protected Rectangle windowBounds() {
return new Rectangle(
this.marginleft,
this.margintop,
this.width - this.marginleft - this.marginright,
this.height - this.margintop - this.marginbottom);
}
@Override
public boolean doesGuiPauseGame() {
return true;
}
@Override
public void updateScreen() {
final Rectangle bounds = windowBounds();
final int panelWidth = bounds.getWidth() * 2 / 5;
this.leftPanel.setSize(bounds.getX(), bounds.getY() + 4, panelWidth, bounds.getHeight() - 6);
this.rightPanel.setSize(
bounds.getX() + bounds.getWidth() - panelWidth,
bounds.getY() + 4,
panelWidth,
bounds.getHeight() - 6);
final int w = Math.min(200, width - 40);
backButton.w = w / 2 - 3;
backButton.h = 20;
backButton.x = (width - w) / 2;
backButton.y = height - 25;
saveButton.state = preset.name.isEmpty() || preset.mode == null || preset.items.isEmpty() ? 2 : 0;
saveButton.w = w / 2 - 3;
saveButton.h = 20;
saveButton.x = width / 2 + 3;
saveButton.y = height - 25;
super.updateScreen();
}
@Override
public void resize() {
this.guiLeft = this.guiTop = 0;
}
@Override
public void drawScreen(int mousex, int mousey, float f) {
Rectangle bounds = windowBounds();
drawDefaultBackground();
drawOverlay(bounds.getY(), bounds.getHeight(), width, zLevel);
drawCenteredString(
Minecraft.getMinecraft().fontRenderer,
NEIClientUtils.translate(this.slotIndex == -1 ? "presets.create" : "presets.update"),
width / 2,
6,
-1);
backButton.draw(mousex, mousey);
saveButton.draw(mousex, mousey);
super.drawScreen(mousex, mousey, f);
List<String> tooltip = new LinkedList<>();
tooltip = leftPanel.handleTooltip(mousex, mousey, tooltip);
tooltip = rightPanel.handleTooltip(mousex, mousey, tooltip);
GuiContainerManager.drawPagedTooltip(Minecraft.getMinecraft().fontRenderer, mousex + 12, mousey - 12, tooltip);
}
@Override
protected void mouseClicked(int x, int y, int button) {
super.mouseClicked(x, y, button);
if (backButton.contains(x, y)) {
backButton.handleClick(x, y, button);
}
if (saveButton.contains(x, y)) {
saveButton.handleClick(x, y, button);
}
}
public static void drawOverlay(int y, int height, int screenwidth, float zLevel) {
OptionScrollPane.drawOverlayTex(0, 0, screenwidth, y, zLevel);
OptionScrollPane.drawOverlayTex(0, y + height, screenwidth, screenwidth - y - height, zLevel);
OptionScrollPane.drawOverlayGrad(0, screenwidth, y, y + 4, zLevel);
OptionScrollPane.drawOverlayGrad(0, screenwidth, y + height, y + height - 4, zLevel);
}
public static void drawOverlayTex(int x, int y, int w, int h, float zLevel) {
GL11.glColor4f(1, 1, 1, 1);
Minecraft.getMinecraft().renderEngine.bindTexture(Gui.optionsBackground);
Tessellator t = Tessellator.instance;
t.startDrawingQuads();
t.addVertexWithUV(x, y, zLevel, 0, 0);
t.addVertexWithUV(x, y + h, zLevel, 0, h / 16D);
t.addVertexWithUV(x + w, y + h, zLevel, w / 16D, h / 16D);
t.addVertexWithUV(x + w, y, zLevel, w / 16D, 0);
t.draw();
}
public static void drawOverlayGrad(int x1, int x2, int y1, int y2, float zLevel) {
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glShadeModel(GL11.GL_SMOOTH);
Tessellator t = Tessellator.instance;
t.startDrawingQuads();
t.setColorRGBA_I(0, 255);
t.addVertex(x2, y1, zLevel);
t.addVertex(x1, y1, zLevel);
t.setColorRGBA_I(0, 0);
t.addVertex(x1, y2, zLevel);
t.addVertex(x2, y2, zLevel);
t.draw();
GL11.glDisable(GL11.GL_BLEND);
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_TEXTURE_2D);
}
}
@@ -0,0 +1,350 @@
package codechicken.nei.config.preset;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.core.gui.GuiWidget;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemsGrid;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.Label;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList.Preset;
import codechicken.nei.PresetsList.PresetMode;
import codechicken.nei.TextField;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerTooltipHandler;
public class LeftPanel extends GuiWidget {
protected static class MouseSelection {
public int startX = -1;
public int startY = -1;
public int startIndex = -1;
public int endIndex = -1;
public Set<ItemStack> items = new HashSet<>();
public MouseSelection(int slotIndex, Rectangle4i rec) {
endIndex = slotIndex;
startIndex = slotIndex;
startX = rec.x;
startY = rec.y;
}
}
protected static final int INPUT_HEIGHT = 20;
public final PresetItemsGrid grid = new PresetItemsGrid() {
@Override
protected ItemFilter getFilter() {
final Set<String> identifiers = preset.items;
return item -> identifiers.contains(Preset.getIdentifier(item));
}
@Override
protected boolean isSelected(ItemStack stack) {
return mouseSelection != null && mouseSelection.items.contains(stack);
}
@Override
protected MouseContext getMouseContext(int mousex, int mousey) {
final ItemsGridSlot hovered = getSlotMouseOver(mousex, mousey);
if (hovered != null) {
return new MouseContext(
hovered.slotIndex,
hovered.slotIndex / this.columns,
hovered.slotIndex % this.columns);
}
return null;
}
};
protected Label nameLabel = new Label(NEIClientUtils.translate("presets.name"), false);
protected TextField nameField = new TextField("name") {
@Override
public void onTextChange(String oldText) {
preset.name = text();
}
};
protected Label modeLabel = new Label(NEIClientUtils.translate("presets.mode"), false);
protected CheckboxButton modeHide;
protected CheckboxButton modeRemove;
protected CheckboxButton modeGroup;
protected CheckboxButton enabledButton;
protected final Preset preset;
protected MouseSelection mouseSelection;
public LeftPanel(Preset preset) {
super(1, 0, 2, 2);
this.preset = preset;
nameField.setText(preset.name);
modeHide = new CheckboxButton(NEIClientUtils.translate("presets.mode.hide")) {
@Override
public boolean isChecked() {
return preset.mode == PresetMode.HIDE;
}
@Override
protected void onChange() {
preset.mode = this.checked ? PresetMode.HIDE : null;
}
};
modeRemove = new CheckboxButton(NEIClientUtils.translate("presets.mode.remove")) {
@Override
public boolean isChecked() {
return preset.mode == PresetMode.REMOVE;
}
@Override
protected void onChange() {
preset.mode = this.checked ? PresetMode.REMOVE : null;
}
};
modeGroup = new CheckboxButton(NEIClientUtils.translate("presets.mode.group")) {
@Override
public boolean isChecked() {
return preset.mode == PresetMode.GROUP;
}
@Override
protected void onChange() {
preset.mode = this.checked ? PresetMode.GROUP : null;
}
};
enabledButton = new CheckboxButton(NEIClientUtils.translate("presets.enabled")) {
@Override
public boolean isChecked() {
return preset.enabled;
}
@Override
protected void onChange() {
preset.enabled = this.checked;
}
};
grid.restartFilter();
}
@Override
public void mouseClicked(int x, int y, int button) {
grid.mouseClicked(x, y, button);
if (modeHide.contains(x, y)) {
modeHide.handleClick(x, y, button);
}
if (modeRemove.contains(x, y)) {
modeRemove.handleClick(x, y, button);
}
if (modeGroup.contains(x, y)) {
modeGroup.handleClick(x, y, button);
}
if (enabledButton.contains(x, y)) {
enabledButton.handleClick(x, y, button);
}
if (nameField.contains(x, y)) {
nameField.handleClick(x, y, button);
} else {
nameField.onGuiClick(x, y);
}
if (mouseSelection == null && button == 0) {
final ItemsGridSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null) {
mouseSelection = new MouseSelection(slot.itemIndex, grid.getItemRect(slot.itemIndex));
}
}
}
protected void onItemsChanges() {}
@Override
public void mouseMovedOrUp(int x, int y, int button) {
nameField.mouseUp(x, y, button);
if (mouseSelection != null && button == 0) {
final ItemsGridSlot hoverSlot = grid.getSlotMouseOver(x, y);
if (hoverSlot != null && hoverSlot.itemIndex == mouseSelection.startIndex) {
preset.items.remove(Preset.getIdentifier(hoverSlot.getItemStack()));
} else if (!mouseSelection.items.isEmpty()) {
for (ItemStack stack : mouseSelection.items) {
preset.items.remove(Preset.getIdentifier(stack));
}
}
mouseSelection = null;
onItemsChanges();
}
}
@Override
public void mouseDragged(int x, int y, int button, long time) {
nameField.mouseDragged(x, y, button, time);
if (mouseSelection != null && button == 0) {
final ItemsGridSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null && slot.itemIndex != mouseSelection.endIndex) {
mouseSelection.endIndex = slot.itemIndex;
mouseSelection.items.clear();
final Rectangle4i rec = grid.getItemRect(slot.itemIndex);
final Rectangle4i sel = new Rectangle4i(
Math.min(rec.x, mouseSelection.startX),
Math.min(rec.y, mouseSelection.startY),
Math.max(rec.x, mouseSelection.startX) - Math.min(rec.x, mouseSelection.startX),
Math.max(rec.y, mouseSelection.startY) - Math.min(rec.y, mouseSelection.startY));
for (int ix = sel.x; ix <= sel.x + sel.w; ix += ItemsGrid.SLOT_SIZE) {
for (int iy = sel.y; iy <= sel.y + sel.h; iy += ItemsGrid.SLOT_SIZE) {
final ItemsGridSlot over = grid.getSlotMouseOver(ix, iy);
if (over != null) {
mouseSelection.items.add(over.getItemStack());
}
}
}
}
}
}
@Override
public void update() {
int CHECKBOX_WIDTH = (this.width - 12) / 3;
nameLabel.x = this.x + 2;
nameLabel.y = this.y + 4;
nameLabel.w = this.width;
nameLabel.h = 10;
nameField.x = this.x;
nameField.y = nameLabel.y + nameLabel.h;
nameField.w = this.width - CHECKBOX_WIDTH - 6;
nameField.h = INPUT_HEIGHT;
enabledButton.x = nameField.x + nameField.w + 6;
enabledButton.y = nameField.y;
enabledButton.w = CHECKBOX_WIDTH;
enabledButton.h = INPUT_HEIGHT;
modeLabel.x = this.x + 2;
modeLabel.y = nameField.y + nameField.h + 6;
modeLabel.w = this.width;
modeLabel.h = 10;
modeHide.w = modeRemove.w = modeGroup.w = CHECKBOX_WIDTH;
modeHide.h = modeRemove.h = modeGroup.h = INPUT_HEIGHT;
modeHide.y = modeRemove.y = modeGroup.y = modeLabel.y + modeLabel.h;
modeHide.x = this.x + 1;
modeRemove.x = modeHide.x + modeHide.w + 6;
modeGroup.x = modeRemove.x + modeRemove.w + 6;
grid.setGridSize(
this.x + 1,
modeHide.y + modeHide.h + 2,
this.width - 2,
this.height - (modeHide.y + modeHide.h + 2));
grid.refresh(null);
}
@Override
public void draw(int mousex, int mousey, float frame) {
nameLabel.draw(mousex, mousey);
nameField.draw(mousex, mousey);
modeLabel.draw(mousex, mousey);
modeHide.draw(mousex, mousey);
modeRemove.draw(mousex, mousey);
modeGroup.draw(mousex, mousey);
enabledButton.draw(mousex, mousey);
RenderHelper.enableGUIStandardItemLighting();
GL11.glPushMatrix();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
grid.draw(mousex, mousey);
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
GL11.glPopMatrix();
RenderHelper.enableStandardItemLighting();
}
public List<String> handleTooltip(int mousex, int mousey, List<String> tooltip) {
final ItemsGridSlot over = grid.getSlotMouseOver(mousex, mousey);
if (over != null) {
tooltip = GuiContainerManager.itemDisplayNameMultiline(over.getItemStack(), null, true);
synchronized (GuiContainerManager.tooltipHandlers) {
for (IContainerTooltipHandler handler : GuiContainerManager.tooltipHandlers) {
tooltip = handler.handleItemTooltip(null, over.getItemStack(), mousex, mousey, tooltip);
}
}
if (!tooltip.isEmpty()) {
tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE); // add space after 'title'
}
} else if (modeHide.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.mode.hide.tip"));
} else if (modeRemove.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.mode.remove.tip"));
} else if (modeGroup.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.mode.group.tip"));
}
return tooltip;
}
@Override
public void keyTyped(char c, int keycode) {
nameField.handleKeyPress(keycode, c);
}
@Override
public void mouseScrolled(int x, int y, int scroll) {
if (grid.contains(x, y)) {
grid.shiftPage(-scroll);
}
}
}
@@ -0,0 +1,194 @@
package codechicken.nei.config.preset;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.Button;
import codechicken.nei.ItemList;
import codechicken.nei.ItemSorter;
import codechicken.nei.ItemsGrid;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.Label;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.RestartableTask;
import codechicken.nei.api.ItemFilter;
public abstract class PresetItemsGrid extends ItemsGrid<PresetItemsGrid.PresetsGridSlot, ItemsGrid.MouseContext> {
protected static final int BUTTON_SIZE = 16;
public class PresetsGridSlot extends ItemsGridSlot {
public PresetsGridSlot(int slotIndex, int itemIndex, ItemStack itemStack) {
super(slotIndex, itemIndex, itemStack);
}
@Override
public void beforeDraw(Rectangle4i rect, MouseContext mouseContext) {
if (mouseContext != null && mouseContext.slotIndex == this.slotIndex || isSelected(getItemStack())) {
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, HIGHLIGHT_COLOR);
}
}
}
public Button pagePrev;
public Label pageLabel;
public Button pageNext;
protected ArrayList<ItemStack> newItems;
protected List<PresetsGridSlot> gridMask;
protected final RestartableTask updateFilter = new RestartableTask("NEI Presets Item Filtering") {
@Override
public void execute() {
ArrayList<ItemStack> filtered;
ItemFilter filter = getFilter();
try {
filtered = ItemList.forkJoinPool.submit(
() -> ItemList.items.parallelStream().filter(filter::matches)
.collect(Collectors.toCollection(ArrayList::new)))
.get();
} catch (InterruptedException | ExecutionException e) {
filtered = new ArrayList<>();
e.printStackTrace();
stop();
}
if (interrupted()) return;
ItemSorter.sort(filtered);
if (interrupted()) return;
updateItemList(filtered);
}
};
protected PresetItemsGrid() {
pageLabel = new Label("0/0", true);
pagePrev = new Button("<") {
public boolean onButtonPress(boolean rightclick) {
if (rightclick) {
setPage(0);
} else {
shiftPage(-1);
}
return true;
}
};
pageNext = new Button(">") {
public boolean onButtonPress(boolean rightclick) {
if (rightclick) {
setPage(getNumPages() - 1);
} else {
shiftPage(1);
}
return true;
}
};
}
protected String getLabelText() {
return String.format("%d/%d", getPage(), Math.max(1, getNumPages()));
}
@Override
public void setGridSize(int mleft, int mtop, int w, int h) {
pageLabel.text = getLabelText();
pagePrev.w = pageNext.w = BUTTON_SIZE;
pagePrev.h = pageNext.h = BUTTON_SIZE;
pagePrev.y = pageNext.y = mtop;
pagePrev.x = mleft;
pageNext.x = mleft + w - pageNext.w;
pageLabel.x = mleft + w / 2;
pageLabel.y = pagePrev.y + 5;
super.setGridSize(mleft, mtop + BUTTON_SIZE + 2, w, h - BUTTON_SIZE - 4);
}
@Override
public void draw(int mousex, int mousey) {
pagePrev.draw(mousex, mousey);
pageNext.draw(mousex, mousey);
pageLabel.draw(mousex, mousey);
super.draw(mousex, mousey);
}
public void mouseClicked(int x, int y, int button) {
if (pagePrev.contains(x, y)) {
pagePrev.handleClick(x, y, button);
}
if (pageNext.contains(x, y)) {
pageNext.handleClick(x, y, button);
}
}
public void restartFilter() {
updateFilter.restart();
}
protected void updateItemList(List<ItemStack> newItems) {
this.newItems = new ArrayList<>(newItems);
}
@Override
protected void onGridChanged() {
this.gridMask = null;
super.onGridChanged();
}
@Override
public List<PresetsGridSlot> getMask() {
if (this.gridMask == null) {
this.gridMask = new ArrayList<>();
int itemIndex = page * perPage;
for (int slotIndex = 0; slotIndex < rows * columns && itemIndex < size(); slotIndex++) {
this.gridMask.add(new PresetsGridSlot(slotIndex, itemIndex, getItem(itemIndex)));
itemIndex++;
}
}
return this.gridMask;
}
@Override
public void refresh(GuiContainer gui) {
if (this.newItems != null) {
this.realItems = this.newItems;
this.newItems = null;
onItemsChanged();
}
super.refresh(gui);
}
protected abstract boolean isSelected(ItemStack stack);
protected abstract ItemFilter getFilter();
}
@@ -0,0 +1,414 @@
package codechicken.nei.config.preset;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.core.gui.GuiWidget;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.CollapsibleItems;
import codechicken.nei.ItemList.AllMultiItemFilter;
import codechicken.nei.ItemList.AnyMultiItemFilter;
import codechicken.nei.ItemList.NegatedItemFilter;
import codechicken.nei.ItemsGrid;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList;
import codechicken.nei.PresetsList.Preset;
import codechicken.nei.SearchField.GuiSearchField;
import codechicken.nei.TextField;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.util.TextHistory;
import cpw.mods.fml.common.registry.GameRegistry;
public class RightPanel extends GuiWidget {
protected static class MouseSelection {
public int startX = -1;
public int startY = -1;
public int startIndex = -1;
public int endIndex = -1;
public Set<ItemStack> items = new HashSet<>();
public boolean append = true;
public MouseSelection(int slotIndex, Rectangle4i rec, boolean ppnd) {
append = ppnd;
endIndex = slotIndex;
startIndex = slotIndex;
startX = rec.x;
startY = rec.y;
}
}
protected abstract static class PresetSearchField extends TextField {
private static final TextHistory history = new TextHistory();
protected PresetSearchField(String ident) {
super(ident);
}
@Override
protected void initInternalTextField() {
field = new GuiSearchField();
field.setMaxStringLength(maxSearchLength);
field.setCursorPositionZero();
}
@Override
public int getTextColour() {
if (!text().isEmpty()) {
return focused() ? 0xFFcc3300 : 0xFF993300;
} else {
return focused() ? 0xFFE0E0E0 : 0xFF909090;
}
}
@Override
public void lastKeyTyped(int keyID, char keyChar) {
if (!focused() && NEIClientConfig.isKeyHashDown("gui.search")) {
setFocus(true);
}
if (focused() && NEIClientConfig.isKeyHashDown("gui.getprevioussearch")) {
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
}
if (focused() && NEIClientConfig.isKeyHashDown("gui.getnextsearch")) {
handleNavigateHistory(TextHistory.Direction.NEXT);
}
}
@Override
public String filterText(String s) {
return EnumChatFormatting.getTextWithoutFormattingCodes(s);
}
public ItemFilter getFilter() {
return ((GuiSearchField) field).getFilter();
}
@Override
public void setFocus(boolean focus) {
final boolean previousFocus = field.isFocused();
if (previousFocus != focus) {
history.add(text());
}
super.setFocus(focus);
}
private boolean handleNavigateHistory(TextHistory.Direction direction) {
if (focused()) {
return history.get(direction, text()).map(newText -> {
setText(newText);
return true;
}).orElse(false);
}
return false;
}
}
protected static final int INPUT_HEIGHT = 20;
protected static final int BUTTON_SIZE = 16;
protected final PresetItemsGrid grid = new PresetItemsGrid() {
@Override
protected ItemFilter getFilter() {
final AllMultiItemFilter filter = new AllMultiItemFilter(searchField.getFilter());
if (enabledPresets.isChecked()) {
final AllMultiItemFilter andFilter = new AllMultiItemFilter();
final AnyMultiItemFilter orFilter = new AnyMultiItemFilter();
final Set<String> identifiers = PresetsList.presets.stream().flatMap(p -> p.items.stream())
.collect(Collectors.toSet());
andFilter.filters.add(item -> !identifiers.contains(Preset.getIdentifier(item)));
andFilter.filters.add(new NegatedItemFilter(CollapsibleItems.getItemFilter()));
if (slotIndex != -1) {
orFilter.filters.add(PresetsList.presets.get(slotIndex));
}
orFilter.filters.add(andFilter);
filter.filters.add(orFilter);
}
return filter;
}
@Override
protected boolean isSelected(ItemStack stack) {
if (mouseSelection != null && mouseSelection.items.contains(stack)) {
return mouseSelection.append;
}
return preset.items.contains(Preset.getIdentifier(stack));
}
@Override
protected MouseContext getMouseContext(int mousex, int mousey) {
final ItemsGridSlot hovered = getSlotMouseOver(mousex, mousey);
if (hovered != null) {
return new MouseContext(
hovered.slotIndex,
hovered.slotIndex / this.columns,
hovered.slotIndex % this.columns);
}
return null;
}
};
protected CheckboxButton enabledPresets;
protected final Preset preset;
protected final int slotIndex;
protected MouseSelection mouseSelection;
protected final PresetSearchField searchField = new PresetSearchField("preset-search") {
@Override
public void onTextChange(String oldText) {
final String newText = text();
if (!newText.equals(oldText)) {
grid.restartFilter();
}
}
};
public RightPanel(Preset preset, int slotIndex) {
super(1, 0, 2, 2);
this.slotIndex = slotIndex;
this.preset = preset;
enabledPresets = new CheckboxButton(NEIClientUtils.translate("presets.filter")) {
@Override
protected void onChange() {
grid.restartFilter();
}
};
enabledPresets.setChecked(true);
grid.restartFilter();
}
@Override
public void mouseClicked(int x, int y, int button) {
grid.mouseClicked(x, y, button);
if (enabledPresets.contains(x, y)) {
enabledPresets.handleClick(x, y, button);
}
if (searchField.contains(x, y)) {
searchField.handleClick(x, y, button);
} else {
searchField.onGuiClick(x, y);
}
if (mouseSelection == null && (button == 0 || button == 1)) {
final ItemsGridSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null) {
mouseSelection = new MouseSelection(slot.itemIndex, grid.getItemRect(slot.itemIndex), button == 0);
}
}
}
protected void onItemsChanges() {}
@Override
public void mouseMovedOrUp(int x, int y, int button) {
searchField.mouseUp(x, y, button);
if (mouseSelection != null && (button == 0 || button == 1)) {
final ItemsGridSlot hoverSlot = grid.getSlotMouseOver(x, y);
if (hoverSlot != null && hoverSlot.itemIndex == mouseSelection.startIndex) {
setHidden(hoverSlot.getItemStack(), button == 0);
} else if (!mouseSelection.items.isEmpty()) {
for (ItemStack stack : mouseSelection.items) {
hideItem(stack, mouseSelection.append);
}
}
mouseSelection = null;
onItemsChanges();
}
}
protected void setHidden(final ItemStack stack, final boolean append) {
if (NEIClientUtils.shiftKey()) {
final List<ItemStack> items = grid.getItems();
for (int i = 0; i < items.size(); i++) {
if (stack.getItem().equals(items.get(i).getItem())) {
hideItem(items.get(i), append);
}
}
} else if (NEIClientUtils.controlKey()) {
final String modId = getModId(stack);
if (modId == null) {
hideItem(stack, append);
} else {
final List<ItemStack> items = grid.getItems();
for (int i = 0; i < items.size(); i++) {
final String mod = getModId(items.get(i));
if (mod != null && mod.equals(modId)) {
hideItem(items.get(i), append);
}
}
}
} else {
hideItem(stack, append);
}
}
protected void hideItem(final ItemStack stack, boolean append) {
if (append) {
preset.items.add(Preset.getIdentifier(stack));
} else {
preset.items.remove(Preset.getIdentifier(stack));
}
}
protected static String getModId(final ItemStack stack) {
try {
return GameRegistry.findUniqueIdentifierFor(stack.getItem()).modId;
} catch (Exception ignored) {}
return null;
}
@Override
public void mouseDragged(int x, int y, int button, long time) {
searchField.mouseDragged(x, y, button, time);
if (mouseSelection != null && (button == 0 || button == 1)) {
final ItemsGridSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null && slot.itemIndex != mouseSelection.endIndex) {
mouseSelection.endIndex = slot.itemIndex;
mouseSelection.items.clear();
final Rectangle4i rec = grid.getItemRect(slot.itemIndex);
final Rectangle4i sel = new Rectangle4i(
Math.min(rec.x, mouseSelection.startX),
Math.min(rec.y, mouseSelection.startY),
Math.max(rec.x, mouseSelection.startX) - Math.min(rec.x, mouseSelection.startX),
Math.max(rec.y, mouseSelection.startY) - Math.min(rec.y, mouseSelection.startY));
for (int ix = sel.x; ix <= sel.x + sel.w; ix += ItemsGrid.SLOT_SIZE) {
for (int iy = sel.y; iy <= sel.y + sel.h; iy += ItemsGrid.SLOT_SIZE) {
final ItemsGridSlot over = grid.getSlotMouseOver(ix, iy);
if (over != null) {
mouseSelection.items.add(over.getItemStack());
}
}
}
}
}
}
@Override
public void update() {
enabledPresets.w = 20;
enabledPresets.h = INPUT_HEIGHT;
enabledPresets.x = this.x;
enabledPresets.y = this.y + this.height - 2 - INPUT_HEIGHT;
searchField.w = this.width - enabledPresets.w - 3;
searchField.h = INPUT_HEIGHT;
searchField.x = enabledPresets.x + enabledPresets.w + 3;
searchField.y = enabledPresets.y;
grid.setGridSize(this.x, this.y, this.width, searchField.y - this.y);
grid.refresh(null);
}
@Override
public void draw(int mousex, int mousey, float frame) {
enabledPresets.draw(mousex, mousey);
searchField.draw(mousex, mousey);
RenderHelper.enableGUIStandardItemLighting();
GL11.glPushMatrix();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
grid.draw(mousex, mousey);
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
GL11.glPopMatrix();
RenderHelper.enableStandardItemLighting();
}
public List<String> handleTooltip(int mousex, int mousey, List<String> tooltip) {
final ItemsGridSlot over = grid.getSlotMouseOver(mousex, mousey);
if (over != null) {
tooltip = GuiContainerManager.itemDisplayNameMultiline(over.getItemStack(), null, true);
synchronized (GuiContainerManager.tooltipHandlers) {
for (IContainerTooltipHandler handler : GuiContainerManager.tooltipHandlers) {
tooltip = handler.handleItemTooltip(null, over.getItemStack(), mousex, mousey, tooltip);
}
}
if (!tooltip.isEmpty()) {
tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE); // add space after 'title'
}
} else if (enabledPresets.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.filter.tip"));
}
return tooltip;
}
@Override
public void keyTyped(char c, int keycode) {
searchField.handleKeyPress(keycode, c);
}
@Override
public void mouseScrolled(int x, int y, int scroll) {
if (grid.contains(x, y)) {
grid.shiftPage(-scroll);
}
}
}
@@ -12,20 +12,14 @@ import cpw.mods.fml.common.eventhandler.Event;
/**
* Event is posted every time the handler infos got registered or reloaded. During it, you can safely register your
* custom handler info.
*
* <br>
* This event does not have a result. {@link HasResult}<br>
* custom handler info. <br>
* This event does not have {@link HasResult result}.<br>
* <br>
* This event is fired on the {@link MinecraftForge#EVENT_BUS}.
*/
public class NEIRegisterHandlerInfosEvent extends Event {
public void registerHandlerInfo(String handlerName, String modName, String modId,
Consumer<HandlerInfo.Builder> builder) {
HandlerInfo.Builder b = new HandlerInfo.Builder(handlerName, modName, modId);
builder.accept(b);
HandlerInfo info = b.build();
public void registerHandlerInfo(HandlerInfo info) {
if (GuiRecipeTab.handlerMap.put(info.getHandlerName(), info) != null) {
NEIClientConfig.logger.info("Replaced handler info for {}", info.getHandlerName());
} else {
@@ -33,6 +27,14 @@ public class NEIRegisterHandlerInfosEvent extends Event {
}
}
public void registerHandlerInfo(String handlerName, String modName, String modId,
Consumer<HandlerInfo.Builder> builder) {
HandlerInfo.Builder b = new HandlerInfo.Builder(handlerName, modName, modId);
builder.accept(b);
HandlerInfo info = b.build();
registerHandlerInfo(info);
}
public void registerHandlerInfo(Class<? extends IRecipeHandler> handlerClazz, String modName, String modId,
Consumer<HandlerInfo.Builder> builder) {
registerHandlerInfo(handlerClazz.getName(), modName, modId, builder);
Loaded 100 of 177 files, more files were not shown because too many files have changed in this diff. Show more