Compare commits

...
Author SHA1 Message Date
June Awesome 4058f23490 testing if this works 2026-03-22 18:53:26 -04:00
slprime 0ba14091fb Refactor DebugHandlerWidget (#900) 2026-03-22 14:10:10 +02:00
slprimeandUltraProdigy 6ed0be7961 Add Repair Handler (#899)
Co-authored-by: UltraProdigy <[email protected]>
2026-03-21 15:04:09 +02:00
slprime d40b951cce Fix areStacksSameTypeWithNBT damage check (#896) 2026-03-19 14:43:45 +02:00
slprime ecdf7892ce updateBuildScript (#895) 2026-03-19 09:39:59 +02:00
slprime 1eaaac94bc Fix filtered permutations (#893) 2026-03-18 01:25:27 +02:00
slprime e99167dddb Change calculateBounds (#892) 2026-03-15 22:41:31 +02:00
slprime 34cb0dc43f Set minimum GTNHLib version to 0.9.6 (#891) 2026-03-15 16:07:31 +01:00
slprime acaad4bf91 Fix Favorite Option (#887) 2026-03-09 21:23:22 +02:00
slprime 3de75f4e26 Fix bookmark slot placement logic (#885) 2026-03-08 12:23:18 +02:00
slprime 47497090ea fix glColor4f; disabled generateSingleRecipeFavorites by default (#884) 2026-03-07 16:58:30 +02:00
slprime 8b45a1757f Add Favorite Item Support (#880) 2026-03-07 16:34:41 +02:00
UltraProdigy 2782f8252e Optimize images (#883) 2026-03-07 09:40:11 +01:00
slprime a5538b2566 Always Show Recipe Ingredients Overlay (#878) 2026-03-01 11:38:05 +02:00
slprime a1f324b796 Remove Generated Favorites from Accepts Followings Tooltip (#873) 2026-02-23 09:32:15 +02:00
slprimeandMartin Robertz f3b6be26df Generate Single-Recipe Favorites (#863)
Co-authored-by: Martin Robertz <[email protected]>
2026-02-16 23:14:55 +01:00
slprime 9c764e3682 Restore the 'get infinite items' action (#867) 2026-02-16 18:39:17 +02:00
slprime 08605c3d73 Removed GTNHLib from required dependency (#866) 2026-02-16 04:37:20 -05:00
slprime 9ec1e0f0cd Change Bookmarks Panel Width (#862) 2026-02-10 19:41:28 +02:00
UltraProdigy e61151186c Exclude Duplicates (#860) 2026-02-09 23:05:15 +01:00
Martin Robertz f7787a9a22 update gradle + deps + bs 2026-02-09 22:32:25 +01:00
slprimeandUltraProdigy a91083bb5a Fix Pull Bookmarked Items (#857)
Co-authored-by: UltraProdigy <[email protected]>
2026-02-09 21:29:07 +00:00
slprimeandUltraProdigy 51f830bdf6 Reset item panel page on search result size change (#855)
Co-authored-by: UltraProdigy <[email protected]>
2026-02-09 16:18:22 -05:00
slprime 9326ac48ad Align panels from center to edges (#856) 2026-02-09 21:11:10 +00:00
c125b71ae0 Added checks for abstract classes when retrieving entities (#833)
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-08 20:49:58 +00:00
Ranzu 805b90d6f8 Add debug text localization and tooltips (#854) 2026-02-03 17:58:20 +02:00
RanzuandMartin Robertz 900b9f90e7 Added show all handlers and recipes function (#852)
Co-authored-by: Martin Robertz <[email protected]>
2026-02-03 15:38:35 +02:00
Ranzuandslprime 06d4a96c3a Add texture for toggled state of magnet button (#849)
Co-authored-by: slprime <[email protected]>
2026-01-26 20:15:10 +02:00
sbwaz 9a5a4a77ef [Extended+] Quote in extended+ depending on "Quote Drop Item Name" NEI option (#848) 2026-01-26 20:08:27 +02:00
Connor-ColensoandConnor Colenso 4d874ec910 Format number centralisation (#846)
Co-authored-by: Connor Colenso <colen@CONNORSPC>
2026-01-23 20:51:38 -05:00
slprime 7f0f2466a5 Fix Information Handler Background Padding (#843) 2026-01-19 13:13:14 +02:00
slprime 83e1966ff2 Fix Recipe Handlers Padding (#842) 2026-01-19 07:47:05 +01:00
slprime 548f754823 Fix Autocrafting for recipe without ingredients in bookmarks (#841) 2026-01-19 07:46:46 +01:00
slprime e036fd14a8 Correctly crop colored text (#839) 2026-01-13 15:16:09 +02:00
slprime 463f4c9b60 Fix transparency border (#838) 2026-01-13 13:06:59 +02:00
Ranzu 5070fde640 Added optional subset label localization (#836) 2026-01-06 03:02:38 +02:00
454b4f7e1d Added Transparency Border to recipe-background and catalyst-tab (#822)
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: slprime <[email protected]>
2025-12-28 15:40:21 +01:00
7b83456f01 Add tooltip for "Required Crafts" with shift (#810)
Co-authored-by: Wilhelm Schuster <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: slprime <[email protected]>
2025-12-28 15:36:39 +02:00
PLASMAchicken 4b7b84b031 Restore NEIModContainer public plugins field (#829) 2025-12-26 19:31:41 +01:00
slprime 75309b81ec Hide Untranslator Subset when Untranslator disabled (#827) 2025-12-21 13:26:26 +02:00
slprimeandMartin Robertz 24e46bb43e Add the ability to move bookmark groups between namespaces (#803)
Co-authored-by: Martin Robertz <[email protected]>
2025-12-16 23:39:32 +02:00
Alexdoru 2ba0773401 [Memory-opti:fix leak] Fix WorldServer leak in NEIServerConfig (#815) 2025-12-16 19:44:15 +00:00
PLASMAchicken eac913c80c Remove Obsolete Code from ModContainer (#820) 2025-12-13 12:42:40 +02:00
slprime 126f0ea73c Fix missing favorites and incorrect crafting chains for recipes with identical ingredients (#814) 2025-11-25 07:24:30 +01:00
slprimeandMartin Robertz cd4668ec84 Backup bookmarks.ini if loading failed (#798)
Co-authored-by: Martin Robertz <[email protected]>
2025-11-24 08:52:01 +02:00
slprime 7c247dd0d2 Ignore space hotkeys when typing in search bar (#808) 2025-11-24 00:21:24 +02:00
slprime 87b549fab5 Normalize Fluid Packet (#811) 2025-11-16 14:17:56 +02:00
slprimeandMartin Robertz 8ed1f7a043 Properly clears inventory before filling a recipe (#796)
Co-authored-by: Martin Robertz <[email protected]>
2025-11-13 08:19:55 +02:00
slprime f2efa35654 Extend HandlerInfo.Builder interface (#809) 2025-11-08 23:54:35 +02:00
slprime bcef287e71 Fix Permutations for Information Handler (#804) 2025-11-08 09:32:47 +02:00
slprime 7f555f7a7f Add Tooltip for debug option (#805) 2025-11-08 09:27:21 +02:00
slprime 9fd38da205 Correctly collapse recipe (#807) 2025-11-08 09:18:14 +02:00
slprime 2fa5563408 Optimizing cross-dimension loading (#806) 2025-11-08 09:12:40 +02:00
slprimeandMartin Robertz 541c0e2def Add 'Bookmark recipe with count' Option (#776)
Co-authored-by: Martin Robertz <[email protected]>
2025-11-07 19:54:09 +02:00
Martin Robertz ac868097e7 update 2025-11-07 18:32:09 +01:00
slprimeandMartin Robertz 2f0de0b6a8 Add 'Show only favorites' option to the 'Craftables' panel (#800)
Co-authored-by: Martin Robertz <[email protected]>
2025-11-06 17:37:00 +02:00
sisyphussy 32bc29e654 Remove glBlitFramebuffer (#801) 2025-11-06 14:36:30 +02:00
slprimeandMartin Robertz ef8a7d8bd5 Create normalizeRecipeQueryStack (#772)
Co-authored-by: Martin Robertz <[email protected]>
2025-11-05 23:15:45 +02:00
slprimeandMartin Robertz adc5a5df16 Add GuiOverlapSlots for subpanels (#799)
Co-authored-by: Martin Robertz <[email protected]>
2025-11-05 21:55:33 +02:00
slprime a828ff227a Remove try/catch from static block (#797) 2025-11-05 19:08:55 +01:00
slprime 9b6f98330e Remove Permutations from Output (#777) 2025-11-05 19:14:48 +02:00
slprime 667c8cb5b6 Implement Dynamic Handler Height (#792) 2025-11-05 19:00:09 +02:00
slprimeandMartin Robertz a186f69444 Fix favorite state refresh (#787)
Co-authored-by: Martin Robertz <[email protected]>
2025-11-04 23:11:00 +01:00
slprime 16f4f20239 Fixed small mouse movement while double-clicking causing drop all items (#793) 2025-11-04 23:10:43 +01:00
slprime bac207cacb Change item slot size in GuiRecipe (#789) 2025-11-04 23:10:32 +01:00
slprime 630e856d83 Fix hotkeys when keyBinding disabled (#786) 2025-10-30 10:17:16 +02:00
slprime 42d96aed0c Show 'Delete Item' tooltip in Creative Mode (#785) 2025-10-29 21:47:34 +01:00
slprimeandsisyphussy bd6384bf24 Сalculate the height of the container before scrolling to the recipe (#782)
Co-authored-by: sisyphussy <[email protected]>
2025-10-29 07:52:33 +00:00
slprime af9726d356 Fixed shift+scroll of ingredients in the recipe GUI (#783) 2025-10-29 07:42:18 +00:00
Martin Robertz 1e1d2f1076 update 2025-10-29 07:54:19 +01:00
slprimeandWilhelm Schuster 7cb94fb22a Clear rawText before formatting (#780)
Co-authored-by: Wilhelm Schuster <[email protected]>
2025-10-25 15:20:28 +02:00
Martin Robertz 87aa4f9ed5 update 2025-10-25 14:18:58 +02:00
DarkShadow44andMartin Robertz 9760fd3eaf Fix another race condition, affecting IndustrialGrafter (#779)
Co-authored-by: Martin Robertz <[email protected]>
2025-10-25 14:11:49 +02:00
slprime 1054871982 Add Scroll to Recipe Catalysts (#770) 2025-10-21 12:28:14 +00:00
slprime d90a667f68 Fix Bookmarks Chain Tooltip Height (#773) 2025-10-19 21:33:46 +03:00
slprime 69e6df5848 Fix Button Texture (#771) 2025-10-19 19:56:23 +02:00
slprime 25fa7ce44e Add defaultbookmarkcontainers.cfg (#769) 2025-10-19 16:07:45 +03:00
slprime e3cd7b860d Fix recipe result count (#767) 2025-10-18 11:07:39 +00:00
slprime 2a3aabc073 Add recipe index to recipe handler height (#768) 2025-10-18 13:03:08 +02:00
slprimeandMartin Robertz 76db43c835 Optimize permutations (#761)
Co-authored-by: Martin Robertz <[email protected]>
2025-10-17 22:23:10 +03:00
slprimeandMartin Robertz 40e53eea7a Fixing HUD flickering (#762)
Co-authored-by: Martin Robertz <[email protected]>
2025-10-17 21:36:30 +03:00
Martin Robertz 6c4d16d6b9 update 2025-10-17 12:50:52 +02:00
RealSilverMoon 4a2abe9fd7 Add a function to copy item name and meta (#758) 2025-10-17 10:54:47 +03:00
sisyphussy d47417302e Fix recipe tooltip lighting (#757) 2025-10-14 17:09:02 +03:00
e13401ded8 Optimize Bookmark Chains with Containers (#751)
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: sisyphussy <[email protected]>
2025-10-13 11:01:58 +00:00
sisyphussy 7ada842ef3 Fix tooltip item lighting (#755) 2025-10-13 00:29:09 +03:00
slprimeandMartin Robertz fe0c5d4e50 Create Recipe Widget; Recipe GUI: Infinity Scroll; Recipe GUI: Max Height Settings (#701)
Co-authored-by: Martin Robertz <[email protected]>
2025-10-12 18:39:21 +02:00
slprime 2ea9ae1eb9 Show Handler Icon in Bookmarks (#747) 2025-10-09 21:22:37 +02:00
slprime f7f0596fda Show Items Loading Message (#745) 2025-10-08 16:58:23 +02:00
sbwaz d5e919a9cd [Extended+] Fix the prefixed sequence parsing. (#741) 2025-10-04 13:19:00 +02:00
sisyphussyandMartin Robertz a0ed5da699 Speedup rendering (#740)
Co-authored-by: Martin Robertz <[email protected]>
2025-10-02 12:53:18 +02:00
Martin Robertz 99fb5a656e update 2025-10-02 12:13:08 +02:00
DarkShadow44 4b663222b1 Force tag compounds to be initialized so doesn't happen concurrently later (#730) 2025-10-02 07:15:28 +02:00
Martin Robertz 3e5d0088bc update 2025-10-01 17:21:16 +02:00
948be399d2 allow the steam furnace multiblock to show up in NEI under furnaces (#702)
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: EnderProyects <[email protected]>
2025-09-28 13:39:45 +02:00
DarkShadow44 5f6091924d Add more logging for fuel crash (#736) 2025-09-28 01:02:47 +03:00
Dredonkey c5bd1f897a Fix pressing '2' when hovering crafting output not putting the crafted item(s) in the hotbar (#733) 2025-09-27 10:17:40 +00:00
Julia 61d4b6ab62 Revert "Replace lambda with method reference" (#735) 2025-09-27 03:09:17 -07:00
Julia 791d05d5f5 Support Inline Comments After # (#734) 2025-09-26 18:11:47 -07:00
Mike_be 66001275c4 Remove UXV and MAX biolab from NEI recipe catalysts (#732) 2025-09-26 21:40:03 +02:00
slprime db6b83c906 Try fix Fuels (#729) 2025-09-24 13:17:34 +02:00
slprime 58ef6c85e0 Fix NBT Copy (#728) 2025-09-22 20:28:05 -07:00
Martin Robertz ab0aeef872 update 2025-09-21 21:38:41 +02:00
slprime 23b7c69e2f Fix None hotkeys for java8 (#726) 2025-09-21 19:44:20 +02:00
slprime bb89384493 Fix Bookmarks Shadow Items (#724) 2025-09-18 19:07:51 +02:00
slprime e96e4dfdde Create Item Untranslator (#719) 2025-09-17 12:42:35 +00:00
slprime 0a6a6771d8 Fixed Favorite Recipes in bookmarks for ingredients (#720) 2025-09-15 19:21:52 +02:00
sbwaz c96199a727 [Extended+] Filter permutations on the left. Fail on recipe expression, when not searching a recipe. (#716) 2025-09-13 11:18:29 +02:00
azod ab4ea2cfa1 feat(moboverlay): add chat message (on/off) (#715) 2025-09-11 03:45:06 -03:00
Mike_be b679883d02 Remove old entries which resulted in ghost catalysts (#714) 2025-09-08 20:11:32 +02:00
Worive 0048ef80d0 Fix(MobSpawnOverlay): avoid IOB from checking light value from block outside of world (#711) 2025-09-07 11:03:21 +00:00
slprime 84576aa7a2 Fix Permutation Filter (#712) 2025-09-06 22:32:14 +02:00
Dream Master c5cd5b9e61 update 2025-09-05 16:08:54 +02:00
slprimeandMartin Robertz b1bedcf403 Recipe search improvement (#706)
Co-authored-by: Martin Robertz <[email protected]>
2025-09-04 15:59:51 +02:00
Matthew Bentham bba0a11466 Add missing lang key for favorite keybind (#709) 2025-09-04 13:20:53 +02:00
slprime b80948f2f2 Fix Subset Name (#705) 2025-08-31 18:34:19 +02:00
slprime 28539bbacc Fix Keyboard IndexOutOfBoundsException (#704) 2025-08-31 18:33:59 +02:00
UltraProdigy ec28bdf116 Make EFR Lingering Potion Recipes Visible in NEI (#703) 2025-08-30 09:10:05 -04:00
sbwaz e5d55a9bd8 Advanced search expressions and improved recipe search in a new pattern mode: extended+ (#692) 2025-08-24 14:35:59 +07:00
slprime c1f7489de1 Presets: Custom Subsets Mode (#671) 2025-08-22 12:22:09 +00:00
slprime fa6fd01a3a Add Option to Disable Hotkeys Tooltip (#680) 2025-08-22 12:15:23 +00:00
slprime 453ba6667f Add Favorite Hotkey (#681) 2025-08-22 19:12:42 +07:00
slprime 4e11a45852 Add the ability to create a chain of items with zero (#682) 2025-08-22 12:06:27 +00:00
slprime 95274339a0 Change panel position algorithm (#683) 2025-08-22 12:03:05 +00:00
slprime 31fcd6af51 Crate Craftables Panel (#696) 2025-08-22 11:58:41 +00:00
koolkrafter5 860bc059ca Allow shift+scrolling other stacks in recipes (#698) 2025-08-18 19:57:08 +07:00
koolkrafter5 2fc2152809 Strict Item Identify Format (#697) 2025-08-16 21:11:27 +07:00
slprimeandkoolkrafter5 57e865fc6f Custom Subsets in config; RecipeId Command (#691)
Co-authored-by: koolkrafter5 <[email protected]>
2025-08-16 18:56:59 +07:00
Dream Master 6dcd26a978 update 2025-08-16 18:39:01 +07:00
koolkrafter5 aeb59081d9 Information Handler (#695) 2025-08-16 18:24:40 +07:00
slprime ef8706ae38 Loading items after the player to ensure the hint cache works correctly in some mods (#687) 2025-08-16 07:38:24 +07:00
Dream Master b49d066231 update 2025-08-08 19:05:06 +07:00
slprime 594fbe6f79 Allowed fill crafting grid without all ingredients (#693) 2025-08-06 13:40:52 -04:00
koolkrafter5andEthryan 3edb85b317 Allow handlers to hide the favorite and overlay buttons via IMC (#678)
Co-authored-by: Ethryan <[email protected]>
2025-07-29 20:37:37 +07:00
TotallyNotOndre 5fd0a74363 Add ability to bookmark linked items (#674) 2025-07-26 07:42:34 +07:00
Dream Master 2ae94e94a0 update 2025-07-17 22:31:09 +07:00
TotallyNotOndre fa3adde3e6 Add ability to link Item in chat (#673) 2025-07-17 10:09:43 +07:00
slprime 56941cc45d Correctly used tools in favorites (#670) 2025-07-12 07:44:34 +02:00
slprimeandCaedis cd7d014704 Bookmarks Chains: Use active Item as preferred if exists (#664)
Co-authored-by: Caedis <[email protected]>
2025-07-11 14:36:10 +00:00
slprime 0634466851 Bookmarks Chains: Optimize GTTools (#667) 2025-07-11 14:33:14 +00:00
slprimeandCaedis b87e389132 Bookmarks Hotkeys: optimization thaumcraft recipes (#663)
Co-authored-by: Caedis <[email protected]>
2025-07-11 14:25:15 +00:00
slprimeandCaedis c788a07cf5 Bookmarks Chains Math: fix infinity loop (#662)
Co-authored-by: Caedis <[email protected]>
2025-07-11 16:21:32 +02:00
Martin Robertz 7d4ed91e86 update 2025-07-09 14:43:40 +02:00
slprime ca79cdd3c9 Disable play sound when crafting with gt tools (#659) 2025-07-08 15:41:42 +02:00
slprime 3a0722adc2 Update Bookmark Chain Tooltip Cache (#657) 2025-07-01 05:52:46 -05:00
slprime 77fa3bafd6 Autocrafting Improvement (#655) 2025-06-27 08:32:54 -05:00
Martin Robertz e23e542aac update 2025-06-22 18:27:06 +02:00
slprime 7ec2ad132e Tools in autocrafting (#653) 2025-06-22 17:49:20 +02:00
slprime 7b43826d05 Clear Crafting Grid after autocrafting (#652) 2025-06-20 09:25:02 -05:00
slprime c7a18dd288 Fix Item Tooltip (#651) 2025-06-19 16:22:12 +00:00
184 changed files with 12596 additions and 4293 deletions

No files matched your search

+17
View File
@@ -0,0 +1,17 @@
name: Optimize images
on:
pull_request:
branches: [ master, main, release/** ]
paths:
- "**/*.png"
push:
branches: [ master, main, release/** ]
paths:
- "**/*.png"
jobs:
optimize-images:
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/optimize-images.yml@master
secrets: inherit
+53
View File
@@ -22,6 +22,59 @@ If you have issues with NEI outside of the GTNH modpack you may report them in t
* Cycle between Recipe, Utility, and Cheat mode by ctrl clicking on the Wrench Icon
* GT5u Tools/Items and GT6 tools should now properly work with the Overlay Recipe Transfer
### Information Page Handler
Want to add some information about a block or item without making a massive tooltip for it? You can add information about any block or item by registering it in the Information Handler.
Information page(s) are displayed when either the uses or recipes of a matching item are searched. All matching items will cycle at the top of the information page.
Your mod can call:
```java
FMLInterModComms.sendMessage("NotEnoughItems", "addItemInfo", nbt);
```
Where nbt is an NBTTagCompound formatted as described below.
| Tag | Type | Description |
|------------------|----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `filter` | String | A string filter to match what items should return this information page.<br/>modname:itemname, metadata, Ore Dictionary tags, and regex can all be used. The full format may be seen in `config/NEI/collapsibleitems.cfg`. |
| `page` / `pages` | String / String NBTTagList | The actual text to display. See below for differences between single and multi-page messages.<br/>Both formats will automatically translate provided strings. |
#### Single Page Format
Use the `"page"` string tag when you only want to add one page of information:
```java
NBTTagCompound tag = new NBTTagCompound();
tag.setString("filter", "minecraft:log 3");
tag.setString("page", "Exotic wood found in tropical climates.");
FMLInterModComms.sendMessage("NotEnoughItems", "addItemInfo", tag);
```
#### Multiple Page Format
Use the `"pages"` tag as an `NBTTagList` of strings when you want more than one page:
```java
NBTTagCompound tag = new NBTTagCompound();
tag.setString("filter", "minecraft:diamond_sword");
NBTTagList pages = new NBTTagList();
pages.appendTag(new NBTTagString("A powerful melee weapon."));
pages.appendTag(new NBTTagString("Can be enchanted for extra effects."));
tag.setTag("pages", pages);
FMLInterModComms.sendMessage("NotEnoughItems", "addItemInfo", tag);
```
* Each list entry is one page.
* Pages will appear in NEI with buttons to scroll through them.
#### Item Matching
All items that match `filter` will show your information page. See `config/NEI/collapsibleitems.cfg` for the full filter format.
#### Item Information Config File
If you're a modpack creator and want to make custom item information pages, they can easily be added in `config/NEI/informationpages.cfg`, which has a few more examples.
## Other items of note:
* Remove TMI style
+26
View File
@@ -1,3 +1,29 @@
compileJava {
options.encoding = "UTF-8"
}
generateGrammarSource {
maxHeapSize = "128m"
arguments += ['-package', 'codechicken.nei.search', '-visitor', '-no-listener']
outputDirectory = file("${projectDir}/build/generated/sources/search/antlr/codechicken/nei/search/")
}
compileJava.dependsOn generateGrammarSource
sourcesJar.dependsOn generateGrammarSource
sourcesJar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
sourceSets {
main {
java.srcDirs += ["build/generated/sources/search/antlr/"]
}
}
test {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
}
}
+1
View File
@@ -1,5 +1,6 @@
//version: 1707058017
plugins {
id 'antlr'
id 'com.gtnewhorizons.gtnhconvention'
}
+13 -3
View File
@@ -1,10 +1,20 @@
// Add your dependencies here
dependencies {
api('com.github.GTNewHorizons:CodeChickenCore:1.4.3:dev')
implementation('com.github.GTNewHorizons:GTNHLib:0.6.31:dev')
api('com.github.GTNewHorizons:CodeChickenCore:1.4.10:dev')
devOnlyNonPublishable('com.github.GTNewHorizons:GTNHLib:0.9.13:dev')
shadowImplementation('org.apache.commons:commons-csv:1.10.0')
compileOnly 'maven.modrinth:forge-essentials:7.5.1'
compileOnly('maven.modrinth:forge-essentials:7.5.1')
antlr('org.antlr:antlr4:4.13.2')
shadowImplementation('org.antlr:antlr4-runtime:4.13.2')
testImplementation(platform('org.junit:junit-bom:5.13.4'))
testImplementation('org.junit.jupiter:junit-jupiter')
testImplementation("org.mockito:mockito-core:5.+")
testRuntimeOnly('org.junit.platform:junit-platform-launcher')
testRuntimeOnly("org.lwjgl.lwjgl:lwjgl:2.9.3");
}
+40 -5
View File
@@ -39,9 +39,33 @@ remoteMappings = https\://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/co
# `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE.
developmentEnvironmentUserName = Developer
# Enables using modern Java syntax (up to version 17) via Jabel, while still targeting JVM 8.
# See https://github.com/bsideup/jabel for details on how this works.
enableModernJavaSyntax = true
# Enables modern Java syntax support. Valid values:
# - false: No modern syntax, Java 8 only
# - jabel: Jabel syntax-only support, compiles to J8 bytecode
# - jvmDowngrader: Full modern Java via JVM Downgrader (syntax + stdlib APIs)
# - modern: Native modern Java bytecode, no downgrading
enableModernJavaSyntax = jabel
# If set, ignores the above setting and compiles with the given toolchain. This may cause unexpected issues,
# and should *not* be used in most situations. -1 disables this.
# forceToolchainVersion = -1
# Target JVM version for JVM Downgrader bytecode downgrading.
# Only used when enableModernJavaSyntax = jvmDowngrader
# downgradeTargetVersion = 8
# Comma-separated list of Java versions for multi-release jar support (JVM Downgrader only).
# Classes will be available in META-INF/versions/N/ for each version N in this list.
# Default: "21,25" (J25+ gets native classes, J21-24 gets partial downgrade, J8-20 gets full downgrade).
# jvmDowngraderMultiReleaseVersions = 21,25
# Specifies how JVM Downgrader API stubs are provided. Options:
# - shade: Shade minimized stubs into the jar
# - gtnhlib: GTNHLib provides stubs at runtime (adds version constraint)
# - external: Another dependency provides stubs (no constraint, no warning)
# - (empty): Warning reminding you to configure stubs
# Note: 'shade' option requires you to verify license compliance, see: https://github.com/unimined/JvmDowngrader/blob/main/LICENSE.md
# jvmDowngraderStubsProvider =
# Enables injecting missing generics into the decompiled source code for a better coding experience.
# Turns most publicly visible List, Map, etc. into proper List<E>, Map<K, V> types.
@@ -96,7 +120,9 @@ usesMixinDebug = false
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
mixinPlugin =
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
# Specify the package that contains all of your Mixins. The package must exist or
# the build will fail. If you have a package property defined in your mixins.<modid>.json,
# it must match with this or the build will fail.
mixinsPackage =
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
@@ -151,7 +177,7 @@ modrinthProjectId = notenoughitems-unofficial
# 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
# Note: UniMixins is automatically set as a required dependency if usesMixins = true.
modrinthRelations = required-project\:codechickencore-unofficial
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
@@ -172,6 +198,12 @@ curseForgeRelations = requiredDependency\:codechickencore-unofficial
# projects. New projects should not use this parameter.
# customArchiveBaseName =
# Optional parameter to customize the default working directory used by the runClient* tasks. Relative to the project directory.
# runClientWorkingDirectory = run/client
# Optional parameter to customize the default working directory used by the runServer* tasks. Relative to the project directory.
# runServerWorkingDirectory = run/server
# Optional parameter to have the build automatically fail if an illegal version is used.
# This can be useful if you e.g. only want to allow versions in the form of '1.1.xxx'.
# The check is ONLY performed if the version is a git tag.
@@ -201,3 +233,6 @@ curseForgeRelations = requiredDependency\:codechickencore-unofficial
# This is meant to be set in $HOME/.gradle/gradle.properties.
# ideaCheckSpotlessOnBuild = true
# Non-GTNH properties
org.gradle.configuration-cache = true
org.gradle.parallel = true
+12
View File
@@ -0,0 +1,12 @@
#This file is generated by updateDaemonJvm
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c5ee947fbfb70bc347d8d531e3a578c4/redirect
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/5ee463876563a46fff651cce1bc53a4c/redirect
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c5ee947fbfb70bc347d8d531e3a578c4/redirect
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/5ee463876563a46fff651cce1bc53a4c/redirect
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/e1118b4c7c2858d28154d086dbff010e/redirect
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/faa12903720d410b387cc69ccafb1a74/redirect
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c5ee947fbfb70bc347d8d531e3a578c4/redirect
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/5ee463876563a46fff651cce1bc53a4c/redirect
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/a4c09dd2e2d7079373d30e524bbc2829/redirect
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/b96cb7670c095245220e7d01d5927b58/redirect
toolchainVersion=25
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+3 -6
View File
@@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -114,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -172,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -212,8 +210,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
Vendored
+1 -2
View File
@@ -70,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
+1 -1
View File
@@ -1,4 +1,4 @@
// Add any additional repositiroes for your dependencies here
// Add any additional repositories for your dependencies here
repositories {
maven {
+1 -1
View File
@@ -17,7 +17,7 @@ pluginManagement {
}
plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.38'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.24'
}
+47
View File
@@ -0,0 +1,47 @@
lexer grammar SearchExpressionLexer;
// Antlr4 generates imports with .*
@header {
// CHECKSTYLE:OFF
import codechicken.nei.SearchTokenParser;
}
@members {
private SearchTokenParser searchParser;
public SearchExpressionLexer(CharStream input, SearchTokenParser searchParser) {
this(input);
this.searchParser = searchParser;
}
}
// Lexer rules
REGEX_LEFT : 'r'? '/' -> pushMode(REGEX) ;
QUOTE_LEFT : '"' -> pushMode(QUOTED) ;
DASH : '-' ;
RECIPE_INGREDIENTS : '<&' | '<' ;
RECIPE_RESULT : '>&' | '>' ;
RECIPE_OTHERS : '^&' | '^' ;
OR : '|' ;
LEFT_BRACKET : '{' ;
RIGHT_BRACKET : '}' ;
NEWLINE_OR_TAB : [\t\r\n] -> skip ;
SPACE : ' ' ;
ESCAPED_SYMBOL : '\\' . ;
PREFIX : CLEAN_SYMBOL {searchParser.hasRedefinedPrefix(getText().charAt(0))}? ;
CLEAN_SYMBOL : ~[-<>^{}|/\\ "] ;
mode REGEX;
REGEX_CONTENT : (~[/] | '\\/')+ ;
REGEX_RIGHT : '/' -> popMode ;
mode QUOTED;
QUOTED_CONTENT : (~["] | '\\"')+ ;
QUOTE_RIGHT : '"' -> popMode ;
+73
View File
@@ -0,0 +1,73 @@
parser grammar SearchExpressionParser;
// Antlr4 generates imports with .*
@header {
// CHECKSTYLE:OFF
}
options { tokenVocab=SearchExpressionLexer; }
// Parser rules
// Should only be used for recipes. Thanks to antlr inability to properly
// inherit grammars, this is included where it's not supposed to be
recipeSearchExpression
: recipeClauseExpression*
;
recipeClauseExpression
: ingredientsPrefix=RECIPE_INGREDIENTS searchExpression[0, $ingredientsPrefix.getText().length() > 1]
| resultPrefix=RECIPE_RESULT searchExpression[1, $resultPrefix.getText().length() > 1]
| othersPrefix=RECIPE_OTHERS searchExpression[2, $othersPrefix.getText().length() > 1]
| searchExpression[3, false]
;
// General search expression rules
searchExpression[int type, boolean allRecipe]
: orExpression
;
orExpression
: sequenceExpression (OR sequenceExpression)*
;
sequenceExpression
: (SPACE* unaryExpression SPACE*)+
;
unaryExpression
: LEFT_BRACKET orExpression RIGHT_BRACKET?
| prefixedExpression
| negateExpression
| token['\0']
;
negateExpression
: DASH unaryExpression
;
prefixedExpression
locals [
Character prefix
]
: prefixToken=PREFIX { $prefix = $prefixToken.getText().charAt(0); } token[$prefix]
;
token[Character prefix]
: regex[prefix]
| quoted[prefix]
| plainText
;
regex[Character prefix]
: REGEX_LEFT REGEX_CONTENT REGEX_RIGHT?
;
quoted[Character prefix]
: QUOTE_LEFT QUOTED_CONTENT QUOTE_RIGHT?
;
plainText
: (CLEAN_SYMBOL | ESCAPED_SYMBOL)+
;
@@ -0,0 +1,148 @@
package codechicken.nei;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.ShortcutInputHandler;
import codechicken.nei.drawable.DrawableBuilder;
import codechicken.nei.drawable.DrawableResource;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.recipe.GuiRecipe;
public abstract class AbstractSubpanel<T extends ItemsGrid<? extends ItemsGridSlot, ? extends ItemsGrid.MouseContext>>
extends Widget implements IContainerTooltipHandler {
final DrawableResource DASH = new DrawableBuilder("nei:textures/dash.png", 0, 0, 6, 1).setTextureSize(6, 1).build();
protected int mouseDownItemIndex = -1;
protected int splittingLineColor = 0xffffffff;
protected int linePaddingStart = 0;
protected T grid;
public boolean isEmpty() {
return this.grid.isEmpty();
}
public void draw(int mousex, int mousey) {
drawSplittingLine();
this.grid.draw(mousex, mousey);
}
public void update() {
this.grid.update();
}
public abstract int setPanelWidth(int width);
public void resize(GuiContainer gui) {
this.grid.setGridSize(x, y + 4, w, h - 8);
this.grid.refresh(gui);
}
@Override
public ItemStack getStackMouseOver(int mousex, int mousey) {
final ItemsGridSlot slot = getSlotMouseOver(mousex, mousey);
return slot == null ? null : slot.getItemStack();
}
public ItemsGridSlot getSlotMouseOver(int mousex, int mousey) {
return this.grid.getSlotMouseOver(mousex, mousey);
}
protected void updateLinePadding() {
GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
this.linePaddingStart = 0;
while (GuiInfo
.hideItemPanelSlot(guiContainer, new Rectangle4i(this.x + this.linePaddingStart, this.y - 1, 10, 2))) {
this.linePaddingStart += 10;
}
}
protected void drawSplittingLine() {
float alpha = (this.splittingLineColor >> 24 & 255) / 255.0F;
float red = (this.splittingLineColor >> 16 & 255) / 255.0F;
float green = (this.splittingLineColor >> 8 & 255) / 255.0F;
float blue = (this.splittingLineColor & 255) / 255.0F;
int width = this.grid.columns * ItemsGrid.SLOT_SIZE - this.linePaddingStart;
int repeat = width / 6;
int shiftX = this.x + this.linePaddingStart + (this.w - width) / 2;
GL11.glColor4f(red, green, blue, alpha);
for (int i = 0; i < repeat; i++) {
DASH.draw(shiftX + i * 6, this.y);
}
GL11.glColor4f(1, 1, 1, 1);
}
@Override
public void mouseDragged(int mousex, int mousey, int button, long heldTime) {
if (this.mouseDownItemIndex >= 0 && ItemPanels.itemPanel.draggedStack == null
&& NEIClientUtils.getHeldItem() == null
&& NEIClientConfig.hasSMPCounterPart()) {
final ItemsGridSlot mouseOverSlot = getSlotMouseOver(mousex, mousey);
if (mouseOverSlot == null || mouseOverSlot.itemIndex != this.mouseDownItemIndex || heldTime > 500) {
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(
this.grid.getItem(this.mouseDownItemIndex));
this.mouseDownItemIndex = -1;
}
}
}
@Override
public boolean handleClick(int mousex, int mousey, int button) {
if (handleClickExt(mousex, mousey, button)) return true;
final ItemsGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
if (hoverSlot != null) {
if (button == 2) {
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(hoverSlot.getItemStack());
} else {
mouseDownItemIndex = hoverSlot.itemIndex;
}
return true;
}
return false;
}
protected abstract ItemStack getDraggedStackWithQuantity(ItemStack itemStack);
public ItemStack getStackMouseOverWithQuantity(int mousex, int mousey) {
final ItemStack hoverSlot = getStackMouseOver(mousex, mousey);
return hoverSlot != null ? getDraggedStackWithQuantity(hoverSlot) : null;
}
@Override
public void mouseUp(int mousex, int mousey, int button) {
final ItemsGridSlot hoverSlot = getSlotMouseOver(mousex, mousey);
if (hoverSlot != null && hoverSlot.itemIndex == this.mouseDownItemIndex
&& ItemPanels.itemPanel.draggedStack == null) {
if (NEIController.manager.window instanceof GuiRecipe || NEIClientUtils.shiftKey()
|| !NEIClientConfig.canCheatItem(hoverSlot.getItemStack())) {
ShortcutInputHandler.handleMouseClick(hoverSlot.getItemStack().copy());
} else {
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.getItemStack()), button, -1);
}
}
this.mouseDownItemIndex = -1;
}
}
+107 -51
View File
@@ -9,6 +9,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -28,6 +29,7 @@ import codechicken.nei.api.IBookmarkContainerHandler;
import codechicken.nei.bookmark.BookmarkGrid;
import codechicken.nei.bookmark.BookmarkGroup;
import codechicken.nei.bookmark.BookmarkItem;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.bookmark.BookmarkStorage;
import codechicken.nei.bookmark.BookmarksGridSlot;
import codechicken.nei.bookmark.GroupingItem;
@@ -183,34 +185,37 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
final boolean existsRecipe = recipeId != null
&& this.grid.existsRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID);
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(itemStack);
long factor = nbTag.getInteger("Count");
long count = nbTag.getInteger("Count");
long factor = existsRecipe ? Math.max(count, 1) : 1;
if (existsRecipe) {
for (int i = 0; i < this.grid.size(); i++) {
if (this.grid.getBookmarkItem(i).equalsRecipe(recipeId, groupId)) {
final long multiplier = this.grid.getBookmarkItem(i).getMultiplier();
factor *= multiplier;
count *= this.grid.getBookmarkItem(i).getMultiplier();
break;
}
}
} else {
factor = nbTag.hasKey("gtFluidName") ? Math.min(144, nbTag.getInteger("Count")) : 1;
}
this.grid.addItem(BookmarkItem.of(groupId, itemStack, factor, recipeId, false), true);
this.grid.addItem(
BookmarkItem.of(
groupId,
StackInfo.withAmount(itemStack, count),
factor,
recipeId,
existsRecipe ? BookmarkItemType.RESULT : BookmarkItemType.ITEM),
true);
return true;
}
return false;
}
public boolean addRecipe(Recipe recipe, int groupId) {
public boolean addRecipe(Recipe recipe, int multiplier, int groupId) {
final RecipeId recipeId = recipe.getRecipeId();
if (recipe != null && this.grid.getGroup(groupId) != null && !this.grid.existsRecipe(recipeId, groupId)) {
this.grid.addRecipe(recipe, groupId);
this.grid.addRecipe(recipe, multiplier, groupId);
return true;
}
@@ -233,7 +238,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
if (item instanceof Recipe recipe) {
if (uniqueRecipe.add(recipe.getRecipeId())) {
this.grid.addRecipe(recipe, groupId);
this.grid.addRecipe(recipe, 1, groupId);
}
} else if (item instanceof RecipeId recipeId) {
@@ -241,7 +246,8 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
if (stack != null && uniqueRecipe.add(recipeId)) {
this.grid.addItem(
BookmarkItem.of(groupId, stack, StackInfo.getAmount(stack), recipeId, false),
BookmarkItem
.of(groupId, stack, StackInfo.getAmount(stack), recipeId, BookmarkItemType.ITEM),
true);
uniqueStack.add(stack);
}
@@ -301,23 +307,49 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
}
final int groupId = slot.getGroupId();
final RecipeId recipeId = slot.getRecipeId();
final RecipeId recipeId = slot.getType() == BookmarkItemType.ITEM ? null : slot.getRecipeId();
final BookmarkGroup group = slot.getGroup();
if (recipeId == null || !removeFullRecipe) {
this.grid.removeRecipe(slot.itemIndex, removeFullRecipe);
if (group.crafting != null && group.collapsed) {
if (!removeFullRecipe) {
return true;
}
this.grid.removeGroup(groupId);
return true;
}
if (group.crafting != null && group.crafting.recipeRelations.containsKey(recipeId)) {
boolean removed = false;
if (recipeId != null && group.crafting != null) {
Set<RecipeId> recipes = group.crafting.recipeRelations.getOrDefault(recipeId, Collections.emptySet());
for (RecipeId relRecipeId : group.crafting.recipeRelations.get(recipeId)) {
removed = this.grid.removeRecipe(relRecipeId, groupId) || removed;
if (recipes.isEmpty()) {
for (Map.Entry<RecipeId, Set<RecipeId>> entry : group.crafting.recipeRelations.entrySet()) {
if (entry.getValue().contains(recipeId)) {
recipes = entry.getValue();
break;
}
}
}
return removed;
if (!recipes.isEmpty()) {
if (!removeFullRecipe) {
return true;
}
boolean removed = false;
for (RecipeId relRecipeId : recipes) {
removed = this.grid.removeRecipe(relRecipeId, groupId) || removed;
}
return removed;
}
}
if (recipeId == null || !removeFullRecipe) {
this.grid.removeRecipe(slot.itemIndex, removeFullRecipe);
return true;
}
return this.grid.removeRecipe(recipeId, groupId);
@@ -339,7 +371,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
public RecipeId getRecipeId(int itemIndex) {
BookmarkItem meta = this.grid.getCalculatedItem(itemIndex);
return meta.isIngredient ? null : meta.recipeId;
return meta.type == BookmarkItemType.INGREDIENT ? null : meta.recipeId;
}
public boolean existsRecipe(RecipeId recipeId, int groupId) {
@@ -419,7 +451,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
protected int resizeHeader(GuiContainer gui) {
final LayoutStyleMinecraft layout = (LayoutStyleMinecraft) LayoutManager.getLayoutStyle();
final int rows = (int) Math.ceil((double) layout.buttonCount / layout.numButtons);
final int diff = rows * 19 + getMarginTop(gui) - y;
final int diff = rows * 19 + PADDING - y;
if (diff > 0) {
y += diff;
@@ -477,24 +509,31 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
}
}
protected String getPositioningSettingName() {
return "world.panels.bookmarks";
}
@Override
public Rectangle4i calculateBounds(GuiContainer gui) {
final int maxWidth = (gui.width - 176) / 2 - PADDING * 2;
final int maxHeight = gui.height - PADDING * 2;
final int freeSpace = (gui.width - gui.xSize) / 2 - PADDING * 2;
public int getMarginLeft(GuiContainer gui) {
return PADDING;
}
final int paddingLeft = (int) Math
.ceil(maxWidth * NEIClientConfig.getSetting("world.panels.bookmarks.left").getIntValue() / 100000.0);
final int paddingTop = (int) Math
.ceil(maxHeight * NEIClientConfig.getSetting("world.panels.bookmarks.top").getIntValue() / 100000.0);
final int paddingRight = (int) Math
.ceil(maxWidth * NEIClientConfig.getSetting("world.panels.bookmarks.right").getIntValue() / 100000.0);
final int paddingBottom = (int) Math
.ceil(maxHeight * NEIClientConfig.getSetting("world.panels.bookmarks.bottom").getIntValue() / 100000.0);
public int getMarginTop(GuiContainer gui) {
return PADDING;
}
final int width = Math.max(
ItemsGrid.SLOT_SIZE,
snapDownToMultiple(
Math.min(freeSpace - paddingLeft, maxWidth - paddingLeft - paddingRight)
- BookmarkGrid.GROUP_PANEL_WIDTH,
ItemsGrid.SLOT_SIZE))
+ BookmarkGrid.GROUP_PANEL_WIDTH;
final int height = Math.max(ItemsGrid.SLOT_SIZE, maxHeight - paddingTop - paddingBottom);
public int getWidth(GuiContainer gui) {
return gui.width - (gui.xSize + gui.width) / 2 - PADDING * 2;
}
public int getHeight(GuiContainer gui) {
return gui.height - getMarginTop(gui) - PADDING;
return new Rectangle4i(paddingLeft + PADDING, paddingTop + PADDING, width, height);
}
protected ItemStack getDraggedStackWithQuantity(ItemStack itemStack) {
@@ -661,7 +700,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
}
@Override
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
public List<String> handleTooltip(int mousex, int mousey, List<String> currenttip) {
if (this.grid.getPerPage() == 0 || this.grid.isEmpty()) {
return new ArrayList<>();
@@ -688,7 +727,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
this.recipeChainTooltipLineHandler = null;
}
return super.handleTooltip(gui, mousex, mousey, currenttip);
return super.handleTooltip(mousex, mousey, currenttip);
}
@Override
@@ -714,7 +753,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
}
@Override
public Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
public Map<String, String> handleHotkeys(int mousex, int mousey, Map<String, String> hotkeys) {
final int overRowIndex = this.grid.getHoveredRowIndex(true);
final BookmarksGridSlot slot = getSlotMouseOver(mousex, mousey);
@@ -747,7 +786,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
NEIClientConfig.getKeyName("gui.remove_recipe"),
NEIClientUtils.translate("bookmark.group.remove_recipe"));
if (BookmarkContainerInfo.getBookmarkContainerHandler(gui) != null) {
if (BookmarkContainerInfo.getBookmarkContainerHandler(NEIClientUtils.getGuiContainer()) != null) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark_pull_items"),
NEIClientUtils.translate("bookmark.group.pull_items"));
@@ -844,7 +883,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
}
}
return hotkeys;
return super.handleHotkeys(mousex, mousey, hotkeys);
}
private List<String> recipeChainTooltip(int groupId, List<String> currenttip) {
@@ -881,13 +920,13 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
}
@Override
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
List<String> currenttip) {
public List<String> handleItemTooltip(ItemStack itemstack, int mousex, int mousey, List<String> currenttip) {
final BookmarksGridSlot slot = this.grid.getSlotMouseOver(mousex, mousey);
if (slot != null) {
if (slot.isIngredient() && slot.getRecipeId() != null && slot.getBookmarkItem().permutations.size() > 1) {
if (slot.getType() == BookmarkItemType.INGREDIENT && slot.getRecipeId() != null
&& slot.getBookmarkItem().permutations.size() > 1) {
RecipeId recipeId = slot.getRecipeId();
if (recipeId == null) {
@@ -957,7 +996,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
@Override
public boolean onMouseWheel(int shift, int mousex, int mousey) {
if (!inEditingState() && new Rectangle4i(
if ((!inEditingState() || this.sortableGroup != null) && new Rectangle4i(
namespacePrev.x,
namespacePrev.y,
namespaceNext.x + namespaceNext.w - namespacePrev.x,
@@ -985,7 +1024,8 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
if (NEIClientUtils.altKey()) {
multiplier = NEIClientConfig.showItemQuantityWidget() ? NEIClientConfig.getItemQuantity() : 0;
if (multiplier == 0) {
multiplier = slot.getItemStack().getMaxStackSize();
multiplier = StackInfo.itemStackToNBT(slot.getItemStack()).hasKey("gtFluidName") ? 144
: slot.getItemStack().getMaxStackSize();
}
}
@@ -1147,12 +1187,25 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
}
if (!items.isEmpty()) {
containerHandler.pullBookmarkItemsFromContainer(guiContainer, items);
final int helmStackIndex = FastTransferManager.dropHeldItem(guiContainer);
if (guiContainer.mc.thePlayer.inventory.getItemStack() == null) {
containerHandler.pullBookmarkItemsFromContainer(guiContainer, items);
if (helmStackIndex != -1) {
FastTransferManager.clickSlot(guiContainer, helmStackIndex, 0, 0);
}
}
}
return true;
}
public void clearTooltips() {
this.acceptsFollowingTooltipLineHandler = null;
this.recipeChainTooltipLineHandler = null;
}
@Deprecated
public void addItem(ItemStack stack, boolean saveSize) {
addItem(saveSize ? stack : StackInfo.withAmount(stack, 0));
@@ -1174,7 +1227,10 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
&& !handlerName.isEmpty()
&& ingredients != null
&& !ingredients.isEmpty()) {
addRecipe(Recipe.of(Arrays.asList(stack), handlerName, ingredients), BookmarkGrid.DEFAULT_GROUP_ID);
addRecipe(
Recipe.of(Arrays.asList(stack), handlerName, ingredients),
saveSize ? 1 : 0,
BookmarkGrid.DEFAULT_GROUP_ID);
} else {
addItem(stack, saveSize);
}
@@ -1188,7 +1244,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
@Deprecated
public void addRecipe(BookmarkRecipe recipe, boolean saveSize, int groupId) {
addRecipe(recipe.getRecipe(), groupId);
addRecipe(recipe.getRecipe(), saveSize ? 1 : 0, groupId);
}
@Deprecated
@@ -1210,7 +1266,7 @@ public class BookmarkPanel extends PanelWidget<BookmarkGrid> {
@Deprecated
public BookmarkRecipeId getBookmarkRecipeId(int itemIndex) {
BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
return item == null || item.isIngredient || item.recipeId == null ? null
return item == null || item.type == BookmarkItemType.INGREDIENT || item.recipeId == null ? null
: new BookmarkRecipeId(item.recipeId.getHandleName(), item.recipeId.getIngredients());
}
+1 -1
View File
@@ -15,7 +15,7 @@ public abstract class Button extends Widget {
}
public int contentWidth() {
return getRenderIcon() == null ? getStringWidth(label) : getRenderIcon().width;
return getRenderIcon() == null ? getStringWidth(getRenderLabel()) : getRenderIcon().width;
}
@Override
@@ -1,10 +1,13 @@
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.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
@@ -21,10 +24,13 @@ import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiErrorScreen;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiSelectWorld;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.resources.IResource;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.launchwrapper.Launch;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.client.event.GuiOpenEvent;
import net.minecraftforge.client.event.RenderWorldLastEvent;
@@ -37,7 +43,6 @@ import com.google.common.collect.Lists;
import codechicken.core.ClassDiscoverer;
import codechicken.core.ClientUtils;
import codechicken.core.GuiModListScroll;
import codechicken.lib.packet.PacketCustom;
import codechicken.nei.api.API;
import codechicken.nei.api.IConfigureNEI;
@@ -147,6 +152,8 @@ public class ClientHandler {
loadHeightHackHandlers();
loadHiddenHandlers();
loadEnableAutoFocus();
loadGuiCraftablesBlacklist();
loadDefaultBookmarkContainers();
ItemInfo.preInit();
StackInfo.loadGuidFilters();
}
@@ -164,11 +171,34 @@ public class ClientHandler {
}, callback);
}
public static void loadSettingsFile(String resource, BiConsumer<File, FileWriter> createDefault,
public static boolean loadSettingsResource(String resource, Consumer<Stream<String>> callback) {
final ResourceLocation location = new ResourceLocation("nei", resource);
try {
final IResource res = Minecraft.getMinecraft().getResourceManager().getResource(location);
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(res.getInputStream(), StandardCharsets.UTF_8))) {
NEIClientConfig.logger.info("Loading '{}' from jar {}", resource, location);
callback.accept(
IOUtils.readLines(reader).stream()
.map(line -> line.contains("#") ? line.substring(0, line.indexOf('#')) : line)
.map(String::trim).filter(line -> !line.isEmpty()));
return true;
}
} catch (Exception io) {
NEIClientConfig.logger.error("Failed to load '{}' file {}", resource, location);
}
return false;
}
public static boolean loadSettingsFile(String resource, BiConsumer<File, FileWriter> createDefault,
Consumer<Stream<String>> callback) {
File file = new File(NEIClientConfig.configDir, resource);
if (!file.exists()) {
if (!file.exists() && createDefault != null) {
try (FileWriter writer = new FileWriter(file)) {
NEIClientConfig.logger.info("Creating default '{}' {}", resource, file);
createDefault.accept(file, writer);
@@ -177,13 +207,20 @@ public class ClientHandler {
}
}
try (FileReader reader = new FileReader(file)) {
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 '{}' file {}", resource, file, e);
if (file.exists()) {
try (FileReader reader = new FileReader(file)) {
NEIClientConfig.logger.info("Loading '{}' file {}", resource, file);
callback.accept(
IOUtils.readLines(reader).stream()
.map(line -> line.contains("#") ? line.substring(0, line.indexOf('#')) : line)
.map(String::trim).filter(line -> !line.isEmpty()));
return true;
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load '{}' file {}", resource, file, e);
}
}
return false;
}
public static void loadSerialHandlers() {
@@ -208,8 +245,27 @@ public class ClientHandler {
public static void loadEnableAutoFocus() {
loadSettingsFile(
"enableautofocus.cfg",
lines -> AutoFocusWidget.enableAutoFocusPrefixes = lines
.collect(Collectors.toCollection(ArrayList::new)));
lines -> AutoFocusWidget.enableAutoFocusPrefixes = lines.collect(Collectors.toList()));
}
public static void loadGuiCraftablesBlacklist() {
loadSettingsFile(
"guicraftablesblacklist.cfg",
lines -> ItemCraftablesPanel.guiBlacklist = lines.collect(Collectors.toList()));
}
public static void loadDefaultBookmarkContainers() {
loadSettingsFile("defaultbookmarkcontainers.cfg", lines -> {
for (String clazz : lines.collect(Collectors.toList())) {
try {
API.registerBookmarkContainerHandler(
(Class<? extends GuiContainer>) Class.forName(clazz),
new DefaultBookmarkContainerHandler());
} catch (Exception e) {
NEIClientConfig.logger.error("Failed to load class '{}' for defaultbookmarkcontainers.cfg", clazz);
}
}
});
}
public static void loadHiddenItems() {
@@ -219,7 +275,6 @@ public class ClientHandler {
public static void load() {
instance = new ClientHandler();
GuiModListScroll.register("NotEnoughItems");
PacketCustom.assignHandler(NEICPH.channel, new NEICPH());
FMLCommonHandler.instance().bus().register(instance);
MinecraftForge.EVENT_BUS.register(instance);
@@ -1,9 +1,10 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import codechicken.nei.api.IBookmarkContainerHandler;
@@ -12,36 +13,18 @@ public class DefaultBookmarkContainerHandler implements IBookmarkContainerHandle
@Override
public void pullBookmarkItemsFromContainer(GuiContainer guiContainer, ArrayList<ItemStack> bookmarkItems) {
FastTransferManager manager = new FastTransferManager();
LinkedList<ItemStack> containerStacks = manager.saveContainer(guiContainer.inventorySlots);
final List<Slot> slots = guiContainer.inventorySlots.inventorySlots;
final FastTransferManager manager = new FastTransferManager();
for (ItemStack bookmarkItem : bookmarkItems) {
int bookmarkSizeBackup = bookmarkItem.stackSize;
for (int i = 0; i < containerStacks.size() - 4 * 9; i++) { // Last 36 slots are player inventory
ItemStack containerItem = containerStacks.get(i);
if (containerItem == null) {
continue;
}
if (bookmarkItem.isItemEqual(containerItem)) {
if (bookmarkItem.stackSize <= 0) {
break;
}
int transferAmount = Math.min(bookmarkItem.stackSize, containerItem.stackSize);
for (int i = 0; i < slots.size() - 4 * 9; i++) {
final Slot slot = slots.get(i);
if (slot.getHasStack() && bookmarkItem.isItemEqual(slot.getStack())) {
final int transferAmount = Math.min(bookmarkItem.stackSize, slot.getStack().stackSize);
manager.transferItems(guiContainer, i, transferAmount);
bookmarkItem.stackSize -= transferAmount;
if (bookmarkItem.stackSize == 0) {
break;
}
}
}
bookmarkItem.stackSize = bookmarkSizeBackup;
}
}
}
@@ -1,24 +0,0 @@
package codechicken.nei;
import net.minecraft.item.ItemStack;
import codechicken.nei.api.ItemFilter;
public class DoubleFilteredFilter implements ItemFilter {
private ItemFilter filter;
private ItemList.PatternItemFilter patternFilter;
public DoubleFilteredFilter(ItemFilter filter, String itemFilter) {
this.filter = filter;
this.patternFilter = new ItemList.PatternItemFilter(SearchField.getPattern(itemFilter));
}
@Override
public boolean matches(ItemStack item) {
if (filter.matches(item)) {
return patternFilter.matches(item);
}
return false;
}
}
@@ -9,7 +9,9 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
@@ -281,6 +283,27 @@ public class FastTransferManager {
GuiContainerManager.getManager(window).handleSlotClick(slotIndex, button, modifier);
}
public static int dropHeldItem(GuiContainer window) {
final EntityPlayerSP player = window.mc.thePlayer;
final ItemStack held = player.inventory.getItemStack();
if (held == null) return -1;
for (int i = 0; held != null && i < window.inventorySlots.inventorySlots.size(); i++) {
final Slot slot = window.inventorySlots.inventorySlots.get(i);
if (slot.inventory instanceof InventoryPlayer && !slot.getHasStack() && slot.isItemValid(held)) {
clickSlot(window, i, 0, 0);
if (player.inventory.getItemStack() == null) {
return i;
}
}
}
return -1;
}
private boolean fillZoneWithHeldItem(GuiContainer window, int zoneIndex) {
for (int transferTo : slotZones.get(zoneIndex)) {
ItemStack held = NEIClientUtils.getHeldItem();
@@ -8,36 +8,142 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Objects;
import java.util.Set;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import org.apache.commons.io.IOUtils;
import com.google.common.io.Files;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import codechicken.core.CommonUtils;
import codechicken.nei.api.API;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.ICraftingHandler;
import codechicken.nei.recipe.IRecipeHandler;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.RecipeHandlerRef;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.FavoriteStorage;
import codechicken.nei.util.NBTJson;
public class FavoriteRecipes {
private static final Map<NBTTagCompound, RecipeId> items = new HashMap<>();
private static final Map<String, RecipeId> fluids = new HashMap<>();
protected static final class FastKey {
public final ItemStack stack;
private int hash;
public FastKey(ItemStack stack) {
this.stack = stack;
this.hash = 31 + Item.getIdFromItem(stack.getItem());
this.hash = 31 * this.hash + stack.getItemDamage();
}
@Override
public int hashCode() {
return this.hash;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o instanceof FastKey k && this.stack.getItem() == k.stack.getItem()
&& this.stack.getItemDamage() == k.stack.getItemDamage()) {
return this.stack == k.stack || Objects.equals(this.stack.stackTagCompound, k.stack.stackTagCompound);
}
return false;
}
}
private static final RestartableTask singleRecipeFavoritesTask = new RestartableTask(
"Generate Single-Recipe Favorites") {
@Override
public void execute() {
final List<ICraftingHandler> handlers = GuiCraftingRecipe.getCraftingHandlers("all");
final Map<FastKey, RecipeHandlerRef> autogeneratedRecipes = new HashMap<>();
final Set<FastKey> whitelistItems = new HashSet<>(ItemList.items.size());
final FavoriteStorage storage = new FavoriteStorage();
for (ItemStack stack : ItemList.items) {
whitelistItems.add(new FastKey(stack));
}
if (interrupted()) return;
for (ICraftingHandler handler : handlers) {
if (!GuiRecipeTab.getHandlerInfo(handler).getShowFavoritesButton()) continue;
for (int i = 0; i < handler.numRecipes(); i++) {
RecipeHandlerRef ref = null;
for (PositionedStack result : getOutputs(handler, i)) {
ItemStack stack = StackInfo.getItemStackWithMinimumDamage(result.items);
final FastKey key = new FastKey(stack);
if (!whitelistItems.contains(key)) continue;
if (autogeneratedRecipes.get(key) == null) {
if (ref == null) {
ref = RecipeHandlerRef.of(handler, i);
}
autogeneratedRecipes.put(key, ref);
} else {
autogeneratedRecipes.remove(key);
whitelistItems.remove(key);
}
}
}
if (interrupted()) return;
}
final Map<RecipeHandlerRef, RecipeId> recipesCache = new HashMap<>();
for (Map.Entry<FastKey, RecipeHandlerRef> entry : autogeneratedRecipes.entrySet()) {
final RecipeId recipeId = recipesCache
.computeIfAbsent(entry.getValue(), r -> RecipeId.of(r.handler, r.recipeIndex));
storage.add(entry.getKey().stack, recipeId);
}
FavoriteRecipes.autoFavorites = storage;
updateSubsetVisibility();
}
protected List<PositionedStack> getOutputs(IRecipeHandler handler, int recipeIndex) {
final PositionedStack pStackResult = handler.getResultStack(recipeIndex);
return pStackResult != null ? Collections.singletonList(pStackResult) : handler.getOtherStacks(recipeIndex);
}
};
public static final String FAVORITE_ITEM = "FavoriteItem";
private static final FavoriteStorage manualFavorites = new FavoriteStorage();
private static FavoriteStorage autoFavorites = new FavoriteStorage();
private static File favoriteFile;
private static int revision = 0;
static {
API.addSubset("Favorites", FavoriteRecipes::contains);
API.addSubset("Favorites.Manual", manualFavorites::contains);
API.addSubset("Favorites.Generated", stack -> FavoriteRecipes.autoFavorites.contains(stack));
}
private FavoriteRecipes() {}
@@ -63,7 +169,6 @@ public class FavoriteRecipes {
final File defaultFavorites = configFavorites.exists() ? configFavorites : globalFavorites;
if (defaultFavorites.exists()) {
try {
if (favoriteFile.createNewFile()) {
InputStream src = new FileInputStream(defaultFavorites);
@@ -98,7 +203,9 @@ public class FavoriteRecipes {
}
final JsonParser parser = new JsonParser();
items.clear();
boolean hasErrors = false;
manualFavorites.clear();
for (String itemStr : itemStrings) {
@@ -114,85 +221,139 @@ public class FavoriteRecipes {
final RecipeId recipeId = RecipeId.of(jsonObject.getAsJsonObject("recipeId"));
final ItemStack stack = StackInfo.loadFromNBT(itemStackNBT);
if (stack != null) {
final String fluidKey = getFluidKey(stack);
if (fluidKey != null) {
fluids.put(fluidKey, recipeId);
}
if (recipeId == null || stack == null) {
continue;
}
if (FAVORITE_ITEM.equals(recipeId.getHandleName()) || RecipeHandlerRef.of(recipeId) != null) {
manualFavorites.add(stack, recipeId);
} else {
hasErrors = true;
}
items.put(itemStackNBT, recipeId);
}
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
NEIClientConfig.logger.error("Failed to load favorite from json string:\n{}", itemStr);
} catch (Exception e) {
NEIClientConfig.logger.error("Failed to load favorite from json string: {}", itemStr);
hasErrors = true;
}
}
SubsetWidget.updateHiddenItems();
if (hasErrors) {
try {
Files.copy(
favoriteFile,
new File(favoriteFile.getAbsolutePath() + ".backup-" + System.currentTimeMillis()));
NEIClientConfig.logger.info("Backed up invalid favorite file to {}", favoriteFile);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to backup invalid favorite file to {}", favoriteFile, e);
}
save();
}
loadAutoGeneratedRecipes();
}
public static RecipeId getGeneratedFavorite(ItemStack stack) {
if (NEIClientConfig.favoritesEnabled() && stack != null) {
return autoFavorites.getRecipeId(stack);
}
return null;
}
public static ItemStack getGeneratedFavorite(RecipeId recipeId) {
if (NEIClientConfig.favoritesEnabled() && recipeId != null) {
return autoFavorites.getItemStack(recipeId);
}
return null;
}
public static RecipeId getManualFavorite(ItemStack stack) {
if (NEIClientConfig.favoritesEnabled() && stack != null) {
return manualFavorites.getRecipeId(stack);
}
return null;
}
public static ItemStack getManualFavorite(RecipeId recipeId) {
if (NEIClientConfig.favoritesEnabled() && recipeId != null) {
return manualFavorites.getItemStack(recipeId);
}
return null;
}
public static RecipeId getFavorite(ItemStack stack) {
if (NEIClientConfig.favoritesEnabled() && stack != null) {
RecipeId recipeId = items.get(StackInfo.itemStackToNBT(stack, false));
if (recipeId == null) {
recipeId = fluids.get(getFluidKey(stack));
}
return recipeId;
final RecipeId recipeId = manualFavorites.getRecipeId(stack);
return recipeId != null ? recipeId : autoFavorites.getRecipeId(stack);
}
return null;
}
public static ItemStack getFavorite(RecipeId recipeId) {
if (NEIClientConfig.favoritesEnabled()) {
final Optional<Map.Entry<NBTTagCompound, RecipeId>> result = items.entrySet().stream()
.filter(entry -> entry.getValue().equals(recipeId)).findAny();
if (result.isPresent()) {
return StackInfo.loadFromNBT(result.get().getKey());
}
if (NEIClientConfig.favoritesEnabled() && recipeId != null) {
final ItemStack stack = manualFavorites.getItemStack(recipeId);
return stack != null ? stack : autoFavorites.getItemStack(recipeId);
}
return null;
}
public static int size() {
return manualFavorites.size() + autoFavorites.size();
}
public static void reload() {
save();
load();
}
public static boolean containsManual(ItemStack stack) {
return getManualFavorite(stack) != null;
}
public static boolean contains(ItemStack stack) {
return getFavorite(stack) != null;
}
public static void setFavorite(ItemStack stack, RecipeId recipeId) {
final NBTTagCompound itemStackNBT = StackInfo.itemStackToNBT(stack, false);
final String fluidKey = getFluidKey(stack);
if (stack == null) return;
items.entrySet().removeIf(entry -> entry.getKey().equals(itemStackNBT) || entry.getValue().equals(recipeId));
fluids.entrySet().removeIf(entry -> entry.getKey().equals(fluidKey) || entry.getValue().equals(recipeId));
manualFavorites.removeItemStack(stack);
if (recipeId != null) {
items.put(itemStackNBT, recipeId);
if (fluidKey != null) {
fluids.put(fluidKey, recipeId);
}
manualFavorites.removeRecipeId(recipeId);
manualFavorites.add(stack, recipeId);
}
SubsetWidget.updateHiddenItems();
ItemList.updateFilter.restart();
updateSubsetVisibility();
}
private static String getFluidKey(ItemStack stack) {
final FluidStack fluid = StackInfo.getFluid(stack);
public static void loadAutoGeneratedRecipes() {
if (ItemList.loadFinished
&& NEIClientConfig.getBooleanSetting("inventory.favorites.generateSingleRecipeFavorites")) {
singleRecipeFavoritesTask.restart();
} else {
singleRecipeFavoritesTask.stop();
autoFavorites.clear();
if (fluid != null) {
return FluidRegistry.getFluidName(fluid);
updateSubsetVisibility();
}
}
return null;
protected static void updateSubsetVisibility() {
SubsetWidget.updateHiddenItems();
FavoriteRecipes.revision++;
}
public static int getRevision() {
return revision;
}
public static void save() {
@@ -203,7 +364,7 @@ public class FavoriteRecipes {
final List<String> strings = new ArrayList<>();
for (Map.Entry<NBTTagCompound, RecipeId> entry : items.entrySet()) {
for (Map.Entry<NBTTagCompound, RecipeId> entry : manualFavorites.getAllFavorites()) {
try {
final JsonObject line = new JsonObject();
@@ -221,7 +382,7 @@ public class FavoriteRecipes {
try (FileOutputStream output = new FileOutputStream(favoriteFile)) {
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save favorites list to file {}", favoriteFile, e);
NEIClientConfig.logger.error("Failed to save favorites list to file {}", favoriteFile, e);
}
}
@@ -38,6 +38,10 @@ public class FormattedTextField extends GuiTextField {
this.formatter = formatter;
}
public TextFormatter getFormatter() {
return this.formatter;
}
public void setPlaceholder(String placeholder) {
this.placeholder = placeholder;
}
@@ -57,6 +61,11 @@ public class FormattedTextField extends GuiTextField {
super.setFocused(focus);
}
@Override
public void setText(String rawText) {
super.setText(EnumChatFormatting.getTextWithoutFormattingCodes(rawText));
}
@Override
public void setSelectionPos(int p_146199_1_) {
String text = this.getText();
@@ -269,7 +278,7 @@ public class FormattedTextField extends GuiTextField {
}
Tessellator tessellator = Tessellator.instance;
GL11.glColor4f(0.0F, 0.0F, 255.0F, 255.0F);
GL11.glColor4f(0.0F, 0.0F, 1.0F, 1.0F);
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_COLOR_LOGIC_OP);
GL11.glLogicOp(GL11.GL_OR_REVERSE);
@@ -42,13 +42,11 @@ public class HUDRenderer implements IKeyStateTracker {
&& mc.objectMouseOver != null
&& mc.objectMouseOver.typeOfHit == MovingObjectType.BLOCK) {
World world = mc.theWorld;
ItemStack[] items = ItemInfo.getIdentifierItems(world, mc.thePlayer, mc.objectMouseOver)
.toArray(new ItemStack[0]);
final List<ItemStack> items = ItemInfo.getIdentifierItems(world, mc.thePlayer, mc.objectMouseOver);
if (items.length == 0) return;
ItemStack stack = StackInfo.getItemStackWithMinimumDamage(items);
if (items.isEmpty()) return;
final ItemStack stack = StackInfo.getItemStackWithMinimumDamage(items.toArray(new ItemStack[0]));
renderOverlay(stack, ItemInfo.getText(stack, world, mc.thePlayer, mc.objectMouseOver), getPositioning());
}
}
@@ -27,8 +27,8 @@ public class HeldItemHandler implements IContainerInputHandler, IContainerToolti
protected boolean contains(int mousex, int mousey) {
return NEIClientUtils.getHeldItem() != null && !ItemPanels.bookmarkPanel.inEditingState()
&& !AutoCraftingManager.processing()
&& (ItemPanels.bookmarkPanel.contains(mousex, mousey) || ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey));
&& (ItemPanels.bookmarkPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.containsWithSubpanels(mousex, mousey));
}
@Override
@@ -36,7 +36,8 @@ public class HeldItemHandler implements IContainerInputHandler, IContainerToolti
if (contains(mousex, mousey)) {
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")) {
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")
|| NEIClientUtils.mc().playerController.isInCreativeMode()) {
if (button == 1) {
NEIClientUtils.decreaseSlotStack(-999);
} else {
@@ -101,7 +102,8 @@ public class HeldItemHandler implements IContainerInputHandler, IContainerToolti
if (contains(mousex, mousey)) {
currenttip.clear();
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")) {
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")
|| NEIClientUtils.mc().playerController.isInCreativeMode()) {
currenttip.add(EnumChatFormatting.RED + translate("itempanel.deleteItem"));
}
}
@@ -0,0 +1,147 @@
package codechicken.nei;
import net.minecraft.client.gui.GuiRepair;
import net.minecraft.client.gui.inventory.GuiBrewingStand;
import net.minecraft.client.gui.inventory.GuiCrafting;
import net.minecraft.client.gui.inventory.GuiFurnace;
import net.minecraft.client.gui.inventory.GuiInventory;
import net.minecraft.nbt.NBTTagCompound;
import codechicken.nei.api.API;
import codechicken.nei.recipe.BrewingOverlayHandler;
import codechicken.nei.recipe.BrewingRecipeHandler;
import codechicken.nei.recipe.DefaultOverlayHandler;
import codechicken.nei.recipe.FireworkRecipeHandler;
import codechicken.nei.recipe.FuelRecipeHandler;
import codechicken.nei.recipe.FurnaceRecipeHandler;
import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.recipe.ProfilerRecipeHandler;
import codechicken.nei.recipe.RepairOverlayHandler;
import codechicken.nei.recipe.RepairRecipeHandler;
import codechicken.nei.recipe.ShapedRecipeHandler;
import codechicken.nei.recipe.ShapelessRecipeHandler;
import cpw.mods.fml.common.event.FMLInterModComms;
public class IMCForNEI {
public static void IMCSender() {
API.registerRecipeHandler(new ShapedRecipeHandler());
API.registerUsageHandler(new ShapedRecipeHandler());
sendHandler("codechicken.nei.recipe.ShapedRecipeHandler", "minecraft:crafting_table");
API.registerRecipeHandler(new ShapelessRecipeHandler());
API.registerUsageHandler(new ShapelessRecipeHandler());
sendHandler("codechicken.nei.recipe.ShapelessRecipeHandler", "minecraft:crafting_table");
API.registerRecipeHandler(new FireworkRecipeHandler());
API.registerUsageHandler(new FireworkRecipeHandler());
sendHandler("codechicken.nei.recipe.FireworkRecipeHandler", "minecraft:fireworks");
API.registerRecipeHandler(new FurnaceRecipeHandler());
API.registerUsageHandler(new FurnaceRecipeHandler());
sendHandler("codechicken.nei.recipe.FurnaceRecipeHandler", "minecraft:furnace");
API.registerRecipeHandler(new BrewingRecipeHandler());
API.registerUsageHandler(new BrewingRecipeHandler());
sendHandler("codechicken.nei.recipe.BrewingRecipeHandler", "minecraft:brewing_stand");
API.registerRecipeHandler(new FuelRecipeHandler());
API.registerUsageHandler(new FuelRecipeHandler());
sendFuelRecipeHandler();
API.registerRecipeHandler(new InformationHandler());
API.registerUsageHandler(new InformationHandler());
sendInformationHandler();
API.registerRecipeHandler(new RepairRecipeHandler());
API.registerUsageHandler(new RepairRecipeHandler());
sendRepairHandler();
sendCatalyst("repair", "minecraft:anvil");
API.registerGuiOverlay(GuiCrafting.class, "crafting");
API.registerGuiOverlay(GuiInventory.class, "crafting2x2", 63, 20);
API.registerGuiOverlay(GuiFurnace.class, "smelting");
API.registerGuiOverlay(GuiFurnace.class, "fuel");
API.registerGuiOverlay(GuiBrewingStand.class, "brewing");
API.registerGuiOverlay(GuiRepair.class, "repair", 2, 37);
API.registerGuiOverlayHandler(GuiCrafting.class, new DefaultOverlayHandler(), "crafting");
API.registerGuiOverlayHandler(GuiInventory.class, new DefaultOverlayHandler(63, 20), "crafting2x2");
API.registerGuiOverlayHandler(GuiBrewingStand.class, new BrewingOverlayHandler(), "brewing");
API.registerGuiOverlayHandler(GuiRepair.class, new RepairOverlayHandler(), "repair");
API.registerRecipeHandler(new ProfilerRecipeHandler(true));
API.registerUsageHandler(new ProfilerRecipeHandler(false));
}
private static void sendHandler(String aName, String aBlock) {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handler", aName);
aNBT.setString("modName", "Minecraft");
aNBT.setString("modId", "minecraft");
aNBT.setString("itemName", aBlock);
aNBT.setInteger("handlerWidth", 166);
aNBT.setInteger("handlerHeight", 65);
aNBT.setBoolean("multipleWidgetsAllowed", true);
aNBT.setInteger("yShift", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
}
private static void sendRepairHandler() {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handler", "codechicken.nei.recipe.RepairRecipeHandler");
aNBT.setString("modName", "Minecraft");
aNBT.setString("modId", "minecraft");
aNBT.setString("itemName", "minecraft:anvil");
aNBT.setInteger("handlerHeight", 39);
aNBT.setInteger("handlerWidth", 166);
aNBT.setBoolean("multipleWidgetsAllowed", true);
aNBT.setBoolean("showFavoritesButton", false);
aNBT.setInteger("yShift", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
}
private static void sendFuelRecipeHandler() {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handler", "codechicken.nei.recipe.FuelRecipeHandler");
aNBT.setString("modName", "Minecraft");
aNBT.setString("modId", "minecraft");
aNBT.setString("imageResource", "nei:textures/nei_tabbed_sprites.png");
aNBT.setInteger("imageX", 80);
aNBT.setInteger("imageY", 0);
aNBT.setInteger("imageWidth", 14);
aNBT.setInteger("imageHeight", 14);
aNBT.setInteger("handlerHeight", 65);
aNBT.setInteger("handlerWidth", 166);
aNBT.setBoolean("multipleWidgetsAllowed", true);
aNBT.setInteger("yShift", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
}
private static void sendInformationHandler() {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handler", "codechicken.nei.recipe.InformationHandler");
aNBT.setString("modName", "Not Enough Items");
aNBT.setString("modId", "nei");
aNBT.setString("imageResource", "nei:textures/nei_tabbed_sprites.png");
aNBT.setInteger("imageX", 96);
aNBT.setInteger("imageY", 0);
aNBT.setInteger("imageWidth", 16);
aNBT.setInteger("imageHeight", 16);
aNBT.setInteger("handlerHeight", 65);
aNBT.setInteger("handlerWidth", 166);
aNBT.setBoolean("multipleWidgetsAllowed", true);
aNBT.setInteger("yShift", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
}
private static void sendCatalyst(String aName, String aStack) {
NBTTagCompound aNBT = new NBTTagCompound();
aNBT.setString("handlerID", aName);
aNBT.setString("itemName", aStack);
aNBT.setInteger("priority", 0);
FMLInterModComms.sendMessage("NotEnoughItems", "registerCatalystInfo", aNBT);
}
}
@@ -0,0 +1,313 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.ItemsGrid.MouseContext;
import codechicken.nei.NEIClientUtils.Alignment;
import codechicken.nei.recipe.AutoCraftingManager;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.ICraftingHandler;
import codechicken.nei.recipe.IRecipeHandler;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.RecipeInfo;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.ReadableNumberConverter;
public class ItemCraftablesPanel
extends AbstractSubpanel<ItemsGrid<ItemCraftablesPanel.CraftablesGridSlot, MouseContext>> {
public static class CraftablesGridSlot extends ItemsGridSlot {
protected final long realAmount;
protected final boolean isFluidDisplay;
protected final RecipeId recipeId;
public CraftablesGridSlot(int slotIndex, int itemIndex, ItemStack itemStack, RecipeId recipeId) {
super(slotIndex, itemIndex, itemStack);
this.realAmount = StackInfo.getAmount(itemStack);
this.isFluidDisplay = StackInfo.itemStackToNBT(itemStack).hasKey("gtFluidName");
this.recipeId = recipeId;
}
@Override
public RecipeId getRecipeId() {
return this.recipeId;
}
@Override
public <M extends MouseContext> void afterDraw(Rectangle4i rect, M mouseContext) {
drawStackSize(rect);
}
protected void drawStackSize(Rectangle4i rect) {
long stackSize = this.realAmount;
if (stackSize > 1) {
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
String amountString = "";
if (stackSize < 10_000) {
amountString = String.valueOf(stackSize);
} else {
amountString = ReadableNumberConverter.INSTANCE.toWideReadableForm(stackSize);
}
if (this.isFluidDisplay) {
amountString += "L";
}
NEIClientUtils.drawNEIOverlayText(
amountString,
new Rectangle4i(rect.x + 1, rect.y + 1, rect.w - 2, rect.h - 2),
panelFactor,
0xFFFFFF,
true,
this.isFluidDisplay ? Alignment.BottomLeft : Alignment.BottomRight);
}
}
}
public static List<String> guiBlacklist = new ArrayList<>();
private final int MIN_DELAY = 600;
private Map<String, ArrayList<ICraftingHandler>> identHandlers = new HashMap<>();
private Map<ItemStack, RecipeId> availableRecipes = new HashMap<>();
private GuiContainer lastGuiContainer = null;
private ItemStackAmount lastPlayerInventory = null;
private long lastPlayerInventorySync = 0;
private int lastFavoritesCount = 0;
public ItemCraftablesPanel() {
this.grid = new ItemsGrid<>() {
protected List<CraftablesGridSlot> gridMask;
@Override
protected void onGridChanged() {
this.gridMask = null;
super.onGridChanged();
}
@Override
public List<CraftablesGridSlot> getMask() {
if (this.gridMask == null) {
final int maxSlotIndex = this.rows * this.columns;
final List<CraftablesGridSlot> gridMask = new ArrayList<>();
this.realItems.clear();
if (!ItemCraftablesPanel.this.availableRecipes.isEmpty()) {
final List<Map.Entry<ItemStack, RecipeId>> entries = ItemCraftablesPanel.this.availableRecipes
.entrySet().stream()
.sorted(
Map.Entry.comparingByKey(
Comparator.comparing(FavoriteRecipes::containsManual)
.thenComparing(FavoriteRecipes::contains).reversed()
.thenComparing(ItemSorter.instance)))
.limit(maxSlotIndex).collect(Collectors.toList());
int slotIndex = 0;
int itemIndex = 0;
for (Map.Entry<ItemStack, RecipeId> entry : entries) {
if (!isInvalidSlot(slotIndex)) {
this.realItems.add(entry.getKey());
gridMask.add(
new CraftablesGridSlot(
slotIndex,
itemIndex++,
entry.getKey(),
entry.getValue()));
}
if (slotIndex++ >= maxSlotIndex) {
break;
}
}
this.gridMask = gridMask;
} else {
this.gridMask = Collections.emptyList();
}
ItemCraftablesPanel.this.updateLinePadding();
}
return this.gridMask;
}
@Override
protected MouseContext getMouseContext(int mousex, int mousey) {
final ItemsGridSlot hovered = getSlotMouseOver(mousex, mousey);
if (hovered != null) {
return new MouseContext(
hovered.slotIndex,
hovered.slotIndex / this.columns,
hovered.slotIndex % this.columns);
}
return null;
}
};
}
@Override
protected ItemStack getDraggedStackWithQuantity(ItemStack itemStack) {
return ItemQuantityField.prepareStackWithQuantity(itemStack, StackInfo.getAmount(itemStack));
}
@Override
public void draw(int mousex, int mousey) {
if (!this.availableRecipes.isEmpty()) {
super.draw(mousex, mousey);
}
}
@Override
public int setPanelWidth(int width) {
if (getGuiContainer() != this.lastGuiContainer) updateCraftables();
final int columns = width / ItemsGrid.SLOT_SIZE;
final int useRows = NEIClientConfig.getIntSetting("inventory.craftables.useRows");
final int rows = (int) Math.min(Math.ceil(this.availableRecipes.size() * 1f / columns), useRows);
this.w = width;
this.h = 8 + ItemsGrid.SLOT_SIZE * Math.max(rows, 1);
return rows;
}
public void update() {
this.splittingLineColor = NEIClientConfig.getSetting("inventory.craftables.color").getHexValue();
updateCraftables();
super.update();
}
private void updateCraftables() {
if (!NEIClientConfig.showCraftablesPanelWidget()) {
clearCraftables();
} else if (this.lastPlayerInventory == null
|| Math.abs(System.currentTimeMillis() - this.lastPlayerInventorySync) >= MIN_DELAY) {
final GuiContainer firstGui = getGuiContainer();
this.lastPlayerInventorySync = System.currentTimeMillis();
if (firstGui != null && !ItemCraftablesPanel.guiBlacklist.contains(firstGui.getClass().getName())) {
final boolean showOnlyFavorites = NEIClientConfig
.getBooleanSetting("inventory.craftables.favoritesOnly");
final ItemStackAmount inv = AutoCraftingManager.getInventoryItems(firstGui);
if (this.lastGuiContainer != firstGui
|| showOnlyFavorites && this.lastFavoritesCount != FavoriteRecipes.size()
|| !inv.equals(this.lastPlayerInventory)) {
this.lastPlayerInventory = inv;
this.lastGuiContainer = firstGui;
this.lastFavoritesCount = FavoriteRecipes.size();
this.availableRecipes = generateCraftables(firstGui);
this.grid.onGridChanged();
}
} else {
clearCraftables();
}
}
}
private void clearCraftables() {
if (!this.availableRecipes.isEmpty()) {
this.availableRecipes = Collections.emptyMap();
this.lastPlayerInventory = null;
this.grid.onGridChanged();
}
}
private GuiContainer getGuiContainer() {
final GuiContainer firstGui = NEIClientUtils.getGuiContainer();
return (firstGui instanceof GuiRecipe gui) ? gui.firstGui : firstGui;
}
private Map<ItemStack, RecipeId> generateCraftables(GuiContainer firstGui) {
final List<IRecipeHandler> availableHandlers = getAvailableHandlers(firstGui);
final Map<ItemStack, RecipeId> availableRecipes = new HashMap<>();
if (!availableHandlers.isEmpty()) {
final List<ItemStack> invStacks = ItemCraftablesPanel.this.lastPlayerInventory.values();
for (IRecipeHandler handler : availableHandlers) {
availableRecipes.putAll(filterHandlerRecipes(handler, firstGui, invStacks));
}
}
return availableRecipes;
}
private List<IRecipeHandler> getAvailableHandlers(GuiContainer firstGui) {
final List<IRecipeHandler> availableHandlers = new ArrayList<>();
for (String ident : RecipeInfo.getOverlayHandlerIdents(firstGui)) {
availableHandlers.addAll(identHandlers.computeIfAbsent(ident, GuiCraftingRecipe::getCraftingHandlers));
}
return availableHandlers;
}
private Map<ItemStack, RecipeId> filterHandlerRecipes(IRecipeHandler handler, GuiContainer firstGui,
List<ItemStack> invStacks) {
final Map<ItemStack, RecipeId> availableRecipes = new HashMap<>();
final boolean showOnlyFavorites = NEIClientConfig.getBooleanSetting("inventory.craftables.favoritesOnly");
IntStream.range(0, handler.numRecipes()).parallel().forEach(recipeIndex -> {
if (existsIngredients(firstGui, handler.getIngredientStacks(recipeIndex), invStacks)) {
final Recipe recipe = Recipe.of(handler, recipeIndex);
if (!recipe.getResults().isEmpty()
&& (!showOnlyFavorites || FavoriteRecipes.getFavorite(recipe.getRecipeId()) != null)) {
synchronized (availableRecipes) {
availableRecipes.put(recipe.getResult(), recipe.getRecipeId());
}
}
}
});
return availableRecipes;
}
private boolean existsIngredients(GuiContainer firstGui, List<PositionedStack> ingredients,
List<ItemStack> invStacks) {
final Map<ItemStack, Integer> usedItems = new HashMap<>();
for (PositionedStack pStack : ingredients) {
final ItemStack used = invStacks.stream().filter(
is -> usedItems.getOrDefault(is, is.stackSize) >= pStack.item.stackSize && pStack.contains(is))
.findAny().orElse(null);
if (used != null) {
usedItems.put(used, usedItems.getOrDefault(used, used.stackSize) - pStack.item.stackSize);
} else {
return false;
}
}
return !usedItems.isEmpty();
}
}
@@ -3,85 +3,106 @@ package codechicken.nei;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.ItemsGrid.MouseContext;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.GuiUsageRecipe;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
public class ItemHistoryPanel extends Widget implements IContainerTooltipHandler {
public class ItemHistoryPanel extends AbstractSubpanel<ItemsGrid<ItemHistoryPanel.HistoryGridSlot, MouseContext>> {
protected int mouseDownItemIndex = -1;
public static class HistoryGridSlot extends ItemsGridSlot {
protected ItemsGrid<ItemsGridSlot, MouseContext> grid = new ItemsGrid<>() {
protected List<ItemsGridSlot> gridMask;
@Override
protected void onGridChanged() {
this.gridMask = null;
super.onGridChanged();
public HistoryGridSlot(int slotIndex, int itemIndex, ItemStack item) {
super(slotIndex, itemIndex, item);
}
@Override
public List<ItemsGridSlot> getMask() {
if (this.gridMask == null) {
this.gridMask = new ArrayList<>();
for (int slotIndex = 0; slotIndex < Math.min(size(), this.rows * this.columns); slotIndex++) {
this.gridMask.add(new ItemsGridSlot(slotIndex, slotIndex, getItem(slotIndex)));
}
}
return this.gridMask;
public RecipeId getRecipeId() {
return FavoriteRecipes.getFavorite(this.item);
}
@Override
protected MouseContext getMouseContext(int mousex, int mousey) {
final ItemsGridSlot hovered = getSlotMouseOver(mousex, mousey);
if (hovered != null) {
return new MouseContext(
hovered.slotIndex,
hovered.slotIndex / this.columns,
hovered.slotIndex % this.columns);
}
return null;
}
};
public boolean isEmpty() {
return grid.isEmpty();
}
public ItemHistoryPanel() {
this.grid = new ItemsGrid<>() {
protected List<HistoryGridSlot> gridMask;
@Override
protected void onGridChanged() {
this.gridMask = null;
super.onGridChanged();
}
@Override
public List<HistoryGridSlot> getMask() {
if (this.gridMask == null) {
this.gridMask = new ArrayList<>();
int itemIndex = 0;
for (int slotIndex = 0; slotIndex < this.rows * this.columns && itemIndex < size(); slotIndex++) {
if (!isInvalidSlot(slotIndex)) {
this.gridMask.add(new HistoryGridSlot(slotIndex, itemIndex, getItem(itemIndex)));
itemIndex++;
}
}
ItemHistoryPanel.this.updateLinePadding();
}
return this.gridMask;
}
@Override
protected MouseContext getMouseContext(int mousex, int mousey) {
final HistoryGridSlot hovered = getSlotMouseOver(mousex, mousey);
if (hovered != null) {
return new MouseContext(
hovered.slotIndex,
hovered.slotIndex / this.columns,
hovered.slotIndex % this.columns);
}
return null;
}
};
}
@Override
protected ItemStack getDraggedStackWithQuantity(ItemStack itemStack) {
return ItemQuantityField.prepareStackWithQuantity(itemStack, 0);
}
@Override
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());
if (this.grid.size() > 0) {
super.draw(mousex, mousey);
}
}
this.grid.draw(mousex, mousey);
@Override
public int setPanelWidth(int width) {
final int columns = width / ItemsGrid.SLOT_SIZE;
final int useRows = NEIClientConfig.getIntSetting("inventory.history.useRows");
final int rows = (int) Math.min(Math.ceil(this.grid.size() * 1f / columns), useRows);
this.w = width;
this.h = 8 + ItemsGrid.SLOT_SIZE * Math.max(rows, 1);
return rows;
}
public void update() {
this.grid.update();
this.splittingLineColor = NEIClientConfig.getSetting("inventory.history.color").getHexValue();
super.update();
}
public void addItem(ItemStack stack) {
if (stack != null) {
ItemStack is = StackInfo.loadFromNBT(StackInfo.itemStackToNBT(stack), 0);
ItemStack is = StackInfo.withAmount(stack, 0);
this.grid.realItems.removeIf(historyStack -> StackInfo.equalItemAndNBT(historyStack, stack, true));
this.grid.realItems.add(0, is);
@@ -94,124 +115,4 @@ public class ItemHistoryPanel extends Widget implements IContainerTooltipHandler
}
}
public void resize(GuiContainer gui) {
this.grid.setGridSize(x, y + 4, w, h - 8);
this.grid.refresh(gui);
}
@Override
public ItemStack getStackMouseOver(int mousex, int mousey) {
final ItemsGridSlot slot = getSlotMouseOver(mousex, mousey);
return slot == null ? null : slot.getItemStack();
}
public ItemsGridSlot getSlotMouseOver(int mousex, int mousey) {
return grid.getSlotMouseOver(mousex, mousey);
}
private void drawSplittingArea(int x, int y, int width, int height, int color) {
float alpha = (color >> 24 & 255) / 255.0F;
float red = (color >> 16 & 255) / 255.0F;
float green = (color >> 8 & 255) / 255.0F;
float blue = (color & 255) / 255.0F;
GL11.glPushMatrix();
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_LINE_STIPPLE);
GL11.glColor4f(red, green, blue, alpha);
GL11.glLineWidth(2F);
GL11.glLineStipple(2, (short) 0x00FF);
GL11.glBegin(GL11.GL_LINE_LOOP);
GL11.glVertex2i(x, y);
GL11.glVertex2i(x + width, y);
GL11.glVertex2i(x + width, y + height);
GL11.glVertex2i(x, y + height);
GL11.glEnd();
GL11.glLineStipple(1, (short) 0xFFFF);
GL11.glLineWidth(1F);
GL11.glDisable(GL11.GL_LINE_STIPPLE);
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glColor4f(1F, 1F, 1F, 1F);
GL11.glPopMatrix();
}
@Override
public void mouseDragged(int mousex, int mousey, int button, long heldTime) {
if (this.mouseDownItemIndex >= 0 && ItemPanels.itemPanel.draggedStack == null
&& NEIClientUtils.getHeldItem() == null
&& NEIClientConfig.hasSMPCounterPart()) {
final ItemsGridSlot mouseOverSlot = getSlotMouseOver(mousex, mousey);
if (mouseOverSlot == null || mouseOverSlot.itemIndex != this.mouseDownItemIndex || heldTime > 500) {
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(
this.grid.getItem(this.mouseDownItemIndex));
this.mouseDownItemIndex = -1;
}
}
}
@Override
public boolean handleClick(int mousex, int mousey, int button) {
if (handleClickExt(mousex, mousey, button)) return true;
final ItemsGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
if (hoverSlot != null) {
if (button == 2) {
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(hoverSlot.getItemStack());
} else {
mouseDownItemIndex = hoverSlot.itemIndex;
}
return true;
}
return false;
}
protected ItemStack getDraggedStackWithQuantity(ItemStack itemStack) {
return ItemQuantityField.prepareStackWithQuantity(itemStack, 0);
}
public ItemStack getStackMouseOverWithQuantity(int mousex, int mousey) {
final ItemStack hoverSlot = getStackMouseOver(mousex, mousey);
return hoverSlot != null ? getDraggedStackWithQuantity(hoverSlot) : null;
}
@Override
public void mouseUp(int mousex, int mousey, int button) {
final ItemsGridSlot hoverSlot = getSlotMouseOver(mousex, mousey);
if (hoverSlot != null && hoverSlot.itemIndex == this.mouseDownItemIndex
&& ItemPanels.itemPanel.draggedStack == null) {
if (NEIController.manager.window instanceof GuiRecipe || NEIClientUtils.shiftKey()
|| !NEIClientConfig.canCheatItem(hoverSlot.getItemStack())) {
if (button == 0) {
GuiCraftingRecipe.openRecipeGui("item", hoverSlot.getItemStack().copy());
} else if (button == 1) {
GuiUsageRecipe.openRecipeGui("item", hoverSlot.getItemStack().copy());
}
} else {
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.getItemStack()), button, -1);
}
}
this.mouseDownItemIndex = -1;
}
}
+82 -4
View File
@@ -16,10 +16,12 @@ import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import net.minecraft.client.Minecraft;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IIcon;
import net.minecraftforge.fluids.IFluidContainerItem;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
@@ -28,7 +30,12 @@ import codechicken.nei.ThreadOperationTimer.TimeoutException;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.recipe.RecipeHandlerRef;
import codechicken.nei.recipe.RepairRecipeHandler;
import codechicken.nei.search.TooltipFilter;
import codechicken.nei.util.ItemUntranslator;
import cpw.mods.fml.common.FMLLog;
public class ItemList {
@@ -96,7 +103,13 @@ public class ItemList {
public boolean matches(ItemStack item) {
String displayName = EnumChatFormatting.getTextWithoutFormattingCodes(item.getDisplayName());
if (displayName != null && !displayName.isEmpty() && pattern.matcher(displayName).find()) {
if (displayName != null && !displayName.isEmpty() && this.pattern.matcher(displayName).find()) {
return true;
}
displayName = ItemUntranslator.getInstance().getItemStackDisplayName(item);
if (!displayName.isEmpty() && this.pattern.matcher(displayName).find()) {
return true;
}
@@ -104,7 +117,7 @@ public class ItemList {
displayName = EnumChatFormatting
.getTextWithoutFormattingCodes(item.getItem().getItemStackDisplayName(item));
return displayName != null && !displayName.isEmpty() && pattern.matcher(displayName).find();
return displayName != null && !displayName.isEmpty() && this.pattern.matcher(displayName).find();
}
return false;
@@ -289,11 +302,69 @@ public class ItemList {
.collect(Collectors.toList());
}
// For optimization it generate itemslist, permutations, orders & collapsibleitems
private void runChecked(ItemStack stack, Runnable action, String reason) {
int hashOld = 0;
if (stack.hasTagCompound()) {
hashOld = stack.stackTagCompound.hashCode();
}
action.run();
if (stack.hasTagCompound() && hashOld != stack.stackTagCompound.hashCode()) {
FMLLog.warning(
"NEI: Forced tag update with reason (" + reason
+ ") for "
+ stack
+ "("
+ stack.getItem()
+ ")");
}
}
private void forceTagCompoundInitialization(ItemStack stack) {
Item item = stack.getItem();
if (item == null) {
return;
}
if (item instanceof IFluidContainerItem) {
IFluidContainerItem fluidItem = (IFluidContainerItem) item;
runChecked(stack, () -> fluidItem.getFluid(stack), "getFluid");
}
runChecked(stack, () -> item.isDamaged(stack), "isDamaged");
runChecked(stack, () -> item.getDamage(stack), "getDamage");
runChecked(stack, () -> item.showDurabilityBar(stack), "showDurabilityBar");
runChecked(stack, () -> item.getAttributeModifiers(stack), "getAttributeModifiers");
runChecked(stack, () -> item.getDurabilityForDisplay(stack), "getDurabilityForDisplay");
runChecked(stack, () -> item.getItemStackLimit(stack), "getItemStackLimit");
runChecked(stack, () -> item.getToolClasses(stack), "getToolClasses");
runChecked(stack, () -> item.getUnlocalizedNameInefficiently(stack), "getUnlocalizedNameInefficiently");
runChecked(stack, () -> item.hasEffect(stack), "hasEffect");
runChecked(stack, () -> item.getDigSpeed(stack, Blocks.stone, 0), "getDigSpeed");
/*
* unused... for now runChecked(stack, () -> GameRegistry.getFuelValue(stack), "getFuelValue");
* runChecked(stack, () -> item.getUnlocalizedName(stack), "getUnlocalizedName"); runChecked(stack, () ->
* item.doesContainerItemLeaveCraftingGrid(stack), "doesContainerItemLeaveCraftingGrid"); runChecked(stack,
* () -> item.getItemUseAction(stack), "getItemUseAction"); runChecked(stack, () ->
* item.getMaxItemUseDuration(stack), "getMaxItemUseDuration"); runChecked(stack, () ->
* item.getPotionEffect(stack), "getPotionEffect"); runChecked(stack, () -> item.isPotionIngredient(stack),
* "isPotionIngredient"); runChecked(stack, () -> item.getRarity(stack), "getRarity"); runChecked(stack, ()
* -> item.hasCustomEntity(stack), "hasCustomEntity"); runChecked(stack, () ->
* item.getSmeltingExperience(stack), "getSmeltingExperience"); runChecked(stack, () ->
* item.getMaxDamage(stack), "getMaxDamage"); runChecked(stack, () -> item.getDamage(stack), "getDamage");
* runChecked(stack, stack::isItemDamaged, "isItemDamaged"); runChecked(stack, () -> item.hasEffect(stack,
* 0), "hasEffect"); runChecked(stack, () -> item.getItemEnchantability(stack), "getItemEnchantability");
* runChecked(stack, () -> item.isBeaconPayment(stack), "isBeaconPayment"); runChecked(stack, () ->
* item.getDamage(stack), "getDamage"); runChecked(stack, () -> item.getDamage(stack), "getDamage");
* runChecked(stack, () -> item.getDamage(stack), "getDamage");
*/
}
// Generate itemlist, permutations, orders, collapsibleitems, and informationhandler stacks
@Override
@SuppressWarnings("unchecked")
public void execute() {
if (!NEIClientConfig.isEnabled()) return;
if (!NEIClientConfig.isEnabled() || NEIClientUtils.mc().thePlayer == null) return;
ThreadOperationTimer timer = getTimer(NEIClientConfig.getItemLoadingTimeout());
LayoutManager.itemsLoaded = true;
@@ -303,6 +374,7 @@ public class ItemList {
ItemSorter.instance.ordering.clear();
CollapsibleItems.clearCache();
TooltipFilter.clearCache();
InformationHandler.clearCache();
List<ItemStack> items = new ArrayList<>();
ListMultimap<Item, ItemStack> itemMap = ArrayListMultimap.create();
@@ -327,8 +399,11 @@ public class ItemList {
items.add(stack);
}
forceTagCompoundInitialization(stack);
CollapsibleItems.putItem(stack);
TooltipFilter.getSearchTooltip(stack);
InformationHandler.populateStacks(stack);
}
}
@@ -359,6 +434,9 @@ public class ItemList {
loadFinished = true;
RepairRecipeHandler.findRepairRecipesOnceParallel();
RecipeHandlerRef.clearCache();
FavoriteRecipes.reload();
SubsetWidget.updateHiddenItems();
ItemPanels.bookmarkPanel.load();
updateFilter.restart();
+250 -69
View File
@@ -1,8 +1,10 @@
package codechicken.nei;
import java.util.HashMap;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
@@ -15,6 +17,7 @@ import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityMobSpawner;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IIcon;
@@ -26,10 +29,27 @@ import cpw.mods.fml.relauncher.SideOnly;
public class ItemMobSpawner extends ItemBlock {
private static final Map<Integer, EntityLiving> entityHashMap = new HashMap<>();
private static final Map<Integer, String> IDtoNameMap = new HashMap<>();
public static int idPig;
private static boolean loaded;
private static final Map<Integer, EntityLiving> entityHashMap = new ConcurrentHashMap<>();
private static final Map<Integer, String> IDtoNameMap = new ConcurrentHashMap<>();
private static final Map<Class<? extends Entity>, String> ENTITY_CLASS_TO_NAME_CACHE = new ConcurrentHashMap<>();
public static int idPig = 90;
private static volatile boolean loaded = false;
// For asm
public static int placedX;
public static int placedY;
public static int placedZ;
public static void setLastPlacedPosition(int x, int y, int z) {
placedX = x;
placedY = y;
placedZ = z;
}
public static int[] getLastPlacedPosition() {
return new int[] { placedX, placedY, placedZ };
}
public ItemMobSpawner() {
super(Blocks.mob_spawner);
@@ -37,99 +57,260 @@ public class ItemMobSpawner extends ItemBlock {
MinecraftForgeClient.registerItemRenderer(this, new SpawnerRenderer());
}
/**
* These are ASM translated from BlockMobSpawner
*/
public static int placedX;
public static int placedY;
public static int placedZ;
@Override
public IIcon getIconFromDamage(int par1) {
public IIcon getIconFromDamage(int meta) {
return Blocks.mob_spawner.getBlockTextureFromSide(0);
}
public boolean onItemUse(ItemStack itemstack, EntityPlayer entityplayer, World world, int x, int y, int z, int par7,
float par8, float par9, float par10) {
if (super.onItemUse(itemstack, entityplayer, world, x, y, z, par7, par8, par9, par10) && world.isRemote) {
TileEntityMobSpawner tileentitymobspawner = (TileEntityMobSpawner) world
.getTileEntity(placedX, placedY, placedZ);
if (tileentitymobspawner != null) {
setDefaultTag(itemstack);
String mobtype = IDtoNameMap.get(itemstack.getItemDamage());
if (mobtype != null) {
NEICPH.sendMobSpawnerID(placedX, placedY, placedZ, mobtype);
tileentitymobspawner.func_145881_a().setEntityName(mobtype);
@Override
public boolean onItemUse(ItemStack itemstack, EntityPlayer entityplayer, World world, int x, int y, int z, int side,
float hitX, float hitY, float hitZ) {
placedX = x;
placedY = y;
placedZ = z;
boolean placed = super.onItemUse(itemstack, entityplayer, world, x, y, z, side, hitX, hitY, hitZ);
if (placed && !world.isRemote) {
TileEntity tileEntity = world.getTileEntity(x, y, z);
if (tileEntity instanceof TileEntityMobSpawner) {
TileEntityMobSpawner spawner = (TileEntityMobSpawner) tileEntity;
String mobType = getMobTypeFromItemStack(itemstack);
if (mobType != null) {
spawner.func_145881_a().setEntityName(mobType);
world.markBlockForUpdate(x, y, z);
NEICPH.sendMobSpawnerID(x, y, z, mobType);
}
}
return true;
}
return false;
return placed;
}
private String getMobTypeFromItemStack(ItemStack stack) {
int meta = getValidMetaData(stack);
return IDtoNameMap.get(meta);
}
private int getValidMetaData(ItemStack stack) {
int meta = stack.getItemDamage();
if (meta == 0 || !IDtoNameMap.containsKey(meta)) {
return idPig;
}
return meta;
}
@SideOnly(Side.CLIENT)
@Override
public void addInformation(ItemStack itemstack, EntityPlayer par2EntityPlayer, List<String> list, boolean par4) {
setDefaultTag(itemstack);
int meta = itemstack.getItemDamage();
if (meta == 0) {
meta = idPig;
public void addInformation(ItemStack itemstack, EntityPlayer player, List<String> tooltip, boolean advanced) {
int meta = getValidMetaData(itemstack);
EntityLiving entity = getEntity(meta);
String mobName = IDtoNameMap.get(meta);
if (entity != null && mobName != null) {
EnumChatFormatting color = (entity instanceof IMob) ? EnumChatFormatting.DARK_RED
: EnumChatFormatting.DARK_AQUA;
tooltip.add(color + mobName);
}
Entity e = getEntity(meta);
list.add(
(e instanceof IMob ? EnumChatFormatting.DARK_RED : EnumChatFormatting.DARK_AQUA)
+ IDtoNameMap.get(meta));
}
public static EntityLiving getEntity(int ID) {
EntityLiving e = entityHashMap.get(ID);
if (e == null) {
loadSpawners();
Class<?> clazz = EntityList.IDtoClassMapping.get(ID);
World world = NEIClientUtils.mc().theWorld;
try {
e = (EntityLiving) clazz.getConstructor(new Class[] { World.class }).newInstance(world);
} catch (Throwable t) {
if (clazz == null)
NEIClientConfig.logger.error("Null class for entity (" + ID + ", " + IDtoNameMap.get(ID));
else NEIClientConfig.logger.error("Error creating instance of entity: " + clazz.getName(), t);
e = getEntity(idPig);
}
entityHashMap.put(ID, e);
public static EntityLiving getEntity(int id) {
EntityLiving cached = entityHashMap.get(id);
if (cached != null) {
return cached;
}
return e;
loadSpawners();
Class<?> entityClass = EntityList.IDtoClassMapping.get(id);
World world = NEIClientUtils.mc() != null ? NEIClientUtils.mc().theWorld : null;
if (isInvalidEntityClass(entityClass)) {
return cacheFallback(id);
}
EntityLiving entity = createEntityInstance(entityClass, world, id);
if (entity != null) {
entityHashMap.put(id, entity);
}
return entity;
}
private static boolean isInvalidEntityClass(Class<?> entityClass) {
if (entityClass == null) {
return true;
}
int modifiers = entityClass.getModifiers();
if (Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers)) {
NEIClientConfig.logger.warn("Skipping abstract/interface entity class: {}", entityClass.getName());
return true;
}
if (!EntityLiving.class.isAssignableFrom(entityClass)) {
NEIClientConfig.logger.warn("Skipping non-EntityLiving class: {}", entityClass.getName());
return true;
}
return false;
}
@SuppressWarnings("unchecked")
private static EntityLiving createEntityInstance(Class<?> entityClass, World world, int id) {
if (entityClass == null || world == null) {
NEIClientConfig.logger.debug("World or entity class is null, using fallback for ID: {}", id);
return getFallbackEntity(id);
}
try {
Class<? extends EntityLiving> livingClass = (Class<? extends EntityLiving>) entityClass;
return livingClass.getConstructor(World.class).newInstance(world);
} catch (Throwable t) {
logEntityCreationError(entityClass, id, t);
return getFallbackEntity(id);
}
}
private static void logEntityCreationError(Class<?> entityClass, int id, Throwable t) {
String entityName = IDtoNameMap.getOrDefault(id, "unknown");
if (entityClass == null) {
NEIClientConfig.logger
.error("Failed to create entity instance: Class is null for ID {}, Name {}", id, entityName, t);
} else {
NEIClientConfig.logger.error(
"Failed to create instance of entity: Class {}, ID {}, Name {}",
entityClass.getName(),
id,
entityName,
t);
}
}
private static EntityLiving cacheFallback(int id) {
EntityLiving fallback = getFallbackEntity(id);
if (fallback != null) {
entityHashMap.put(id, fallback);
}
return fallback;
}
private static EntityLiving getFallbackEntity(int originalId) {
EntityLiving pig = entityHashMap.get(idPig);
if (pig == null) {
World world = NEIClientUtils.mc() != null ? NEIClientUtils.mc().theWorld : null;
if (world != null) {
try {
pig = new EntityPig(world);
entityHashMap.put(idPig, pig);
NEIClientConfig.logger.debug("Created fallback pig entity for ID: {}", originalId);
} catch (Exception e) {
NEIClientConfig.logger
.error("Failed to create fallback pig entity for original ID: {}", originalId, e);
}
} else {
NEIClientConfig.logger.warn("World is null, cannot create fallback entity for ID: {}", originalId);
}
}
return pig;
}
public static void clearEntityReferences() {
entityHashMap.clear();
NEIClientConfig.logger.debug("Cleared all entity references from cache");
}
private void setDefaultTag(ItemStack itemstack) {
if (!IDtoNameMap.containsKey(itemstack.getItemDamage())) itemstack.setItemDamage(idPig);
}
@SuppressWarnings("unchecked")
public static void loadSpawners() {
if (loaded) return;
loaded = true;
for (Map.Entry<Class<? extends Entity>, String> entry : EntityList.classToStringMapping.entrySet()) {
final Class<? extends Entity> clazz = entry.getKey();
if (EntityLiving.class.isAssignableFrom(clazz)) {
Integer id = (Integer) EntityList.classToIDMapping.get(clazz);
if (id == null) continue;
String name = entry.getValue();
if (name == null) continue;
if (name.equals("EnderDragon")) continue;
if (name.equals("Pig")) idPig = id;
if (clazz != EntityPig.class || name.equals("Pig")) {
IDtoNameMap.put(id, name);
if (loaded) {
return;
}
synchronized (ItemMobSpawner.class) {
try {
for (Map.Entry<Class<? extends Entity>, String> entry : ((Map<Class<? extends Entity>, String>) EntityList.classToStringMapping)
.entrySet()) {
Class<? extends Entity> clazz = entry.getKey();
String name = entry.getValue();
if (shouldRegisterEntity(clazz, name)) {
Integer id = (Integer) EntityList.classToIDMapping.get(clazz);
if (id != null) {
IDtoNameMap.put(id, name);
ENTITY_CLASS_TO_NAME_CACHE.put(clazz, name);
if ("Pig".equals(name)) {
idPig = id;
NEIClientConfig.logger.debug("Set pig entity ID to: {}", id);
}
}
}
}
loaded = true;
NEIClientConfig.logger.info("Loaded {} spawner entity mappings", IDtoNameMap.size());
} catch (Exception e) {
NEIClientConfig.logger.error("Error loading spawners from entity list", e);
}
}
}
private static boolean shouldRegisterEntity(Class<? extends Entity> clazz, String name) {
if (clazz == null || name == null || name.trim().isEmpty()) {
return false;
}
if (!EntityLiving.class.isAssignableFrom(clazz)) {
return false;
}
if ("EnderDragon".equals(name) || "Giant".equals(name)) {
return false;
}
return true;
}
@Override
public void getSubItems(Item item, CreativeTabs tab, List<ItemStack> list) {
if (!NEIClientConfig.hasSMPCounterPart()) list.add(new ItemStack(item));
else for (int i : IDtoNameMap.keySet()) list.add(new ItemStack(item, 1, i));
if (!NEIClientConfig.hasSMPCounterPart()) {
list.add(new ItemStack(item));
} else {
loadSpawners();
for (int id : IDtoNameMap.keySet()) {
ItemStack stack = new ItemStack(item, 1, id);
list.add(stack);
}
}
}
public static String getEntityNameForMeta(int meta) {
loadSpawners();
return IDtoNameMap.getOrDefault(meta, IDtoNameMap.getOrDefault(idPig, "Pig"));
}
public static boolean isValidEntityMeta(int meta) {
loadSpawners();
return IDtoNameMap.containsKey(meta) || meta == 0;
}
public static Map<Integer, String> getRegisteredSpawnerEntities() {
loadSpawners();
return Collections.unmodifiableMap(IDtoNameMap);
}
public static boolean isEntityValidForSpawner(Class<? extends Entity> entityClass) {
if (entityClass == null) return false;
String name = ENTITY_CLASS_TO_NAME_CACHE.get(entityClass);
if (name == null) {
name = (String) EntityList.classToStringMapping.get(entityClass);
}
return name != null && shouldRegisterEntity(entityClass, name);
}
}
+76 -35
View File
@@ -8,6 +8,7 @@ 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.ItemsPanelGrid.ItemsPanelGridSlot;
import codechicken.nei.util.NEIMouseUtils;
@@ -32,7 +33,8 @@ public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
}
public ItemHistoryPanel historyPanel = new ItemHistoryPanel();
public Button toggleGroups;
public ItemCraftablesPanel craftablesPanel = new ItemCraftablesPanel();
protected Button toggleGroups;
@Deprecated
public static class ItemPanelSlot extends ItemsPanelGridSlot {
@@ -73,7 +75,13 @@ public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
}
public static void updateItemList(ArrayList<ItemStack> newItems) {
ItemPanels.itemPanel.getGrid().setItems(newItems);
final ItemsPanelGrid grid = ItemPanels.itemPanel.getGrid();
if (grid.rawItems.size() != newItems.size()) {
grid.setPage(0);
}
grid.setItems(newItems);
ItemPanels.itemPanel.realItems = newItems;
}
@@ -83,6 +91,11 @@ public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
toggleGroups = new Button("G") {
@Override
public String getRenderLabel() {
return NEIClientUtils.translate("itempanel.collapsed.button");
}
@Override
public String getButtonTip() {
return NEIClientUtils.translate("itempanel.collapsed.button.tip");
@@ -108,24 +121,29 @@ public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
return String.format("%d/%d", getPage(), Math.max(1, getNumPages()));
}
protected String getPositioningSettingName() {
return "world.panels.items";
}
@Override
public Rectangle4i calculateBounds(GuiContainer gui) {
final int maxWidth = (gui.width - 176) / 2 - PADDING * 2;
final int maxHeight = gui.height - PADDING * 2;
final int freeSpace = (gui.width - gui.xSize) / 2 - PADDING * 2;
public int getMarginLeft(GuiContainer gui) {
return (gui.width + gui.xSize) / 2 + PADDING;
}
final int paddingLeft = (int) Math
.ceil(maxWidth * NEIClientConfig.getSetting("world.panels.items.left").getIntValue() / 100000.0);
final int paddingTop = (int) Math
.ceil(maxHeight * NEIClientConfig.getSetting("world.panels.items.top").getIntValue() / 100000.0);
final int paddingRight = (int) Math
.ceil(maxWidth * NEIClientConfig.getSetting("world.panels.items.right").getIntValue() / 100000.0);
final int paddingBottom = (int) Math
.ceil(maxHeight * NEIClientConfig.getSetting("world.panels.items.bottom").getIntValue() / 100000.0);
public int getMarginTop(GuiContainer gui) {
return PADDING;
}
final int width = Math.max(
ItemsGrid.SLOT_SIZE,
snapDownToMultiple(
Math.min(freeSpace - paddingRight, maxWidth - paddingLeft - paddingRight),
ItemsGrid.SLOT_SIZE));
final int height = Math.max(ItemsGrid.SLOT_SIZE, maxHeight - paddingTop - paddingBottom);
public int getWidth(GuiContainer gui) {
return gui.width - (gui.xSize + gui.width) / 2 - PADDING * 2;
}
public int getHeight(GuiContainer gui) {
return gui.height - getMarginTop(gui) - PADDING;
return new Rectangle4i(gui.width - width - PADDING - paddingRight, paddingTop + PADDING, width, height);
}
@Override
@@ -141,26 +159,38 @@ public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
}
protected int resizeFooter(GuiContainer gui) {
if (!NEIClientConfig.showItemQuantityWidget() && NEIClientConfig.isSearchWidgetCentered()
&& !NEIClientConfig.showHistoryPanelWidget()) {
int footerY = y + h;
int footerHeight = 0;
if (grid.getPerPage() == 0) {
return 0;
}
if (NEIClientConfig.showItemQuantityWidget() || !NEIClientConfig.isSearchWidgetCentered()) {
footerY = LayoutManager.quantity.y;
footerHeight = LayoutManager.quantity.h + PanelWidget.PADDING;
}
if (NEIClientConfig.showHistoryPanelWidget()) {
historyPanel.x = x;
historyPanel.w = w;
historyPanel.h = 8 + ItemsGrid.SLOT_SIZE * NEIClientConfig.getIntSetting("inventory.history.useRows");
if (NEIClientConfig.showItemQuantityWidget() || !NEIClientConfig.isSearchWidgetCentered()) {
historyPanel.y = LayoutManager.quantity.y - historyPanel.h - PanelWidget.PADDING;
return LayoutManager.quantity.h + historyPanel.h + PanelWidget.PADDING * 2;
} else {
historyPanel.y = y + h - historyPanel.h;
return historyPanel.h + PanelWidget.PADDING;
if (historyPanel.setPanelWidth(w) != 0) {
footerY = historyPanel.y = footerY - historyPanel.h;
footerHeight += historyPanel.h;
}
}
if (NEIClientConfig.showCraftablesPanelWidget()) {
craftablesPanel.x = x;
if (craftablesPanel.setPanelWidth(w) != 0) {
footerY = craftablesPanel.y = footerY - craftablesPanel.h;
footerHeight += craftablesPanel.h;
}
}
return LayoutManager.quantity.h + PanelWidget.PADDING;
return footerHeight;
}
@Override
@@ -168,20 +198,27 @@ public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
super.setVisible();
if (grid.getPerPage() > 0) {
if (!CollapsibleItems.isEmpty() && !grid.isEmpty()) {
LayoutManager.addWidget(toggleGroups);
}
if (NEIClientConfig.showHistoryPanelWidget() && (!grid.isEmpty() || !historyPanel.isEmpty())) {
if (NEIClientConfig.showCraftablesPanelWidget()) {
LayoutManager.addWidget(craftablesPanel);
}
if (NEIClientConfig.showHistoryPanelWidget()) {
LayoutManager.addWidget(historyPanel);
}
}
}
@Override
public void resize(GuiContainer gui) {
super.resize(gui);
historyPanel.resize(gui);
this.historyPanel.resize(gui);
this.craftablesPanel.resize(gui);
}
protected ItemStack getDraggedStackWithQuantity(ItemStack itemStack) {
@@ -189,8 +226,7 @@ public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
}
@Override
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
List<String> currenttip) {
public List<String> handleItemTooltip(ItemStack itemstack, int mousex, int mousey, List<String> currenttip) {
if (!this.grid.forceExpand && !currenttip.isEmpty()) {
final ItemsPanelGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
@@ -204,7 +240,7 @@ public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
}
}
return super.handleItemTooltip(gui, itemstack, mousex, mousey, currenttip);
return super.handleItemTooltip(itemstack, mousex, mousey, currenttip);
}
@Override
@@ -225,7 +261,7 @@ public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
}
@Override
public Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
public Map<String, String> handleHotkeys(int mousex, int mousey, Map<String, String> hotkeys) {
final ItemsPanelGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
if (!this.grid.forceExpand && hoverSlot != null && hoverSlot.groupIndex >= 0 && hoverSlot.groupSize > 1) {
@@ -236,7 +272,12 @@ public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
NEIClientUtils.translate(message, hoverSlot.groupSize));
}
return hotkeys;
return super.handleHotkeys(mousex, mousey, hotkeys);
}
public boolean containsWithSubpanels(int px, int py) {
return contains(px, py) || NEIClientConfig.showHistoryPanelWidget() && this.historyPanel.contains(px, py)
|| NEIClientConfig.showCraftablesPanelWidget() && this.craftablesPanel.contains(px, py);
}
}
@@ -104,6 +104,16 @@ public class ItemStackAmount {
return this.itemMap.isEmpty();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ItemStackAmount items) {
return this.itemMap.equals(items.itemMap);
}
return false;
}
public static ItemStackAmount of(ItemStackAmount map) {
ItemStackAmount result = new ItemStackAmount();
result.itemMap.putAll(map.itemMap);
+1 -1
View File
@@ -58,7 +58,7 @@ public class ItemZoom extends Widget implements IContainerInputHandler {
GL11.glPopMatrix();
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
GuiContainerManager.enable2DRender();
if (NEIClientConfig.getBooleanSetting("inventory.itemzoom.showName")) {
+6 -31
View File
@@ -15,11 +15,11 @@ import net.minecraft.client.shader.Framebuffer;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL30;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends ItemsGrid.MouseContext> {
@@ -51,7 +51,7 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
}
public void captureScreen(Runnable callback, int mode) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
resetFramebuffer();
this.framebuffer.bindFramebuffer(false);
@@ -84,21 +84,6 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
} else {
this.framebuffer.framebufferClear();
}
// copy depth buffer from MC (fix Angelica)
OpenGlHelper.func_153171_g(GL30.GL_READ_FRAMEBUFFER, minecraft.getFramebuffer().framebufferObject);
OpenGlHelper.func_153171_g(GL30.GL_DRAW_FRAMEBUFFER, this.framebuffer.framebufferObject);
GL30.glBlitFramebuffer(
0,
0,
minecraft.displayWidth,
minecraft.displayHeight,
0,
0,
minecraft.displayWidth,
minecraft.displayHeight,
GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT,
GL11.GL_NEAREST);
}
public void renderCapturedScreen() {
@@ -171,6 +156,10 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
public <M extends MouseContext> void afterDraw(Rectangle4i rect, M mouseContext) {}
public RecipeId getRecipeId() {
return null;
}
public void drawItem(Rectangle4i rect) {
drawItem(getItemStack(), rect);
}
@@ -276,8 +265,6 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
protected boolean[] invalidSlotMap;
protected Label messageLabel = new Label(getMessageOnEmpty(), true);
protected ScreenCapture screenCapture = null;
public ArrayList<ItemStack> getItems() {
@@ -355,9 +342,6 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
rows = height / SLOT_SIZE;
paddingLeft = (width % SLOT_SIZE) / 2;
messageLabel.x = marginLeft + width / 2;
messageLabel.y = marginTop + height / 2;
}
public void shiftPage(int shift) {
@@ -561,12 +545,6 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
afterDrawItems(mousex, mousey, mouseContext);
}
public void setVisible() {
if (getItems().isEmpty() && getMessageOnEmpty() != null) {
LayoutManager.addWidget(messageLabel);
}
}
public boolean contains(int px, int py) {
final Rectangle4i rect = new Rectangle4i(
marginLeft + paddingLeft,
@@ -581,7 +559,4 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
return !isInvalidSlot(columns * getRowIndex(py) + getColumnIndex(px));
}
public String getMessageOnEmpty() {
return null;
}
}
@@ -11,9 +11,11 @@ import java.util.Set;
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.ItemsGrid.ItemsGridSlot;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.Recipe.RecipeId;
public class ItemsPanelGrid extends ItemsGrid<ItemsPanelGrid.ItemsPanelGridSlot, ItemsPanelGrid.MouseContext> {
@@ -37,6 +39,11 @@ public class ItemsPanelGrid extends ItemsGrid<ItemsPanelGrid.ItemsPanelGridSlot,
return this.bgItemStack;
}
@Override
public RecipeId getRecipeId() {
return FavoriteRecipes.getFavorite(this.item);
}
@Override
public void beforeDraw(Rectangle4i rect, MouseContext mouseContext) {
super.beforeDraw(rect, mouseContext);
@@ -63,7 +70,7 @@ public class ItemsPanelGrid extends ItemsGrid<ItemsPanelGrid.ItemsPanelGridSlot,
}
public ArrayList<ItemStack> newItems;
public ArrayList<ItemStack> rawItems;
public ArrayList<ItemStack> rawItems = new ArrayList<>();
protected List<ItemsPanelGridSlot> gridMask;
protected final Map<Integer, Integer> itemToGroup = new HashMap<>();
@@ -231,9 +238,18 @@ public class ItemsPanelGrid extends ItemsGrid<ItemsPanelGrid.ItemsPanelGridSlot,
Math.min((int) (color.getAlpha() + (255f / 5) * 2), 255));
}
@Override
public String getMessageOnEmpty() {
return ItemList.loadFinished ? null : NEIClientUtils.translate("itempanel.loading");
public void draw(int mousex, int mousey) {
if (ItemList.loadFinished) {
super.draw(mousex, mousey);
} else {
GuiDraw.drawStringC(
NEIClientUtils
.cropText(GuiDraw.fontRenderer, NEIClientUtils.translate("itempanel.loading"), width - 10),
marginLeft + width / 2,
marginTop + height / 2,
0xffffff,
true);
}
}
}
@@ -70,7 +70,7 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
}
public void setActiveStack(ItemStack activeStack) {
final ItemStack realStack = items.stream().filter(stack -> StackInfo.equalItemAndNBT(stack, activeStack, true))
final ItemStack realStack = items.stream().filter(stack -> NEIClientUtils.areStacksSameType(stack, activeStack))
.findFirst().orElse(null);
this.activeStackIndex = items.indexOf(realStack);
}
@@ -100,13 +100,15 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
fontRenderer.drawStringWithShadow(this.labelColor + this.label + ":", x, y, 0);
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL11.glPushMatrix();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
RenderHelper.enableGUIStandardItemLighting();
GL11.glScaled(1, 1, 3);
GL11.glTranslatef(x, y + fontRenderer.FONT_HEIGHT + 2, 0);
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
final int xTranslation = x;
final int yTranslation = y + fontRenderer.FONT_HEIGHT + 2;
final int zTranslation = GuiContainerManager.TOOLTIP_Z_OFFSET;
GL11.glTranslatef(xTranslation, yTranslation, zTranslation);
int indexShift = 0;
@@ -142,7 +144,7 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
});
}
GL11.glPopMatrix();
GL11.glTranslatef(-xTranslation, -yTranslation, -zTranslation);
GL11.glPopAttrib();
}
@@ -4,6 +4,10 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map.Entry;
import org.lwjgl.input.Keyboard;
import codechicken.nei.util.NEIKeyboardUtils;
/**
* Good old down/held/up keystate tracker
*/
@@ -26,7 +30,8 @@ public class KeyManager {
public static void tickKeyStates() {
for (Entry<String, KeyState> entry : keyStates.entrySet()) {
final boolean down = NEIClientConfig.isKeyHashDown(entry.getKey());
final int keyCode = NEIKeyboardUtils.unhash(NEIClientConfig.getKeyBinding(entry.getKey()));
final boolean down = keyCode > 0 && keyCode < Keyboard.KEYBOARD_SIZE && Keyboard.isKeyDown(keyCode);
final KeyState state = entry.getValue();
if (down) {
@@ -68,6 +68,7 @@ import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.recipe.AutoCraftingManager;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.RecipeCatalysts;
import codechicken.nei.recipe.debug.DebugHandlerWidget;
public class LayoutManager implements IContainerInputHandler, IContainerTooltipHandler, IContainerDrawHandler,
IContainerObjectHandler, IKeyStateTracker {
@@ -102,7 +103,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public static Button delete;
public static ButtonCycled gamemode;
public static Button rain;
public static Button magnet;
public static ButtonCycled magnet;
public static Button[] timeButtons = new Button[4];
public static Button heal;
@@ -136,10 +137,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public void onPreDraw(GuiContainer gui) {
if (!isHidden() && isEnabled() && gui instanceof InventoryEffectRenderer) // Reset the gui to the center of the
// screen, for potion effect offsets
// etc
{
// Reset the gui to the center of the screen, for potion effect offsets etc
if (isEnabled() && gui instanceof InventoryEffectRenderer) {
gui.guiLeft = (gui.width - gui.xSize) / 2;
gui.guiTop = (gui.height - gui.ySize) / 2;
@@ -293,19 +292,6 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
}
}
@Override
public void postRenderTooltips(GuiContainer gui, int mousex, int mousey, List<String> tooltip) {
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused != null) {
focused.postDrawTooltips(mousex, mousey, tooltip);
}
}
}
@Override
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
@@ -356,6 +342,10 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused != null) {
currenttip = focused.handleItemTooltip(itemstack, mousex, mousey, currenttip);
}
if (focused instanceof IContainerTooltipHandler tip) {
currenttip = tip.handleItemTooltip(gui, itemstack, mousex, mousey, currenttip);
}
@@ -370,9 +360,14 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused instanceof IContainerTooltipHandler tip) {
hotkeys = tip.handleHotkeys(gui, mousex, mousey, hotkeys);
if (focused != null) {
hotkeys = focused.handleHotkeys(mousex, mousey, hotkeys);
if (focused instanceof IContainerTooltipHandler tip) {
hotkeys = tip.handleHotkeys(gui, mousex, mousey, hotkeys);
}
}
}
return hotkeys;
@@ -602,7 +597,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
return getStateTip("rain", state);
}
};
magnet = new Button() {
magnet = new ButtonCycled(2) {
@Override
public boolean onButtonPress(boolean rightclick) {
@@ -785,9 +780,10 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
addWidget(itemZoom);
if (visiblity.showSubsetDropdown) {
// Bookmarks or Subset/dropdown
addWidget(dropDown);
}
addWidget(DebugHandlerWidget.instance);
}
public static LayoutStyle getLayoutStyle(int id) {
@@ -907,6 +903,9 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
final int ty2 = ty + 20 - h2 - te;
final int tx2 = 200 - w2 - te;
final boolean is2DTexture = GL11.glGetBoolean(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_TEXTURE_2D);
changeTexture("textures/gui/widgets.png");
drawTexturedModalRect(x, y, tx1, ty1, w1, h1); // top left
drawTexturedModalRect(x, y2, tx1, ty2, w1, h2); // bottom left
@@ -919,6 +918,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
drawTexturedModalRect(x2, y, tx2, ty1, w2, h1); // top right
drawTexturedModalRect(x2, y2, tx2, ty2, w2, h2); // bottom right
if (!is2DTexture) GL11.glDisable(GL11.GL_TEXTURE_2D);
}
public static void drawItemPresenceOverlay(int slotX, int slotY, boolean isPresent, boolean slotHighlight) {
@@ -31,7 +31,8 @@ public class LayoutStyleMinecraft extends LayoutStyle {
LayoutManager.gamemode.icons[0] = new Image(132, 12, 12, 12);
LayoutManager.gamemode.icons[1] = new Image(156, 12, 12, 12);
LayoutManager.gamemode.icons[2] = new Image(168, 12, 12, 12);
LayoutManager.magnet.icon = new Image(180, 24, 12, 12);
LayoutManager.magnet.icons[0] = new Image(180, 24, 12, 12);
LayoutManager.magnet.icons[1] = new Image(180, 36, 12, 12);
LayoutManager.timeButtons[0].icon = new Image(132, 24, 12, 12);
LayoutManager.timeButtons[1].icon = new Image(120, 24, 12, 12);
LayoutManager.timeButtons[2].icon = new Image(144, 24, 12, 12);
@@ -52,7 +53,7 @@ public class LayoutStyleMinecraft extends LayoutStyle {
public void layout(GuiContainer gui, VisiblityData visiblity) {
reset();
leftSize = ItemPanels.bookmarkPanel.getWidth(gui);
leftSize = (gui.width - gui.xSize) / 2 - 4;
numButtons = Math.max(leftSize / 20, 1);
LayoutManager.delete.state = 0x4;
@@ -86,6 +87,7 @@ public class LayoutStyleMinecraft extends LayoutStyle {
LayoutManager.options.index = NEIClientConfig.getCheatMode();
LayoutManager.magnet.state = 0x4 | (NEIClientConfig.getMagnetMode() ? 1 : 0);
LayoutManager.magnet.index = (LayoutManager.magnet.state & 0x1) != 0 ? 1 : 0;
if (NEIClientConfig.canPerformAction("delete")) {
layoutButton(LayoutManager.delete);
@@ -186,6 +186,12 @@ public class NEICPH implements IClientPacketHandler {
packet.sendToServer();
}
public static void sendChatLink(ItemStack stackover) {
PacketCustom packet = new PacketCustom(channel, C2S.SEND_CHAT_ITEM_LINK);
packet.writeItemStack(stackover);
packet.sendToServer();
}
public static void sendOpenEnchantmentWindow() {
PacketCustom packet = new PacketCustom(channel, C2S.REQUEST_ENCHANTMENT_GUI);
packet.sendToServer();
@@ -58,8 +58,9 @@ import codechicken.nei.config.preset.GuiPresetList;
import codechicken.nei.event.NEIConfigsLoadedEvent;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.IRecipeHandler;
import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.recipe.RecipeCatalysts;
import codechicken.nei.recipe.RecipeInfo;
import codechicken.nei.util.ItemUntranslator;
import codechicken.nei.util.NEIKeyboardUtils;
import codechicken.obfuscator.ObfuscationRun;
@@ -145,6 +146,9 @@ public class NEIClientConfig {
tag.getTag("inventory.widgetsenabled").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.widgetsenabled"));
tag.getTag("findFuelsParallel").getBooleanValue(true);
tag.getTag("showRepairOnlyForDamageableItems").getBooleanValue(true);
tag.getTag("inventory.autocrafting").getBooleanValue(true);
tag.getTag("inventory.dynamicFontSize").getBooleanValue(true);
tag.getTag("inventory.hidden").getBooleanValue(false);
@@ -205,6 +209,10 @@ public class NEIClientConfig {
0,
OptionIntegerField.UNSIGNED_INT_MAX));
tag.getTag("inventory.bookmarks.showRecipeHandlerIcon").setComment("Show Recipe Handler Icon")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.bookmarks.showRecipeHandlerIcon", true));
tag.getTag("inventory.bookmarks.recipeChainDir").getIntValue(1);
API.addOption(new OptionCycled("inventory.bookmarks.recipeChainDir", 2, true));
@@ -216,17 +224,17 @@ public class NEIClientConfig {
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.bookmarks.bookmarkItemsWithRecipe", true));
tag.getTag("inventory.bookmarks.bookmarkRecipeWithCount").setComment("Bookmark recipe with count")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.bookmarks.bookmarkRecipeWithCount", true));
tag.getTag("inventory.guirecipe.jeiStyleTabs").setComment("Enable/disable JEI Style Tabs")
.getBooleanValue(true);
API.addOption(new OptionToggleButtonBoubs("inventory.guirecipe.jeiStyleTabs", true));
tag.getTag("inventory.guirecipe.jeiStyleRecipeCatalyst").setComment("Enable/disable JEI Style Recipe Catalysts")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.guirecipe.jeiStyleRecipeCatalyst", true));
tag.getTag("inventory.guirecipe.jeiStyleCycledIngredients").setComment("JEI styled cycled ingredients")
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.guirecipe.jeiStyleCycledIngredients", true));
tag.getTag("inventory.guirecipe.jeiStyleRecipeCatalyst")
.setComment("JEI Style Recipe Catalysts (0 - none, 1 - grid, 2 - scroll)").getIntValue(1);
API.addOption(new OptionCycled("inventory.guirecipe.jeiStyleRecipeCatalyst", 3, true));
tag.getTag("inventory.guirecipe.cycledIngredientsTooltip").setComment("Show cycled ingredients tooltip")
.getBooleanValue(true);
@@ -244,6 +252,13 @@ public class NEIClientConfig {
.getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.guirecipe.slotHighlightPresent", true));
tag.getTag("inventory.guirecipe.infiniteScroll").setComment("Use Infinite Scroll for Handlers")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.guirecipe.infiniteScroll", true));
tag.getTag("inventory.guirecipe.maxHeight").setComment("Recipe GUI Max Height").getIntValue(370);
API.addOption(new OptionIntegerField("inventory.guirecipe.maxHeight", 166, 4000));
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));
@@ -251,6 +266,10 @@ public class NEIClientConfig {
tag.getTag("inventory.guirecipe.profile").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.guirecipe.profile", true));
tag.getTag("inventory.guirecipe.handlerInfo").setComment("ADVANCED: Handler Info Widget")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.guirecipe.handlerInfo", true));
tag.getTag("inventory.subsets.enabled").setComment("Enable/disable Subsets Dropdown").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.subsets.enabled", true));
@@ -260,15 +279,25 @@ public class NEIClientConfig {
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.color").setComment("Color of the history area display").getHexValue(0xee555555);
API.addOption(new OptionIntegerField("inventory.history.color", 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.craftables.enabled").setComment("Enable/disable Craftables Panel").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.craftables.enabled", true));
tag.getTag("inventory.craftables.color").setComment("Color of the craftables area display")
.getHexValue(0xee555555);
API.addOption(new OptionIntegerField("inventory.craftables.color", 0, OptionIntegerField.UNSIGNED_INT_MAX));
tag.getTag("inventory.craftables.useRows").setComment("Rows used in craftables areas").getIntValue(2);
API.addOption(new OptionIntegerField("inventory.craftables.useRows", 1, 5));
tag.getTag("inventory.craftables.favoritesOnly").setComment("Show Only Favorites Recipes")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.craftables.favoritesOnly", true));
tag.getTag("inventory.collapsibleItems.enabled").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.collapsibleItems.enabled", true) {
@@ -390,6 +419,8 @@ public class NEIClientConfig {
});
tag.getTag("inventory.hotkeysHelpText").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.hotkeysHelpText", true));
tag.getTag("inventory.showHotkeys").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.showHotkeys", true));
tag.getTag("loadPluginsInParallel").getBooleanValue(true);
tag.getTag("itemLoadingTimeout").getIntValue(500);
@@ -415,6 +446,24 @@ public class NEIClientConfig {
tag.getTag("inventory.autocrafting").setComment("Autocrafting").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.autocrafting", true));
tag.getTag("inventory.itemUntranslator").setComment("Item Untranslator").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.itemUntranslator", true) {
@Override
public boolean onClick(int button) {
super.onClick(button);
if (enableItemUntranslator()) {
ItemUntranslator.getInstance().load();
} else {
ItemUntranslator.getInstance().unload();
}
return 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) {
@@ -491,12 +540,15 @@ public class NEIClientConfig {
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) {
API.addOption(new OptionCycled("inventory.search.patternMode", 4, true) {
@Override
public boolean onClick(int button) {
if (!super.onClick(button)) {
return false;
}
SearchField.searchParser.clearCache();
return super.onClick(button);
return true;
}
});
@@ -549,7 +601,7 @@ public class NEIClientConfig {
@Override
public boolean onClick(int button) {
// SearchField.searchParser.clearCache();
SearchField.searchParser.clearCache();
return super.onClick(button);
}
@@ -566,8 +618,11 @@ public class NEIClientConfig {
@Override
public boolean onClick(int button) {
if (!super.onClick(button)) {
return false;
}
SearchField.searchParser.clearCache();
return super.onClick(button);
return true;
}
@Override
@@ -591,8 +646,11 @@ public class NEIClientConfig {
@Override
public boolean onClick(int button) {
if (!super.onClick(button)) {
return false;
}
SearchField.searchParser.clearCache();
return super.onClick(button);
return true;
}
@Override
@@ -615,8 +673,11 @@ public class NEIClientConfig {
@Override
public boolean onClick(int button) {
if (!super.onClick(button)) {
return false;
}
SearchField.searchParser.clearCache();
return super.onClick(button);
return true;
}
@Override
@@ -639,8 +700,11 @@ public class NEIClientConfig {
@Override
public boolean onClick(int button) {
if (!super.onClick(button)) {
return false;
}
SearchField.searchParser.clearCache();
return super.onClick(button);
return true;
}
@Override
@@ -663,8 +727,11 @@ public class NEIClientConfig {
@Override
public boolean onClick(int button) {
if (!super.onClick(button)) {
return false;
}
SearchField.searchParser.clearCache();
return super.onClick(button);
return true;
}
@Override
@@ -682,6 +749,9 @@ public class NEIClientConfig {
});
tag.getTag("inventory.search.logSearchExceptions").setComment("Search exceptions for extended+")
.getBooleanValue(false);
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("{}");
@@ -692,6 +762,7 @@ public class NEIClientConfig {
};
Map<Character, Character> charMap = new Gson().fromJson(prefixRedefinitions, typeToken.getType());
SearchField.searchParser.prefixRedefinitions.putAll(charMap);
SearchField.searchParser.clearCache();
} catch (JsonParseException e) {
logger.warn("Failed to convert prefix redefinitions from JSON to CharToCharMap:", e);
}
@@ -710,8 +781,7 @@ public class NEIClientConfig {
@Override
public boolean onClick(int button) {
super.onClick(button);
FavoriteRecipes.save();
FavoriteRecipes.load();
FavoriteRecipes.reload();
return true;
}
});
@@ -724,7 +794,19 @@ public class NEIClientConfig {
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.favorites.showRecipeTooltipInGui", true));
tag.getTag("inventory.favorites.depth").setComment("Bookmark creation depth").getIntValue(3);
tag.getTag("inventory.favorites.generateSingleRecipeFavorites")
.setComment("Automatically generate favorites for items with only one recipe").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.favorites.generateSingleRecipeFavorites", true) {
@Override
public boolean onClick(int button) {
super.onClick(button);
FavoriteRecipes.loadAutoGeneratedRecipes();
return true;
}
});
tag.getTag("inventory.favorites.depth").setComment("Bookmark creation depth").getIntValue(9);
API.addOption(new OptionIntegerField("inventory.favorites.depth", 0, 100));
}
@@ -743,10 +825,12 @@ public class NEIClientConfig {
API.addHashBind("gui.hide", Keyboard.KEY_O);
API.addHashBind("gui.search", Keyboard.KEY_F);
API.addKeyBind("gui.bookmark", Keyboard.KEY_A);
API.addHashBind("gui.favorite", Keyboard.KEY_F + NEIClientUtils.SHIFT_HASH);
API.addKeyBind("gui.favorite_item", Keyboard.KEY_F);
API.addHashBind("gui.remove_recipe", Keyboard.KEY_A + NEIClientUtils.SHIFT_HASH);
API.addKeyBind("gui.bookmark_pull_items", Keyboard.KEY_V);
API.addKeyBind("gui.overlay", Keyboard.KEY_S);
API.addHashBind("gui.craft", Keyboard.KEY_C + NEIClientUtils.SHIFT_HASH);
API.addKeyBind("gui.craft_items", Keyboard.KEY_C);
API.addHashBind("gui.hide_bookmarks", Keyboard.KEY_B);
API.addKeyBind("gui.getprevioussearch", Keyboard.KEY_UP);
API.addKeyBind("gui.getnextsearch", Keyboard.KEY_DOWN);
@@ -769,6 +853,8 @@ public class NEIClientConfig {
API.addKeyBind("world.creative", 0);
API.addHashBind("gui.copy_name", Keyboard.KEY_C + NEIClientUtils.CTRL_HASH);
API.addHashBind("gui.copy_oredict", Keyboard.KEY_D + NEIClientUtils.CTRL_HASH);
API.addHashBind("gui.copy_id", Keyboard.KEY_X + NEIClientUtils.CTRL_HASH);
API.addHashBind("gui.chat_link_item", Keyboard.KEY_L + NEIClientUtils.CTRL_HASH);
}
public static OptionList getOptionList() {
@@ -776,24 +862,27 @@ public class NEIClientConfig {
}
public static void loadWorld(String worldPath) {
final File specificDir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
final boolean newWorld = !specificDir.exists();
unloadWorld();
setInternalEnabled(true);
if (!worldPath.equals(NEIClientConfig.worldPath)) {
if (!worldPath.equals(NEIClientConfig.worldPath) || newWorld) {
NEIClientConfig.worldPath = worldPath;
logger.debug("Loading " + (Minecraft.getMinecraft().isSingleplayer() ? "Local" : "Remote") + " World");
final File specificDir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
final boolean newWorld = !specificDir.exists();
if (newWorld) {
specificDir.mkdirs();
}
world = new ConfigSet(new File(specificDir, "NEI.dat"), new ConfigFile(new File(specificDir, "NEI.cfg")));
if (newWorld && Minecraft.getMinecraft().isSingleplayer()) {
world.config.getTag("inventory.cheatmode")
.setIntValue(NEIClientUtils.mc().playerController.isInCreativeMode() ? 2 : 0);
}
bootNEI();
onWorldLoad(newWorld);
onWorldLoad();
}
}
@@ -801,7 +890,7 @@ public class NEIClientConfig {
return NEIClientConfig.worldPath;
}
private static void onWorldLoad(boolean newWorld) {
private static void onWorldLoad() {
world.config.setComment(
"World based configuration of NEI.\nMost of these options can be changed ingame.\nDeleting any element will restore it to it's default value");
@@ -809,12 +898,6 @@ public class NEIClientConfig {
creativeInv = new ItemStack[54];
LayoutManager.searchField.setText(getSearchExpression());
LayoutManager.quantity.setText(Integer.toString(getItemQuantity()));
if (newWorld && Minecraft.getMinecraft().isSingleplayer()) {
world.config.getTag("inventory.cheatmode")
.setIntValue(NEIClientUtils.mc().playerController.isInCreativeMode() ? 2 : 0);
}
NEIInfo.load(ClientUtils.getWorld());
}
@@ -828,6 +911,10 @@ public class NEIClientConfig {
}
public static void unloadWorld() {
if (world == null) {
return;
}
if (ItemPanels.bookmarkPanel != null) {
ItemPanels.bookmarkPanel.save();
}
@@ -835,10 +922,7 @@ public class NEIClientConfig {
SubsetWidget.saveHidden();
FavoriteRecipes.save();
CollapsibleItems.saveStates();
if (world != null) {
world.saveNBT();
}
world.saveNBT();
}
private static final Map<String, String> keySettings = new HashMap<>();
@@ -856,7 +940,7 @@ public class NEIClientConfig {
final int hash = getKeyBinding(string);
if (hash != Keyboard.CHAR_NONE && Keyboard.getEventKeyState()) {
return KeyManager.keyStates.containsKey(string) ? hash == Keyboard.getEventKey()
return KeyManager.keyStates.containsKey(string) ? Keyboard.isKeyDown(NEIKeyboardUtils.unhash(hash))
: hash == NEIClientUtils.getKeyHash();
}
@@ -893,11 +977,11 @@ public class NEIClientConfig {
// main NEI config loading
ItemInfo.load();
GuiInfo.load();
RecipeInfo.load();
HeldItemHandler.load();
LayoutManager.load();
NEIController.load();
BookmarkContainerInfo.load();
InformationHandler.load();
mainNEIConfigLoaded = true;
new Thread("NEI Plugin Loader") {
@@ -920,10 +1004,10 @@ public class NEIClientConfig {
});
RecipeCatalysts.loadCatalystInfo();
SubsetWidget.loadCustomSubsets();
SubsetWidget.loadHidden();
CollapsibleItems.load();
ItemSorter.loadConfig();
FavoriteRecipes.load();
// Set pluginNEIConfigLoaded here before posting the NEIConfigsLoadedEvent. This used to be the
// other way around, but apparently if your modpack includes 800 mods the event poster might not
@@ -932,7 +1016,6 @@ public class NEIClientConfig {
// API. I don't expect any handler to do this, but who knows what modders have come up with...
pluginNEIConfigLoaded = true;
MinecraftForge.EVENT_BUS.post(new NEIConfigsLoadedEvent());
ItemList.loadItems.restart();
}
}.start();
@@ -1029,8 +1112,8 @@ public class NEIClientConfig {
return getBooleanSetting("inventory.guirecipe.slotHighlightPresent");
}
public static boolean areJEIStyleRecipeCatalystsVisible() {
return getBooleanSetting("inventory.guirecipe.jeiStyleRecipeCatalyst");
public static int getJEIStyleRecipeCatalysts() {
return getIntSetting("inventory.guirecipe.jeiStyleRecipeCatalyst");
}
public static boolean useCreativeTabStyle() {
@@ -1049,10 +1132,6 @@ public class NEIClientConfig {
return getBooleanSetting("inventory.optimize_gui_overlap_computation");
}
public static boolean useJEIStyledCycledIngredients() {
return getBooleanSetting("inventory.guirecipe.jeiStyleCycledIngredients");
}
public static boolean showCycledIngredientsTooltip() {
return getBooleanSetting("inventory.guirecipe.cycledIngredientsTooltip");
}
@@ -1161,6 +1240,10 @@ public class NEIClientConfig {
return getBooleanSetting("inventory.history.enabled");
}
public static boolean showCraftablesPanelWidget() {
return getBooleanSetting("inventory.craftables.enabled");
}
public static int getGridRenderingCacheMode() {
return OpenGlHelper.framebufferSupported ? getIntSetting("inventory.gridRenderingCacheMode") : 0;
}
@@ -1169,6 +1252,10 @@ public class NEIClientConfig {
return getBooleanSetting("inventory.collapsibleItems.enabled");
}
public static boolean enableItemUntranslator() {
return getBooleanSetting("inventory.itemUntranslator");
}
public static boolean getMagnetMode() {
return enabledActions.contains("magnet");
}
@@ -11,7 +11,6 @@ import static codechicken.nei.NEIClientConfig.world;
import java.awt.Color;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
@@ -47,6 +46,7 @@ import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import com.google.common.collect.Iterables;
import com.gtnewhorizon.gtnhlib.util.numberformatting.NumberFormatUtil;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.inventory.InventoryRange;
@@ -126,16 +126,22 @@ public class NEIClientUtils extends NEIServerUtils {
});
}
public static String formatNumbers(BigInteger aNumber) {
public static String formatNumber(long aNumber) {
if (NEIModContainer.isGTNHLibLoaded()) {
return NumberFormatUtil.formatNumber(aNumber);
}
return getDecimalFormat().format(aNumber);
}
public static String formatNumbers(long aNumber) {
return getDecimalFormat().format(aNumber);
}
public static String formatFluid(long aNumber) {
public static String formatNumbers(double aNumber) {
return getDecimalFormat().format(aNumber);
if (NEIModContainer.isGTNHLibLoaded()) {
return NumberFormatUtil.formatFluid(aNumber);
}
return getDecimalFormat().format(aNumber) + " L";
}
public static void deleteHeldItem() {
@@ -198,7 +204,7 @@ public class NEIClientUtils extends NEIServerUtils {
public static void cheatItem(ItemStack stack, int button, int mode) {
if (!canCheatItem(stack)) return;
if (mode == -1 && button == 0 && shiftKey() && NEIClientConfig.hasSMPCounterPart()) {
if (mode == -1 && button == 0 && controlKey() && NEIClientConfig.hasSMPCounterPart()) {
for (IInfiniteItemHandler handler : ItemInfo.infiniteHandlers) {
if (!handler.canHandleItem(stack)) continue;
@@ -370,6 +376,10 @@ public class NEIClientUtils extends NEIServerUtils {
else sendCommand(getStringSetting("command.heal"), mc().thePlayer.getCommandSenderName());
}
public static void sendChatItemLink(ItemStack stackover) {
if (hasSMPCounterPart()) NEICPH.sendChatLink(stackover);
}
public static void toggleMagnetMode() {
if (hasSMPCounterPart()) NEICPH.sendToggleMagnetMode();
}
@@ -409,18 +419,11 @@ public class NEIClientUtils extends NEIServerUtils {
if (textWidth > containerWidth) {
int dots = fontRenderer.getStringWidth("...");
if (containerWidth > dots) {
textWidth += dots;
while (textWidth > containerWidth) {
textWidth -= fontRenderer.getCharWidth(text.charAt(text.length() - 1));
text = text.substring(0, text.length() - 1);
}
return text + "...";
if (containerWidth <= dots) {
return "...";
}
return "...";
return fontRenderer.trimStringToWidth(text, containerWidth - dots) + "...";
}
return text;
@@ -524,7 +527,9 @@ public class NEIClientUtils extends NEIServerUtils {
}
public static void drawRect(double left, double top, double width, double height, Color color) {
Tessellator tessellator = Tessellator.instance;
final boolean is2DTexture = GL11.glGetBoolean(GL11.GL_TEXTURE_2D);
final boolean isBlend = GL11.glGetBoolean(GL11.GL_BLEND);
final Tessellator tessellator = Tessellator.instance;
GL11.glEnable(GL11.GL_BLEND);
GL11.glDisable(GL11.GL_TEXTURE_2D);
@@ -536,8 +541,9 @@ public class NEIClientUtils extends NEIServerUtils {
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);
GL11.glColor4f(1, 1, 1, 1);
if (is2DTexture) GL11.glEnable(GL11.GL_TEXTURE_2D);
if (!isBlend) GL11.glDisable(GL11.GL_BLEND);
}
public static void drawNEIOverlayText(String text, Rectangle4i rect, float scale, int color, boolean shadow,
@@ -11,16 +11,24 @@ import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.inventory.SlotCrafting;
import net.minecraft.item.ItemStack;
import net.minecraftforge.client.ClientCommandHandler;
import codechicken.core.CommonUtils;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.api.API;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.IInfiniteItemHandler;
import codechicken.nei.api.INEIGuiHandler;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.commands.CommandBookmarkAdd;
import codechicken.nei.commands.CommandRecipeId;
import codechicken.nei.commands.CommandUntranslator;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.guihook.IContainerSlotClickHandler;
import codechicken.nei.recipe.GuiRecipe;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class NEIController implements IContainerSlotClickHandler, IContainerInputHandler {
@@ -39,6 +47,8 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
public static void load() {
GuiContainerManager.addSlotClickHandler(instance);
GuiContainerManager.addInputHandler(instance);
if (CommonUtils.isClient()) registerClientCommands();
}
public static void load(GuiContainer gui) {
@@ -56,6 +66,13 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
return gui.field_147007_t && gui.field_147008_s.size() > 1;
}
@SideOnly(Side.CLIENT)
public static void registerClientCommands() {
ClientCommandHandler.instance.registerCommand(new CommandBookmarkAdd());
ClientCommandHandler.instance.registerCommand(new CommandRecipeId());
ClientCommandHandler.instance.registerCommand(new CommandUntranslator());
}
public static void updateUnlimitedItems(InventoryPlayer inventory) {
if (!NEIClientConfig.canPerformAction("item") || !NEIClientConfig.hasSMPCounterPart()) return;
@@ -122,7 +139,7 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
return true;
}
if (button == 1 && slot instanceof SlotCrafting) // right click
if (button == 1 && modifier != 2 && slot instanceof SlotCrafting) // right click
{
for (int i1 = 0; i1 < 64; i1++) // click this slot 64 times
manager.handleSlotClick(slot.slotNumber, button, 0);
@@ -140,20 +157,32 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
if (GuiInfo.hasCustomSlots(gui)) return false;
if (slotIndex >= 0 && NEIClientUtils.shiftKey()
&& NEIClientUtils.getHeldItem() != null
&& !slot.getHasStack()) {
ItemStack held = NEIClientUtils.getHeldItem();
manager.handleSlotClick(slot.slotNumber, button, 0);
if (slot.isItemValid(held) && !ItemInfo.fastTransferExemptions.contains(slot.getClass()))
fastTransferManager.performMassTransfer(gui, pickedUpFromSlot, slotIndex, held);
if (NEIClientUtils.shiftKey()) {
// fix small mouse movement while clicking causing slotIndex to be -999
if (slotIndex == -999) {
final Point mouse = GuiDraw.getMousePosition();
slot = gui.getSlotAtPosition(mouse.x, mouse.y);
return true;
}
if (slot != null) {
slotIndex = slot.slotNumber;
}
}
if (slotIndex == -999 && NEIClientUtils.shiftKey() && button == 0) {
fastTransferManager.throwAll(gui, pickedUpFromSlot);
return true;
if (slotIndex >= 0 && NEIClientUtils.getHeldItem() != null && !slot.getHasStack()) {
final ItemStack held = NEIClientUtils.getHeldItem();
manager.handleSlotClick(slot.slotNumber, button, 0);
if (slot.isItemValid(held) && !ItemInfo.fastTransferExemptions.contains(slot.getClass())) {
fastTransferManager.performMassTransfer(gui, pickedUpFromSlot, slotIndex, held);
}
return true;
}
if (slotIndex == -999 && button == 0) {
fastTransferManager.throwAll(gui, pickedUpFromSlot);
return true;
}
}
return false;
@@ -7,8 +7,7 @@ import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import net.minecraft.util.EnumChatFormatting;
import java.util.concurrent.CopyOnWriteArrayList;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
@@ -18,6 +17,7 @@ import codechicken.core.launch.CodeChickenCorePlugin;
import codechicken.nei.api.IConfigureNEI;
import codechicken.nei.asm.NEICorePlugin;
import codechicken.nei.config.IMCHandler;
import codechicken.nei.guihook.HideousLinkedList;
import codechicken.nei.recipe.GuiRecipeTab;
import cpw.mods.fml.client.FMLFileResourcePack;
import cpw.mods.fml.client.FMLFolderResourcePack;
@@ -31,13 +31,15 @@ import cpw.mods.fml.common.event.FMLInterModComms;
import cpw.mods.fml.common.event.FMLLoadCompleteEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.event.FMLServerAboutToStartEvent;
import cpw.mods.fml.common.versioning.ArtifactVersion;
import cpw.mods.fml.common.versioning.VersionParser;
import cpw.mods.fml.common.versioning.VersionRange;
@SuppressWarnings("UnstableApiUsage")
public class NEIModContainer extends DummyModContainer {
public static LinkedList<IConfigureNEI> plugins = new LinkedList<>();
public static final LinkedList<IConfigureNEI> plugins = new HideousLinkedList<>(new CopyOnWriteArrayList<>());
private static boolean gregTech5Loaded;
private static boolean gtnhLibLoaded;
@@ -46,7 +48,6 @@ public class NEIModContainer extends DummyModContainer {
public NEIModContainer() {
super(getModMetadata());
loadMetadata();
}
private static ModMetadata getModMetadata() {
@@ -54,7 +55,7 @@ public class NEIModContainer extends DummyModContainer {
modMetadata.name = "NotEnoughItems";
modMetadata.modId = "NotEnoughItems";
modMetadata.version = Tags.VERSION;
modMetadata.authorList = Arrays.asList("ChickenBones", "mitchej123");
modMetadata.authorList = Arrays.asList("ChickenBones", "mitchej123", "SLPrime");
modMetadata.url = "https://github.com/GTNewHorizons/NotEnoughItems";
modMetadata.description = "Recipe Viewer, Inventory Manager, Item Spawner, Cheats and more; GTNH Version includes many enhancements.";
return modMetadata;
@@ -79,36 +80,12 @@ public class NEIModContainer extends DummyModContainer {
public List<ArtifactVersion> getDependencies() {
List<ArtifactVersion> deps = new ArrayList<>();
deps.add(VersionParser.parseVersionReference("CodeChickenCore@[" + codechicken.core.asm.Tags.VERSION + ",)"));
deps.add(VersionParser.parseVersionReference("gtnhlib@[0.6.0,)"));
deps.add(VersionParser.parseVersionReference("gtnhlib@[0.9.6,)"));
return deps;
}
private String description;
private void loadMetadata() {
description = super.getMetadata().description.replace("Supporters:", EnumChatFormatting.AQUA + "Supporters:");
}
@Override
public ModMetadata getMetadata() {
StringBuilder s_plugins = new StringBuilder();
if (plugins.size() == 0) {
s_plugins.append(EnumChatFormatting.RED).append("No installed plugins.");
} else {
s_plugins.append(EnumChatFormatting.GREEN).append("Installed plugins: ");
for (int i = 0; i < plugins.size(); i++) {
if (i > 0) s_plugins.append(", ");
IConfigureNEI plugin = plugins.get(i);
s_plugins.append(plugin.getName()).append(" ").append(plugin.getVersion());
}
s_plugins.append(".");
}
ModMetadata meta = super.getMetadata();
meta.description = description.replace("<plugins>", s_plugins.toString());
return meta;
}
@Override
public boolean registerBus(EventBus bus, LoadController controller) {
bus.register(this);
@@ -125,8 +102,10 @@ public class NEIModContainer extends DummyModContainer {
@Subscribe
public void init(FMLInitializationEvent event) {
if (CommonUtils.isClient()) ClientHandler.load();
if (CommonUtils.isClient()) {
ClientHandler.load();
IMCForNEI.IMCSender();
}
ServerHandler.load();
}
@@ -147,6 +126,11 @@ public class NEIModContainer extends DummyModContainer {
}
}
@Subscribe
public void onServerAboutToStart(FMLServerAboutToStartEvent event) {
NEIServerConfig.resetFirstLoad();
}
@Subscribe
public void handleIMCMessages(FMLInterModComms.IMCEvent event) {
IMCHandler.processIMC(event.getMessages());
@@ -88,9 +88,16 @@ public class NEISPH implements IServerPacketHandler {
case C2S.SET_DUMMY_SLOT:
handleDummySlotSet(sender, packet);
break;
case C2S.SEND_CHAT_ITEM_LINK:
handleSendChatItemLink(sender, packet);
break;
}
}
private void handleSendChatItemLink(EntityPlayerMP sender, PacketCustom packet) {
NEIServerUtils.sendChatItemLink(sender, packet.readItemStack());
}
private void handleDummySlotSet(EntityPlayerMP sender, PacketCustom packet) {
int slotNumber = packet.readShort();
ItemStack stack = packet.readItemStack(true);
@@ -18,7 +18,6 @@ import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.permission.PermissionLevel;
@@ -37,21 +36,23 @@ import codechicken.lib.packet.PacketCustom;
public class NEIServerConfig {
private static MinecraftServer server;
private static boolean firstLoad;
public static Logger logger = LogManager.getLogger("NotEnoughItems");
public static File saveDir;
public static ConfigFile serverConfig;
public static Map<Integer, NBTTagCompound> dimTags = new HashMap<>();
public static HashMap<String, PlayerSave> playerSaves = new HashMap<>();
public static ItemStackMap<Set<String>> bannedItems = new ItemStackMap<>();
private static boolean doesPermAPIExist = false;
public static void resetFirstLoad() {
firstLoad = true;
}
public static void load(World world) {
if (MinecraftServer.getServer() != server) {
if (firstLoad) {
firstLoad = false;
logger.debug("Loading NEI Server");
server = MinecraftServer.getServer();
saveDir = new File(DimensionManager.getCurrentSaveRootDirectory(), "NEI");
dimTags.clear();
@@ -17,6 +17,7 @@ import net.minecraft.enchantment.Enchantment;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.event.ClickEvent;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@@ -46,9 +47,25 @@ import codechicken.nei.PacketIDs.S2C;
import codechicken.nei.util.NBTHelper;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.relauncher.ReflectionHelper;
public class NEIServerUtils {
private static class GTMetaBaseItemHolder {
private static final Class<?> gtMetaBaseItem = loadMetaBaseItem();
private static Class<?> loadMetaBaseItem() {
try {
final ClassLoader loader = NEIServerUtils.class.getClassLoader();
return ReflectionHelper
.getClass(loader, "gregtech.api.items.MetaBaseItem", "gregtech.api.items.GT_MetaBase_Item");
} catch (Exception ignored) {
return null;
}
}
}
public static boolean isRaining(World world) {
return world.getWorldInfo().isRaining();
}
@@ -69,6 +86,18 @@ public class NEIServerUtils {
player.extinguish();
}
public static void sendChatItemLink(EntityPlayerMP sender, ItemStack stackover) {
ServerUtils.sendChatToAll(
new ChatComponentTranslation(
"nei.chat.item_link.text",
sender.getDisplayName(),
stackover.func_151000_E().setChatStyle(
stackover.func_151000_E().getChatStyle().setChatClickEvent(
new ClickEvent(
ClickEvent.Action.RUN_COMMAND,
"/nei_bookmark " + stackover.writeToNBT(new NBTTagCompound()))))));
}
public static long getTime(World world) {
return world.getWorldInfo().getWorldTime();
}
@@ -146,7 +175,7 @@ public class NEIServerUtils {
/**
* NBT-friendly version of {@link #areStacksSameType(ItemStack, ItemStack)}
*
*
* @param stack1 The {@link ItemStack} being compared.
* @param stack2 The {@link ItemStack} to compare to.
* @return whether the two items are the same in terms of itemID, damage and NBT.
@@ -154,7 +183,7 @@ public class NEIServerUtils {
public static boolean areStacksSameTypeWithNBT(ItemStack stack1, ItemStack stack2) {
return stack1 != null && stack2 != null
&& stack1.getItem() == stack2.getItem()
&& (!stack2.getHasSubtypes() || stack2.getItemDamage() == stack1.getItemDamage())
&& (stack2.isItemStackDamageable() || stack2.getItemDamage() == stack1.getItemDamage())
&& NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound());
}
@@ -177,19 +206,36 @@ public class NEIServerUtils {
/**
* NBT-friendly version of {@link #areStacksSameTypeCrafting(ItemStack, ItemStack)}
*
*
* @param stack1 The {@link ItemStack} being compared.
* @param stack2 The {@link ItemStack} to compare to.
* @return whether the two items are the same from the perspective of a crafting inventory.
*/
public static boolean areStacksSameTypeCraftingWithNBT(ItemStack stack1, ItemStack stack2) {
return stack1 != null && stack2 != null
&& stack1.getItem() == stack2.getItem()
&& (stack1.getItemDamage() == stack2.getItemDamage()
|| stack1.getItemDamage() == OreDictionary.WILDCARD_VALUE
|| stack2.getItemDamage() == OreDictionary.WILDCARD_VALUE
|| stack1.getItem().isDamageable())
&& NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound());
if (NEIServerUtils.areStacksSameTypeCrafting(stack2, stack1)) {
if (NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound())) return true;
if (isItemTool(stack1)
&& (stack1.stackTagCompound == null || stack1.stackTagCompound.hasKey("GT.ToolStats"))
&& (stack2.stackTagCompound == null || stack2.stackTagCompound.hasKey("GT.ToolStats")))
return true;
return stack1.getMaxStackSize() == 1 && stack2.getMaxStackSize() == 1
&& (stack1.stackTagCompound == null ^ stack2.stackTagCompound == null);
}
return false;
}
/**
* GT Items don't have any NBT set for the recipe, so if either of the stacks has a NULL nbt, and the other doesn't,
* pretend they stack
*
* @param ItemStack stack
* @return
*/
public static boolean isItemTool(ItemStack stack) {
return GTMetaBaseItemHolder.gtMetaBaseItem != null
&& GTMetaBaseItemHolder.gtMetaBaseItem.isInstance(stack.getItem());
}
/**
@@ -23,6 +23,7 @@ public final class PacketIDs {
public static final int SET_CREATIVE_PLUS_MODE = 23;
public static final int REQUEST_POTION_GUI = 24;
public static final int SET_DUMMY_SLOT = 25;
public static final int SEND_CHAT_ITEM_LINK = 26;
}
public static final class S2C {
+12 -46
View File
@@ -11,14 +11,12 @@ import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.INEIGuiHandler;
import codechicken.nei.api.ShortcutInputHandler;
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<T extends ItemsGrid<? extends ItemsGridSlot, ? extends ItemsGrid.MouseContext>>
extends Widget implements IContainerTooltipHandler {
extends Widget {
protected static final int PADDING = 2;
@@ -84,44 +82,19 @@ public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ?
public abstract String getLabelText();
protected abstract String getPositioningSettingName();
public abstract Rectangle4i calculateBounds(GuiContainer gui);
public abstract int getMarginLeft(GuiContainer gui);
public abstract int getMarginTop(GuiContainer gui);
public abstract int getWidth(GuiContainer gui);
public abstract int getHeight(GuiContainer gui);
protected static int snapDownToMultiple(int value, int multiple) {
return (value / multiple) * multiple;
}
public void resize(GuiContainer gui) {
final Rectangle4i margin = new Rectangle4i(
getMarginLeft(gui),
getMarginTop(gui),
getWidth(gui),
getHeight(gui));
final Rectangle4i bounds = calculateBounds(gui);
final String settingName = getPositioningSettingName();
int paddingLeft = (int) Math
.ceil(margin.w * NEIClientConfig.getSetting(settingName + ".left").getIntValue() / 100000.0);
int paddingTop = (int) Math
.ceil(margin.h * NEIClientConfig.getSetting(settingName + ".top").getIntValue() / 100000.0);
int paddingRight = (int) Math
.ceil(margin.w * NEIClientConfig.getSetting(settingName + ".right").getIntValue() / 100000.0);
int paddingBottom = (int) Math
.ceil(margin.h * NEIClientConfig.getSetting(settingName + ".bottom").getIntValue() / 100000.0);
int deltaHeight = Math.min(0, margin.h - paddingTop - paddingBottom - ItemsGrid.SLOT_SIZE) / 2;
paddingLeft = Math.min(paddingLeft, Math.max(0, margin.w - paddingRight - ItemsGrid.SLOT_SIZE));
paddingRight = Math.min(paddingRight, Math.max(0, margin.w - paddingLeft - ItemsGrid.SLOT_SIZE));
paddingTop = Math.min(margin.h - ItemsGrid.SLOT_SIZE, Math.max(0, paddingTop + deltaHeight));
paddingBottom = Math.min(margin.h - paddingTop - ItemsGrid.SLOT_SIZE, Math.max(0, paddingBottom - deltaHeight));
x = margin.x + paddingLeft;
y = margin.y + paddingTop;
w = margin.w - paddingLeft - paddingRight;
h = margin.h - paddingTop - paddingBottom;
x = bounds.x;
y = bounds.y;
w = bounds.w;
h = bounds.h;
final int header = resizeHeader(gui);
final int footer = resizeFooter(gui);
@@ -176,7 +149,6 @@ public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ?
LayoutManager.addWidget(pagePrev);
LayoutManager.addWidget(pageNext);
LayoutManager.addWidget(pageLabel);
this.grid.setVisible();
}
}
@@ -314,13 +286,7 @@ public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ?
if (NEIController.manager.window instanceof GuiRecipe || NEIClientUtils.shiftKey()
|| !NEIClientConfig.canCheatItem(hoverSlot.getItemStack())) {
if (button == 0) {
GuiCraftingRecipe.openRecipeGui("item", hoverSlot.getItemStack().copy());
} else if (button == 1) {
GuiUsageRecipe.openRecipeGui("item", hoverSlot.getItemStack().copy());
}
ShortcutInputHandler.handleMouseClick(hoverSlot.getItemStack());
} else {
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.getItemStack()), button, -1);
}
@@ -14,6 +14,7 @@ import net.minecraftforge.oredict.OreDictionary;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.StackInfo;
/**
* Simply an {@link ItemStack} with position. Mainly used in the recipe handlers.
@@ -103,7 +104,7 @@ public class PositionedStack {
items = filteringPermutations(items, GuiRecipe.getSearchItemFilter());
items = filteringPermutations(items, additionalFilter);
items.sort(Comparator.comparing(FavoriteRecipes::contains).reversed());
items.sort(Comparator.comparing(FavoriteRecipes::containsManual).reversed());
return items;
}
@@ -113,16 +114,25 @@ public class PositionedStack {
return filteredItems.isEmpty() ? items : filteredItems;
}
public boolean setPermutationToRender(ItemStack ingredient) {
public int getPermutationIndex(ItemStack stack) {
for (int index = 0; index < this.items.length; index++) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(this.items[index], ingredient)) {
setPermutationToRender(index);
return true;
if (NEIServerUtils.areStacksSameType(items[index], stack)) {
return index;
}
}
return false;
return -1;
}
public boolean setPermutationToRender(ItemStack ingredient) {
final int stackIndex = getPermutationIndex(ingredient);
if (stackIndex >= 0) {
setPermutationToRender(stackIndex);
}
return stackIndex >= 0;
}
public void setPermutationToRender(int index) {
@@ -135,6 +145,10 @@ public class PositionedStack {
}
}
public boolean contains(int mx, int my) {
return mx >= this.relx - 1 && mx < this.relx + 17 && my >= this.rely - 1 && my < this.rely + 17;
}
public boolean contains(ItemStack ingredient) {
for (ItemStack item : items) if (NEIServerUtils.areStacksSameTypeCrafting(item, ingredient)) return true;
@@ -145,7 +159,7 @@ public class PositionedStack {
* NBT-friendly version of {@link #contains(ItemStack)}
*/
public boolean containsWithNBT(ItemStack ingredient) {
for (ItemStack item : items) if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(item, ingredient)) return true;
for (ItemStack item : items) if (StackInfo.equalItemAndNBT(item, ingredient, true)) return true;
return false;
}
+29 -7
View File
@@ -21,6 +21,7 @@ import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import codechicken.core.CommonUtils;
import codechicken.nei.SubsetWidget.SubsetTag;
import codechicken.nei.api.API;
import codechicken.nei.api.IRecipeFilter;
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
@@ -33,6 +34,7 @@ import codechicken.nei.util.NBTJson;
public class PresetsList {
public enum PresetMode {
SUBSET,
HIDE,
REMOVE,
GROUP;
@@ -66,11 +68,11 @@ public class PresetsList {
}
}
protected static class RecipesFilter implements IRecipeFilterProvider, IRecipeFilter {
protected static class PresetRecipeFilter implements IRecipeFilterProvider, IRecipeFilter {
public Set<String> cache;
public IRecipeFilter getFilter() {
public IRecipeFilter getRecipeFilter() {
if (cache == null) {
cache = PresetsList.presets.stream().filter(p -> p.enabled && p.mode == PresetMode.REMOVE)
@@ -81,17 +83,20 @@ public class PresetsList {
}
@Override
public boolean matches(IRecipeHandler handler, List<PositionedStack> ingredients, PositionedStack result,
List<PositionedStack> others) {
public boolean matches(IRecipeHandler handler, int recipeIndex) {
if (matchPositionedStack(ingredients, false)) {
if (matchPositionedStack(handler.getIngredientStacks(recipeIndex), false)) {
return false;
}
final PositionedStack result = handler.getResultStack(recipeIndex);
if (result != null && matchPositionedStack(result)) {
return true;
}
final List<PositionedStack> others = handler.getOtherStacks(recipeIndex);
if (!others.isEmpty() && matchPositionedStack(others, true)) {
return true;
}
@@ -143,7 +148,7 @@ public class PresetsList {
}
public static final List<Preset> presets = new ArrayList<>();
protected static RecipesFilter recipeFilter = new RecipesFilter();
protected static PresetRecipeFilter recipeFilter = new PresetRecipeFilter();
protected static ItemPanelFilter itemFilter = new ItemPanelFilter();
static {
@@ -216,6 +221,8 @@ public class PresetsList {
if (!preset.items.isEmpty()) {
presets.add(preset);
}
updateSubsets();
}
public static void savePresets() {
@@ -236,14 +243,29 @@ public class PresetsList {
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);
NEIClientConfig.logger.error("Failed to save presets list to file {}", presetsFile, e);
}
recipeFilter.cache = null;
itemFilter.cache = null;
updateSubsets();
CollapsibleItems.saveStates();
CollapsibleItems.load();
LayoutManager.markItemsDirty();
}
private static void updateSubsets() {
SubsetWidget.removeTag("Presets");
for (Preset preset : PresetsList.presets) {
if (preset.enabled && preset.mode == PresetMode.SUBSET) {
SubsetWidget.addTag(
new SubsetTag(
"Presets." + preset.name,
stack -> preset.items.contains(Preset.getIdentifier(stack))));
}
}
}
}
@@ -3,10 +3,13 @@ package codechicken.nei;
import net.minecraft.util.EnumChatFormatting;
import codechicken.nei.SearchField.GuiSearchField;
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.util.TextHistory;
public abstract class RecipeSearchField extends TextField {
public abstract class RecipeSearchField extends TextField implements ItemFilterProvider, IRecipeFilterProvider {
private static final TextHistory history = new TextHistory();
@@ -17,9 +20,12 @@ public abstract class RecipeSearchField extends TextField {
@Override
protected void initInternalTextField() {
field = new GuiSearchField();
final GuiSearchField field = new GuiSearchField();
field.setMaxStringLength(maxSearchLength);
field.setCursorPositionZero();
field.setSkipRecipeTokens(true);
((SearchTextFormatter) field.getFormatter()).setContextToken("<>");
this.field = field;
}
public boolean isVisible() {
@@ -58,10 +64,16 @@ public abstract class RecipeSearchField extends TextField {
return EnumChatFormatting.getTextWithoutFormattingCodes(s);
}
@Override
public ItemFilter getFilter() {
return ((GuiSearchField) field).getFilter();
}
@Override
public IRecipeFilter getRecipeFilter() {
return ((GuiSearchField) field).getRecipeFilter();
}
@Override
public void setFocus(boolean focus) {
final boolean previousFocus = field.isFocused();
+33 -5
View File
@@ -16,6 +16,8 @@ import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ItemList.NothingItemFilter;
import codechicken.nei.SearchTokenParser.ISearchParserProvider;
import codechicken.nei.SearchTokenParser.SearchMode;
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.StackInfo;
@@ -88,9 +90,10 @@ public class SearchField extends TextField implements ItemFilterProvider {
}
}
public static class GuiSearchField extends FormattedTextField {
public static class GuiSearchField extends FormattedTextField implements ItemFilterProvider, IRecipeFilterProvider {
protected final SearchTokenParser searchParser;
protected boolean skipRecipeTokens = false;
public GuiSearchField() {
this(SearchField.searchParser);
@@ -104,12 +107,26 @@ public class SearchField extends TextField implements ItemFilterProvider {
setPlaceholder(NEIClientUtils.translate("inventory.search.placeholder"));
}
public void setSkipRecipeTokens(boolean skipRecipeTokens) {
this.skipRecipeTokens = skipRecipeTokens;
}
@Override
public ItemFilter getFilter() {
return getFilter(getText());
}
@Override
public IRecipeFilter getRecipeFilter() {
return getRecipeFilter(getText());
}
public ItemFilter getFilter(String filterText) {
return this.searchParser.getFilter(filterText);
return this.searchParser.getFilter(filterText, this.skipRecipeTokens);
}
public IRecipeFilter getRecipeFilter(String filterText) {
return this.searchParser.getRecipeFilter(filterText);
}
}
@@ -205,7 +222,6 @@ public class SearchField extends TextField implements ItemFilterProvider {
public void onTextChange(String oldText) {
final String newText = text();
if (!newText.equals(oldText)) {
if (newText.length() > 0) NEIClientConfig.logger.debug("Searching for " + newText);
NEIClientConfig.setSearchExpression(newText);
ItemList.updateFilter.restart();
}
@@ -272,7 +288,7 @@ public class SearchField extends TextField implements ItemFilterProvider {
default:
break;
}
// regex and extended+
if (!search.isEmpty()) {
try {
return Pattern.compile(search, Pattern.MULTILINE | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
@@ -298,6 +314,9 @@ public class SearchField extends TextField implements ItemFilterProvider {
public static String getEscapedSearchText(String text) {
text = EnumChatFormatting.getTextWithoutFormattingCodes(text);
boolean addQuotes = text.contains(" ")
&& NEIClientConfig.getBooleanSetting("inventory.search.quoteDropItemName");
switch (NEIClientConfig.getIntSetting("inventory.search.patternMode")) {
case 1:
text = text.replaceAll("[\\?|\\*]", "\\\\$0");
@@ -305,11 +324,20 @@ public class SearchField extends TextField implements ItemFilterProvider {
case 2:
text = text.replaceAll("[{}()\\[\\].+*?^$\\\\|]", "\\\\$0");
break;
case 3:
// In extended+ quotes require only quotes to be escaped
if (addQuotes) {
text = text.replaceAll("\"", "\\\\$0");
} else {
String prefixes = searchParser.getPrefixes();
text = text.replaceAll("[-<>^{}|/\\\\\"" + Pattern.quote(prefixes) + "]", "\\\\$0");
}
break;
default:
break;
}
if (text.contains(" ") && NEIClientConfig.getBooleanSetting("inventory.search.quoteDropItemName")) {
if (addQuotes) {
text = "\"" + text + "\"";
}
@@ -1,66 +1,96 @@
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;
import codechicken.nei.search.SearchExpressionFormatVisitor;
import codechicken.nei.search.SearchExpressionUtils;
import codechicken.nei.search.SearchToken;
public class SearchTextFormatter implements TextFormatter {
protected final SearchTokenParser searchParser;
protected String contextToken = "";
public SearchTextFormatter(SearchTokenParser searchParser) {
this.searchParser = searchParser;
}
public void setContextToken(String contextToken) {
this.contextToken = contextToken;
}
@Override
public String format(String text) {
final String[] parts = (text + "| ").split("\\|");
StringJoiner formattedText = new StringJoiner(EnumChatFormatting.GRAY + "|");
final int patternMode = NEIClientConfig.getIntSetting("inventory.search.patternMode");
if (patternMode == 3) {
final int spaceModeEnabled = NEIClientConfig.getIntSetting("inventory.search.spaceMode");
if (spaceModeEnabled == 1) {
text = SearchTokenParser.SPACE_PATTERN.matcher(text).replaceAll("\\\\ ");
}
final SearchExpressionFormatVisitor visitor = new SearchExpressionFormatVisitor(searchParser);
return SearchExpressionUtils.visitRecipeSearchExpression(text, visitor);
} else {
final StringBuilder formattedText = new StringBuilder();
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 (String[] orQuery : searchParser.splitByDelimiters(text, "|", false)) {
final String filterText = orQuery[1];
for (SearchToken token : tokens) {
formattedPart.append(filterText.substring(startIndex, token.start));
EnumChatFormatting tokenColor = EnumChatFormatting.RESET;
formattedText.append(SearchExpressionUtils.HIGHLIGHTS.OR + orQuery[0]);
if (token.firstChar != null) {
tokenColor = searchParser.getProvider(token.firstChar).getHighlightedColor();
for (String[] contextPart : searchParser.splitByDelimiters(filterText, this.contextToken, false)) {
if (!contextPart[0].isEmpty()) {
formattedText.append(
SearchExpressionUtils.HIGHLIGHTS.RECIPE + contextPart[0].substring(0, 1)
+ EnumChatFormatting.RESET);
contextPart[1] = contextPart[0].substring(1) + contextPart[1];
}
if (contextPart[1].isEmpty()) {
continue;
}
int startIndex = 0;
for (SearchToken token : searchParser.splitSearchText(contextPart[1])) {
formattedText.append(contextPart[1].substring(startIndex, token.start));
EnumChatFormatting tokenColor = EnumChatFormatting.RESET;
if (token.firstChar != null) {
tokenColor = searchParser.getProvider(token.firstChar).getHighlightedColor();
}
if (token.ignore != null) {
formattedText
.append(SearchExpressionUtils.HIGHLIGHTS.NEGATE + String.valueOf(token.ignore));
}
if (token.firstChar != null) {
formattedText.append(tokenColor + String.valueOf(token.firstChar));
}
if (token.quotes) {
formattedText.append(SearchExpressionUtils.HIGHLIGHTS.QUOTED + "\"");
}
if (!token.rawText.isEmpty()) {
formattedText.append(tokenColor + token.rawText);
}
if (token.quotes) {
formattedText.append(SearchExpressionUtils.HIGHLIGHTS.QUOTED + "\"");
}
startIndex = token.end;
}
formattedText.append(contextPart[1].substring(startIndex, contextPart[1].length()));
}
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();
}
return formattedText.toString();
}
}
@@ -1,14 +1,11 @@
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;
@@ -18,9 +15,16 @@ 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.IRecipeFilter;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.filter.AllMultiRecipeFilter;
import codechicken.nei.filter.AnyMultiRecipeFilter;
import codechicken.nei.filter.RecipeFilter;
import codechicken.nei.filter.RecipeFilter.FilterContext;
import codechicken.nei.search.ItemFilterVisitor;
import codechicken.nei.search.RecipeFilterVisitor;
import codechicken.nei.search.SearchExpressionUtils;
import codechicken.nei.search.SearchToken;
public class SearchTokenParser {
@@ -39,20 +43,6 @@ public class SearchTokenParser {
}
}
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);
@@ -83,7 +73,7 @@ public class SearchTokenParser {
}
}
private static class IsRegisteredItemFilter implements ItemFilter {
public static class IsRegisteredItemFilter implements ItemFilter {
public ItemFilter filter;
@@ -99,10 +89,14 @@ public class SearchTokenParser {
}
}
public static final Pattern SPACE_PATTERN = Pattern.compile(" ");
protected final LRUCache<String, ItemFilter> filtersCache = new LRUCache<>(20);
protected final LRUCache<String, IRecipeFilter> recipesCache = new LRUCache<>(20);
protected final List<ISearchParserProvider> searchProviders;
protected final ProvidersCache providersCache = new ProvidersCache();
protected final Map<Character, Character> prefixRedefinitions = new HashMap<>();
protected String prefixes = null;
public SearchTokenParser(List<ISearchParserProvider> searchProviders) {
this.searchProviders = searchProviders;
@@ -114,22 +108,22 @@ public class SearchTokenParser {
public void addProvider(ISearchParserProvider provider) {
this.searchProviders.add(provider);
this.providersCache.clear();
this.filtersCache.clear();
clearCache();
}
public void clearCache() {
this.providersCache.clear();
this.filtersCache.clear();
this.recipesCache.clear();
this.prefixes = null;
}
protected List<ISearchParserProvider> getProviders() {
public List<ISearchParserProvider> getProviders() {
Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage();
if (!currentLanguage.getLanguageCode().equals(providersCache.languageCode)) {
providersCache.providers = new ArrayList<>();
providersCache.languageCode = currentLanguage.getLanguageCode();
Map<Character, ISearchParserProvider> providers = new HashMap<>();
final List<ISearchParserProvider> providersList = new ArrayList<>();
final Map<Character, ISearchParserProvider> providers = new HashMap<>();
for (int index = this.searchProviders.size() - 1; index >= 0; index--) {
ISearchParserProvider provider = this.searchProviders.get(index);
@@ -138,177 +132,360 @@ public class SearchTokenParser {
if (provider.getSearchMode() == SearchMode.PREFIX && !providers.containsKey(provider.getPrefix())) {
providers.put(provider.getPrefix(), provider);
} else if (provider.getSearchMode() == SearchMode.ALWAYS) {
providersCache.providers.add(provider);
providersList.add(provider);
}
}
}
providersCache.providers.addAll(providers.values());
providersList.addAll(providers.values());
providersCache.languageCode = currentLanguage.getLanguageCode();
providersCache.providers = providersList;
}
return providersCache.providers;
}
public boolean hasRedefinedPrefix(char ch) {
return getPrefixes().indexOf(ch) >= 0;
}
public ISearchParserProvider getProvider(char ch) {
return getProviders().stream()
.filter(
provider -> provider.getSearchMode() == SearchMode.PREFIX
&& getRedefinedPrefix(provider.getPrefix()) == ch)
.findFirst().orElse(null);
if (!hasRedefinedPrefix(ch)) {
return null;
}
for (ISearchParserProvider provider : getProviders()) {
if (provider.getSearchMode() == SearchMode.PREFIX && getRedefinedPrefix(provider.getPrefix()) == ch) {
return provider;
}
}
return null;
}
public List<ItemFilter> getAlwaysProvidersFilters(String searchText) {
final List<ItemFilter> filters = new ArrayList<>();
for (ISearchParserProvider provider : getProviders()) {
if (provider.getSearchMode() == SearchMode.ALWAYS) {
filters.add(provider.getFilter(searchText));
}
}
return filters;
}
public synchronized ItemFilter getFilter(String filterText) {
return getFilter(filterText, false);
}
public synchronized ItemFilter getFilter(String rawText, boolean skipRecipeTokens) {
final String filterText = EnumChatFormatting.getTextWithoutFormattingCodes(rawText).toLowerCase();
if (filterText == null || filterText.isEmpty()) {
return new EverythingItemFilter();
}
final int patternMode = NEIClientConfig.getIntSetting("inventory.search.patternMode");
if (patternMode != 3) {
return this.filtersCache.computeIfAbsent(skipRecipeTokens + ":" + filterText, _t -> {
final List<ItemFilter> searchTokens = new ArrayList<>();
for (String[] subQuery : splitByDelimiters(filterText, "|", false)) {
if (subQuery[1].isEmpty()) {
continue;
}
final List<ItemFilter> tokens = new ArrayList<>();
for (String[] contextQuery : splitByDelimiters(subQuery[1], skipRecipeTokens ? "<>" : "", false)) {
if (contextQuery[1].isEmpty() || contextQuery[0].startsWith(">")) {
continue;
}
if (!contextQuery[0].isEmpty()) {
contextQuery[0] = contextQuery[0].substring(1);
}
for (SearchToken token : splitSearchText(contextQuery[0] + contextQuery[1])) {
final ItemFilter result = token.getFilter(this);
if (result != null) {
tokens.add(result);
}
}
}
if (tokens.size() == 1) {
searchTokens.add(tokens.get(0));
} else if (!tokens.isEmpty()) {
searchTokens.add(new AllMultiItemFilter(tokens));
}
}
if (searchTokens.isEmpty()) {
return new EverythingItemFilter();
} else if (searchTokens.size() == 1) {
return new IsRegisteredItemFilter(searchTokens.get(0));
} else {
return new IsRegisteredItemFilter(new AnyMultiItemFilter(searchTokens));
}
});
} else {
return this.filtersCache.computeIfAbsent(filterText, text -> {
final int spaceMode = NEIClientConfig.getIntSetting("inventory.search.spaceMode");
if (spaceMode == 1) {
text = SearchTokenParser.SPACE_PATTERN.matcher(text).replaceAll("\\\\ ");
}
if (skipRecipeTokens) {
return new IsRegisteredItemFilter(
SearchExpressionUtils.visitRecipeSearchExpression(text, new ItemFilterVisitor(this)));
} else {
return new IsRegisteredItemFilter(
SearchExpressionUtils.visitSearchExpression(text, new ItemFilterVisitor(this)));
}
});
}
}
public synchronized IRecipeFilter getRecipeFilter(String filterText) {
filterText = EnumChatFormatting.getTextWithoutFormattingCodes(filterText).toLowerCase();
return this.filtersCache.computeIfAbsent(filterText, text -> {
final String[] parts = text.split("\\|");
final List<ItemFilter> searchTokens = Arrays.stream(parts).map(this::parseSearchText).filter(s -> s != null)
.collect(Collectors.toList());
if (filterText == null || filterText.isEmpty()) {
return new RecipeFilter(FilterContext.ANY, true, new EverythingItemFilter());
}
if (searchTokens.isEmpty()) {
return new EverythingItemFilter();
} else if (searchTokens.size() == 1) {
return new IsRegisteredItemFilter(searchTokens.get(0));
} else {
return new IsRegisteredItemFilter(new AnyMultiItemFilter(searchTokens));
}
final int patternMode = NEIClientConfig.getIntSetting("inventory.search.patternMode");
});
if (patternMode != 3) {
return this.recipesCache.computeIfAbsent(filterText, input -> {
final List<IRecipeFilter> searchTokens = new ArrayList<>();
for (String[] orQueryPart : splitByDelimiters(input, "|", false)) {
if (orQueryPart[1].isEmpty()) {
continue;
}
final List<IRecipeFilter> contextList = new ArrayList<>();
for (String[] contextQuery : splitByDelimiters(orQueryPart[1], "<>", false)) {
if (contextQuery[1].isEmpty()) {
continue;
}
final List<IRecipeFilter> tokens = new ArrayList<>();
FilterContext context = FilterContext.ANY;
if (!contextQuery[0].isEmpty()) {
context = FilterContext.fromChar(contextQuery[0].charAt(0));
contextQuery[0] = contextQuery[0].substring(1);
}
for (SearchToken token : splitSearchText(contextQuery[0] + contextQuery[1])) {
final ItemFilter result = token.getFilter(this);
if (result != null) {
tokens.add(
new RecipeFilter(context, token.ignore == null || token.ignore != '!', result));
}
}
if (tokens.size() == 1) {
contextList.add(tokens.get(0));
} else if (!tokens.isEmpty()) {
contextList.add(new AllMultiRecipeFilter(tokens));
}
}
if (contextList.size() == 1) {
searchTokens.add(contextList.get(0));
} else if (!contextList.isEmpty()) {
searchTokens.add(new AllMultiRecipeFilter(contextList));
}
}
if (searchTokens.isEmpty()) {
return new RecipeFilter(FilterContext.ANY, true, new EverythingItemFilter());
} else if (searchTokens.size() == 1) {
return searchTokens.get(0);
} else {
return new AnyMultiRecipeFilter(searchTokens);
}
});
} else {
return this.recipesCache.computeIfAbsent(filterText, text -> {
final int spaceMode = NEIClientConfig.getIntSetting("inventory.search.spaceMode");
if (spaceMode == 1) {
text = SearchTokenParser.SPACE_PATTERN.matcher(text).replaceAll("\\\\ ");
}
return SearchExpressionUtils.visitRecipeSearchExpression(text, new RecipeFilterVisitor(this));
});
}
}
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);
final String prefixes = getPrefixes();
SearchToken lastToken = null;
int lastEnd = 0;
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");
for (String[] part : splitByDelimiters(filterText, "-!" + prefixes, true)) {
final SearchToken token = createToken(lastEnd, part, prefixes);
final int length = part[0].length() + part[1].length();
if (firstChar != null && !firstChar.isEmpty()) {
token.firstChar = firstChar.charAt(0);
if (token.isSimpleFilter() && token.rawText.isEmpty()) {
lastEnd += length;
continue;
}
if (token.rawText == null) { // spaceMode == 0
token.rawText = filterMatcher.group("tokenB");
token.quotes = token.rawText.length() > 1 && token.rawText.startsWith("\"")
&& token.rawText.endsWith("\"");
if (spaceMode == 0) { // and
tokens.add(lastToken = token);
} else if (spaceMode == 1) { // space
if (token.quotes) {
token.rawText = token.rawText.substring(1, token.rawText.length() - 1);
if (lastToken != null && lastToken.isSimpleFilter() && token.isSimpleFilter()) {
lastToken.rawText = filterText.substring(lastToken.start, token.end).trim();
lastToken.words[0] = lastToken.rawText;
lastToken.end = token.end;
} else {
tokens.add(lastToken = token);
}
} else if (spaceMode == 2) { // and-x
if (lastToken != null && lastToken.isSimpleFilter() && token.isSimpleFilter()) {
final String[] newWords = new String[lastToken.words.length + token.words.length];
System.arraycopy(lastToken.words, 0, newWords, 0, lastToken.words.length);
System.arraycopy(token.words, 0, newWords, lastToken.words.length, token.words.length);
lastToken.words = newWords;
lastToken.rawText = filterText.substring(lastToken.start, token.end).trim();
lastToken.end = token.end;
} else {
tokens.add(lastToken = token);
}
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);
lastEnd += length;
}
return tokens;
}
private String getPrefixes() {
StringBuilder prefixes = new StringBuilder().append('\0');
private SearchToken createToken(int lastEnd, String[] part, String prefixes) {
final SearchToken token = new SearchToken();
String pref = part[0];
String query = part[1].trim();
for (ISearchParserProvider provider : getProviders()) {
if (provider.getSearchMode() == SearchMode.PREFIX) {
prefixes.append(getRedefinedPrefix(provider.getPrefix()));
token.start = lastEnd;
token.end = lastEnd + pref.length() + query.length();
if (pref.startsWith("-")) {
token.ignore = '-';
pref = pref.substring(1);
} else if (pref.startsWith("!")) {
token.ignore = '!';
pref = pref.substring(1);
}
if (!pref.isEmpty()) {
char firstChar = pref.charAt(0);
if (prefixes.indexOf(firstChar) >= 0) {
token.firstChar = firstChar;
pref = pref.substring(1);
}
}
return prefixes.toString();
String text = pref + query;
token.quotes = text.length() > 1 && text.startsWith("\"") && text.endsWith("\"");
if (token.quotes) {
text = text.substring(1, text.length() - 1);
}
token.rawText = text;
token.words = new String[] { token.quotes ? text.replaceAll("\\\\\"", "\"") : text };
return token;
}
public List<String[]> splitByDelimiters(String input, String delimiters, boolean space) {
if (delimiters == null || delimiters.isEmpty()) {
return Collections.singletonList(new String[] { "", input });
}
final List<String[]> tokens = new ArrayList<>();
final int length = input.length();
boolean insideQuotes = false;
String token = "";
int lastEnd = 0;
int index = 0;
while (index < length) {
final char ch = input.charAt(index);
if (!insideQuotes && delimiters.indexOf(ch) >= 0
&& (!space || index == 0 || input.charAt(index - 1) == ' ')) {
if (lastEnd == index) {
token += String.valueOf(ch);
} else {
tokens.add(new String[] { token, input.substring(lastEnd, index) });
token = String.valueOf(ch);
}
lastEnd = index + 1;
} else if (!insideQuotes && space && ch != ' ' && (index > 0 && input.charAt(index - 1) == ' ')) {
tokens.add(new String[] { token, input.substring(lastEnd, index) });
token = "";
lastEnd = index;
}
if (ch == '"' && (index == 0 || input.charAt(index - 1) != '\\')) {
insideQuotes = !insideQuotes;
}
index++;
}
tokens.add(new String[] { token, input.substring(lastEnd) });
return tokens;
}
public String getPrefixes() {
if (this.prefixes == null) {
final StringBuilder builder = new StringBuilder();
for (ISearchParserProvider provider : getProviders()) {
if (provider.getSearchMode() == SearchTokenParser.SearchMode.PREFIX) {
builder.append(getRedefinedPrefix(provider.getPrefix()));
}
}
this.prefixes = builder.toString();
}
return this.prefixes;
}
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;
}
}
@@ -21,10 +21,8 @@ import cpw.mods.fml.common.gameevent.TickEvent.Phase;
public class ServerHandler {
private static ServerHandler instance;
public static void load() {
instance = new ServerHandler();
ServerHandler instance = new ServerHandler();
PacketCustom.assignHandler(NEICPH.channel, new NEISPH());
FMLCommonHandler.instance().bus().register(instance);
+166 -115
View File
@@ -1,6 +1,7 @@
package codechicken.nei;
import java.awt.Point;
import java.io.File;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
@@ -9,20 +10,21 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
import com.google.gson.JsonParser;
import codechicken.core.gui.GuiScrollSlot;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
@@ -34,18 +36,21 @@ import codechicken.nei.api.API;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.ICraftingHandler;
import codechicken.nei.recipe.IRecipeHandler;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
import codechicken.nei.util.NEIMouseUtils;
public class SubsetWidget extends Button implements ItemFilterProvider, IContainerTooltipHandler {
public class SubsetWidget extends Button implements ItemFilterProvider {
protected static final int SLOT_HEIGHT = 18;
protected static final int MARGIN = 2;
protected static final char PREFIX = '%';
protected static ReentrantReadWriteLock hiddenItemLock = new ReentrantReadWriteLock();
protected static Lock hiddenWriteLock = hiddenItemLock.writeLock();
protected static Lock hiddenReadLock = hiddenItemLock.readLock();
private static final Object hiddenLock = new Object();
public static class SubsetTag {
@@ -188,7 +193,7 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
}
public String name() {
int idx = this.fullname.indexOf('.');
int idx = this.fullname.lastIndexOf('.');
return idx < 0 ? this.fullname : this.fullname.substring(idx + 1);
}
@@ -358,14 +363,27 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
private static class DefaultParserProvider implements ISearchParserProvider {
public ItemFilter getFilter(String searchText) {
final String pathPart = searchText.replaceAll("\\s+", "").toLowerCase();
final int patternMode = NEIClientConfig.getIntSetting("inventory.search.patternMode");
Pattern pattern = null;
if (patternMode != 3) {
searchText = searchText.replaceAll("\\s+", "").toLowerCase();
} else {
pattern = SearchField.getPattern(searchText, patternMode);
}
final AnyMultiItemFilter filter = new AnyMultiItemFilter();
final Set<ItemStack> filteredItems = new HashSet<>();
final List<SubsetTag> snapshot;
for (SubsetTag tag : tags.values()) {
if (tag.filter != null && tag.path.contains(pathPart)) {
filteredItems.addAll(tag.items);
filter.filters.add(tag.filter);
synchronized (tags) {
snapshot = new ArrayList<>(tags.values());
}
for (SubsetTag tag : snapshot) {
if (tag.filter != null && matches(tag.path, searchText, pattern)) {
synchronized (tag.items) {
filteredItems.addAll(tag.items);
filter.filters.add(tag.filter);
}
}
}
@@ -384,12 +402,21 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
public SearchMode getSearchMode() {
return SearchMode.fromInt(NEIClientConfig.getIntSetting("inventory.search.subsetsSearchMode"));
}
private boolean matches(String name, String searchText, Pattern pattern) {
if (pattern != null) {
return pattern.matcher(name).find();
} else {
return name.contains(searchText);
}
}
}
/**
* All operations on this variable should be synchronised.
*/
private static final ItemStackSet hiddenItems = new ItemStackSet();
private static final Map<String, SubsetTag> tags = new HashMap<>();
private static final SubsetTag root = new SubsetTag("");
protected static boolean enableSearchBySubsets = false;
@@ -412,24 +439,26 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
}
updateHiddenItems();
SearchField.searchParser.clearCache();
}
}
public static void removeTag(String path) {
updateState.stop();
synchronized (tags) {
tags.keySet().removeIf(
parentpath -> parentpath.equals(path.toLowerCase())
|| parentpath.startsWith(path.toLowerCase() + "."));
updateHiddenItems();
SearchField.searchParser.clearCache();
}
}
public static boolean isHidden(ItemStack item) {
try {
if (hiddenReadLock.tryLock(5, TimeUnit.SECONDS)) {
try {
return hiddenItems.contains(item);
} finally {
hiddenReadLock.unlock();
}
} else {
NEIClientConfig.logger.error("Unable to obtain read lock in 'isHidden'");
}
} catch (InterruptedException e) {
e.printStackTrace();
synchronized (hiddenLock) {
return hiddenItems.contains(item);
}
return false;
}
private static List<ItemStack> getItems(SubsetTag tag, List<ItemStack> items) {
@@ -443,90 +472,45 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
}
public static void showOnly(SubsetTag tag) {
try {
if (hiddenWriteLock.tryLock(5, TimeUnit.SECONDS)) {
try {
hiddenItems.clear();
hiddenItems.addAll(getItems(root, new ArrayList<>()));
hiddenItems.removeAll(getItems(tag, new ArrayList<>()));
} finally {
hiddenWriteLock.unlock();
}
} else {
NEIClientConfig.logger.error("Unable to obtain write lock in 'showOnly'");
}
calculateVisibility();
} catch (InterruptedException e) {
e.printStackTrace();
synchronized (hiddenLock) {
hiddenItems.clear();
hiddenItems.addAll(getItems(root, new ArrayList<>()));
hiddenItems.removeAll(getItems(tag, new ArrayList<>()));
}
calculateVisibility();
}
public static void setHidden(SubsetTag tag, boolean hidden) {
try {
if (hiddenWriteLock.tryLock(5, TimeUnit.SECONDS)) {
try {
List<ItemStack> tagItems = getItems(tag, new ArrayList<>());
synchronized (hiddenLock) {
final List<ItemStack> tagItems = getItems(tag, new ArrayList<>());
if (hidden) {
hiddenItems.addAll(tagItems);
} else {
hiddenItems.removeAll(tagItems);
}
} finally {
hiddenWriteLock.unlock();
}
if (hidden) {
hiddenItems.addAll(tagItems);
} else {
NEIClientConfig.logger.error("Unable to obtain write lock in 'setHidden'");
hiddenItems.removeAll(tagItems);
}
calculateVisibility();
} catch (InterruptedException e) {
e.printStackTrace();
}
calculateVisibility();
}
public static void setHidden(ItemStack item, boolean hidden) {
try {
if (hiddenWriteLock.tryLock(5, TimeUnit.SECONDS)) {
try {
if (hidden) {
hiddenItems.add(item);
} else {
hiddenItems.remove(item);
}
} finally {
hiddenWriteLock.unlock();
}
synchronized (hiddenLock) {
if (hidden) {
hiddenItems.add(item);
} else {
NEIClientConfig.logger.error("Unable to obtain write lock in 'setHidden'");
hiddenItems.remove(item);
}
calculateVisibility();
} catch (InterruptedException e) {
e.printStackTrace();
}
calculateVisibility();
}
public static void unhideAll() {
try {
if (hiddenWriteLock.tryLock(5, TimeUnit.SECONDS)) {
try {
hiddenItems.clear();
} finally {
hiddenWriteLock.unlock();
}
} else {
NEIClientConfig.logger.error("Unable to obtain write lock in 'unhideAll'");
}
calculateVisibility();
} catch (InterruptedException e) {
e.printStackTrace();
synchronized (hiddenLock) {
hiddenItems.clear();
}
calculateVisibility();
}
public static void updateHiddenItems() {
@@ -535,6 +519,68 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
}
}
public static void loadCustomSubsets() {
File dir = new File(NEIClientConfig.configDir, "subsets");
if (!dir.exists() || !dir.isDirectory()) {
return;
}
Stream.of(dir.listFiles()).filter(file -> !file.isDirectory()).forEach(file -> {
ClientHandler.loadSettingsFile(
"subsets/" + file.getName(),
lines -> parseFile(file.getName(), lines.collect(Collectors.toList())));
});
}
private static void parseFile(String resource, List<String> itemStrings) {
final JsonParser parser = new JsonParser();
final int dotIndex = resource.lastIndexOf('.');
final String subsetNamespace = dotIndex > 0 ? resource.substring(0, dotIndex) : resource;
SubsetTag processedTag = new SubsetTag(subsetNamespace, new ItemStackSet());
for (String itemStr : itemStrings) {
try {
if (itemStr.startsWith("; ")) {
addTag(processedTag);
final String handlerName = itemStr.substring(2);
final IRecipeHandler recipeHandler = Stream
.concat(
GuiCraftingRecipe.craftinghandlers.stream(),
GuiCraftingRecipe.serialCraftingHandlers.stream())
.filter(handler -> handlerName.equals(getHandlerName(handler))).findFirst().orElse(null);
String recipeName = handlerName;
if (recipeHandler != null) {
recipeName = recipeHandler.getRecipeName().trim();
}
processedTag = new SubsetTag(
subsetNamespace + "." + recipeName.replace(".", ""),
new ItemStackSet());
} else {
final NBTBase nbt = NBTJson.toNbt(parser.parse(itemStr));
if (nbt instanceof NBTTagCompound tag) {
((ItemStackSet) processedTag.filter).add(StackInfo.loadFromNBT(tag));
} else {
throw new IllegalArgumentException(
"Expected NBTTagCompound but got " + nbt.getClass().getSimpleName());
}
}
} catch (Exception e) {
NEIClientConfig.logger.error("Failed to load custom subset items from json string:\n{}", itemStr);
}
}
addTag(processedTag);
}
private static String getHandlerName(ICraftingHandler handler) {
return GuiRecipeTab.getHandlerInfo(handler).getHandlerName();
}
public static void loadHidden() {
final List<ItemStack> itemList = new LinkedList<>();
@@ -549,29 +595,20 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
return;
}
try {
if (hiddenWriteLock.tryLock(5, TimeUnit.SECONDS)) {
try {
hiddenItems.clear();
hiddenItems.addAll(itemList);
} finally {
hiddenWriteLock.unlock();
}
} else {
NEIClientConfig.logger.error("Unable to obtain second write lock in 'loadHidden'");
}
} catch (InterruptedException e) {
e.printStackTrace();
synchronized (hiddenLock) {
hiddenItems.clear();
hiddenItems.addAll(itemList);
}
}
public static void saveHidden() {
if (NEIClientConfig.world == null) return;
final NBTTagList list = new NBTTagList();
for (ItemStack stack : hiddenItems.values()) {
list.appendTag(stack.writeToNBT(new NBTTagCompound()));
synchronized (hiddenLock) {
for (ItemStack stack : hiddenItems.values()) {
list.appendTag(stack.writeToNBT(new NBTTagCompound()));
}
}
NEIClientConfig.world.nbt.setTag("hiddenItems", list);
@@ -589,14 +626,22 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
public void execute() {
try {
final List<SubsetTag> list = new ArrayList<>(tags.values());
final List<SubsetTag> list;
synchronized (tags) {
list = new ArrayList<>(tags.values());
}
root.clearCache();
list.parallelStream().forEach(tag -> {
tag.clearCache();
ItemList.items.stream().filter(tag.filter::matches)
.collect(Collectors.toCollection(() -> tag.items));
if (!(tag.filter instanceof NothingItemFilter)) {
ItemList.items.stream().filter(tag.filter::matches)
.collect(Collectors.toCollection(() -> tag.items));
}
});
for (SubsetTag tag : list) {
@@ -632,6 +677,7 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
e.printStackTrace();
}
SearchField.searchParser.clearCache();
}
}
@@ -648,6 +694,11 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
if (NEIClientConfig.subsetWidgetOnTop()) {
return NEIClientUtils.translate("inventory.item_subsets");
} else {
final String translated = NEIClientUtils.translate("gui.button.label.subset");
if (!translated.startsWith("nei.")) { // Optional localization string for resource packs
return translated;
}
return EnumChatFormatting.DARK_PURPLE + String.valueOf(SearchField.searchParser.getRedefinedPrefix(PREFIX))
+ EnumChatFormatting.RESET;
}
@@ -689,7 +740,7 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
root.resize(screen, parent, dropRight);
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
GuiContainerManager.enable2DRender();
GuiContainerManager.drawItems.zLevel += 100;
@@ -840,7 +891,7 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
}
@Override
public Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
public Map<String, String> handleHotkeys(int mousex, int mousey, Map<String, String> hotkeys) {
if (SubsetWidget.hoverStack != null) {
+1 -1
View File
@@ -89,7 +89,7 @@ public abstract class TextField extends Widget {
onTextChange(oldText);
}
return handled;
return handled || keyID == Keyboard.KEY_SPACE;
}
public abstract void onTextChange(String oldText);
+14 -2
View File
@@ -1,6 +1,7 @@
package codechicken.nei;
import java.util.List;
import java.util.Map;
import net.minecraft.item.ItemStack;
@@ -14,8 +15,6 @@ 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;
}
@@ -38,6 +37,10 @@ public abstract class Widget {
return false;
}
public Map<String, String> handleHotkeys(int mousex, int mousey, Map<String, String> hotkeys) {
return hotkeys;
}
public void update() {}
public Rectangle4i bounds() {
@@ -58,6 +61,14 @@ public abstract class Widget {
return tooltip;
}
public List<String> handleItemTooltip(ItemStack itemstack, int mousex, int mousey, List<String> tooltip) {
return tooltip;
}
public boolean isFocused() {
return false;
}
public void loseFocus() {}
public void gainFocus() {}
@@ -67,4 +78,5 @@ public abstract class Widget {
public int z;
public int w;
public int h;
}
@@ -0,0 +1,254 @@
package codechicken.nei;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import net.minecraft.item.ItemStack;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
public class WidgetContainer extends Widget {
protected final List<Widget> widgets = new ArrayList<>();
protected boolean isFocused = false;
public void addWidget(Widget widget) {
this.widgets.add(widget);
}
public void setWidgets(List<Widget> widgets) {
final boolean isFocused = this.isFocused;
clear();
loseFocus();
for (Widget widget : widgets) {
addWidget(widget);
}
this.isFocused = isFocused;
}
public void clear() {
this.widgets.clear();
this.isFocused = false;
}
public List<Widget> getWidgets() {
return Collections.unmodifiableList(this.widgets);
}
public boolean removeIf(Predicate<Widget> filter) {
return this.widgets.removeIf(filter);
}
@Override
public void draw(int mousex, int mousey) {
drawWidgets(mousex, mousey);
}
protected void drawWidgets(int mousex, int mousey) {
final Rectangle4i bounds = bounds();
for (Widget widget : this.widgets) {
if (widget.bounds().intersects(bounds)) {
widget.draw(mousex, mousey);
}
}
}
@Override
public void update() {
for (Widget widget : this.widgets) {
widget.update();
}
Collections.sort(this.widgets, Comparator.comparingInt((Widget widget) -> widget.z));
}
public Widget getWidgetUnderMouse(int mousex, int mousey) {
if (!bounds().contains(mousex, mousey)) {
return null;
}
for (int index = this.widgets.size() - 1; index >= 0; index--) {
final Widget widget = this.widgets.get(index);
if (widget.contains(mousex, mousey)) {
return widget;
}
}
return null;
}
@Override
public boolean onMouseWheel(int scroll, int mousex, int mousey) {
final Widget widget = getWidgetUnderMouse(mousex, mousey);
return widget != null && widget.onMouseWheel(scroll, mousex, mousey);
}
@Override
public boolean handleClick(int mousex, int mousey, int button) {
if (contains(mousex, mousey)) {
gainFocus();
}
final Widget widget = getWidgetUnderMouse(mousex, mousey);
return widget != null && widget.handleClick(mousex, mousey, button);
}
@Override
public boolean handleClickExt(int mousex, int mousey, int button) {
loseFocus();
for (int index = this.widgets.size() - 1; index >= 0; index--) {
final Widget widget = this.widgets.get(index);
if (!widget.contains(mousex, mousey) && widget.handleClickExt(mousex, mousey, button)) {
return true;
}
}
return false;
}
@Override
public void mouseDragged(int mousex, int mousey, int button, long heldTime) {
for (int index = this.widgets.size() - 1; index >= 0; index--) {
final Widget widget = this.widgets.get(index);
widget.mouseDragged(mousex, mousey, button, heldTime);
}
}
@Override
public void mouseUp(int mousex, int mousey, int button) {
for (int index = this.widgets.size() - 1; index >= 0; index--) {
final Widget widget = this.widgets.get(index);
widget.mouseUp(mousex, mousey, button);
}
}
@Override
public boolean handleKeyPress(int keyCode, char keyChar) {
for (int index = this.widgets.size() - 1; index >= 0; index--) {
final Widget widget = this.widgets.get(index);
if (widget.handleKeyPress(keyCode, keyChar)) {
return true;
}
}
return false;
}
@Override
public void lastKeyTyped(int keyID, char keyChar) {
for (int index = this.widgets.size() - 1; index >= 0; index--) {
final Widget widget = this.widgets.get(index);
widget.lastKeyTyped(keyID, keyChar);
}
}
@Override
public boolean isFocused() {
return this.isFocused;
}
@Override
public void loseFocus() {
for (int index = this.widgets.size() - 1; index >= 0; index--) {
final Widget widget = this.widgets.get(index);
if (widget.isFocused()) {
widget.loseFocus();
}
}
this.isFocused = false;
}
@Override
public void gainFocus() {
final Point mouse = GuiDraw.getMousePosition();
final Widget widget = getWidgetUnderMouse(mouse.x, mouse.y);
if (widget != null) {
if (!widget.isFocused()) {
loseFocus();
widget.gainFocus();
}
} else {
loseFocus();
}
this.isFocused = true;
}
@Override
public ItemStack getStackMouseOver(int mousex, int mousey) {
final Widget widget = getWidgetUnderMouse(mousex, mousey);
if (widget != null) {
return widget.getStackMouseOver(mousex, mousey);
}
return null;
}
@Override
public void postDraw(int mousex, int mousey) {
for (Widget widget : this.widgets) {
widget.postDraw(mousex, mousey);
}
}
@Override
public void onGuiClick(int mousex, int mousey) {
for (int index = this.widgets.size() - 1; index >= 0; index--) {
final Widget widget = this.widgets.get(index);
widget.onGuiClick(mousex, mousey);
}
}
@Override
public List<String> handleTooltip(int mousex, int mousey, List<String> tooltip) {
final Widget widget = getWidgetUnderMouse(mousex, mousey);
if (widget != null) {
return widget.handleTooltip(mousex, mousey, tooltip);
}
return tooltip;
}
@Override
public Map<String, String> handleHotkeys(int mousex, int mousey, Map<String, String> hotkeys) {
final Widget widget = getWidgetUnderMouse(mousex, mousey);
if (widget != null) {
return widget.handleHotkeys(mousex, mousey, hotkeys);
}
return hotkeys;
}
}
@@ -38,7 +38,11 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
public void tickKeyStates() {
if (Minecraft.getMinecraft().currentScreen != null) return;
if (KeyManager.keyStates.get("world.moboverlay").down) mobOverlay = (mobOverlay + 1) % 2;
if (KeyManager.keyStates.get("world.moboverlay").down) {
mobOverlay = (mobOverlay + 1) % 2;
NEIClientUtils
.printChatMessage(new ChatComponentText(NEIClientUtils.translate("chat.moboverlay." + mobOverlay)));
}
if (KeyManager.keyStates.get("world.chunkoverlay").down) {
chunkOverlay = (chunkOverlay + 1) % (NEIModContainer.isGT5Loaded() ? 4 : 3);
// 0-2 (or 3 with gt)
@@ -73,9 +77,11 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
}
World world = entity.worldObj;
int worldHeight = world.getHeight();
int x1 = (int) entity.posX;
int z1 = (int) entity.posZ;
int y1 = (int) MathHelper.clip(entity.posY, 16, world.getHeight() - 16);
int y1 = (int) MathHelper.clip(entity.posY, 16, worldHeight - 16);
for (int i = 0; i <= 32; i++) {
int x = x1 - 16 + i;
@@ -94,6 +100,12 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
for (int k = 0; k <= 32; k++) {
int y = y1 - 16 + k;
if (y >= worldHeight) {
mobSpawnCache[bufIndex + k] = -1;
continue;
}
if (y > maxHeight) {
mobSpawnCache[bufIndex + k] = -1;
break;
@@ -177,6 +189,10 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
private static final AxisAlignedBB aabb = AxisAlignedBB.getBoundingBox(0, 0, 0, 0, 0, 0);
private static byte getSpawnMode(Chunk chunk, int x, int y, int z) {
if (y >= chunk.worldObj.getHeight()) {
return 0;
}
if (chunk.getSavedLightValue(EnumSkyBlock.Block, x & 15, y, z & 15) >= 8
|| !SpawnerAnimals.canCreatureTypeSpawnAtLocation(EnumCreatureType.monster, chunk.worldObj, x, y, z)) {
return 0;
@@ -24,7 +24,7 @@ public class DefaultOverlayRenderer implements IRecipeOverlayRenderer {
@Override
public void renderOverlay(GuiContainerManager gui, Slot slot) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(770, 1);
@@ -16,7 +16,6 @@ import codechicken.nei.NEIDummySlotHandler;
import codechicken.nei.NEIPotionGuiHandler;
import codechicken.nei.recipe.CheatItemHandler;
import codechicken.nei.recipe.FillFluidContainerHandler;
import codechicken.nei.recipe.GuiRecipeCatalyst;
import codechicken.nei.recipe.SearchInputDropHandler;
public class GuiInfo {
@@ -31,7 +30,6 @@ public class GuiInfo {
API.registerNEIGuiHandler(new NEICreativeGuiHandler());
API.registerNEIGuiHandler(new NEIChestGuiHandler());
API.registerNEIGuiHandler(new NEIDummySlotHandler());
API.registerNEIGuiHandler(new GuiRecipeCatalyst(null));
API.registerNEIGuiHandler(new SearchInputDropHandler());
API.registerNEIGuiHandler(new FillFluidContainerHandler());
API.registerNEIGuiHandler(new CheatItemHandler());
@@ -15,7 +15,7 @@ public interface IBookmarkContainerHandler {
for (int i = 0; i < slots.size() - 4 * 9; i++) {
if (slots.get(i).getHasStack()) {
stacks.add(slots.get(i).getStack());
stacks.add(slots.get(i).getStack().copy());
}
}
@@ -1,18 +1,14 @@
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 IRecipeFilter getRecipeFilter();
}
public boolean matches(IRecipeHandler handler, List<PositionedStack> ingredients, PositionedStack result,
List<PositionedStack> others);
public boolean matches(IRecipeHandler handler, int recipeIndex);
}
@@ -6,9 +6,22 @@ import net.minecraftforge.fluids.FluidStack;
public interface IStackStringifyHandler {
public NBTTagCompound convertItemStackToNBT(ItemStack stack, boolean saveStackSize);
default NBTTagCompound convertItemStackToNBT(ItemStack stack, boolean saveStackSize) {
return null;
}
public ItemStack convertNBTToItemStack(NBTTagCompound nbtTag);
default ItemStack convertNBTToItemStack(NBTTagCompound nbtTag) {
return null;
}
default FluidStack getFluid(ItemStack stack) {
return null;
}
default ItemStack normalizeRecipeQueryStack(ItemStack stack) {
return null;
}
default void pauseItemDamageSound(boolean pause) {}
public FluidStack getFluid(ItemStack stack);
}
+24 -11
View File
@@ -65,6 +65,7 @@ import codechicken.nei.search.IdentifierFilter;
import codechicken.nei.search.ModNameFilter;
import codechicken.nei.search.OreDictionaryFilter;
import codechicken.nei.search.TooltipFilter;
import codechicken.nei.util.ItemUntranslator;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.registry.GameRegistry;
@@ -137,6 +138,10 @@ public class ItemInfo {
addSearchProviders();
RecipeItemInputHandler.load();
PresetsList.load();
if (NEIClientConfig.enableItemUntranslator()) {
ItemUntranslator.getInstance().load();
}
}
private static void addSearchProviders() {
@@ -416,30 +421,38 @@ public class ItemInfo {
Block mouseoverBlock = world.getBlock(x, y, z);
ArrayList<ItemStack> items = new ArrayList<>();
ArrayList<IHighlightHandler> handlers = new ArrayList<>();
if (highlightIdentifiers.containsKey(null)) handlers.addAll(highlightIdentifiers.get(null));
if (highlightIdentifiers.containsKey(mouseoverBlock)) handlers.addAll(highlightIdentifiers.get(mouseoverBlock));
for (IHighlightHandler ident : handlers) {
ItemStack item = ident.identifyHighlight(world, player, hit);
final ItemStack item = ident.identifyHighlight(world, player, hit);
if (item != null) items.add(item);
}
if (items.size() > 0) return items;
if (!items.isEmpty()) return items;
ItemStack pick = mouseoverBlock.getPickBlock(hit, world, x, y, z, player);
if (pick != null) items.add(pick);
try {
final ItemStack pick = mouseoverBlock.getPickBlock(hit, world, x, y, z, player);
if (pick != null) items.add(pick);
} catch (Exception ignored) {}
if (!items.isEmpty()) return items;
if (mouseoverBlock instanceof IShearable shearable) {
if (shearable.isShearable(new ItemStack(Items.shears), world, x, y, z)) {
items.addAll(shearable.onSheared(new ItemStack(Items.shears), world, x, y, z, 0));
}
}
if (!items.isEmpty()) return items;
try {
items.addAll(mouseoverBlock.getDrops(world, x, y, z, world.getBlockMetadata(x, y, z), 0));
} catch (Exception ignored) {}
if (mouseoverBlock instanceof IShearable) {
IShearable shearable = (IShearable) mouseoverBlock;
if (shearable.isShearable(new ItemStack(Items.shears), world, x, y, z))
items.addAll(shearable.onSheared(new ItemStack(Items.shears), world, x, y, z, 0));
}
if (items.size() == 0) items.add(0, new ItemStack(mouseoverBlock, 1, world.getBlockMetadata(x, y, z)));
if (items.isEmpty()) items.add(new ItemStack(mouseoverBlock, 1, world.getBlockMetadata(x, y, z)));
return items;
}
@@ -19,15 +19,19 @@ import codechicken.nei.BookmarkContainerInfo;
import codechicken.nei.FavoriteRecipes;
import codechicken.nei.ItemPanels;
import codechicken.nei.ItemQuantityField;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.SearchField;
import codechicken.nei.bookmark.BookmarkGrid;
import codechicken.nei.bookmark.BookmarkGroup;
import codechicken.nei.bookmark.BookmarkItem;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.bookmark.BookmarksGridSlot;
import codechicken.nei.recipe.AutoCraftingManager;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiFavoriteButton;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.GuiUsageRecipe;
import codechicken.nei.recipe.Recipe;
@@ -39,6 +43,31 @@ import codechicken.nei.util.NEIMouseUtils;
public abstract class ShortcutInputHandler {
private static class HotkeysCache {
public int mousex;
public int mousey;
public ItemStack stack;
public int groupId;
public Map<String, String> hotkeys = new HashMap<>();
public boolean matches(int mousex, int mousey, ItemStack stack, int groupId) {
return Math.abs(this.mousex - mousex) < 16 && Math.abs(this.mousey - mousey) < 16
&& (this.stack == null ? stack == null && this.groupId == groupId
: stack != null && NEIClientUtils.areStacksSameTypeWithNBT(stack, this.stack));
}
public void update(int mousex, int mousey, ItemStack stack, int groupId, Map<String, String> hotkeys) {
this.mousex = mousex;
this.mousey = mousey;
this.stack = stack != null ? stack.copy() : null;
this.groupId = groupId;
this.hotkeys = hotkeys;
}
}
private static HotkeysCache hotkeysCache = new HotkeysCache();
public static boolean handleKeyEvent(ItemStack stackover) {
if (!NEIClientConfig.isLoaded()) {
@@ -65,11 +94,20 @@ public abstract class ShortcutInputHandler {
return ItemPanels.bookmarkPanel.pullBookmarkItems(groupId, NEIClientUtils.shiftKey());
}
if (NEIClientConfig.autocraftingEnabled() && ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)
&& NEIClientConfig.isKeyHashDown("gui.craft")) {
AutoCraftingManager
.runProcessing(ItemPanels.bookmarkPanel.getGrid().createRecipeChainMath(groupId));
return true;
if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft_items")
&& NEIClientUtils.shiftKey()
&& ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)) {
final RecipeChainMath math = ItemPanels.bookmarkPanel.getGrid().createRecipeChainMath(groupId);
if (math != null) {
if (!NEIClientUtils.controlKey()) {
autocraftingIgnoreInventory(math);
}
AutoCraftingManager.runProcessing(math);
return true;
}
}
}
@@ -86,11 +124,18 @@ public abstract class ShortcutInputHandler {
if (NEIClientConfig.isKeyHashDown("gui.copy_name")) {
return copyItemStackName(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.copy_id")) {
return copyItemStackID(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.copy_oredict")) {
return copyItemStackOreDictionary(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.chat_link_item")) {
return sendItemStackChatLink(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.recipe")) {
return GuiCraftingRecipe.openRecipeGui("item", stackover);
}
@@ -99,6 +144,10 @@ public abstract class ShortcutInputHandler {
return GuiUsageRecipe.openRecipeGui("item", stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.favorite")) {
return saveFavoriteTree(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark")) {
return saveRecipeInBookmark(stackover, NEIClientUtils.shiftKey(), NEIClientUtils.controlKey());
}
@@ -107,8 +156,9 @@ public abstract class ShortcutInputHandler {
return pullRecipeItems(stackover, NEIClientUtils.shiftKey());
}
if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft")) {
return runAutoCrafting(stackover);
if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft_items")
&& NEIClientUtils.shiftKey()) {
return runAutoCrafting(stackover, !NEIClientUtils.controlKey());
}
return false;
@@ -124,9 +174,9 @@ public abstract class ShortcutInputHandler {
final int button = Mouse.getEventButton();
if (button == 0) {
return GuiCraftingRecipe.openRecipeGui("item", stackover);
return GuiCraftingRecipe.openRecipeGui("item", stackover.copy());
} else if (button == 1) {
return GuiUsageRecipe.openRecipeGui("item", stackover);
return GuiUsageRecipe.openRecipeGui("item", stackover.copy());
}
}
@@ -138,6 +188,21 @@ public abstract class ShortcutInputHandler {
return true;
}
private static boolean copyItemStackID(ItemStack stackover) {
if (stackover == null || stackover.getItem() == null) return false;
GuiScreen.setClipboardString(
stackover.getItem().delegate.name()
+ (stackover.getItemDamage() != 0 ? "/" + stackover.getItemDamage() : ""));
return true;
}
private static boolean sendItemStackChatLink(ItemStack stackover) {
if (stackover == null) return false;
NEIClientUtils.sendChatItemLink(stackover); // I wish clients could just send formatted messages
return true;
}
private static boolean copyItemStackOreDictionary(ItemStack stackover) {
StringBuilder builder = new StringBuilder();
@@ -156,7 +221,7 @@ public abstract class ShortcutInputHandler {
return true;
}
private static boolean runAutoCrafting(ItemStack stackover) {
private static boolean runAutoCrafting(ItemStack stackover, boolean ignoreInventory) {
final RecipeId recipeId = GuiCraftingRecipe.getRecipeId(NEIClientUtils.getGuiContainer(), stackover);
if (recipeId != null) {
@@ -169,12 +234,12 @@ public abstract class ShortcutInputHandler {
if (recipe != null) {
math = RecipeChainMath.of(recipe, 1);
}
} else if (slot.getRecipeId() != null && !slot.isIngredient()) {
} else if (slot.getRecipeId() != null && slot.getType() != BookmarkItemType.INGREDIENT) {
if (slot.getGroup().crafting == null) {
final Recipe recipe = Recipe.of(slot.getRecipeId());
if (recipe != null) {
math = RecipeChainMath.of(recipe, slot != null ? slot.getMultiplier() : 1);
math = RecipeChainMath.of(recipe, Math.max(1, slot != null ? slot.getMultiplier() : 1));
}
} else {
math = ItemPanels.bookmarkPanel.getGrid()
@@ -184,6 +249,11 @@ public abstract class ShortcutInputHandler {
}
if (math != null) {
if (ignoreInventory) {
autocraftingIgnoreInventory(math);
}
AutoCraftingManager.runProcessing(math);
return true;
}
@@ -221,14 +291,36 @@ public abstract class ShortcutInputHandler {
return false;
}
private static boolean saveFavoriteTree(ItemStack stackover) {
final Point mouse = GuiDraw.getMousePosition();
if (ItemPanels.itemPanel.contains(mouse.x, mouse.y)
|| ItemPanels.itemPanel.historyPanel.contains(mouse.x, mouse.y)) {
final RecipeHandlerRef handlerRef = RecipeHandlerRef.of(FavoriteRecipes.getFavorite(stackover));
if (handlerRef != null) {
final GuiFavoriteButton button = new GuiFavoriteButton(handlerRef, 0, 0);
button.saveRecipeInBookmark();
return true;
}
return true;
}
return false;
}
private static boolean saveRecipeInBookmark(ItemStack stackover, boolean saveIngredients, boolean saveStackSize) {
final Point mousePos = GuiDraw.getMousePosition();
// If no slot was removed from the bookmark panel on click:
if (!ItemPanels.bookmarkPanel.removeSlot(mousePos.x, mousePos.y, saveIngredients)) {
final Recipe recipe = getFocusedRecipe(stackover, mousePos.x, mousePos.y, saveIngredients);
// --- Case 1: saving a recipe (with ingredients) ---
if (recipe != null && saveIngredients) {
// If the recipe is not already bookmarked, add it
if (!ItemPanels.bookmarkPanel.removeRecipe(recipe.getRecipeId(), BookmarkGrid.DEFAULT_GROUP_ID)) {
final Recipe singleRecipe = Recipe.of(
Arrays.asList(recipe.getResult(stackover)),
@@ -236,26 +328,38 @@ public abstract class ShortcutInputHandler {
recipe.getIngredients());
singleRecipe.setCustomRecipeId(recipe.getRecipeId());
ItemPanels.bookmarkPanel.addRecipe(singleRecipe, BookmarkGrid.DEFAULT_GROUP_ID);
ItemPanels.bookmarkPanel.addRecipe(
singleRecipe,
// Determine if stack size should be saved
saveStackSize
|| NEIClientConfig.getBooleanSetting("inventory.bookmarks.bookmarkRecipeWithCount")
? 1
: 0,
BookmarkGrid.DEFAULT_GROUP_ID);
}
// --- Case 2: saving an item only ---
} else {
final RecipeId recipeId = recipe != null ? recipe.getRecipeId() : null;
// Determine if the item is associated with a recipe and should be saved with it
final boolean existsRecipe = recipeId != null
&& ItemPanels.bookmarkPanel.existsRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID)
|| NEIClientConfig.getBooleanSetting("inventory.bookmarks.bookmarkItemsWithRecipe");
// If the item was not removed from the bookmarks, add it
if (!ItemPanels.bookmarkPanel
.removeItem(stackover, existsRecipe ? recipeId : null, BookmarkGrid.DEFAULT_GROUP_ID)) {
// Determine whether to preserve the item count
saveStackSize = saveStackSize || saveIngredients
|| ItemPanels.bookmarkPanel.existsRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID);
if (!saveStackSize) {
stackover = StackInfo.withAmount(stackover, 0);
} else if (ItemPanels.itemPanel.contains(mousePos.x, mousePos.y)
|| ItemPanels.itemPanel.historyPanel.contains(mousePos.x, mousePos.y)) {
stackover = ItemQuantityField.prepareStackWithQuantity(stackover, 0);
}
} else if (ItemPanels.itemPanel.containsWithSubpanels(mousePos.x, mousePos.y)) {
stackover = ItemQuantityField.prepareStackWithQuantity(stackover, 0);
}
ItemPanels.bookmarkPanel
.addItem(stackover, existsRecipe ? recipeId : null, BookmarkGrid.DEFAULT_GROUP_ID);
@@ -271,25 +375,38 @@ public abstract class ShortcutInputHandler {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
Recipe recipe = null;
if (useFavorites && (ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey))) {
recipe = Recipe.of(FavoriteRecipes.getFavorite(stackover));
if (recipe != null) {
recipe.getIngredients().stream().forEach(ingr -> {
final List<ItemStack> permutations = ingr.getPermutations();
for (int index = 0; index < permutations.size(); index++) {
if (FavoriteRecipes.getFavorite(permutations.get(index)) != null) {
ingr.setActiveIndex(index);
break;
}
}
});
if (useFavorites) {
ItemsGridSlot itemSlot = ItemPanels.itemPanel.getSlotMouseOver(mousex, mousey);
if (itemSlot == null) {
itemSlot = ItemPanels.itemPanel.historyPanel.getSlotMouseOver(mousex, mousey);
}
} else if (gui instanceof GuiRecipe guiRecipe) {
if (itemSlot == null) {
itemSlot = ItemPanels.itemPanel.craftablesPanel.getSlotMouseOver(mousex, mousey);
}
if (itemSlot != null) {
final RecipeId recipeId = itemSlot.getRecipeId();
if (recipeId != null && (recipe = Recipe.of(recipeId)) != null) {
recipe.getIngredients().stream().forEach(ingr -> {
final List<ItemStack> permutations = ingr.getPermutations();
for (int index = 0; index < permutations.size(); index++) {
if (FavoriteRecipes.contains(permutations.get(index))) {
ingr.setActiveIndex(index);
break;
}
}
});
}
}
}
if (gui instanceof GuiRecipe guiRecipe) {
recipe = guiRecipe.getFocusedRecipe();
}
@@ -314,8 +431,14 @@ public abstract class ShortcutInputHandler {
return ItemPanels.bookmarkPanel.pullBookmarkItems(math, shift);
}
public static Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, ItemStack stack) {
public static Map<String, String> handleHotkeys(int mousex, int mousey, ItemStack stack) {
final int groupId = ItemPanels.bookmarkPanel.getHoveredGroupId(true);
if (hotkeysCache.matches(mousex, mousey, stack, groupId)) {
return hotkeysCache.hotkeys;
}
final GuiContainer gui = NEIClientUtils.getGuiContainer();
final Map<String, String> hotkeys = new HashMap<>();
if (groupId != -1) {
@@ -334,11 +457,21 @@ public abstract class ShortcutInputHandler {
}
if (NEIClientConfig.autocraftingEnabled() && ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)) {
hotkeys.put(NEIClientConfig.getKeyName("gui.craft"), NEIClientUtils.translate("bookmark.group.craft"));
hotkeys.put(
NEIClientConfig
.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("bookmark.group.craft_missing"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.craft_all"));
}
hotkeysCache.update(mousex, mousey, stack, groupId, hotkeys);
return hotkeys;
}
if (stack == null) {
hotkeysCache.update(mousex, mousey, stack, groupId, hotkeys);
return hotkeys;
}
@@ -346,15 +479,57 @@ public abstract class ShortcutInputHandler {
final RecipeId recipeId = getHotkeyRecipeId(gui, mousex, mousey, stack, slot);
if (slot != null) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate(slot.isIngredient() ? "bookmark.remove_item" : "bookmark.remove_recipe"));
final BookmarkGroup group = slot.getGroup();
if (slot.isIngredient()) {
if (group.crafting != null && group.collapsed) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
}
NEIClientUtils.translate("bookmark.group.remove_recipe"));
} else if (slot.getRecipeId() == null || slot.getType() == BookmarkItemType.ITEM) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate("bookmark.remove_item"));
} else if (group.crafting != null && group.crafting.recipeRelations.entrySet().stream().anyMatch(
entry -> entry.getKey().equals(slot.getRecipeId())
|| entry.getValue().contains(slot.getRecipeId()))) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
} else {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
if (slot.getType() == BookmarkItemType.INGREDIENT) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate("bookmark.remove_item"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
} else {
final BookmarkItem item = slot.getBookmarkItem();
if (ItemPanels.bookmarkPanel.getGrid().createChainItems(groupId).values().stream()
.noneMatch(
m -> m.type == BookmarkItemType.RESULT && !m.equals(item)
&& item.equalsRecipe(m))) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate("bookmark.remove_recipe"));
} else {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate("bookmark.remove_item"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
}
}
}
if (BookmarkContainerInfo.getBookmarkContainerHandler(gui) != null) {
hotkeys.put(
@@ -375,11 +550,22 @@ public abstract class ShortcutInputHandler {
}
if (recipeId != null) {
hotkeys.put(
NEIClientConfig
.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("bookmark.add_item_with_recipe_and_count"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.add_item_with_recipe"));
}
if ((ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey)) && FavoriteRecipes.contains(stack)) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.favorite"),
NEIClientUtils.translate("recipe.favorite.bookmark_recipe"));
}
}
hotkeys.put(NEIClientConfig.getKeyName("gui.recipe"), NEIClientUtils.translate("itempanel.open_crafting"));
@@ -387,6 +573,10 @@ public abstract class ShortcutInputHandler {
hotkeys.put(NEIClientConfig.getKeyName("gui.copy_name"), NEIClientUtils.translate("itempanel.copy_name"));
hotkeys.put(NEIClientConfig.getKeyName("gui.copy_oredict"), NEIClientUtils.translate("itempanel.copy_oredict"));
hotkeys.put(NEIClientConfig.getKeyName("gui.copy_id"), NEIClientUtils.translate("itempanel.copy_id"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.chat_link_item"),
NEIClientUtils.translate("itempanel.chat_link_item"));
if (!(gui instanceof GuiRecipe) && NEIClientConfig.canCheatItem(stack)) {
hotkeys.put(
@@ -395,6 +585,9 @@ public abstract class ShortcutInputHandler {
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_RMB),
NEIClientUtils.translate("itempanel.open_usage"));
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.CTRL_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("itempanel.infinite_item"));
} else {
hotkeys.put(
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB),
@@ -430,31 +623,74 @@ public abstract class ShortcutInputHandler {
}
if (NEIClientConfig.autocraftingEnabled()) {
hotkeys.put(NEIClientConfig.getKeyName("gui.craft"), NEIClientUtils.translate("itempanel.craft"));
hotkeys.put(
NEIClientConfig.getKeyName(
"gui.craft_items",
NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("itempanel.craft_missing"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("itempanel.craft_all"));
}
}
}
hotkeysCache.update(mousex, mousey, stack, groupId, hotkeys);
return hotkeys;
}
private static void autocraftingIgnoreInventory(RecipeChainMath math) {
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
final List<ItemStack> playerInventory = AutoCraftingManager.getInventoryItems(guiContainer).values();
final RecipeId rootRecipeId = math.createMasterRoot();
for (BookmarkItem item : math.recipeIngredients) {
if (item.amount > 0 && rootRecipeId.equals(item.recipeId)) {
long amount = 0;
for (ItemStack stack : playerInventory) {
if (NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack, item.itemStack)) {
amount += StackInfo.getAmount(stack);
}
}
if (amount >= item.amount) {
item.factor = item.amount = amount + item.amount - (amount % item.amount);
}
}
}
}
private static RecipeId getHotkeyRecipeId(GuiContainer gui, int mousex, int mousey, ItemStack stack,
BookmarksGridSlot slot) {
if (slot != null) {
return slot.getRecipeId();
} else if (ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey)) {
return FavoriteRecipes.getFavorite(stack);
} else
if (gui instanceof GuiRecipe guiRecipe) {
final Recipe focusedRecipe = guiRecipe.getFocusedRecipe();
return slot.getType() == BookmarkItemType.INGREDIENT ? null : slot.getRecipeId();
}
if (focusedRecipe != null) {
return focusedRecipe.getRecipeId();
}
ItemsGridSlot itemSlot = ItemPanels.itemPanel.getSlotMouseOver(mousex, mousey);
if (itemSlot == null) {
itemSlot = ItemPanels.itemPanel.historyPanel.getSlotMouseOver(mousex, mousey);
}
if (itemSlot == null) {
itemSlot = ItemPanels.itemPanel.craftablesPanel.getSlotMouseOver(mousex, mousey);
}
if (itemSlot != null) {
return itemSlot.getRecipeId();
}
if (gui instanceof GuiRecipe guiRecipe) {
final Recipe focusedRecipe = guiRecipe.getFocusedRecipe();
if (focusedRecipe != null) {
return focusedRecipe.getRecipeId();
}
}
return null;
}
@@ -30,6 +30,7 @@ import codechicken.nei.ItemsGrid.MouseContext;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
@@ -88,7 +89,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
public static final Color PLACEHOLDER_COLOR = new Color(0x66222222, true);
public static final int DEFAULT_GROUP_ID = 0;
protected static final int GROUP_PANEL_WIDTH = 7;
public static final int GROUP_PANEL_WIDTH = 7;
protected static final float SCALE_SPEED = 0.1f;
protected List<BookmarkItem> bookmarkItems = new ArrayList<>();
@@ -367,19 +368,26 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
}
for (BookmarkItem item : this.bookmarkItems) {
if (item.groupId == groupId && item.recipeId != null) {
if (item.recipeId == null && item.type != BookmarkItemType.ITEM) {
item.type = BookmarkItemType.ITEM;
} else if (item.groupId == groupId && item.recipeId != null && item.type != BookmarkItemType.ITEM) {
recipeState.put(
item.recipeId,
recipeState.getOrDefault(item.recipeId, 0) | (item.isIngredient ? 1 : 2));
recipeState.getOrDefault(item.recipeId, 0)
| (item.type == BookmarkItemType.INGREDIENT ? 1 : 2));
}
}
for (BookmarkItem item : this.bookmarkItems) {
if (item.groupId == groupId && item.isIngredient
&& (item.recipeId == null || recipeState.getOrDefault(item.recipeId, 1) == 1)) {
if (item.groupId == groupId && item.type != BookmarkItemType.ITEM
&& recipeState.getOrDefault(item.recipeId, 0) != 3) {
if (item.type == BookmarkItemType.INGREDIENT) {
item.recipeId = null;
}
recipeState.remove(item.recipeId);
item.isIngredient = false;
item.recipeId = null;
item.type = BookmarkItemType.ITEM;
}
}
@@ -405,7 +413,8 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
for (int index = itemIndex; index < size; index++) {
if (item.equalsRecipe(this.bookmarkItems.get(index))) {
sortingRank.put(index, this.bookmarkItems.get(index).isIngredient ? 1 : -1);
sortingRank
.put(index, this.bookmarkItems.get(index).type == BookmarkItemType.INGREDIENT ? 1 : -1);
items.add(index);
}
}
@@ -632,6 +641,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
if (group.crafting == null) {
for (BookmarkItem item : chainItems) {
item.type = BookmarkItemType.ITEM;
item.recipeId = null;
}
}
@@ -761,6 +771,25 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
int absoluteSlotIndex = absoluteRowIndex * this.columns;
int overGroupId = getRowGroupId(overRowIndex);
// move group to same grid
if (this != sortableGroup.grid) {
final BookmarkGroup sourceGroup = sortableGroup.grid.getGroup(sortableGroup.groupId);
final List<BookmarkItem> itemsToMove = sortableGroup.getBookmarkItems();
sortableGroup.grid.removeGroup(sortableGroup.groupId);
final int groupId = this.addGroup(sourceGroup);
for (BookmarkItem item : itemsToMove) {
item.groupId = groupId;
this.bookmarkItems.add(item);
}
sortableGroup.grid = this;
sortableGroup.groupId = groupId;
this.onItemsChanged();
this.getMask();// force generate grid
}
if (sortableGroup.groupId == overGroupId) {
return;
}
@@ -820,7 +849,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
for (int itemIndex = 0; itemIndex < this.bookmarkItems.size(); itemIndex++) {
final BookmarkItem item = this.bookmarkItems.get(itemIndex);
if (item.groupId == groupId && item.isIngredient == ingredient
if (item.groupId == groupId && ingredient == (item.type == BookmarkItemType.INGREDIENT)
&& (recipeId == item.recipeId || recipeId != null && recipeId.equals(item.recipeId))
&& StackInfo.equalItemAndNBT(stackA, item.itemStack, true)) {
return itemIndex;
@@ -866,7 +895,7 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
onItemsChanged();
}
public void addRecipe(Recipe recipe, int groupId) {
public void addRecipe(Recipe recipe, int multiplier, int groupId) {
final RecipeId recipeId = recipe.getRecipeId();
final List<ItemStack> results = recipe.getResults().stream().map(res -> res.getItemStack())
.collect(Collectors.toList());
@@ -874,17 +903,26 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
.collect(Collectors.toList());
for (ItemStack stack : ItemStackAmount.of(results).values()) {
this.addItem(BookmarkItem.of(groupId, stack, StackInfo.getAmount(stack), recipeId, false), true);
}
for (ItemStack stack : ItemStackAmount.of(ingredients).values()) {
long factor = StackInfo.getAmount(stack);
this.addItem(
BookmarkItem.of(
groupId,
stack,
StackInfo.getAmount(stack),
StackInfo.withAmount(stack, factor * multiplier),
factor,
recipeId,
true,
BookmarkItemType.RESULT),
true);
}
for (ItemStack stack : ItemStackAmount.of(ingredients).values()) {
long factor = StackInfo.getAmount(stack);
this.addItem(
BookmarkItem.of(
groupId,
StackInfo.withAmount(stack, factor * multiplier),
factor,
recipeId,
BookmarkItemType.INGREDIENT,
BookmarkItem.generatePermutations(stack, recipe)),
true);
}
@@ -897,14 +935,14 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
return;
}
if (!removeFullRecipe && item.recipeId != null && !item.isIngredient) {
if (!removeFullRecipe && item.recipeId != null && item.type == BookmarkItemType.RESULT) {
removeFullRecipe = this.bookmarkItems.stream()
.noneMatch(m -> !m.isIngredient && !m.equals(item) && item.equalsRecipe(m));
.noneMatch(m -> m.type == BookmarkItemType.RESULT && !m.equals(item) && item.equalsRecipe(m));
}
if (item.recipeId != null && removeFullRecipe) {
if (item.recipeId != null && item.type != BookmarkItemType.ITEM && removeFullRecipe) {
removeRecipe(item.recipeId, item.groupId);
} else {
} else if (itemIndex >= 0) {
this.bookmarkItems.remove(itemIndex);
onItemsChanged();
}
@@ -921,7 +959,8 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
}
public boolean existsRecipe(RecipeId recipeId, int groupId) {
return this.bookmarkItems.stream().anyMatch(item -> item.equalsRecipe(recipeId, groupId));
return this.bookmarkItems.stream()
.anyMatch(item -> item.type != BookmarkItemType.ITEM && item.equalsRecipe(recipeId, groupId));
}
public RecipeId getRecipeId(int itemIndex) {
@@ -1024,9 +1063,14 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
}
if (bookmarkItem != null && (group.crafting != null && group.viewMode == BookmarkViewMode.DEFAULT
|| group.viewMode == BookmarkViewMode.TODO_LIST)) {
|| group.viewMode == BookmarkViewMode.TODO_LIST
&& sortableItem.bookmarkItem.type == BookmarkItemType.RESULT)) {
BookmarkItem prevBookmarkItem = sortIndex > 1 ? getCalculatedItem(sortedIndexes.get(sortIndex - 1)) : null;
while (sortIndex > 0 && bookmarkItem.equalsRecipe(getCalculatedItem(sortedIndexes.get(sortIndex - 1)))) {
while (sortIndex > 0 && prevBookmarkItem != null
&& prevBookmarkItem.type != BookmarkItemType.ITEM
&& bookmarkItem.equalsRecipe(prevBookmarkItem)) {
prevBookmarkItem = sortIndex > 1 ? getCalculatedItem(sortedIndexes.get(sortIndex - 1)) : null;
sortIndex--;
}
@@ -1055,7 +1099,8 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
if (nextSortIndex < sortedIndexes.size()) {
final int nextItemIndex = sortedIndexes.get(nextSortIndex);
if (group.viewMode == BookmarkViewMode.TODO_LIST && target.equalsRecipe(getCalculatedItem(nextItemIndex))) {
if (group.viewMode == BookmarkViewMode.TODO_LIST && target.type == BookmarkItemType.RESULT
&& target.equalsRecipe(getCalculatedItem(nextItemIndex))) {
return -1;
}
@@ -1116,16 +1161,16 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
if (item.factor > 0
&& outputRecipes.stream().anyMatch(recipeId -> item.equalsRecipe(recipeId, targetGroupId))) {
final long multiplier = recipeMultipliers.getOrDefault(item.recipeId, (long) Integer.MAX_VALUE);
final boolean isOutputRecipe = group.crafting != null
&& !group.crafting.recipeInMiddle.contains(item.recipeId);
final boolean recipeInMiddle = group.crafting != null
&& group.crafting.recipeInMiddle.contains(item.recipeId);
recipeMultipliers.put(
item.recipeId,
Math.min(
shiftMultiplier(
Math.max(isOutputRecipe ? 1 : 0, item.getMultiplier()),
Math.max(recipeInMiddle ? 1 : 0, item.getMultiplier()),
shift,
isOutputRecipe ? 1 : 0),
recipeInMiddle ? 1 : 0),
multiplier));
items.add(item);
}
@@ -1145,19 +1190,19 @@ public class BookmarkGrid extends ItemsGrid<BookmarksGridSlot, BookmarkGrid.Book
if (group.collapsed) {
shiftGroupAmount(targetItem.groupId, shift);
} else if (targetItem.recipeId != null) {
} else if (targetItem.recipeId != null && targetItem.type != BookmarkItemType.ITEM) {
final RecipeId recipeId = this.gridGenerator.itemToRecipe
.getOrDefault(targetItemIndex, targetItem.recipeId);
final boolean isOutputRecipe = group.crafting != null && !group.crafting.recipeInMiddle.contains(recipeId);
final boolean recipeInMiddle = group.crafting != null && group.crafting.recipeInMiddle.contains(recipeId);
long multiplier = Integer.MAX_VALUE;
for (BookmarkItem item : this.bookmarkItems) {
if (item.equalsRecipe(recipeId, targetItem.groupId) && item.factor > 0) {
multiplier = Math.min(
shiftMultiplier(
Math.max(isOutputRecipe ? 1 : 0, item.getMultiplier()),
Math.max(recipeInMiddle ? 1 : 0, item.getMultiplier()),
shift,
isOutputRecipe ? 1 : 0),
recipeInMiddle ? 1 : 0),
multiplier);
}
}
@@ -11,6 +11,7 @@ import java.util.stream.Collectors;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.ItemSorter;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.bookmark.RecipeChainDetails.BookmarkChainItem;
import codechicken.nei.bookmark.RecipeChainDetails.CalculatedType;
import codechicken.nei.recipe.Recipe.RecipeId;
@@ -117,7 +118,7 @@ public class BookmarkGridGenerator {
this.itemToSlot.put(collapsedItemIndex, absoluteSlotIndex);
this.caclulatedItems.put(collapsedItemIndex, getItem(group, collapsedItemIndex));
if (!(shadows = getShadows(group, item.recipeId)).isEmpty()) {
if (item.recipeId != null && !(shadows = getShadows(group, item.recipeId)).isEmpty()) {
borderGrid.put(absoluteSlotIndex, "recipe:" + shadows.get(0));
}
}
@@ -165,7 +166,7 @@ public class BookmarkGridGenerator {
break;
}
if (!bookmarkItem.isIngredient
if (bookmarkItem.type != BookmarkItemType.INGREDIENT
&& (group.crafting == null || group.crafting.calculatedItems.containsKey(itemIndex))) {
results.add(itemIndex);
}
@@ -193,7 +194,7 @@ public class BookmarkGridGenerator {
bookmarkItem.itemStack,
1,
bookmarkItem.recipeId,
isIngredient,
isIngredient ? BookmarkItemType.INGREDIENT : BookmarkItemType.RESULT,
Collections.emptyMap());
if ((absoluteSlotIndex = nextSlotIndex(
@@ -227,7 +228,7 @@ public class BookmarkGridGenerator {
index = Math.max(0, index);
while (j++ < maxIndex) {
boolean isFirstColumn = (index % gridColumns) == 0;
final boolean isFirstColumn = (index % gridColumns) == 0;
if (this.grid.isInvalidSlot(index % maxIndex)) {
index++;
@@ -238,17 +239,22 @@ public class BookmarkGridGenerator {
return index;
} else if (isFirstColumn && (meta.recipeId == null || previousMeta == null
|| previousMeta.groupId != meta.groupId
|| meta.type != BookmarkItemType.INGREDIENT
|| !meta.recipeId.equals(previousMeta.recipeId)
|| index + 1 < maxIndex && this.grid.isInvalidSlot((index + 1) % maxIndex))) {
// In first column must be an item without recipe, a recipe result, or an ingredient
// if the second column is occupied
return index;
} else
if (!isFirstColumn && meta.recipeId != null && meta.recipeId.equals(previousMeta.recipeId)) {
return index;
} else {
index++;
}
if (!isFirstColumn && meta.type != BookmarkItemType.ITEM
&& previousMeta.type != BookmarkItemType.ITEM
&& meta.groupId == previousMeta.groupId
&& meta.recipeId != null
&& meta.recipeId.equals(previousMeta.recipeId)) {
return index;
} else {
index++;
}
}
@@ -9,6 +9,7 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fluids.FluidStack;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.Recipe.RecipeIngredient;
@@ -16,6 +17,23 @@ import codechicken.nei.recipe.StackInfo;
public class BookmarkItem {
public enum BookmarkItemType {
INGREDIENT,
RESULT,
ITEM;
public static BookmarkItemType fromInt(int type) {
return type == 0 ? ITEM : type == 1 ? RESULT : INGREDIENT;
}
public int toInt() {
return this == ITEM ? 0 : this == RESULT ? 1 : 2;
}
}
private static Map<ItemStack, String> fuzzyPermutations = new HashMap<>();
public int groupId;
public long amount = 0L;
@@ -25,10 +43,10 @@ public class BookmarkItem {
public long factor;
public RecipeId recipeId;
public boolean isIngredient = false;
public BookmarkItemType type = BookmarkItemType.ITEM;
protected BookmarkItem(int groupId, long amount, int fluidCellAmount, ItemStack itemStack,
Map<String, ItemStack> permutations, long factor, RecipeId recipeId, boolean isIngredient) {
Map<String, ItemStack> permutations, long factor, RecipeId recipeId, BookmarkItemType type) {
this.groupId = groupId;
this.amount = amount;
@@ -38,10 +56,10 @@ public class BookmarkItem {
this.factor = factor;
this.recipeId = recipeId;
this.isIngredient = isIngredient;
this.type = type == null ? BookmarkItemType.ITEM : type;
}
public static BookmarkItem of(int groupId, ItemStack stack, long factor, RecipeId recipeId, boolean isIngredient,
public static BookmarkItem of(int groupId, ItemStack stack, long factor, RecipeId recipeId, BookmarkItemType type,
Map<String, ItemStack> permutations) {
final FluidStack fluidStack = StackInfo.getFluid(stack);
int fluidCellAmount = 1;
@@ -62,18 +80,29 @@ public class BookmarkItem {
permutations,
factor * fluidCellAmount,
recipeId,
isIngredient);
type);
}
public static BookmarkItem of(int groupId, ItemStack stack, long factor, RecipeId recipeId, boolean isIngredient) {
return of(groupId, stack, factor, recipeId, isIngredient, generatePermutations(stack, recipeId, isIngredient));
public static BookmarkItem of(int groupId, ItemStack stack, long factor, RecipeId recipeId, BookmarkItemType type) {
return of(
groupId,
stack,
factor,
recipeId,
type,
generatePermutations(stack, recipeId, type == BookmarkItemType.INGREDIENT));
}
public static BookmarkItem of(int groupId, ItemStack stack) {
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(stack);
final long factor = nbTag.hasKey("gtFluidName") ? Math.min(144, nbTag.getInteger("Count")) : 1;
return BookmarkItem
.of(groupId, stack, factor, null, false, Collections.singletonMap(getItemGUID(stack), stack));
return BookmarkItem.of(
groupId,
stack,
factor,
null,
BookmarkItemType.ITEM,
Collections.singletonMap(getItemGUID(stack), stack));
}
public BookmarkItem copyWithAmount(long amount) {
@@ -85,7 +114,7 @@ public class BookmarkItem {
this.permutations,
this.factor,
this.recipeId,
this.isIngredient);
this.type);
}
public BookmarkItem copy() {
@@ -120,13 +149,24 @@ public class BookmarkItem {
return Collections.singletonMap(getItemGUID(stack), stack);
}
private static String getItemGUID(ItemStack stack) {
private static synchronized String getItemGUID(ItemStack stack) {
final FluidStack fluidStack = StackInfo.getFluid(stack);
if (fluidStack != null) {
return fluidStack.getFluid().getName() + ":" + fluidStack.tag;
} else {
return StackInfo.getItemStackGUID(stack);
for (Map.Entry<ItemStack, String> entry : BookmarkItem.fuzzyPermutations.entrySet()) {
if (NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack, entry.getKey())) {
BookmarkItem.fuzzyPermutations.put(stack, entry.getValue());
return entry.getValue();
}
}
final String stackGUID = StackInfo.getItemStackGUID(stack);
BookmarkItem.fuzzyPermutations.put(stack, stackGUID);
return stackGUID;
}
}
@@ -172,14 +212,14 @@ public class BookmarkItem {
@Override
public int hashCode() {
return Objects.hash(this.groupId, this.fluidCellAmount, this.isIngredient, this.recipeId);
return Objects.hash(this.groupId, this.fluidCellAmount, this.type.toInt(), this.recipeId);
}
@Override
public boolean equals(Object object) {
if (object instanceof BookmarkItem item) {
return this.groupId == item.groupId && this.isIngredient == item.isIngredient
return this.groupId == item.groupId && this.type == item.type
&& this.fluidCellAmount == item.fluidCellAmount
&& StackInfo.equalItemAndNBT(this.itemStack, item.itemStack, true)
&& (this.recipeId == item.recipeId || this.recipeId != null && this.recipeId.equals(item.recipeId));
@@ -7,7 +7,6 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -16,6 +15,7 @@ import net.minecraft.nbt.NBTTagCompound;
import org.apache.commons.io.IOUtils;
import com.google.common.io.Files;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -25,6 +25,7 @@ import com.google.gson.JsonSyntaxException;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
@@ -136,6 +137,7 @@ public class BookmarkStorage {
NBTTagCompound navigation = new NBTTagCompound();
namespaces.add(new BookmarkGrid());
BookmarkGrid grid = namespaces.get(0);
boolean wasError = false;
if (NEIClientConfig.world.nbt.hasKey("bookmark")) {
navigation = NEIClientConfig.world.nbt.getCompoundTag("bookmark");
@@ -150,17 +152,19 @@ public class BookmarkStorage {
}
if (itemStr.startsWith("; ")) {
JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
if (grid.size() > 0) {
// do not create empty namespaces
grid = new BookmarkGrid();
if (navigation.hasKey("namespacePage." + namespaces.size())) {
grid.setPage(navigation.getInteger("namespacePage." + namespaces.size()));
}
namespaces.add(grid);
}
if (navigation.hasKey("namespacePage." + (namespaces.size() - 1))) {
grid.setPage(navigation.getInteger("namespacePage." + (namespaces.size() - 1)));;
}
final JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
if (settings.get("viewmode") != null) {
grid.groups.get(BookmarkGrid.DEFAULT_GROUP_ID).viewMode = BookmarkViewMode
@@ -195,17 +199,28 @@ public class BookmarkStorage {
}
if (!addItemToGrid(grid, parser.parse(itemStr).getAsJsonObject())) {
wasError = true;
NEIClientConfig.logger.warn(
"Failed to load bookmarked ItemStack from json string, the item no longer exists:\n{}",
itemStr);
}
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
} catch (Exception e) {
wasError = true;
NEIClientConfig.logger.error("Failed to load bookmarked ItemStack from json string:\n{}", itemStr);
}
}
prepareOldRecipeFormat(namespaces);
if (wasError) {
try {
Files.copy(
bookmarkFile,
new File(bookmarkFile.getAbsolutePath() + ".backup-" + System.currentTimeMillis()));
NEIClientConfig.logger.info("Backed up invalid bookmark file to {}", bookmarkFile);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to backup invalid bookmark file to {}", bookmarkFile, e);
}
}
for (BookmarkGrid gr : namespaces) {
gr.onItemsChanged();
@@ -239,7 +254,15 @@ public class BookmarkStorage {
int groupId = jsonObject.has("groupId") ? jsonObject.get("groupId").getAsInt()
: BookmarkGrid.DEFAULT_GROUP_ID;
int factor = jsonObject.has("factor") ? Math.abs(jsonObject.get("factor").getAsInt()) : (isFluid ? 144 : 1);
boolean isIngredient = jsonObject.has("ingredient") && jsonObject.get("ingredient").getAsBoolean();
BookmarkItemType type = jsonObject.has("type") ? BookmarkItemType.fromInt(jsonObject.get("type").getAsInt())
: null;
if (type == null) {
// old format
type = jsonObject.has("ingredient") && jsonObject.get("ingredient").getAsBoolean()
? BookmarkItemType.INGREDIENT
: BookmarkItemType.RESULT;
}
if (jsonObject.get("recipeId") instanceof JsonObject recipeJson) {
recipeId = RecipeId.of(recipeJson);
@@ -249,51 +272,12 @@ public class BookmarkStorage {
groupId = BookmarkGrid.DEFAULT_GROUP_ID;
}
grid.addItem(BookmarkItem.of(groupId, itemStack, factor, recipeId, isIngredient), false);
grid.addItem(BookmarkItem.of(groupId, itemStack, factor, recipeId, type), false);
}
return itemStack != null;
}
private void prepareOldRecipeFormat(List<BookmarkGrid> namespaces) {
for (BookmarkGrid grid : namespaces) {
if (grid.bookmarkItems.stream()
.noneMatch(item -> item.recipeId != null && item.recipeId.getResult() == null)) {
continue;
}
final Map<String, RecipeId> recipes = new HashMap<>();
for (BookmarkItem item : grid.bookmarkItems) {
if (item.recipeId != null && !item.isIngredient && item.recipeId.getResult() == null) {
final JsonObject recipeJson = item.recipeId.toJsonObject();
final String recipeGUID = item.groupId + ":" + NBTJson.toJson(recipeJson);
if (!recipes.containsKey(recipeGUID)) {
recipeJson.add("result", NBTJson.toJsonObject(StackInfo.itemStackToNBT(item.itemStack)));
recipes.put(recipeGUID, item.recipeId = RecipeId.of(recipeJson));
}
}
}
for (BookmarkItem item : grid.bookmarkItems) {
if (item.recipeId != null && item.recipeId.getResult() == null) {
final JsonObject recipeJson = item.recipeId.toJsonObject();
final String recipeGUID = item.groupId + ":" + NBTJson.toJson(recipeJson);
if (recipes.containsKey(recipeGUID)) {
item.recipeId = recipes.get(recipeGUID).copy();
item.permutations = BookmarkItem
.generatePermutations(item.itemStack, item.recipeId, item.isIngredient);
} else {
item.recipeId = null;
}
}
}
}
}
public void save() {
if (this.bookmarkFile == null) {
@@ -338,7 +322,7 @@ public class BookmarkStorage {
row.add("item", NBTJson.toJsonObject(StackInfo.itemStackToNBT(item.getItemStack())));
row.add("factor", new JsonPrimitive(item.getFactor()));
row.add("ingredient", new JsonPrimitive(item.isIngredient));
row.add("type", new JsonPrimitive(item.type.toInt()));
if (item.groupId != BookmarkGrid.DEFAULT_GROUP_ID) {
row.add("groupId", new JsonPrimitive(item.groupId));
@@ -359,7 +343,7 @@ public class BookmarkStorage {
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
NEIClientConfig.world.nbt.setTag("bookmark", navigation);
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save bookmarks list to file {}", bookmarkFile, e);
NEIClientConfig.logger.error("Failed to save bookmarks list to file {}", bookmarkFile, e);
}
}
@@ -4,6 +4,8 @@ import java.awt.Color;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.ItemPanels;
@@ -13,7 +15,11 @@ import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIClientUtils.Alignment;
import codechicken.nei.bookmark.BookmarkGrid.BookmarkMouseContext;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.bookmark.RecipeChainDetails.CalculatedType;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.HandlerInfo;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.ReadableNumberConverter;
@@ -51,6 +57,7 @@ public class BookmarksGridSlot extends ItemsGridSlot {
protected final CalculatedType calculatedType;
protected final CalculatedType realType;
protected final BookmarkItem bookmarkItem;
protected HandlerInfo handlerInfo = null;
protected final boolean isOutputRecipe;
protected final boolean isFirstOutput;
@@ -83,7 +90,7 @@ public class BookmarksGridSlot extends ItemsGridSlot {
this.realType = this.group.crafting.calculatedItems.get(this.itemIndex).calculatedType
== CalculatedType.INGREDIENT ? CalculatedType.INGREDIENT : CalculatedType.RESULT;
} else {
this.realType = this.bookmarkItem.isIngredient
this.realType = this.bookmarkItem.type == BookmarkItemType.INGREDIENT
|| this.group.crafting != null && this.bookmarkItem.recipeId == null ? CalculatedType.INGREDIENT
: CalculatedType.RESULT;
}
@@ -91,9 +98,10 @@ public class BookmarksGridSlot extends ItemsGridSlot {
final BookmarkGrid grid = ItemPanels.bookmarkPanel.getGrid();
final BookmarkItem prevItem = grid.getCalculatedItem(
grid.gridGenerator.slotToItem.getOrDefault(grid.gridGenerator.itemToSlot.get(this.itemIndex) - 1, -1));
this.isFirstOutput = this.itemIndex >= 0 && !this.bookmarkItem.isIngredient
this.isFirstOutput = this.itemIndex >= 0 && this.bookmarkItem.type == BookmarkItemType.RESULT
&& ((this.slotIndex % grid.getColumns()) == 0 || group.viewMode == BookmarkViewMode.DEFAULT)
&& (prevItem == null || prevItem.isIngredient || !this.bookmarkItem.equalsRecipe(prevItem));
&& (prevItem == null || prevItem.type == BookmarkItemType.INGREDIENT
|| !this.bookmarkItem.equalsRecipe(prevItem));
this.rowIndex = this.slotIndex / grid.getColumns();
}
@@ -105,12 +113,13 @@ public class BookmarksGridSlot extends ItemsGridSlot {
return this.bookmarkItem;
}
@Override
public RecipeId getRecipeId() {
return this.bookmarkItem.recipeId;
}
public boolean isIngredient() {
return this.bookmarkItem.isIngredient;
public BookmarkItemType getType() {
return this.bookmarkItem.type;
}
public BookmarkGroup getGroup() {
@@ -144,11 +153,17 @@ public class BookmarksGridSlot extends ItemsGridSlot {
return false;
}
if (this.group.crafting != null) {
if (this.slotIndex == mouseContext.slotIndex || this.group.crafting != null) {
return true;
}
return this.bookmarkItem.equalsRecipe(mouseContext.recipeId, mouseContext.groupId);
if (this.bookmarkItem.type == BookmarkItemType.ITEM && this.group.viewMode == BookmarkViewMode.TODO_LIST
&& mouseContext.rowIndex == this.rowIndex) {
return true;
}
return this.bookmarkItem.type != BookmarkItemType.ITEM
&& this.bookmarkItem.equalsRecipe(mouseContext.recipeId, mouseContext.groupId);
}
protected boolean showRealItem(BookmarkMouseContext mouseContext) {
@@ -166,7 +181,8 @@ public class BookmarksGridSlot extends ItemsGridSlot {
return true;
}
if (this.bookmarkItem.equalsRecipe(mouseContext.recipeId, mouseContext.groupId)) {
if (this.bookmarkItem.type != BookmarkItemType.ITEM
&& this.bookmarkItem.equalsRecipe(mouseContext.recipeId, mouseContext.groupId)) {
return true;
}
@@ -174,6 +190,13 @@ public class BookmarksGridSlot extends ItemsGridSlot {
&& mouseContext.recipeId.equals(this.group.crafting.itemToRecipe.get(this.itemIndex));
}
protected HandlerInfo getHandlerInfo() {
if (this.bookmarkItem.recipeId != null && this.handlerInfo == null) {
this.handlerInfo = GuiRecipeTab.getHandlerInfo(this.bookmarkItem.recipeId.getHandleName(), null);
}
return this.handlerInfo;
}
@Override
public void drawItem(Rectangle4i rect) {
super.drawItem(this.emptyItemStack, rect);
@@ -198,7 +221,7 @@ public class BookmarksGridSlot extends ItemsGridSlot {
}
if (!this.bookmarkItem.isIngredient && this.bookmarkItem.recipeId != null
if (this.bookmarkItem.type != BookmarkItemType.INGREDIENT && this.bookmarkItem.recipeId != null
&& calculatedType == null
&& showMarker
&& (mouseContext == null || mouseContext.slotIndex != this.slotIndex)) {
@@ -245,7 +268,7 @@ public class BookmarksGridSlot extends ItemsGridSlot {
drawStackSize(rect, shownItemType);
if (this.bookmarkItem.isIngredient || this.bookmarkItem.recipeId == null) {
if (this.bookmarkItem.type == BookmarkItemType.INGREDIENT || this.bookmarkItem.recipeId == null) {
return;
}
@@ -254,27 +277,65 @@ public class BookmarksGridSlot extends ItemsGridSlot {
drawMarker(
rect,
"x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(this.realMultiplier),
0xFFFFFF);
0xFFFFFF,
Alignment.TopLeft);
} else if (shownItemType == ShownItemType.SHIFT) {
drawMarker(rect, "x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(getMultiplier()), 0xFFFFFF);
drawMarker(
rect,
"x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(getMultiplier()),
0xFFFFFF,
Alignment.TopLeft);
} else if (this.isOutputRecipe || this.realMultiplier > 1) {
drawMarker(
rect,
"x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(this.realMultiplier),
NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue());
} else if (NEIClientConfig.showRecipeMarkerMode() == 1) {
drawMarker(
rect,
"R",
NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue());
NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue(),
Alignment.TopLeft);
}
} else if (NEIClientConfig.showRecipeMarkerMode() == 1) {
drawMarker(rect, "R", NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue());
}
if (this.isFirstOutput || NEIClientConfig.showRecipeMarkerMode() == 1) {
drawRecipeMarker(rect);
}
}
protected void drawMarker(Rectangle4i rect, String text, int color) {
protected void drawRecipeMarker(Rectangle4i rect) {
if (NEIClientConfig.getBooleanSetting("inventory.bookmarks.showRecipeHandlerIcon")
&& getHandlerInfo() != null) {
drawHandlerIcon(rect);
} else if (NEIClientConfig.showRecipeMarkerMode() == 1) {
drawMarker(
rect,
"R",
NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue(),
Alignment.TopRight);
}
}
protected void drawHandlerIcon(Rectangle4i rect) {
float panelFactor = 1;
if (rect.w != DEFAULT_SLOT_SIZE) {
panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
}
panelFactor *= 0.4f;
float x = rect.x + 2 + 16 - 16 * panelFactor;
GL11.glTranslatef(x, rect.y, 0);
GL11.glScaled(panelFactor, panelFactor, 1.5f);
if (this.handlerInfo.getImage() != null) {
this.handlerInfo.getImage().draw(0, 0);
} else {
GuiContainerManager.drawItem(0, 0, this.handlerInfo.getItemStack(), true, "");
}
GL11.glScaled(1f / panelFactor, 1f / panelFactor, 1f / 1.5f);
GL11.glTranslatef(-1 * x, -1 * rect.y, 0);
}
protected void drawMarker(Rectangle4i rect, String text, int color, Alignment alignment) {
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
NEIClientUtils.drawNEIOverlayText(
text,
@@ -282,7 +343,7 @@ public class BookmarksGridSlot extends ItemsGridSlot {
panelFactor,
color,
true,
Alignment.TopLeft);
alignment);
}
protected void drawStackSize(Rectangle4i rect, ShownItemType shownItemType) {
@@ -7,6 +7,7 @@ import java.util.Map;
import java.util.Set;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.recipe.Recipe.RecipeId;
public class GroupingItem {
@@ -124,7 +125,7 @@ public class GroupingItem {
final BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
if (item.recipeId != null) {
if (item.recipeId != null && item.type != BookmarkItemType.ITEM) {
final List<Integer> sortedItems = this.grid.getSortedItems();
final BookmarkGroup group = this.grid.getGroup(item.groupId);
final boolean isCollapsedGroup = group.collapsed
@@ -139,7 +140,8 @@ public class GroupingItem {
for (Integer rItemIndex : sortedItems) {
final BookmarkItem rItem = this.grid.getCalculatedItem(rItemIndex);
if (rItem.groupId == item.groupId && (isCollapsedGroup || recipeRelations.contains(rItem.recipeId))) {
if (rItem.groupId == item.groupId && (isCollapsedGroup
|| rItem.type != BookmarkItemType.ITEM && recipeRelations.contains(rItem.recipeId))) {
return this.grid.getAbsoluteSlotIndex(rItemIndex) / this.grid.getColumns();
}
}
@@ -160,7 +162,7 @@ public class GroupingItem {
final BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
if (item.recipeId != null) {
if (item.recipeId != null && item.type != BookmarkItemType.ITEM) {
final List<Integer> sortedItems = this.grid.getSortedItems();
final BookmarkGroup group = this.grid.getGroup(item.groupId);
final boolean isCollapsedGroup = group.collapsed
@@ -176,7 +178,8 @@ public class GroupingItem {
final int rItemIndex = sortedItems.get(index);
final BookmarkItem rItem = this.grid.getCalculatedItem(rItemIndex);
if (rItem.groupId == item.groupId && (isCollapsedGroup || recipeRelations.contains(rItem.recipeId))) {
if (rItem.groupId == item.groupId && (isCollapsedGroup
|| rItem.type != BookmarkItemType.ITEM && recipeRelations.contains(rItem.recipeId))) {
return this.grid.getAbsoluteSlotIndex(rItemIndex) / this.grid.getColumns();
}
}
@@ -12,6 +12,7 @@ import java.util.stream.Collectors;
import net.minecraft.item.ItemStack;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.recipe.chain.RecipeChainMath;
@@ -69,7 +70,7 @@ public class RecipeChainDetails {
item,
item.amount,
item.amount,
item.isIngredient ? CalculatedType.INGREDIENT : CalculatedType.RESULT);
item.type == BookmarkItemType.INGREDIENT ? CalculatedType.INGREDIENT : CalculatedType.RESULT);
}
public ItemStack getItemStack(long amount) {
@@ -179,9 +180,10 @@ public class RecipeChainDetails {
if (itemIndex >= 0 && this.calculatedItems.containsKey(itemIndex)) {
final BookmarkItem item = entry.getValue();
if (this.recipeInMiddle.contains(item.recipeId)) {
this.calculatedItems.get(itemIndex).setRealAmount(item.amount);
this.calculatedItems.get(itemIndex)
.setRealAmount(Math.max(0, item.factor * (item.getMultiplier() - 1)));
} else {
this.calculatedItems.get(itemIndex).setRealAmount(Math.max(item.factor, item.amount));
this.calculatedItems.get(itemIndex).setRealAmount(item.amount);
}
}
}
@@ -216,11 +218,12 @@ public class RecipeChainDetails {
for (BookmarkChainItem value : items) {
int itemIndex = sortingChainItems.get(value.getItem());
if (value.getItem().isIngredient || !recipeId.equals(value.getItem().recipeId)) {
if (value.getItem().type == BookmarkItemType.INGREDIENT || !recipeId.equals(value.getItem().recipeId)) {
itemIndex *= -1;
}
if (!value.getItem().isIngredient && !math.outputRecipes.containsKey(value.getItem().recipeId)) {
if (value.getItem().type == BookmarkItemType.RESULT
&& !math.outputRecipes.containsKey(value.getItem().recipeId)) {
value.calculatedType = CalculatedType.REMAINDER;
}
@@ -250,7 +253,7 @@ public class RecipeChainDetails {
for (BookmarkChainItem value : items) {
int itemIndex = sortingChainItems.get(value.getItem());
if (value.getItem().isIngredient || !recipeId.equals(value.getItem().recipeId)) {
if (value.getItem().type == BookmarkItemType.INGREDIENT || !recipeId.equals(value.getItem().recipeId)) {
itemIndex *= -1;
}
@@ -347,22 +350,20 @@ public class RecipeChainDetails {
private Set<RecipeId> getRecipeParents(RecipeChainMath math, RecipeId recipeId, Set<RecipeId> parents,
Set<RecipeId> visited) {
final Set<RecipeId> recipeIds = math.preferredItems.entrySet().stream()
.filter(
entry -> entry.getValue() != null && recipeId.equals(entry.getValue().recipeId)
&& !visited.contains(entry.getKey().recipeId))
.filter(entry -> entry.getValue() != null && recipeId.equals(entry.getValue().recipeId))
.map(entry -> entry.getKey().recipeId).collect(Collectors.toSet());
visited.addAll(recipeIds);
if (recipeIds.isEmpty()) {
parents.add(recipeId);
} else {
for (RecipeId ingrRecipeId : recipeIds) {
if (math.outputRecipes.containsKey(ingrRecipeId)) {
parents.add(ingrRecipeId);
} else {
getRecipeParents(math, ingrRecipeId, parents, visited);
if (visited.add(ingrRecipeId)) {
if (math.outputRecipes.containsKey(ingrRecipeId)) {
parents.add(ingrRecipeId);
} else {
getRecipeParents(math, ingrRecipeId, parents, visited);
}
}
}
@@ -9,6 +9,7 @@ import java.util.Map;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.ItemsGrid;
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
import codechicken.nei.bookmark.RecipeChainDetails.BookmarkChainItem;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.Recipe.RecipeId;
@@ -30,10 +31,10 @@ public class SortableItem {
this.grid = grid;
this.bookmarkItem = bookmarkItem.copy();
this.moveRecipe = bookmarkItem.recipeId != null && !bookmarkItem.isIngredient
this.moveRecipe = bookmarkItem.recipeId != null && bookmarkItem.type == BookmarkItemType.RESULT
&& (group.viewMode == BookmarkViewMode.TODO_LIST || group.crafting != null);
this.crossGroup = !group.collapsed && group.viewMode == BookmarkViewMode.TODO_LIST
&& !this.bookmarkItem.isIngredient;
&& bookmarkItem.type != BookmarkItemType.INGREDIENT;
this.isCollapsedRecipe = group.crafting != null && group.crafting.itemToRecipe.values().stream()
.anyMatch(recipeId -> this.bookmarkItem.equalsRecipe(recipeId, this.bookmarkItem.groupId));
@@ -0,0 +1,48 @@
package codechicken.nei.commands;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommandSender;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTException;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.ChatComponentTranslation;
import codechicken.nei.ItemPanels;
public class CommandBookmarkAdd extends CommandBase {
@Override
public String getCommandName() {
return "nei_bookmark";
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "/nei_bookmark <nbt>";
}
@Override
public int getRequiredPermissionLevel() {
return 0;
}
@Override
public void processCommand(ICommandSender sender, String[] args) {
if (args.length < 1 || args[0].length() < 3) {
sender.addChatMessage(new ChatComponentText("§c/nei_bookmark <nbt>"));
return;
}
try {
ItemPanels.bookmarkPanel.addItem(
ItemStack.loadItemStackFromNBT((NBTTagCompound) JsonToNBT.func_150315_a(String.join(" ", args))));
sender.addChatMessage(new ChatComponentTranslation("nei.chat.bookmark_added.text"));
} catch (NBTException e) {
sender.addChatMessage(new ChatComponentText(e.toString()));
}
}
}
@@ -0,0 +1,296 @@
package codechicken.nei.commands;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommandSender;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.util.ChatStyle;
import net.minecraft.util.EnumChatFormatting;
import org.apache.commons.io.IOUtils;
import com.google.gson.JsonParser;
import codechicken.core.CommonUtils;
import codechicken.nei.ClientHandler;
import codechicken.nei.ItemList;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.ICraftingHandler;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.RecipeHandlerQuery;
import codechicken.nei.util.NBTJson;
public class CommandRecipeId extends CommandBase {
protected static class ProcessDiffThread extends Thread {
protected final ICommandSender sender;
protected final File prevFile;
protected final File currFile;
protected final File diffFile;
public ProcessDiffThread(ICommandSender sender, File prevFile, File currFile, File diffFile) {
this.sender = sender;
this.prevFile = prevFile;
this.currFile = currFile;
this.diffFile = diffFile;
}
@Override
public void run() {
sendChatInfoMessage(sender, "nei.chat.recipeid.diff.start");
final Set<String> prevRecipes = loadFileContent(this.prevFile);
final Set<String> currRecipes = loadFileContent(this.currFile);
final Set<String> notAllowedRecipes = prevRecipes.stream().filter(recipe -> !currRecipes.contains(recipe))
.collect(Collectors.toCollection(TreeSet::new));
final List<String> subsetsList = new ArrayList<>();
generateSubsets(notAllowedRecipes).forEach((handlerName, recipes) -> {
subsetsList.add("; " + handlerName);
subsetsList.addAll(recipes);
});
saveFile(this.diffFile, subsetsList);
saveFile(getFile("not-allowed-recipes"), new ArrayList<>(notAllowedRecipes));
sendChatInfoMessage(sender, "nei.chat.recipeid.diff.finish");
}
private Set<String> loadFileContent(File file) {
try (FileReader reader = new FileReader(file)) {
return new HashSet<>(IOUtils.readLines(reader));
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load '{}' file {}", file.getName(), file, e);
}
return new HashSet<>();
}
private Map<String, Set<String>> generateSubsets(Set<String> notAllowedRecipes) {
final JsonParser parser = new JsonParser();
final Map<String, Set<String>> subsetsBuilder = new TreeMap<>();
for (String recipeStr : notAllowedRecipes) {
try {
final NBTTagCompound nbtRecipe = (NBTTagCompound) NBTJson.toNbt(parser.parse(recipeStr));
if (nbtRecipe.hasKey("result")) {
final NBTTagCompound nbtStack = nbtRecipe.getCompoundTag("result");
nbtStack.removeTag("Count");
subsetsBuilder.computeIfAbsent(nbtRecipe.getString("handlerName"), rn -> new TreeSet<>())
.add(NBTJson.toJson(nbtStack));
} else {
NEIClientConfig.logger.error("Found Broken RecipeId {}", recipeStr);
}
} catch (Exception ex) {
NEIClientConfig.logger.error("Found Broken RecipeId {}", recipeStr, ex);
}
}
return subsetsBuilder;
}
private void saveFile(File file, List<String> content) {
try (FileOutputStream output = new FileOutputStream(file)) {
IOUtils.writeLines(content, "\n", output, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to save recipeid diff list to file {}", file, e);
}
}
}
protected static class ProcessDumpThread extends Thread {
private ArrayList<ICraftingHandler> craftinghandlers = new ArrayList<>();
private ArrayList<ICraftingHandler> serialCraftingHandlers = new ArrayList<>();
protected final ICommandSender sender;
protected final File currFile;
public ProcessDumpThread(ICommandSender sender, File currFile) {
this.sender = sender;
this.currFile = currFile;
ClientHandler.loadSettingsFile("recipeidblacklist.cfg", lines -> {
final Set<String> names = lines.collect(Collectors.toSet());
this.craftinghandlers = GuiCraftingRecipe.craftinghandlers.stream()
.filter(h -> !names.contains(GuiRecipeTab.getHandlerInfo(h).getHandlerName()))
.collect(Collectors.toCollection(ArrayList::new));
this.serialCraftingHandlers = GuiCraftingRecipe.serialCraftingHandlers.stream()
.filter(h -> !names.contains(GuiRecipeTab.getHandlerInfo(h).getHandlerName()))
.collect(Collectors.toCollection(ArrayList::new));
});
}
@Override
public void run() {
NEIClientConfig.logger.info("Start processing recipe handlers!");
sendChatInfoMessage(sender, "nei.chat.recipeid.dump.start");
try (BufferedWriter writer = Files.newBufferedWriter(currFile.toPath(), StandardCharsets.UTF_8)) {
int total = ItemList.items.size();
int count = 0;
for (ItemStack stack : ItemList.items) {
if (count % 1000 == 0) {
NEIClientConfig.logger.info(
"({}/{}). Processing {} crafting recipes...",
count,
total,
stack.getDisplayName());
}
count++;
for (ICraftingHandler handler : getCraftingHandlers(stack)) {
for (int index = 0, num = handler.numRecipes(); index < num; index++) {
try {
final Recipe recipe = Recipe.of(handler, index);
if (!recipe.getIngredients().isEmpty() && !recipe.getResults().isEmpty()) {
writer.write(NBTJson.toJson(recipe.getRecipeId().toJsonObject()));
writer.newLine();
}
} catch (Exception ex) {
NEIClientConfig.logger.error(
"Found Broken RecipeId {}:{}",
GuiRecipeTab.getHandlerInfo(handler).getHandlerName(),
stack,
ex);
}
}
}
}
} catch (Exception e) {
NEIClientConfig.logger.error("Error dumping RecipeId", e);
}
NEIClientConfig.logger.info("Finished processing recipe handlers!");
sendChatInfoMessage(sender, "nei.chat.recipeid.dump.finish");
}
private ArrayList<ICraftingHandler> getCraftingHandlers(Object... results) {
return new RecipeHandlerQuery<>(
h -> h.getRecipeHandler("item", results),
this.craftinghandlers,
this.serialCraftingHandlers,
"Error while looking up crafting recipe",
"outputId: item",
"results: " + Arrays.toString(results))
.runWithProfiling(NEIClientUtils.translate("recipe.concurrent.crafting"));
}
}
@Override
public String getCommandName() {
return "recipeid";
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "/recipeid dump <filename> OR /recipeid diff <prev-filename> <curr-filename> [subset name]";
}
@Override
public int getRequiredPermissionLevel() {
return 0;
}
@Override
public void processCommand(ICommandSender sender, String[] args) {
final String command = args.length == 0 ? null : args[0];
if ("dump".equals(command)) {
processDumpCommand(sender, args);
} else if ("diff".equals(command)) {
processDiffCommand(sender, args);
} else {
sendChatErrorMessage(sender, getCommandUsage(sender));
}
}
protected void processDiffCommand(ICommandSender sender, String[] args) {
if (args.length > 4) {
sendChatErrorMessage(sender, "nei.chat.recipeid.many_params", getCommandUsage(sender));
return;
}
if (args.length < 3) {
sendChatErrorMessage(sender, getCommandUsage(sender));
return;
}
final File prevFilename = getFile(args[1]);
final File currFilename = getFile(args[2]);
final File diffFilename = getFile(args.length > 3 ? args[3] : "changelog");
if (!prevFilename.exists()) {
sendChatErrorMessage(sender, "nei.chat.recipeid.not_found", prevFilename.getName());
return;
}
if (!currFilename.exists()) {
sendChatErrorMessage(sender, "nei.chat.recipeid.not_found", currFilename.getName());
return;
}
(new ProcessDiffThread(sender, prevFilename, currFilename, diffFilename)).start();
}
protected void processDumpCommand(ICommandSender sender, String[] args) {
if (args.length > 2) {
sendChatErrorMessage(sender, "nei.chat.recipeid.many_params", getCommandUsage(sender));
return;
}
final File dir = new File(CommonUtils.getMinecraftDir(), "recipeid");
final String currFilename = args.length == 2 ? args[1] : "recipeId";
if (!dir.exists()) dir.mkdirs();
(new ProcessDumpThread(sender, getFile(currFilename))).start();
}
private static File getFile(String filename) {
return new File(CommonUtils.getMinecraftDir(), "recipeid/" + filename + ".json");
}
private static void sendChatInfoMessage(ICommandSender sender, String translationKey, Object... args) {
sender.addChatMessage(
new ChatComponentTranslation(translationKey, args)
.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.AQUA)));
}
private static void sendChatErrorMessage(ICommandSender sender, String translationKey, Object... args) {
sender.addChatMessage(
new ChatComponentTranslation(translationKey, args)
.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.RED)));
}
}
@@ -0,0 +1,78 @@
package codechicken.nei.commands;
import java.io.File;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommandSender;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.util.ChatStyle;
import net.minecraft.util.EnumChatFormatting;
import codechicken.nei.ItemList;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.util.ItemUntranslator;
public class CommandUntranslator extends CommandBase {
@Override
public String getCommandName() {
return "untranslator";
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "/untranslator dump OR /untranslator clear";
}
@Override
public int getRequiredPermissionLevel() {
return 0;
}
@Override
public void processCommand(ICommandSender sender, String[] args) {
final String command = args.length == 0 ? null : args[0];
if ("dump".equals(command)) {
if (ItemList.items.isEmpty()) {
sendChatErrorMessage(sender, "nei.chat.untranslator.dump.error");
return;
} else {
sendChatInfoMessage(sender, "nei.chat.untranslator.dump.start");
ItemUntranslator.getInstance().generateUntranslatedNames();
sendChatInfoMessage(sender, "nei.chat.untranslator.dump.finish");
if (NEIClientConfig.enableItemUntranslator()) {
ItemUntranslator.getInstance().load();
}
}
} else if ("clear".equals(command)) {
final File file = new File(NEIClientConfig.configDir, "untranslator.cfg");
if (file.exists() && file.delete()) {
sendChatInfoMessage(sender, "nei.chat.untranslator.clear");
if (NEIClientConfig.enableItemUntranslator()) {
ItemUntranslator.getInstance().load();
}
} else {
sendChatErrorMessage(sender, "nei.chat.untranslator.clear.error");
}
} else {
sendChatErrorMessage(sender, getCommandUsage(sender));
}
}
private static void sendChatInfoMessage(ICommandSender sender, String translationKey, Object... args) {
sender.addChatMessage(
new ChatComponentTranslation(translationKey, args)
.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.AQUA)));
}
private static void sendChatErrorMessage(ICommandSender sender, String translationKey, Object... args) {
sender.addChatMessage(
new ChatComponentTranslation(translationKey, args)
.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.RED)));
}
}
@@ -160,8 +160,8 @@ public class GuiPanelSettings extends GuiScreenWidget {
}
protected void drawItems() {
final int columns = w / ItemsGrid.SLOT_SIZE;
final int rows = (h - (PANEL_SIZE + 2) * 2) / ItemsGrid.SLOT_SIZE;
final int columns = (w - 2) / ItemsGrid.SLOT_SIZE;
final int rows = (h - (PANEL_SIZE + 2) * 2 - 2) / ItemsGrid.SLOT_SIZE;
final int paddingLeft = (w % ItemsGrid.SLOT_SIZE) / 2;
final List<ItemStack> items = ItemPanels.itemPanel.getItems();
if (items.isEmpty()) return;
@@ -97,7 +97,7 @@ public class HandlerDumper extends DataDumper {
}
writer.close();
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save dump handler list to file {}", file, e);
NEIClientConfig.logger.error("Failed to save dump handler list to file {}", file, e);
}
}
@@ -1,13 +1,13 @@
package codechicken.nei.config;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import codechicken.core.CommonUtils;
import codechicken.nei.NEIClientConfig;
@@ -15,6 +15,7 @@ import codechicken.nei.NEIServerUtils;
import codechicken.nei.recipe.CatalystInfo;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.HandlerInfo;
import codechicken.nei.recipe.InformationHandler;
import codechicken.nei.recipe.RecipeCatalysts;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Loader;
@@ -33,18 +34,11 @@ public class IMCHandler {
if (type == null || type.isEmpty()) continue;
if (CommonUtils.isClient()) {
switch (type) {
case "registerHandlerInfo":
handleRegisterHandlerInfo(message);
break;
case "removeHandlerInfo":
handleRemoveHandlerInfo(message);
break;
case "registerCatalystInfo":
handleRegisterCatalystInfo(message);
break;
case "removeCatalystInfo":
handleRemoveCatalystInfo(message);
break;
case "registerHandlerInfo" -> handleRegisterHandlerInfo(message);
case "removeHandlerInfo" -> handleRemoveHandlerInfo(message);
case "registerCatalystInfo" -> handleRegisterCatalystInfo(message);
case "removeCatalystInfo" -> handleRemoveCatalystInfo(message);
case "addItemInfo" -> handleAddItemInfo(message);
}
}
}
@@ -57,14 +51,14 @@ public class IMCHandler {
}
final NBTTagCompound tag = message.getNBTValue();
final String handler = tag.getString("handler");
NEIClientConfig.logger.info("Processing registerHandlerInfo `" + handler + "` from " + message.getSender());
NEIClientConfig.logger.info("Processing registerHandlerInfo `{}` from {}", handler, message.getSender());
final String modName = tag.getString("modName");
final String modId = tag.getString("modId");
final boolean requiresMod = tag.getBoolean("modRequired");
final String excludedModId = tag.hasKey("excludedModId") ? tag.getString("excludedModId") : null;
if (handler.equals("") || modName.equals("") || modId.equals("")) {
if (handler.isEmpty() || modName.isEmpty() || modId.isEmpty()) {
NEIClientConfig.logger.warn("Missing relevant information to registerHandlerInfo!");
return;
}
@@ -74,7 +68,7 @@ public class IMCHandler {
HandlerInfo info = new HandlerInfo(handler, modName, modId, requiresMod, excludedModId);
final String imageResource = tag.hasKey("imageResource") ? tag.getString("imageResource") : null;
if (imageResource != null && !imageResource.equals("")) {
if (imageResource != null && !imageResource.isEmpty()) {
info.setImage(
imageResource,
tag.getInteger("imageX"),
@@ -84,7 +78,7 @@ public class IMCHandler {
}
if (!info.hasImageOrItem()) {
final String itemName = tag.getString("itemName");
if (itemName != null && !itemName.equals("")) {
if (itemName != null && !itemName.isEmpty()) {
info.setItem(itemName, tag.hasKey("nbtInfo") ? tag.getString("nbtInfo") : null);
}
}
@@ -92,17 +86,24 @@ public class IMCHandler {
info.setYShift(yShift);
try {
final int imageHeight = tag.hasKey("handlerHeight") ? tag.getInteger("handlerHeight")
final int handlerHeight = tag.hasKey("handlerHeight") ? tag.getInteger("handlerHeight")
: HandlerInfo.DEFAULT_HEIGHT;
final int imageWidth = tag.hasKey("handlerWidth") ? tag.getInteger("handlerWidth")
final int handlerWidth = tag.hasKey("handlerWidth") ? tag.getInteger("handlerWidth")
: HandlerInfo.DEFAULT_WIDTH;
final int maxRecipesPerPage = tag.hasKey("maxRecipesPerPage") ? tag.getInteger("maxRecipesPerPage")
: HandlerInfo.DEFAULT_MAX_PER_PAGE;
info.setHandlerDimensions(imageHeight, imageWidth, maxRecipesPerPage);
final boolean multipleWidgetsAllowed = tag.hasKey("multipleWidgetsAllowed")
? tag.getBoolean("multipleWidgetsAllowed")
: tag.hasKey("maxRecipesPerPage") && tag.getInteger("maxRecipesPerPage") > 1;
info.setHandlerDimensions(handlerWidth, handlerHeight);
info.setMultipleWidgetsAllowed(multipleWidgetsAllowed);
} catch (NumberFormatException ignored) {
NEIClientConfig.logger.info("Error setting handler dimensions for " + handler);
NEIClientConfig.logger.info("Error setting handler dimensions for {}", handler);
}
// true if not set to false
info.setUseCustomScroll(tag.hasKey("useCustomScroll") && tag.getBoolean("useCustomScroll"));
info.setShowFavoritesButton(!tag.hasKey("showFavoritesButton") || tag.getBoolean("showFavoritesButton"));
info.setShowOverlayButton(!tag.hasKey("showOverlayButton") || tag.getBoolean("showOverlayButton"));
GuiRecipeTab.handlerAdderFromIMC.remove(handler);
GuiRecipeTab.handlerAdderFromIMC.put(handler, info);
}
@@ -114,7 +115,7 @@ public class IMCHandler {
}
final NBTTagCompound tag = message.getNBTValue();
final String handler = tag.getString("handler");
NEIClientConfig.logger.info("Processing removeHandlerInfo `" + handler + "` from " + message.getSender());
NEIClientConfig.logger.info("Processing removeHandlerInfo `{}` from {}", handler, message.getSender());
GuiRecipeTab.handlerRemoverFromIMC.add(handler);
}
@@ -126,7 +127,7 @@ public class IMCHandler {
}
if (!processedCatalystSenders.contains(message.getSender())) {
NEIClientConfig.logger.info("Processing registerCatalystInfo from " + message.getSender());
NEIClientConfig.logger.info("Processing registerCatalystInfo from {}", message.getSender());
processedCatalystSenders.add(message.getSender());
}
final NBTTagCompound tag = message.getNBTValue();
@@ -135,23 +136,14 @@ public class IMCHandler {
NEIClientConfig.logger.warn("Missing handlerID for registerCatalystInfo!");
return;
}
final String itemName = tag.getString("itemName");
final String nbtInfo = tag.hasKey("nbtInfo") ? tag.getString("nbtInfo") : null;
if (itemName.isEmpty()) {
NEIClientConfig.logger.warn(String.format("Missing itemName for registerCatalystInfo in `%s`!", handlerID));
return;
}
final ItemStack itemStack = NEIServerUtils.getModdedItem(itemName, nbtInfo);
final ItemStack itemStack = getItemStackFromIMC(message, "registerCatalystInfo");
if (itemStack == null) {
NEIClientConfig.logger.warn(String.format("Cannot find item `%s`!", itemName));
return;
}
final int priority = tag.getInteger("priority");
RecipeCatalysts
.addOrPut(RecipeCatalysts.catalystsAdderFromIMC, handlerID, new CatalystInfo(itemStack, priority));
NEIClientConfig.logger
.info(String.format("Added catalyst `%s` to handler %s", itemStack.getDisplayName(), handlerID));
NEIClientConfig.logger.info("Added catalyst `{}` to handler {}", itemStack.getDisplayName(), handlerID);
}
private static void handleRemoveCatalystInfo(IMCMessage message) {
@@ -160,33 +152,62 @@ public class IMCHandler {
return;
}
NEIClientConfig.logger.info("Processing removeCatalystInfo from " + message.getSender());
final NBTTagCompound tag = message.getNBTValue();
final String handlerID = tag.getString("handlerID");
if (handlerID.isEmpty()) {
NEIClientConfig.logger.warn("Missing handlerID for registerCatalystInfo!");
NEIClientConfig.logger.warn("Missing handlerID for removeCatalystInfo!");
return;
}
final String itemName = tag.getString("itemName");
final String nbtInfo = tag.hasKey("nbtInfo") ? tag.getString("nbtInfo") : null;
if (itemName.isEmpty()) {
NEIClientConfig.logger.warn(String.format("Missing itemName for registerCatalystInfo in `%s`!", handlerID));
return;
}
final ItemStack itemStack = NEIServerUtils.getModdedItem(itemName, nbtInfo);
final ItemStack itemStack = getItemStackFromIMC(message, "removeCatalystInfo");
if (itemStack == null) {
NEIClientConfig.logger.warn(String.format("Cannot find item `%s`!", itemName));
return;
}
if (RecipeCatalysts.catalystsRemoverFromIMC.containsKey(handlerID)) {
RecipeCatalysts.catalystsRemoverFromIMC.get(handlerID).add(itemStack);
} else {
RecipeCatalysts.catalystsRemoverFromIMC
.put(handlerID, new ArrayList<>(Collections.singletonList(itemStack)));
RecipeCatalysts.catalystsRemoverFromIMC.computeIfAbsent(handlerID, k -> new ArrayList<>()).add(itemStack);
NEIClientConfig.logger.info("Removed catalyst `{}` from handler {}", itemStack.getDisplayName(), handlerID);
}
private static void handleAddItemInfo(IMCMessage message) {
if (!message.isNBTMessage()) {
logInvalidMessage(message, "NBT");
return;
}
NEIClientConfig.logger
.info(String.format("Removed catalyst `%s` from handler %s", itemStack.getDisplayName(), handlerID));
final NBTTagCompound tag = message.getNBTValue();
if (tag.hasKey("pages")) addMultipleInfoPages(message);
if (tag.hasKey("page")) addSingleInfoPage(message);
}
private static void addMultipleInfoPages(IMCMessage message) {
final NBTTagCompound tag = message.getNBTValue();
final String filter = tag.getString("filter");
final NBTTagList pages = tag.getTagList("pages", 8); // 8 = TAG_String
for (int i = 0; i < pages.tagCount(); i++) {
String page = pages.getStringTagAt(i);
InformationHandler.addInformationPage(filter, page);
}
}
private static void addSingleInfoPage(IMCMessage message) {
final NBTTagCompound tag = message.getNBTValue();
String filter = tag.getString("filter");
String page = tag.getString("page");
InformationHandler.addInformationPage(filter, page);
}
private static ItemStack getItemStackFromIMC(IMCMessage message, String logAction) {
final NBTTagCompound tag = message.getNBTValue();
final String itemName = tag.getString("itemName");
final String nbtInfo = tag.hasKey("nbtInfo") ? tag.getString("nbtInfo") : null;
NEIClientConfig.logger.info("Processing {} for item `{}` from {}", logAction, itemName, message.getSender());
final ItemStack itemStack = NEIServerUtils.getModdedItem(itemName, nbtInfo);
if (itemStack == null) {
NEIClientConfig.logger.warn("Cannot find item `{}`!", itemName);
}
return itemStack;
}
private static void logInvalidMessage(FMLInterModComms.IMCMessage message, String type) {
@@ -47,7 +47,7 @@ public class OptionUtilities extends OptionStringSet {
LayoutManager.drawIcon(x + 4, 4, new Image(132, 12, 12, 12));
x += 24;
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
RenderHelper.enableGUIStandardItemLighting();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
ItemStack sword = new ItemStack(Items.diamond_sword);
@@ -207,6 +207,10 @@ public class GuiPresetList extends GuiOptionPane {
modeName = EnumChatFormatting.GOLD + NEIClientUtils.translate("presets.mode.hide.char")
+ EnumChatFormatting.RESET;
break;
case SUBSET:
modeName = EnumChatFormatting.DARK_PURPLE + NEIClientUtils.translate("presets.mode.subset.char")
+ EnumChatFormatting.RESET;
break;
case REMOVE:
modeName = EnumChatFormatting.RED + NEIClientUtils.translate("presets.mode.remove.char")
+ EnumChatFormatting.RESET;
@@ -86,6 +86,7 @@ public class LeftPanel extends GuiWidget {
protected Label modeLabel = new Label(NEIClientUtils.translate("presets.mode"), false);
protected CheckboxButton modeHide;
protected CheckboxButton modeSubset;
protected CheckboxButton modeRemove;
protected CheckboxButton modeGroup;
@@ -114,6 +115,19 @@ public class LeftPanel extends GuiWidget {
}
};
modeSubset = new CheckboxButton(NEIClientUtils.translate("presets.mode.subset")) {
@Override
public boolean isChecked() {
return preset.mode == PresetMode.SUBSET;
}
@Override
protected void onChange() {
preset.mode = this.checked ? PresetMode.SUBSET : null;
}
};
modeRemove = new CheckboxButton(NEIClientUtils.translate("presets.mode.remove")) {
@Override
@@ -164,6 +178,10 @@ public class LeftPanel extends GuiWidget {
modeHide.handleClick(x, y, button);
}
if (modeSubset.contains(x, y)) {
modeSubset.handleClick(x, y, button);
}
if (modeRemove.contains(x, y)) {
modeRemove.handleClick(x, y, button);
}
@@ -248,7 +266,7 @@ public class LeftPanel extends GuiWidget {
@Override
public void update() {
int CHECKBOX_WIDTH = (this.width - 12) / 3;
int CHECKBOX_WIDTH = (this.width - 12) / 4;
nameLabel.x = this.x + 2;
nameLabel.y = this.y + 4;
nameLabel.w = this.width;
@@ -269,12 +287,13 @@ public class LeftPanel extends GuiWidget {
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.w = modeSubset.w = modeRemove.w = modeGroup.w = CHECKBOX_WIDTH;
modeHide.h = modeSubset.h = modeRemove.h = modeGroup.h = INPUT_HEIGHT;
modeHide.y = modeSubset.y = modeRemove.y = modeGroup.y = modeLabel.y + modeLabel.h;
modeHide.x = this.x + 1;
modeRemove.x = modeHide.x + modeHide.w + 6;
modeSubset.x = modeHide.x + modeHide.w + 6;
modeRemove.x = modeSubset.x + modeSubset.w + 6;
modeGroup.x = modeRemove.x + modeRemove.w + 6;
grid.setGridSize(
@@ -292,6 +311,7 @@ public class LeftPanel extends GuiWidget {
modeLabel.draw(mousex, mousey);
modeHide.draw(mousex, mousey);
modeSubset.draw(mousex, mousey);
modeRemove.draw(mousex, mousey);
modeGroup.draw(mousex, mousey);
@@ -326,6 +346,8 @@ public class LeftPanel extends GuiWidget {
} else if (modeHide.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.mode.hide.tip"));
} else if (modeSubset.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.mode.subset.tip"));
} else if (modeRemove.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.mode.remove.tip"));
} else if (modeGroup.contains(mousex, mousey)) {
@@ -4,6 +4,8 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL11;
import codechicken.nei.Image;
public class DrawableResource extends Image {
@@ -43,15 +45,160 @@ public class DrawableResource extends Image {
}
public void draw(int xOffset, int yOffset, int maskTop, int maskBottom, int maskLeft, int maskRight) {
Minecraft.getMinecraft().getTextureManager().bindTexture(this.resourceLocation);
final int x = xOffset + this.paddingLeft + maskLeft;
final int y = yOffset + this.paddingTop + maskTop;
final int textureX = this.x + maskLeft;
final int textureY = this.y + maskTop;
final boolean is2DTexture = GL11.glGetBoolean(GL11.GL_TEXTURE_2D);
final int width = this.width - maskRight - maskLeft;
final int height = this.height - maskBottom - maskTop;
// drawModalRectWithCustomSizedTexture
Gui.func_146110_a(x, y, textureX, textureY, width, height, textureWidth, textureHeight);
GL11.glEnable(GL11.GL_TEXTURE_2D);
Minecraft.getMinecraft().getTextureManager().bindTexture(this.resourceLocation);
drawModalRectWithCustomSizedTexture(xOffset + maskLeft, yOffset + maskTop, maskLeft, maskTop, width, height);
if (!is2DTexture) GL11.glDisable(GL11.GL_TEXTURE_2D);
}
public void draw(int xOffset, int yOffset, int width, int height, int sliceLeft, int sliceRight, int sliceTop,
int sliceBottom) {
final int textureWidth = getWidth();
final int textureHeight = getHeight();
final int middleWidth = textureWidth - sliceLeft - sliceRight;
final int middleHeight = textureHeight - sliceTop - sliceBottom;
final int tileWidth = width - sliceLeft - sliceRight;
final int tileHeight = height - sliceTop - sliceBottom;
if (middleWidth > 0 && middleHeight > 0 && tileWidth > 0 && tileHeight > 0) {
final boolean is2DTexture = GL11.glGetBoolean(GL11.GL_TEXTURE_2D);
final int tileWidthCount = tileWidth / middleWidth;
final int remainderWidth = tileWidth - (tileWidthCount * middleWidth);
final int tileHeightCount = tileHeight / middleHeight;
final int remainderHeight = tileHeight - (tileHeightCount * middleHeight);
GL11.glEnable(GL11.GL_TEXTURE_2D);
Minecraft.getMinecraft().getTextureManager().bindTexture(this.resourceLocation);
// middle parts
for (int tileW = 0; tileW <= tileWidthCount; tileW++) {
final int tileWidthSize = (tileW == tileWidthCount) ? remainderWidth : middleWidth;
final int x = xOffset + sliceLeft + tileW * middleWidth;
for (int tileH = 0; tileH <= tileHeightCount; tileH++) {
final int tileHeightSize = (tileH == tileHeightCount) ? remainderHeight : middleHeight;
drawModalRectWithCustomSizedTexture(
x,
yOffset + sliceTop + tileH * middleHeight,
sliceLeft,
sliceTop,
tileWidthSize,
tileHeightSize);
}
}
// border top
if (sliceTop > 0) {
for (int tileW = 0; tileW <= tileWidthCount; tileW++) {
final int tileWidthSize = (tileW == tileWidthCount) ? remainderWidth : middleWidth;
drawModalRectWithCustomSizedTexture(
xOffset + sliceLeft + tileW * middleWidth,
yOffset,
sliceLeft,
0,
tileWidthSize,
sliceTop);
}
}
// border bottom
if (sliceBottom > 0) {
for (int tileW = 0; tileW <= tileWidthCount; tileW++) {
final int tileWidthSize = (tileW == tileWidthCount) ? remainderWidth : middleWidth;
drawModalRectWithCustomSizedTexture(
xOffset + sliceLeft + tileW * middleWidth,
yOffset + sliceTop + tileHeight,
sliceLeft,
sliceTop + middleHeight,
tileWidthSize,
sliceBottom);
}
}
// border left
if (sliceLeft > 0) {
for (int tileH = 0; tileH <= tileHeightCount; tileH++) {
final int tileHeightSize = (tileH == tileHeightCount) ? remainderHeight : middleHeight;
drawModalRectWithCustomSizedTexture(
xOffset,
yOffset + sliceTop + tileH * middleHeight,
0,
sliceTop,
sliceLeft,
tileHeightSize);
}
}
// border right
if (sliceRight > 0) {
for (int tileH = 0; tileH <= tileHeightCount; tileH++) {
final int tileHeightSize = (tileH == tileHeightCount) ? remainderHeight : middleHeight;
drawModalRectWithCustomSizedTexture(
xOffset + sliceLeft + tileWidth,
yOffset + sliceTop + tileH * middleHeight,
sliceLeft + middleWidth,
sliceTop,
sliceRight,
tileHeightSize);
}
}
// angle left-top
if (sliceLeft > 0 && sliceTop > 0) {
drawModalRectWithCustomSizedTexture(xOffset, yOffset, 0, 0, sliceLeft, sliceTop);
}
// angle right-top
if (sliceRight > 0 && sliceTop > 0) {
drawModalRectWithCustomSizedTexture(
xOffset + sliceLeft + tileWidth,
yOffset,
sliceLeft + middleWidth,
0,
sliceRight,
sliceTop);
}
// angle left-bottom
if (sliceLeft > 0 && sliceBottom > 0) {
drawModalRectWithCustomSizedTexture(
xOffset,
yOffset + sliceTop + tileHeight,
0,
sliceTop + middleHeight,
sliceLeft,
sliceBottom);
}
// angle right-bottom
if (sliceRight > 0 && sliceBottom > 0) {
drawModalRectWithCustomSizedTexture(
xOffset + sliceLeft + tileWidth,
yOffset + sliceTop + tileHeight,
sliceLeft + middleWidth,
sliceTop + middleHeight,
sliceRight,
sliceBottom);
}
if (!is2DTexture) GL11.glDisable(GL11.GL_TEXTURE_2D);
}
}
private void drawModalRectWithCustomSizedTexture(int xOffset, int yOffset, int u, int v, int width, int height) {
Gui.func_146110_a(
xOffset + this.paddingLeft,
yOffset + this.paddingTop,
this.x + u,
this.y + v,
width,
height,
this.textureWidth,
this.textureHeight);
}
}
@@ -1,93 +0,0 @@
package codechicken.nei.drawable;
import net.minecraft.client.gui.GuiScreen;
import org.lwjgl.opengl.GL11;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
/*
* Taken from Mantle 1.12-1.3.3.49 under the MIT License The MIT License (MIT) Copyright (c) 2013-2014 Slime Knights
* (mDiyo, fuj1n, Sunstrike, progwml6, pillbox, alexbegt) Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions: The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
@SideOnly(Side.CLIENT)
public class GuiElementDuex {
// this is totally completely ugly but it's a simple solution that doesn't clutter everything too much >_>
public static int defaultTexW = 256;
public static int defaultTexH = 256;
public final int x;
public final int y;
public final int w;
public final int h;
public int texW;
public int texH;
public GuiElementDuex(int x, int y, int w, int h, int texW, int texH) {
this(x, y, w, h);
setTextureSize(texW, texH);
defaultTexW = texW;
defaultTexH = texH;
}
public GuiElementDuex(int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
setTextureSize(defaultTexW, defaultTexH);
}
public GuiElementDuex setTextureSize(int w, int h) {
texW = w;
texH = h;
return this;
}
public GuiElementDuex shift(int xd, int yd) {
return new GuiElementDuex(this.x + xd, this.y + yd, this.w, this.h, this.texW, this.texH);
}
/**
* Draws the element at the given x/y coordinates
*
* @param xPos X-Coordinate on the screen
* @param yPos Y-Coordinate on the screen
*/
public int draw(int xPos, int yPos) {
// drawModalRectWithCustomSizedTexture
GL11.glColor4f(1, 1, 1, 1);
GuiScreen.func_146110_a(xPos, yPos, x, y, w, h, texW, texH);
return w;
}
public static class Builder {
public int w;
public int h;
public Builder(int w, int h) {
this.w = w;
this.h = h;
}
public GuiElementDuex get(int x, int y, int w, int h) {
return new GuiElementDuex(x, y, w, h, this.w, this.h);
}
}
}
@@ -1,91 +0,0 @@
package codechicken.nei.drawable;
import net.minecraft.client.gui.GuiScreen;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
/*
* Taken from Mantle 1.12-1.3.3.49 under the MIT License The MIT License (MIT) Copyright (c) 2013-2014 Slime Knights
* (mDiyo, fuj1n, Sunstrike, progwml6, pillbox, alexbegt) Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions: The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
@SideOnly(Side.CLIENT)
public class GuiElementScalable extends GuiElementDuex {
public GuiElementScalable(int x, int y, int w, int h, int texW, int texH) {
super(x, y, w, h, texW, texH);
}
public GuiElementScalable(int x, int y, int w, int h) {
super(x, y, w, h);
}
public int drawScaledX(int xPos, int yPos, int width) {
for (int i = 0; i < width / w; i++) {
draw(xPos + i * w, yPos);
}
// remainder that doesn't fit total width
int remainder = width % w;
if (remainder > 0) {
GuiScreen.func_146110_a(xPos + width - remainder, yPos, x, y, remainder, h, texW, texH);
}
return width;
}
public int drawScaledY(int xPos, int yPos, int height) {
for (int i = 0; i < height / h; i++) {
draw(xPos, yPos + i * h);
}
// remainder that doesn't fit total width
int remainder = height % h;
if (remainder > 0) {
// drawModalRectWithCustomSizedTexture
GuiScreen.func_146110_a(xPos, yPos + height - remainder, x, y, w, remainder, texW, texH);
}
return w;
}
public int drawScaled(int xPos, int yPos, int width, int height) {
// we draw full height row-wise
int full = height / this.h;
for (int i = 0; i < full; i++) {
drawScaledX(xPos, yPos + i * this.h, width);
}
yPos += full * this.h;
// and the remainder is drawn manually
int yRest = height % this.h;
// the same as drawScaledX but with the remaining height
for (int i = 0; i < width / w; i++) {
drawScaledY(xPos + i * w, yPos, yRest);
}
// remainder that doesn't fit total width
int remainder = width % w;
if (remainder > 0) {
// drawModalRectWithCustomSizedTexture
GuiScreen.func_146110_a(xPos + width - remainder, yPos, x, y, remainder, yRest, texW, texH);
}
return width;
}
@Override
public GuiElementScalable shift(int xd, int yd) {
GuiElementScalable element = new GuiElementScalable(this.x + xd, this.y + yd, this.w, this.h);
element.setTextureSize(texW, texH);
return element;
}
}
@@ -0,0 +1,40 @@
package codechicken.nei.filter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.api.IRecipeFilter;
import codechicken.nei.recipe.IRecipeHandler;
public class AllMultiRecipeFilter implements IRecipeFilter {
public final List<IRecipeFilter> filters;
public AllMultiRecipeFilter(List<IRecipeFilter> filters) {
this.filters = filters;
}
public AllMultiRecipeFilter(IRecipeFilter filters) {
this(Arrays.asList(filters));
}
public AllMultiRecipeFilter() {
this(new ArrayList<>());
}
@Override
public boolean matches(IRecipeHandler handler, int recipeIndex) {
for (IRecipeFilter filter : filters) {
try {
if (filter != null && !filter.matches(handler, recipeIndex)) return false;
} catch (Exception e) {
NEIClientConfig.logger.error("Exception filtering " + handler + " with " + filter, e);
}
}
return true;
}
}
@@ -0,0 +1,44 @@
package codechicken.nei.filter;
import net.minecraft.item.ItemStack;
import codechicken.nei.PositionedStack;
import codechicken.nei.api.IRecipeFilter;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.recipe.IRecipeHandler;
public class AllOthersRecipeFilter implements IRecipeFilter {
private final ItemFilter filter;
public AllOthersRecipeFilter(ItemFilter filter) {
this.filter = filter;
}
@Override
public boolean matches(IRecipeHandler handler, int recipeIndex) {
for (PositionedStack pStack : handler.getOtherStacks(recipeIndex)) {
if (!match(pStack)) {
return false;
}
}
return true;
}
protected boolean match(PositionedStack pStack) {
if (pStack == null) {
return false;
}
for (ItemStack stack : pStack.items) {
if (filter.matches(stack)) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,40 @@
package codechicken.nei.filter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.api.IRecipeFilter;
import codechicken.nei.recipe.IRecipeHandler;
public class AnyMultiRecipeFilter implements IRecipeFilter {
public final List<IRecipeFilter> filters;
public AnyMultiRecipeFilter(List<IRecipeFilter> filters) {
this.filters = filters;
}
public AnyMultiRecipeFilter(IRecipeFilter filters) {
this(Arrays.asList(filters));
}
public AnyMultiRecipeFilter() {
this(new ArrayList<>());
}
@Override
public boolean matches(IRecipeHandler handler, int recipeIndex) {
for (IRecipeFilter filter : filters) {
try {
if (filter != null && filter.matches(handler, recipeIndex)) return true;
} catch (Exception e) {
NEIClientConfig.logger.error("Exception filtering " + handler + " with " + filter, e);
}
}
return false;
}
}
@@ -0,0 +1,44 @@
package codechicken.nei.filter;
import net.minecraft.item.ItemStack;
import codechicken.nei.PositionedStack;
import codechicken.nei.api.IRecipeFilter;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.recipe.IRecipeHandler;
public class AnyOthersRecipeFilter implements IRecipeFilter {
private final ItemFilter filter;
public AnyOthersRecipeFilter(ItemFilter filter) {
this.filter = filter;
}
@Override
public boolean matches(IRecipeHandler handler, int recipeIndex) {
for (PositionedStack pStack : handler.getOtherStacks(recipeIndex)) {
if (match(pStack)) {
return true;
}
}
return false;
}
protected boolean match(PositionedStack pStack) {
if (pStack == null) {
return false;
}
for (ItemStack stack : pStack.items) {
if (filter.matches(stack)) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,89 @@
package codechicken.nei.filter;
import java.util.List;
import net.minecraft.item.ItemStack;
import codechicken.nei.PositionedStack;
import codechicken.nei.api.IRecipeFilter;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.recipe.IRecipeHandler;
public class RecipeFilter implements IRecipeFilter {
public enum FilterContext {
ANY,
INPUT,
OUTPUT;
public static FilterContext fromChar(char c) {
switch (c) {
case '<':
return INPUT;
case '>':
return OUTPUT;
default:
return ANY;
}
}
}
private final ItemFilter filter;
private final FilterContext context;
private final boolean anyMatch;
public RecipeFilter(FilterContext context, boolean anyMatch, ItemFilter filter) {
this.context = context;
this.anyMatch = anyMatch;
this.filter = filter;
}
@Override
public boolean matches(IRecipeHandler handler, int recipeIndex) {
if ((this.context == FilterContext.ANY || this.context == FilterContext.INPUT)
&& matchPositionedStack(handler.getIngredientStacks(recipeIndex), this.anyMatch)) {
return this.anyMatch;
}
if (this.context == FilterContext.ANY || this.context == FilterContext.OUTPUT) {
final PositionedStack result = handler.getResultStack(recipeIndex);
if (result != null && matchPositionedStack(result) == this.anyMatch) {
return this.anyMatch;
}
if (matchPositionedStack(handler.getOtherStacks(recipeIndex), this.anyMatch)) {
return this.anyMatch;
}
}
return !this.anyMatch;
}
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) {
if (pStack == null) return false;
for (ItemStack stack : pStack.items) {
if (this.filter.matches(stack)) {
return true;
}
}
return false;
}
}
@@ -16,6 +16,7 @@ import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.function.IntFunction;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -49,6 +50,7 @@ import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIModContainer;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.ItemUntranslator;
import codechicken.nei.util.ReadableNumberConverter;
import codechicken.nei.util.RenderTooltipEventHelper;
@@ -60,6 +62,10 @@ public class GuiContainerManager {
public void onResourceManagerReload(IResourceManager p_110549_1_) {
renderingErrorItems.clear();
ItemList.loadItems.restart();
if (NEIClientConfig.enableItemUntranslator()) {
ItemUntranslator.getInstance().load();
}
}
}
@@ -77,6 +83,9 @@ public class GuiContainerManager {
public static final LinkedList<IContainerSlotClickHandler> slotClickHandlers = new HideousLinkedList<>(
new CopyOnWriteArrayList<>());
// Any item rendered with this z offset should render it on top of every other gui element
public static final int TOOLTIP_Z_OFFSET = 400;
static {
addSlotClickHandler(new DefaultSlotClickHandler());
}
@@ -156,7 +165,7 @@ public class GuiContainerManager {
* @return A list of Strings representing the text to be displayed on each line of the tool tip.
*/
public static List<String> itemDisplayNameMultiline(ItemStack stack, GuiContainer gui, boolean includeHandlers) {
List<String> namelist = null;
List<String> namelist;
try {
namelist = stack.getTooltip(
Minecraft.getMinecraft().thePlayer,
@@ -180,7 +189,9 @@ public class GuiContainerManager {
namelist.set(0, stack.getRarity().rarityColor.toString() + namelist.get(0));
for (int i = 1; i < namelist.size(); i++) {
if (!namelist.get(i).startsWith(GuiDraw.TOOLTIP_HANDLER)) {
if (namelist.get(i) == null) {
namelist.set(i, "");
} else if (!namelist.get(i).startsWith(GuiDraw.TOOLTIP_HANDLER)) {
namelist.set(i, EnumChatFormatting.GRAY + namelist.get(i) + EnumChatFormatting.RESET);
}
}
@@ -189,26 +200,27 @@ public class GuiContainerManager {
}
@Nullable
public static String countDetails(int stackSize, int maxStackSize, String fullPattern, String shortPattern) {
public static String countDetails(int stackSize, int maxStackSize, String fullPattern, String shortPattern,
IntFunction<String> valueFormatter) {
if (maxStackSize > 1 && stackSize > maxStackSize) {
final int remainder = stackSize % maxStackSize;
final int units = stackSize / maxStackSize;
if (remainder > 0) {
return String.format(
fullPattern,
NEIClientUtils.formatNumbers(stackSize),
NEIClientUtils.formatNumbers(stackSize / maxStackSize),
NEIClientUtils.formatNumbers(maxStackSize),
NEIClientUtils.formatNumbers(remainder));
valueFormatter.apply(stackSize),
NEIClientUtils.formatNumber(units),
valueFormatter.apply(maxStackSize),
valueFormatter.apply(remainder));
} else {
return String.format(
shortPattern,
NEIClientUtils.formatNumbers(stackSize),
NEIClientUtils.formatNumbers(stackSize / maxStackSize),
NEIClientUtils.formatNumbers(maxStackSize));
valueFormatter.apply(stackSize),
NEIClientUtils.formatNumber(units),
valueFormatter.apply(maxStackSize));
}
}
return null;
}
@@ -222,7 +234,8 @@ public class GuiContainerManager {
stack.stackSize,
stack.getMaxStackSize(),
translate("inventory.tooltip.count.item", "%s = %s * %s + %s"),
translate("inventory.tooltip.count.item", "%s = %s * %s"));
translate("inventory.tooltip.count.item", "%s = %s * %s"),
NEIClientUtils::formatNumber);
}
}
@@ -237,8 +250,9 @@ public class GuiContainerManager {
return countDetails(
amount,
144,
translate("inventory.tooltip.count.fluid", "%s L = %s * %s L + %s L"),
translate("inventory.tooltip.count.fluid", "%s L = %s * %s L"));
translate("inventory.tooltip.count.fluid", "%s = %s * %s + %s"),
translate("inventory.tooltip.count.fluid", "%s = %s * %s"),
NEIClientUtils::formatFluid);
}
/**
@@ -397,7 +411,7 @@ public class GuiContainerManager {
public static void enableMatrixStackLogging() {
if (!contextEnabled) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
modelviewDepth = GL11.glGetInteger(GL11.GL_MODELVIEW_STACK_DEPTH);
contextEnabled = true;
}
@@ -588,9 +602,7 @@ public class GuiContainerManager {
}
}
if (!tooltip.isEmpty()) tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE); // add space after 'title'
if (showTooltip) {
if (showTooltip && NEIClientConfig.getBooleanSetting("inventory.showHotkeys")) {
List<String> hotkeystips = collectHotkeyTips(mousex, mousey);
if (!hotkeystips.isEmpty()) {
@@ -603,6 +615,19 @@ public class GuiContainerManager {
}
}
if (showTooltip && stack != null && !tooltip.isEmpty()) {
final String secondDisplayName = ItemUntranslator.getInstance().getItemStackDisplayName(stack);
if (!secondDisplayName.isEmpty()) {
tooltip.add(1, EnumChatFormatting.DARK_GRAY + secondDisplayName + GuiDraw.TOOLTIP_LINESPACE);
} else {
tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE);
}
} else if (!tooltip.isEmpty()) {
tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE);
}
if (NEIModContainer.isGTNHLibLoaded() && !tooltip.isEmpty()) {
if (RenderTooltipEventHelper.post(stack, this.window, mousex, mousey, font)) {
return;
@@ -630,9 +655,6 @@ public class GuiContainerManager {
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) {
@@ -646,12 +668,12 @@ public class GuiContainerManager {
}
}
hotkeys.remove(null);
hotkeys.remove("");
if (!hotkeys.isEmpty()) {
List<String> hotkeystips = new ArrayList<>();
Map<String, List<String>> messages = new HashMap<>();
hotkeys.remove(null);
hotkeys.remove("");
for (Map.Entry<String, String> entry : hotkeys.entrySet()) {
messages.computeIfAbsent(entry.getValue(), m -> new ArrayList<>()).add(entry.getKey());
@@ -686,13 +708,19 @@ public class GuiContainerManager {
}
} else if (NEIClientConfig.getBooleanSetting("inventory.hotkeysHelpText")) {
Map<String, String> hotkeys = new HashMap<>();
boolean existsHotkeys = false;
synchronized (instanceTooltipHandlers) {
for (IContainerTooltipHandler handler : instanceTooltipHandlers) {
if (!handler.handleHotkeys(window, mousex, mousey, new HashMap<>()).isEmpty()) {
existsHotkeys = true;
break;
if (!(hotkeys = handler.handleHotkeys(window, mousex, mousey, hotkeys)).isEmpty()) {
hotkeys.remove("");
hotkeys.remove(null);
if (!hotkeys.isEmpty()) {
existsHotkeys = true;
break;
}
}
}
}
@@ -19,12 +19,12 @@ import java.util.stream.Stream;
*
* @param <E>
*/
final class HideousLinkedList<E> extends LinkedList<E> {
public final class HideousLinkedList<E> extends LinkedList<E> {
private static final long serialVersionUID = -8504433551965776915L;
private final List<E> backing;
HideousLinkedList(List<E> backing) {
public HideousLinkedList(List<E> backing) {
this.backing = backing;
}
@@ -1,7 +1,5 @@
package codechicken.nei.guihook;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.inventory.Slot;
@@ -9,14 +7,14 @@ public interface IContainerDrawHandler {
/**
* Initialize your objects and the gui for drawing.
*
*
* @param gui An instance of the currentscreen
*/
public void onPreDraw(GuiContainer gui);
/**
* Draw your objects. Called after all normal gui rendering has been performed.
*
*
* @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
@@ -25,27 +23,16 @@ public interface IContainerDrawHandler {
/**
* Use this to draw things that should always be on top, for example objects being held by the mouse.
*
*
* @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
*/
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.
*
*
* @param gui An instance of the currentscreen
* @param slot The slot being rendered.
*/
@@ -53,7 +40,7 @@ public interface IContainerDrawHandler {
/**
* Render something over a slot after the item in the slot.
*
*
* @param gui An instance of the currentscreen
* @param slot The slot being rendered.
*/
@@ -11,7 +11,7 @@ import codechicken.nei.NEIClientUtils;
public class AcceptsFollowingTooltipLineHandler extends ItemsTooltipLineHandler {
protected static final int DEFAULT_MAX_ROWS = 5;
protected static final int DEFAULT_MAX_ROWS = 4;
public Object tooltipGUID;
@@ -31,7 +31,7 @@ public class AcceptsFollowingTooltipLineHandler extends ItemsTooltipLineHandler
ItemStack activeStack, int maxRows) {
if (items.size() > 1) {
items.sort(Comparator.comparing(FavoriteRecipes::contains).reversed());
items.sort(Comparator.comparing(FavoriteRecipes::containsManual).reversed());
return new AcceptsFollowingTooltipLineHandler(tooltipGUID, items, activeStack, maxRows);
}
@@ -42,7 +42,7 @@ public class AcceptsFollowingTooltipLineHandler extends ItemsTooltipLineHandler
protected void drawItem(int x, int y, ItemStack drawStack, String stackSize) {
super.drawItem(x, y, drawStack, stackSize);
if (FavoriteRecipes.contains(drawStack)) {
if (FavoriteRecipes.containsManual(drawStack)) {
NEIClientUtils.drawNEIOverlayText("F", x, y);
}
}
@@ -1,16 +1,14 @@
package codechicken.nei.recipe;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.inventory.Slot;
import net.minecraft.inventory.SlotCrafting;
import codechicken.nei.ItemPanels;
import codechicken.nei.ItemStackAmount;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.RestartableTask;
@@ -25,25 +23,20 @@ public class AutoCraftingManager {
private static final RestartableTask task = new RestartableTask("NEI Bookmark AutoCraft Processing") {
private static final ItemStack ROOT_ITEM = new ItemStack(Blocks.fire);
private static final RecipeId ROOT_RECIPE_ID = RecipeId
.of(ROOT_ITEM, "recipe-autocrafting", Collections.emptyList());
@Override
public void execute() {
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
final InventoryPlayer playerInventory = guiContainer.mc.thePlayer.inventory;
final ItemStackAmount inventory = ItemStackAmount.of(Arrays.asList(playerInventory.mainInventory));
final RecipeChainMath math = createMasterRoot(AutoCraftingManager.math);
final List<BookmarkItem> initialItems = prepareInitialItems(math, inventory);
final List<BookmarkItem> initialItems = prepareInitialItems(math, getInventoryItems(guiContainer));
boolean processed = false;
boolean changed = false;
StackInfo.pauseItemDamageSound(true);
do {
changed = false;
RecipeChainIterator iterator = new RecipeChainIterator(math, initialItems);
iterator.updateInventory(playerInventory.mainInventory);
iterator.updateInventory(getInventoryItems(guiContainer));
while (iterator.hasNext() && !interrupted(guiContainer)) {
final Map<RecipeId, Long> recipes = iterator.next();
@@ -69,12 +62,14 @@ public class AutoCraftingManager {
if (craft) {
changed = true;
processed = true;
iterator.updateInventory(playerInventory.mainInventory);
iterator.updateInventory(getInventoryItems(guiContainer));
}
}
} while (changed && !interrupted(guiContainer));
StackInfo.pauseItemDamageSound(false);
if (processed && !changed && !interrupted(guiContainer)) {
NEIClientUtils.playClickSound();
}
@@ -91,31 +86,6 @@ public class AutoCraftingManager {
return interrupted() || guiContainer != NEIClientUtils.getGuiContainer();
}
private RecipeChainMath createMasterRoot(RecipeChainMath math) {
final List<BookmarkItem> rootIngredients = new ArrayList<>();
for (BookmarkItem item : math.recipeResults) {
if (math.outputRecipes.containsKey(item.recipeId)) {
long amount = item.factor * math.outputRecipes.get(item.recipeId);
rootIngredients.add(
BookmarkItem.of(
-1,
item.getItemStack(amount),
item.getStackSize(amount),
ROOT_RECIPE_ID,
true,
BookmarkItem.generatePermutations(item.itemStack, null)));
}
}
math.outputRecipes.clear();
math.outputRecipes.put(ROOT_RECIPE_ID, 1L);
math.recipeResults.add(BookmarkItem.of(-1, ROOT_ITEM, 1, ROOT_RECIPE_ID, false));
math.recipeIngredients.addAll(rootIngredients);
return math;
}
private List<BookmarkItem> prepareInitialItems(RecipeChainMath math, ItemStackAmount inventory) {
final List<BookmarkItem> initialItems = new ArrayList<>();
@@ -139,6 +109,8 @@ public class AutoCraftingManager {
AutoCraftingManager.math = math;
if (AutoCraftingManager.math != null) {
ItemPanels.bookmarkPanel.clearTooltips();
math.createMasterRoot();
task.restart();
}
}
@@ -147,4 +119,16 @@ public class AutoCraftingManager {
return AutoCraftingManager.math != null && !task.interrupted();
}
public static ItemStackAmount getInventoryItems(GuiContainer guiContainer) {
final ItemStackAmount inventory = new ItemStackAmount();
for (Slot slot : guiContainer.inventorySlots.inventorySlots) {
if (slot.getHasStack() && !(slot instanceof SlotCrafting) && slot.canTakeStack(guiContainer.mc.thePlayer)) {
inventory.add(slot.getStack());
}
}
return inventory;
}
}
@@ -11,6 +11,7 @@ import java.util.stream.Collectors;
import net.minecraft.client.gui.inventory.GuiBrewingStand;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemPotion;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.Potion;
@@ -36,6 +37,13 @@ public class BrewingRecipeHandler extends TemplateRecipeHandler {
ingredient = new PositionedStack(ingred, 74, 6);
result = new PositionedStack(new ItemStack(potionitem, 1, resultDamage), 97, 35);
}
// Arbitrary precursor/result stacks (for Lingering)
public BrewingRecipe(ItemStack ingred, ItemStack precursor, ItemStack resultStack) {
precursorPotion = new PositionedStack(precursor, 51, 35);
ingredient = new PositionedStack(ingred, 74, 6);
result = new PositionedStack(resultStack, 97, 35);
}
}
public class CachedBrewingRecipe extends CachedRecipe {
@@ -63,6 +71,9 @@ public class BrewingRecipeHandler extends TemplateRecipeHandler {
public static final ItemStackSet ingredients = new ItemStackSet();
public static final HashSet<BrewingRecipe> apotions = new HashSet<>();
private static ItemStack DRAGONS_BREATH = null;
private static Item LINGERING_POTION_ITEM = null;
@Override
public void loadTransferRects() {
transferRects.add(new RecipeTransferRect(new Rectangle(58, 3, 14, 30), "brewing"));
@@ -90,23 +101,38 @@ public class BrewingRecipeHandler extends TemplateRecipeHandler {
@Override
public void loadCraftingRecipes(ItemStack result) {
if (result.getItem() != potionitem) return;
if (result == null) return;
// Allow lingering potion items as output
Item out = result.getItem();
boolean isPotion = out == potionitem;
boolean isLingering = (LINGERING_POTION_ITEM != null && out == LINGERING_POTION_ITEM);
if (!isPotion && !isLingering) return;
int damage = result.getItemDamage();
// Note: Not safe as written for parallelStream
apotions.stream().filter(recipe -> recipe.result.item.getItemDamage() == damage).map(CachedBrewingRecipe::new)
.collect(Collectors.toCollection(() -> arecipes));
apotions.stream()
.filter(recipe -> recipe.result.item.getItem() == out && recipe.result.item.getItemDamage() == damage)
.map(CachedBrewingRecipe::new).collect(Collectors.toCollection(() -> arecipes));
}
@Override
public void loadUsageRecipes(ItemStack ingredient) {
if (ingredient.getItem() != potionitem && !ingredients.contains(ingredient)) return;
if (ingredient == null) return;
// allow lingering potions to pass the guard & keeps og potion behavior
boolean passIt = ingredient.getItem() == potionitem
|| (LINGERING_POTION_ITEM != null && ingredient.getItem() == LINGERING_POTION_ITEM)
|| ingredients.contains(ingredient);
if (!passIt) return;
// Note: Not safe as written for parallelStream
apotions.stream()
.filter(
recipe -> NEIServerUtils.areStacksSameType(recipe.ingredient.item, ingredient)
|| NEIServerUtils.areStacksSameType(recipe.precursorPotion.item, ingredient))
|| NEIServerUtils.areStacksSameType(recipe.precursorPotion.item, ingredient)
|| NEIServerUtils.areStacksSameType(recipe.result.item, ingredient))
.map(CachedBrewingRecipe::new).collect(Collectors.toCollection(() -> arecipes));
}
@@ -141,7 +167,7 @@ public class BrewingRecipeHandler extends TemplateRecipeHandler {
List<?> baseMods = potionitem.getEffects(basePotion);
List<?> newMods = potionitem.getEffects(result); // compare ID's
if (basePotion > 0 && baseMods == newMods || // same modifers and not water->empty
if (basePotion > 0 && baseMods == newMods || // same modifiers and not water->empty
baseMods != null && (baseMods.equals(newMods) || newMods == null) || // modifiers different
// and doesn't lose
// modifiers
@@ -183,6 +209,42 @@ public class BrewingRecipeHandler extends TemplateRecipeHandler {
API.addSubset("Items.Potions.Positive", positivepots);
API.addSubset("Items.Potions.Negative", negativepots);
API.addSubset("Items.Potions.Neutral", neutralpots);
// EFR Potion Recipe Visibility - Will safely skip if EFR isn't loaded
tryResolveEFRItems();
if (DRAGONS_BREATH != null && LINGERING_POTION_ITEM != null) {
ingredients.add(DRAGONS_BREATH.copy());
// Iterate over snapshot to avoid concurrent modification when adding to apotions
ArrayList<BrewingRecipe> snapshot = new ArrayList<>(apotions);
for (BrewingRecipe bgr : snapshot) {
if (bgr == null || bgr.result == null || bgr.result.item == null) continue;
ItemStack splashOut = bgr.result.item;
if (splashOut.getItem() != potionitem) continue;
int meta = splashOut.getItemDamage();
if (!ItemPotion.isSplash(meta)) continue;
// Clear the splash bit (0x4000) and keep meta otherwise
int lingeringMeta = (meta & ~0x4000);
ItemStack precursorSplash = splashOut.copy();
ItemStack lingeringOut = new ItemStack(LINGERING_POTION_ITEM, 1, lingeringMeta);
apotions.add(new BrewingRecipe(DRAGONS_BREATH, precursorSplash, lingeringOut));
}
// Lingering items
final List<ItemStack> allLingering = apotions.stream()
.map(lpr -> lpr.result != null ? lpr.result.item : null)
.filter(lps -> lps != null && lps.getItem() == LINGERING_POTION_ITEM).collect(Collectors.toList());
if (!allLingering.isEmpty()) {
API.setItemListEntries(LINGERING_POTION_ITEM, allLingering);
API.addSubset("Items.Potions.Lingering", stack -> stack.getItem() == LINGERING_POTION_ITEM);
}
}
}
private static boolean levelModifierChanged(int basePotionID, int result) {
@@ -199,6 +261,16 @@ public class BrewingRecipeHandler extends TemplateRecipeHandler {
newPotions.add(result);
}
private static void tryResolveEFRItems() {
if (DRAGONS_BREATH == null) {
Item breath = (Item) Item.itemRegistry.getObject("etfuturum:dragon_breath");
DRAGONS_BREATH = (breath != null) ? new ItemStack(breath) : null;
}
if (LINGERING_POTION_ITEM == null) {
LINGERING_POTION_ITEM = (Item) Item.itemRegistry.getObject("etfuturum:lingering_potion");
}
}
@Override
public String getOverlayIdentifier() {
return "brewing";
Loaded 100 of 184 files, more files were not shown because too many files have changed in this diff. Show more