Compare commits

...
189 Commits
Author SHA1 Message Date
slprimeandkoolkrafter5 57e865fc6f Custom Subsets in config; RecipeId Command (#691)
Co-authored-by: koolkrafter5 <[email protected]>
2025-08-16 18:56:59 +07:00
Dream Master 6dcd26a978 update 2025-08-16 18:39:01 +07:00
koolkrafter5 aeb59081d9 Information Handler (#695) 2025-08-16 18:24:40 +07:00
slprime ef8706ae38 Loading items after the player to ensure the hint cache works correctly in some mods (#687) 2025-08-16 07:38:24 +07:00
Dream Master b49d066231 update 2025-08-08 19:05:06 +07:00
slprime 594fbe6f79 Allowed fill crafting grid without all ingredients (#693) 2025-08-06 13:40:52 -04:00
koolkrafter5andEthryan 3edb85b317 Allow handlers to hide the favorite and overlay buttons via IMC (#678)
Co-authored-by: Ethryan <[email protected]>
2025-07-29 20:37:37 +07:00
TotallyNotOndre 5fd0a74363 Add ability to bookmark linked items (#674) 2025-07-26 07:42:34 +07:00
Dream Master 2ae94e94a0 update 2025-07-17 22:31:09 +07:00
TotallyNotOndre fa3adde3e6 Add ability to link Item in chat (#673) 2025-07-17 10:09:43 +07:00
slprime 56941cc45d Correctly used tools in favorites (#670) 2025-07-12 07:44:34 +02:00
slprimeandCaedis cd7d014704 Bookmarks Chains: Use active Item as preferred if exists (#664)
Co-authored-by: Caedis <[email protected]>
2025-07-11 14:36:10 +00:00
slprime 0634466851 Bookmarks Chains: Optimize GTTools (#667) 2025-07-11 14:33:14 +00:00
slprimeandCaedis b87e389132 Bookmarks Hotkeys: optimization thaumcraft recipes (#663)
Co-authored-by: Caedis <[email protected]>
2025-07-11 14:25:15 +00:00
slprimeandCaedis c788a07cf5 Bookmarks Chains Math: fix infinity loop (#662)
Co-authored-by: Caedis <[email protected]>
2025-07-11 16:21:32 +02:00
Martin Robertz 7d4ed91e86 update 2025-07-09 14:43:40 +02:00
slprime ca79cdd3c9 Disable play sound when crafting with gt tools (#659) 2025-07-08 15:41:42 +02:00
slprime 3a0722adc2 Update Bookmark Chain Tooltip Cache (#657) 2025-07-01 05:52:46 -05:00
slprime 77fa3bafd6 Autocrafting Improvement (#655) 2025-06-27 08:32:54 -05:00
Martin Robertz e23e542aac update 2025-06-22 18:27:06 +02:00
slprime 7ec2ad132e Tools in autocrafting (#653) 2025-06-22 17:49:20 +02:00
slprime 7b43826d05 Clear Crafting Grid after autocrafting (#652) 2025-06-20 09:25:02 -05:00
slprime c7a18dd288 Fix Item Tooltip (#651) 2025-06-19 16:22:12 +00:00
slprime 4fb1d7b1d8 Add Autocrafting Option (#649) 2025-06-16 23:30:10 +02:00
AlexdoruandMartin Robertz 081071562f Fix WorldClient leak in ItemModSpawner and ClientHandler (#637)
Co-authored-by: Martin Robertz <[email protected]>
2025-06-15 12:09:55 +02:00
Martin Robertz 81e05dc030 update 2025-06-14 00:08:03 +02:00
slprime efc54fb662 Add Translation to Item Count Details (#647) 2025-06-13 23:46:32 +02:00
slprime 6e75124ea2 Set Minimum Zoom Size (#648) 2025-06-13 23:46:22 +02:00
slprime 2c9f17983a Fix Paged Tooltip with Line Handler (#645) 2025-06-13 23:46:05 +02:00
slprime e0b6d62143 Add Bookmark items with recipe Option (#644) 2025-06-13 23:45:50 +02:00
Martin Robertz 3d5e9aecf0 update 2025-06-08 11:59:07 +02:00
FalsePattern 07cec30f3e allow setOverrideName to remove name overrides (#643) 2025-06-06 14:11:33 +00:00
koolkrafter5 f3add01e74 Too Many (Hidden) Items (#641) 2025-06-03 08:26:44 +02:00
Maya d469fdc90d update 2025-06-01 18:05:04 -06:00
abel1502 763d9b8cd4 Fix Incorrect handleDragNDrop Implementation (#639) 2025-06-01 18:04:55 -06:00
Jason Mitchell 55ccb70c8b Update JarJar detection so it works when jarjar is loaded but rfb is not setup properly. (#636) 2025-05-26 16:49:52 -04:00
2e1c7764b7 Ignore prefix when SearchMode is ALWAYS (#635)
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: Maya <[email protected]>
2025-05-26 15:55:37 +00:00
Martin Robertz 9daa9cabb2 update 2025-05-26 08:46:40 +02:00
Jason Mitchell 74dc7c34d9 Don't exclude locals/frames when transforming. (#632) 2025-05-18 17:50:06 -05:00
slprimeandslprime e5f85e32ec Add Settings: Dynamic Font Size (#631)
Co-authored-by: slprime <[email protected]>
2025-05-18 11:18:12 -05:00
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
querns 1ed004e619 Holding ALT now increases bookmark stack increase in increments of output item's stack size (#418) 2023-09-09 09:22:33 +02:00
Nico Spiske 153da523d6 Hide bookmarkItemPulling button if currently opened gui is not supported (#419)
* [minor] hide pullBookmarkedItems button if open container is not supported

* [minor] spotless apply
2023-09-08 07:16:37 +02:00
miozune c732361bbc More readable packet IDs (#417) 2023-09-06 11:05:15 +02:00
miozune bdb206b45d Fix world specific settings on MP being also specific to dimension (#414) 2023-08-18 21:42:20 +02:00
Raven Szewczyk aa44a97f80 Partial fix for the NEI custom diagram in recipe tooltip issue (#413) 2023-08-17 10:36:15 +02:00
Nico Spiske 00c4411ec5 Pull bookmarked items from container to player inventory (#410)
* [major] first potential version for basic chests

* [major] added api to register chest/inventory guis for bookmark item pulling

* [minor] added hotkey to pull all bookmarked items

* [major] finished

* [minor] spotless apply

* [minor] removed bak file

* [minor] function cleanup

* [minor] fixed bookmarks being set to 0

* [minor] little oversight

* [minor] private attribute and curly brackets
2023-08-07 15:29:05 +02:00
miozune 4f23d21d37 Fix recipe tooltip crash with BetterQuesting (#409)
* updateBuildScript

* Fix recipe tooltip crash with BetterQuesting
2023-07-28 13:20:45 +02:00
8569431e1d Recipe tooltip fixes (#402)
* Unconditionally override Minecraft.currentScreen when drawing tooltips

* Fix bad item lighting in recipe tooltips

* Update buildscript

* Fix NEI ignoring handler switching on click

Handlers might call Minecraft#displayGuiScreen and overwrite Minecraft.currentScreen, but the height hack would unconditionally undo this again.

* spotlessApply (#404)

Co-authored-by: GitHub GTNH Actions <>

* Attempt to fix CME when opening recipes immediately after load (#403)

* Rename the internal private class HeightHack->CompatibilityHacks to better reflect the new usage.

* Move trueGui assignment down.

* Fix overlay button y offsets

* Fix wrong recipe tooltip background rendering

* Apply spotless

---------

Co-authored-by: Wilhelm Schuster <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-07-23 08:04:31 +02:00
Wilhelm Schuster 5b9c27e253 Fix potential NPE when calling ItemMobSpawner#loadSpawners. (#405) 2023-07-16 14:29:31 +02:00
Raven Szewczyk d613d06471 Attempt to fix CME when opening recipes immediately after load (#403) 2023-07-16 09:00:35 +01:00
65ffbad491 Show a full recipe widget in item tooltips for bookmarked recipes (#398)
* Update buildscript

* Show a full recipe widget in item tooltips for bookmarked recipes

* Make recipe tooltips configurable and only show in the bookmarks panel

* Fix layout relative to tooltip boxes

* Fix wildcard import

* spotlessApply (#401)

Co-authored-by: GitHub GTNH Actions <>

* Fix handler tooltip offsets for new&legacy handlers

* Fix render order to draw crafting tooltips on top of container manager buttons

* Fix wrong mouse Y half-point calculation

* Allow saving recipes with empty item ingredient lists to bookmarks (e.g. fluid-only)

* Fix waila vs. non-waila tooltip offsets

Co-authored-by: Wilhelm Schuster <[email protected]>

---------

Co-authored-by: Wilhelm Schuster <[email protected]>
2023-07-10 17:38:07 +01:00
Wilhelm Schuster 885609720e Extend height hack for legacy recipe handlers (#395)
* Store heighthackhandlers.cfg as an internal asset instead of an array of strings

Is copied into the config directory upon first launch. Also, comments
are now allowed (only from the beginning of the file).

* Store serialhandlers.cfg as an internal asset instead of an array of strings

Is copied into the config directory upon first launch. Also, comments
are now allowed (only from the beginning of the file).

Removes GTNH-specific code to be replaced with a configuration file.

* Extend the height hack to also cover guiTop and getRecipePosition

Certain legacy recipe handlers hardcode even more of the NEI recipe
screen layout, requiring only the singular recipe handler switcher
widget at the top, whereas this improved NEI moves the recipe pager to
the top as well expecting recipe handler to move down another 16px. One
such mod that breaks is Immersive Engineering. To fix it we move the top
edge of the gui (guiTop) down by 16px so that the old gap calculation
works correctly. This required special handling in getRecipePosition()
and refreshSlots().

* Fix Immersive Engineering recipe handlers

* Fix Ex Nihilo recipe handlers

* Fix Thermal Expansion recipe handlers

These handlers expect only two recipes to be displayed at a time. This can only be fixed through asm AFAICT.
2023-07-08 23:23:19 +02:00
194 changed files with 20830 additions and 6514 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
+10 -2
View File
@@ -1,6 +1,7 @@
.gradle
.settings
/.idea/
/.vscode/
/run/
/build/
/eclipse/
@@ -25,6 +26,13 @@ whitelist.json
*.iml
*.ipr
*.iws
src/main/resources/mixins.*.json
src/main/resources/mixins.*([!.]).json
*.bat
.DS_Store
*.DS_Store
!gradlew.bat
.factorypath
addon.local.gradle
addon.local.gradle.kts
addon.late.local.gradle
addon.late.local.gradle.kts
layout.json
+54 -8
View File
@@ -22,21 +22,67 @@ If you have issues with NEI outside of the GTNH modpack you may report them in t
* Cycle between Recipe, Utility, and Cheat mode by ctrl clicking on the Wrench Icon
* GT5u Tools/Items and GT6 tools should now properly work with the Overlay Recipe Transfer
### Information Page Handler
Want to add some information about a block or item without making a massive tooltip for it? You can add information about any block or item by registering it in the Information Handler.
Information page(s) are displayed when either the uses or recipes of a matching item are searched. All matching items will cycle at the top of the information page.
Your mod can call:
```java
FMLInterModComms.sendMessage("NotEnoughItems", "addItemInfo", nbt);
```
Where nbt is an NBTTagCompound formatted as described below.
| Tag | Type | Description |
|------------------|----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `filter` | String | A string filter to match what items should return this information page.<br/>modname:itemname, metadata, Ore Dictionary tags, and regex can all be used. The full format may be seen in `config/NEI/collapsibleitems.cfg`. |
| `page` / `pages` | String / String NBTTagList | The actual text to display. See below for differences between single and multi-page messages.<br/>Both formats will automatically translate provided strings. |
#### Single Page Format
Use the `"page"` string tag when you only want to add one page of information:
```java
NBTTagCompound tag = new NBTTagCompound();
tag.setString("filter", "minecraft:log 3");
tag.setString("page", "Exotic wood found in tropical climates.");
FMLInterModComms.sendMessage("NotEnoughItems", "addItemInfo", tag);
```
#### Multiple Page Format
Use the `"pages"` tag as an `NBTTagList` of strings when you want more than one page:
```java
NBTTagCompound tag = new NBTTagCompound();
tag.setString("filter", "minecraft:diamond_sword");
NBTTagList pages = new NBTTagList();
pages.appendTag(new NBTTagString("A powerful melee weapon."));
pages.appendTag(new NBTTagString("Can be enchanted for extra effects."));
tag.setTag("pages", pages);
FMLInterModComms.sendMessage("NotEnoughItems", "addItemInfo", tag);
```
* Each list entry is one page.
* Pages will appear in NEI with buttons to scroll through them.
#### Item Matching
All items that match `filter` will show your information page. See `config/NEI/collapsibleitems.cfg` for the full filter format.
#### Item Information Config File
If you're a modpack creator and want to make custom item information pages, they can easily be added in `config/NEI/informationpages.cfg`, which has a few more examples.
## Other items of note:
* Remove TMI style
* Removed inventory Load/Save state
## Development
Before launching, you need to add
```
-Dfml.coreMods.load=codechicken.nei.asm.NEICorePlugin
```
as a command line argument to the VM.
## 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 -1509
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.7:dev')
implementation('com.github.GTNewHorizons:GTNHLib:0.6.39: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: UniMixins 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.1.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
+20 -13
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,10 +85,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# 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"'
# 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
@@ -133,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.
@@ -144,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
@@ -152,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
@@ -197,11 +200,15 @@ if "$cygwin" || "$msys" ; then
done
fi
# 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.
# 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 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"
}
}
+8 -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,12 +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.41'
}
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;
}
}
@@ -0,0 +1,34 @@
package codechicken.nei;
import java.util.HashMap;
import net.minecraft.client.gui.inventory.GuiChest;
import net.minecraft.client.gui.inventory.GuiContainer;
import codechicken.nei.api.API;
import codechicken.nei.api.IBookmarkContainerHandler;
public class BookmarkContainerInfo {
private static final HashMap<Class<? extends GuiContainer>, IBookmarkContainerHandler> handlerMap = new HashMap<>();
public static void registerBookmarkContainerHandler(Class<? extends GuiContainer> classz,
IBookmarkContainerHandler handler) {
handlerMap.put(classz, handler);
}
public static boolean hasBookmarkContainerHandler(Class<? extends GuiContainer> classz) {
return handlerMap.containsKey(classz);
}
public static IBookmarkContainerHandler getBookmarkContainerHandler(GuiContainer gui) {
if (gui != null) {
return handlerMap.get(gui.getClass());
}
return null;
}
public static void load() {
API.registerBookmarkContainerHandler(GuiChest.class, new DefaultBookmarkContainerHandler());
}
}
File diff suppressed because it is too large. Load diff
+137 -105
View File
@@ -1,78 +1,66 @@
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.Arrays;
import java.util.Collection;
import java.util.Collections;
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;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiErrorScreen;
import net.minecraft.client.gui.GuiMainMenu;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiSelectWorld;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.launchwrapper.Launch;
import net.minecraft.world.World;
import net.minecraftforge.client.event.GuiOpenEvent;
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[] defaultSerialHandlers = {
"WayofTime.alchemicalWizardry.client.nei.NEIAlchemyRecipeHandler" };
private static String[] defaultHeightHackHandlerRegex = { "buildcraft.compat.nei.*",
"cofh.thermalexpansion.plugins.nei.handlers.*", "crazypants.enderio.nei.*",
"forestry.factory.recipes.nei.*", "ic2.neiIntegration.core.recipehandler.*", "mariculture.plugins.nei.*",
"redgear.brewcraft.plugins.nei.*", "tconstruct.plugins.nei.*",
"WayofTime.alchemicalWizardry.client.nei.*", };
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;
public void addSMPMagneticItem(int i, World world) {
WorldClient cworld = (WorldClient) world;
@@ -155,50 +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);
Collection<String> toSave = Loader.isModLoaded("dreamcraft") ? Collections.singletonList("")
: Arrays.asList(defaultSerialHandlers);
IOUtils.writeLines(toSave, "\n", 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 = new HashSet<>(IOUtils.readLines(reader));
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);
Collection<String> toSave = Arrays.asList(defaultHeightHackHandlerRegex);
IOUtils.writeLines(toSave, "\n", 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().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() {
@@ -215,53 +230,60 @@ 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() {
final boolean jarjar = Launch.blackboard.getOrDefault("jarjar.rfbPluginLoaded", Boolean.FALSE) == Boolean.TRUE;
if (!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);
NEIClientConfig.pluginsList.addAll(classDiscoverer.findClasses());
NEIClientConfig.logger
.info("Loading NEI Plugins via ClassDiscoverer: " + NEIClientConfig.pluginsList.size());
int ordering;
} 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();
NEIClientConfig.logger.info("Loading NEI Plugins via JarJar: " + NEIClientConfig.pluginsList.size());
}
}
@@ -285,18 +307,19 @@ public class ClientHandler {
if (mc.currentScreen == null) NEIController.processCreativeCycling(mc.thePlayer.inventory);
updateMagnetMode(mc.theWorld, mc.thePlayer);
} else {
lastworld = null;
}
}
GuiScreen gui = mc.currentScreen;
if (gui != lastGui) {
if (gui instanceof GuiMainMenu) lastworld = null;
else if (gui instanceof GuiSelectWorld) NEIClientConfig.reloadSaves();
else if (gui == null) {
/* prevent WorldClient reference being held in the Gui */
NEIController.manager = null;
}
@SubscribeEvent
public void onGuiScreen(GuiOpenEvent event) {
if (event.gui instanceof GuiSelectWorld) {
NEIClientConfig.reloadSaves();
} else if (event.gui == null) {
/* prevent WorldClient reference being held in the Gui */
NEIController.manager = null;
}
lastGui = gui;
}
@SubscribeEvent
@@ -309,21 +332,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();
ItemMobSpawner.clearEntityReferences();
}
}
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);
}
lastworld = world;
}
}
@@ -350,9 +381,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,47 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.LinkedList;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import codechicken.nei.api.IBookmarkContainerHandler;
public class DefaultBookmarkContainerHandler implements IBookmarkContainerHandler {
@Override
public void pullBookmarkItemsFromContainer(GuiContainer guiContainer, ArrayList<ItemStack> bookmarkItems) {
FastTransferManager manager = new FastTransferManager();
LinkedList<ItemStack> containerStacks = manager.saveContainer(guiContainer.inventorySlots);
for (ItemStack bookmarkItem : bookmarkItems) {
int bookmarkSizeBackup = bookmarkItem.stackSize;
for (int i = 0; i < containerStacks.size() - 4 * 9; i++) { // Last 36 slots are player inventory
ItemStack containerItem = containerStacks.get(i);
if (containerItem == null) {
continue;
}
if (bookmarkItem.isItemEqual(containerItem)) {
if (bookmarkItem.stackSize <= 0) {
break;
}
int transferAmount = Math.min(bookmarkItem.stackSize, containerItem.stackSize);
manager.transferItems(guiContainer, i, transferAmount);
bookmarkItem.stackSize -= transferAmount;
if (bookmarkItem.stackSize == 0) {
break;
}
}
}
bookmarkItem.stackSize = bookmarkSizeBackup;
}
}
}
@@ -184,6 +184,12 @@ public class FastTransferManager {
moveOutputSet(window, fromSlot, toSlot);
}
public void transferItems(GuiContainer window, int fromSlot, int itemCount) {
for (int i = 0; i < itemCount; i++) {
transferItem(window, fromSlot);
}
}
public void moveOutputSet(GuiContainer window, int fromSlot, int toSlot) {
if (NEIClientUtils.getHeldItem() != null) return;
@@ -0,0 +1,251 @@
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.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
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 Set<NBTTagCompound> tools = new HashSet<>();
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);
if (NEIServerUtils.isItemTool(stack)) {
tools.add(itemStackNBT);
}
}
} 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));
}
if (recipeId != null) {
return recipeId;
}
if (NEIServerUtils.isItemTool(stack)
&& (stack.stackTagCompound == null || !stack.stackTagCompound.hasKey("GT.ToolStats"))) {
for (NBTTagCompound nbt : tools) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(stack, StackInfo.loadFromNBT(nbt))) {
return items.get(nbt);
}
}
}
}
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 (NEIServerUtils.isItemTool(stack)) {
tools.add(itemStackNBT);
}
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("Failed 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;
}
}
+192 -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,8 @@ 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.recipe.InformationHandler;
import codechicken.nei.search.TooltipFilter;
public class ItemList {
@@ -36,11 +45,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 +71,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 +95,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 +120,10 @@ public class ItemList {
this.filters = filters;
}
public AllMultiItemFilter(ItemFilter... filters) {
this(new LinkedList<>(Arrays.asList(filters)));
}
public AllMultiItemFilter() {
this(new LinkedList<>());
}
@@ -91,9 +131,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 +156,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 +174,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 +199,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 +213,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 +229,127 @@ 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());
}
// Generate itemlist, permutations, orders, collapsibleitems, and informationhandler stacks
@Override
@SuppressWarnings("unchecked")
public void execute() {
// System.out.println("Executing NEI Item Loading");
if (!NEIClientConfig.isEnabled() || NEIClientUtils.mc().thePlayer == null) 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();
InformationHandler.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);
InformationHandler.populateStacks(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 +357,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 +408,11 @@ public class ItemList {
}
if (interrupted()) return;
ItemSorter.sort(filtered);
filtered.sort(Comparator.comparingInt(ItemList.ordering::get));
if (interrupted()) return;
ItemPanel.updateItemList(filtered);
}
};
@@ -16,32 +16,31 @@ import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntityMobSpawner;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IIcon;
import net.minecraft.world.World;
import net.minecraftforge.client.MinecraftForgeClient;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class ItemMobSpawner extends ItemBlock {
private static Map<Integer, EntityLiving> entityHashMap;
private static Map<Integer, String> IDtoNameMap;
private static final Map<Integer, EntityLiving> entityHashMap = new HashMap<>();
private static final Map<Integer, String> IDtoNameMap = new HashMap<>();
public static int idPig;
private static boolean loaded;
public ItemMobSpawner() {
super(Blocks.mob_spawner);
hasSubtypes = true;
MinecraftForgeClient.registerItemRenderer(this, new SpawnerRenderer());
entityHashMap = new HashMap<>();
IDtoNameMap = new HashMap<>();
}
/**
* These are ASM translated from BlockMobSpawner
*/
public static int placedX;
public static int placedY;
public static int placedZ;
@@ -68,23 +67,26 @@ public class ItemMobSpawner extends ItemBlock {
return false;
}
@SideOnly(Side.CLIENT)
@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) {
meta = idPig;
}
Entity e = getEntity(meta);
list.add("\u00A7" + (e instanceof IMob ? "4" : "3") + IDtoNameMap.get(meta));
list.add(
(e instanceof IMob ? EnumChatFormatting.DARK_RED : EnumChatFormatting.DARK_AQUA)
+ IDtoNameMap.get(meta));
}
public static EntityLiving getEntity(int ID) {
EntityLiving e = entityHashMap.get(ID);
if (e == null) {
loadSpawners();
Class<?> clazz = EntityList.IDtoClassMapping.get(ID);
World world = NEIClientUtils.mc().theWorld;
loadSpawners(world);
Class<?> clazz = (Class<?>) EntityList.IDtoClassMapping.get(ID);
try {
e = (EntityLiving) clazz.getConstructor(new Class[] { World.class }).newInstance(world);
} catch (Throwable t) {
@@ -98,43 +100,35 @@ public class ItemMobSpawner extends ItemBlock {
return e;
}
public static void clearEntityReferences(World newWorld) {
entityHashMap.values().removeIf(e -> e.worldObj != newWorld);
public static void clearEntityReferences() {
entityHashMap.clear();
}
private void setDefaultTag(ItemStack itemstack) {
if (!IDtoNameMap.containsKey(itemstack.getItemDamage())) itemstack.setItemDamage(idPig);
}
public static void loadSpawners(World world) {
public static void loadSpawners() {
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()) {
if (!EntityLiving.class.isAssignableFrom(eclass)) continue;
try {
EntityLiving entityliving = (EntityLiving) eclass.getConstructor(new Class[] { World.class })
.newInstance(world);
entityliving.isChild();
int id = classToIDMapping.get(eclass);
String name = classToStringMapping.get(eclass);
for (Map.Entry<Class<? extends Entity>, String> entry : EntityList.classToStringMapping.entrySet()) {
final Class<? extends Entity> clazz = entry.getKey();
if (EntityLiving.class.isAssignableFrom(clazz)) {
Integer id = (Integer) EntityList.classToIDMapping.get(clazz);
if (id == null) continue;
String name = entry.getValue();
if (name == null) continue;
if (name.equals("EnderDragon")) continue;
IDtoNameMap.put(id, name);
if (name.equals("Pig")) idPig = id;
} catch (Throwable ignored) {}
if (clazz != EntityPig.class || name.equals("Pig")) {
IDtoNameMap.put(id, name);
}
}
}
IDtoNameMap.entrySet()
.removeIf(e -> getEntity(e.getKey()).getClass() == EntityPig.class && !e.getValue().equals("Pig"));
}
@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 && this.availableAreaWidth >= SLOT_SIZE * 2
&& (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) {}
}
+348 -143
View File
@@ -1,12 +1,10 @@
package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.drawRect;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nullable;
import java.util.Objects;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.ScaledResolution;
@@ -17,16 +15,248 @@ import net.minecraft.client.shader.Framebuffer;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL30;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.guihook.GuiContainerManager;
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;
@@ -48,27 +278,28 @@ public class ItemsGrid {
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;
}
}
@@ -105,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;
@@ -147,7 +386,13 @@ public class ItemsGrid {
}
protected void onGridChanged() {
refreshBuffer = true;
if (this.screenCapture != null) {
this.screenCapture.refreshBuffer();
}
}
public void onItemsChanged() {
onGridChanged();
}
public void refresh(GuiContainer gui) {
@@ -163,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)) {
@@ -183,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--;
@@ -194,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) {
@@ -218,77 +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));
}
}
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
protected void afterDrawItems(int mousex, int mousey, M mouseContext) {
for (T item : getMask()) {
item.afterDraw(getSlotRect(item.slotIndex), mouseContext);
}
}
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);
}
public void update() {}
private Framebuffer getFrameBuffer() {
protected void drawItems() {
if (framebuffer == null) {
framebuffer = new Framebuffer(1, 1, true);
framebuffer.setFramebufferColor(0.0F, 0.0F, 0.0F, 0.0F);
for (T item : getMask()) {
item.drawItem(getSlotRect(item.slotIndex));
}
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) {
@@ -296,37 +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();
}
afterDrawItems(mousex, mousey, mouseContext);
}
public void setVisible() {
@@ -335,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;
}
}
+192 -79
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;
@@ -138,16 +136,14 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public void onPreDraw(GuiContainer gui) {
if (!isHidden() && isEnabled() && gui instanceof InventoryEffectRenderer) // Reset the gui to the center of the
// screen, for potion effect offsets
// etc
{
// Reset the gui to the center of the screen, for potion effect offsets etc
if (isEnabled() && gui instanceof InventoryEffectRenderer) {
gui.guiLeft = (gui.width - gui.xSize) / 2;
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 +164,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 +189,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,12 +229,11 @@ 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;
}
@@ -248,12 +259,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;
}
@@ -281,10 +292,33 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
}
@Override
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
public void postRenderTooltips(GuiContainer gui, int mousex, int mousey, List<String> tooltip) {
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) {
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)) {
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;
}
@@ -301,29 +335,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();
@@ -346,9 +406,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) {
@@ -370,7 +432,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
@@ -394,7 +457,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
@@ -413,7 +479,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public boolean onButtonPress(boolean rightclick) {
NEIClientConfig.toggleBooleanSetting("inventory.bookmarksEnabled");
NEIClientConfig.toggleBooleanSetting("inventory.bookmarks.enabled");
return true;
}
@@ -427,9 +493,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
@@ -605,12 +705,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);
@@ -642,14 +742,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();
}
@@ -658,13 +759,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) {
@@ -679,6 +780,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
if (canPerformAction("delete")) addWidget(delete);
}
addWidget(itemZoom);
if (visiblity.showSubsetDropdown) {
// Bookmarks or Subset/dropdown
addWidget(dropDown);
@@ -713,7 +816,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;
}
@@ -723,7 +828,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. */
@@ -746,17 +851,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) {
@@ -812,9 +919,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));
}
}
}
+40 -31
View File
@@ -1,5 +1,8 @@
package codechicken.nei;
import static codechicken.nei.PacketIDs.C2S;
import static codechicken.nei.PacketIDs.S2C;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiInventory;
import net.minecraft.item.ItemStack;
@@ -20,37 +23,37 @@ public class NEICPH implements IClientPacketHandler {
@Override
public void handlePacket(PacketCustom packet, Minecraft mc, INetHandlerPlayClient netHandler) {
switch (packet.getType()) {
case 1:
case S2C.SEND_SERVER_SIDE_CHECK:
handleSMPCheck(packet.readUByte(), packet.readString(), mc.theWorld);
break;
case 10:
case S2C.SEND_LOGIN_STATE:
handleLoginState(packet);
break;
case 11:
case S2C.SEND_ACTION_DISABLED:
handleActionDisabled(packet);
break;
case 12:
case S2C.SEND_ACTION_ENABLED:
handleActionEnabled(packet);
break;
case 13:
case S2C.SEND_MAGNETIC_ITEM:
ClientHandler.instance().addSMPMagneticItem(packet.readInt(), mc.theWorld);
break;
case 14:
case S2C.SEND_GAME_MODE:
handleGamemode(mc, packet.readUByte());
break;
case 21:
case S2C.OPEN_ENCHANTMENT_GUI:
ClientUtils.openSMPGui(
packet.readUByte(),
new GuiEnchantmentModifier(mc.thePlayer.inventory, mc.theWorld, 0, 0, 0));
break;
case 23:
case S2C.SET_CREATIVE_PLUS_MODE:
if (packet.readBoolean()) ClientUtils.openSMPGui(
packet.readUByte(),
new GuiExtendedCreativeInv(
new ContainerCreativeInv(mc.thePlayer, new ExtendedCreativeInv(null, Side.CLIENT))));
else mc.displayGuiScreen(new GuiInventory(mc.thePlayer));
break;
case 24:
case S2C.OPEN_POTION_GUI:
ClientUtils.openSMPGui(packet.readUByte(), new GuiPotionCreator(mc.thePlayer.inventory));
break;
}
@@ -102,7 +105,7 @@ public class NEICPH implements IClientPacketHandler {
try {
ClientHandler.instance().loadWorld(world, true);
NEIClientConfig.setHasSMPCounterPart(true);
NEIClientConfig.loadWorld(getSaveName(worldName));
NEIClientConfig.loadWorld(getSaveName());
sendRequestLoginInfo();
} catch (Exception e) {
NEIClientConfig.logger.error("Error handling SMP Check", e);
@@ -110,14 +113,14 @@ public class NEICPH implements IClientPacketHandler {
}
}
private static String getSaveName(String worldName) {
private static String getSaveName() {
if (Minecraft.getMinecraft().isSingleplayer()) return "local/" + ClientUtils.getWorldSaveName();
return "remote/" + ClientUtils.getServerIP().replace(':', '~') + "/" + worldName;
return "remote/" + ClientUtils.getServerIP().replace(':', '~');
}
public static void sendGiveItem(ItemStack spawnstack, boolean infinite, boolean doSpawn) {
PacketCustom packet = new PacketCustom(channel, 1);
PacketCustom packet = new PacketCustom(channel, C2S.GIVE_ITEM);
packet.writeItemStack(spawnstack, true);
packet.writeBoolean(infinite);
packet.writeBoolean(doSpawn);
@@ -125,7 +128,7 @@ public class NEICPH implements IClientPacketHandler {
}
public static void sendDeleteAllItems() {
PacketCustom packet = new PacketCustom(channel, 4);
PacketCustom packet = new PacketCustom(channel, C2S.DELETE_ALL_ITEMS);
packet.sendToServer();
}
@@ -139,18 +142,18 @@ public class NEICPH implements IClientPacketHandler {
sendSetSlot(slot, item, false);
}
PacketCustom packet = new PacketCustom(channel, 11);
PacketCustom packet = new PacketCustom(channel, C2S.REQUEST_CONTAINER_CONTENTS);
packet.sendToServer();
}
public static void sendRequestContainer() {
PacketCustom packet = new PacketCustom(channel, 16);
PacketCustom packet = new PacketCustom(channel, C2S.REQUEST_CONTAINER);
packet.writeInt(Minecraft.getMinecraft().thePlayer.openContainer.getInventory().size());
packet.sendToServer();
}
public static void sendSetSlot(int slot, ItemStack stack, boolean container) {
PacketCustom packet = new PacketCustom(channel, 5);
PacketCustom packet = new PacketCustom(channel, C2S.SET_SLOT);
packet.writeBoolean(container);
packet.writeShort(slot);
packet.writeItemStack(stack);
@@ -158,38 +161,44 @@ public class NEICPH implements IClientPacketHandler {
}
private static void sendRequestLoginInfo() {
PacketCustom packet = new PacketCustom(channel, 10);
PacketCustom packet = new PacketCustom(channel, C2S.REQUEST_LOGIN_INFO);
packet.sendToServer();
}
public static void sendToggleMagnetMode() {
PacketCustom packet = new PacketCustom(channel, 6);
PacketCustom packet = new PacketCustom(channel, C2S.TOGGLE_MAGNET);
packet.sendToServer();
}
public static void sendSetTime(int hour) {
PacketCustom packet = new PacketCustom(channel, 7);
PacketCustom packet = new PacketCustom(channel, C2S.SET_TIME);
packet.writeByte(hour);
packet.sendToServer();
}
public static void sendHeal() {
PacketCustom packet = new PacketCustom(channel, 8);
PacketCustom packet = new PacketCustom(channel, C2S.HEAL);
packet.sendToServer();
}
public static void sendToggleRain() {
PacketCustom packet = new PacketCustom(channel, 9);
PacketCustom packet = new PacketCustom(channel, C2S.TOGGLE_RAIN);
packet.sendToServer();
}
public static void sendChatLink(ItemStack stackover) {
PacketCustom packet = new PacketCustom(channel, C2S.SEND_CHAT_ITEM_LINK);
packet.writeItemStack(stackover);
packet.sendToServer();
}
public static void sendOpenEnchantmentWindow() {
PacketCustom packet = new PacketCustom(channel, 21);
PacketCustom packet = new PacketCustom(channel, C2S.REQUEST_ENCHANTMENT_GUI);
packet.sendToServer();
}
public static void sendModifyEnchantment(int enchID, int level, boolean add) {
PacketCustom packet = new PacketCustom(channel, 22);
PacketCustom packet = new PacketCustom(channel, C2S.MODIFY_ENCHANTMENT);
packet.writeByte(enchID);
packet.writeByte(level);
packet.writeBoolean(add);
@@ -197,30 +206,30 @@ public class NEICPH implements IClientPacketHandler {
}
public static void sendSetPropertyDisabled(String name, boolean enable) {
PacketCustom packet = new PacketCustom(channel, 12);
PacketCustom packet = new PacketCustom(channel, C2S.CHANGE_PROPERTY);
packet.writeString(name);
packet.writeBoolean(enable);
packet.sendToServer();
}
public static void sendGamemode(int mode) {
new PacketCustom(channel, 13).writeByte(mode).sendToServer();
new PacketCustom(channel, C2S.SET_GAME_MODE).writeByte(mode).sendToServer();
}
public static void sendCreativeInv(boolean open) {
PacketCustom packet = new PacketCustom(channel, 23);
PacketCustom packet = new PacketCustom(channel, C2S.SET_CREATIVE_PLUS_MODE);
packet.writeBoolean(open);
packet.sendToServer();
}
public static void sendCreativeScroll(int steps) {
PacketCustom packet = new PacketCustom(channel, 14);
PacketCustom packet = new PacketCustom(channel, C2S.CYCLE_CREATIVE_INV);
packet.writeInt(steps);
packet.sendToServer();
}
public static void sendMobSpawnerID(int x, int y, int z, String mobtype) {
PacketCustom packet = new PacketCustom(channel, 15);
PacketCustom packet = new PacketCustom(channel, C2S.SEND_MOB_SPAWNER_ID);
packet.writeCoord(x, y, z);
packet.writeString(mobtype);
packet.sendToServer();
@@ -231,13 +240,13 @@ public class NEICPH implements IClientPacketHandler {
InventoryUtils.readItemStacksFromTag(
potionStore,
NEIClientConfig.global.nbt.getCompoundTag("potionStore").getTagList("items", 10));
PacketCustom packet = new PacketCustom(channel, 24);
PacketCustom packet = new PacketCustom(channel, C2S.REQUEST_POTION_GUI);
for (ItemStack stack : potionStore) packet.writeItemStack(stack);
packet.sendToServer();
}
public static void sendDummySlotSet(int slotNumber, ItemStack stack) {
PacketCustom packet = new PacketCustom(channel, 25);
PacketCustom packet = new PacketCustom(channel, C2S.SET_DUMMY_SLOT);
packet.writeShort(slotNumber);
packet.writeItemStack(stack, true);
packet.sendToServer();
File diff suppressed because it is too large. Load diff
+138 -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);
@@ -333,6 +370,10 @@ public class NEIClientUtils extends NEIServerUtils {
else sendCommand(getStringSetting("command.heal"), mc().thePlayer.getCommandSenderName());
}
public static void sendChatItemLink(ItemStack stackover) {
if (hasSMPCounterPart()) NEICPH.sendChatLink(stackover);
}
public static void toggleMagnetMode() {
if (hasSMPCounterPart()) NEICPH.sendToggleMagnetMode();
}
@@ -367,18 +408,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 +440,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 +479,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 +487,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 +514,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 +526,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);
}
}
@@ -11,16 +11,22 @@ import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.inventory.SlotCrafting;
import net.minecraft.item.ItemStack;
import net.minecraftforge.client.ClientCommandHandler;
import codechicken.core.CommonUtils;
import codechicken.nei.api.API;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.IInfiniteItemHandler;
import codechicken.nei.api.INEIGuiHandler;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.commands.CommandBookmarkAdd;
import codechicken.nei.commands.CommandRecipeId;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.guihook.IContainerSlotClickHandler;
import codechicken.nei.recipe.GuiRecipe;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class NEIController implements IContainerSlotClickHandler, IContainerInputHandler {
@@ -39,6 +45,8 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
public static void load() {
GuiContainerManager.addSlotClickHandler(instance);
GuiContainerManager.addInputHandler(instance);
if (CommonUtils.isClient()) registerClientCommands();
}
public static void load(GuiContainer gui) {
@@ -56,6 +64,12 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
return gui.field_147007_t && gui.field_147008_s.size() > 1;
}
@SideOnly(Side.CLIENT)
public static void registerClientCommands() {
ClientCommandHandler.instance.registerCommand(new CommandBookmarkAdd());
ClientCommandHandler.instance.registerCommand(new CommandRecipeId());
}
public static void updateUnlimitedItems(InventoryPlayer inventory) {
if (!NEIClientConfig.canPerformAction("item") || !NEIClientConfig.hasSMPCounterPart()) return;
@@ -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;
}
}
+39 -28
View File
@@ -1,5 +1,8 @@
package codechicken.nei;
import static codechicken.nei.PacketIDs.C2S;
import static codechicken.nei.PacketIDs.S2C;
import java.util.LinkedList;
import java.util.Set;
@@ -28,66 +31,73 @@ public class NEISPH implements IServerPacketHandler {
if (!NEIServerConfig.authenticatePacket(sender, packet)) return;
switch (packet.getType()) {
case 1:
case C2S.GIVE_ITEM:
handleGiveItem(sender, packet);
break;
case 4:
case C2S.DELETE_ALL_ITEMS:
NEIServerUtils.deleteAllItems(sender);
break;
case 5:
case C2S.SET_SLOT:
setInventorySlot(sender, packet);
break;
case 6:
case C2S.TOGGLE_MAGNET:
NEIServerUtils.toggleMagnetMode(sender);
break;
case 7:
case C2S.SET_TIME:
NEIServerUtils.setHourForward(sender.worldObj, packet.readUByte(), true);
break;
case 8:
case C2S.HEAL:
NEIServerUtils.healPlayer(sender);
break;
case 9:
case C2S.TOGGLE_RAIN:
NEIServerUtils.toggleRaining(sender.worldObj, true);
break;
case 10:
case C2S.REQUEST_LOGIN_INFO:
sendLoginState(sender);
break;
case 11:
case C2S.REQUEST_CONTAINER_CONTENTS:
sender.sendContainerAndContentsToPlayer(sender.openContainer, sender.openContainer.getInventory());
break;
case 12:
case C2S.CHANGE_PROPERTY:
handlePropertyChange(sender, packet);
break;
case 13:
case C2S.SET_GAME_MODE:
NEIServerUtils.setGamemode(sender, packet.readUByte());
break;
case 14:
case C2S.CYCLE_CREATIVE_INV:
NEIServerUtils.cycleCreativeInv(sender, packet.readInt());
break;
case 15:
case C2S.SEND_MOB_SPAWNER_ID:
handleMobSpawnerID(sender.worldObj, packet.readCoord(), packet.readString());
break;
case 16:
case C2S.REQUEST_CONTAINER:
handleRequestContainer(sender, packet.readInt());
break;
case 21:
case C2S.REQUEST_ENCHANTMENT_GUI:
openEnchantmentGui(sender);
break;
case 22:
case C2S.MODIFY_ENCHANTMENT:
modifyEnchantment(sender, packet.readUByte(), packet.readUByte(), packet.readBoolean());
break;
case 23:
case C2S.SET_CREATIVE_PLUS_MODE:
processCreativeInv(sender, packet.readBoolean());
break;
case 24:
case C2S.REQUEST_POTION_GUI:
openPotionGui(sender, packet);
break;
case 25:
case C2S.SET_DUMMY_SLOT:
handleDummySlotSet(sender, packet);
break;
case C2S.SEND_CHAT_ITEM_LINK:
handleSendChatItemLink(sender, packet);
break;
}
}
private void handleSendChatItemLink(EntityPlayerMP sender, PacketCustom packet) {
NEIServerUtils.sendChatItemLink(sender, packet.readItemStack());
}
private void handleDummySlotSet(EntityPlayerMP sender, PacketCustom packet) {
int slotNumber = packet.readShort();
ItemStack stack = packet.readItemStack(true);
@@ -126,14 +136,14 @@ public class NEISPH implements IServerPacketHandler {
NEIServerConfig.forPlayer(sender.getCommandSenderName()),
Side.SERVER)),
(player, windowId) -> {
PacketCustom packet = new PacketCustom(channel, 23);
PacketCustom packet = new PacketCustom(channel, S2C.SET_CREATIVE_PLUS_MODE);
packet.writeBoolean(true);
packet.writeByte(windowId);
packet.sendToPlayer(player);
});
} else {
sender.closeContainer();
PacketCustom packet = new PacketCustom(channel, 23);
PacketCustom packet = new PacketCustom(channel, S2C.SET_CREATIVE_PLUS_MODE);
packet.writeBoolean(false);
packet.sendToPlayer(sender);
}
@@ -169,7 +179,7 @@ public class NEISPH implements IServerPacketHandler {
player,
new ContainerEnchantmentModifier(player.inventory, player.worldObj, 0, 0, 0),
(player1, windowId) -> {
PacketCustom packet = new PacketCustom(channel, 21);
PacketCustom packet = new PacketCustom(channel, S2C.OPEN_ENCHANTMENT_GUI);
packet.writeByte(windowId);
packet.sendToPlayer(player1);
});
@@ -179,18 +189,19 @@ public class NEISPH implements IServerPacketHandler {
InventoryBasic b = new InventoryBasic("potionStore", true, 9);
for (int i = 0; i < b.getSizeInventory(); i++) b.setInventorySlotContents(i, packet.readItemStack());
ServerUtils.openSMPContainer(player, new ContainerPotionCreator(player.inventory, b), (player1, windowId) -> {
PacketCustom packet1 = new PacketCustom(channel, 24);
PacketCustom packet1 = new PacketCustom(channel, S2C.OPEN_POTION_GUI);
packet1.writeByte(windowId);
packet1.sendToPlayer(player1);
});
}
public static void sendActionDisabled(int dim, String name, boolean disable) {
new PacketCustom(channel, 11).writeString(name).writeBoolean(disable).sendToDimension(dim);
new PacketCustom(channel, S2C.SEND_ACTION_DISABLED).writeString(name).writeBoolean(disable)
.sendToDimension(dim);
}
public static void sendActionEnabled(EntityPlayerMP player, String name, boolean enable) {
new PacketCustom(channel, 12).writeString(name).writeBoolean(enable).sendToPlayer(player);
new PacketCustom(channel, S2C.SEND_ACTION_ENABLED).writeString(name).writeBoolean(enable).sendToPlayer(player);
}
private void sendLoginState(EntityPlayerMP player) {
@@ -209,7 +220,7 @@ public class NEISPH implements IServerPacketHandler {
if (!NEIServerConfig.isPlayerInList(player.getCommandSenderName(), entry.value, true))
bannedItems.add(entry.key);
PacketCustom packet = new PacketCustom(channel, 10);
PacketCustom packet = new PacketCustom(channel, S2C.SEND_LOGIN_STATE);
packet.writeByte(actions.size());
for (String s : actions) packet.writeString(s);
@@ -228,7 +239,7 @@ public class NEISPH implements IServerPacketHandler {
public static void sendHasServerSideTo(EntityPlayerMP player) {
NEIServerConfig.logger.debug("Sending serverside check to: " + player.getCommandSenderName());
PacketCustom packet = new PacketCustom(channel, 1);
PacketCustom packet = new PacketCustom(channel, S2C.SEND_SERVER_SIDE_CHECK);
packet.writeByte(NEIActions.protocol);
packet.writeString(CommonUtils.getWorldName(player.worldObj));
@@ -236,7 +247,7 @@ public class NEISPH implements IServerPacketHandler {
}
public static void sendAddMagneticItemTo(EntityPlayerMP player, EntityItem item) {
PacketCustom packet = new PacketCustom(channel, 13);
PacketCustom packet = new PacketCustom(channel, S2C.SEND_MAGNETIC_ITEM);
packet.writeInt(item.getEntityId());
packet.sendToPlayer(player);
@@ -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 =");
@@ -17,6 +17,7 @@ import net.minecraft.enchantment.Enchantment;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.event.ClickEvent;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@@ -42,12 +43,26 @@ import codechicken.core.ServerUtils;
import codechicken.lib.inventory.InventoryRange;
import codechicken.lib.inventory.InventoryUtils;
import codechicken.lib.packet.PacketCustom;
import codechicken.nei.PacketIDs.S2C;
import codechicken.nei.util.NBTHelper;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.relauncher.ReflectionHelper;
public class NEIServerUtils {
private static Class<?> gtMetaBaseItem;
static {
try {
final ClassLoader loader = NEIServerUtils.class.getClassLoader();
NEIServerUtils.gtMetaBaseItem = ReflectionHelper
.getClass(loader, "gregtech.api.items.MetaBaseItem", "gregtech.api.items.GT_MetaBase_Item");
} catch (Exception ignored) {
/* Do nothing */
}
}
public static boolean isRaining(World world) {
return world.getWorldInfo().isRaining();
}
@@ -68,6 +83,18 @@ public class NEIServerUtils {
player.extinguish();
}
public static void sendChatItemLink(EntityPlayerMP sender, ItemStack stackover) {
ServerUtils.sendChatToAll(
new ChatComponentTranslation(
"nei.chat.item_link.text",
sender.getDisplayName(),
stackover.func_151000_E().setChatStyle(
stackover.func_151000_E().getChatStyle().setChatClickEvent(
new ClickEvent(
ClickEvent.Action.RUN_COMMAND,
"/nei_bookmark " + stackover.writeToNBT(new NBTTagCompound()))))));
}
public static long getTime(World world) {
return world.getWorldInfo().getWorldTime();
}
@@ -88,9 +115,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());
}
@@ -146,7 +172,7 @@ public class NEIServerUtils {
/**
* NBT-friendly version of {@link #areStacksSameType(ItemStack, ItemStack)}
*
*
* @param stack1 The {@link ItemStack} being compared.
* @param stack2 The {@link ItemStack} to compare to.
* @return whether the two items are the same in terms of itemID, damage and NBT.
@@ -177,19 +203,35 @@ public class NEIServerUtils {
/**
* NBT-friendly version of {@link #areStacksSameTypeCrafting(ItemStack, ItemStack)}
*
*
* @param stack1 The {@link ItemStack} being compared.
* @param stack2 The {@link ItemStack} to compare to.
* @return whether the two items are the same from the perspective of a crafting inventory.
*/
public static boolean areStacksSameTypeCraftingWithNBT(ItemStack stack1, ItemStack stack2) {
return stack1 != null && stack2 != null
&& stack1.getItem() == stack2.getItem()
&& (stack1.getItemDamage() == stack2.getItemDamage()
|| stack1.getItemDamage() == OreDictionary.WILDCARD_VALUE
|| stack2.getItemDamage() == OreDictionary.WILDCARD_VALUE
|| stack1.getItem().isDamageable())
&& NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound());
if (NEIServerUtils.areStacksSameTypeCrafting(stack2, stack1)) {
if (NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound())) return true;
if (isItemTool(stack1)
&& (stack1.stackTagCompound == null || stack1.stackTagCompound.hasKey("GT.ToolStats"))
&& (stack2.stackTagCompound == null || stack2.stackTagCompound.hasKey("GT.ToolStats")))
return true;
return stack1.getMaxStackSize() == 1 && stack2.getMaxStackSize() == 1
&& (stack1.stackTagCompound == null ^ stack2.stackTagCompound == null);
}
return false;
}
/**
* GT Items don't have any NBT set for the recipe, so if either of the stacks has a NULL nbt, and the other doesn't,
* pretend they stack
*
* @param ItemStack stack
* @return
*/
public static boolean isItemTool(ItemStack stack) {
return NEIServerUtils.gtMetaBaseItem != null && NEIServerUtils.gtMetaBaseItem.isInstance(stack.getItem());
}
/**
@@ -295,7 +337,7 @@ public class NEIServerUtils {
player.theItemInWorldManager.setGameType(getGameType(mode));
// tell the client to change it
new PacketCustom(NEISPH.channel, 14).writeByte(mode).sendToPlayer(player);
new PacketCustom(NEISPH.channel, S2C.SEND_GAME_MODE).writeByte(mode).sendToPlayer(player);
player.addChatMessage(new ChatComponentTranslation("nei.chat.gamemode." + mode));
}
@@ -0,0 +1,41 @@
package codechicken.nei;
public final class PacketIDs {
public static final class C2S {
public static final int GIVE_ITEM = 1;
public static final int DELETE_ALL_ITEMS = 4;
public static final int SET_SLOT = 5;
public static final int TOGGLE_MAGNET = 6;
public static final int SET_TIME = 7;
public static final int HEAL = 8;
public static final int TOGGLE_RAIN = 9;
public static final int REQUEST_LOGIN_INFO = 10;
public static final int REQUEST_CONTAINER_CONTENTS = 11;
public static final int CHANGE_PROPERTY = 12;
public static final int SET_GAME_MODE = 13;
public static final int CYCLE_CREATIVE_INV = 14;
public static final int SEND_MOB_SPAWNER_ID = 15;
public static final int REQUEST_CONTAINER = 16;
public static final int REQUEST_ENCHANTMENT_GUI = 21;
public static final int MODIFY_ENCHANTMENT = 22;
public static final int SET_CREATIVE_PLUS_MODE = 23;
public static final int REQUEST_POTION_GUI = 24;
public static final int SET_DUMMY_SLOT = 25;
public static final int SEND_CHAT_ITEM_LINK = 26;
}
public static final class S2C {
public static final int SEND_SERVER_SIDE_CHECK = 1;
public static final int SEND_LOGIN_STATE = 10;
public static final int SEND_ACTION_DISABLED = 11;
public static final int SEND_ACTION_ENABLED = 12;
public static final int SEND_MAGNETIC_ITEM = 13;
public static final int SEND_GAME_MODE = 14;
public static final int OPEN_ENCHANTMENT_GUI = 21;
public static final int SET_CREATIVE_PLUS_MODE = 23;
public static final int OPEN_POTION_GUI = 24;
}
}
+78 -79
View File
@@ -1,20 +1,24 @@
package codechicken.nei;
import java.awt.Point;
import java.util.ArrayList;
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;
@@ -25,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);
}
};
}
@@ -89,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);
@@ -102,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;
@@ -117,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) {
@@ -163,17 +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() {
this.grid.update();
}
@Override
public void draw(int mousex, int mousey) {
grid.draw(mousex, mousey);
this.grid.draw(mousex, mousey);
}
@Override
@@ -187,53 +201,33 @@ public abstract class PanelWidget extends Widget {
@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;
}
@@ -248,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;
}
@@ -314,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;
@@ -341,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;
}
@@ -363,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,21 @@
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;
import codechicken.nei.recipe.StackInfo;
/**
* Simply an {@link ItemStack} with position. Mainly used in the recipe handlers.
*/
@@ -26,8 +34,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 +48,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 +83,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) {
@@ -93,7 +146,7 @@ public class PositionedStack {
* NBT-friendly version of {@link #contains(ItemStack)}
*/
public boolean containsWithNBT(ItemStack ingredient) {
for (ItemStack item : items) if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(item, ingredient)) return true;
for (ItemStack item : items) if (StackInfo.equalItemAndNBT(item, ingredient, true)) return true;
return false;
}
@@ -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("Failed 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,314 @@
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)) {
providersCache.providers = new ArrayList<>();
providersCache.languageCode = currentLanguage.getLanguageCode();
Map<Character, ISearchParserProvider> providers = new HashMap<>();
for (int index = this.searchProviders.size() - 1; index >= 0; index--) {
ISearchParserProvider provider = this.searchProviders.get(index);
if (provider.getMatchingLanguages().contains(currentLanguage)) {
if (provider.getSearchMode() == SearchMode.PREFIX && !providers.containsKey(provider.getPrefix())) {
providers.put(provider.getPrefix(), provider);
} else if (provider.getSearchMode() == SearchMode.ALWAYS) {
providersCache.providers.add(provider);
}
}
}
providersCache.providers.addAll(providers.values());
}
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;
}
}
@@ -9,7 +9,6 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.boss.BossStatus;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.client.IItemRenderer;
import org.lwjgl.opengl.GL11;
@@ -27,21 +26,16 @@ public class SpawnerRenderer implements IItemRenderer {
public void renderInventoryItem(RenderBlocks render, ItemStack item) {
int meta = item.getItemDamage();
if (meta == 0) meta = ItemMobSpawner.idPig;
String bossName = BossStatus.bossName;
int bossTimeout = BossStatus.statusBarTime;
boolean bossHasColorModifier = BossStatus.hasColorModifier;
Entity entity = ItemMobSpawner.getEntity(meta);
try {
World world = NEIClientUtils.mc().theWorld;
ItemMobSpawner.loadSpawners(world);
CCRenderState.changeTexture(TextureMap.locationBlocksTexture);
render.renderBlockAsItem(Blocks.mob_spawner, 0, 1F);
entity.setWorld(render.minecraftRB.theWorld);
GL11.glPushMatrix();
Entity entity = ItemMobSpawner.getEntity(meta);
entity.setWorld(world);
float f1 = 0.4375F;
if (entity.getShadowSize() > 1.5) f1 = 0.1F;
GL11.glRotatef((float) (ClientUtils.getRenderTime() * 10), 0.0F, 1.0F, 0.0F);
@@ -51,7 +45,6 @@ public class SpawnerRenderer implements IItemRenderer {
entity.setLocationAndAngles(0, 0, 0, 0.0F, 0.0F);
RenderManager.instance.renderEntityWithPosYaw(entity, 0.0D, 0.0D, 0.0D, 0.0F, 0);
GL11.glPopMatrix();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit);
GL11.glDisable(GL11.GL_TEXTURE_2D);
@@ -64,7 +57,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 +67,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;
}
}
@@ -14,6 +14,8 @@ public abstract class Widget {
public void postDraw(int mx, int my) {}
public void postDrawTooltips(int mx, int my, List<String> tooltip) {}
public boolean handleClick(int mx, int my, int button) {
return true;
}
@@ -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());
}
+53 -20
View File
@@ -3,6 +3,7 @@ package codechicken.nei.api;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import net.minecraft.block.Block;
import net.minecraft.client.gui.inventory.GuiContainer;
@@ -14,6 +15,7 @@ import org.lwjgl.input.Keyboard;
import com.google.common.collect.Sets;
import codechicken.nei.BookmarkContainerInfo;
import codechicken.nei.ItemList;
import codechicken.nei.ItemSorter;
import codechicken.nei.ItemStackSet;
@@ -24,13 +26,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;
@@ -38,6 +43,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
@@ -147,19 +153,32 @@ 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
*/
public static void setOverrideName(ItemStack item, String name) {
if (!name.equals(ItemInfo.nameOverrides.get(item))) {
ItemInfo.nameOverrides.put(item, name);
String existing = ItemInfo.nameOverrides.get(item);
if (!Objects.equals(name, existing)) {
if (name == null) {
ItemInfo.nameOverrides.remove(item);
} else {
ItemInfo.nameOverrides.put(item, name);
}
LayoutManager.markItemsDirty();
}
}
/**
* 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) {
@@ -182,7 +201,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}
*/
@@ -194,7 +213,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}
*/
@@ -209,7 +228,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.
*/
@@ -219,7 +238,7 @@ public class API {
/**
* Registers a new Infinite Item Handler.
*
*
* @param handler The handler to be registered.
*/
public static void addInfiniteItemHandler(IInfiniteItemHandler handler) {
@@ -228,7 +247,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.
*/
@@ -238,7 +257,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) {
@@ -247,7 +266,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.
@@ -258,16 +277,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) {
@@ -278,7 +303,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
*/
@@ -288,7 +313,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
*/
@@ -305,16 +330,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
*/
@@ -325,7 +353,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
*/
@@ -344,7 +372,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
@@ -365,7 +393,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
@@ -390,6 +418,11 @@ public class API {
RecipeCatalysts.removeRecipeCatalyst(handlerID, stack);
}
public static void registerBookmarkContainerHandler(Class<? extends GuiContainer> gui,
IBookmarkContainerHandler handler) {
BookmarkContainerInfo.registerBookmarkContainerHandler(gui, handler);
}
@Deprecated
public static void addRecipeCatalyst(List<ItemStack> stacks, IRecipeHandler handler) {
for (ItemStack stack : stacks) {
@@ -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;
@@ -0,0 +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);
}
@@ -6,9 +6,18 @@ import net.minecraftforge.fluids.FluidStack;
public interface IStackStringifyHandler {
public NBTTagCompound convertItemStackToNBT(ItemStack stack, boolean saveStackSize);
default NBTTagCompound convertItemStackToNBT(ItemStack stack, boolean saveStackSize) {
return null;
}
public ItemStack convertNBTToItemStack(NBTTagCompound nbtTag);
default ItemStack convertNBTToItemStack(NBTTagCompound nbtTag) {
return null;
}
default FluidStack getFluid(ItemStack stack) {
return null;
}
default void pauseItemDamageSound(boolean pause) {}
public FluidStack getFluid(ItemStack stack);
}
+75 -134
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);
}
@@ -144,37 +124,38 @@ public class ItemInfo {
addMobSpawnerItem();
}
public static void load(World world) {
public static void load() {
addVanillaBlockProperties();
addDefaultDropDowns();
searchItems();
parseModItems();
ItemMobSpawner.loadSpawners(world);
ItemMobSpawner.loadSpawners();
addSpawnEggs();
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,41 +1,107 @@
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 {
public static boolean handleKeyEvent(ItemStack stackover) {
if (NEIClientConfig.isKeyHashDown("gui.overlay_hide")) {
return hideOverlayRecipe();
if (!NEIClientConfig.isLoaded()) {
return false;
}
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() && NEIClientConfig.isKeyHashDown("gui.craft_items")
&& NEIClientUtils.shiftKey()
&& ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)) {
final RecipeChainMath math = ItemPanels.bookmarkPanel.getGrid().createRecipeChainMath(groupId);
if (math != null) {
if (!NEIClientUtils.controlKey()) {
autocraftingIgnoreInventory(math);
}
AutoCraftingManager.runProcessing(math);
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.chat_link_item")) {
return sendItemStackChatLink(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.recipe")) {
@@ -47,19 +113,16 @@ 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_items")
&& NEIClientUtils.shiftKey()) {
return runAutoCrafting(stackover, !NEIClientUtils.controlKey());
}
return false;
@@ -67,9 +130,12 @@ public abstract class ShortcutInputHandler {
public static boolean handleMouseClick(ItemStack stackover) {
if (!NEIClientConfig.isLoaded()) {
return false;
}
if (stackover != null) {
final int button = Mouse.getEventButton();
stackover = stackover.copy();
if (button == 0) {
return GuiCraftingRecipe.openRecipeGui("item", stackover);
@@ -81,43 +147,380 @@ 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 sendItemStackChatLink(ItemStack stackover) {
if (stackover == null) return false;
if (gui == null || gui instanceof GuiRecipe) {
return false;
}
return GuiCraftingRecipe.openRecipeGui("item", true, shift, stack);
NEIClientUtils.sendChatItemLink(stackover); // I wish clients could just send formatted messages
return true;
}
private static boolean saveRecipeInBookmark(ItemStack stack, boolean saveIngredients, boolean saveStackSize) {
private static boolean copyItemStackOreDictionary(ItemStack stackover) {
StringBuilder builder = new StringBuilder();
if (stack != null) {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
List<PositionedStack> ingredients = null;
String handlerName = "";
for (int id : OreDictionary.getOreIDs(stackover)) {
String oreDictionaryName = OreDictionary.getOreName(id);
if (!"Unknown".equals(oreDictionaryName)) {
builder.append(oreDictionaryName).append(",");
}
}
if (builder.length() > 0) {
builder.deleteCharAt(builder.length() - 1);
}
GuiScreen.setClipboardString(builder.toString());
return true;
}
private static boolean runAutoCrafting(ItemStack stackover, boolean ignoreInventory) {
final RecipeId recipeId = GuiCraftingRecipe.getRecipeId(NEIClientUtils.getGuiContainer(), stackover);
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) {
if (ignoreInventory) {
autocraftingIgnoreInventory(math);
}
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)
|| NEIClientConfig.getBooleanSetting("inventory.bookmarks.bookmarkItemsWithRecipe");
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.contains(permutations.get(index))) {
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_items", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("bookmark.group.craft_missing"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.craft_all"));
}
}
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"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.chat_link_item"),
NEIClientUtils.translate("itempanel.chat_link_item"));
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_items",
NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("itempanel.craft_missing"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("itempanel.craft_all"));
}
}
}
return hotkeys;
}
private static void autocraftingIgnoreInventory(RecipeChainMath math) {
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
final List<ItemStack> playerInventory = AutoCraftingManager.getInventoryItems(guiContainer).values();
final RecipeId rootRecipeId = math.createMasterRoot();
for (BookmarkItem item : math.recipeIngredients) {
if (item.amount > 0 && rootRecipeId.equals(item.recipeId)) {
long amount = 0;
for (ItemStack stack : playerInventory) {
if (NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack, item.itemStack)) {
amount += StackInfo.getAmount(stack);
}
}
if (amount >= item.amount) {
item.factor = item.amount = amount + item.amount - (amount % item.amount);
}
}
}
}
private static RecipeId getHotkeyRecipeId(GuiContainer gui, int mousex, int mousey, ItemStack stack,
BookmarksGridSlot slot) {
if (slot != null) {
return slot.isIngredient() ? null : 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
@@ -416,7 +413,7 @@ public class NEITransformer implements IClassTransformer {
if (name.equals("net.minecraftforge.oredict.OreDictionary")) {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cr.accept(new OreDictionaryVisitor(ASM5, cw), ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
cr.accept(new OreDictionaryVisitor(ASM5, cw), 0);
bytes = cw.toByteArray();
}
bytes = transformSubclasses(name, bytes);
@@ -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,205 @@
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.NEIClientUtils;
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 {
private static Map<ItemStack, String> fuzzyPermutations = new HashMap<>();
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 synchronized String getItemGUID(ItemStack stack) {
final FluidStack fluidStack = StackInfo.getFluid(stack);
if (fluidStack != null) {
return fluidStack.getFluid().getName() + ":" + fluidStack.tag;
} else {
for (Map.Entry<ItemStack, String> entry : BookmarkItem.fuzzyPermutations.entrySet()) {
if (NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack, entry.getKey())) {
BookmarkItem.fuzzyPermutations.put(stack, entry.getValue());
return entry.getValue();
}
}
final String stackGUID = StackInfo.getItemStackGUID(stack);
BookmarkItem.fuzzyPermutations.put(stack, stackGUID);
return stackGUID;
}
}
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("Failed 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);
}
}
@@ -0,0 +1,48 @@
package codechicken.nei.commands;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommandSender;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTException;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.ChatComponentTranslation;
import codechicken.nei.ItemPanels;
public class CommandBookmarkAdd extends CommandBase {
@Override
public String getCommandName() {
return "nei_bookmark";
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "/nei_bookmark <nbt>";
}
@Override
public int getRequiredPermissionLevel() {
return 0;
}
@Override
public void processCommand(ICommandSender sender, String[] args) {
if (args.length < 1 || args[0].length() < 3) {
sender.addChatMessage(new ChatComponentText("§c/nei_bookmark <nbt>"));
return;
}
try {
ItemPanels.bookmarkPanel.addItem(
ItemStack.loadItemStackFromNBT((NBTTagCompound) JsonToNBT.func_150315_a(String.join(" ", args))));
sender.addChatMessage(new ChatComponentTranslation("nei.chat.bookmark_added.text"));
} catch (NBTException e) {
sender.addChatMessage(new ChatComponentText(e.toString()));
}
}
}
@@ -0,0 +1,296 @@
package codechicken.nei.commands;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommandSender;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.util.ChatStyle;
import net.minecraft.util.EnumChatFormatting;
import org.apache.commons.io.IOUtils;
import com.google.gson.JsonParser;
import codechicken.core.CommonUtils;
import codechicken.nei.ClientHandler;
import codechicken.nei.ItemList;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.ICraftingHandler;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.RecipeHandlerQuery;
import codechicken.nei.util.NBTJson;
public class CommandRecipeId extends CommandBase {
protected static class ProcessDiffThread extends Thread {
protected final ICommandSender sender;
protected final File prevFile;
protected final File currFile;
protected final File diffFile;
public ProcessDiffThread(ICommandSender sender, File prevFile, File currFile, File diffFile) {
this.sender = sender;
this.prevFile = prevFile;
this.currFile = currFile;
this.diffFile = diffFile;
}
@Override
public void run() {
sendChatInfoMessage(sender, "nei.chat.recipeid.diff.start");
final Set<String> prevRecipes = loadFileContent(this.prevFile);
final Set<String> currRecipes = loadFileContent(this.currFile);
final Set<String> notAllowedRecipes = prevRecipes.stream().filter(recipe -> !currRecipes.contains(recipe))
.collect(Collectors.toCollection(TreeSet::new));
final List<String> subsetsList = new ArrayList<>();
generateSubsets(notAllowedRecipes).forEach((handlerName, recipes) -> {
subsetsList.add("; " + handlerName);
subsetsList.addAll(recipes);
});
saveFile(this.diffFile, subsetsList);
saveFile(getFile("not-allowed-recipes"), new ArrayList<>(notAllowedRecipes));
sendChatInfoMessage(sender, "nei.chat.recipeid.diff.finish");
}
private Set<String> loadFileContent(File file) {
try (FileReader reader = new FileReader(file)) {
return new HashSet<>(IOUtils.readLines(reader));
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load '{}' file {}", file.getName(), file, e);
}
return new HashSet<>();
}
private Map<String, Set<String>> generateSubsets(Set<String> notAllowedRecipes) {
final JsonParser parser = new JsonParser();
final Map<String, Set<String>> subsetsBuilder = new TreeMap<>();
for (String recipeStr : notAllowedRecipes) {
try {
final NBTTagCompound nbtRecipe = (NBTTagCompound) NBTJson.toNbt(parser.parse(recipeStr));
if (nbtRecipe.hasKey("result")) {
final NBTTagCompound nbtStack = nbtRecipe.getCompoundTag("result");
nbtStack.removeTag("Count");
subsetsBuilder.computeIfAbsent(nbtRecipe.getString("handlerName"), rn -> new TreeSet<>())
.add(NBTJson.toJson(nbtStack));
} else {
NEIClientConfig.logger.error("Found Broken RecipeId {}", recipeStr);
}
} catch (Exception ex) {
NEIClientConfig.logger.error("Found Broken RecipeId {}", recipeStr, ex);
}
}
return subsetsBuilder;
}
private void saveFile(File file, List<String> content) {
try (FileOutputStream output = new FileOutputStream(file)) {
IOUtils.writeLines(content, "\n", output, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to save recipeid diff list to file {}", file, e);
}
}
}
protected static class ProcessDumpThread extends Thread {
private ArrayList<ICraftingHandler> craftinghandlers = new ArrayList<>();
private ArrayList<ICraftingHandler> serialCraftingHandlers = new ArrayList<>();
protected final ICommandSender sender;
protected final File currFile;
public ProcessDumpThread(ICommandSender sender, File currFile) {
this.sender = sender;
this.currFile = currFile;
ClientHandler.loadSettingsFile("recipeidblacklist.cfg", lines -> {
final Set<String> names = lines.collect(Collectors.toSet());
this.craftinghandlers = GuiCraftingRecipe.craftinghandlers.stream()
.filter(h -> !names.contains(GuiRecipeTab.getHandlerInfo(h).getHandlerName()))
.collect(Collectors.toCollection(ArrayList::new));
this.serialCraftingHandlers = GuiCraftingRecipe.serialCraftingHandlers.stream()
.filter(h -> !names.contains(GuiRecipeTab.getHandlerInfo(h).getHandlerName()))
.collect(Collectors.toCollection(ArrayList::new));
});
}
@Override
public void run() {
NEIClientConfig.logger.info("Start processing recipe handlers!");
sendChatInfoMessage(sender, "nei.chat.recipeid.dump.start");
try (BufferedWriter writer = Files.newBufferedWriter(currFile.toPath(), StandardCharsets.UTF_8)) {
int total = ItemList.items.size();
int count = 0;
for (ItemStack stack : ItemList.items) {
if (count % 1000 == 0) {
NEIClientConfig.logger.info(
"({}/{}). Processing {} crafting recipes...",
count,
total,
stack.getDisplayName());
}
count++;
for (ICraftingHandler handler : getCraftingHandlers(stack)) {
for (int index = 0, num = handler.numRecipes(); index < num; index++) {
try {
final Recipe recipe = Recipe.of(handler, index);
if (!recipe.getIngredients().isEmpty() && !recipe.getResults().isEmpty()) {
writer.write(NBTJson.toJson(recipe.getRecipeId().toJsonObject()));
writer.newLine();
}
} catch (Exception ex) {
NEIClientConfig.logger.error(
"Found Broken RecipeId {}:{}",
GuiRecipeTab.getHandlerInfo(handler).getHandlerName(),
stack,
ex);
}
}
}
}
} catch (Exception e) {
NEIClientConfig.logger.error("Error dumping RecipeId", e);
}
NEIClientConfig.logger.info("Finished processing recipe handlers!");
sendChatInfoMessage(sender, "nei.chat.recipeid.dump.finish");
}
private ArrayList<ICraftingHandler> getCraftingHandlers(Object... results) {
return new RecipeHandlerQuery<>(
h -> h.getRecipeHandler("item", results),
this.craftinghandlers,
this.serialCraftingHandlers,
"Error while looking up crafting recipe",
"outputId: item",
"results: " + Arrays.toString(results))
.runWithProfiling(NEIClientUtils.translate("recipe.concurrent.crafting"));
}
}
@Override
public String getCommandName() {
return "recipeid";
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "/recipeid dump <filename> OR /recipeid diff <prev-filename> <curr-filename> [subset name]";
}
@Override
public int getRequiredPermissionLevel() {
return 0;
}
@Override
public void processCommand(ICommandSender sender, String[] args) {
final String command = args.length == 0 ? null : args[0];
if ("dump".equals(command)) {
processDumpCommand(sender, args);
} else if ("diff".equals(command)) {
processDiffCommand(sender, args);
} else {
sendChatErrorMessage(sender, getCommandUsage(sender));
}
}
protected void processDiffCommand(ICommandSender sender, String[] args) {
if (args.length > 4) {
sendChatErrorMessage(sender, "nei.chat.recipeid.many_params", getCommandUsage(sender));
return;
}
if (args.length < 3) {
sendChatErrorMessage(sender, getCommandUsage(sender));
return;
}
final File prevFilename = getFile(args[1]);
final File currFilename = getFile(args[2]);
final File diffFilename = getFile(args.length > 3 ? args[3] : "changelog");
if (!prevFilename.exists()) {
sendChatErrorMessage(sender, "nei.chat.recipeid.not_found", prevFilename.getName());
return;
}
if (!currFilename.exists()) {
sendChatErrorMessage(sender, "nei.chat.recipeid.not_found", currFilename.getName());
return;
}
(new ProcessDiffThread(sender, prevFilename, currFilename, diffFilename)).start();
}
protected void processDumpCommand(ICommandSender sender, String[] args) {
if (args.length > 2) {
sendChatErrorMessage(sender, "nei.chat.recipeid.many_params", getCommandUsage(sender));
return;
}
final File dir = new File(CommonUtils.getMinecraftDir(), "recipeid");
final String currFilename = args.length == 2 ? args[1] : "recipeId";
if (!dir.exists()) dir.mkdirs();
(new ProcessDumpThread(sender, getFile(currFilename))).start();
}
private static File getFile(String filename) {
return new File(CommonUtils.getMinecraftDir(), "recipeid/" + filename + ".json");
}
private static void sendChatInfoMessage(ICommandSender sender, String translationKey, Object... args) {
sender.addChatMessage(
new ChatComponentTranslation(translationKey, args)
.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.AQUA)));
}
private static void sendChatErrorMessage(ICommandSender sender, String translationKey, Object... args) {
sender.addChatMessage(
new ChatComponentTranslation(translationKey, args)
.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.RED)));
}
}
@@ -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";
@@ -97,7 +97,7 @@ public class HandlerDumper extends DataDumper {
}
writer.close();
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save dump handler list to file {}", file, e);
NEIClientConfig.logger.error("Failed to save dump handler list to file {}", file, e);
}
}
@@ -1,13 +1,13 @@
package codechicken.nei.config;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import codechicken.core.CommonUtils;
import codechicken.nei.NEIClientConfig;
@@ -15,6 +15,7 @@ import codechicken.nei.NEIServerUtils;
import codechicken.nei.recipe.CatalystInfo;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.HandlerInfo;
import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.recipe.RecipeCatalysts;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Loader;
@@ -33,18 +34,11 @@ public class IMCHandler {
if (type == null || type.isEmpty()) continue;
if (CommonUtils.isClient()) {
switch (type) {
case "registerHandlerInfo":
handleRegisterHandlerInfo(message);
break;
case "removeHandlerInfo":
handleRemoveHandlerInfo(message);
break;
case "registerCatalystInfo":
handleRegisterCatalystInfo(message);
break;
case "removeCatalystInfo":
handleRemoveCatalystInfo(message);
break;
case "registerHandlerInfo" -> handleRegisterHandlerInfo(message);
case "removeHandlerInfo" -> handleRemoveHandlerInfo(message);
case "registerCatalystInfo" -> handleRegisterCatalystInfo(message);
case "removeCatalystInfo" -> handleRemoveCatalystInfo(message);
case "addItemInfo" -> handleAddItemInfo(message);
}
}
}
@@ -57,14 +51,14 @@ public class IMCHandler {
}
final NBTTagCompound tag = message.getNBTValue();
final String handler = tag.getString("handler");
NEIClientConfig.logger.info("Processing registerHandlerInfo `" + handler + "` from " + message.getSender());
NEIClientConfig.logger.info("Processing registerHandlerInfo `{}` from {}", handler, message.getSender());
final String modName = tag.getString("modName");
final String modId = tag.getString("modId");
final boolean requiresMod = tag.getBoolean("modRequired");
final String excludedModId = tag.hasKey("excludedModId") ? tag.getString("excludedModId") : null;
if (handler.equals("") || modName.equals("") || modId.equals("")) {
if (handler.isEmpty() || modName.isEmpty() || modId.isEmpty()) {
NEIClientConfig.logger.warn("Missing relevant information to registerHandlerInfo!");
return;
}
@@ -74,7 +68,7 @@ public class IMCHandler {
HandlerInfo info = new HandlerInfo(handler, modName, modId, requiresMod, excludedModId);
final String imageResource = tag.hasKey("imageResource") ? tag.getString("imageResource") : null;
if (imageResource != null && !imageResource.equals("")) {
if (imageResource != null && !imageResource.isEmpty()) {
info.setImage(
imageResource,
tag.getInteger("imageX"),
@@ -84,7 +78,7 @@ public class IMCHandler {
}
if (!info.hasImageOrItem()) {
final String itemName = tag.getString("itemName");
if (itemName != null && !itemName.equals("")) {
if (itemName != null && !itemName.isEmpty()) {
info.setItem(itemName, tag.hasKey("nbtInfo") ? tag.getString("nbtInfo") : null);
}
}
@@ -100,9 +94,13 @@ public class IMCHandler {
: HandlerInfo.DEFAULT_MAX_PER_PAGE;
info.setHandlerDimensions(imageHeight, imageWidth, maxRecipesPerPage);
} catch (NumberFormatException ignored) {
NEIClientConfig.logger.info("Error setting handler dimensions for " + handler);
NEIClientConfig.logger.info("Error setting handler dimensions for {}", handler);
}
// true if not set to false
info.setShowFavoritesButton(!tag.hasKey("showFavoritesButton") || tag.getBoolean("showFavoritesButton"));
info.setShowOverlayButton(!tag.hasKey("showOverlayButton") || tag.getBoolean("showOverlayButton"));
GuiRecipeTab.handlerAdderFromIMC.remove(handler);
GuiRecipeTab.handlerAdderFromIMC.put(handler, info);
}
@@ -114,7 +112,7 @@ public class IMCHandler {
}
final NBTTagCompound tag = message.getNBTValue();
final String handler = tag.getString("handler");
NEIClientConfig.logger.info("Processing removeHandlerInfo `" + handler + "` from " + message.getSender());
NEIClientConfig.logger.info("Processing removeHandlerInfo `{}` from {}", handler, message.getSender());
GuiRecipeTab.handlerRemoverFromIMC.add(handler);
}
@@ -126,7 +124,7 @@ public class IMCHandler {
}
if (!processedCatalystSenders.contains(message.getSender())) {
NEIClientConfig.logger.info("Processing registerCatalystInfo from " + message.getSender());
NEIClientConfig.logger.info("Processing registerCatalystInfo from {}", message.getSender());
processedCatalystSenders.add(message.getSender());
}
final NBTTagCompound tag = message.getNBTValue();
@@ -135,23 +133,14 @@ public class IMCHandler {
NEIClientConfig.logger.warn("Missing handlerID for registerCatalystInfo!");
return;
}
final String itemName = tag.getString("itemName");
final String nbtInfo = tag.hasKey("nbtInfo") ? tag.getString("nbtInfo") : null;
if (itemName.isEmpty()) {
NEIClientConfig.logger.warn(String.format("Missing itemName for registerCatalystInfo in `%s`!", handlerID));
return;
}
final ItemStack itemStack = NEIServerUtils.getModdedItem(itemName, nbtInfo);
final ItemStack itemStack = getItemStackFromIMC(message, "registerCatalystInfo");
if (itemStack == null) {
NEIClientConfig.logger.warn(String.format("Cannot find item `%s`!", itemName));
return;
}
final int priority = tag.getInteger("priority");
RecipeCatalysts
.addOrPut(RecipeCatalysts.catalystsAdderFromIMC, handlerID, new CatalystInfo(itemStack, priority));
NEIClientConfig.logger
.info(String.format("Added catalyst `%s` to handler %s", itemStack.getDisplayName(), handlerID));
NEIClientConfig.logger.info("Added catalyst `{}` to handler {}", itemStack.getDisplayName(), handlerID);
}
private static void handleRemoveCatalystInfo(IMCMessage message) {
@@ -160,33 +149,62 @@ public class IMCHandler {
return;
}
NEIClientConfig.logger.info("Processing removeCatalystInfo from " + message.getSender());
final NBTTagCompound tag = message.getNBTValue();
final String handlerID = tag.getString("handlerID");
if (handlerID.isEmpty()) {
NEIClientConfig.logger.warn("Missing handlerID for registerCatalystInfo!");
NEIClientConfig.logger.warn("Missing handlerID for removeCatalystInfo!");
return;
}
final String itemName = tag.getString("itemName");
final String nbtInfo = tag.hasKey("nbtInfo") ? tag.getString("nbtInfo") : null;
if (itemName.isEmpty()) {
NEIClientConfig.logger.warn(String.format("Missing itemName for registerCatalystInfo in `%s`!", handlerID));
return;
}
final ItemStack itemStack = NEIServerUtils.getModdedItem(itemName, nbtInfo);
final ItemStack itemStack = getItemStackFromIMC(message, "removeCatalystInfo");
if (itemStack == null) {
NEIClientConfig.logger.warn(String.format("Cannot find item `%s`!", itemName));
return;
}
if (RecipeCatalysts.catalystsRemoverFromIMC.containsKey(handlerID)) {
RecipeCatalysts.catalystsRemoverFromIMC.get(handlerID).add(itemStack);
} else {
RecipeCatalysts.catalystsRemoverFromIMC
.put(handlerID, new ArrayList<>(Collections.singletonList(itemStack)));
RecipeCatalysts.catalystsRemoverFromIMC.computeIfAbsent(handlerID, k -> new ArrayList<>()).add(itemStack);
NEIClientConfig.logger.info("Removed catalyst `{}` from handler {}", itemStack.getDisplayName(), handlerID);
}
private static void handleAddItemInfo(IMCMessage message) {
if (!message.isNBTMessage()) {
logInvalidMessage(message, "NBT");
return;
}
NEIClientConfig.logger
.info(String.format("Removed catalyst `%s` from handler %s", itemStack.getDisplayName(), handlerID));
final NBTTagCompound tag = message.getNBTValue();
if (tag.hasKey("pages")) addMultipleInfoPages(message);
if (tag.hasKey("page")) addSingleInfoPage(message);
}
private static void addMultipleInfoPages(IMCMessage message) {
final NBTTagCompound tag = message.getNBTValue();
final String filter = tag.getString("filter");
final NBTTagList pages = tag.getTagList("pages", 8); // 8 = TAG_String
for (int i = 0; i < pages.tagCount(); i++) {
String page = pages.getStringTagAt(i);
InformationHandler.addInformationPage(filter, page);
}
}
private static void addSingleInfoPage(IMCMessage message) {
final NBTTagCompound tag = message.getNBTValue();
String filter = tag.getString("filter");
String page = tag.getString("page");
InformationHandler.addInformationPage(filter, page);
}
private static ItemStack getItemStackFromIMC(IMCMessage message, String logAction) {
final NBTTagCompound tag = message.getNBTValue();
final String itemName = tag.getString("itemName");
final String nbtInfo = tag.hasKey("nbtInfo") ? tag.getString("nbtInfo") : null;
NEIClientConfig.logger.info("Processing {} for item `{}` from {}", logAction, itemName, message.getSender());
final ItemStack itemStack = NEIServerUtils.getModdedItem(itemName, nbtInfo);
if (itemStack == null) {
NEIClientConfig.logger.warn("Cannot find item `{}`!", itemName);
}
return itemStack;
}
private static void logInvalidMessage(FMLInterModComms.IMCMessage message, String type) {
@@ -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;
}
Loaded 100 of 194 files, more files were not shown because too many files have changed in this diff. Show more