Compare commits

...
133 Commits
Author SHA1 Message Date
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
chochemandglowredman bacf246504 Adjust nei overlay to gt oregen changes (#391)
* adjust to oregen changes

* add compat for old worlds

* remove testing debug

* Update buildscript

* Adjust to changed oregenPattern API

* fix fieldname

---------

Co-authored-by: glowredman <[email protected]>
2023-07-04 18:36:35 +02:00
Wilhelm Schuster 1ab3350eb8 Adjust recipe handler scrolling again (#393)
* Update buildscript

* Rework recipe handler tab scrolling again

Move the recipe handler tab scrolling before the handler-specific
scrolling again. This ensures that tab scrolling while hovering over the
tab bar will always be possible, regardless of how a recipe handler
handles scrolling itself. This mostly reverts back to how this feature
was implemented originally with one change: the Shift-scrolling behavior
is moved outside the recipe tabs scroll handler after the recipe
handler-specific scroll handling to prevent this from overwriting any
other behavior.
2023-06-24 12:01:21 +02:00
Wilhelm Schuster f3aa12483d Expand the tooltips for the time manipulation action buttons (#392) 2023-06-15 23:19:57 +02:00
miozune d86c472790 Fix crash with IC2 setItemDamage (#387)
* Ducttape fix for crash with IC2 setItemDamage

* Use Items.feather
2023-06-01 07:20:24 +02:00
Wilhelm Schuster 4124151208 Prevent recipe handler tab scrolling from overwriting recipe handler-specific scrolling (#384)
* Rename variable in GuiRecipeTabs to avoid confusion

Based on feedback in a previous PR review.

* Make sure recipe handler-specific scrolling behavior takes precedence over recipe handler tab scrolling
2023-05-13 17:40:08 +02:00
miozune 68ad800620 Remove handlers for Et Futurum Requiem (#383)
* Update dependencies

* updateBuildScript

* Remove handlers for Et Futurum Requiem
2023-05-13 14:12:22 +02:00
Wilhelm Schuster 2c7207485d Ensure the NEI config is really only initialized once (#381)
bootNEI() is supposed to only be called once during the client's
lifetime. Turns out, if your pack has 800 mods, bootNEI() might be
called a second time before configLoaded is set to true at the end of
the plugin loading thread. This introduces a second variable that is
set at the end of the single threaded portion of bootNEI() so that it
truly can only be called once, but we can still retain the ability to
check if the plugin loading thread has finished.
2023-05-10 23:55:45 +02:00
158 changed files with 13656 additions and 5482 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
+1 -8
View File
@@ -27,16 +27,9 @@ If you have issues with NEI outside of the GTNH modpack you may report them in t
* 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 -1492
View File
File diff suppressed because it is too large. Load diff
+4 -3
View File
@@ -1,7 +1,8 @@
// Add your dependencies here
dependencies {
api('com.github.GTNewHorizons:CodeChickenLib:1.1.6:dev')
api('com.github.GTNewHorizons:CodeChickenCore:1.1.10:dev')
shadowImplementation('org.apache.commons:commons-csv:1.9.0')
api('com.github.GTNewHorizons:CodeChickenCore:1.4.1:dev')
implementation('com.github.GTNewHorizons:GTNHLib:0.6.5:dev')
shadowImplementation('org.apache.commons:commons-csv:1.10.0')
}
+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.
# Due to a history of using JitPack, the default is com.github.GTNewHorizons for all mods.
useModGroupForPublishing = false
# Will update your build.gradle automatically whenever an update is available
# Updates your build.gradle and settings.gradle automatically whenever an update is available.
autoUpdateBuildScript = false
# Version of Minecraft to target
minecraftVersion = 1.7.10
# Version of Minecraft Forge to target
forgeVersion = 10.13.4.1614
# Select a username for testing your mod with breakpoints. You may leave this empty for a random username each time you
# restart Minecraft in development. Choose this dependent on your mod:
# Do you need consistent player progressing (for example Thaumcraft)? -> Select a name
# Do you need to test how your custom blocks interacts with a player that is not the owner? -> leave name empty
# Specify an MCP channel for dependency deobfuscation and the deobfParams task.
channel = stable
# Specify an MCP mappings version for dependency deobfuscation and the deobfParams task.
mappingsVersion = 12
# Defines other MCP mappings for dependency deobfuscation.
remoteMappings = https\://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/
# Select a default username for testing your mod. You can always override this per-run by running
# `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE.
developmentEnvironmentUserName = Developer
# Define a source file of your project with:
# public static final String VERSION = "GRADLETOKEN_VERSION";
# The string's content will be replaced with your mod's version when compiled. You should use this to specify your mod's
# version in @Mod([...], version = VERSION, [...])
# Leave these properties empty to skip individual token replacements
# Generate a class with String fields for the mod id, name, version and group name named with the fields below
# Enables using modern Java syntax (up to version 17) via Jabel, while still targeting JVM 8.
# See https://github.com/bsideup/jabel for details on how this works.
enableModernJavaSyntax = true
# Enables injecting missing generics into the decompiled source code for a better coding experience.
# Turns most publicly visible List, Map, etc. into proper List<E>, Map<K, V> types.
enableGenericInjection = true
# Generate a class with a String field for the mod version named as defined below.
# If generateGradleTokenClass is empty or not missing, no such class will be generated.
# If gradleTokenVersion is empty or missing, the field will not be present in the class.
generateGradleTokenClass = codechicken.nei.Tags
gradleTokenModId = MODID
gradleTokenModName = MODNAME
# Name of the token containing the project's current version to generate/replace.
gradleTokenVersion = VERSION
gradleTokenGroupName = GROUPNAME
# [DEPRECATED] Mod ID replacement token.
gradleTokenModId =
# [DEPRECATED] Mod name replacement token.
gradleTokenModName =
# [DEPRECATED] Mod Group replacement token.
gradleTokenGroupName =
# [DEPRECATED]
# Multiple source files can be defined here by providing a comma-seperated list: Class1.java,Class2.java,Class3.java
# Multiple source files can be defined here by providing a comma-separated list: Class1.java,Class2.java,Class3.java
# public static final String VERSION = "GRADLETOKEN_VERSION";
# The string's content will be replaced with your mod's version when compiled. You should use this to specify your mod's
# version in @Mod([...], version = VERSION, [...])
# Leave these properties empty to skip individual token replacements
# version in @Mod([...], version = VERSION, [...]).
# Leave these properties empty to skip individual token replacements.
replaceGradleTokenInFile =
# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can
# leave this property empty.
# Example value: apiPackage = api + modGroup = com.myname.mymodid -> com.myname.mymodid.api
# Example value: (apiPackage = api) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.api
apiPackage =
# Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/META-INF/
# Example value: mymodid_at.cfg
# There can be multiple files in a space-separated list.
# Example value: mymodid_at.cfg nei_at.cfg
accessTransformersFile = nei_at.cfg
# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled!
usesMixins = false
# Specify the location of your implementation of IMixinPlugin. Leave it empty otherwise.
# Set to a non-empty string to configure mixins in a separate source set under src/VALUE, instead of src/main.
# This can speed up compile times thanks to not running the mixin annotation processor on all input sources.
# Mixin classes will have access to "main" classes, but not the other way around.
separateMixinSourceSet =
# Adds some debug arguments like verbose output and class export.
usesMixinDebug = false
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
mixinPlugin =
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
mixinsPackage =
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
# This parameter is for legacy compatibility only
# Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin
# Example value: (coreModClass = asm.FMLPlugin) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.asm.FMLPlugin
coreModClass = asm.NEICorePlugin
# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class
# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false!
containsMixinsAndOrCoreModOnly = true
# If enabled, you may use 'shadowImplementation' for dependencies. They will be integrated in your jar. It is your
# responsibility check the licence and request permission for distribution, if required.
# Enables Mixins even if this mod doesn't use them, useful if one of the dependencies uses mixins.
forceEnableMixins = false
# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated into your jar. It is your
# responsibility to check the license and request permission for distribution if required.
usesShadowedDependencies = true
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
# If disabled, won't remove unused classes from shadowed dependencies. Some libraries use reflection to access
# their own classes, making the minimization unreliable.
minimizeShadowedDependencies = true
# The project's numeric ID on CurseForge. You can find this in the About Project box.
# Leave this empty if you don't want to publish on CurseForge.
curseForgeProjectId = 358228
# If disabled, won't rename the shadowed classes.
relocateShadowedDependencies = true
# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge.
# Syntax: type1:name1;type2:name2;...
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
# and the name is the CurseForge project id of the other mod.
curseForgeRelations = requiredDependency:codechickencore-unofficial;requiredDependency:codechickenlib-unofficial
# Adds CurseMaven, Modrinth, and some more well-known 1.7.10 repositories.
includeWellKnownRepositories = true
# A list of repositories to exclude from the includeWellKnownRepositories setting. Should be a space separated
# list of strings, with the acceptable keys being(case does not matter):
# cursemaven
# modrinth
excludeWellKnownRepositories =
# Publishing to modrinth requires you to set the MODRINTH_TOKEN environment variable to your current modrinth API token.
# Change these to your Maven coordinates if you want to publish to a custom Maven repository instead of the default GTNH Maven.
# Authenticate with the MAVEN_USER and MAVEN_PASSWORD environment variables.
# If you need a more complex setup disable maven publishing here and add a publishing repository to addon.gradle.
usesMavenPublishing = true
# Maven repository to publish the mod to.
# mavenPublishUrl = https\://nexus.gtnewhorizons.com/repository/releases/
# Publishing to Modrinth requires you to set the MODRINTH_TOKEN environment variable to your current Modrinth API token.
#
# The project's ID on Modrinth. Can be either the slug or the ID.
# Leave this empty if you don't want to publish on Modrinth.
# Leave this empty if you don't want to publish to Modrinth.
modrinthProjectId = notenoughitems-unofficial
# The project's relations on Modrinth. You can use this to refer to other projects on Modrinth.
@@ -92,7 +150,54 @@ modrinthProjectId = notenoughitems-unofficial
# Where scope can be one of [required, optional, incompatible, embedded],
# type can be one of [project, version],
# and the name is the Modrinth project or version slug/id of the other mod.
# Example: required-project:fplib;optional-project:gasstation;incompatible-project:gregtech
# Note: GTNH Mixins is automatically set as a required dependency if usesMixins = true
modrinthRelations = required-project\:codechickencore-unofficial
modrinthRelations = required-project:codechickenlib-unofficial;required-project:codechickencore-unofficial
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
#
# The project's numeric ID on CurseForge. You can find this in the About Project box.
# Leave this empty if you don't want to publish on CurseForge.
curseForgeProjectId = 358228
# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge.
# Syntax: type1:name1;type2:name2;...
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
# and the name is the CurseForge project slug of the other mod.
# Example: requiredDependency:railcraft;embeddedLibrary:cofhlib;incompatible:buildcraft
# Note: UniMixins is automatically set as a required dependency if usesMixins = true.
curseForgeRelations = requiredDependency\:codechickencore-unofficial
# Optional parameter to customize the produced artifacts. Use this to preserve artifact naming when migrating older
# projects. New projects should not use this parameter.
# customArchiveBaseName =
# Optional parameter to have the build automatically fail if an illegal version is used.
# This can be useful if you e.g. only want to allow versions in the form of '1.1.xxx'.
# The check is ONLY performed if the version is a git tag.
# Note: the specified string must be escaped, so e.g. 1\\.1\\.\\d+ instead of 1\.1\.\d+
# versionPattern =
# Uncomment to prevent the source code from being published.
# noPublishedSources = true
# Uncomment this to disable Spotless checks.
# This should only be uncommented to keep it easier to sync with upstream/other forks.
# That is, if there is no other active fork/upstream, NEVER change this.
# disableSpotless = true
# Uncomment this to disable Checkstyle checks (currently wildcard import check).
# disableCheckstyle = true
# Override the IDEA build type. Valid values are: "" (leave blank, do not override), "idea" (force use native IDEA build), "gradle"
# (force use delegated build).
# This is meant to be set in $HOME/.gradle/gradle.properties.
# e.g. add "systemProp.org.gradle.project.ideaOverrideBuildType=idea" will override the build type to be native build.
# WARNING: If you do use this option, it will overwrite whatever you have in your existing projects. This might not be what you want!
# Usually there is no need to uncomment this here as other developers do not necessarily use the same build type as you.
# ideaOverrideBuildType = idea
# Whether IDEA should run spotless checks when pressing the Build button.
# This is meant to be set in $HOME/.gradle/gradle.properties.
# ideaCheckSpotlessOnBuild = true
Binary file not shown.
+2 -1
View File
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+21 -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,9 @@ 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
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -133,10 +134,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 +148,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 +156,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 +201,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, 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
-11
View File
@@ -1,15 +1,4 @@
// Add any additional repositiroes for your dependencies here
repositories {
mavenCentral()
maven {
name 'GTNH Maven'
url 'http://jenkins.usrv.eu:8081/nexus/content/groups/public/'
}
maven {
url 'https://cursemaven.com'
content {
includeGroup 'curse.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.31'
}
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());
}
}
@@ -0,0 +1,319 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import codechicken.nei.BookmarkPanel.ItemStackMetadata;
import codechicken.nei.recipe.BookmarkRecipeId;
import codechicken.nei.recipe.StackInfo;
public class BookmarkCraftingChain {
public HashMap<ItemStack, ItemStack> calculatedItems = new HashMap<>();
public HashMap<ItemStack, Integer> multiplier = new HashMap<>();
public HashMap<ItemStack, ItemStack> inputs = new HashMap<>();
public HashMap<ItemStack, ItemStack> outputs = new HashMap<>();
public HashMap<ItemStack, ItemStack> remainder = new HashMap<>();
public HashMap<ItemStack, ItemStack> intermediate = new HashMap<>();
protected static class CraftingChainItem {
public String guid;
public int stackIndex = 0;
public int recipeIndex = 0;
public int factor = 0;
public int count = 0;
public boolean ingredient = false;
public int fluidCellAmount = 1;
public ItemStack stack = null;
public CraftingChainItem(ItemStack stack, ItemStackMetadata stackMetadata) {
FluidStack fluid = StackInfo.getFluid(stack);
this.recipeIndex = getRecipeIndex(stackMetadata.recipeId);
this.ingredient = stackMetadata.ingredient;
this.stack = stack;
if (fluid != null) {
this.stackIndex = getStackIndex(fluid);
this.count = fluid.amount * Math.max(0, stack.stackSize);
this.fluidCellAmount = StackInfo.isFluidContainer(stack) ? fluid.amount : 1;
this.factor = this.fluidCellAmount * stackMetadata.factor;
} else {
this.stackIndex = getStackIndex(stack);
this.count = StackInfo.itemStackToNBT(stack).getInteger("Count");
this.factor = stackMetadata.factor;
}
this.guid = this.stackIndex + " " + this.recipeIndex;
}
public ItemStack getItemStack(long count) {
return StackInfo.loadFromNBT(
StackInfo.itemStackToNBT(this.stack),
this.factor > 0 ? (count / this.fluidCellAmount) : 0);
}
public static void clearStatic() {
itemCache.clear();
fluidCache.clear();
recipeCache.clear();
}
private static HashMap<ItemStack, Integer> itemCache = new HashMap<>();
private static int getStackIndex(ItemStack stackA) {
if (!itemCache.containsKey(stackA)) {
for (ItemStack item : itemCache.keySet()) {
if (StackInfo.equalItemAndNBT(stackA, item, true)) {
itemCache.put(stackA, itemCache.get(item));
return itemCache.get(stackA);
}
}
itemCache.put(stackA, itemCache.size() + fluidCache.size());
}
return itemCache.get(stackA);
}
private static HashMap<FluidStack, Integer> fluidCache = new HashMap<>();
private static int getStackIndex(FluidStack fluidA) {
if (!fluidCache.containsKey(fluidA)) {
for (FluidStack item : fluidCache.keySet()) {
if (fluidA.isFluidEqual(item)) {
fluidCache.put(fluidA, fluidCache.get(item));
return fluidCache.get(fluidA);
}
}
fluidCache.put(fluidA, itemCache.size() + fluidCache.size());
}
return fluidCache.get(fluidA);
}
private static HashMap<BookmarkRecipeId, Integer> recipeCache = new HashMap<>();
private static int getRecipeIndex(BookmarkRecipeId recipe) {
if (recipe == null) {
return -1;
}
if (!recipeCache.containsKey(recipe)) {
for (BookmarkRecipeId item : recipeCache.keySet()) {
if (item.equals(recipe)) {
recipeCache.put(recipe, recipeCache.get(item));
return recipeCache.get(recipe);
}
}
recipeCache.put(recipe, recipeCache.size());
}
return recipeCache.get(recipe);
}
}
protected static class CraftingChainRequest {
public List<CraftingChainItem> items = new ArrayList<>();
public HashMap<Integer, Integer> multiplier = new HashMap<>();
public HashMap<String, Long> counts = new HashMap<>();
public HashMap<Integer, HashSet<CraftingChainItem>> inputs = new HashMap<>();
public HashMap<Integer, HashSet<CraftingChainItem>> outputs = new HashMap<>();
public HashSet<Integer> initialItems = new HashSet<>();
public HashSet<Integer> startedIngrs = new HashSet<>();
public CraftingChainRequest(List<ItemStack> items, List<ItemStackMetadata> metadata) {
HashSet<Integer> inputs = new HashSet<>();
HashSet<Integer> outputs = new HashSet<>();
for (int index = 0; index < items.size(); index++) {
CraftingChainItem item = new CraftingChainItem(items.get(index), metadata.get(index));
item.guid = item.ingredient ? "i" + item.guid : "r" + item.guid;
this.items.add(item);
if (this.multiplier.get(item.recipeIndex) == null) {
this.multiplier.put(item.recipeIndex, 0);
}
this.counts.put(item.guid, this.counts.getOrDefault(item.guid, 0L) + item.count);
if (item.ingredient) {
inputs.add(item.recipeIndex);
if (this.inputs.get(item.stackIndex) == null) {
this.inputs.put(item.stackIndex, new HashSet<>());
}
this.inputs.get(item.stackIndex).add(item);
} else {
outputs.add(item.recipeIndex);
if (this.outputs.get(item.stackIndex) == null) {
this.outputs.put(item.stackIndex, new HashSet<>());
}
this.outputs.get(item.stackIndex).add(item);
}
}
for (int recipeIndex : this.multiplier.keySet()) {
if (recipeIndex == -1 || !inputs.contains(recipeIndex) || !outputs.contains(recipeIndex)) {
this.initialItems.add(recipeIndex);
}
}
for (CraftingChainItem item : this.items) {
if (item.ingredient == false && !this.initialItems.contains(item.recipeIndex)) {
this.startedIngrs.add(item.stackIndex);
}
}
CraftingChainItem.clearStatic();
}
}
public void refresh(List<ItemStack> items, List<ItemStackMetadata> metadata) {
CraftingChainRequest request = new CraftingChainRequest(items, metadata);
HashMap<Integer, Long> iShift = new HashMap<>();
HashMap<Integer, Long> oShift = new HashMap<>();
boolean change = true;
int iteration = 100;
while (--iteration > 0 && change) {
change = false;
for (int stackIndex : request.startedIngrs) {
change = calculateShift(request, stackIndex) || change;
}
}
this.inputs.clear();
this.outputs.clear();
this.remainder.clear();
this.intermediate.clear();
this.calculatedItems.clear();
this.multiplier.clear();
for (CraftingChainItem item : request.items) {
if (request.initialItems.contains(item.recipeIndex)) {
long iCount = calculateCount(request, request.inputs.get(item.stackIndex))
- iShift.getOrDefault(item.stackIndex, 0L);
this.calculatedItems.put(item.stack, item.stack);
if (iCount == 0) {
this.inputs.put(item.stack, item.getItemStack(0));
} else {
long count = Math.min(iCount, item.count);
this.inputs.put(item.stack, item.getItemStack(count));
iShift.put(item.stackIndex, iShift.getOrDefault(item.stackIndex, 0L) + count);
}
}
}
for (CraftingChainItem item : request.items) {
if (!request.initialItems.contains(item.recipeIndex)) {
long count = item.count + item.factor * request.multiplier.get(item.recipeIndex);
this.calculatedItems.put(item.stack, item.getItemStack(count));
if (item.ingredient) { // input
long oCount = calculateCount(request, request.outputs.get(item.stackIndex))
- oShift.getOrDefault(item.stackIndex, 0L);
if (oCount < count) {
this.inputs.put(item.stack, item.getItemStack(count - oCount));
oShift.put(item.stackIndex, oShift.getOrDefault(item.stackIndex, 0L) + oCount);
} else if (oCount >= count) {
this.intermediate.put(item.stack, item.getItemStack(0));
oShift.put(item.stackIndex, oShift.getOrDefault(item.stackIndex, 0L) + count);
}
} else { // output
long iCalcCount = calculateCount(request, request.inputs.get(item.stackIndex));
long iCount = iCalcCount - iShift.getOrDefault(item.stackIndex, 0L);
this.multiplier.put(item.stack, item.factor > 0 ? (int) (count / item.factor) : 0);
if (iCount >= count) {
this.intermediate.put(item.stack, item.getItemStack(0));
iShift.put(item.stackIndex, iShift.getOrDefault(item.stackIndex, 0L) + count);
} else if (iCalcCount > 0) {
this.remainder.put(item.stack, item.getItemStack(count - iCount));
iShift.put(item.stackIndex, iShift.getOrDefault(item.stackIndex, 0L) + iCount);
} else {
this.outputs.put(item.stack, item.getItemStack(count - iCount));
iShift.put(item.stackIndex, iShift.getOrDefault(item.stackIndex, 0L) + iCount);
}
}
}
}
}
private boolean calculateShift(CraftingChainRequest request, int stackIndex) {
if (!request.outputs.containsKey(stackIndex)) {
return false;
}
int minRecipeIndex = 0;
int minShift = Integer.MAX_VALUE;
for (CraftingChainItem item : request.outputs.get(stackIndex)) {
if (!request.initialItems.contains(item.recipeIndex) && item.factor > 0) {
long ingrCount = calculateCount(request, request.inputs.get(item.stackIndex), item.recipeIndex);
long outputCount = calculateCount(request, request.outputs.get(item.stackIndex));
long shift = (long) Math.ceil((ingrCount - outputCount) / (double) item.factor);
if (shift > 0 && shift < minShift) {
minShift = (int) shift;
minRecipeIndex = item.recipeIndex;
}
}
}
if (minShift < Integer.MAX_VALUE) {
request.multiplier.put(minRecipeIndex, request.multiplier.get(minRecipeIndex) + minShift);
return true;
}
return false;
}
private long calculateCount(CraftingChainRequest request, HashSet<CraftingChainItem> items) {
return calculateCount(request, items, -1);
}
private long calculateCount(CraftingChainRequest request, HashSet<CraftingChainItem> items, int recipeIndex) {
long count = 0L;
if (items != null) {
for (CraftingChainItem item : items) {
if (item.recipeIndex != recipeIndex || recipeIndex == -1) {
count += request.counts.get(item.guid) + item.factor * request.multiplier.get(item.recipeIndex);
}
}
}
return count;
}
}
File diff suppressed because it is too large. Load diff
+102 -97
View File
@@ -1,22 +1,19 @@
package codechicken.nei;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.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;
@@ -31,46 +28,34 @@ import net.minecraft.entity.item.EntityItem;
import net.minecraft.world.World;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.WorldEvent;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.io.IOUtils;
import com.google.common.collect.Lists;
import codechicken.core.ClassDiscoverer;
import codechicken.core.ClientUtils;
import codechicken.core.GuiModListScroll;
import codechicken.lib.packet.PacketCustom;
import codechicken.nei.api.API;
import codechicken.nei.api.IConfigureNEI;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.StackInfo;
import cpw.mods.fml.client.CustomModLoadingErrorDisplayException;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.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;
@@ -155,50 +140,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,54 +227,38 @@ 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 ClassDiscoverer classDiscoverer = new ClassDiscoverer(
test -> test.startsWith("NEI") && test.endsWith("Config.class"),
IConfigureNEI.class);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) {
NEIClientConfig.logger.info("Loading handler ordering from file {}", file);
CSVParser csvParser = CSVFormat.EXCEL.withCommentMarker('#').parse(reader);
for (CSVRecord record : csvParser) {
final String handlerId = record.get(0);
int ordering;
try {
ordering = Integer.parseInt(record.get(1));
} catch (NumberFormatException e) {
NEIClientConfig.logger.error("Error parsing CSV record {}: {}", record, e);
continue;
}
NEIClientConfig.handlerOrdering.put(handlerId, ordering);
}
} catch (Exception e) {
NEIClientConfig.logger.info("Error parsing CSV");
e.printStackTrace();
}
NEIClientConfig.pluginsList.addAll(classDiscoverer.findClasses());
}
@SubscribeEvent
@@ -309,6 +305,15 @@ public class ClientHandler {
if (NEIClientConfig.isEnabled()) WorldOverlayRenderer.render(event.partialTicks);
}
@SideOnly(Side.CLIENT)
@SubscribeEvent
public void onWorldUnload(WorldEvent.Unload event) {
Minecraft mc = Minecraft.getMinecraft();
if (event.world == mc.theWorld) {
NEIClientConfig.unloadWorld();
}
}
public void loadWorld(World world, boolean fromServer) {
if (world != lastworld) {
SMPmagneticItems.clear();
@@ -320,9 +325,8 @@ public class ClientHandler {
if (!Minecraft.getMinecraft().isSingleplayer()) // wait for server to initiate in singleplayer
NEIClientConfig.loadWorld("remote/" + ClientUtils.getServerIP().replace(':', '~'));
ItemMobSpawner.clearEntityReferences(world);
}
ItemMobSpawner.clearEntityReferences(world);
lastworld = world;
}
@@ -350,9 +354,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,245 @@
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) {
final GroupItem group = CollapsibleItems.groups.stream().filter(g -> g.matches(stack)).findFirst().orElse(null);
if (group != null) {
CollapsibleItems.cache.put(stack, CollapsibleItems.groups.indexOf(group));
}
}
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 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.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 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;
}
@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_;
}
@Override
public void drawTextBox() {
if (this.getVisible()) {
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;
}
}
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(this.getCursorPosition());
int selectionEnd = getFormattedTextShift(this.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 = this.isFocused() && this.frame / 6 % 2 == 0 && flag;
boolean flag2 = this.getCursorPosition() < this.rawText.length()
|| this.rawText.length() >= this.getMaxStringLength();
int x = this.getEnableBackgroundDrawing() ? this.xPosition + 4 : this.xPosition;
int y = this.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,122 @@
package codechicken.nei;
import static codechicken.nei.NEIClientUtils.translate;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.guihook.IContainerTooltipHandler;
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.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> handleItemDisplayName(GuiContainer gui, ItemStack itemstack, List<String> currenttip) {
return currenttip;
}
@Override
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
List<String> currenttip) {
return currenttip;
}
@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,189 @@
package codechicken.nei;
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.ItemPanel.ItemPanelSlot;
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 {
protected int mouseDownSlot = -1;
protected ItemsGrid grid;
public ItemHistoryPanel() {
grid = new ItemsGrid();
}
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());
}
grid.draw(mousex, mousey);
}
public void update() {
grid.update();
}
public void addItem(ItemStack stack) {
if (stack != null) {
ItemStack is = StackInfo.loadFromNBT(StackInfo.itemStackToNBT(stack), 0);
grid.realItems.removeIf(historyStack -> StackInfo.equalItemAndNBT(historyStack, stack, true));
grid.realItems.add(0, is);
if (grid.realItems.size() > Math.max(50, grid.rows * grid.columns)) {
grid.realItems.remove(grid.realItems.size() - 1);
}
grid.onItemsChanged();
}
}
public void resize(GuiContainer gui) {
grid.setGridSize(x, y, w, h);
grid.refresh(gui);
}
@Override
public ItemStack getStackMouseOver(int mousex, int mousey) {
ItemPanelSlot slot = getSlotMouseOver(mousex, mousey);
return slot == null ? null : slot.item;
}
public ItemPanelSlot 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 (mouseDownSlot >= 0 && ItemPanels.itemPanel.draggedStack == null
&& NEIClientUtils.getHeldItem() == null
&& NEIClientConfig.hasSMPCounterPart()) {
ItemPanelSlot mouseOverSlot = getSlotMouseOver(mousex, mousey);
if (mouseOverSlot == null || mouseOverSlot.slotIndex != mouseDownSlot || heldTime > 500) {
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(mouseDownSlot);
mouseDownSlot = -1;
}
}
}
@Override
public boolean handleClick(int mousex, int mousey, int button) {
if (handleClickExt(mousex, mousey, button)) return true;
ItemPanelSlot hoverSlot = getSlotMouseOver(mousex, mousey);
if (hoverSlot != null) {
if (button == 2) {
if (hoverSlot.item != null) {
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(hoverSlot.slotIndex);
}
} else {
mouseDownSlot = hoverSlot.slotIndex;
}
return true;
}
return false;
}
@Override
public void mouseUp(int mousex, int mousey, int button) {
ItemPanelSlot hoverSlot = getSlotMouseOver(mousex, mousey);
if (hoverSlot != null && hoverSlot.slotIndex == mouseDownSlot && ItemPanels.itemPanel.draggedStack == null) {
ItemStack item = hoverSlot.item.copy();
if (NEIController.manager.window instanceof GuiRecipe || NEIClientUtils.shiftKey()
|| !NEIClientConfig.canCheatItem(item)) {
if (button == 0) {
GuiCraftingRecipe.openRecipeGui("item", item);
} else if (button == 1) {
GuiUsageRecipe.openRecipeGui("item", item);
}
mouseDownSlot = -1;
return;
}
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.slotIndex), button, -1);
}
mouseDownSlot = -1;
}
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();
}
return NEIServerUtils.copyStack(stack, amount);
}
return null;
}
}
+191 -42
View File
@@ -1,16 +1,23 @@
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.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 +27,7 @@ import codechicken.nei.ThreadOperationTimer.TimeoutException;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.search.TooltipFilter;
public class ItemList {
@@ -36,11 +43,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 HashMap<ItemStack, Integer> ordering = new HashMap<>();
/**
* Unlike {@link LayoutManager#itemsLoaded}, this indicates whether item loading is actually finished or not.
*/
@@ -62,6 +69,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 +93,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 +118,10 @@ public class ItemList {
this.filters = filters;
}
public AllMultiItemFilter(ItemFilter... filters) {
this(new LinkedList<>(Arrays.asList(filters)));
}
public AllMultiItemFilter() {
this(new LinkedList<>());
}
@@ -91,9 +129,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 +154,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 +172,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 +197,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,7 +211,7 @@ 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);
@@ -185,43 +228,126 @@ 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) {
ItemSorter.sort(items);
HashMap<ItemStack, Integer> newOrdering = new HashMap<>();
if (!CollapsibleItems.isEmpty()) {
HashMap<Integer, Integer> groups = new HashMap<>();
int orderIndex = 0;
for (ItemStack stack : items) {
final int groupIndex = CollapsibleItems.getGroupIndex(stack);
if (groupIndex == -1) {
newOrdering.put(stack, orderIndex++);
} else {
if (!groups.containsKey(groupIndex)) {
groups.put(groupIndex, orderIndex++);
}
newOrdering.put(stack, groups.get(groupIndex));
}
}
} else {
int orderIndex = 0;
for (ItemStack stack : items) {
newOrdering.put(stack, orderIndex++);
}
}
ItemList.ordering = newOrdering;
}
private List<ItemStack> getPermutations(Item item) {
final List<ItemStack> permutations = new LinkedList<>(ItemInfo.itemOverrides.get(item));
if (permutations.isEmpty()) {
item.getSubItems(item, null, permutations);
}
if (permutations.isEmpty()) {
damageSearch(item, permutations);
}
permutations.addAll(ItemInfo.itemVariants.get(item));
return permutations.stream()
.filter(
stack -> stack.getItem() != null && stack.getItem().delegate.name() != null
&& !ItemInfo.isHidden(stack))
.collect(Collectors.toList());
}
// For optimization it generate itemslist, permutations, orders & collapsibleitems
@Override
@SuppressWarnings("unchecked")
public void execute() {
// System.out.println("Executing NEI Item Loading");
if (!NEIClientConfig.isEnabled()) return;
ThreadOperationTimer timer = getTimer(NEIClientConfig.getItemLoadingTimeout());
LayoutManager.itemsLoaded = true;
loadFinished = false;
LinkedList<ItemStack> items = new LinkedList<>();
LinkedList<ItemStack> permutations = new LinkedList<>();
SearchField.searchParser.clearCache();
ItemSorter.instance.ordering.clear();
CollapsibleItems.clearCache();
TooltipFilter.clearCache();
List<ItemStack> items = new ArrayList<>();
ListMultimap<Item, ItemStack> itemMap = ArrayListMultimap.create();
ItemStackSet unique = new ItemStackSet();
timer.setLimit(NEIClientConfig.getItemLoadingTimeout());
for (Item item : (Iterable<Item>) Item.itemRegistry) {
if (interrupted()) return;
if (item == null || erroredItems.contains(item)) continue;
StreamSupport.stream(((Iterable<Item>) Item.itemRegistry).spliterator(), true).forEach(item -> {
if (item == null || item.delegate.name() == null || erroredItems.contains(item)) return;
try {
timer.reset(item);
permutations.clear();
permutations.addAll(ItemInfo.itemOverrides.get(item));
if (permutations.isEmpty()) item.getSubItems(item, null, permutations);
if (permutations.isEmpty()) damageSearch(item, permutations);
permutations.addAll(ItemInfo.itemVariants.get(item));
List<ItemStack> permutations = getPermutations(item);
timer.reset();
items.addAll(permutations);
itemMap.putAll(item, permutations);
for (ItemStack stack : permutations) {
if (!unique.contains(stack)) {
synchronized (unique) {
unique.add(stack);
}
synchronized (items) {
items.add(stack);
}
CollapsibleItems.putItem(stack);
}
}
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 +355,51 @@ public class ItemList {
ItemList.itemMap = itemMap;
for (ItemsLoadedCallback callback : loadCallbacks) callback.itemsLoaded();
updateFilter.restart();
if (interrupted()) return;
updateOrdering(ItemList.items);
new Thread(
() -> ItemList.items.parallelStream().forEach(TooltipFilter::getSearchTooltip),
"NEI Tooltip Filter Loader").start();
loadFinished = true;
SubsetWidget.updateHiddenItems();
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 +409,12 @@ public class ItemList {
}
if (interrupted()) return;
ItemSorter.sort(filtered);
Comparator<ItemStack> comparator = Comparator.comparingInt(ItemList.ordering::get);
filtered.sort(comparator::compare);
if (interrupted()) return;
ItemPanel.updateItemList(filtered);
}
};
@@ -22,8 +22,8 @@ import net.minecraftforge.client.MinecraftForgeClient;
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;
@@ -32,9 +32,6 @@ public class ItemMobSpawner extends ItemBlock {
hasSubtypes = true;
MinecraftForgeClient.registerItemRenderer(this, new SpawnerRenderer());
entityHashMap = new HashMap<>();
IDtoNameMap = new HashMap<>();
}
/**
@@ -69,7 +66,7 @@ public class ItemMobSpawner extends ItemBlock {
}
@Override
public void addInformation(ItemStack itemstack, EntityPlayer par2EntityPlayer, List list, boolean par4) {
public void addInformation(ItemStack itemstack, EntityPlayer par2EntityPlayer, List<String> list, boolean par4) {
setDefaultTag(itemstack);
int meta = itemstack.getItemDamage();
if (meta == 0) {
@@ -109,9 +106,10 @@ public class ItemMobSpawner extends ItemBlock {
public static void loadSpawners(World world) {
if (loaded) return;
loaded = true;
HashMap<Class<Entity>, String> classToStringMapping = (HashMap<Class<Entity>, String>) EntityList.classToStringMapping;
HashMap<Class<Entity>, Integer> classToIDMapping = (HashMap<Class<Entity>, Integer>) EntityList.classToIDMapping;
for (Class<Entity> eclass : classToStringMapping.keySet()) {
Map<Class<? extends Entity>, String> classToStringMapping = EntityList.classToStringMapping;
@SuppressWarnings("unchecked")
Map<Class<? extends Entity>, Integer> classToIDMapping = (Map<Class<? extends Entity>, Integer>) EntityList.classToIDMapping;
for (Class<? extends Entity> eclass : classToStringMapping.keySet()) {
if (!EntityLiving.class.isAssignableFrom(eclass)) continue;
try {
EntityLiving entityliving = (EntityLiving) eclass.getConstructor(new Class[] { World.class })
@@ -134,7 +132,7 @@ public class ItemMobSpawner extends ItemBlock {
}
@Override
public void getSubItems(Item item, CreativeTabs tab, List list) {
public void getSubItems(Item item, CreativeTabs tab, List<ItemStack> list) {
if (!NEIClientConfig.hasSMPCounterPart()) list.add(new ItemStack(item));
else for (int i : IDtoNameMap.keySet()) list.add(new ItemStack(item, 1, i));
}
+350 -68
View File
@@ -1,15 +1,25 @@
package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.drawRect;
import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.guihook.GuiContainerManager;
public class ItemPanel extends PanelWidget {
@@ -31,9 +41,8 @@ public class ItemPanel extends PanelWidget {
return super.getStackMouseOver(mousex, mousey);
}
public Button more;
public Button less;
public ItemQuantityField quantity;
public ItemHistoryPanel historyPanel;
public Button toggleGroups;
public static class ItemPanelSlot {
@@ -51,9 +60,30 @@ public class ItemPanel extends PanelWidget {
}
}
protected static class MaskMetadata {
public int groupIndex = -1;
public String displayName = "";
public boolean extended = false;
public Color bgColor = null;
public Color color = null;
public boolean left = false;
public boolean top = false;
public boolean right = false;
public boolean bottom = false;
}
protected static class ItemPanelGrid extends ItemsGrid {
public ArrayList<ItemStack> newItems;
public ArrayList<ItemStack> rawItems;
protected final HashMap<Integer, List<ItemStack>> groupItems = new HashMap<>();
protected final HashMap<Integer, MaskMetadata> maskMetadata = new HashMap<>();
protected boolean forceExpand = false;
public void setItems(ArrayList<ItemStack> items) {
newItems = items;
@@ -61,21 +91,220 @@ public class ItemPanel extends PanelWidget {
public void refresh(GuiContainer gui) {
if (newItems != null) {
realItems = newItems;
newItems = null;
onGridChanged();
if (this.newItems != null) {
this.groupItems.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.realItems.add(stack);
groups.add(groupIndex);
}
if (!this.groupItems.containsKey(groupIndex)) {
this.groupItems.put(groupIndex, new ArrayList<>());
}
this.groupItems.get(groupIndex).add(stack);
}
}
// automatically opens if there are elements from only one group
if (!outsideGroup && groups.size() == 1) {
this.realItems = new ArrayList<>(this.newItems);
this.forceExpand = true;
}
} else {
this.realItems = new ArrayList<>(this.newItems);
}
this.newItems = null;
onItemsChanged();
}
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);
protected List<Integer> getMask() {
final boolean updateBorders = this.gridMask == null;
final List<Integer> mask = super.getMask();
if (updateBorders) {
calculateGroupBorders(mask);
}
return mask;
}
protected void calculateGroupBorders(List<Integer> mask) {
this.maskMetadata.clear();
if (mask.isEmpty() || this.groupItems.isEmpty()) {
return;
}
final HashMap<Integer, Integer> maskGroup = new HashMap<>();
final Color collapsedColor = new Color(
NEIClientConfig.getSetting("inventory.collapsibleItems.collapsedColor").getHexValue(),
true);
final Color expandedColor = new Color(
NEIClientConfig.getSetting("inventory.collapsibleItems.expandedColor").getHexValue(),
true);
for (int slotIndex = 0; slotIndex < mask.size(); slotIndex++) {
if (mask.get(slotIndex) == null) {
continue;
}
int idx = mask.get(slotIndex);
maskGroup.put(idx, CollapsibleItems.getGroupIndex(getItem(idx)));
}
for (int slotIndex = 0; slotIndex < mask.size(); slotIndex++) {
if (mask.get(slotIndex) == null) {
continue;
}
int idx = mask.get(slotIndex);
int groupIndex = maskGroup.get(idx);
if (groupIndex == -1 || this.groupItems.get(groupIndex).size() == 1) {
continue;
}
int column = slotIndex % this.columns;
int row = slotIndex / this.columns;
int prevSlotIndex = (row - 1) * this.columns + column;
int nextSlotIndex = (row + 1) * this.columns + column;
MaskMetadata metadata = new MaskMetadata();
metadata.groupIndex = groupIndex;
metadata.displayName = CollapsibleItems.getDisplayName(groupIndex);
metadata.extended = this.forceExpand || CollapsibleItems.isExpanded(groupIndex);
metadata.bgColor = metadata.extended ? expandedColor : collapsedColor;
metadata.color = darkerColor(metadata.bgColor);
metadata.left = column == 0 || idx == 0
|| mask.get(slotIndex - 1) == null
|| maskGroup.getOrDefault(idx - 1, -1) != groupIndex;
metadata.right = column == this.columns - 1 || maskGroup.getOrDefault(idx + 1, -1) != groupIndex;
if (prevSlotIndex >= 0) {
Integer previdx = mask.get(prevSlotIndex);
metadata.top = previdx == null || maskGroup.getOrDefault(previdx, -1) != groupIndex;
} else {
metadata.top = true;
}
if (nextSlotIndex < mask.size()) {
Integer nextidx = mask.get(nextSlotIndex);
metadata.bottom = nextidx == null || maskGroup.getOrDefault(nextidx, -1) != groupIndex;
} else {
metadata.bottom = true;
}
this.maskMetadata.put(idx, metadata);
}
}
@Override
protected void beforeDrawItems(int mousex, int mousey, @Nullable ItemPanelSlot focused) {
final List<Integer> mask = getMask();
super.beforeDrawItems(mousex, mousey, focused);
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) != null) {
drawBorder(mask.get(i), getSlotRect(i));
}
}
}
protected void drawBorder(int slotIdx, Rectangle4i rect) {
final MaskMetadata metadata = this.maskMetadata.get(slotIdx);
if (metadata != null) {
final float LINE_WIDTH = 0.75f;
drawRect(rect.x, rect.y, rect.w, rect.h, metadata.bgColor);
if (metadata.left) {
float leftBottom = metadata.bottom ? -LINE_WIDTH : 0;
drawRect(rect.x, rect.y, LINE_WIDTH, rect.h + leftBottom, metadata.color);
}
if (metadata.right) {
float rightTop = metadata.top ? LINE_WIDTH : 0;
drawRect(rect.x + rect.w, rect.y - rightTop, LINE_WIDTH, rect.h + rightTop, metadata.color);
}
if (metadata.top) {
drawRect(rect.x, rect.y - LINE_WIDTH, rect.w, LINE_WIDTH, metadata.color);
}
if (metadata.bottom) {
drawRect(rect.x, rect.y + rect.h - LINE_WIDTH, rect.w, LINE_WIDTH, metadata.color);
}
}
}
private static Color darkerColor(Color color) {
return new Color(
color.getRed(),
color.getGreen(),
color.getBlue(),
Math.min((int) (color.getAlpha() + (255f / 5) * 2), 255));
}
private 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);
}
@Override
protected void drawItem(Rectangle4i rect, int slotIdx) {
final MaskMetadata metadata = this.maskMetadata.get(slotIdx);
if (metadata != null && !metadata.extended) {
final List<ItemStack> groupItems = this.groupItems.get(metadata.groupIndex);
GuiContainerManager.drawItems.zLevel -= 10F;
GuiContainerManager.drawItem(rect.x + 1, rect.y - 1, groupItems.get(groupItems.size() - 1), true, "");
GuiContainerManager.drawItems.zLevel += 10F;
GuiContainerManager.drawItem(rect.x - 1, rect.y + 1, getItem(slotIdx), true, "");
} else {
super.drawSlotOutline(focused, slotIdx, rect);
super.drawItem(rect, slotIdx);
}
}
@@ -98,42 +327,22 @@ 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");
historyPanel = new ItemHistoryPanel();
}
@Deprecated
@@ -142,7 +351,7 @@ public class ItemPanel extends PanelWidget {
}
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,46 +374,62 @@ 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 = 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);
if (grid.getPerPage() > 0) {
if (!CollapsibleItems.isEmpty() && !grid.isEmpty()) {
LayoutManager.addWidget(toggleGroups);
}
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(int mouseDownSlot) {
ItemStack stack = grid.getItem(mouseDownSlot);
@@ -220,4 +445,61 @@ public class ItemPanel extends PanelWidget {
return null;
}
@Override
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
List<String> currenttip) {
final ItemPanelGrid panelGrid = ((ItemPanelGrid) this.grid);
if (!panelGrid.forceExpand && !NEIClientConfig.isHidden() && !currenttip.isEmpty()) {
final ItemPanelSlot hoverSlot = getSlotMouseOver(mousex, mousey);
if (hoverSlot != null) {
final MaskMetadata metadata = panelGrid.maskMetadata.get(hoverSlot.slotIndex);
if (metadata != null) {
final List<ItemStack> items = panelGrid.groupItems.get(metadata.groupIndex);
if (NEIClientConfig.getBooleanSetting("inventory.collapsibleItems.customName") && !metadata.extended
&& !"".equals(metadata.displayName)) {
currenttip.clear();
currenttip.add(metadata.displayName + GuiDraw.TOOLTIP_LINESPACE);
}
if (items != null && items.size() > 1) {
String message = metadata.extended ? "itempanel.collapsed.hint.collapse"
: "itempanel.collapsed.hint.expand";
currenttip.add(
1,
EnumChatFormatting.GRAY + NEIClientUtils.translate(message, items.size())
+ EnumChatFormatting.RESET);
}
}
}
}
return super.handleItemTooltip(gui, itemstack, mousex, mousey, currenttip);
}
@Override
public boolean handleClick(int mousex, int mousey, int button) {
final ItemPanelGrid panelGrid = ((ItemPanelGrid) this.grid);
if (NEIClientUtils.altKey() && button == 0 && !panelGrid.forceExpand) {
final ItemPanelSlot hoverSlot = grid.getSlotMouseOver(mousex, mousey);
if (hoverSlot != null) {
final MaskMetadata metadata = panelGrid.maskMetadata.get(hoverSlot.slotIndex);
if (metadata != null) {
CollapsibleItems.setExpanded(metadata.groupIndex, !metadata.extended);
panelGrid.setItems(panelGrid.rawItems);
return true;
}
}
}
return super.handleClick(mousex, mousey, button);
}
}
@@ -44,6 +44,7 @@ public class ItemQuantityField extends TextField {
if (!focused() && intValue() == 0) {
field.setText(translate("itempanel.quantity.default"));
field.setCursorPositionZero();
field.setEnabled(false);
super.draw(mousex, mousey);
field.setEnabled(true);
@@ -52,4 +53,20 @@ public class ItemQuantityField extends TextField {
super.draw(mousex, mousey);
}
}
@Override
public boolean onMouseWheel(int i, int mx, int my) {
if (!contains(mx, my)) return false;
int multiplier = 1;
if (NEIClientUtils.shiftKey()) {
multiplier = 10;
} else if (NEIClientUtils.controlKey()) {
multiplier = 64;
}
int quantity = intValue() + i * multiplier;
setText(Integer.toString(quantity));
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,119 @@
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 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);
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);
this.itemMap.put(key, value);
}
public long getOrDefault(ItemStack stack, long defaultAmount) {
final Long e = get(stack);
return e == null ? defaultAmount : e;
}
public void clear() {
this.itemMap.clear();
}
public Long remove(ItemStack stack) {
if (stack == null || stack.getItem() == null) return null;
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
return this.itemMap.remove(key);
}
public boolean removeIf(Predicate<Map.Entry<NBTTagCompound, Long>> predicate) {
return this.itemMap.entrySet().removeIf(predicate);
}
public Set<Map.Entry<NBTTagCompound, Long>> entrySet() {
return this.itemMap.entrySet();
}
public List<ItemStack> values() {
List<ItemStack> list = new ArrayList<>();
for (Map.Entry<NBTTagCompound, Long> entry : this.itemMap.entrySet()) {
list.add(StackInfo.loadFromNBT(entry.getKey(), Math.max(0, entry.getValue())));
}
return list;
}
public int size() {
return this.itemMap.size();
}
public boolean isEmpty() {
return this.itemMap.isEmpty();
}
public static ItemStackAmount of(ItemStackAmount map) {
ItemStackAmount result = new ItemStackAmount();
result.itemMap.putAll(map.itemMap);
return result;
}
public static ItemStackAmount of(ItemStackMap<Long> map) {
ItemStackAmount result = new ItemStackAmount();
for (ItemStackMap.Entry<Long> entry : map.entries()) {
result.put(entry.key, entry.value);
}
return result;
}
public static ItemStackAmount of(Iterable<ItemStack> items) {
ItemStackAmount result = new ItemStackAmount();
for (ItemStack stack : items) {
result.add(stack);
}
return result;
}
}
@@ -5,9 +5,11 @@ import static codechicken.lib.inventory.InventoryUtils.newItemStack;
import static net.minecraftforge.oredict.OreDictionary.WILDCARD_VALUE;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@@ -24,8 +26,13 @@ public class ItemStackMap<T> {
public final int damage;
public final NBTTagCompound tag;
private final int hashCode;
public StackMetaKey(int damage, NBTTagCompound tag) {
if (tag != null && tag.hasNoTags()) {
tag = null;
}
this.hashCode = Objects.hashCode(damage, tag);
this.damage = damage;
this.tag = tag;
}
@@ -35,7 +42,7 @@ public class ItemStackMap<T> {
}
public int hashCode() {
return Objects.hashCode(damage, tag);
return this.hashCode;
}
public boolean equals(Object o) {
@@ -191,7 +198,7 @@ public class ItemStackMap<T> {
WILDCARD_TAG.setBoolean("*", true);
}
private final HashMap<Item, DetailMap> itemMap = new HashMap<>();
private final Map<Item, DetailMap> itemMap = new LinkedHashMap<>();
private int size;
public T get(ItemStack key) {
@@ -203,6 +210,11 @@ public class ItemStackMap<T> {
return map == null ? null : map.get(key);
}
public T getOrDefault(ItemStack key, T defaultValue) {
T e = get(key);
return e == null ? defaultValue : e;
}
public void put(ItemStack key, T value) {
if (key == null || key.getItem() == null) return;
@@ -211,8 +223,22 @@ public class ItemStackMap<T> {
map.put(key, value);
}
public T computeIfAbsent(ItemStack key, Function<ItemStack, ? extends T> mappingFunction) {
T value;
if ((value = get(key)) == null) {
T newValue;
if ((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
}
return value;
}
public void clear() {
itemMap.clear();
size = 0;
}
public T remove(ItemStack key) {
@@ -27,6 +27,16 @@ public class ItemStackSet extends ItemStackMap<ItemStack> implements ItemFilter
put(item, item);
}
public ItemStackSet addAll(Iterable<ItemStack> items) {
for (ItemStack item : items) add(item);
return this;
}
public ItemStackSet removeAll(Iterable<ItemStack> items) {
for (ItemStack item : items) remove(item);
return this;
}
public boolean contains(ItemStack item) {
return get(item) != null;
}
+250
View File
@@ -0,0 +1,250 @@
package codechicken.nei;
import java.awt.Point;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.recipe.StackInfo;
public class ItemZoom extends Widget implements IContainerInputHandler {
public static final int MIN_ZOOM = 0;
public static final int MAX_ZOOM = 1000;
private static final int MIN_SCALE = 2;
private static final int SLOT_SIZE = 16;
private Boolean previousKeyboardRepeatEnabled = null;
private ItemStack stack = null;
private String displayName = "";
private int availableAreaWidth = 0;
private float xPosition = 0;
private float yPosition = 0;
private float scale = 1;
public ItemZoom() {
GuiContainerManager.addInputHandler(this);
}
@Override
public void draw(int mx, int my) {
if (this.stack != null
&& (NEIClientConfig.getBooleanSetting("inventory.itemzoom.enabled")
|| NEIClientConfig.isKeyHashDown("gui.itemzoom_hold"))
&& GuiContainerManager.shouldShowTooltip(NEIClientUtils.getGuiContainer())) {
final float inverseScaleFactor = 1.0f / this.scale;
final float screenScale = getScreenScale();
final float size = SLOT_SIZE * this.scale;
int shiftText = 10;
GL11.glPushMatrix();
GL11.glScaled(screenScale, screenScale, 1);
GL11.glScaled(this.scale, this.scale, 2);
GL11.glTranslated(this.xPosition * inverseScaleFactor, this.yPosition * inverseScaleFactor, 0);
GuiContainerManager.drawItem(0, 0, this.stack, false, "");
GL11.glPopMatrix();
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GuiContainerManager.enable2DRender();
if (NEIClientConfig.getBooleanSetting("inventory.itemzoom.showName")) {
String dispalyName = NEIClientUtils
.cropText(GuiDraw.fontRenderer, this.displayName, this.availableAreaWidth);
GuiDraw.drawStringC(
dispalyName,
(int) ((this.xPosition + size / 2) * screenScale),
(int) ((this.yPosition + size) * screenScale) + shiftText,
NEIClientConfig.getSetting("inventory.itemzoom.nameColor").getHexValue());
shiftText += GuiDraw.fontRenderer.FONT_HEIGHT;
}
if (NEIClientConfig.getBooleanSetting("inventory.itemzoom.enabled")
&& NEIClientConfig.getBooleanSetting("inventory.itemzoom.helpText")) {
String keyName = NEIClientConfig.getKeyName("gui.itemzoom_toggle");
if (keyName != null) {
String helpText = NEIClientUtils.translate("itemzoom.toggle", keyName);
List<String> lines = GuiDraw.fontRenderer
.listFormattedStringToWidth(helpText, this.availableAreaWidth);
for (String line : lines) {
GuiDraw.drawStringC(
line,
(int) ((this.xPosition + size / 2) * screenScale),
(int) ((this.yPosition + size) * screenScale) + 10 + shiftText,
0x66555555);
shiftText += GuiDraw.fontRenderer.FONT_HEIGHT;
}
}
}
GL11.glPopAttrib();
}
}
public void resize(GuiContainer gui) {
final ItemStack stack = getStackMouseOver(gui);
if (stack != null && (!NEIClientConfig.getBooleanSetting("inventory.itemzoom.onlySolid")
|| Block.getBlockFromItem(stack.getItem()).getMaterial().isSolid())) {
final float screenScale = 1.0f / getScreenScale();
final float availableAreaWidth = (gui.width - gui.xSize) / 2 * screenScale;
final float availableAreaHeight = gui.height * screenScale;
final Point mouse = GuiDraw.getMousePosition();
this.scale = Math.round(getZoomAmount(gui) * getPointSize(gui) / SLOT_SIZE);
this.yPosition = (availableAreaHeight - this.scale * SLOT_SIZE) / 2;
this.xPosition = (availableAreaWidth - this.scale * SLOT_SIZE) / 2;
this.availableAreaWidth = (int) (availableAreaWidth / screenScale);
if (availableAreaWidth / screenScale >= mouse.x) {
this.xPosition += gui.width * screenScale - availableAreaWidth;
}
try {
this.displayName = stack.getDisplayName();
} catch (Throwable ignored) {
this.displayName = "Unnamed";
}
this.stack = StackInfo.loadFromNBT(StackInfo.itemStackToNBT(stack), 0);
} else {
this.stack = null;
this.displayName = "";
}
}
private float getPointSize(GuiContainer gui) {
final float screenScale = 1.0f / getScreenScale();
final float availableAreaWidth = (gui.width - (gui.xSize + gui.width) / 2) * screenScale;
return availableAreaWidth / MAX_ZOOM;
}
private float getScreenScale() {
return Minecraft.getMinecraft().currentScreen.width * 1f / Minecraft.getMinecraft().displayWidth;
}
private int getZoomAmount(GuiContainer gui) {
return Math.max(
Math.round(SLOT_SIZE * MIN_SCALE / getPointSize(gui)),
NEIClientConfig.getIntSetting("inventory.itemzoom.zoom"));
}
private void increaseZoom(GuiContainer gui) {
final float pointSize = getPointSize(gui);
final float scale = Math.round(getZoomAmount(gui) * pointSize / SLOT_SIZE);
NEIClientConfig.setIntSetting(
"inventory.itemzoom.zoom",
Math.min(MAX_ZOOM, Math.round((scale + 1) / (pointSize / SLOT_SIZE))));
}
private void decreaseZoom(GuiContainer gui) {
final float pointSize = getPointSize(gui);
final float scale = Math.round(getZoomAmount(gui) * pointSize / SLOT_SIZE);
NEIClientConfig.setIntSetting(
"inventory.itemzoom.zoom",
Math.max(MIN_ZOOM, Math.round(Math.max(MIN_SCALE, scale - 1) / (pointSize / SLOT_SIZE))));
}
private ItemStack getStackMouseOver(GuiContainer gui) {
if (NEIClientConfig.getBooleanSetting("inventory.itemzoom.neiOnly")) {
final Point mouse = GuiDraw.getMousePosition();
ItemStack stack = ItemPanels.itemPanel.getStackMouseOver(mouse.x, mouse.y);
if (stack == null) {
stack = ItemPanels.bookmarkPanel.getStackMouseOver(mouse.x, mouse.y);
}
if (stack == null) {
stack = ItemPanels.itemPanel.historyPanel.getStackMouseOver(mouse.x, mouse.y);
}
return stack;
}
return GuiContainerManager.getStackMouseOver(gui);
}
@Override
public boolean keyTyped(GuiContainer gui, char keyChar, int keyCode) {
return false;
}
@Override
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
return false;
}
@Override
public void onKeyTyped(GuiContainer gui, char keyChar, int keyID) {}
@Override
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
if (NEIClientConfig.isKeyHashDown("gui.itemzoom_toggle")) {
NEIClientConfig.getSetting("inventory.itemzoom.enabled")
.setBooleanValue(!NEIClientConfig.getBooleanSetting("inventory.itemzoom.enabled"));
return true;
}
if (this.stack != null && NEIClientConfig.isKeyHashDown("gui.itemzoom_hold")) {
return true;
}
if (this.stack != null && NEIClientConfig.isKeyHashDown("gui.itemzoom_zoom_in")) {
increaseZoom(gui);
previousKeyboardRepeatEnabled = Keyboard.areRepeatEventsEnabled();
Keyboard.enableRepeatEvents(true);
return true;
}
if (this.stack != null && NEIClientConfig.isKeyHashDown("gui.itemzoom_zoom_out")) {
decreaseZoom(gui);
previousKeyboardRepeatEnabled = Keyboard.areRepeatEventsEnabled();
Keyboard.enableRepeatEvents(true);
return true;
}
if (previousKeyboardRepeatEnabled != null) {
Keyboard.enableRepeatEvents(previousKeyboardRepeatEnabled);
previousKeyboardRepeatEnabled = null;
}
return false;
}
@Override
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {}
@Override
public void onMouseUp(GuiContainer gui, int mousex, int mousey, int button) {}
@Override
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
return false;
}
@Override
public void onMouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {}
@Override
public void onMouseDragged(GuiContainer gui, int mousex, int mousey, int button, long heldTime) {}
}
+197 -80
View File
@@ -17,6 +17,7 @@ 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;
@@ -26,6 +27,119 @@ import codechicken.nei.recipe.StackInfo;
public class ItemsGrid {
private 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 final int SLOT_SIZE = 18;
protected int width;
@@ -43,15 +157,13 @@ public class ItemsGrid {
protected int rows;
protected int columns;
protected List<Integer> gridMask = null;
protected boolean[] invalidSlotMap;
protected Label messageLabel = new Label(getMessageOnEmpty(), true);
@Nullable
private Framebuffer framebuffer = null;
protected boolean refreshBuffer = true;
protected ScreenCapture screenCapture = null;
public ArrayList<ItemStack> getItems() {
return realItems;
@@ -65,10 +177,14 @@ public class ItemsGrid {
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 +221,10 @@ public class ItemsGrid {
return columns;
}
public int getLastRowIndex() {
return this.columns > 0 ? (int) Math.ceil((float) this.getMask().size() / this.columns) - 1 : 0;
}
public void setGridSize(int mleft, int mtop, int w, int h) {
marginLeft = mleft;
marginTop = mtop;
@@ -147,7 +267,14 @@ public class ItemsGrid {
}
protected void onGridChanged() {
refreshBuffer = true;
if (this.screenCapture != null) {
this.screenCapture.refreshBuffer();
}
this.gridMask = null;
}
protected void onItemsChanged() {
onGridChanged();
}
public void refresh(GuiContainer gui) {
@@ -163,11 +290,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 +312,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--;
@@ -223,60 +352,50 @@ public class ItemsGrid {
}
protected List<Integer> getMask() {
List<Integer> mask = new ArrayList<>();
int idx = page * perPage;
for (int i = 0; i < rows * columns && idx < size(); i++) {
mask.add(isInvalidSlot(i) ? null : idx++);
if (this.gridMask == null) {
this.gridMask = new ArrayList<>();
int idx = page * perPage;
for (int i = 0; i < rows * columns && idx < size(); i++) {
this.gridMask.add(isInvalidSlot(i) ? null : idx++);
}
}
return mask;
return this.gridMask;
}
private void drawSlotOutlines(int mousex, int mousey) {
ItemPanelSlot focused = getSlotMouseOver(mousex, mousey);
protected void beforeDrawItems(int mousex, int mousey, @Nullable ItemPanelSlot focused) {
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));
beforeDrawSlot(focused, mask.get(i), getSlotRect(i));
}
}
}
protected void drawSlotOutline(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {
protected void afterDrawItems(int mousex, int mousey, @Nullable ItemPanelSlot focused) {
final List<Integer> mask = getMask();
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) != null) {
afterDrawSlot(focused, mask.get(i), getSlotRect(i));
}
}
}
public void update() {}
protected void beforeDrawSlot(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {
if (focused != null && focused.slotIndex == slotIdx) {
drawRect(rect.x, rect.y, rect.w, rect.h, 0xee555555); // highlight
}
}
private void blitExistingBuffer() {
Minecraft minecraft = Minecraft.getMinecraft();
GL11.glEnable(GL11.GL_BLEND);
OpenGlHelper.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
getFrameBuffer().bindFramebufferTexture();
GL11.glEnable(GL11.GL_TEXTURE_2D);
ScaledResolution res = new ScaledResolution(minecraft, minecraft.displayWidth, minecraft.displayHeight);
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(0, res.getScaledHeight_double(), 0.0, 0, 0);
tessellator.addVertexWithUV(res.getScaledWidth_double(), res.getScaledHeight_double(), 0.0, 1, 0);
tessellator.addVertexWithUV(res.getScaledWidth_double(), 0, 0.0, 1, 1);
tessellator.addVertexWithUV(0, 0, 0, 0, 1);
tessellator.draw();
OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
}
private Framebuffer getFrameBuffer() {
if (framebuffer == null) {
framebuffer = new Framebuffer(1, 1, true);
framebuffer.setFramebufferColor(0.0F, 0.0F, 0.0F, 0.0F);
}
return framebuffer;
}
protected void afterDrawSlot(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {}
private void drawItems() {
GuiContainerManager.enableMatrixStackLogging();
@@ -291,42 +410,36 @@ public class ItemsGrid {
GuiContainerManager.disableMatrixStackLogging();
}
protected int getGridRenderingCacheMode() {
return NEIClientConfig.getGridRenderingCacheMode();
}
public void draw(int mousex, int mousey) {
if (getPerPage() == 0) {
return;
}
if (NEIClientConfig.shouldCacheItemRendering()) {
final ItemPanelSlot focused = getSlotMouseOver(mousex, mousey);
final int gridRenderingCacheMode = getGridRenderingCacheMode();
if (refreshBuffer) {
Minecraft minecraft = Minecraft.getMinecraft();
Framebuffer framebuffer = getFrameBuffer();
framebuffer.createBindFramebuffer(minecraft.displayWidth, minecraft.displayHeight);
framebuffer.framebufferClear();
framebuffer.bindFramebuffer(false);
beforeDrawItems(mousex, mousey, focused);
/* 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(this::drawItems, gridRenderingCacheMode);
}
this.screenCapture.renderCapturedScreen();
} else {
drawSlotOutlines(mousex, mousey);
drawItems();
}
afterDrawItems(mousex, mousey, focused);
}
public void setVisible() {
@@ -344,8 +457,8 @@ public class ItemsGrid {
return null;
}
final int overRow = (int) ((mousey - marginTop) / SLOT_SIZE);
final int overColumn = (int) ((mousex - marginLeft - paddingLeft) / SLOT_SIZE);
final int overRow = (mousey - marginTop) / SLOT_SIZE;
final int overColumn = (mousex - marginLeft - paddingLeft) / SLOT_SIZE;
final int slt = columns * overRow + overColumn;
if (overRow >= rows || overColumn >= columns) {
@@ -364,16 +477,20 @@ public class ItemsGrid {
}
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;
final int r = (py - marginTop) / SLOT_SIZE;
final int c = (px - marginLeft - paddingLeft) / SLOT_SIZE;
return r >= rows || c >= columns || !isInvalidSlot(slt);
return !isInvalidSlot(columns * r + c);
}
public String getMessageOnEmpty() {
@@ -0,0 +1,138 @@
package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.fontRenderer;
import java.awt.Dimension;
import java.util.List;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.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 MAX_COLUMNS = 11;
protected static final int MARGIN_TOP = 2;
protected String label;
protected EnumChatFormatting labelColor = EnumChatFormatting.GRAY;
protected List<ItemStack> items;
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 * ItemsGrid.SLOT_SIZE, fontRenderer.getStringWidth(this.label) + 15);
this.size.height = this.rows * ItemsGrid.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) / ItemsGrid.SLOT_SIZE);
}
}
}
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);
for (int i = 0; i < this.count; i++) {
ItemStack drawStack = this.items.get(i);
int col = i % this.columns;
int row = i / this.columns;
String stackSize = !this.saveStackSize || drawStack.stackSize == 0 ? ""
: ReadableNumberConverter.INSTANCE.toWideReadableForm(drawStack.stackSize);
drawItem(col * ItemsGrid.SLOT_SIZE, row * ItemsGrid.SLOT_SIZE, drawStack, stackSize);
}
if (this.count < this.items.size()) {
String text = "+" + (this.items.size() - this.count);
fontRenderer.drawStringWithShadow(
text,
MAX_COLUMNS * ItemsGrid.SLOT_SIZE - fontRenderer.getStringWidth(text) - 2,
(this.rows - 1) * ItemsGrid.SLOT_SIZE + (ItemsGrid.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 = ItemStackAmount.of(items).values();
for (ItemStack stack : result) {
if (StackInfo.itemStackToNBT(stack).hasKey("gtFluidName")) {
stack.stackSize = 0;
}
}
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;
}
}
+203 -78
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;
@@ -77,28 +79,23 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
/**
* Sorted bottom first
*/
private static TreeSet<Widget> drawWidgets = new TreeSet<>(new WidgetZOrder(false));
private static Set<Widget> drawWidgets = new TreeSet<>(new WidgetZOrder(false));
/**
* Sorted top first
*/
private static TreeSet<Widget> controlWidgets = new TreeSet<>(new WidgetZOrder(true));
private static Set<Widget> controlWidgets = new TreeSet<>(new WidgetZOrder(true));
public static ItemPanel itemPanel;
public static BookmarkPanel bookmarkPanel;
public static SubsetWidget dropDown;
public static PresetsWidget presetsPanel;
public static SearchField searchField;
public static ItemZoom itemZoom;
public static ButtonCycled options;
public static ButtonCycled bookmarksButton;
@Deprecated
public static Button more;
@Deprecated
public static Button less;
@Deprecated
public static ItemQuantityField quantity;
public static Button delete;
@@ -146,8 +143,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
gui.guiTop = (gui.height - gui.ySize) / 2;
if (gui instanceof GuiContainerCreative && gui.buttonList.size() >= 2) {
GuiButton button1 = (GuiButton) gui.buttonList.get(0);
GuiButton button2 = (GuiButton) gui.buttonList.get(1);
GuiButton button1 = gui.buttonList.get(0);
GuiButton button2 = gui.buttonList.get(1);
button1.xPosition = gui.guiLeft;
button2.xPosition = gui.guiLeft + gui.xSize - 20;
}
@@ -168,14 +165,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 +190,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,7 +230,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
}
if (NEIClientConfig.isKeyHashDown("gui.hide_bookmarks")) {
toggleBooleanSetting("inventory.bookmarksEnabled");
toggleBooleanSetting("inventory.bookmarks.enabled");
return true;
}
@@ -248,12 +261,12 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public ItemStack getStackUnderMouse(GuiContainer gui, int mousex, int mousey) {
if (!isHidden() && isEnabled()) {
for (Widget widget : drawWidgets) {
ItemStack stack = widget.getStackMouseOver(mousex, mousey);
if (stack != null) return stack;
}
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused != null) {
return focused.getStackMouseOver(mousex, mousey);
}
return null;
}
@@ -281,10 +294,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 +337,55 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
currenttip.set(0, mainname);
}
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
final Point mouse = GuiDraw.getMousePosition();
final Widget focused = getWidgetUnderMouse(mouse.x, mouse.y);
if (focused instanceof IContainerTooltipHandler tip) {
currenttip = tip.handleItemDisplayName(gui, stack, currenttip);
}
}
return currenttip;
}
@Override
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
List<String> currenttip) {
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused instanceof IContainerTooltipHandler tip) {
currenttip = tip.handleItemTooltip(gui, itemstack, mousex, mousey, currenttip);
}
}
return currenttip;
}
@Override
public Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused instanceof IContainerTooltipHandler tip) {
hotkeys = tip.handleHotkeys(gui, mousex, mousey, hotkeys);
}
}
return hotkeys;
}
public static void layout(GuiContainer gui) {
VisiblityData visiblity = new VisiblityData();
if (isHidden()) visiblity.showNEI = false;
if (isBookmarkPanelHidden()) visiblity.showBookmarkPanel = false;
if (gui.height - gui.ySize <= 40) visiblity.showSearchSection = false;
if (visiblity.showBookmarkPanel || gui.guiTop <= 20) visiblity.showSubsetDropdown = false;
if (!visiblity.showBookmarkPanel || gui.guiTop <= 20) visiblity.showPresetsDropdown = false;
if (gui.guiLeft - 4 < 76) visiblity.showWidgets = false;
visiblity.showNEI = !isHidden();
visiblity.showBookmarkPanel = !isBookmarkPanelHidden();
visiblity.showSearchSection = !(gui.height - gui.ySize <= 40 && NEIClientConfig.isSearchWidgetCentered());
visiblity.showSubsetDropdown = NEIClientConfig.showSubsetWidget()
&& (gui.guiTop > 20 || visiblity.showSearchSection && !NEIClientConfig.subsetWidgetOnTop());
visiblity.showWidgets = gui.guiLeft - 4 > 76;
try {
GuiInfo.readLock.lock();
@@ -346,9 +408,11 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
bookmarkPanel = ItemPanels.bookmarkPanel;
bookmarkPanel.init();
itemZoom = new ItemZoom();
dropDown = new SubsetWidget();
presetsPanel = new PresetsWidget();
searchField = new SearchField("search");
API.addItemFilter(searchField);
options = new ButtonCycled(3) {
@@ -370,7 +434,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public boolean onButtonPress(boolean rightclick) {
if (!rightclick) {
if (Keyboard.getEventKeyState() && getIsAccessibleControlEventKey()) {
if (Keyboard.getEventKeyState() && getIsAccessibleControlEventKey()
&& NEIClientConfig.canChangeCheatMode()) {
NEIClientConfig.cycleSetting("inventory.cheatmode", 3);
} else {
if (Keyboard.getEventKeyState() && (Keyboard.getEventKey() == Keyboard.KEY_LSHIFT
@@ -394,7 +459,10 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
else if (cheatMode == 2) modeColor = EnumChatFormatting.RED.toString();
String controlKeyLocalization = translate(Minecraft.isRunningOnMac ? "key.ctrl.mac" : "key.ctrl");
tooltip.add(modeColor + translate("inventory.options.tip.cheatmode." + cheatMode));
tooltip.add(modeColor + translate("inventory.options.tip.cheatmode.disable", controlKeyLocalization));
if (NEIClientConfig.canChangeCheatMode()) {
tooltip.add(
modeColor + translate("inventory.options.tip.cheatmode.disable", controlKeyLocalization));
}
}
@Override
@@ -413,7 +481,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public boolean onButtonPress(boolean rightclick) {
NEIClientConfig.toggleBooleanSetting("inventory.bookmarksEnabled");
NEIClientConfig.toggleBooleanSetting("inventory.bookmarks.enabled");
return true;
}
@@ -427,9 +495,43 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
}
};
more = ItemPanels.itemPanel.more;
less = ItemPanels.itemPanel.less;
quantity = ItemPanels.itemPanel.quantity;
more = new Button("+") {
@Override
public boolean onButtonPress(boolean rightclick) {
if (rightclick) return false;
int modifier = NEIClientUtils.controlKey() ? 64 : NEIClientUtils.shiftKey() ? 10 : 1;
int quantity = NEIClientConfig.getItemQuantity() + modifier;
if (quantity < 0) {
quantity = 0;
}
LayoutManager.quantity.setText(Integer.toString(quantity));
return true;
}
};
less = new Button("-") {
@Override
public boolean onButtonPress(boolean rightclick) {
if (rightclick) return false;
int modifier = NEIClientUtils.controlKey() ? -64 : NEIClientUtils.shiftKey() ? -10 : -1;
int quantity = NEIClientConfig.getItemQuantity() + modifier;
if (quantity < 0) {
quantity = 0;
}
LayoutManager.quantity.setText(Integer.toString(quantity));
return true;
}
};
quantity = new ItemQuantityField("quantity");
delete = new Button() {
@Override
@@ -531,8 +633,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
}
@Override
public String getButtonTip() {
return getTimeTip(NEIActions.timeZones[zone], state);
public void addTooltips(List<String> tooltip) {
addTimeTip(NEIActions.timeZones[zone], state, tooltip);
}
};
}
@@ -565,9 +667,13 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
return translate("inventory." + name + "." + sfx);
}
private static String getTimeTip(String name, int state) {
String sfx = (state & 0x3) == 2 ? "enable" : "set";
return translate("inventory." + name + "." + sfx);
private static void addTimeTip(String name, int state, List<String> tooltip) {
if ((state & 0x3) == 2) {
tooltip.add(translate("inventory." + name + ".enable"));
} else {
tooltip.add(translate("inventory." + name + ".set"));
tooltip.add(EnumChatFormatting.GRAY + translate("inventory." + name + ".disable"));
}
}
private static boolean handleDisabledButtonPress(String ident, boolean rightclick) {
@@ -601,12 +707,12 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
if (!itemsLoaded) {
ItemList.loadItems.restart();
itemsLoaded = true;
}
overlayRenderer = null;
overlayRenderer = null;
getLayoutStyle().init();
layout(gui);
AutoFocusWidget.instance.load(gui);
}
NEIController.load(gui);
@@ -638,14 +744,15 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
addWidget(options);
addWidget(bookmarksButton);
if (visiblity.showItemPanel && NEIClientConfig.showItemQuantityWidget()) {
addWidget(quantity);
addWidget(more);
addWidget(less);
}
if (visiblity.showItemPanel) {
if (PresetsWidget.inEditMode()) {
drawWidgets.add(itemPanel);
} else {
addWidget(itemPanel);
}
addWidget(itemPanel);
itemPanel.setVisible();
}
@@ -654,13 +761,13 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
bookmarkPanel.setVisible();
}
if (visiblity.showPresetsDropdown) {
addWidget(presetsPanel);
}
searchField.setVisible(visiblity.showSearchSection);
if (visiblity.showSearchSection) {
if (visiblity.showSearchSection && NEIClientConfig.isSearchWidgetCentered()
|| visiblity.showItemPanel && !NEIClientConfig.isSearchWidgetCentered()) {
searchField.setVisible(true);
addWidget(searchField);
} else {
searchField.setVisible(false);
searchField.setFocus(false);
}
if (visiblity.showUtilityButtons) {
@@ -675,6 +782,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
if (canPerformAction("delete")) addWidget(delete);
}
addWidget(itemZoom);
if (visiblity.showSubsetDropdown) {
// Bookmarks or Subset/dropdown
addWidget(dropDown);
@@ -709,7 +818,9 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
if (isHidden() || !isEnabled()) return false;
for (Widget widget : drawWidgets) if (widget.onMouseWheel(scrolled, mousex, mousey)) return true;
for (Widget widget : controlWidgets) {
if (widget.onMouseWheel(scrolled, mousex, mousey)) return true;
}
return false;
}
@@ -719,7 +830,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public boolean shouldShowTooltip(GuiContainer gui) {
return itemPanel.draggedStack == null && bookmarkPanel.sortedStackIndex == -1;
return itemPanel.draggedStack == null && !bookmarkPanel.inEditingState();
}
/** Note: this method isn't actually used by this mod, but NEI add-ons might need it. */
@@ -742,17 +853,21 @@ 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)) {
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);
}
}
}
public static void drawIcon(int x, int y, Image image) {
@@ -808,9 +923,19 @@ 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) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glDisable(GL11.GL_DEPTH_TEST);
drawRect(slotX, slotY, 16, 16, isPresent ? 0x8000AA00 : 0x80AA0000);
GL11.glPopAttrib();
} 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 = gui.xSize - 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));
}
}
}
+34 -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,38 @@ 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 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 +200,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 +234,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();
+574 -184
View File
@@ -5,6 +5,8 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Pattern;
@@ -13,6 +15,7 @@ import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.world.World;
import net.minecraft.world.storage.SaveFormatComparator;
import net.minecraftforge.common.MinecraftForge;
@@ -22,9 +25,11 @@ import org.apache.logging.log4j.Logger;
import org.lwjgl.input.Keyboard;
import com.google.common.base.Objects;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.JsonParseException;
import codechicken.core.CCUpdateChecker;
import codechicken.core.ClassDiscoverer;
import codechicken.core.ClientUtils;
import codechicken.core.CommonUtils;
import codechicken.lib.config.ConfigFile;
@@ -40,14 +45,17 @@ import codechicken.nei.config.GuiHighlightTips;
import codechicken.nei.config.GuiNEIOptionList;
import codechicken.nei.config.GuiOptionList;
import codechicken.nei.config.GuiPanelSettings;
import codechicken.nei.config.OptionButton;
import codechicken.nei.config.OptionCycled;
import codechicken.nei.config.OptionGamemodes;
import codechicken.nei.config.OptionIntegerField;
import codechicken.nei.config.OptionList;
import codechicken.nei.config.OptionOpenGui;
import codechicken.nei.config.OptionTextField;
import codechicken.nei.config.OptionToggleButton;
import codechicken.nei.config.OptionToggleButtonBoubs;
import codechicken.nei.config.OptionUtilities;
import codechicken.nei.config.preset.GuiPresetList;
import codechicken.nei.event.NEIConfigsLoadedEvent;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.IRecipeHandler;
@@ -57,7 +65,8 @@ import codechicken.obfuscator.ObfuscationRun;
public class NEIClientConfig {
private static boolean configLoaded;
private static boolean mainNEIConfigLoaded;
private static boolean pluginNEIConfigLoaded;
private static boolean enabledOverride;
private static String worldPath;
@@ -69,9 +78,6 @@ public class NEIClientConfig {
public static ConfigSet world;
public static final File handlerFile = new File(configDir, "handlers.csv");
public static final File catalystFile = new File(configDir, "catalysts.csv");
public static final File serialHandlersFile = new File(configDir, "serialhandlers.cfg");
public static final File heightHackHandlersFile = new File(configDir, "heighthackhandlers.cfg");
public static final File handlerOrderingFile = new File(configDir, "handlerordering.csv");
@Deprecated
public static File bookmarkFile;
@@ -83,11 +89,16 @@ public class NEIClientConfig {
// We use regex here so that we can apply the height hack to entire mods with one entry.
public static HashSet<Pattern> heightHackHandlerRegex = new HashSet<>();
// Set of handler Name or Id of handlers that need hide.
public static HashSet<String> hiddenHandlers = new HashSet<>();
// Map of handler ID to sort order.
// Handlers will be sorted in ascending order, so smaller numbers show up earlier.
// Any handler not in the map will be assigned to 0, and negative numbers are fine.
public static HashMap<String, Integer> handlerOrdering = new HashMap<>();
public static final Set<Class<?>> pluginsList = new HashSet<>();
// Function that extracts the handler ID from a handler, with special logic for
// TemplateRecipeHandler: prefer using the overlay ID if it exists.
public static final Function<IRecipeHandler, String> HANDLER_ID_FUNCTION = handler -> Objects
@@ -146,7 +157,7 @@ public class NEIClientConfig {
return getLockedMode() == -1 || getLockedMode() == index && NEIInfo.isValidMode(index);
}
});
checkCheatMode();
canChangeCheatMode();
tag.getTag("inventory.utilities").setDefaultValue("delete, magnet");
API.addOption(new OptionUtilities("inventory.utilities"));
@@ -155,13 +166,168 @@ public class NEIClientConfig {
API.addOption(new OptionGamemodes("inventory.gamemodes"));
ItemSorter.initConfig(tag);
setInventorySearchDefaults(tag);
tag.getTag("inventory.bookmarks.enabled").setComment("Enable/Disable Bookmark Panel").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.bookmarks.enabled", true));
tag.getTag("inventory.bookmarks.worldSpecific").setComment("Global or world specific bookmarks")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.bookmarks.worldSpecific", true) {
@Override
public boolean onClick(int button) {
super.onClick(button);
ItemPanels.bookmarkPanel.load();
return true;
}
});
tag.getTag("inventory.bookmarks.animation").setComment("REI Style Animation in Bookmarks")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.bookmarks.animation", true));
tag.getTag("inventory.bookmarks.recipeTooltipsMode").setComment("Show recipe tooltips in Bookmarks")
.getIntValue(1);
API.addOption(new OptionCycled("inventory.bookmarks.recipeTooltipsMode", 4, true));
tag.getTag("inventory.bookmarks.showRecipeMarker").setComment("Show Recipe Marker").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.bookmarks.showRecipeMarker", true));
tag.getTag("inventory.bookmarks.craftingChainDir").getIntValue(1);
API.addOption(new OptionCycled("inventory.bookmarks.craftingChainDir", 2, true));
tag.getTag("inventory.bookmarks.ignorePotionOverlap").setComment("Ignore overlap with potion effect HUD")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.bookmarks.ignorePotionOverlap", true));
tag.getTag("inventory.guirecipe.jeiStyleTabs").setComment("Enable/disable JEI Style Tabs")
.getBooleanValue(true);
API.addOption(new OptionToggleButtonBoubs("inventory.guirecipe.jeiStyleTabs", true));
tag.getTag("inventory.guirecipe.jeiStyleRecipeCatalyst").setComment("Enable/disable JEI Style Recipe Catalysts")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.guirecipe.jeiStyleRecipeCatalyst", true));
tag.getTag("inventory.guirecipe.jeiStyleCycledIngredients").setComment("JEI styled cycled ingredients")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.guirecipe.jeiStyleCycledIngredients", true));
tag.getTag("inventory.guirecipe.cycledIngredientsTooltip").setComment("Show cycled ingredients tooltip")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.guirecipe.cycledIngredientsTooltip", true));
tag.getTag("inventory.guirecipe.creativeTabStyle").setComment("Creative or JEI style tabs")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.guirecipe.creativeTabStyle", true));
tag.getTag("inventory.guirecipe.itemPresenceOverlay").setComment("Item presence overlay on ?-hover")
.getIntValue(1);
API.addOption(new OptionCycled("inventory.guirecipe.itemPresenceOverlay", 3, true));
tag.getTag("inventory.guirecipe.slotHighlightPresent").setComment("Highlight Present Item")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.guirecipe.slotHighlightPresent", true));
tag.getTag("inventory.guirecipe.shiftOverlayRecipe")
.setComment("Require holding shift to move items when overlaying recipe").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.guirecipe.shiftOverlayRecipe", true));
tag.getTag("inventory.subsets.enabled").setComment("Enable/disable Subsets Dropdown").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.subsets.enabled", true));
tag.getTag("inventory.subsets.widgetPosition").setComment("Subsets Widget Position").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.subsets.widgetPosition", true));
tag.getTag("inventory.guirecipe.profile").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.guirecipe.profile", true));
tag.getTag("inventory.history.enabled").setComment("Enable/disable History Panel").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.history.enabled", true));
tag.getTag("inventory.history.historyColor").setComment("Color of the history area display")
.getHexValue(0xee555555);
API.addOption(new OptionIntegerField("inventory.history.historyColor", 0, OptionIntegerField.UNSIGNED_INT_MAX));
tag.getTag("inventory.history.useRows").setComment("Rows used in historical areas").getIntValue(2);
API.addOption(new OptionIntegerField("inventory.history.useRows", 1, 5));
tag.getTag("inventory.history.splittingMode").getIntValue(1);
API.addOption(new OptionCycled("inventory.history.splittingMode", 2, true));
tag.getTag("inventory.collapsibleItems.enabled").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.collapsibleItems.enabled", true) {
@Override
public boolean onClick(int button) {
super.onClick(button);
CollapsibleItems.saveStates();
CollapsibleItems.load();
LayoutManager.markItemsDirty();
return true;
}
});
tag.getTag("inventory.collapsibleItems.customName").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.collapsibleItems.customName", true));
tag.getTag("inventory.collapsibleItems.expandedColor")
.setComment("Color of the collapsible item expanded state").getHexValue(0x335555EE);
API.addOption(
new OptionIntegerField(
"inventory.collapsibleItems.expandedColor",
0,
OptionIntegerField.UNSIGNED_INT_MAX));
tag.getTag("inventory.collapsibleItems.collapsedColor")
.setComment("Color of the collapsible item collapsed state").getHexValue(0x335555EE);
API.addOption(
new OptionIntegerField(
"inventory.collapsibleItems.collapsedColor",
0,
OptionIntegerField.UNSIGNED_INT_MAX));
API.addOption(
new OptionButton(
"inventory.collapsibleItems.reloadLabel",
"inventory.collapsibleItems.reloadButton",
"inventory.collapsibleItems.reloadTip") {
@Override
public boolean onClick(int button) {
LayoutManager.markItemsDirty();
return super.onClick(button);
}
});
tag.getTag("inventory.itemzoom.enabled").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.itemzoom.enabled", true));
tag.getTag("inventory.itemzoom.neiOnly")
.setComment("Zoom items only from the JEI ingredient and bookmark list overlays.")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.itemzoom.neiOnly", true));
tag.getTag("inventory.itemzoom.onlySolid").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.itemzoom.onlySolid", true));
tag.getTag("inventory.itemzoom.helpText")
.setComment("Display name \"Item Zoom\" and the hotkey to toggle this mod below the zoomed item.")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.itemzoom.helpText", true));
tag.getTag("inventory.itemzoom.zoom").getIntValue(500);
API.addOption(new OptionIntegerField("inventory.itemzoom.zoom", ItemZoom.MIN_ZOOM, ItemZoom.MAX_ZOOM));
tag.getTag("inventory.itemzoom.showName").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.itemzoom.showName", true));
tag.getTag("inventory.itemzoom.nameColor").getHexValue(0xFFFFFFFF);
API.addOption(new OptionIntegerField("inventory.itemzoom.nameColor", 0, OptionIntegerField.UNSIGNED_INT_MAX));
tag.getTag("inventory.itemIDs").getIntValue(1);
API.addOption(new OptionCycled("inventory.itemIDs", 3, true));
tag.getTag("inventory.searchmode").getIntValue(1);
API.addOption(new OptionCycled("inventory.searchmode", 3, true));
tag.getTag("world.highlight_tips").getBooleanValue(false);
tag.getTag("world.highlight_tips.x").getIntValue(5000);
tag.getTag("world.highlight_tips.y").getIntValue(100);
@@ -179,8 +345,7 @@ public class NEIClientConfig {
API.addOption(new OptionOpenGui("world.panels", GuiPanelSettings.class));
tag.getTag("inventory.profileRecipes").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.profileRecipes", true));
API.addOption(new OptionOpenGui("world.presets", GuiPresetList.class));
tag.getTag("inventory.disableMouseScrollTransfer").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.disableMouseScrollTransfer", true));
@@ -194,8 +359,10 @@ public class NEIClientConfig {
}
});
tag.getTag("inventory.cacheItemRendering").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.cacheItemRendering", true));
tag.getTag("inventory.gridRenderingCacheFPS").getIntValue(8);
tag.getTag("inventory.gridRenderingCacheMode").getIntValue(0);
API.addOption(new OptionCycled("inventory.gridRenderingCacheMode", 3, true));
tag.getTag("itemLoadingTimeout").getIntValue(500);
@@ -210,74 +377,13 @@ public class NEIClientConfig {
tag.getTag("command.heal").setDefaultValue("");
API.addOption(new OptionTextField("command.heal"));
tag.getTag("inventory.worldSpecificBookmarks").setComment("Global or world specific bookmarks")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.worldSpecificBookmarks", true) {
@Override
public boolean onClick(int button) {
super.onClick(button);
initBookmarkFile(worldPath);
return true;
}
});
tag.getTag("inventory.worldSpecificPresets").setComment("Global or world specific presets")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.worldSpecificPresets", true) {
@Override
public boolean onClick(int button) {
super.onClick(button);
initPresetsFile(worldPath);
return true;
}
});
tag.getTag("inventory.bookmarksEnabled").setComment("Enable/disable bookmarks").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.bookmarksEnabled", true));
tag.getTag("inventory.useNBTInBookmarks").setComment("Use NBT in Bookmarks").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.useNBTInBookmarks", true));
tag.getTag("inventory.bookmarksAnimationEnabled").setComment("REI Style Animation in Bookmarks")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.bookmarksAnimationEnabled", true));
tag.getTag("inventory.showRecipeMarker").setComment("Show Recipe Marker").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.showRecipeMarker", true));
tag.getTag("inventory.showItemQuantityWidget").setComment("Show Item Quantity Widget").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.showItemQuantityWidget", true));
tag.getTag("inventory.centerSearchWidget").setComment("Center Search Widget").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.centerSearchWidget", true));
tag.getTag("inventory.jei_style_tabs").setComment("Enable/disable JEI Style Tabs").getBooleanValue(true);
API.addOption(new OptionToggleButtonBoubs("inventory.jei_style_tabs", true));
tag.getTag("inventory.jei_style_item_presence_overlay")
.setComment("Enable/disable JEI Style item presence overlay on ?-hover").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.jei_style_item_presence_overlay", true));
tag.getTag("inventory.jei_style_recipe_catalyst").setComment("Enable/disable JEI Style Recipe Catalysts")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.jei_style_recipe_catalyst", true));
tag.getTag("inventory.creative_tab_style").setComment("Creative or JEI style tabs").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.creative_tab_style", true));
tag.getTag("inventory.ignore_potion_overlap").setComment("Ignore overlap with potion effect HUD")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.ignore_potion_overlap", true));
tag.getTag("inventory.optimize_gui_overlap_computation").setComment("Optimize computation for GUI overlap")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.optimize_gui_overlap_computation", true));
tag.getTag("inventory.jei_style_cycled_ingredients").setComment("JEI styled cycled ingredients")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.jei_style_cycled_ingredients", true));
tag.getTag("inventory.shift_overlay_recipe")
.setComment("Require holding shift to move items when overlaying recipe").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.shift_overlay_recipe", true));
tag.getTag("tools.handler_load_from_config").setComment("ADVANCED: Load handlers from config")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("tools.handler_load_from_config", true) {
@@ -330,6 +436,237 @@ public class NEIClientConfig {
});
}
private static void setInventorySearchDefaults(ConfigTagParent tag) {
tag.getTag("inventory.search.widgetPosition").setComment("Widget Position").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.search.widgetPosition", true));
tag.getTag("inventory.search.hideUntilSearching").setComment("Hide Items Until Searching")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.search.hideUntilSearching", true) {
@Override
public boolean onClick(int button) {
super.onClick(button);
ItemList.updateFilter.restart();
return true;
}
});
tag.getTag("inventory.search.widgetAutofocus")
.setComment(
"Focus Search Widget on Open, blurs/unfocuses on mouse move unless typing has started first")
.getIntValue(0);
API.addOption(new OptionCycled("inventory.search.widgetAutofocus", 3, true));
tag.getTag("inventory.search.patternMode").setComment("Search Mode").getIntValue(1);
API.addOption(new OptionCycled("inventory.search.patternMode", 3, true) {
@Override
public boolean onClick(int button) {
SearchField.searchParser.clearCache();
return super.onClick(button);
}
});
tag.getTag("inventory.search.quoteDropItemName").setComment("Quote Drop Item Name").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.search.quoteDropItemName", true));
tag.getTag("inventory.search.format").setComment("Search Format (true: old format, false: custom format)")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.search.format", true) {
@Override
public boolean onClick(int button) {
if (!super.onClick(button)) {
return false;
}
if (state()) {
NEIClientConfig.setIntSetting("inventory.search.spaceMode", 1);
NEIClientConfig.setIntSetting("inventory.search.modNameSearchMode", 0);
NEIClientConfig.setIntSetting("inventory.search.tooltipSearchMode", 0);
NEIClientConfig.setIntSetting("inventory.search.identifierSearchMode", 0);
NEIClientConfig.setIntSetting("inventory.search.oreDictSearchMode", 0);
NEIClientConfig.setIntSetting("inventory.search.subsetsSearchMode", 1);
tag.getTag("inventory.search.prefixRedefinitions").setValue("{\"%\": \"@\", \"@\": \"%\"}");
SearchField.searchParser.prefixRedefinitions.clear();
SearchField.searchParser.prefixRedefinitions.put('%', '@');
SearchField.searchParser.prefixRedefinitions.put('@', '%');
SearchField.searchParser.clearCache();
} else {
NEIClientConfig.setIntSetting("inventory.search.spaceMode", 0);
NEIClientConfig.setIntSetting("inventory.search.modNameSearchMode", 1);
NEIClientConfig.setIntSetting("inventory.search.tooltipSearchMode", 0);
NEIClientConfig.setIntSetting("inventory.search.identifierSearchMode", 0);
NEIClientConfig.setIntSetting("inventory.search.oreDictSearchMode", 0);
NEIClientConfig.setIntSetting("inventory.search.subsetsSearchMode", 1);
tag.getTag("inventory.search.prefixRedefinitions").setValue("{}");
SearchField.searchParser.prefixRedefinitions.clear();
SearchField.searchParser.clearCache();
}
return true;
}
});
tag.getTag("inventory.search.spaceMode").setComment("Search Space Rules").getIntValue(0);
API.addOption(new OptionCycled("inventory.search.spaceMode", 3, true) {
@Override
public boolean onClick(int button) {
// SearchField.searchParser.clearCache();
return super.onClick(button);
}
@Override
public boolean isEnabled() {
return !tag.getTag("inventory.search.format").getBooleanValue();
}
});
tag.getTag("inventory.search.modNameSearchMode").setComment("Search mode for Mod Names (prefix: @)")
.getIntValue(1);
API.addOption(new OptionCycled("inventory.search.modNameSearchMode", 3, true) {
@Override
public boolean onClick(int button) {
SearchField.searchParser.clearCache();
return super.onClick(button);
}
@Override
public String getButtonText() {
return translateN(
name + "." + value(),
EnumChatFormatting.LIGHT_PURPLE
+ String.valueOf(SearchField.searchParser.getRedefinedPrefix('@')));
}
@Override
public boolean isEnabled() {
return !tag.getTag("inventory.search.format").getBooleanValue();
}
});
tag.getTag("inventory.search.tooltipSearchMode").setComment("Search mode for Tooltips (prefix: #)")
.getIntValue(0);
API.addOption(new OptionCycled("inventory.search.tooltipSearchMode", 3, true) {
@Override
public boolean onClick(int button) {
SearchField.searchParser.clearCache();
return super.onClick(button);
}
@Override
public String getButtonText() {
return translateN(
name + "." + value(),
EnumChatFormatting.YELLOW + String.valueOf(SearchField.searchParser.getRedefinedPrefix('#')));
}
@Override
public boolean isEnabled() {
return !tag.getTag("inventory.search.format").getBooleanValue();
}
});
tag.getTag("inventory.search.identifierSearchMode").setComment("Search mode for identifier (prefix: &)")
.getIntValue(0);
API.addOption(new OptionCycled("inventory.search.identifierSearchMode", 3, true) {
@Override
public boolean onClick(int button) {
SearchField.searchParser.clearCache();
return super.onClick(button);
}
@Override
public String getButtonText() {
return translateN(
name + "." + value(),
EnumChatFormatting.GOLD + String.valueOf(SearchField.searchParser.getRedefinedPrefix('&')));
}
@Override
public boolean isEnabled() {
return !tag.getTag("inventory.search.format").getBooleanValue();
}
});
tag.getTag("inventory.search.oreDictSearchMode").setComment("Search mode for Tag Names (prefix: $)")
.getIntValue(0);
API.addOption(new OptionCycled("inventory.search.oreDictSearchMode", 3, true) {
@Override
public boolean onClick(int button) {
SearchField.searchParser.clearCache();
return super.onClick(button);
}
@Override
public String getButtonText() {
return translateN(
name + "." + value(),
EnumChatFormatting.AQUA + String.valueOf(SearchField.searchParser.getRedefinedPrefix('$')));
}
@Override
public boolean isEnabled() {
return !tag.getTag("inventory.search.format").getBooleanValue();
}
});
tag.getTag("inventory.search.subsetsSearchMode").setComment("Search mode for Item Subsets (prefix: %)")
.getIntValue(1);
API.addOption(new OptionCycled("inventory.search.subsetsSearchMode", 3, true) {
@Override
public boolean onClick(int button) {
SearchField.searchParser.clearCache();
return super.onClick(button);
}
@Override
public String getButtonText() {
return translateN(
name + "." + value(),
EnumChatFormatting.DARK_PURPLE
+ String.valueOf(SearchField.searchParser.getRedefinedPrefix('%')));
}
@Override
public boolean isEnabled() {
return !tag.getTag("inventory.search.format").getBooleanValue();
}
});
String prefixRedefinitions = tag.getTag("inventory.search.prefixRedefinitions").setComment(
"Redefine search prefixes by providing a char-to-char map (JSON). The keys are the original prefixes, the values the new ones. Example: { \"$\": \"€\", \"#\": \"+\", \"@\": \"°\", \"%\": \"!\" }")
.getValue("{}");
try {
TypeToken<Map<Character, Character>> typeToken = new TypeToken<Map<Character, Character>>() {
private static final long serialVersionUID = 1L;
};
Map<Character, Character> charMap = new Gson().fromJson(prefixRedefinitions, typeToken.getType());
SearchField.searchParser.prefixRedefinitions.putAll(charMap);
} catch (JsonParseException e) {
logger.warn("Failed to convert prefix redefinitions from JSON to CharToCharMap:", e);
}
}
private static void setDefaultKeyBindings() {
API.addHashBind("gui.recipe", Keyboard.KEY_R);
API.addHashBind("gui.usage", Keyboard.KEY_U);
@@ -346,10 +683,13 @@ public class NEIClientConfig {
API.addHashBind("gui.search", Keyboard.KEY_F);
API.addHashBind("gui.bookmark", Keyboard.KEY_A);
API.addHashBind("gui.bookmark_recipe", Keyboard.KEY_A + NEIClientUtils.SHIFT_HASH);
API.addHashBind("gui.remove_recipe", Keyboard.KEY_A + NEIClientUtils.SHIFT_HASH);
API.addHashBind("gui.bookmark_count", Keyboard.KEY_A + NEIClientUtils.CTRL_HASH);
API.addHashBind(
"gui.bookmark_recipe_count",
Keyboard.KEY_A + NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH);
API.addHashBind("gui.bookmark_pull_items", Keyboard.KEY_V);
API.addHashBind("gui.bookmark_pull_items_ingredients", Keyboard.KEY_V + NEIClientUtils.SHIFT_HASH);
API.addHashBind("gui.overlay", Keyboard.KEY_S);
API.addHashBind("gui.overlay_use", Keyboard.KEY_S + NEIClientUtils.SHIFT_HASH);
API.addHashBind("gui.overlay_hide", Keyboard.KEY_S + NEIClientUtils.CTRL_HASH);
@@ -358,6 +698,11 @@ public class NEIClientConfig {
API.addKeyBind("gui.getnextsearch", Keyboard.KEY_DOWN);
API.addHashBind("gui.next_tooltip", Keyboard.KEY_Z);
API.addHashBind("gui.itemzoom_toggle", Keyboard.KEY_Z + NEIClientUtils.SHIFT_HASH);
API.addHashBind("gui.itemzoom_hold", 0);
API.addHashBind("gui.itemzoom_zoom_in", 0);
API.addHashBind("gui.itemzoom_zoom_out", 0);
API.addKeyBind("world.chunkoverlay", Keyboard.KEY_F9);
API.addKeyBind("world.moboverlay", Keyboard.KEY_F7);
API.addKeyBind("world.highlight_tips", Keyboard.KEY_NUMPAD0);
@@ -368,6 +713,8 @@ public class NEIClientConfig {
API.addKeyBind("world.rain", 0);
API.addKeyBind("world.heal", 0);
API.addKeyBind("world.creative", 0);
API.addHashBind("gui.copy_name", Keyboard.KEY_C + NEIClientUtils.CTRL_HASH);
API.addHashBind("gui.copy_oredict", Keyboard.KEY_D + NEIClientUtils.CTRL_HASH);
}
public static OptionList getOptionList() {
@@ -375,23 +722,29 @@ public class NEIClientConfig {
}
public static void loadWorld(String worldPath) {
NEIClientConfig.worldPath = worldPath;
unloadWorld();
setInternalEnabled(true);
logger.debug("Loading " + (Minecraft.getMinecraft().isSingleplayer() ? "Local" : "Remote") + " World");
bootNEI(ClientUtils.getWorld());
final File specificDir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
final boolean newWorld = !specificDir.exists();
if (!worldPath.equals(NEIClientConfig.worldPath)) {
NEIClientConfig.worldPath = worldPath;
if (newWorld) {
specificDir.mkdirs();
logger.debug("Loading " + (Minecraft.getMinecraft().isSingleplayer() ? "Local" : "Remote") + " World");
final File specificDir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
final boolean newWorld = !specificDir.exists();
if (newWorld) {
specificDir.mkdirs();
}
world = new ConfigSet(new File(specificDir, "NEI.dat"), new ConfigFile(new File(specificDir, "NEI.cfg")));
bootNEI(ClientUtils.getWorld());
onWorldLoad(newWorld);
}
}
initBookmarkFile(worldPath);
initPresetsFile(worldPath);
world = new ConfigSet(new File(specificDir, "NEI.dat"), new ConfigFile(new File(specificDir, "NEI.cfg")));
onWorldLoad(newWorld);
public static String getWorldPath() {
return NEIClientConfig.worldPath;
}
private static void onWorldLoad(boolean newWorld) {
@@ -401,11 +754,12 @@ public class NEIClientConfig {
setWorldDefaults();
creativeInv = new ItemStack[54];
LayoutManager.searchField.setText(getSearchExpression());
ItemPanels.itemPanel.quantity.setText(Integer.toString(getItemQuantity()));
SubsetWidget.loadHidden();
LayoutManager.quantity.setText(Integer.toString(getItemQuantity()));
if (newWorld && Minecraft.getMinecraft().isSingleplayer()) world.config.getTag("inventory.cheatmode")
.setIntValue(NEIClientUtils.mc().playerController.isInCreativeMode() ? 2 : 0);
if (newWorld && Minecraft.getMinecraft().isSingleplayer()) {
world.config.getTag("inventory.cheatmode")
.setIntValue(NEIClientUtils.mc().playerController.isInCreativeMode() ? 2 : 0);
}
NEIInfo.load(ClientUtils.getWorld());
}
@@ -419,8 +773,24 @@ public class NEIClientConfig {
world.saveNBT();
}
public static void unloadWorld() {
if (ItemPanels.bookmarkPanel != null) {
ItemPanels.bookmarkPanel.saveBookmarks();
}
SubsetWidget.saveHidden();
CollapsibleItems.saveStates();
if (world != null) {
world.saveNBT();
}
}
private static final Map<String, String> keySettings = new HashMap<>();
public static int getKeyBinding(String string) {
return getSetting("keys." + string).getIntValue(Keyboard.KEY_NONE);
final String key = keySettings.computeIfAbsent(string, (s) -> "keys." + s);
return getSetting(key).getIntValue(Keyboard.KEY_NONE);
}
public static void setDefaultKeyBinding(String string, int key) {
@@ -432,90 +802,66 @@ public class NEIClientConfig {
return hash != Keyboard.CHAR_NONE && hash == NEIClientUtils.getKeyHash();
}
public static String getKeyName(int keyBind, boolean useHash) {
return getKeyName(keyBind, useHash, false);
}
public static String getKeyName(String keyBind) {
final int hash = getKeyBinding(keyBind);
public static String getKeyName(int keyBind, boolean useHash, boolean showOnlyHash) {
String keyText = "";
if (useHash) {
final String DELIMITER = " + ";
if ((keyBind & NEIClientUtils.CTRL_HASH) != 0) {
keyText += NEIClientUtils.translate(Minecraft.isRunningOnMac ? "key.ctrl.mac" : "key.ctrl") + DELIMITER;
}
if ((keyBind & NEIClientUtils.SHIFT_HASH) != 0) {
keyText += "SHIFT" + DELIMITER;
}
if ((keyBind & NEIClientUtils.ALT_HASH) != 0) {
keyText += "ALT" + DELIMITER;
}
if (hash == Keyboard.CHAR_NONE) {
return null;
}
if (!showOnlyHash) {
keyText += Keyboard.getKeyName(unHashKey(keyBind));
}
return keyText;
}
public static int unHashKey(int keyBind) {
return keyBind & ~(NEIClientUtils.CTRL_HASH | NEIClientUtils.SHIFT_HASH | NEIClientUtils.ALT_HASH);
return NEIClientUtils.getKeyName(hash);
}
public static void bootNEI(World world) {
if (configLoaded) return;
if (!mainNEIConfigLoaded) {
// main NEI config loading
ItemInfo.load(world);
GuiInfo.load();
RecipeInfo.load();
HeldItemHandler.load();
LayoutManager.load();
NEIController.load();
BookmarkContainerInfo.load();
mainNEIConfigLoaded = true;
ItemInfo.load(world);
GuiInfo.load();
RecipeInfo.load();
LayoutManager.load();
NEIController.load();
RecipeCatalysts.loadCatalystInfo();
new Thread("NEI Plugin Loader") {
new Thread("NEI Plugin Loader") {
@Override
public void run() {
@Override
public void run() {
ClassDiscoverer classDiscoverer = new ClassDiscoverer(
test -> test.startsWith("NEI") && test.endsWith("Config.class"),
IConfigureNEI.class);
NEIClientConfig.pluginsList.parallelStream().forEach(clazz -> {
try {
IConfigureNEI config = (IConfigureNEI) clazz.getConstructor().newInstance();
config.loadConfig();
NEIModContainer.plugins.add(config);
logger.debug("Loaded {}", clazz.getName());
} catch (Throwable e) {
logger.error("Failed to Load {}", clazz.getName(), e);
}
});
classDiscoverer.findClasses();
RecipeCatalysts.loadCatalystInfo();
ItemPanels.bookmarkPanel.load();
SubsetWidget.loadHidden();
CollapsibleItems.load();
ItemSorter.loadConfig();
for (Class<?> clazz : classDiscoverer.classes) {
try {
IConfigureNEI config = (IConfigureNEI) clazz.newInstance();
config.loadConfig();
NEIModContainer.plugins.add(config);
logger.debug("Loaded " + clazz.getName());
} catch (Exception e) {
logger.error("Failed to Load " + clazz.getName(), e);
}
// Set pluginNEIConfigLoaded here before posting the NEIConfigsLoadedEvent. This used to be the
// other way around, but apparently if your modpack includes 800 mods the event poster might not
// return in time and cause issues when loading a world for a second time as configLoaded is still
// false. This may cause issues in case one of the event handler calls the (non-thread-safe) NEI
// API. I don't expect any handler to do this, but who knows what modders have come up with...
pluginNEIConfigLoaded = true;
MinecraftForge.EVENT_BUS.post(new NEIConfigsLoadedEvent());
ItemList.loadItems.restart();
}
MinecraftForge.EVENT_BUS.post(new NEIConfigsLoadedEvent());
configLoaded = true;
}
}.start();
ItemSorter.loadConfig();
}
private static void initBookmarkFile(String worldPath) {
if (!global.config.getTag("inventory.worldSpecificBookmarks").getBooleanValue()) {
worldPath = "global";
}.start();
} else {
ItemPanels.bookmarkPanel.load();
SubsetWidget.loadHidden();
ItemList.loadItems.restart();
}
ItemPanels.bookmarkPanel.setBookmarkFile(worldPath);
}
private static void initPresetsFile(String worldPath) {
if (!global.config.getTag("inventory.worldSpecificPresets").getBooleanValue()) {
worldPath = "global";
}
PresetsWidget.loadPresets(worldPath);
}
public static boolean isWorldSpecific(String setting) {
@@ -537,47 +883,71 @@ public class NEIClientConfig {
}
public static boolean isBookmarkPanelHidden() {
return !getBooleanSetting("inventory.bookmarksEnabled");
}
public static boolean useNBTInBookmarks() {
return getBooleanSetting("inventory.useNBTInBookmarks");
return !getBooleanSetting("inventory.bookmarks.enabled");
}
public static boolean areBookmarksAnimated() {
return getBooleanSetting("inventory.bookmarksAnimationEnabled");
return getBooleanSetting("inventory.bookmarks.animation");
}
public static int getRecipeTooltipsMode() {
return getIntSetting("inventory.bookmarks.recipeTooltipsMode");
}
public static boolean showRecipeMarker() {
return getBooleanSetting("inventory.showRecipeMarker");
return getBooleanSetting("inventory.bookmarks.showRecipeMarker");
}
public static boolean showItemQuantityWidget() {
return getBooleanSetting("inventory.showItemQuantityWidget");
}
public static boolean hideItemsUntilSearching() {
return getBooleanSetting("inventory.search.hideUntilSearching");
}
public static boolean isSearchWidgetCentered() {
return getBooleanSetting("inventory.centerSearchWidget");
return getBooleanSetting("inventory.search.widgetPosition");
}
public static boolean showSubsetWidget() {
return getBooleanSetting("inventory.subsets.enabled");
}
public static boolean subsetWidgetOnTop() {
return getBooleanSetting("inventory.subsets.widgetPosition");
}
public static int searchWidgetAutofocus() {
return getIntSetting("inventory.search.widgetAutofocus");
}
public static boolean areJEIStyleTabsVisible() {
return getBooleanSetting("inventory.jei_style_tabs");
return getBooleanSetting("inventory.guirecipe.jeiStyleTabs");
}
public static boolean isJEIStyleItemPresenceOverlayVisible() {
return getBooleanSetting("inventory.jei_style_item_presence_overlay");
public static int itemPresenceOverlay() {
return getIntSetting("inventory.guirecipe.itemPresenceOverlay");
}
public static boolean isSlotHighlightPresent() {
return getBooleanSetting("inventory.guirecipe.slotHighlightPresent");
}
public static boolean areJEIStyleRecipeCatalystsVisible() {
return getBooleanSetting("inventory.jei_style_recipe_catalyst");
return getBooleanSetting("inventory.guirecipe.jeiStyleRecipeCatalyst");
}
public static boolean useCreativeTabStyle() {
return getBooleanSetting("inventory.creative_tab_style");
return getBooleanSetting("inventory.guirecipe.creativeTabStyle");
}
public static boolean ignorePotionOverlap() {
return getBooleanSetting("inventory.ignore_potion_overlap");
return getBooleanSetting("inventory.bookmarks.ignorePotionOverlap");
}
public static int craftingChainDir() {
return getIntSetting("inventory.bookmarks.craftingChainDir");
}
public static boolean optimizeGuiOverlapComputation() {
@@ -585,11 +955,15 @@ public class NEIClientConfig {
}
public static boolean useJEIStyledCycledIngredients() {
return getBooleanSetting("inventory.jei_style_cycled_ingredients");
return getBooleanSetting("inventory.guirecipe.jeiStyleCycledIngredients");
}
public static boolean showCycledIngredientsTooltip() {
return getBooleanSetting("inventory.guirecipe.cycledIngredientsTooltip");
}
public static boolean requireShiftForOverlayRecipe() {
return getBooleanSetting("inventory.shift_overlay_recipe");
return getBooleanSetting("inventory.guirecipe.shiftOverlayRecipe");
}
public static boolean isEnabled() {
@@ -597,7 +971,7 @@ public class NEIClientConfig {
}
public static boolean isLoaded() {
return configLoaded;
return mainNEIConfigLoaded && pluginNEIConfigLoaded;
}
public static boolean loadHandlersFromJar() {
@@ -608,6 +982,10 @@ public class NEIClientConfig {
return !getBooleanSetting("tools.catalyst_load_from_config");
}
public static boolean isProfileRecipeEnabled() {
return NEIClientConfig.getBooleanSetting("inventory.guirecipe.profile");
}
public static void setEnabled(boolean flag) {
getSetting("inventory.widgetsenabled").setBooleanValue(flag);
}
@@ -620,8 +998,13 @@ public class NEIClientConfig {
return getIntSetting("inventory.cheatmode");
}
private static void checkCheatMode() {
if (getLockedMode() != -1) setIntSetting("inventory.cheatmode", getLockedMode());
public static boolean canChangeCheatMode() {
if (getLockedMode() != -1) {
setIntSetting("inventory.cheatmode", getLockedMode());
return false;
}
return true;
}
public static int getLockedMode() {
@@ -669,7 +1052,6 @@ public class NEIClientConfig {
public static void setSearchExpression(String expression) {
world.nbt.setString("search", expression);
world.saveNBT();
}
public static boolean isMouseScrollTransferEnabled() {
@@ -680,8 +1062,16 @@ public class NEIClientConfig {
return !getBooleanSetting("inventory.invertMouseScrollTransfer");
}
public static boolean shouldCacheItemRendering() {
return getBooleanSetting("inventory.cacheItemRendering") && OpenGlHelper.framebufferSupported;
public static boolean showHistoryPanelWidget() {
return getBooleanSetting("inventory.history.enabled");
}
public static int getGridRenderingCacheMode() {
return OpenGlHelper.framebufferSupported ? getIntSetting("inventory.gridRenderingCacheMode") : 0;
}
public static boolean enableCollapsibleItems() {
return getBooleanSetting("inventory.collapsibleItems.enabled");
}
public static boolean getMagnetMode() {
@@ -25,6 +25,7 @@ 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;
@@ -36,8 +37,6 @@ 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;
@@ -58,11 +57,26 @@ public class NEIClientUtils extends NEIServerUtils {
/** Formats a number with group separator and at most 2 fraction digits. */
private static final Map<Locale, DecimalFormat> decimalFormatters = new HashMap<>();
private static final Map<Integer, Integer> keyHashMap = 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;
static {
keyHashMap.put(Keyboard.KEY_LSHIFT, SHIFT_HASH);
keyHashMap.put(Keyboard.KEY_RSHIFT, SHIFT_HASH);
keyHashMap.put(Keyboard.KEY_LCONTROL, CTRL_HASH);
keyHashMap.put(Keyboard.KEY_LCONTROL, CTRL_HASH);
keyHashMap.put(Keyboard.KEY_LMETA, CTRL_HASH);
keyHashMap.put(Keyboard.KEY_RMETA, CTRL_HASH);
keyHashMap.put(Keyboard.KEY_LMENU, ALT_HASH);
keyHashMap.put(Keyboard.KEY_LMENU, ALT_HASH);
}
public static Minecraft mc() {
return Minecraft.getMinecraft();
}
@@ -308,7 +322,7 @@ public class NEIClientUtils extends NEIServerUtils {
}
public static void sendCommand(String command, Object... args) {
if (command.length() == 0) return;
if (command.isEmpty()) return;
NumberFormat numberformat = NumberFormat.getIntegerInstance();
numberformat.setGroupingUsed(false);
@@ -367,18 +381,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 +413,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 +452,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 (!keyHashMap.containsKey(keycode)) {
return getMetaHash() + keycode;
}
}
@@ -446,6 +460,45 @@ public class NEIClientUtils extends NEIServerUtils {
return Keyboard.CHAR_NONE;
}
public static String getKeyHashName(int keyBind) {
StringJoiner keyText = new StringJoiner(" + ");
if ((keyBind & CTRL_HASH) != 0) {
keyText.add(translate(Minecraft.isRunningOnMac ? "key.ctrl.mac" : "key.ctrl"));
}
if ((keyBind & SHIFT_HASH) != 0) {
keyText.add(translate("key.shift"));
}
if ((keyBind & ALT_HASH) != 0) {
keyText.add(translate("key.alt"));
}
return keyText.toString();
}
public static String getKeyName(int keyBind) {
keyBind = keyHashMap.getOrDefault(keyBind, keyBind);
StringJoiner keyText = new StringJoiner(" + ");
String hashText = getKeyHashName(keyBind);
int keyID = unHashKey(keyBind);
if (!hashText.isEmpty()) {
keyText.add(hashText);
}
if (keyID != Keyboard.CHAR_NONE || hashText.isEmpty()) {
keyText.add(Keyboard.getKeyName(keyID));
}
return keyText.toString();
}
public static int unHashKey(int keyBind) {
return keyBind & ~(CTRL_HASH | SHIFT_HASH | ALT_HASH);
}
public static void playClickSound() {
mc().getSoundHandler()
.playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F));
@@ -457,16 +510,9 @@ public class NEIClientUtils extends NEIServerUtils {
String stackTrace = cause + sw;
if (buffer.contains(stackTrace)) return;
System.err.println("Error while rendering: " + cause);
System.err.println("Error while rendering: " + cause + " (" + e.getMessage() + ")");
e.printStackTrace();
buffer.add(stackTrace);
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
if (player != null) {
IChatComponent chat = new ChatComponentTranslation("nei.chat.render.error");
chat.getChatStyle().setColor(EnumChatFormatting.RED);
player.addChatComponentMessage(chat);
}
}
public static void reportErrorBuffered(Throwable e, Set<String> buffer, ItemStack cause) {
@@ -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;
@@ -22,6 +27,7 @@ import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModMetadata;
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 +39,7 @@ public class NEIModContainer extends DummyModContainer {
public static LinkedList<IConfigureNEI> plugins = new LinkedList<>();
private static boolean gregTech5Loaded;
private static boolean gtnhLibLoaded;
public NEIModContainer() {
super(getModMetadata());
@@ -54,16 +61,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,6 +115,7 @@ 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();
}
@@ -114,11 +129,19 @@ 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();
}
}
@Subscribe
public void handleIMCMessages(FMLInterModComms.IMCEvent event) {
IMCHandler.processIMC(event.getMessages());
+32 -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,61 +31,61 @@ 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;
}
@@ -126,14 +129,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 +172,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 +182,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 +213,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 +232,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 +240,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);
@@ -197,7 +197,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 =");
@@ -42,6 +42,7 @@ 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;
@@ -88,9 +89,8 @@ public class NEIServerUtils {
else return player.inventory.getStackInSlot(slot);
}
@SuppressWarnings("unchecked")
public static void deleteAllItems(EntityPlayerMP player) {
for (Slot slot : (List<Slot>) player.openContainer.inventorySlots) slot.putStack(null);
for (Slot slot : player.openContainer.inventorySlots) slot.putStack(null);
player.sendContainerAndContentsToPlayer(player.openContainer, player.openContainer.getInventory());
}
@@ -295,7 +295,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,40 @@
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 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;
}
}
+45 -30
View File
@@ -1,6 +1,7 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
@@ -10,11 +11,12 @@ import codechicken.nei.ItemPanel.ItemPanelSlot;
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 extends Widget implements IContainerTooltipHandler {
protected static final int PADDING = 2;
@@ -41,11 +43,14 @@ public abstract class PanelWidget extends Widget {
pagePrev = new Button("Prev") {
public boolean onButtonPress(boolean rightclick) {
if (!rightclick) {
if (rightclick) {
grid.setPage(0);
} else {
grid.shiftPage(-1);
return true;
}
return false;
return true;
}
@Override
@@ -56,11 +61,14 @@ public abstract class PanelWidget extends Widget {
pageNext = new Button("Next") {
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
@@ -163,7 +171,7 @@ public abstract class PanelWidget extends Widget {
protected abstract int resizeFooter(GuiContainer gui);
public void setVisible() {
if (grid.getPerPage() > 0) {
if (grid.getPerPage() > 0 && !grid.isEmpty()) {
LayoutManager.addWidget(pagePrev);
LayoutManager.addWidget(pageNext);
LayoutManager.addWidget(pageLabel);
@@ -171,6 +179,11 @@ public abstract class PanelWidget extends Widget {
}
}
@Override
public void update() {
grid.update();
}
@Override
public void draw(int mousex, int mousey) {
grid.draw(mousex, mousey);
@@ -187,6 +200,10 @@ public abstract class PanelWidget extends Widget {
@Override
public void mouseDragged(int mousex, int mousey, int button, long heldTime) {
if (mouseDownSlot >= grid.realItems.size()) {
mouseDownSlot = -1;
}
if (mouseDownSlot >= 0 && draggedStack == null
&& NEIClientUtils.getHeldItem() == null
&& NEIClientConfig.hasSMPCounterPart()) {
@@ -203,28 +220,8 @@ public abstract class PanelWidget extends Widget {
@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);
if (hoverSlot != null) {
@@ -317,9 +314,10 @@ public abstract class PanelWidget extends Widget {
ItemPanelSlot hoverSlot = getSlotMouseOver(mousex, mousey);
if (hoverSlot != null && hoverSlot.slotIndex == mouseDownSlot && draggedStack == null) {
ItemStack item = hoverSlot.item;
ItemStack item = hoverSlot.item.copy();
if (NEIController.manager.window instanceof GuiRecipe || !NEIClientConfig.canCheatItem(item)) {
if (NEIController.manager.window instanceof GuiRecipe || NEIClientUtils.shiftKey()
|| !NEIClientConfig.canCheatItem(item)) {
if (button == 0) {
GuiCraftingRecipe.openRecipeGui("item", item);
@@ -383,4 +381,21 @@ public abstract class PanelWidget extends Widget {
public boolean contains(int px, int py) {
return grid.contains(px, py);
}
@Override
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
return currenttip;
}
@Override
public List<String> handleItemDisplayName(GuiContainer gui, ItemStack itemstack, List<String> currenttip) {
return currenttip;
}
@Override
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
List<String> currenttip) {
return currenttip;
}
}
@@ -1,13 +1,20 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.Arrays;
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.ItemList.AllMultiItemFilter;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.recipe.GuiRecipe;
/**
* Simply an {@link ItemStack} with position. Mainly used in the recipe handlers.
*/
@@ -26,8 +33,11 @@ public class PositionedStack {
relx = x;
rely = y;
if (genPerms) generatePermutations();
else setPermutationToRender(0);
if (genPerms) {
generatePermutations();
} else {
setPermutationToRender(0);
}
}
public PositionedStack(Object object, int x, int y) {
@@ -37,7 +47,7 @@ public class PositionedStack {
public void generatePermutations() {
if (permutated) return;
ArrayList<ItemStack> stacks = new ArrayList<>();
List<ItemStack> stacks = new ArrayList<>();
for (ItemStack item : items) {
if (item == null || item.getItem() == null) continue;
@@ -72,15 +82,60 @@ public class PositionedStack {
}
public PositionedStack copy() {
return new PositionedStack(items, relx, rely);
PositionedStack pStack = new PositionedStack(Arrays.asList(items), 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).stream().filter(getItemFilter(additionalFilter)::matches)
.collect(Collectors.toList());
if (items.isEmpty()) {
items.addAll(
Arrays.asList(this.items).stream().filter(item -> !ItemInfo.isHidden(item))
.collect(Collectors.toList()));
}
if (items.isEmpty()) {
items.addAll(Arrays.asList(this.items));
}
return items;
}
private ItemFilter getItemFilter(ItemFilter additionalFilter) {
return new AllMultiItemFilter(
additionalFilter,
item -> !ItemInfo.isHidden(item),
PresetsList.getItemFilter(),
GuiRecipe.getSearchItemFilter());
}
public boolean setPermutationToRender(ItemStack ingredient) {
for (int index = 0; index < this.items.length; index++) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(this.items[index], ingredient)) {
setPermutationToRender(index);
return true;
}
}
return false;
}
public void setPermutationToRender(int index) {
item = items[index].copy();
if (item.getItem() == null) item = new ItemStack(Blocks.fire);
else if (item.getItemDamage() == OreDictionary.WILDCARD_VALUE && item.getItem() != null
&& item.getItem().isRepairable())
item.setItemDamage(0);
this.item = this.items[index].copy();
if (this.item.getItem() == null) {
this.item = new ItemStack(Blocks.fire);
} else if (this.item.getItemDamage() == OreDictionary.WILDCARD_VALUE && this.item.getItem().isRepairable()) {
this.item.setItemDamage(0);
}
}
public boolean contains(ItemStack ingredient) {
@@ -0,0 +1,249 @@
package codechicken.nei;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import net.minecraft.item.ItemStack;
import org.apache.commons.io.IOUtils;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import codechicken.core.CommonUtils;
import codechicken.nei.api.API;
import codechicken.nei.api.IRecipeFilter;
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.recipe.IRecipeHandler;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
public class PresetsList {
public enum PresetMode {
HIDE,
REMOVE,
GROUP;
}
public static class Preset implements ItemFilter {
public String name = "";
public boolean enabled = true;
public PresetMode mode = PresetMode.HIDE;
public Set<String> items = new HashSet<>();
public static String getIdentifier(ItemStack stack) {
return StackInfo.getItemStackGUID(stack);
}
@Override
public boolean matches(ItemStack item) {
return items.contains(Preset.getIdentifier(item));
}
public Preset copy() {
Preset preset = new Preset();
preset.name = name;
preset.enabled = enabled;
preset.mode = mode;
preset.items = new HashSet<>(items);
return preset;
}
}
protected static class RecipesFilter implements IRecipeFilterProvider, IRecipeFilter {
public Set<String> cache;
public IRecipeFilter getFilter() {
if (cache == null) {
cache = PresetsList.presets.stream().filter(p -> p.enabled && p.mode == PresetMode.REMOVE)
.flatMap(p -> p.items.stream()).collect(Collectors.toSet());
}
return cache.isEmpty() ? null : this;
}
@Override
public boolean matches(IRecipeHandler handler, List<PositionedStack> ingredients, PositionedStack result,
List<PositionedStack> others) {
if (matchPositionedStack(ingredients, false)) {
return false;
}
if (result != null && matchPositionedStack(result)) {
return true;
}
if (!others.isEmpty() && matchPositionedStack(others, true)) {
return true;
}
return result == null && others.isEmpty();
}
private boolean matchPositionedStack(List<PositionedStack> items, boolean dir) {
for (PositionedStack pStack : items) {
if (matchPositionedStack(pStack) == dir) {
return true;
}
}
return false;
}
private boolean matchPositionedStack(PositionedStack pStack) {
for (ItemStack stack : pStack.items) {
if (!cache.contains(Preset.getIdentifier(stack))) {
return true;
}
}
return false;
}
}
protected static class ItemPanelFilter implements ItemFilterProvider, ItemFilter {
public Set<String> cache;
public ItemFilter getFilter() {
if (cache == null) {
cache = PresetsList.presets.stream()
.filter(p -> p.enabled && (p.mode == PresetMode.HIDE || p.mode == PresetMode.REMOVE))
.flatMap(p -> p.items.stream()).collect(Collectors.toSet());
}
return cache.isEmpty() ? null : this;
}
@Override
public boolean matches(ItemStack stack) {
return !cache.contains(Preset.getIdentifier(stack));
}
}
public static final List<Preset> presets = new ArrayList<>();
protected static RecipesFilter recipeFilter = new RecipesFilter();
protected static ItemPanelFilter itemFilter = new ItemPanelFilter();
static {
API.addItemFilter(itemFilter);
API.addRecipeFilter(recipeFilter);
}
public static ItemFilter getItemFilter() {
return itemFilter.getFilter();
}
public static void load() {
final File presetsFile = new File(CommonUtils.getMinecraftDir(), "saves/NEI/global/presets.ini");
if (presetsFile == null || !presetsFile.exists()) {
return;
}
List<String> itemStrings;
try (FileInputStream reader = new FileInputStream(presetsFile)) {
NEIClientConfig.logger.info("Loading presets from file {}", presetsFile);
itemStrings = IOUtils.readLines(reader, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load presets from file {}", presetsFile, e);
return;
}
JsonParser parser = new JsonParser();
Preset preset = new Preset();
presets.clear();
for (String itemStr : itemStrings) {
try {
if (itemStr.isEmpty()) {
itemStr = "; {}";
}
if (itemStr.startsWith("; ")) {
JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
if (!preset.items.isEmpty()) {
// do not create empty namespaces
presets.add(preset);
preset = new Preset();
}
if (settings.has("name")) {
preset.name = settings.get("name").getAsString();
}
if (settings.has("enabled")) {
preset.enabled = settings.get("enabled").getAsBoolean();
}
if (settings.has("mode")) {
preset.mode = PresetMode.valueOf(settings.get("mode").getAsString());
}
} else {
preset.items.add(itemStr);
}
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
NEIClientConfig.logger.error("Failed to load presets ItemStack from json string:\n{}", itemStr);
}
}
if (!preset.items.isEmpty()) {
presets.add(preset);
}
}
public static void savePresets() {
final File presetsFile = new File(CommonUtils.getMinecraftDir(), "saves/NEI/global/presets.ini");
final List<String> strings = new ArrayList<>();
for (Preset preset : presets) {
JsonObject settings = new JsonObject();
settings.add("name", new JsonPrimitive(preset.name));
settings.add("enabled", new JsonPrimitive(preset.enabled));
settings.add("mode", new JsonPrimitive(preset.mode.toString()));
strings.add("; " + NBTJson.toJson(settings));
strings.addAll(preset.items);
}
try (FileOutputStream output = new FileOutputStream(presetsFile)) {
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save presets list to file {}", presetsFile, e);
}
recipeFilter.cache = null;
itemFilter.cache = null;
CollapsibleItems.saveStates();
CollapsibleItems.load();
LayoutManager.markItemsDirty();
}
}
@@ -1,922 +0,0 @@
package codechicken.nei;
import static codechicken.nei.NEIClientUtils.translate;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.item.ItemStack;
import org.apache.commons.io.IOUtils;
import org.lwjgl.input.Keyboard;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import codechicken.core.CommonUtils;
import codechicken.core.gui.GuiScrollSlot;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
import cpw.mods.fml.common.registry.GameRegistry;
public class PresetsWidget extends Widget {
public static class PresetTag implements ItemFilter {
public String filename = null;
public String displayName = "";
public boolean whitelist = true;
public HashSet<String> items;
public PresetTag(String displayName) {
this(displayName, new HashSet<>(), false, null);
}
public PresetTag(String displayName, HashSet<String> items) {
this(displayName, items, true, null);
}
public PresetTag(String displayName, HashSet<String> items, boolean whitelist, String filename) {
this.displayName = displayName;
this.items = items != null ? items : new HashSet<>();
this.whitelist = whitelist;
this.filename = filename;
}
public boolean matches(final ItemStack stack) {
return items.contains(StackInfo.getItemStackGUID(stack)) == whitelist;
}
public static PresetTag loadFromFile(File file) {
if (!file.isFile() || !file.exists() || file.getName().equals("selected.ini")) {
return null;
}
try {
List<String> itemStrings;
try (FileInputStream input = new FileInputStream(file)) {
NEIClientConfig.logger.info("Loading presets from file {}", file);
itemStrings = IOUtils.readLines(input, "UTF-8");
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load presets from file {}", file, e);
return null;
}
final JsonParser parser = new JsonParser();
final JsonObject metaObject = parser.parse(itemStrings.remove(0)).getAsJsonObject();
final String displayName = metaObject.get("displayName").getAsString();
final boolean whitelist = metaObject.get("whitelist").getAsBoolean();
final HashSet<String> items = new HashSet<>();
for (String itemStr : itemStrings) {
items.add(itemStr);
}
return new PresetTag(displayName, items, whitelist, file.getName());
} catch (Throwable th) {
NEIClientConfig.logger.error("Failed to load presets ItemStack from file", file);
}
return null;
}
public void deleteFile() {
if (presetsDir == null || filename == null) return;
final File tagFile = new File(presetsDir, filename);
if (tagFile.exists()) {
tagFile.delete();
}
}
public void saveToFile() {
if (presetsDir == null) return;
if (filename == null) {
final String sanitized = displayName.replaceAll("[^_\\-.0-9a-zA-Z]", "_");
int index = 1;
filename = sanitized + ".ini";
while ((new File(presetsDir, filename)).exists() || filename.equals("selected.ini")) {
filename = sanitized + " (" + index + ").ini";
index++;
}
}
final List<String> strings = new ArrayList<>();
final JsonObject row = new JsonObject();
row.add("displayName", new JsonPrimitive(displayName));
row.add("whitelist", new JsonPrimitive(whitelist));
strings.add(NBTJson.toJson(row));
try {
strings.addAll(items);
} catch (JsonSyntaxException e) {
NEIClientConfig.logger.error("Failed to stringify presets ItemStack to json string");
}
final File tagFile = new File(presetsDir, filename);
try (FileOutputStream output = new FileOutputStream(tagFile)) {
IOUtils.writeLines(strings, "\n", output, "UTF-8");
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save presets list to file {}", tagFile, e);
}
}
@SuppressWarnings("unchecked")
public PresetTag copy() {
return new PresetTag(displayName, (HashSet) items.clone(), whitelist, null);
}
}
protected static class SubsetListBox extends GuiScrollSlot {
protected final List<PresetTag> presets = new ArrayList<>();
protected final List<PresetTag> selected = new ArrayList<>();
protected int lastSelectedIndex = 0;
public SubsetListBox(File presetsDir) {
super(0, 0, 0, 0);
setSmoothScroll(false);
try {
presets.addAll(
ItemList.forkJoinPool.submit(
() -> Arrays.asList(presetsDir.listFiles()).parallelStream()
.map(f -> PresetTag.loadFromFile(f)).filter(p -> p != null)
.collect(Collectors.toCollection(ArrayList::new)))
.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return;
}
selected.addAll(loadSelFromFile(presetsDir, presets));
sort();
}
public SubsetListBox() {
super(0, 0, 0, 0);
setSmoothScroll(false);
}
public void addTag(final PresetTag tag, boolean sel) {
presets.add(tag);
if (sel) {
selected.add(tag);
}
}
protected List<PresetTag> getPresets() {
return presets;
}
protected List<PresetTag> getSelected() {
return selected;
}
public void replaceSeleted(final PresetTag tag) {
if (selected.size() == 1) {
selected.get(0).deleteFile();
presets.set(presets.indexOf(selected.get(0)), tag);
selected.set(0, tag);
} else {
presets.add(tag);
selected.add(tag);
}
tag.saveToFile();
saveSelToFile();
sort();
}
public void sort() {
presets.sort((o1, o2) -> o1.displayName.compareTo(o2.displayName));
}
public void clear() {
presets.clear();
selected.clear();
}
@Override
public int getSlotHeight(int slot) {
return 18;
}
@Override
protected int getNumSlots() {
return presets.size();
}
@Override
protected void slotClicked(int slot, int button, int mx, int my, int count) {
if (slot >= presets.size()) {
return;
}
final PresetTag tag = presets.get(slot);
final int width = windowBounds().width;
final Rectangle4i direction = new Rectangle4i(0, 0, 18, 18);
final Rectangle4i delete = new Rectangle4i(width - 18, 0, 18, 18);
final Rectangle4i option = new Rectangle4i(18, 0, width - 18 - 18, 18);
if (option.contains(mx, my)) {
final boolean sel = selected.contains(tag);
if (NEIClientUtils.controlKey()) {
if (sel) {
selected.remove(tag);
} else {
selected.add(tag);
}
} else if (NEIClientUtils.shiftKey()) {
selected.clear();
for (int i = Math.min(lastSelectedIndex, slot); i <= Math.max(lastSelectedIndex, slot); i++) {
if (!selected.contains(presets.get(i))) {
selected.add(presets.get(i));
}
}
} else {
final int size = selected.size();
selected.clear();
if (!sel || size > 1) {
selected.add(tag);
}
}
if (selected.isEmpty()) {
lastSelectedIndex = 0;
} else if (!NEIClientUtils.shiftKey()) {
lastSelectedIndex = slot;
}
} else if (delete.contains(mx, my)) {
presets.remove(tag);
selected.remove(tag);
tag.deleteFile();
} else if (direction.contains(mx, my)) {
tag.whitelist = !tag.whitelist;
tag.saveToFile();
}
saveSelToFile();
PresetsWidget.edit = null;
PresetsWidget.openListBox = !presets.isEmpty()
&& (NEIClientUtils.controlKey() || NEIClientUtils.shiftKey() || !option.contains(mx, my));
ItemList.updateFilter.restart();
}
@Override
protected void drawSlot(int slot, int x, int y, int mx, int my, float frame) {
if (slot >= presets.size()) {
return;
}
final int width = windowBounds().width;
final Rectangle4i direction = new Rectangle4i(x, y, 18, 18);
final Rectangle4i delete = new Rectangle4i(x + width - 18, y, 18, 18);
final Rectangle4i option = new Rectangle4i(x + 18, y, width - 18 - 18, 18);
final PresetTag tag = presets.get(slot);
final int optionState = selected.contains(tag) ? 0 : option.contains(x + mx, y + my) ? 1 : 2;
final int directionState = direction.contains(x + mx, y + my) ? 1 : 2;
final int deleteState = delete.contains(x + mx, y + my) ? 1 : 2;
final String displayName = NEIClientUtils
.cropText(PresetsWidget.fontRenderer, tag.displayName, option.w - 6);
final String dirName = tag.whitelist ? translate("presets.whitelist.label")
: translate("presets.blacklist.label");
// blacklist or whitelist
LayoutManager.getLayoutStyle()
.drawSubsetTag(null, direction.x, direction.y, direction.w, direction.h, directionState, false);
GuiDraw.drawString(dirName, direction.x + 6, direction.y + 5, directionState == 2 ? 0xFFE0E0E0 : 0xFFFFA0);
// option name
LayoutManager.getLayoutStyle()
.drawSubsetTag(null, option.x, option.y, option.w, option.h, optionState, false);
GuiDraw.drawString(displayName, option.x + 3, option.y + 5, optionState == 2 ? 0xFFE0E0E0 : 0xFFFFA0);
// remove icon
LayoutManager.getLayoutStyle()
.drawSubsetTag(null, delete.x, delete.y, delete.w, delete.h, deleteState, false);
GuiDraw.drawString("✕", delete.x + 6, delete.y + 5, deleteState == 2 ? 0xFFE0E0E0 : 0x601010);
}
@Override
public void drawOverlay(float frame) {}
@Override
public void drawBackground(float frame) {
drawRect(x, y, x + width, y + height, 0xFF202020);
}
@Override
public void drawScrollbar(float frame) {
if (hasScrollbar()) {
super.drawScrollbar(frame);
}
}
@Override
public int scrollbarGuideAlignment() {
return 0;
}
protected List<PresetTag> loadSelFromFile(File presetsDir, List<PresetTag> presets) {
final File file = new File(presetsDir, "selected.ini");
List<PresetTag> selected = new ArrayList<>();
if (file.exists()) {
try {
List<String> itemStrings;
try (FileInputStream input = new FileInputStream(file)) {
NEIClientConfig.logger.info("Loading presets selected from file {}", file);
itemStrings = IOUtils.readLines(input, "UTF-8");
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load presets selected from file {}", file, e);
return selected;
}
final HashMap<String, PresetTag> map = new HashMap<>();
for (PresetTag tag : presets) {
map.put(tag.filename, tag);
}
for (String filename : itemStrings) {
if (map.containsKey(filename)) {
selected.add(map.get(filename));
}
}
} catch (Throwable th) {
NEIClientConfig.logger.error("Failed to load presets selected from file", file);
}
}
return selected;
}
public void saveSelToFile() {
final File file = new File(presetsDir, "selected.ini");
final List<String> list = new ArrayList<>();
for (final PresetTag tag : selected) {
list.add(tag.filename);
}
try (FileOutputStream output = new FileOutputStream(file)) {
IOUtils.writeLines(list, "\n", output, "UTF-8");
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save presets selected list to file {}", file, e);
}
}
}
protected static class MouseSelection {
public int startX = -1;
public int startY = -1;
public int startIndex = -1;
public int endIndex = -1;
public HashSet<ItemStack> items = new HashSet<>();
public boolean append = true;
public MouseSelection(int slotIndex, boolean append) {
final ItemsGrid grid = ItemPanels.itemPanel.getGrid();
final Rectangle4i rec = grid.getItemRect(slotIndex);
this.append = append;
endIndex = slotIndex;
startIndex = slotIndex;
startX = rec.x;
startY = rec.y;
}
}
protected static final FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer;
protected static SubsetListBox listbox = new SubsetListBox();
protected static File presetsDir;
protected static boolean openListBox = false;
protected static PresetTag edit;
protected long lastclicktime;
protected static MouseSelection mouseSelection;
protected static final Button dropdown = new Button() {
public boolean onButtonPress(boolean rightclick) {
if (!rightclick) {
openListBox = !openListBox;
return true;
}
return false;
}
@Override
public String getRenderLabel() {
return "...";
}
};
protected static final Label selectedValue = new Label("", false) {
@Override
public void draw(int mousex, int mousey) {
final String text = NEIClientUtils.cropText(fontRenderer, this.text, w);
if (text.equals(this.text)) {
GuiDraw.drawString(text, x + w - fontRenderer.getStringWidth(text), y + (h - 8) / 2, colour);
} else {
GuiDraw.drawString(text, x, y + (h - 8) / 2, colour);
}
}
@Override
public List<String> handleTooltip(int mx, int my, List<String> tooltip) {
if (contains(mx, my) && listbox.getSelected().size() <= 1) {
tooltip.add(translate("presets.label.tooltip"));
}
return tooltip;
}
};
protected static final TextField selectedDisplayName = new TextField("") {
public void onTextChange(String oldText) {
if (edit != null) {
edit.displayName = text();
}
}
@Override
public void draw(int mousex, int mousey) {
super.draw(mousex, mousey);
if (text().isEmpty()) {
GuiDraw.drawGradientRect(x - 1, y - 1, 1, h + 2, 0xFFcc3300, 0xFFcc3300); // Left
GuiDraw.drawGradientRect(x - 1, y - 1, w + 2, 1, 0xFFcc3300, 0xFFcc3300); // Top
GuiDraw.drawGradientRect(x + w, y - 1, 1, h + 2, 0xFFcc3300, 0xFFcc3300); // Left
GuiDraw.drawGradientRect(x - 1, y + h, w + 2, 1, 0xFFcc3300, 0xFFcc3300); // Bottom
}
}
@Override
public List<String> handleTooltip(int mx, int my, List<String> tooltip) {
if (contains(mx, my) && listbox.getSelected().size() <= 1) {
tooltip.add(translate("presets.textfield.tooltip.1"));
tooltip.add(translate("presets.textfield.tooltip.2"));
}
return tooltip;
}
};
protected static final Button selectedState = new Button("B") {
public boolean onButtonPress(boolean rightclick) {
if (!rightclick && edit != null) {
edit.whitelist = !edit.whitelist;
return true;
}
return false;
}
@Override
public String getRenderLabel() {
return edit != null && edit.whitelist ? translate("presets.whitelist.label")
: translate("presets.blacklist.label");
}
@Override
public void addTooltips(List<String> tooltip) {
if (edit != null) {
tooltip.add(
edit.whitelist ? translate("presets.whitelist.tooltip")
: translate("presets.blacklist.tooltip"));
}
}
};
protected static void setEditedTag(final PresetTag tag) {
edit = tag;
openListBox = false;
selectedDisplayName.setText(tag != null ? tag.displayName : "");
ItemList.updateFilter.restart();
}
public static void addTag(final PresetTag tag) {
addTag(tag, false);
}
public static void addTag(final PresetTag tag, boolean sel) {
listbox.addTag(tag, sel);
}
public static boolean inEditMode() {
return edit != null;
}
public static boolean isHidden(final ItemStack item) {
if (edit != null) {
if (mouseSelection != null && mouseSelection.items.contains(item)) {
return mouseSelection.append != edit.whitelist;
}
return !edit.matches(item);
}
if (!listbox.getSelected().isEmpty()) {
final List<PresetTag> selected = listbox.getSelected();
for (int idx = 0; idx < selected.size(); idx++) {
if (!selected.get(idx).matches(item)) {
return true;
}
}
}
return false;
}
public static void setHidden(final ItemStack stack, final boolean append) {
if (edit == null) {
return;
}
if (NEIClientUtils.shiftKey()) {
final ArrayList<ItemStack> items = ItemPanels.itemPanel.getItems();
for (int i = 0; i < items.size(); i++) {
if (stack.getItem().equals(items.get(i).getItem())) {
hideItem(items.get(i), append);
}
}
} else if (NEIClientUtils.controlKey()) {
final String modId = getModId(stack);
if (modId == null) {
hideItem(stack, append);
} else {
final ArrayList<ItemStack> items = ItemPanels.itemPanel.getItems();
for (int i = 0; i < items.size(); i++) {
final String mod = getModId(items.get(i));
if (mod != null && mod.equals(modId)) {
hideItem(items.get(i), append);
}
}
}
} else {
hideItem(stack, append);
}
}
protected static void hideItem(final ItemStack stack, boolean append) {
final String guid = StackInfo.getItemStackGUID(stack);
if (append) {
edit.items.add(guid);
} else {
edit.items.remove(guid);
}
}
protected static String getModId(final ItemStack stack) {
try {
return GameRegistry.findUniqueIdentifierFor(stack.getItem()).modId;
} catch (Exception ignored) {}
return null;
}
public static void loadPresets(final String worldPath) {
final File dir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
presetsDir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath + "/presets");
if (!dir.exists()) {
dir.mkdirs();
}
if (!presetsDir.exists()) {
presetsDir.mkdirs();
}
listbox = new SubsetListBox(presetsDir);
edit = null;
openListBox = false;
selectedDisplayName.setText("");
ItemList.updateFilter.restart();
}
@Override
public void draw(int mx, int my) {
if (edit != null) {
selectedState.x = x;
selectedState.y = y;
selectedState.w = selectedState.h = h;
selectedState.draw(mx, my);
selectedDisplayName.y = y;
selectedDisplayName.h = h;
selectedDisplayName.x = selectedState.x + selectedState.w + 1;
selectedDisplayName.w = w - h * 2 - 5;
selectedDisplayName.draw(mx, my);
} else {
final List<PresetTag> selected = listbox.getSelected();
final int size = selected.size();
selectedValue.text = size > 1 ? translate("presets.label.selected", size)
: (size == 1 ? selected.get(0).displayName : "");
selectedValue.y = y;
selectedValue.h = h;
selectedValue.w = w - h - 4;
selectedValue.x = x;
selectedValue.draw(mx, my);
}
dropdown.y = y;
dropdown.w = dropdown.h = h;
dropdown.x = x + w - dropdown.w;
dropdown.state = edit != null || listbox.getNumSlots() == 0 ? 2 : 0;
dropdown.draw(mx, my);
if (openListBox) {
final int scrollbarWidth = listbox.hasScrollbar() ? listbox.scrollbarDim().width : 0;
listbox.setSize(
x,
y + h + 1,
w,
Math.min(((LayoutManager.searchField.y - h - y) / 18) * 18, listbox.contentHeight()));
listbox.setMargins(0, 0, scrollbarWidth, 0);
listbox.draw(mx, my, 0);
}
}
@Override
public boolean contains(int px, int py) {
return super.contains(px, py) || openListBox && listbox.contains(px, py);
}
@Override
public boolean handleClick(int mx, int my, int button) {
if (openListBox && listbox.contains(mx, my)) {
listbox.mouseClicked(mx, my, button);
return true;
}
if (edit != null) {
if (selectedState.contains(mx, my)) {
selectedState.handleClick(mx, my, button);
return true;
}
if (selectedDisplayName.contains(mx, my)) {
selectedDisplayName.handleClick(mx, my, button);
return true;
}
} else {
if (button == 0 && dropdown.contains(mx, my)) {
openListBox = !openListBox;
return true;
}
openListBox = false;
if (button == 0 && selectedValue.contains(mx, my)) {
if (System.currentTimeMillis() - lastclicktime < 400) { // double click
final List<PresetTag> selected = listbox.getSelected();
final int size = selected.size();
if (size <= 1) {
setEditedTag(size == 1 ? selected.get(0).copy() : new PresetTag(""));
}
}
lastclicktime = System.currentTimeMillis();
}
}
return contains(mx, my);
}
@Override
public boolean handleClickExt(int mx, int my, int button) {
if (edit != null && mouseSelection == null) {
ItemPanelSlot slot = ItemPanels.itemPanel.getSlotMouseOver(mx, my);
if (slot != null && button != 2) {
mouseSelection = new MouseSelection(slot.slotIndex, button == 0);
return true;
}
}
return false;
}
@Override
public boolean handleKeyPress(int keyID, char keyChar) {
if (keyID == Keyboard.KEY_ESCAPE) {
openListBox = false;
}
if (edit == null) {
return false;
}
if (selectedDisplayName.focused() && (keyID == Keyboard.KEY_RETURN || keyID == Keyboard.KEY_NUMPADENTER)
&& !selectedDisplayName.text().isEmpty()) {
selectedDisplayName.handleKeyPress(keyID, keyChar);
selectedDisplayName.setFocus(false);
listbox.replaceSeleted(edit);
setEditedTag(null);
return true;
} else if (selectedDisplayName.focused()) {
return selectedDisplayName.handleKeyPress(keyID, keyChar);
} else if (keyID == Keyboard.KEY_ESCAPE && !(NEIClientUtils.mc().currentScreen instanceof GuiRecipe)) {
setEditedTag(null);
return true;
}
return false;
}
@Override
public void mouseDragged(int mx, int my, int button, long heldTime) {
if (openListBox) {
listbox.mouseDragged(mx, my, button, heldTime);
}
if (edit != null && button != 2 && mouseSelection != null) {
final ItemPanelSlot slot = ItemPanels.itemPanel.getSlotMouseOver(mx, my);
if (slot != null && slot.slotIndex != mouseSelection.endIndex) {
final ItemsGrid grid = ItemPanels.itemPanel.getGrid();
mouseSelection.endIndex = slot.slotIndex;
mouseSelection.items.clear();
final Rectangle4i rec = grid.getItemRect(slot.slotIndex);
final Rectangle4i sel = new Rectangle4i(
Math.min(rec.x, mouseSelection.startX),
Math.min(rec.y, mouseSelection.startY),
Math.max(rec.x, mouseSelection.startX) - Math.min(rec.x, mouseSelection.startX),
Math.max(rec.y, mouseSelection.startY) - Math.min(rec.y, mouseSelection.startY));
for (int x = sel.x; x <= sel.x + sel.w; x += ItemsGrid.SLOT_SIZE) {
for (int y = sel.y; y <= sel.y + sel.h; y += ItemsGrid.SLOT_SIZE) {
ItemStack stack = ItemPanels.itemPanel.getStackMouseOver(x, y);
if (stack != null) {
mouseSelection.items.add(stack);
}
}
}
}
}
}
@Override
public void mouseUp(int mx, int my, int button) {
if (openListBox) {
listbox.mouseMovedOrUp(mx, my, button);
}
if (edit != null && mouseSelection != null) {
ItemPanelSlot hoverSlot = ItemPanels.itemPanel.getSlotMouseOver(mx, my);
if (hoverSlot != null && hoverSlot.slotIndex == mouseSelection.startIndex) {
setHidden(hoverSlot.item, button == 0);
} else if (!mouseSelection.items.isEmpty()) {
for (ItemStack stack : mouseSelection.items) {
hideItem(stack, mouseSelection.append);
}
}
mouseSelection = null;
}
}
@Override
public boolean onMouseWheel(int i, int mx, int my) {
if (openListBox && listbox.hasScrollbar() && listbox.contains(mx, my)) {
listbox.scroll(-i);
return true;
}
return false;
}
@Override
public void onGuiClick(int mx, int my) {
if (!contains(mx, my)) {
openListBox = false;
}
selectedDisplayName.onGuiClick(mx, my);
}
@Override
public List<String> handleTooltip(int mx, int my, List<String> tooltip) {
if (edit != null) {
if (selectedState.contains(mx, my)) {
return selectedState.handleTooltip(mx, my, tooltip);
}
if (selectedDisplayName.contains(mx, my)) {
return selectedDisplayName.handleTooltip(mx, my, tooltip);
}
} else {
if (selectedValue.contains(mx, my)) {
return selectedValue.handleTooltip(mx, my, tooltip);
}
}
return tooltip;
}
public static boolean matches(ItemStack stack) {
if (edit != null) {
return true;
}
final List<PresetTag> selected = listbox.getSelected();
for (int idx = 0; idx < selected.size(); idx++) {
if (!selected.get(idx).matches(stack)) {
return false;
}
}
return true;
}
}
@@ -0,0 +1,86 @@
package codechicken.nei;
import net.minecraft.util.EnumChatFormatting;
import codechicken.nei.SearchField.GuiSearchField;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.util.TextHistory;
public abstract class RecipeSearchField extends TextField {
private static final TextHistory history = new TextHistory();
public RecipeSearchField(String ident) {
super(ident);
this.field.setVisible(false);
}
@Override
protected void initInternalTextField() {
field = new GuiSearchField();
field.setMaxStringLength(maxSearchLength);
field.setCursorPositionZero();
}
public boolean isVisible() {
return this.field.getVisible();
}
public void setVisible(boolean visible) {
this.field.setVisible(visible);
}
protected abstract boolean noResults();
@Override
public int getTextColour() {
if (!text().isEmpty() && !noResults()) {
return focused() ? 0xFFcc3300 : 0xFF993300;
} else {
return focused() ? 0xFFE0E0E0 : 0xFF909090;
}
}
@Override
public void lastKeyTyped(int keyID, char keyChar) {
if (focused() && NEIClientConfig.isKeyHashDown("gui.getprevioussearch")) {
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
}
if (focused() && NEIClientConfig.isKeyHashDown("gui.getnextsearch")) {
handleNavigateHistory(TextHistory.Direction.NEXT);
}
}
@Override
public String filterText(String s) {
return EnumChatFormatting.getTextWithoutFormattingCodes(s);
}
public ItemFilter getFilter() {
return ((GuiSearchField) field).getFilter();
}
@Override
public void setFocus(boolean focus) {
final boolean previousFocus = field.isFocused();
if (previousFocus != focus) {
history.add(text());
}
super.setFocus(focus);
}
private boolean handleNavigateHistory(TextHistory.Direction direction) {
if (focused()) {
return history.get(direction, text()).map(newText -> {
setText(newText);
return true;
}).orElse(false);
}
return false;
}
}
+206 -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,98 @@ 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));
}
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 +144,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 +154,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 +193,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 +202,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 +215,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 +230,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.isFluidContainer(stack) ? null : StackInfo.getFluid(stack);
String displayName;
if (fluidStack != null) {
displayName = fluidStack.getLocalizedName();
} else {
displayName = stack.getDisplayName();
}
return getEscapedSearchText(displayName);
}
public static String getEscapedSearchText(String text) {
text = EnumChatFormatting.getTextWithoutFormattingCodes(text);
switch (NEIClientConfig.getIntSetting("inventory.search.patternMode")) {
case 1:
text = text.replaceAll("[\\?|\\*]", "\\\\$0");
break;
case 2:
text = text.replaceAll("[{}()\\[\\].+*?^$\\\\|]", "\\\\$0");
break;
default:
break;
}
if (text.contains(" ") && NEIClientConfig.getBooleanSetting("inventory.search.quoteDropItemName")) {
text = "\"" + text + "\"";
}
return text;
}
@Override
public ItemFilter getFilter() {
String s_filter = text().toLowerCase();
List<ItemFilter> primary = new LinkedList<>();
List<ItemFilter> secondary = new LinkedList<>();
for (ISearchProvider p : searchProviders) {
ItemFilter filter = p.getFilter(s_filter);
if (filter != null) (p.isPrimary() ? primary : secondary).add(filter);
if (field.getText().isEmpty() && NEIClientConfig.hideItemsUntilSearching()) {
return new NothingItemFilter();
}
if (!primary.isEmpty()) return new AnyMultiItemFilter(primary);
if (!secondary.isEmpty()) return new AnyMultiItemFilter(secondary);
return new EverythingItemFilter();
return ((GuiSearchField) field).getFilter();
}
public static ItemFilter getFilter(String filterText) {
return SearchField.searchParser.getFilter(filterText);
}
@Override
@@ -0,0 +1,66 @@
package codechicken.nei;
import java.util.List;
import java.util.StringJoiner;
import net.minecraft.util.EnumChatFormatting;
import codechicken.nei.FormattedTextField.TextFormatter;
import codechicken.nei.SearchTokenParser.SearchToken;
public class SearchTextFormatter implements TextFormatter {
protected final SearchTokenParser searchParser;
public SearchTextFormatter(SearchTokenParser searchParser) {
this.searchParser = searchParser;
}
public String format(String text) {
final String[] parts = (text + "| ").split("\\|");
StringJoiner formattedText = new StringJoiner(EnumChatFormatting.GRAY + "|");
for (int i = 0; i < parts.length - 1; i++) {
final String filterText = parts[i];
final List<SearchToken> tokens = searchParser.splitSearchText(filterText);
StringBuilder formattedPart = new StringBuilder();
int startIndex = 0;
for (SearchToken token : tokens) {
formattedPart.append(filterText.substring(startIndex, token.start));
EnumChatFormatting tokenColor = EnumChatFormatting.RESET;
if (token.firstChar != null) {
tokenColor = searchParser.getProvider(token.firstChar).getHighlightedColor();
}
if (token.ignore) {
formattedPart.append(EnumChatFormatting.BLUE + "-");
}
if (token.firstChar != null) {
formattedPart.append(tokenColor + String.valueOf(token.firstChar));
}
if (token.quotes) {
formattedPart.append(EnumChatFormatting.GOLD + "\"");
}
if (!token.rawText.isEmpty()) {
formattedPart.append(tokenColor + token.rawText);
}
if (token.quotes) {
formattedPart.append(EnumChatFormatting.GOLD + "\"");
}
startIndex = token.end;
}
formattedPart.append(filterText.substring(startIndex, filterText.length()));
formattedText.add(formattedPart);
}
return formattedText.toString();
}
}
@@ -0,0 +1,309 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.Language;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import codechicken.nei.ItemList.AllMultiItemFilter;
import codechicken.nei.ItemList.AnyMultiItemFilter;
import codechicken.nei.ItemList.EverythingItemFilter;
import codechicken.nei.ItemList.NegatedItemFilter;
import codechicken.nei.ItemList.NothingItemFilter;
import codechicken.nei.api.ItemFilter;
public class SearchTokenParser {
public enum SearchMode {
ALWAYS,
PREFIX,
NEVER;
public static SearchMode fromInt(int value) {
return switch (value) {
case 0 -> ALWAYS;
case 1 -> PREFIX;
default -> NEVER;
};
}
}
public static class SearchToken {
public boolean ignore = false;
public boolean quotes = false;
public Character firstChar = null;
public String[] words;
public String rawText = "";
public int start = 0;
public int end = 0;
}
public static interface ISearchParserProvider {
public ItemFilter getFilter(String searchText);
public static List<Language> getAllLanguages() {
return new ArrayList<>(Minecraft.getMinecraft().getLanguageManager().getLanguages());
}
default List<Language> getMatchingLanguages() {
return getAllLanguages();
}
public char getPrefix();
public EnumChatFormatting getHighlightedColor();
public SearchMode getSearchMode();
}
private static class ProvidersCache {
public String languageCode = null;
public List<ISearchParserProvider> providers = new ArrayList<>();
public void clear() {
this.languageCode = null;
this.providers.clear();
}
}
private static class IsRegisteredItemFilter implements ItemFilter {
public ItemFilter filter;
public IsRegisteredItemFilter(ItemFilter filter) {
this.filter = filter;
}
@Override
public boolean matches(ItemStack item) {
return item != null && item.getItem() != null
&& item.getItem().delegate.name() != null
&& this.filter.matches(item);
}
}
protected final LRUCache<String, ItemFilter> filtersCache = new LRUCache<>(20);
protected final List<ISearchParserProvider> searchProviders;
protected final ProvidersCache providersCache = new ProvidersCache();
protected final Map<Character, Character> prefixRedefinitions = new HashMap<>();
public SearchTokenParser(List<ISearchParserProvider> searchProviders) {
this.searchProviders = searchProviders;
}
public SearchTokenParser() {
this(new ArrayList<>());
}
public void addProvider(ISearchParserProvider provider) {
this.searchProviders.add(provider);
this.providersCache.clear();
this.filtersCache.clear();
}
public void clearCache() {
this.filtersCache.clear();
}
protected List<ISearchParserProvider> getProviders() {
Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage();
if (!currentLanguage.getLanguageCode().equals(providersCache.languageCode)) {
Map<Character, ISearchParserProvider> providers = new HashMap<>();
for (int index = this.searchProviders.size() - 1; index >= 0; index--) {
ISearchParserProvider provider = this.searchProviders.get(index);
if (!providers.containsKey(provider.getPrefix())
&& provider.getMatchingLanguages().contains(currentLanguage)) {
providers.put(provider.getPrefix(), provider);
}
}
providersCache.providers = new ArrayList<>(providers.values());
providersCache.languageCode = currentLanguage.getLanguageCode();
}
return providersCache.providers;
}
public ISearchParserProvider getProvider(char ch) {
return getProviders().stream()
.filter(
provider -> provider.getSearchMode() == SearchMode.PREFIX
&& getRedefinedPrefix(provider.getPrefix()) == ch)
.findFirst().orElse(null);
}
public synchronized ItemFilter getFilter(String filterText) {
filterText = EnumChatFormatting.getTextWithoutFormattingCodes(filterText).toLowerCase();
return this.filtersCache.computeIfAbsent(filterText, text -> {
final String[] parts = text.split("\\|");
final List<ItemFilter> searchTokens = Arrays.stream(parts).map(this::parseSearchText).filter(s -> s != null)
.collect(Collectors.toCollection(ArrayList::new));
if (searchTokens.isEmpty()) {
return new EverythingItemFilter();
} else if (searchTokens.size() == 1) {
return new IsRegisteredItemFilter(searchTokens.get(0));
} else {
return new IsRegisteredItemFilter(new AnyMultiItemFilter(searchTokens));
}
});
}
public List<SearchToken> splitSearchText(String filterText) {
if (filterText.isEmpty()) {
return Collections.emptyList();
}
final List<SearchToken> tokens = new ArrayList<>();
final String prefixes = getPrefixes();
final int spaceMode = NEIClientConfig.getIntSetting("inventory.search.spaceMode");
// The regular expression first tries to match a string that starts with a space or the beginning of the string,
// followed by a sequence of characters that do not contain special characters -"@#$%&, and ends with a space
// and the characters -"@#$%& or the end of the string.
final String patternPart1 = "(?<tokenA>(^|\\s+)(?:[^" + Pattern.quote(" -\"" + prefixes)
+ "]).+?(?=\\s+["
+ Pattern.quote("-\"" + prefixes)
+ "]|$))";
// If the first condition is not met, it tries to match a sequence of - characters, followed by @#$%&
// characters, then either a quoted string or non-space characters.
final String patternPart2 = "((?<ignore>-*)(?<firstChar>[" + Pattern.quote(prefixes)
+ "]*)(?<tokenB>\\\".*?(?:\\\"|$)|\\S+\\s*))";
final Pattern pattern = Pattern.compile(spaceMode == 0 ? patternPart2 : (patternPart1 + "|" + patternPart2));
final Matcher filterMatcher = pattern.matcher(filterText);
while (filterMatcher.find()) {
String firstChar = filterMatcher.group("firstChar");
SearchToken token = new SearchToken();
token.start = filterMatcher.start();
token.end = filterMatcher.end();
token.ignore = "-".equals(filterMatcher.group("ignore"));
token.rawText = spaceMode == 0 ? null : filterMatcher.group("tokenA");
if (firstChar != null && !firstChar.isEmpty()) {
token.firstChar = firstChar.charAt(0);
}
if (token.rawText == null) { // spaceMode == 0
token.rawText = filterMatcher.group("tokenB");
token.quotes = token.rawText.length() > 1 && token.rawText.startsWith("\"")
&& token.rawText.endsWith("\"");
if (token.quotes) {
token.rawText = token.rawText.substring(1, token.rawText.length() - 1);
}
token.words = new String[] { token.rawText.trim() };
} else if (spaceMode == 2) {
token.words = token.rawText.trim().split("\\s+");
} else {
token.words = new String[] { token.rawText.trim() };
}
tokens.add(token);
}
return tokens;
}
private String getPrefixes() {
StringBuilder prefixes = new StringBuilder().append('\0');
for (ISearchParserProvider provider : getProviders()) {
if (provider.getSearchMode() == SearchMode.PREFIX) {
prefixes.append(getRedefinedPrefix(provider.getPrefix()));
}
}
return prefixes.toString();
}
public char getRedefinedPrefix(char prefix) {
return this.prefixRedefinitions.getOrDefault(prefix, prefix);
}
private ItemFilter parseSearchText(String filterText) {
if (filterText.isEmpty()) {
return null;
}
final AllMultiItemFilter searchTokens = new AllMultiItemFilter();
final List<SearchToken> tokens = splitSearchText(filterText);
for (SearchToken token : tokens) {
if (!token.rawText.isEmpty()) {
ItemFilter result = parseToken(token);
if (token.ignore) {
searchTokens.filters.add(new NegatedItemFilter(result));
} else {
searchTokens.filters.add(result);
}
} else if (!token.ignore) {
searchTokens.filters.add(new NothingItemFilter());
}
}
return searchTokens;
}
private ItemFilter parseToken(SearchToken token) {
final ISearchParserProvider provider = token.firstChar == null ? null : this.getProvider(token.firstChar);
if (provider == null || provider.getSearchMode() == SearchMode.NEVER) {
final List<ItemFilter> filters = new ArrayList<>();
for (ISearchParserProvider _provider : getProviders()) {
if (_provider.getSearchMode() == SearchMode.ALWAYS) {
AllMultiItemFilter filter = generateFilters(_provider, token.words);
if (!filter.filters.isEmpty()) {
filters.add(filter);
}
}
}
return filters.isEmpty() ? new NothingItemFilter() : new AnyMultiItemFilter(filters);
} else {
return generateFilters(provider, token.words);
}
}
private AllMultiItemFilter generateFilters(ISearchParserProvider provider, String[] words) {
final AllMultiItemFilter filters = new AllMultiItemFilter();
for (String work : words) {
final ItemFilter filter = provider.getFilter(work);
if (filter != null) {
filters.filters.add(filter);
}
}
return filters;
}
}
@@ -64,7 +64,6 @@ public class SpawnerRenderer implements IItemRenderer {
BossStatus.hasColorModifier = bossHasColorModifier;
}
@SuppressWarnings("incomplete-switch")
@Override
public void renderItem(ItemRenderType type, ItemStack item, Object... data) {
switch (type) {
@@ -75,6 +74,8 @@ public class SpawnerRenderer implements IItemRenderer {
case ENTITY:
renderInventoryItem((RenderBlocks) data[0], item);
break;
default:
break;
}
}
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -9,7 +9,7 @@ public abstract class TextField extends Widget {
protected GuiTextField field;
private static final int maxSearchLength = 256;
protected static final int maxSearchLength = 256;
public boolean centered;
public String identifier;
@@ -6,9 +6,9 @@ import cpw.mods.fml.common.FMLCommonHandler;
public class ThreadOperationTimer extends Thread {
@SuppressWarnings("serial")
public static class TimeoutException extends RuntimeException {
private static final long serialVersionUID = -8621458005263888185L;
public final Object operation;
public TimeoutException(String msg, Object op) {
@@ -15,10 +15,6 @@ public class VisiblityData {
* Subset dropdown
*/
public boolean showSubsetDropdown = true;
/**
* Presets dropdown
*/
public boolean showPresetsDropdown = true;
/**
* Item and search section
*/
@@ -44,7 +40,6 @@ public class VisiblityData {
public void translateDependancies() {
if (!showNEI) showWidgets = false;
if (!showWidgets) showItemSection = showUtilityButtons = false;
if (!showItemSection)
showBookmarkPanel = showSubsetDropdown = showPresetsDropdown = showSearchSection = showItemPanel = false;
if (!showItemSection) showBookmarkPanel = showSubsetDropdown = showSearchSection = showItemPanel = false;
}
}
@@ -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 {
@@ -24,10 +26,12 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
public static int mobOverlay = 0;
private static byte[] mobSpawnCache;
private static long mobOverlayUpdateTime;
private static String oregenPatternName;
public static void reset() {
mobOverlay = 0;
chunkOverlay = 0;
oregenPatternName = null;
}
@Override
@@ -35,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) {
@@ -195,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;
@@ -221,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) {
@@ -257,90 +268,115 @@ 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) {
int gx1 = (((entity.chunkCoordX < 0 ? entity.chunkCoordX - 3 : entity.chunkCoordX) / 3 * 3) << 4)
- intOffsetX;
int gz1 = (((entity.chunkCoordZ < 0 ? entity.chunkCoordZ - 3 : entity.chunkCoordZ) / 3 * 3) << 4)
- intOffsetZ;
if (entity.chunkCoordX < 0) {
gx1 += 16;
}
if (entity.chunkCoordZ < 0) {
gz1 += 16;
int gx1;
int gz1;
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;
} else {
// gt oregen uses old bugged pattern
gx1 = (((entity.chunkCoordX < 0 ? entity.chunkCoordX - 3 : entity.chunkCoordX) / 3 * 3) << 4)
- intOffsetX;
gz1 = (((entity.chunkCoordZ < 0 ? entity.chunkCoordZ - 3 : entity.chunkCoordZ) / 3 * 3) << 4)
- intOffsetZ;
if (entity.chunkCoordX < 0) {
gx1 += 16;
}
if (entity.chunkCoordZ < 0) {
gz1 += 16;
}
}
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());
}
+45 -18
View File
@@ -14,6 +14,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 +25,16 @@ import codechicken.nei.NEIClientConfig;
import codechicken.nei.OffsetPositioner;
import codechicken.nei.SearchField;
import codechicken.nei.SearchField.ISearchProvider;
import codechicken.nei.SearchTokenParser.ISearchParserProvider;
import codechicken.nei.SubsetWidget;
import codechicken.nei.SubsetWidget.SubsetTag;
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.config.Option;
import codechicken.nei.config.OptionKeyBind;
import codechicken.nei.recipe.CatalystInfo;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.GuiUsageRecipe;
import codechicken.nei.recipe.ICraftingHandler;
import codechicken.nei.recipe.IRecipeHandler;
@@ -38,6 +42,7 @@ import codechicken.nei.recipe.IUsageHandler;
import codechicken.nei.recipe.RecipeCatalysts;
import codechicken.nei.recipe.RecipeInfo;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.ItemStackFilterParser;
/**
* This is the main class that handles item property configuration. WARNING: DO NOT access this class until the world
@@ -147,6 +152,14 @@ public class API {
}
}
public static void hideItem(String rule) {
ItemFilter filter = ItemStackFilterParser.parse(rule);
if (filter != null) {
ItemInfo.hiddenItemsRules.filters.add(filter);
LayoutManager.markItemsDirty();
}
}
/**
* Add or replace the name normally shown on the item tooltip
*/
@@ -159,7 +172,7 @@ public class API {
/**
* Adds an item to the item panel. Any items added using this function will override the default search pattern.
*
*
* @param item an item with data
*/
public static void addItemListEntry(ItemStack item) {
@@ -182,7 +195,7 @@ public class API {
/**
* Add a custom KeyBinding to be configured in the Controls menu.
*
*
* @param ident An identifier for your key, eg "shoot"
* @param defaultKey The default value, commonly obtained from {@link Keyboard}
*/
@@ -194,7 +207,7 @@ public class API {
/**
* Add a custom KeyBinding to be configured in the Controls menu.
*
*
* @param ident An identifier for your key, eg "shoot"
* @param defaultKey The default value, commonly obtained from {@link Keyboard}
*/
@@ -209,7 +222,7 @@ public class API {
/**
* Add a new Layout Style for the NEI interface
*
*
* @param styleID The Unique ID to be used for storing your style in the config and cycling through avaliable styles
* @param style The style to add.
*/
@@ -219,7 +232,7 @@ public class API {
/**
* Registers a new Infinite Item Handler.
*
*
* @param handler The handler to be registered.
*/
public static void addInfiniteItemHandler(IInfiniteItemHandler handler) {
@@ -228,7 +241,7 @@ public class API {
/**
* Registers a new Infinite Item Handler.
*
*
* @param block The block to handle, null for all.
* @param handler The handler to be registered.
*/
@@ -238,7 +251,7 @@ public class API {
/**
* Tells NEI not to perform any Fast Transfer operations on slots of a particular class
*
*
* @param slotClass The class of slot to be exempted
*/
public static void addFastTransferExemptSlot(Class<? extends Slot> slotClass) {
@@ -247,7 +260,7 @@ public class API {
/**
* Register a new text handler for the block highlight tooltip with a layout specification (HEADER, BODY or FOOTER).
*
*
* @param handler The handler to be registered.
* @param layout A HUDAugmenterRegistry.Layout entry. HEADER is displayed before BODY which is displayed before
* FOOTER.
@@ -258,16 +271,22 @@ public class API {
/**
* Register a mode handler for overriding NEI recipe/utility/cheat mode settings.
*
*
* @param handler The handler to be registered.
*/
public static void registerModeHandler(INEIModeHandler handler) {
NEIInfo.modeHandlers.add(handler);
}
public static void addRecipeFilter(IRecipeFilterProvider filterProvider) {
synchronized (GuiRecipe.recipeFilterers) {
GuiRecipe.recipeFilterers.add(filterProvider);
}
}
/**
* Register a filter provider for the item panel.
*
*
* @param filterProvider The filter provider to be registered.
*/
public static void addItemFilter(ItemFilterProvider filterProvider) {
@@ -278,7 +297,7 @@ public class API {
/**
* Adds a new tag to the item subset dropdown.
*
*
* @param name The fully qualified name, Eg Blocks.MobSpawners. NOT case sensitive
* @param filter A filter for matching items that fit in this subset
*/
@@ -288,7 +307,7 @@ public class API {
/**
* Adds a new tag to the item subset dropdown.
*
*
* @param name The fully qualified name, Eg Blocks.MobSpawners. NOT case sensitive
* @param items An iterable of itemstacks to be added as a subset
*/
@@ -305,16 +324,19 @@ public class API {
SubsetWidget.addTag(tag);
}
@Deprecated
public static void addSearchProvider(ISearchProvider provider) {}
/**
* Adds a new search provider to the search field
*/
public static void addSearchProvider(ISearchProvider provider) {
SearchField.searchProviders.add(provider);
public static void addSearchProvider(ISearchParserProvider provider) {
SearchField.searchParser.addProvider(provider);
}
/**
* Adds a new sorting option to the item panel sort menu
*
*
* @param name A unique id for this sort option. Will be used in the config for saving and translated in the options
* gui. Note that if the translation key name.tip exists, it will be used for a tooltip
*/
@@ -325,7 +347,7 @@ public class API {
/**
* Adds an additional item list entry for an item, sorted after the rest of the items are found through the normal
* process
*
*
* @param item The item to add the variant for
* @param variant The stack to appear in the item panel
*/
@@ -344,7 +366,7 @@ public class API {
* Adds an association between an ingredient and what it can craft. (i.e. Furnace ItemStack -> Smelting and Fuel
* Recipes) Allows players to see what ingredient they need to craft in order to make recipes from a recipe
* category.
*
*
* @param stack the ingredient that can craft recipes (like a furnace or crafting table)
* @param handler the recipe category handled by the ingredient
* @param priority higher priority comes first, default to 0
@@ -365,7 +387,7 @@ public class API {
* Adds an association between an ingredient and what it can craft. (i.e. Furnace ItemStack -> Smelting and Fuel
* Recipes) Allows players to see what ingredient they need to craft in order to make recipes from a recipe
* category.
*
*
* @param stack the ingredient that can craft recipes (like a furnace or crafting table)
* @param handlerID recipe category identifier (see also {@link RecipeCatalysts#getRecipeID(IRecipeHandler)})
* @param priority higher priority comes first, default to 0
@@ -390,6 +412,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;
@@ -13,7 +15,7 @@ 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 +23,26 @@ 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) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glDisable(GL11.GL_DEPTH_TEST);
drawRect(x, y, 16, 16, 0x66555555);
GL11.glPopAttrib();
}
final IStackPositioner positioner;
@@ -0,0 +1,11 @@
package codechicken.nei.api;
import java.util.ArrayList;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
public interface IBookmarkContainerHandler {
void pullBookmarkItemsFromContainer(GuiContainer guiContainer, ArrayList<ItemStack> realItems);
}
@@ -1,10 +1,44 @@
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);
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.toCollection(ArrayList::new));
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);
}
+33 -57
View File
@@ -6,7 +6,6 @@ import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.block.Block;
import net.minecraft.client.resources.I18n;
@@ -44,12 +43,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 +60,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 +83,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 +94,11 @@ public class ItemInfo {
public static final HashMap<Item, String> itemOwners = new HashMap<>();
private static class ItemStackKey {
public final ItemStack stack;
public ItemStackKey(ItemStack stack) {
this.stack = stack;
}
@Override
public int hashCode() {
if (this.stack == null) return 1;
int hashCode = 1;
hashCode = 31 * hashCode + stack.stackSize;
hashCode = 31 * hashCode + Item.getIdFromItem(stack.getItem());
hashCode = 31 * hashCode + stack.getItemDamage();
hashCode = 31 * hashCode + (!stack.hasTagCompound() ? 0 : stack.getTagCompound().hashCode());
return hashCode;
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof ItemStackKey)) return false;
return ItemStack.areItemStacksEqual(this.stack, ((ItemStackKey) o).stack);
}
}
// lookup optimisation
public static final ConcurrentHashMap<ItemStackKey, String> itemSearchNames = new ConcurrentHashMap<>();
public static boolean isHidden(ItemStack stack) {
return hiddenItems.contains(stack);
return hiddenItems.contains(stack) || hiddenItemsRules.matches(stack);
}
@Deprecated
public static boolean isHidden(Item item) {
return hiddenItems.containsAll(item);
}
@@ -154,27 +133,28 @@ public class ItemInfo {
addInfiniteHandlers();
addInputHandlers();
addIDDumps();
addHiddenItemFilter();
addSearchOptimisation();
addSearchProviders();
RecipeItemInputHandler.load();
PresetsList.load();
}
private static void addSearchOptimisation() {
ItemList.loadCallbacks.add(ItemInfo::populateSearchMap);
}
private static void addSearchProviders() {
API.addSearchProvider(
new SearchParserProvider('\0', "default", EnumChatFormatting.RESET, PatternItemFilter::new) {
private static void populateSearchMap() {
/* Create a snapshot of the current keys in the cache */
HashSet<ItemStackKey> oldItems = new HashSet<>(itemSearchNames.keySet());
for (ItemStack stack : ItemList.items) {
/* Populate each entry and remove it from the snapshot */
getSearchName(stack);
oldItems.remove(new ItemStackKey(stack));
}
itemSearchNames.keySet().removeAll(oldItems);
}
@Override
public SearchMode getSearchMode() {
return SearchMode.ALWAYS;
}
private static void addHiddenItemFilter() {
API.addItemFilter(() -> item -> !hiddenItems.contains(item));
});
API.addSearchProvider(
new SearchParserProvider('@', "modName", EnumChatFormatting.LIGHT_PURPLE, ModNameFilter::new));
API.addSearchProvider(
new SearchParserProvider('$', "oreDict", EnumChatFormatting.AQUA, OreDictionaryFilter::new));
API.addSearchProvider(new SearchParserProvider('#', "tooltip", EnumChatFormatting.YELLOW, TooltipFilter::new));
API.addSearchProvider(
new SearchParserProvider('&', "identifier", EnumChatFormatting.GOLD, IdentifierFilter::new));
}
private static void addIDDumps() {
@@ -209,7 +189,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" };
}
@@ -316,7 +296,6 @@ public class ItemInfo {
}
private static void addInputHandlers() {
GuiContainerManager.addInputHandler(new RecipeItemInputHandler());
GuiContainerManager.addInputHandler(new PopupInputHandler());
}
@@ -460,7 +439,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 +494,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,17 +1,27 @@
package codechicken.nei.api;
import static codechicken.lib.gui.GuiDraw.getMousePosition;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary;
import org.lwjgl.input.Mouse;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.ItemPanels;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.recipe.BookmarkRecipeId;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.GuiUsageRecipe;
@@ -20,10 +30,31 @@ public abstract class ShortcutInputHandler {
public static boolean handleKeyEvent(ItemStack stackover) {
if (!NEIClientConfig.isLoaded()) {
return false;
}
if (NEIClientConfig.isKeyHashDown("gui.overlay_hide")) {
return hideOverlayRecipe();
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark_pull_items")) {
return ItemPanels.bookmarkPanel.pullBookmarkItems(ItemPanels.bookmarkPanel.getHoveredGroupId(true), false);
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark_pull_items_ingredients")) {
return ItemPanels.bookmarkPanel.pullBookmarkItems(ItemPanels.bookmarkPanel.getHoveredGroupId(true), true);
}
if (stackover == null && NEIClientConfig.isKeyHashDown("gui.remove_recipe")) {
final int groupId = ItemPanels.bookmarkPanel.getHoveredGroupId(true);
if (groupId != -1) {
ItemPanels.bookmarkPanel.removeGroup(groupId);
return true;
}
}
if (stackover == null) {
return false;
}
@@ -34,6 +65,14 @@ public abstract class ShortcutInputHandler {
return openOverlayRecipe(stackover, false);
}
if (NEIClientConfig.isKeyHashDown("gui.copy_name")) {
return copyItemStackName(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.copy_oredict")) {
return copyItemStackOreDictionary(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.overlay_use")) {
return openOverlayRecipe(stackover, true);
}
@@ -67,9 +106,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);
@@ -91,14 +133,52 @@ public abstract class ShortcutInputHandler {
return false;
}
private static boolean openOverlayRecipe(ItemStack stack, boolean shift) {
private static boolean copyItemStackName(ItemStack stackover) {
Toolkit.getDefaultToolkit().getSystemClipboard()
.setContents(new StringSelection(stackover.getDisplayName()), null);
return true;
}
private static boolean copyItemStackOreDictionary(ItemStack stackover) {
StringBuilder builder = new StringBuilder();
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);
}
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(builder.toString()), null);
return true;
}
private static boolean openOverlayRecipe(ItemStack stackover, boolean shift) {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
if (gui == null || gui instanceof GuiRecipe) {
return false;
}
return GuiCraftingRecipe.openRecipeGui("item", true, shift, stack);
final Point mouseover = getMousePosition();
ItemPanelSlot panelSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
BookmarkRecipeId recipeId = null;
if (panelSlot != null) {
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(panelSlot.slotIndex);
} else {
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(stackover);
}
if (recipeId != null) {
return GuiCraftingRecipe.overlayRecipe(stackover, recipeId, shift);
}
return false;
}
private static boolean saveRecipeInBookmark(ItemStack stack, boolean saveIngredients, boolean saveStackSize) {
@@ -120,4 +200,9 @@ public abstract class ShortcutInputHandler {
return false;
}
public static Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, ItemStack stack) {
return new HashMap<>();
}
}
@@ -6,7 +6,14 @@ import static codechicken.lib.asm.InsnComparator.getControlFlowLabels;
import static codechicken.lib.asm.InsnComparator.matches;
import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static org.objectweb.asm.ClassWriter.COMPUTE_MAXS;
import static org.objectweb.asm.Opcodes.*;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ACC_STATIC;
import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ASM5;
import static org.objectweb.asm.Opcodes.ILOAD;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.Opcodes.IRETURN;
import java.util.Map;
@@ -59,16 +66,6 @@ public class NEITransformer implements IClassTransformer {
"func_149689_a",
"(Lnet/minecraft/world/World;IIILnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;)V"),
asmblocks.get("spawnerPlaced")));
// Make MobSpawnerBaseLogic use getSpawnerWorld when creating new entities
transformer.add(
new MethodReplacer(
new ObfMapping(
"net/minecraft/tileentity/MobSpawnerBaseLogic",
"func_98281_h",
"()Lnet/minecraft/entity/Entity;"),
asmblocks.get("d_spawnerWorld"),
asmblocks.get("spawnerWorld")));
}
// Removes trailing seperators from NBTTagList/Compound.toString because OCD
@@ -1,6 +1,22 @@
package codechicken.nei.asm;
import static org.objectweb.asm.Opcodes.*;
import static org.objectweb.asm.Opcodes.ACC_FINAL;
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static org.objectweb.asm.Opcodes.ACC_STATIC;
import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ASTORE;
import static org.objectweb.asm.Opcodes.ATHROW;
import static org.objectweb.asm.Opcodes.CHECKCAST;
import static org.objectweb.asm.Opcodes.DUP;
import static org.objectweb.asm.Opcodes.GETSTATIC;
import static org.objectweb.asm.Opcodes.GOTO;
import static org.objectweb.asm.Opcodes.IFNONNULL;
import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.MONITORENTER;
import static org.objectweb.asm.Opcodes.MONITOREXIT;
import static org.objectweb.asm.Opcodes.NEW;
import static org.objectweb.asm.Opcodes.PUTSTATIC;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -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);
}
}
}
}
@@ -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,7 +7,6 @@ import java.awt.Rectangle;
import org.lwjgl.input.Keyboard;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
public class OptionKeyBind extends OptionButton {
@@ -122,8 +121,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 NEIClientUtils.getKeyHashName(NEIClientUtils.getMetaHash());
}
return NEIClientUtils.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,51 +1,36 @@
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("test") {
@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());
}
}
@Override
public void setFocus(boolean focus) {
if (!focus && !isValidValue(text())) setText(renderTag().getValue());
focused = focus;
super.setFocus(focus);
}
};
public OptionTextField(String name) {
super(name);
textField.h = 20;
}
@Override
public void onAdded(OptionScrollSlot slot) {
super.onAdded(slot);
}
@Override
@@ -58,11 +43,16 @@ public class OptionTextField extends Option {
return translateN(name);
}
protected int getMaxInputWidth() {
return slot.slotWidth();
}
@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);
}
@@ -86,7 +76,7 @@ public class OptionTextField extends Option {
public List<String> handleTooltip(int mousex, int mousey, List<String> currenttip) {
if (new Rectangle4i(10, 0, textField.x - 10, 20).contains(mousex, mousey)) {
String tip = translateN(name + ".tip");
if (!tip.equals(name + ".tip")) currenttip.add(tip);
if (!tip.equals(namespaced(name + ".tip"))) currenttip.add(tip);
}
return currenttip;
}
@@ -17,6 +17,7 @@ public class OptionToggleButton extends OptionButton {
return renderTag().getBooleanValue();
}
@Override
public String getButtonText() {
return translateN(name + (state() ? ".true" : ".false"));
}
@@ -46,6 +46,8 @@ public class OptionUtilities extends OptionStringSet {
x += 24;
LayoutManager.drawIcon(x + 4, 4, new Image(132, 12, 12, 12));
x += 24;
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
RenderHelper.enableGUIStandardItemLighting();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
ItemStack sword = new ItemStack(Items.diamond_sword);
@@ -55,5 +57,6 @@ public class OptionUtilities extends OptionStringSet {
GuiContainerManager.drawItem(x + 2, 2, new ItemStack(Items.potionitem));
x += 24;
GuiContainerManager.drawItem(x + 2, 2, new ItemStack(Blocks.stone));
GL11.glPopAttrib();
}
}
@@ -10,6 +10,7 @@ public abstract class RegistryDumper<T> extends DataDumper {
super(name);
}
@SuppressWarnings("unchecked")
@Override
public Iterable<String[]> dump(int mode) {
LinkedList<String[]> list = new LinkedList<>();
@@ -0,0 +1,53 @@
package codechicken.nei.config.preset;
import static codechicken.lib.gui.GuiDraw.drawStringC;
import org.lwjgl.opengl.GL11;
import codechicken.nei.Button;
import codechicken.nei.LayoutManager;
public abstract class CheckboxButton extends Button {
protected boolean checked = false;
public CheckboxButton(String s) {
super(s);
}
public void setChecked(boolean checked) {
this.checked = checked;
this.onChange();
}
public boolean isChecked() {
return this.checked;
}
@Override
public void draw(int mousex, int mousey) {
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glColor4f(1, 1, 1, 1);
int tex;
if ((this.state & 0x3) == 2) {
tex = 0;
} else if ((this.state & 0x4) == 0 && contains(mousex, mousey) || (this.state & 0x3) == 1) {
tex = 2;
} else {
tex = 1;
}
int colour = tex == 2 ? 0xffffa0 : tex == 0 ? 0x601010 : 0xe0e0e0;
LayoutManager.drawButtonBackground(x, y, w, h, true, isChecked() ? 0 : tex);
drawStringC(getRenderLabel(), x + w / 2, y + (h - 8) / 2, colour);
}
public boolean onButtonPress(boolean rightclick) {
this.setChecked(!isChecked());
return true;
}
protected abstract void onChange();
}
@@ -0,0 +1,260 @@
package codechicken.nei.config.preset;
import static codechicken.lib.gui.GuiDraw.getStringWidth;
import java.awt.Rectangle;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
import codechicken.core.gui.GuiCCButton;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList;
import codechicken.nei.PresetsList.Preset;
import codechicken.nei.config.GuiOptionPane;
import codechicken.nei.config.Option;
public class GuiPresetList extends GuiOptionPane {
private final Option opt;
protected static final int SLOT_HEIGHT = 24;
protected static final int BUTTON_HEIGHT = 20;
protected GuiCCButton createButton;
protected GuiCCButton toggleButton;
protected int sortingItemIndex = -1;
public GuiPresetList(Option opt) {
this.opt = opt;
this.createButton = new GuiCCButton(0, 2, 0, 16, NEIClientUtils.translate("presets.new"))
.setActionCommand("create");
this.toggleButton = new GuiCCButton(0, 2, 0, 16, NEIClientUtils.translate("presets.toggle"))
.setActionCommand("toggle");
}
@Override
public void initGui() {
super.initGui();
this.createButton.width = getStringWidth(this.createButton.text) + 15;
this.createButton.x = width - this.createButton.width - 15;
this.toggleButton.width = getStringWidth(this.toggleButton.text) + 15;
this.toggleButton.x = width - this.toggleButton.width - 15 - this.createButton.width - 10;
}
@Override
public void addWidgets() {
super.addWidgets();
add(this.createButton);
add(this.toggleButton);
}
@Override
public void actionPerformed(String ident, Object... params) {
super.actionPerformed(ident, params);
if (ident.equals("create")) {
cretePreset();
}
if (ident.equals("toggle")) {
togglePreset();
}
}
@Override
protected void mouseMovedOrUp(int x, int y, int button) {
super.mouseMovedOrUp(x, y, button);
if (sortingItemIndex >= 0) {
PresetsList.savePresets();
} else if (button == 0) {
int slot = getSlotMouseOver(x, y);
if (slot != -1) {
Rectangle w = pane.windowBounds();
int mx = x - w.x;
if (mx <= BUTTON_HEIGHT) {
Preset preset = PresetsList.presets.get(slot);
preset.enabled = !preset.enabled;
PresetsList.savePresets();
} else if (mx >= 26 && mx <= w.width - 26 * 2) {
openPreset(slot);
} else if (mx >= w.width - BUTTON_HEIGHT) {
PresetsList.presets.remove(slot);
PresetsList.savePresets();
}
}
}
sortingItemIndex = -1;
}
@Override
protected void mouseClickMove(int x, int y, int button, long time) {
super.mouseClickMove(x, y, button, time);
if (sortingItemIndex == -1) {
Rectangle w = pane.windowBounds();
int mx = x - w.x;
if (mx >= 26 && mx <= w.width - 26 * 2) {
sortingItemIndex = getSlotMouseOver(x, y);
} else {
sortingItemIndex = -2;
}
} else if (sortingItemIndex >= 0) {
Rectangle w = pane.windowBounds();
if (y >= w.y && y <= w.y + w.height) {
int my = y + pane.scrolledPixels() - w.y;
int slot = my / SLOT_HEIGHT;
if (my % SLOT_HEIGHT < BUTTON_HEIGHT && slot < PresetsList.presets.size()
&& slot != -1
&& slot != sortingItemIndex) {
PresetsList.presets.add(slot, PresetsList.presets.remove(sortingItemIndex));
sortingItemIndex = slot;
}
}
}
}
protected int getSlotMouseOver(int x, int y) {
Rectangle w = pane.windowBounds();
if (x >= w.x && x <= w.x + w.width && y >= w.y && y <= w.y + w.height) {
int my = y + pane.scrolledPixels() - w.y;
int slot = my / SLOT_HEIGHT;
if (my % SLOT_HEIGHT < BUTTON_HEIGHT && slot < PresetsList.presets.size()) {
return slot;
}
}
return -1;
}
protected void cretePreset() {
Minecraft.getMinecraft().displayGuiScreen(new GuiPresetSettings(this, -1));
}
protected void togglePreset() {
boolean enabled = PresetsList.presets.stream().noneMatch(g -> g.enabled);
for (Preset preset : PresetsList.presets) {
preset.enabled = enabled;
}
PresetsList.savePresets();
}
protected void openPreset(int slot) {
Minecraft.getMinecraft().displayGuiScreen(new GuiPresetSettings(this, slot));
}
@Override
public int contentHeight() {
return PresetsList.presets.size() * SLOT_HEIGHT;
}
@Override
public void drawContent(int mx, int my, float frame) {
int scrolled = pane.scrolledPixels();
Rectangle w = pane.windowBounds();
int y = 0;
for (int slot = 0; slot < PresetsList.presets.size(); ++slot) {
if (y + SLOT_HEIGHT > scrolled && y < scrolled + w.height) {
if (sortingItemIndex != slot) {
drawSlot(w, slot, w.x, w.y + y - scrolled, mx, my - y);
}
}
y += SLOT_HEIGHT;
}
if (sortingItemIndex >= 0) {
drawSlot(w, sortingItemIndex, w.x, w.y + my - scrolled - BUTTON_HEIGHT / 2, mx, my - y);
}
}
protected void drawSlot(Rectangle w, int slot, int x, int y, int mx, int my) {
final Rectangle4i delete = new Rectangle4i(x + w.width - BUTTON_HEIGHT, y, BUTTON_HEIGHT, BUTTON_HEIGHT);
final Rectangle4i enabled = new Rectangle4i(x, y, BUTTON_HEIGHT, BUTTON_HEIGHT);
final Rectangle4i option = new Rectangle4i(x + 26, y, w.width - 26 * 2, BUTTON_HEIGHT);
final int enabledState = y + my >= w.y && y + my <= w.y + w.height && enabled.contains(x + mx, y + my) ? 2 : 1;
final int optionState = y + my >= w.y && y + my <= w.y + w.height && option.contains(x + mx, y + my) ? 2 : 1;
final int deleteState = y + my >= w.y && y + my <= w.y + w.height && delete.contains(x + mx, y + my) ? 2 : 1;
final Preset preset = PresetsList.presets.get(slot);
final String displayName = preset.name;
final String modeName;
switch (preset.mode) {
case HIDE:
modeName = EnumChatFormatting.GOLD + NEIClientUtils.translate("presets.mode.hide.char")
+ EnumChatFormatting.RESET;
break;
case REMOVE:
modeName = EnumChatFormatting.RED + NEIClientUtils.translate("presets.mode.remove.char")
+ EnumChatFormatting.RESET;
break;
case GROUP:
modeName = EnumChatFormatting.AQUA + NEIClientUtils.translate("presets.mode.group.char")
+ EnumChatFormatting.RESET;
break;
default:
modeName = "?";
break;
}
// enabled icon
GL11.glColor4f(1, 1, 1, 1);
LayoutManager.drawButtonBackground(
enabled.x,
enabled.y,
enabled.w,
enabled.h,
true,
preset.enabled ? 0 : enabledState);
GuiDraw.drawString("✔", enabled.x + 7, enabled.y + 6, enabledState == 2 ? 0xFFFFFFA0 : 0xFFE0E0E0);
// preset name
GL11.glColor4f(1, 1, 1, 1);
LayoutManager.drawButtonBackground(option.x, option.y, option.w, option.h, true, optionState);
GuiDraw.drawString("⋮⋮", option.x + 4, option.y + 5, optionState == 2 ? 0xFFFFFFA0 : 0xFFE0E0E0);
GuiDraw.drawString(
NEIClientUtils.cropText(this.fontRendererObj, modeName + " " + displayName, option.w - 16),
option.x + 6 + 4,
option.y + 6,
optionState == 2 ? 0xFFFFFFA0 : 0xFFE0E0E0);
// remove icon
GL11.glColor4f(1, 1, 1, 1);
LayoutManager.drawButtonBackground(delete.x, delete.y, delete.w, delete.h, true, deleteState);
GuiDraw.drawString("✕", delete.x + 7, delete.y + 6, deleteState == 2 ? 0xFFFFFFA0 : 0xFFE0E0E0);
}
@Override
public GuiScreen getParentScreen() {
return opt.slot.getGui();
}
@Override
public String getTitle() {
return opt.translateN(opt.name);
}
}
@@ -0,0 +1,228 @@
package codechicken.nei.config.preset;
import java.util.LinkedList;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.Tessellator;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.Rectangle;
import codechicken.core.gui.GuiScreenWidget;
import codechicken.nei.Button;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList;
import codechicken.nei.PresetsList.Preset;
import codechicken.nei.config.OptionScrollPane;
import codechicken.nei.guihook.GuiContainerManager;
public class GuiPresetSettings extends GuiScreenWidget {
protected final Preset preset;
protected final GuiScreen parent;
protected final int slotIndex;
public int marginleft;
public int margintop;
public int marginright;
public int marginbottom;
protected LeftPanel leftPanel;
protected RightPanel rightPanel;
protected Button backButton;
protected Button saveButton;
public GuiPresetSettings(GuiScreen parent, int slotIndex) {
this.parent = parent;
this.setMargins(6, 20, 6, 30);
this.slotIndex = slotIndex;
if (slotIndex == -1) {
preset = new Preset();
} else {
preset = PresetsList.presets.get(slotIndex).copy();
}
leftPanel = new LeftPanel(preset) {
@Override
protected void onItemsChanges() {
leftPanel.grid.restartFilter();
}
};
rightPanel = new RightPanel(preset, slotIndex) {
@Override
protected void onItemsChanges() {
leftPanel.grid.restartFilter();
}
};
backButton = new Button(NEIClientUtils.translate("options.back")) {
public boolean onButtonPress(boolean rightclick) {
Minecraft.getMinecraft().displayGuiScreen(parent);
return true;
}
};
saveButton = new Button(NEIClientUtils.translate("options.save")) {
public boolean onButtonPress(boolean rightclick) {
if (state == 0) {
if (slotIndex == -1) {
PresetsList.presets.add(preset);
} else {
PresetsList.presets.set(slotIndex, preset);
}
PresetsList.savePresets();
Minecraft.getMinecraft().displayGuiScreen(parent);
return true;
}
return false;
}
};
add(this.leftPanel);
add(this.rightPanel);
}
protected void setMargins(int left, int top, int right, int bottom) {
this.marginleft = left;
this.margintop = top;
this.marginright = right;
this.marginbottom = bottom;
}
protected Rectangle windowBounds() {
return new Rectangle(
this.marginleft,
this.margintop,
this.width - this.marginleft - this.marginright,
this.height - this.margintop - this.marginbottom);
}
@Override
public boolean doesGuiPauseGame() {
return true;
}
@Override
public void updateScreen() {
final Rectangle bounds = windowBounds();
final int panelWidth = bounds.getWidth() * 2 / 5;
this.leftPanel.setSize(bounds.getX(), bounds.getY() + 4, panelWidth, bounds.getHeight() - 6);
this.rightPanel.setSize(
bounds.getX() + bounds.getWidth() - panelWidth,
bounds.getY() + 4,
panelWidth,
bounds.getHeight() - 6);
final int w = Math.min(200, width - 40);
backButton.w = w / 2 - 3;
backButton.h = 20;
backButton.x = (width - w) / 2;
backButton.y = height - 25;
saveButton.state = preset.name.isEmpty() || preset.mode == null || preset.items.isEmpty() ? 2 : 0;
saveButton.w = w / 2 - 3;
saveButton.h = 20;
saveButton.x = width / 2 + 3;
saveButton.y = height - 25;
super.updateScreen();
}
@Override
public void resize() {
this.guiLeft = this.guiTop = 0;
}
@Override
public void drawScreen(int mousex, int mousey, float f) {
Rectangle bounds = windowBounds();
drawDefaultBackground();
drawOverlay(bounds.getY(), bounds.getHeight(), width, zLevel);
drawCenteredString(
Minecraft.getMinecraft().fontRenderer,
NEIClientUtils.translate(this.slotIndex == -1 ? "presets.create" : "presets.update"),
width / 2,
6,
-1);
backButton.draw(mousex, mousey);
saveButton.draw(mousex, mousey);
super.drawScreen(mousex, mousey, f);
List<String> tooltip = new LinkedList<>();
tooltip = leftPanel.handleTooltip(mousex, mousey, tooltip);
tooltip = rightPanel.handleTooltip(mousex, mousey, tooltip);
GuiContainerManager.drawPagedTooltip(Minecraft.getMinecraft().fontRenderer, mousex + 12, mousey - 12, tooltip);
}
@Override
protected void mouseClicked(int x, int y, int button) {
super.mouseClicked(x, y, button);
if (backButton.contains(x, y)) {
backButton.handleClick(x, y, button);
}
if (saveButton.contains(x, y)) {
saveButton.handleClick(x, y, button);
}
}
public static void drawOverlay(int y, int height, int screenwidth, float zLevel) {
OptionScrollPane.drawOverlayTex(0, 0, screenwidth, y, zLevel);
OptionScrollPane.drawOverlayTex(0, y + height, screenwidth, screenwidth - y - height, zLevel);
OptionScrollPane.drawOverlayGrad(0, screenwidth, y, y + 4, zLevel);
OptionScrollPane.drawOverlayGrad(0, screenwidth, y + height, y + height - 4, zLevel);
}
public static void drawOverlayTex(int x, int y, int w, int h, float zLevel) {
GL11.glColor4f(1, 1, 1, 1);
Minecraft.getMinecraft().renderEngine.bindTexture(Gui.optionsBackground);
Tessellator t = Tessellator.instance;
t.startDrawingQuads();
t.addVertexWithUV(x, y, zLevel, 0, 0);
t.addVertexWithUV(x, y + h, zLevel, 0, h / 16D);
t.addVertexWithUV(x + w, y + h, zLevel, w / 16D, h / 16D);
t.addVertexWithUV(x + w, y, zLevel, w / 16D, 0);
t.draw();
}
public static void drawOverlayGrad(int x1, int x2, int y1, int y2, float zLevel) {
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glShadeModel(GL11.GL_SMOOTH);
Tessellator t = Tessellator.instance;
t.startDrawingQuads();
t.setColorRGBA_I(0, 255);
t.addVertex(x2, y1, zLevel);
t.addVertex(x1, y1, zLevel);
t.setColorRGBA_I(0, 0);
t.addVertex(x1, y2, zLevel);
t.addVertex(x2, y2, zLevel);
t.draw();
GL11.glDisable(GL11.GL_BLEND);
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_TEXTURE_2D);
}
}
@@ -0,0 +1,336 @@
package codechicken.nei.config.preset;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.core.gui.GuiWidget;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.ItemsGrid;
import codechicken.nei.Label;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList.Preset;
import codechicken.nei.PresetsList.PresetMode;
import codechicken.nei.TextField;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerTooltipHandler;
public class LeftPanel extends GuiWidget {
protected static class MouseSelection {
public int startX = -1;
public int startY = -1;
public int startIndex = -1;
public int endIndex = -1;
public Set<ItemStack> items = new HashSet<>();
public MouseSelection(int slotIndex, Rectangle4i rec) {
endIndex = slotIndex;
startIndex = slotIndex;
startX = rec.x;
startY = rec.y;
}
}
protected static final int INPUT_HEIGHT = 20;
public final PresetItemsGrid grid = new PresetItemsGrid() {
@Override
protected ItemFilter getFilter() {
Set<String> identifiers = preset.items;
return item -> identifiers.contains(Preset.getIdentifier(item));
}
@Override
protected boolean isSelected(ItemStack stack) {
return mouseSelection != null && mouseSelection.items.contains(stack);
}
};
protected Label nameLabel = new Label(NEIClientUtils.translate("presets.name"), false);
protected TextField nameField = new TextField("name") {
@Override
public void onTextChange(String oldText) {
preset.name = text();
}
};
protected Label modeLabel = new Label(NEIClientUtils.translate("presets.mode"), false);
protected CheckboxButton modeHide;
protected CheckboxButton modeRemove;
protected CheckboxButton modeGroup;
protected CheckboxButton enabledButton;
protected final Preset preset;
protected MouseSelection mouseSelection;
public LeftPanel(Preset preset) {
super(1, 0, 2, 2);
this.preset = preset;
nameField.setText(preset.name);
modeHide = new CheckboxButton(NEIClientUtils.translate("presets.mode.hide")) {
@Override
public boolean isChecked() {
return preset.mode == PresetMode.HIDE;
}
@Override
protected void onChange() {
preset.mode = this.checked ? PresetMode.HIDE : null;
}
};
modeRemove = new CheckboxButton(NEIClientUtils.translate("presets.mode.remove")) {
@Override
public boolean isChecked() {
return preset.mode == PresetMode.REMOVE;
}
@Override
protected void onChange() {
preset.mode = this.checked ? PresetMode.REMOVE : null;
}
};
modeGroup = new CheckboxButton(NEIClientUtils.translate("presets.mode.group")) {
@Override
public boolean isChecked() {
return preset.mode == PresetMode.GROUP;
}
@Override
protected void onChange() {
preset.mode = this.checked ? PresetMode.GROUP : null;
}
};
enabledButton = new CheckboxButton(NEIClientUtils.translate("presets.enabled")) {
@Override
public boolean isChecked() {
return preset.enabled;
}
@Override
protected void onChange() {
preset.enabled = this.checked;
}
};
grid.restartFilter();
}
@Override
public void mouseClicked(int x, int y, int button) {
grid.mouseClicked(x, y, button);
if (modeHide.contains(x, y)) {
modeHide.handleClick(x, y, button);
}
if (modeRemove.contains(x, y)) {
modeRemove.handleClick(x, y, button);
}
if (modeGroup.contains(x, y)) {
modeGroup.handleClick(x, y, button);
}
if (enabledButton.contains(x, y)) {
enabledButton.handleClick(x, y, button);
}
if (nameField.contains(x, y)) {
nameField.handleClick(x, y, button);
} else {
nameField.onGuiClick(x, y);
}
if (mouseSelection == null && button == 0) {
ItemPanelSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null) {
mouseSelection = new MouseSelection(slot.slotIndex, grid.getItemRect(slot.slotIndex));
}
}
}
protected void onItemsChanges() {}
@Override
public void mouseMovedOrUp(int x, int y, int button) {
nameField.mouseUp(x, y, button);
if (mouseSelection != null && button == 0) {
ItemPanelSlot hoverSlot = grid.getSlotMouseOver(x, y);
if (hoverSlot != null && hoverSlot.slotIndex == mouseSelection.startIndex) {
preset.items.remove(Preset.getIdentifier(hoverSlot.item));
} else if (!mouseSelection.items.isEmpty()) {
for (ItemStack stack : mouseSelection.items) {
preset.items.remove(Preset.getIdentifier(stack));
}
}
mouseSelection = null;
onItemsChanges();
}
}
@Override
public void mouseDragged(int x, int y, int button, long time) {
nameField.mouseDragged(x, y, button, time);
if (mouseSelection != null && button == 0) {
final ItemPanelSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null && slot.slotIndex != mouseSelection.endIndex) {
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 ix = sel.x; ix <= sel.x + sel.w; ix += ItemsGrid.SLOT_SIZE) {
for (int iy = sel.y; iy <= sel.y + sel.h; iy += ItemsGrid.SLOT_SIZE) {
ItemPanelSlot over = grid.getSlotMouseOver(ix, iy);
if (over != null) {
mouseSelection.items.add(over.item);
}
}
}
}
}
}
@Override
public void update() {
int CHECKBOX_WIDTH = (this.width - 12) / 3;
nameLabel.x = this.x + 2;
nameLabel.y = this.y + 4;
nameLabel.w = this.width;
nameLabel.h = 10;
nameField.x = this.x;
nameField.y = nameLabel.y + nameLabel.h;
nameField.w = this.width - CHECKBOX_WIDTH - 6;
nameField.h = INPUT_HEIGHT;
enabledButton.x = nameField.x + nameField.w + 6;
enabledButton.y = nameField.y;
enabledButton.w = CHECKBOX_WIDTH;
enabledButton.h = INPUT_HEIGHT;
modeLabel.x = this.x + 2;
modeLabel.y = nameField.y + nameField.h + 6;
modeLabel.w = this.width;
modeLabel.h = 10;
modeHide.w = modeRemove.w = modeGroup.w = CHECKBOX_WIDTH;
modeHide.h = modeRemove.h = modeGroup.h = INPUT_HEIGHT;
modeHide.y = modeRemove.y = modeGroup.y = modeLabel.y + modeLabel.h;
modeHide.x = this.x + 1;
modeRemove.x = modeHide.x + modeHide.w + 6;
modeGroup.x = modeRemove.x + modeRemove.w + 6;
grid.setGridSize(
this.x + 1,
modeHide.y + modeHide.h + 2,
this.width - 2,
this.height - (modeHide.y + modeHide.h + 2));
grid.refresh(null);
}
@Override
public void draw(int mousex, int mousey, float frame) {
nameLabel.draw(mousex, mousey);
nameField.draw(mousex, mousey);
modeLabel.draw(mousex, mousey);
modeHide.draw(mousex, mousey);
modeRemove.draw(mousex, mousey);
modeGroup.draw(mousex, mousey);
enabledButton.draw(mousex, mousey);
RenderHelper.enableGUIStandardItemLighting();
GL11.glPushMatrix();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
grid.draw(mousex, mousey);
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
GL11.glPopMatrix();
RenderHelper.enableStandardItemLighting();
}
public List<String> handleTooltip(int mousex, int mousey, List<String> tooltip) {
ItemPanelSlot over = grid.getSlotMouseOver(mousex, mousey);
if (over != null) {
tooltip = GuiContainerManager.itemDisplayNameMultiline(over.item, null, true);
synchronized (GuiContainerManager.tooltipHandlers) {
for (IContainerTooltipHandler handler : GuiContainerManager.tooltipHandlers) {
tooltip = handler.handleItemTooltip(null, over.item, mousex, mousey, tooltip);
}
}
if (!tooltip.isEmpty()) {
tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE); // add space after 'title'
}
} else if (modeHide.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.mode.hide.tip"));
} else if (modeRemove.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.mode.remove.tip"));
} else if (modeGroup.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.mode.group.tip"));
}
return tooltip;
}
@Override
public void keyTyped(char c, int keycode) {
nameField.handleKeyPress(keycode, c);
}
@Override
public void mouseScrolled(int x, int y, int scroll) {
if (grid.contains(x, y)) {
grid.shiftPage(-scroll);
}
}
}
@@ -0,0 +1,167 @@
package codechicken.nei.config.preset;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
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.Button;
import codechicken.nei.ItemList;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.ItemSorter;
import codechicken.nei.ItemsGrid;
import codechicken.nei.Label;
import codechicken.nei.RestartableTask;
import codechicken.nei.api.ItemFilter;
public abstract class PresetItemsGrid extends ItemsGrid {
protected static final int BUTTON_SIZE = 16;
public Button pagePrev;
public Label pageLabel;
public Button pageNext;
protected ArrayList<ItemStack> newItems;
protected final RestartableTask updateFilter = new RestartableTask("NEI Presets Item Filtering") {
@Override
public void execute() {
ArrayList<ItemStack> filtered;
ItemFilter filter = getFilter();
try {
filtered = ItemList.forkJoinPool.submit(
() -> ItemList.items.parallelStream().filter(filter::matches)
.collect(Collectors.toCollection(ArrayList::new)))
.get();
} catch (InterruptedException | ExecutionException e) {
filtered = new ArrayList<>();
e.printStackTrace();
stop();
}
if (interrupted()) return;
ItemSorter.sort(filtered);
if (interrupted()) return;
updateItemList(filtered);
}
};
protected PresetItemsGrid() {
pageLabel = new Label("0/0", true);
pagePrev = new Button("<") {
public boolean onButtonPress(boolean rightclick) {
if (rightclick) {
setPage(0);
} else {
shiftPage(-1);
}
return true;
}
};
pageNext = new Button(">") {
public boolean onButtonPress(boolean rightclick) {
if (rightclick) {
setPage(getNumPages() - 1);
} else {
shiftPage(1);
}
return true;
}
};
}
protected String getLabelText() {
return String.format("%d/%d", getPage(), Math.max(1, getNumPages()));
}
@Override
public void setGridSize(int mleft, int mtop, int w, int h) {
pageLabel.text = getLabelText();
pagePrev.w = pageNext.w = BUTTON_SIZE;
pagePrev.h = pageNext.h = BUTTON_SIZE;
pagePrev.y = pageNext.y = mtop;
pagePrev.x = mleft;
pageNext.x = mleft + w - pageNext.w;
pageLabel.x = mleft + w / 2;
pageLabel.y = pagePrev.y + 5;
super.setGridSize(mleft, mtop + BUTTON_SIZE + 2, w, h - BUTTON_SIZE - 4);
}
@Override
public void draw(int mousex, int mousey) {
pagePrev.draw(mousex, mousey);
pageNext.draw(mousex, mousey);
pageLabel.draw(mousex, mousey);
super.draw(mousex, mousey);
}
public void mouseClicked(int x, int y, int button) {
if (pagePrev.contains(x, y)) {
pagePrev.handleClick(x, y, button);
}
if (pageNext.contains(x, y)) {
pageNext.handleClick(x, y, button);
}
}
public void restartFilter() {
updateFilter.restart();
}
protected void updateItemList(List<ItemStack> newItems) {
this.newItems = new ArrayList<>(newItems);
}
@Override
public void refresh(GuiContainer gui) {
if (this.newItems != null) {
this.realItems = this.newItems;
this.newItems = null;
onItemsChanged();
}
super.refresh(gui);
}
@Override
protected void beforeDrawSlot(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {
if (isSelected(getItem(slotIdx))) {
GuiDraw.drawRect(rect.x, rect.y, rect.w, rect.h, 0xee555555);
} else {
super.beforeDrawSlot(focused, slotIdx, rect);
}
}
protected abstract boolean isSelected(ItemStack stack);
protected abstract ItemFilter getFilter();
}
@@ -0,0 +1,400 @@
package codechicken.nei.config.preset;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.core.gui.GuiWidget;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.CollapsibleItems;
import codechicken.nei.ItemList.AllMultiItemFilter;
import codechicken.nei.ItemList.AnyMultiItemFilter;
import codechicken.nei.ItemList.NegatedItemFilter;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.ItemsGrid;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList;
import codechicken.nei.PresetsList.Preset;
import codechicken.nei.SearchField.GuiSearchField;
import codechicken.nei.TextField;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.util.TextHistory;
import cpw.mods.fml.common.registry.GameRegistry;
public class RightPanel extends GuiWidget {
protected static class MouseSelection {
public int startX = -1;
public int startY = -1;
public int startIndex = -1;
public int endIndex = -1;
public Set<ItemStack> items = new HashSet<>();
public boolean append = true;
public MouseSelection(int slotIndex, Rectangle4i rec, boolean ppnd) {
append = ppnd;
endIndex = slotIndex;
startIndex = slotIndex;
startX = rec.x;
startY = rec.y;
}
}
protected abstract static class PresetSearchField extends TextField {
private static final TextHistory history = new TextHistory();
protected PresetSearchField(String ident) {
super(ident);
}
@Override
protected void initInternalTextField() {
field = new GuiSearchField();
field.setMaxStringLength(maxSearchLength);
field.setCursorPositionZero();
}
@Override
public int getTextColour() {
if (!text().isEmpty()) {
return focused() ? 0xFFcc3300 : 0xFF993300;
} else {
return focused() ? 0xFFE0E0E0 : 0xFF909090;
}
}
@Override
public void lastKeyTyped(int keyID, char keyChar) {
if (!focused() && NEIClientConfig.isKeyHashDown("gui.search")) {
setFocus(true);
}
if (focused() && NEIClientConfig.isKeyHashDown("gui.getprevioussearch")) {
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
}
if (focused() && NEIClientConfig.isKeyHashDown("gui.getnextsearch")) {
handleNavigateHistory(TextHistory.Direction.NEXT);
}
}
@Override
public String filterText(String s) {
return EnumChatFormatting.getTextWithoutFormattingCodes(s);
}
public ItemFilter getFilter() {
return ((GuiSearchField) field).getFilter();
}
@Override
public void setFocus(boolean focus) {
final boolean previousFocus = field.isFocused();
if (previousFocus != focus) {
history.add(text());
}
super.setFocus(focus);
}
private boolean handleNavigateHistory(TextHistory.Direction direction) {
if (focused()) {
return history.get(direction, text()).map(newText -> {
setText(newText);
return true;
}).orElse(false);
}
return false;
}
}
protected static final int INPUT_HEIGHT = 20;
protected static final int BUTTON_SIZE = 16;
protected final PresetItemsGrid grid = new PresetItemsGrid() {
@Override
protected ItemFilter getFilter() {
AllMultiItemFilter filter = new AllMultiItemFilter(searchField.getFilter());
if (enabledPresets.isChecked()) {
AllMultiItemFilter andFilter = new AllMultiItemFilter();
AnyMultiItemFilter orFilter = new AnyMultiItemFilter();
Set<String> identifiers = PresetsList.presets.stream().flatMap(p -> p.items.stream())
.collect(Collectors.toSet());
andFilter.filters.add(item -> !identifiers.contains(Preset.getIdentifier(item)));
andFilter.filters.add(new NegatedItemFilter(CollapsibleItems.getItemFilter()));
if (slotIndex != -1) {
orFilter.filters.add(PresetsList.presets.get(slotIndex));
}
orFilter.filters.add(andFilter);
filter.filters.add(orFilter);
}
return filter;
}
@Override
protected boolean isSelected(ItemStack stack) {
if (mouseSelection != null && mouseSelection.items.contains(stack)) {
return mouseSelection.append;
}
return preset.items.contains(Preset.getIdentifier(stack));
}
};
protected CheckboxButton enabledPresets;
protected final Preset preset;
protected final int slotIndex;
protected MouseSelection mouseSelection;
protected final PresetSearchField searchField = new PresetSearchField("preset-search") {
@Override
public void onTextChange(String oldText) {
final String newText = text();
if (!newText.equals(oldText)) {
grid.restartFilter();
}
}
};
public RightPanel(Preset preset, int slotIndex) {
super(1, 0, 2, 2);
this.slotIndex = slotIndex;
this.preset = preset;
enabledPresets = new CheckboxButton(NEIClientUtils.translate("presets.filter")) {
@Override
protected void onChange() {
grid.restartFilter();
}
};
enabledPresets.setChecked(true);
grid.restartFilter();
}
@Override
public void mouseClicked(int x, int y, int button) {
grid.mouseClicked(x, y, button);
if (enabledPresets.contains(x, y)) {
enabledPresets.handleClick(x, y, button);
}
if (searchField.contains(x, y)) {
searchField.handleClick(x, y, button);
} else {
searchField.onGuiClick(x, y);
}
if (mouseSelection == null && (button == 0 || button == 1)) {
ItemPanelSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null) {
mouseSelection = new MouseSelection(slot.slotIndex, grid.getItemRect(slot.slotIndex), button == 0);
}
}
}
protected void onItemsChanges() {}
@Override
public void mouseMovedOrUp(int x, int y, int button) {
searchField.mouseUp(x, y, button);
if (mouseSelection != null && (button == 0 || button == 1)) {
ItemPanelSlot hoverSlot = grid.getSlotMouseOver(x, y);
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;
onItemsChanges();
}
}
protected void setHidden(final ItemStack stack, final boolean append) {
if (NEIClientUtils.shiftKey()) {
final List<ItemStack> items = grid.getItems();
for (int i = 0; i < items.size(); i++) {
if (stack.getItem().equals(items.get(i).getItem())) {
hideItem(items.get(i), append);
}
}
} else if (NEIClientUtils.controlKey()) {
final String modId = getModId(stack);
if (modId == null) {
hideItem(stack, append);
} else {
final List<ItemStack> items = grid.getItems();
for (int i = 0; i < items.size(); i++) {
final String mod = getModId(items.get(i));
if (mod != null && mod.equals(modId)) {
hideItem(items.get(i), append);
}
}
}
} else {
hideItem(stack, append);
}
}
protected void hideItem(final ItemStack stack, boolean append) {
if (append) {
preset.items.add(Preset.getIdentifier(stack));
} else {
preset.items.remove(Preset.getIdentifier(stack));
}
}
protected static String getModId(final ItemStack stack) {
try {
return GameRegistry.findUniqueIdentifierFor(stack.getItem()).modId;
} catch (Exception ignored) {}
return null;
}
@Override
public void mouseDragged(int x, int y, int button, long time) {
searchField.mouseDragged(x, y, button, time);
if (mouseSelection != null && (button == 0 || button == 1)) {
final ItemPanelSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null && slot.slotIndex != mouseSelection.endIndex) {
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 ix = sel.x; ix <= sel.x + sel.w; ix += ItemsGrid.SLOT_SIZE) {
for (int iy = sel.y; iy <= sel.y + sel.h; iy += ItemsGrid.SLOT_SIZE) {
ItemPanelSlot over = grid.getSlotMouseOver(ix, iy);
if (over != null) {
mouseSelection.items.add(over.item);
}
}
}
}
}
}
@Override
public void update() {
enabledPresets.w = 20;
enabledPresets.h = INPUT_HEIGHT;
enabledPresets.x = this.x;
enabledPresets.y = this.y + this.height - 2 - INPUT_HEIGHT;
searchField.w = this.width - enabledPresets.w - 3;
searchField.h = INPUT_HEIGHT;
searchField.x = enabledPresets.x + enabledPresets.w + 3;
searchField.y = enabledPresets.y;
grid.setGridSize(this.x, this.y, this.width, searchField.y - this.y);
grid.refresh(null);
}
@Override
public void draw(int mousex, int mousey, float frame) {
enabledPresets.draw(mousex, mousey);
searchField.draw(mousex, mousey);
RenderHelper.enableGUIStandardItemLighting();
GL11.glPushMatrix();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
grid.draw(mousex, mousey);
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
GL11.glPopMatrix();
RenderHelper.enableStandardItemLighting();
}
public List<String> handleTooltip(int mousex, int mousey, List<String> tooltip) {
ItemPanelSlot over = grid.getSlotMouseOver(mousex, mousey);
if (over != null) {
tooltip = GuiContainerManager.itemDisplayNameMultiline(over.item, null, true);
synchronized (GuiContainerManager.tooltipHandlers) {
for (IContainerTooltipHandler handler : GuiContainerManager.tooltipHandlers) {
tooltip = handler.handleItemTooltip(null, over.item, mousex, mousey, tooltip);
}
}
if (!tooltip.isEmpty()) {
tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE); // add space after 'title'
}
} else if (enabledPresets.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.filter.tip"));
}
return tooltip;
}
@Override
public void keyTyped(char c, int keycode) {
searchField.handleKeyPress(keycode, c);
}
@Override
public void mouseScrolled(int x, int y, int scroll) {
if (grid.contains(x, y)) {
grid.shiftPage(-scroll);
}
}
}
@@ -12,20 +12,14 @@ import cpw.mods.fml.common.eventhandler.Event;
/**
* Event is posted every time the handler infos got registered or reloaded. During it, you can safely register your
* custom handler info.
*
* <br>
* This event does not have a result. {@link HasResult}<br>
* custom handler info. <br>
* This event does not have {@link HasResult result}.<br>
* <br>
* This event is fired on the {@link MinecraftForge#EVENT_BUS}.
*/
public class NEIRegisterHandlerInfosEvent extends Event {
public void registerHandlerInfo(String handlerName, String modName, String modId,
Consumer<HandlerInfo.Builder> builder) {
HandlerInfo.Builder b = new HandlerInfo.Builder(handlerName, modName, modId);
builder.accept(b);
HandlerInfo info = b.build();
public void registerHandlerInfo(HandlerInfo info) {
if (GuiRecipeTab.handlerMap.put(info.getHandlerName(), info) != null) {
NEIClientConfig.logger.info("Replaced handler info for {}", info.getHandlerName());
} else {
@@ -33,6 +27,14 @@ public class NEIRegisterHandlerInfosEvent extends Event {
}
}
public void registerHandlerInfo(String handlerName, String modName, String modId,
Consumer<HandlerInfo.Builder> builder) {
HandlerInfo.Builder b = new HandlerInfo.Builder(handlerName, modName, modId);
builder.accept(b);
HandlerInfo info = b.build();
registerHandlerInfo(info);
}
public void registerHandlerInfo(Class<? extends IRecipeHandler> handlerClazz, String modName, String modId,
Consumer<HandlerInfo.Builder> builder) {
registerHandlerInfo(handlerClazz.getName(), modName, modId, builder);
@@ -4,15 +4,21 @@ import static codechicken.lib.gui.GuiDraw.drawMultilineTip;
import static codechicken.lib.gui.GuiDraw.fontRenderer;
import static codechicken.lib.gui.GuiDraw.getMousePosition;
import static codechicken.lib.gui.GuiDraw.renderEngine;
import static codechicken.nei.NEIClientUtils.translate;
import java.awt.*;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
@@ -20,8 +26,12 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.RenderItem;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;
import net.minecraft.client.resources.SimpleReloadableResourceManager;
import net.minecraft.init.Blocks;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
@@ -34,12 +44,26 @@ import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ItemList;
import codechicken.nei.ItemStackSet;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIModContainer;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.ReadableNumberConverter;
import codechicken.nei.util.RenderTooltipEventHelper;
public class GuiContainerManager {
private static class ResourcePackReloaded implements IResourceManagerReloadListener {
@Override
public void onResourceManagerReload(IResourceManager p_110549_1_) {
renderingErrorItems.clear();
ItemList.loadItems.restart();
}
}
public GuiContainer window;
public static RenderItem drawItems = new RenderItem();
@@ -138,13 +162,15 @@ public class GuiContainerManager {
namelist = stack.getTooltip(
Minecraft.getMinecraft().thePlayer,
includeHandlers && Minecraft.getMinecraft().gameSettings.advancedItemTooltips);
} catch (Throwable ignored) {}
} catch (Throwable ignored) {
namelist = new ArrayList<>();
}
if (namelist == null) namelist = new ArrayList<>();
if (namelist.size() == 0) namelist.add("Unnamed");
if (namelist.get(0) == null || namelist.get(0).equals("")) namelist.set(0, "Unnamed");
if (namelist.isEmpty()) {
namelist.add("Unnamed");
} else if (namelist.get(0) == null || namelist.get(0).isEmpty()) {
namelist.set(0, "Unnamed");
}
if (includeHandlers) {
for (IContainerTooltipHandler handler : tooltipHandlers) {
@@ -217,8 +243,17 @@ public class GuiContainerManager {
* @return The first line of the multiline display name.
*/
public static String itemDisplayNameShort(ItemStack itemstack) {
List<String> list = itemDisplayNameMultiline(itemstack, null, false);
return list.get(0);
try {
List<String> namelist = itemstack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
if (!namelist.isEmpty() && !"".equals(namelist.get(0))) {
return itemstack.getRarity().rarityColor.toString() + namelist.get(0) + EnumChatFormatting.RESET;
}
} catch (Throwable ignored) {}
return "Unnamed";
}
/**
@@ -228,105 +263,126 @@ public class GuiContainerManager {
* @param itemstack The stack to get the name for
* @return The multiline display name of this item separated by '#'
*/
@Deprecated
public static String concatenatedDisplayName(ItemStack itemstack, boolean includeHandlers) {
List<String> list = itemDisplayNameMultiline(itemstack, null, includeHandlers);
StringBuilder sb = new StringBuilder();
boolean first = true;
StringJoiner sb = new StringJoiner("#");
for (String name : list) {
if (first) {
first = false;
} else {
sb.append("#");
if (!name.isEmpty()) {
sb.add(name);
}
sb.append(name);
}
return EnumChatFormatting.getTextWithoutFormattingCodes(sb.toString());
}
public static void drawItem(int i, int j, ItemStack itemstack) {
drawItem(i, j, itemstack, false);
public static void drawItem(int offsetX, int offsetY, ItemStack itemstack) {
drawItem(offsetX, offsetY, itemstack, false);
}
public static void drawItem(int i, int j, ItemStack itemstack, boolean smallAmount) {
drawItem(i, j, itemstack, smallAmount, null);
public static void drawItem(int offsetX, int offsetY, ItemStack itemstack, boolean smallAmount) {
drawItem(offsetX, offsetY, itemstack, smallAmount, null);
}
public static void drawItem(int i, int j, ItemStack itemstack, boolean smallAmount, String stackSize) {
drawItem(i, j, itemstack, getFontRenderer(itemstack), smallAmount, stackSize);
public static void drawItem(int offsetX, int offsetY, ItemStack itemstack, boolean smallAmount, String quantity) {
drawItem(offsetX, offsetY, itemstack, getFontRenderer(itemstack), smallAmount, quantity);
}
public static void drawItem(int i, int j, ItemStack itemstack, FontRenderer fontRenderer) {
drawItem(i, j, itemstack, fontRenderer, false, null);
public static void drawItem(int offsetX, int offsetY, ItemStack itemstack, FontRenderer fontRenderer) {
drawItem(offsetX, offsetY, itemstack, fontRenderer, false, null);
}
private static int modelviewDepth = -1;
private static final HashSet<String> stackTraces = new HashSet<>();
private static final ItemStackSet renderingErrorItems = new ItemStackSet();
public static void drawItem(int i, int j, ItemStack itemstack, FontRenderer fontRenderer, boolean smallAmount,
String stackSize) {
enable3DRender();
// for lighting correction
boolean glRescale = GL11.glGetBoolean(GL12.GL_RESCALE_NORMAL);
public static void drawItem(int offsetX, int offsetY, ItemStack itemstack, FontRenderer fontRenderer,
boolean smallAmount, String quantity) {
float zLevel = drawItems.zLevel += 100F;
try {
drawItems.renderItemAndEffectIntoGUI(fontRenderer, renderEngine, itemstack, i, j);
safeItemRenderContext(itemstack, offsetX, offsetY, fontRenderer, () -> {
float scale = smallAmount ? 0.5f : 1f;
String stackSize = quantity;
if (stackSize == null) {
stackSize = itemstack.stackSize > 1 ? String.valueOf(itemstack.stackSize) : "";
}
if (itemstack.stackSize > 1) {
stackSize = ReadableNumberConverter.INSTANCE.toWideReadableForm(itemstack.stackSize);
if (smallAmount) {
if (stackSize.length() == 3) {
scale = 0.8f;
} else if (stackSize.length() == 4) {
scale = 0.6f;
} else if (stackSize.length() > 4) {
scale = 0.5f;
}
if (!stackSize.isEmpty()) {
drawBigStackSize(i, j, stackSize);
} else {
stackSize = "";
}
// stackSize = "". it needed for correct draw item with alpha and blend
drawItems.renderItemOverlayIntoGUI(fontRenderer, renderEngine, itemstack, i, j, "");
} else {
drawItems.renderItemOverlayIntoGUI(fontRenderer, renderEngine, itemstack, i, j, stackSize);
}
if (!checkMatrixStack()) throw new IllegalStateException("Modelview matrix stack too deep");
if (Tessellator.instance.isDrawing) throw new IllegalStateException("Still drawing");
} catch (Exception e) {
NEIClientUtils.reportErrorBuffered(e, stackTraces, itemstack);
drawItems.renderItemAndEffectIntoGUI(fontRenderer, renderEngine, itemstack, offsetX, offsetY);
restoreMatrixStack();
if (Tessellator.instance.isDrawing) Tessellator.instance.draw();
if (scale != 1f && !stackSize.isEmpty()) {
drawBigStackSize(offsetX, offsetY, stackSize, scale);
stackSize = "";
}
drawItems.zLevel = zLevel;
drawItems.renderItemIntoGUI(fontRenderer, renderEngine, new ItemStack(Blocks.fire), i, j);
}
if (glRescale) {
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
} else {
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
}
enable2DRender();
drawItems.zLevel = zLevel - 100;
drawItems.renderItemOverlayIntoGUI(fontRenderer, renderEngine, itemstack, offsetX, offsetY, stackSize);
});
}
// copy from appeng.client.render.AppEngRenderItem
protected static void drawBigStackSize(int offsetX, int offsetY, String stackSize) {
final float scaleFactor = fontRenderer.getUnicodeFlag() ? 0.85f : 0.5f;
final float inverseScaleFactor = 1.0f / scaleFactor;
protected static void drawBigStackSize(int offsetX, int offsetY, String stackSize, float scale) {
final float inverseScaleFactor = 1.0f / scale;
enable2DRender();
GL11.glScaled(scaleFactor, scaleFactor, scaleFactor);
GL11.glScaled(scale, scale, scale);
final int X = (int) (((float) offsetX + 16.0f - fontRenderer.getStringWidth(stackSize) * scaleFactor)
* inverseScaleFactor);
final int Y = (int) (((float) offsetY + 16.0f - 7.0f * scaleFactor) * inverseScaleFactor);
final int X = (int) ((offsetX + 16.0f - fontRenderer.getStringWidth(stackSize) * scale) * inverseScaleFactor);
final int Y = (int) ((offsetY + 16.0f - 7.0f * scale) * inverseScaleFactor);
fontRenderer.drawStringWithShadow(stackSize, X, Y, 16777215);
GL11.glScaled(inverseScaleFactor, inverseScaleFactor, inverseScaleFactor);
enable3DRender();
}
private static void safeItemRenderContext(ItemStack stack, int x, int y, FontRenderer fontRenderer,
Runnable callback) {
float zLevel = drawItems.zLevel += 100F;
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
enable3DRender();
if (!renderingErrorItems.contains(stack)) {
try {
callback.run();
if (!checkMatrixStack()) throw new IllegalStateException("Modelview matrix stack too deep");
if (Tessellator.instance.isDrawing) throw new IllegalStateException("Still drawing");
} catch (Exception e) {
NEIClientUtils.reportErrorBuffered(e, stackTraces, stack);
restoreMatrixStack();
if (Tessellator.instance.isDrawing) Tessellator.instance.draw();
drawItems.zLevel = zLevel;
drawItems.renderItemIntoGUI(fontRenderer, renderEngine, new ItemStack(Blocks.fire), x, y);
renderingErrorItems.add(stack);
}
} else {
drawItems.renderItemIntoGUI(fontRenderer, renderEngine, new ItemStack(Blocks.fire), x, y);
}
GL11.glPopAttrib();
drawItems.zLevel = zLevel - 100;
}
public static void registerReloadResourceListener() {
if (Minecraft.getMinecraft().getResourceManager() instanceof SimpleReloadableResourceManager manager) {
manager.registerReloadListener(new ResourcePackReloaded());
}
}
public static void enableMatrixStackLogging() {
modelviewDepth = GL11.glGetInteger(GL11.GL_MODELVIEW_STACK_DEPTH);
}
@@ -363,9 +419,9 @@ public class GuiContainerManager {
public GuiContainerManager(GuiContainer screen) {
window = screen;
if (screen instanceof IContainerTooltipHandler) {
if (screen instanceof IContainerTooltipHandler tooltipHandler) {
instanceTooltipHandlers = Collections.synchronizedList(new LinkedList<>());
instanceTooltipHandlers.add((IContainerTooltipHandler) screen);
instanceTooltipHandlers.add(tooltipHandler);
instanceTooltipHandlers.addAll(tooltipHandlers);
} else instanceTooltipHandlers = tooltipHandlers;
}
@@ -497,8 +553,8 @@ public class GuiContainerManager {
tooltip = handler.handleTooltip(window, mousex, mousey, tooltip);
}
ItemStack stack = getStackMouseOver(window);
if (tooltip.isEmpty() && shouldShowTooltip(window)) { // mouseover tip, not holding an item
ItemStack stack = getStackMouseOver(window);
font = getFontRenderer(stack);
if (stack != null) {
tooltip = itemDisplayNameMultiline(stack, window, true);
@@ -511,9 +567,118 @@ public class GuiContainerManager {
}
}
if (tooltip.size() > 0) tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE); // add space after 'title'
if (!tooltip.isEmpty()) tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE); // add space after 'title'
drawPagedTooltip(font, mousex + 12, mousey - 12, tooltip);
if (shouldShowTooltip(window)) {
List<String> hotkeystips = collectHotkeyTips(mousex, mousey);
if (!hotkeystips.isEmpty()) {
if (tooltip.isEmpty()) {
tooltip.addAll(hotkeystips);
} else {
tooltip.addAll(1, hotkeystips);
}
}
}
if (NEIModContainer.isGTNHLibLoaded() && !tooltip.isEmpty()) {
if (RenderTooltipEventHelper.post(stack, this.window, mousex, mousey, font)) {
return;
}
Consumer<List<String>> alternativeRenderer = RenderTooltipEventHelper.getAlternativeRenderer();
if (alternativeRenderer == null) {
drawPagedTooltip(
RenderTooltipEventHelper.getFont(),
RenderTooltipEventHelper.getX() + 12,
RenderTooltipEventHelper.getY() - 12,
tooltip);
} else {
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
RenderHelper.disableStandardItemLighting();
GL11.glDisable(GL11.GL_DEPTH_TEST);
GuiDraw.gui.incZLevel(300.0f);
alternativeRenderer.accept(tooltip);
GuiDraw.gui.incZLevel(-300.0f);
GL11.glEnable(GL11.GL_DEPTH_TEST);
RenderHelper.enableStandardItemLighting();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
}
RenderTooltipEventHelper.flush();
} else {
drawPagedTooltip(font, mousex + 12, mousey - 12, tooltip);
}
for (IContainerDrawHandler drawHandler : drawHandlers) {
drawHandler.postRenderTooltips(window, mousex, mousey, tooltip);
}
}
private List<String> collectHotkeyTips(int mousex, int mousey) {
Map<String, String> hotkeys = new HashMap<>();
synchronized (instanceTooltipHandlers) {
for (IContainerTooltipHandler handler : instanceTooltipHandlers) {
hotkeys = handler.handleHotkeys(window, mousex, mousey, hotkeys);
}
}
if (!hotkeys.isEmpty()) {
List<String> hotkeystips = new ArrayList<>();
if (!NEIClientUtils.altKey()) {
hotkeystips.add(
EnumChatFormatting.GRAY + translate(
"showHotkeys",
EnumChatFormatting.GOLD + translate("key.alt") + EnumChatFormatting.GRAY));
} else {
Map<String, List<String>> messages = new HashMap<>();
hotkeys.remove(null);
hotkeys.remove("");
for (Map.Entry<String, String> entry : hotkeys.entrySet()) {
messages.computeIfAbsent(entry.getValue(), m -> new ArrayList<>()).add(entry.getKey());
}
for (List<String> keys : messages.values()) {
Collections.sort(keys, (a, b) -> {
if (a.length() != b.length()) {
return Integer.compare(a.length(), b.length());
}
return a.compareTo(b);
});
}
messages.entrySet().stream().sorted((a, b) -> {
String sa = String.join("/", a.getValue());
String sb = String.join("/", b.getValue());
if (sa.length() != sb.length()) {
return Integer.compare(sa.length(), sb.length());
}
return sa.compareTo(sb);
}).map(entry -> getHotkeyTip(entry.getValue(), entry.getKey()))
.collect(Collectors.toCollection(() -> hotkeystips));
hotkeystips.set(
hotkeystips.size() - 1,
hotkeystips.get(hotkeystips.size() - 1) + GuiDraw.TOOLTIP_LINESPACE);
}
return hotkeystips;
}
return Collections.emptyList();
}
private String getHotkeyTip(List<String> keys, String message) {
return EnumChatFormatting.GOLD
+ String.join(EnumChatFormatting.DARK_GRAY + " / " + EnumChatFormatting.GOLD, keys)
+ EnumChatFormatting.GRAY
+ " - "
+ message
+ EnumChatFormatting.RESET;
}
private static int tooltipPage;
@@ -528,7 +693,19 @@ public class GuiContainerManager {
"inventory.tooltip.page",
tooltipPage + 1,
tooltips.size(),
NEIClientConfig.getKeyName(NEIClientConfig.getKeyBinding("gui.next_tooltip"), true)));
NEIClientConfig.getKeyName("gui.next_tooltip")));
}
if (NEIModContainer.isGTNHLibLoaded()) {
drawMultilineTip(
font,
x,
y,
tooltips.get(tooltipPage),
RenderTooltipEventHelper.getBackgroundStart(),
RenderTooltipEventHelper.getBackgroundEnd(),
RenderTooltipEventHelper.getBorderStart(),
RenderTooltipEventHelper.getBorderEnd());
return;
}
drawMultilineTip(font, x, y, tooltips.get(tooltipPage));
}
@@ -559,6 +736,7 @@ public class GuiContainerManager {
}
public static boolean shouldShowTooltip(GuiContainer window) {
if (window == null) return false;
for (IContainerObjectHandler handler : objectHandlers) if (!handler.shouldShowTooltip(window)) return false;
return window.mc.thePlayer.inventory.getItemStack() == null;
@@ -617,7 +795,7 @@ public class GuiContainerManager {
if (Keyboard.getEventKeyState() || (k == 0 && Character.isDefined(c))) {
try {
keyTyped(c, k);
} catch (java.lang.IndexOutOfBoundsException e) {
} catch (IndexOutOfBoundsException e) {
System.err.println("Caught out of bounds exception pressing " + c + " " + k);
e.printStackTrace();
}
@@ -640,38 +818,17 @@ public class GuiContainerManager {
* Delegate for changing item rendering for certain slots. Eg. Shrinking text for large itemstacks
*/
public void drawSlotItem(Slot slot, ItemStack stack, int x, int y, String quantity) {
// for lighting correction
boolean glRescale = GL11.glGetBoolean(GL12.GL_RESCALE_NORMAL);
float zLevel = drawItems.zLevel += 100F;
try {
if (window instanceof IGuiSlotDraw) {
((IGuiSlotDraw) window).drawSlotItem(slot, stack, x, y, quantity);
} else {
if (quantity == null) {
quantity = stack != null && stack.stackSize > 1 ? String.valueOf(stack.stackSize) : "";
}
drawItems.renderItemAndEffectIntoGUI(fontRenderer, renderEngine, stack, x, y);
drawItems.renderItemOverlayIntoGUI(fontRenderer, renderEngine, stack, x, y, quantity);
}
} catch (Exception e) {
NEIClientUtils.reportErrorBuffered(e, stackTraces, stack);
restoreMatrixStack();
if (Tessellator.instance.isDrawing) Tessellator.instance.draw();
drawItems.zLevel = zLevel;
drawItems.renderItemIntoGUI(fontRenderer, renderEngine, new ItemStack(Blocks.fire), x, y);
if (window instanceof IGuiSlotDraw) {
safeItemRenderContext(
stack,
x,
y,
fontRenderer,
() -> ((IGuiSlotDraw) window).drawSlotItem(slot, stack, x, y, quantity));
} else if (stack != null) {
drawItem(x, y, stack, false, quantity);
}
if (glRescale) {
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
} else {
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
}
drawItems.zLevel = zLevel - 100;
}
/**
@@ -1,6 +1,13 @@
package codechicken.nei.guihook;
import java.util.*;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
@@ -14,6 +21,7 @@ import java.util.stream.Stream;
*/
final class HideousLinkedList<E> extends LinkedList<E> {
private static final long serialVersionUID = -8504433551965776915L;
private final List<E> backing;
HideousLinkedList(List<E> backing) {
@@ -1,5 +1,7 @@
package codechicken.nei.guihook;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.inventory.Slot;
@@ -30,6 +32,17 @@ public interface IContainerDrawHandler {
*/
public void postRenderObjects(GuiContainer gui, int mousex, int mousey);
/**
* Use this to draw things that should be drawn just after vanilla slot tooltips, on top of buttons and other
* usually always-on-top widgets.
*
* @param gui An instance of the currentscreen
* @param mousex The x position of the mouse in pixels from left
* @param mousey The y position of the mouse in pixels from top
* @param tooltip The contents of the tooltip that has previously been drawn
*/
default void postRenderTooltips(GuiContainer gui, int mousex, int mousey, List<String> tooltip) {}
/**
* Render something over a slot before the item in the slot.
*
@@ -1,6 +1,7 @@
package codechicken.nei.guihook;
import java.util.List;
import java.util.Map;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
@@ -15,36 +16,54 @@ public interface IContainerTooltipHandler {
* Use this to add tooltips for other objects. If the current tip has lines in it after this call, the item tootip
* will not be handled. GuiContainerManager.shouldShowTooltip is not enforced here. It is recommended that you make
* this check yourself
*
*
* @param gui An instance of the currentscreen
* @param mousex The x position of the mouse in pixels from left
* @param mousey The y position of the mouse in pixels from top
* @param currenttip A list of strings, representing each line of the current tooltip as modified by other handlers
* @return The modified list. NOTE: Do not return null
*/
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip);
default List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
return currenttip;
}
/**
* Use this for modifying the multiline display name of an item which may not necessarily be under the mouse.
* GuiContainerManager.shouldShowTooltip is enforced here.
*
*
* @param gui An instance of the currentscreen. If only general information about the item is wanted (Eg.
* potion effects) then this may be null.
* @param itemstack The ItemStack under the mouse
* @param currenttip A list of strings, representing each line of the current tooltip as modified by other handlers
* @return The modified list. NOTE: Do not return null
*/
public List<String> handleItemDisplayName(GuiContainer gui, ItemStack itemstack, List<String> currenttip);
default List<String> handleItemDisplayName(GuiContainer gui, ItemStack itemstack, List<String> currenttip) {
return currenttip;
}
/**
* Use this for modifying the tooltips of items that are under the mouse. GuiContainerManager.shouldShowTooltip is
* enforced here.
*
*
* @param gui An instance of the currentscreen
* @param itemstack The ItemStack under the mouse
* @param currenttip A list of strings, representing each line of the current tooltip as modified by other handlers
* @return The modified list. NOTE: Do not return null
*/
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
List<String> currenttip);
default List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
List<String> currenttip) {
return currenttip;
}
/**
* Use this to specify a list of hotkeys that will work when hovering over an element that is under the mouse
* pointer.
*
* @param gui An instance of the currentscreen
* @param mousex The x position of the mouse in pixels from left
* @param mousey The y position of the mouse in pixels from top
*/
default Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
return hotkeys;
}
}
@@ -16,10 +16,6 @@ import codechicken.nei.util.NBTJson;
public class BookmarkRecipeId {
public int position = -1;
public int recipetype = -1;
public String handlerName = null;
public List<NBTTagCompound> ingredients = new ArrayList<>();
@@ -29,16 +25,16 @@ public class BookmarkRecipeId {
for (Object pos : stacks) {
if (pos instanceof PositionedStack) {
pos = StackInfo.getItemStackWithMinimumDamage(((PositionedStack) pos).items);
if (pos instanceof PositionedStack item) {
pos = StackInfo.getItemStackWithMinimumDamage(item.items);
}
if (pos instanceof ItemStack) {
pos = StackInfo.itemStackToNBT((ItemStack) pos);
if (pos instanceof ItemStack item) {
pos = StackInfo.itemStackToNBT(item);
}
if (pos instanceof NBTTagCompound) {
ingredients.add((NBTTagCompound) pos);
if (pos instanceof NBTTagCompound item) {
ingredients.add(item);
}
}
}
@@ -10,10 +10,8 @@ import net.minecraft.item.ItemStack;
import com.google.common.collect.ForwardingList;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIServerUtils;
// Do not directly extend ArrayList, see Effective Java Item 16
public class CatalystInfoList extends ForwardingList<CatalystInfo> {
private final String handlerID;
@@ -34,16 +32,21 @@ public class CatalystInfoList extends ForwardingList<CatalystInfo> {
}
@Override
public boolean add(@Nonnull CatalystInfo catalystInfo) {
if (contains(catalystInfo)) {
NEIClientConfig.logger.info(
String.format(
"catalyst %s is already registered to handler %s",
catalystInfo.getStack().getDisplayName(),
handlerID));
return false;
public boolean add(@Nonnull CatalystInfo element) {
return doAdd(element);
}
public boolean add(@Nonnull CatalystInfo catalystInfo, boolean overwrite) {
if (overwrite || !contains(catalystInfo)) {
return add(catalystInfo);
}
super.add(catalystInfo);
return false;
}
private boolean doAdd(@Nonnull CatalystInfo catalystInfo) {
catalystInfoList
.removeIf(c -> NEIServerUtils.areStacksSameTypeCraftingWithNBT(c.getStack(), catalystInfo.getStack()));
catalystInfoList.add(catalystInfo);
return true;
}
@@ -16,17 +16,19 @@ import codechicken.lib.inventory.InventoryUtils;
import codechicken.nei.FastTransferManager;
import codechicken.nei.PositionedStack;
import codechicken.nei.api.IOverlayHandler;
import cpw.mods.fml.relauncher.ReflectionHelper;
@SuppressWarnings("rawtypes, unchecked")
public class DefaultOverlayHandler implements IOverlayHandler {
public static Class gtItem;
private static Class<?> gtItem;
static {
try {
gtItem = Class.forName("gregtech.api.items.GT_MetaBase_Item");
} catch (ClassNotFoundException ignored) {
gtItem = null;
final ClassLoader loader = DefaultOverlayHandler.class.getClassLoader();
gtItem = ReflectionHelper
.getClass(loader, "gregtech.api.items.MetaBaseItem", "gregtech.api.items.GT_MetaBase_Item");
} catch (Exception ignored) {
/* Do nothing */
}
}
@@ -85,20 +87,21 @@ public class DefaultOverlayHandler implements IOverlayHandler {
if (quantity != 0) moveIngredients(gui, assignedIngredients, quantity);
}
@SuppressWarnings("unchecked")
private boolean clearIngredients(GuiContainer gui, List<PositionedStack> ingreds) {
for (PositionedStack pstack : ingreds) for (Slot slot : (List<Slot>) gui.inventorySlots.inventorySlots)
if (slot.xDisplayPosition == pstack.relx + offsetx && slot.yDisplayPosition == pstack.rely + offsety) {
if (!slot.getHasStack()) continue;
for (PositionedStack pstack : ingreds) {
for (Slot slot : gui.inventorySlots.inventorySlots) {
if (slot.xDisplayPosition == pstack.relx + offsetx && slot.yDisplayPosition == pstack.rely + offsety) {
if (!slot.getHasStack()) continue;
FastTransferManager.clickSlot(gui, slot.slotNumber, 0, 1);
if (slot.getHasStack()) return false;
FastTransferManager.clickSlot(gui, slot.slotNumber, 0, 1);
if (slot.getHasStack()) return false;
}
}
}
return true;
}
@SuppressWarnings("unchecked")
private void moveIngredients(GuiContainer gui, List<IngredientDistribution> assignedIngredients, int quantity) {
for (IngredientDistribution distrib : assignedIngredients) {
if (distrib.slots.length == 0) continue;
@@ -112,14 +115,14 @@ public class DefaultOverlayHandler implements IOverlayHandler {
int slotTransferred = 0;
int slotTransferCap = pstack.getMaxStackSize();
for (Slot slot : (List<Slot>) gui.inventorySlots.inventorySlots) {
for (Slot slot : gui.inventorySlots.inventorySlots) {
if (!slot.getHasStack() || !canMoveFrom(slot, gui)) continue;
ItemStack stack = slot.getStack();
if (!canStack(stack, pstack)) continue;
FastTransferManager.clickSlot(gui, slot.slotNumber);
int amount = Math.min(transferCap - transferred, stack.stackSize);
FastTransferManager.clickSlot(gui, slot.slotNumber);
for (int c = 0; c < amount; c++) {
FastTransferManager.clickSlot(gui, dest.slotNumber, 1);
transferred++;
@@ -181,7 +184,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
assignedSlots.add(new LinkedList<>());
}
while (avaliableSlots.size() > 0 && remainingIngreds.size() > 0) {
while (!avaliableSlots.isEmpty() && !remainingIngreds.isEmpty()) {
for (Iterator<Integer> iterator = remainingIngreds.iterator(); iterator.hasNext();) {
int i = iterator.next();
boolean assigned = false;
@@ -199,8 +202,9 @@ public class DefaultOverlayHandler implements IOverlayHandler {
}
}
if (!assigned || istack.numSlots * istack.stack.getMaxStackSize() >= istack.invAmount)
if (!assigned || istack.numSlots * istack.stack.getMaxStackSize() >= istack.invAmount) {
iterator.remove();
}
}
}
@@ -245,9 +249,8 @@ public class DefaultOverlayHandler implements IOverlayHandler {
return assignedIngredients;
}
@SuppressWarnings("unchecked")
private void findInventoryQuantities(GuiContainer gui, List<DistributedIngred> ingredStacks) {
for (Slot slot : (List<Slot>) gui.inventorySlots.inventorySlots) /* work out how much we have to go round */ {
for (Slot slot : gui.inventorySlots.inventorySlots) /* work out how much we have to go round */ {
if (slot.getHasStack() && canMoveFrom(slot, gui)) {
ItemStack pstack = slot.getStack();
DistributedIngred istack = findIngred(ingredStacks, pstack);
@@ -272,13 +275,12 @@ public class DefaultOverlayHandler implements IOverlayHandler {
return slot.inventory instanceof InventoryPlayer;
}
@SuppressWarnings("unchecked")
public Slot[][] mapIngredSlots(GuiContainer gui, List<PositionedStack> ingredients) {
Slot[][] recipeSlotList = new Slot[ingredients.size()][];
for (int i = 0; i < ingredients.size(); i++) /* identify slots */ {
LinkedList<Slot> recipeSlots = new LinkedList<>();
PositionedStack pstack = ingredients.get(i);
for (Slot slot : (List<Slot>) gui.inventorySlots.inventorySlots) {
for (Slot slot : gui.inventorySlots.inventorySlots) {
if (slot.xDisplayPosition == pstack.relx + offsetx && slot.yDisplayPosition == pstack.rely + offsety) {
recipeSlots.add(slot);
break;
@@ -70,8 +70,7 @@ public class FillFluidContainerHandler extends INEIGuiAdapter {
}
return FluidContainerRegistry.fillFluidContainer(fluidStack, draggedStack);
} else if (draggedStack.getItem() instanceof IFluidContainerItem) {
IFluidContainerItem item = (IFluidContainerItem) draggedStack.getItem();
} else if (draggedStack.getItem() instanceof IFluidContainerItem item) {
if (item.getCapacity(draggedStack) > 0) {
item.drain(draggedStack, item.getCapacity(draggedStack), true);
Loaded 100 of 158 files, more files were not shown because too many files have changed in this diff. Show more