mirror of
https://github.com/GTNewHorizons/NotEnoughItems.git
synced 2026-11-15 17:54:50 +00:00
Compare commits
207
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a6a6771d8 | ||
|
|
c96199a727 | ||
|
|
ab4ea2cfa1 | ||
|
|
b679883d02 | ||
|
|
0048ef80d0 | ||
|
|
84576aa7a2 | ||
|
|
c5cd5b9e61 | ||
|
|
b1bedcf403 | ||
|
|
bba0a11466 | ||
|
|
b80948f2f2 | ||
|
|
28539bbacc | ||
|
|
ec28bdf116 | ||
|
|
e5d55a9bd8 | ||
|
|
c1f7489de1 | ||
|
|
fa6fd01a3a | ||
|
|
453ba6667f | ||
|
|
4e11a45852 | ||
|
|
95274339a0 | ||
|
|
31fcd6af51 | ||
|
|
860bc059ca | ||
|
|
2fc2152809 | ||
|
|
57e865fc6f | ||
|
|
6dcd26a978 | ||
|
|
aeb59081d9 | ||
|
|
ef8706ae38 | ||
|
|
b49d066231 | ||
|
|
594fbe6f79 | ||
|
|
3edb85b317 | ||
|
|
5fd0a74363 | ||
|
|
2ae94e94a0 | ||
|
|
fa3adde3e6 | ||
|
|
56941cc45d | ||
|
|
cd7d014704 | ||
|
|
0634466851 | ||
|
|
b87e389132 | ||
|
|
c788a07cf5 | ||
|
|
7d4ed91e86 | ||
|
|
ca79cdd3c9 | ||
|
|
3a0722adc2 | ||
|
|
77fa3bafd6 | ||
|
|
e23e542aac | ||
|
|
7ec2ad132e | ||
|
|
7b43826d05 | ||
|
|
c7a18dd288 | ||
|
|
4fb1d7b1d8 | ||
|
|
081071562f | ||
|
|
81e05dc030 | ||
|
|
efc54fb662 | ||
|
|
6e75124ea2 | ||
|
|
2c9f17983a | ||
|
|
e0b6d62143 | ||
|
|
3d5e9aecf0 | ||
|
|
07cec30f3e | ||
|
|
f3add01e74 | ||
|
|
d469fdc90d | ||
|
|
763d9b8cd4 | ||
|
|
55ccb70c8b | ||
|
|
2e1c7764b7 | ||
|
|
9daa9cabb2 | ||
|
|
74dc7c34d9 | ||
|
|
e5f85e32ec | ||
|
|
5383e0891a | ||
|
|
6142d4cc6d | ||
|
|
6aa6b2e6d2 | ||
|
|
29ade6f327 | ||
|
|
5ad6095c43 | ||
|
|
8ae3304861 | ||
|
|
0dc7bc1228 | ||
|
|
19d8b42993 | ||
|
|
3b7eae67af | ||
|
|
64a747e4bd | ||
|
|
4f60928b61 | ||
|
|
8dba2ff4c1 | ||
|
|
eb40e3b112 | ||
|
|
98c8981f05 | ||
|
|
1ed35c8357 | ||
|
|
6249bab886 | ||
|
|
b525760dd3 | ||
|
|
83b4855f5e | ||
|
|
75352caf11 | ||
|
|
475f5811f6 | ||
|
|
7503e1dfcb | ||
|
|
9d1f475941 | ||
|
|
ac50d1b27e | ||
|
|
48934d621f | ||
|
|
0bbb889f39 | ||
|
|
af55a6b191 | ||
|
|
b3e1f23683 | ||
|
|
39578a4419 | ||
|
|
e3574800c0 | ||
|
|
5cd7556e6a | ||
|
|
80c2cba778 | ||
|
|
31173a1fbd | ||
|
|
fd08a93554 | ||
|
|
4dace1f6e5 | ||
|
|
0c0cf37eb0 | ||
|
|
3ec4f8dd68 | ||
|
|
e0dd6847cb | ||
|
|
6374c162ba | ||
|
|
8dd36f1c4a | ||
|
|
4613ade468 | ||
|
|
ca7030df72 | ||
|
|
b32f25c2ce | ||
|
|
4be7a30578 | ||
|
|
7ac3e32635 | ||
|
|
088d37a11a | ||
|
|
6a787dd5b7 | ||
|
|
c305649b95 | ||
|
|
b5d2815eab | ||
|
|
6049d0e9c3 | ||
|
|
9288fc4575 | ||
|
|
ec749ecc8e | ||
|
|
7471a82bca | ||
|
|
3f3c1791cb | ||
|
|
a0e16835c2 | ||
|
|
e9ce5cf72b | ||
|
|
fac011b67e | ||
|
|
f9c8ac504e | ||
|
|
f97711a33a | ||
|
|
b2934c4910 | ||
|
|
759ea69c9f | ||
|
|
36a2cafdac | ||
|
|
6100012f5b | ||
|
|
2e5781beb5 | ||
|
|
43918f3bb1 | ||
|
|
a41299dfca | ||
|
|
ee060b9253 | ||
|
|
82a2273995 | ||
|
|
06fadcc362 | ||
|
|
b328fd3db1 | ||
|
|
9563ebfe5a | ||
|
|
d9143c584e | ||
|
|
65652e5896 | ||
|
|
bd5e991a84 | ||
|
|
165afa2910 | ||
|
|
2507634196 | ||
|
|
e0171adc65 | ||
|
|
72ad8aa2e7 | ||
|
|
f0a554bcc1 | ||
|
|
65781a1649 | ||
|
|
6ad8f05323 | ||
|
|
d61a545d9d | ||
|
|
1774685af6 | ||
|
|
a63a227c3c | ||
|
|
0f115d5439 | ||
|
|
0fad93fb3b | ||
|
|
b1a34c761b | ||
|
|
cc9715d9f2 | ||
|
|
be253a00d2 | ||
|
|
5dde3b2e2f | ||
|
|
8da541460f | ||
|
|
dc4426d9c9 | ||
|
|
d05a9eafb3 | ||
|
|
5056fe5437 | ||
|
|
9fd9aad357 | ||
|
|
acaead41ee | ||
|
|
951f1b0d0d | ||
|
|
daab313288 | ||
|
|
25eaa492f7 | ||
|
|
1b34b24495 | ||
|
|
b9cd48f8f9 | ||
|
|
b2afc8c9e0 | ||
|
|
dc400ea560 | ||
|
|
ea03cfa17d | ||
|
|
94676e0934 | ||
|
|
f7ba34c0af | ||
|
|
db1fd255bb | ||
|
|
94ca7f3134 | ||
|
|
dea024173f | ||
|
|
af320a6c9f | ||
|
|
dcb10bb79d | ||
|
|
d3b6603d06 | ||
|
|
adf2065305 | ||
|
|
e30f6a41ad | ||
|
|
b1a45d0305 | ||
|
|
566d1b095d | ||
|
|
f35a92a101 | ||
|
|
fdf130f741 | ||
|
|
064f31f8db | ||
|
|
9b081ed2a7 | ||
|
|
2fc2ecf082 | ||
|
|
bc7efcfce5 | ||
|
|
0c5af2b892 | ||
|
|
0c61e559ec | ||
|
|
b94bd11e64 | ||
|
|
151a9957de | ||
|
|
b011024164 | ||
|
|
74d98a86f3 | ||
|
|
bd5946f5bf | ||
|
|
1647e8765f | ||
|
|
744b2ffc64 | ||
|
|
e88348aabf | ||
|
|
4766d90db0 | ||
|
|
1dc02a3730 | ||
|
|
a6a5e19e80 | ||
|
|
e9ab2eba9e | ||
|
|
0e3ff1ee06 | ||
|
|
95e9ac3c89 | ||
|
|
1ed004e619 | ||
|
|
153da523d6 | ||
|
|
c732361bbc | ||
|
|
bdb206b45d | ||
|
|
aa44a97f80 | ||
|
|
00c4411ec5 | ||
|
|
4f23d21d37 | ||
|
|
8569431e1d | ||
|
|
5b9c27e253 |
No files matched your search
@@ -0,0 +1,62 @@
|
||||
name: Report Bug
|
||||
description: "Report a bug."
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "A bug/crash report with sufficient information and logs to reproduce and track down."
|
||||
- type: input
|
||||
id: discord
|
||||
attributes:
|
||||
label: Your GTNH Discord Username
|
||||
description: Leave empty if you don't have one, but this will make it harder to contact you if we need additional info.
|
||||
placeholder: "Example: Fake#1234"
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Mod Version
|
||||
description: "What version of the Mod are you using?"
|
||||
placeholder: "Example: 1.0.0"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: report
|
||||
attributes:
|
||||
label: Bug Report
|
||||
description: "Relevant information, as well as relevant logs attached such as `logs/fml-client-latest.log."
|
||||
placeholder: "Example: https://mclo.gs/ OR submit the file to github by dragging it to this textbox."
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: java
|
||||
attributes:
|
||||
label: Java Version
|
||||
description: What Java version are you using? It's worth mentioning that if you play on Java9+ you should try update to latest minor release (e.g. prefer Java 17.0.6 over 17.0.2) of that version.
|
||||
options:
|
||||
- Java 8
|
||||
- Java 9
|
||||
- Java 11
|
||||
- Java 17
|
||||
- Java 19
|
||||
- Java 20
|
||||
- Java 21
|
||||
- Other (Please Specify)
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: modlist
|
||||
attributes:
|
||||
label: Mod List or GTNH Pack Version
|
||||
description: "List of mods, ideally a minimal reproducible set (can be retrieved from latest.log). If using GTNH please indicate pack version and any changed mods, not the entire modlist."
|
||||
placeholder: "List of mods or GTNH Pack version goes here"
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: final
|
||||
attributes:
|
||||
label: Final Checklist
|
||||
description: Certify that you read things
|
||||
options:
|
||||
- label: "I have searched the issues and haven't found a similar issue."
|
||||
required: true
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
name: Feature Request
|
||||
description: "Request a feature."
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Please use this form to request features. We ask you check if it was already requested though"
|
||||
- type: input
|
||||
id: discord
|
||||
attributes:
|
||||
label: Your GTNH Discord Username
|
||||
description: Leave empty if you don't have one, but this will make it harder to contact you if we need additional info.
|
||||
placeholder: "Example: Wumpus#1234"
|
||||
- type: textarea
|
||||
id: request
|
||||
attributes:
|
||||
label: Feature Request
|
||||
description: "Relevant information, as well as relevant images"
|
||||
placeholder: "Example: https://mclo.gs/ OR submit the file to github by dragging it to this textbox."
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: final
|
||||
attributes:
|
||||
label: Final Checklist
|
||||
description: Certify that you read things
|
||||
options:
|
||||
- label: "I have searched the issues and haven't found a similar issue."
|
||||
required: true
|
||||
+10
-2
@@ -1,6 +1,7 @@
|
||||
.gradle
|
||||
.settings
|
||||
/.idea/
|
||||
/.vscode/
|
||||
/run/
|
||||
/build/
|
||||
/eclipse/
|
||||
@@ -25,6 +26,13 @@ whitelist.json
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
src/main/resources/mixins.*.json
|
||||
src/main/resources/mixins.*([!.]).json
|
||||
*.bat
|
||||
.DS_Store
|
||||
*.DS_Store
|
||||
!gradlew.bat
|
||||
.factorypath
|
||||
addon.local.gradle
|
||||
addon.local.gradle.kts
|
||||
addon.late.local.gradle
|
||||
addon.late.local.gradle.kts
|
||||
layout.json
|
||||
@@ -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
|
||||
@@ -29,7 +82,7 @@ If you have issues with NEI outside of the GTNH modpack you may report them in t
|
||||
|
||||
## License
|
||||
|
||||
GTNH Modifications Copyright (c) 2019-2022 mitchej123 and the GTNH Team
|
||||
GTNH Modifications Copyright (c) 2019-2024 mitchej123 and the GTNH Team
|
||||
|
||||
Licensed under LGPL-3.0 or later - use this however you want, but please give back any modifications
|
||||
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
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
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java.srcDirs += ["build/generated/sources/search/antlr/"]
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events "passed", "skipped", "failed"
|
||||
}
|
||||
}
|
||||
+3
-1509
File diff suppressed because it is too large.
Load diff
+15
-2
@@ -1,7 +1,20 @@
|
||||
// Add your dependencies here
|
||||
|
||||
dependencies {
|
||||
api('com.github.GTNewHorizons:CodeChickenLib:1.1.8:dev')
|
||||
api('com.github.GTNewHorizons:CodeChickenCore:1.1.11:dev')
|
||||
api('com.github.GTNewHorizons:CodeChickenCore:1.4.7:dev')
|
||||
implementation('com.github.GTNewHorizons:GTNHLib:0.6.39:dev')
|
||||
|
||||
shadowImplementation('org.apache.commons:commons-csv:1.10.0')
|
||||
|
||||
compileOnly('maven.modrinth:forge-essentials:7.5.1')
|
||||
|
||||
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");
|
||||
}
|
||||
+145
-40
@@ -1,90 +1,148 @@
|
||||
# ExampleMod tag to use as Blowdryer (Spotless, etc.) settings version, leave empty to disable.
|
||||
# LOCAL to test local config updates.
|
||||
gtnh.settings.blowdryerTag = 0.2.0
|
||||
|
||||
# Human-readable mod name, available for mcmod.info population.
|
||||
modName = NotEnoughItems
|
||||
|
||||
# This is a case-sensitive string to identify your mod. Convention is to use lower case.
|
||||
# Case-sensitive identifier string, available for mcmod.info population and used for automatic mixin JSON generation.
|
||||
# Conventionally lowercase.
|
||||
modId = NotEnoughItems
|
||||
|
||||
# Root package of the mod, used to find various classes in other properties,
|
||||
# mcmod.info substitution, enabling assertions in run tasks, etc.
|
||||
modGroup = codechicken.nei
|
||||
|
||||
# WHY is there no version field?
|
||||
# The build script relies on git to provide a version via tags. It is super easy and will enable you to always know the
|
||||
# code base or your binary. Check out this tutorial: https://blog.mattclemente.com/2017/10/13/versioning-with-git-tags/
|
||||
# Whether to use modGroup as the maven publishing group.
|
||||
# When false, com.github.GTNewHorizons is used.
|
||||
useModGroupForPublishing = false
|
||||
|
||||
# Will update your build.gradle automatically whenever an update is available
|
||||
# Updates your build.gradle and settings.gradle automatically whenever an update is available.
|
||||
autoUpdateBuildScript = false
|
||||
|
||||
# Version of Minecraft to target
|
||||
minecraftVersion = 1.7.10
|
||||
|
||||
# Version of Minecraft Forge to target
|
||||
forgeVersion = 10.13.4.1614
|
||||
|
||||
# Select a username for testing your mod with breakpoints. You may leave this empty for a random username each time you
|
||||
# restart Minecraft in development. Choose this dependent on your mod:
|
||||
# Do you need consistent player progressing (for example Thaumcraft)? -> Select a name
|
||||
# Do you need to test how your custom blocks interacts with a player that is not the owner? -> leave name empty
|
||||
# Specify an MCP channel for dependency deobfuscation and the deobfParams task.
|
||||
channel = stable
|
||||
|
||||
# Specify an MCP mappings version for dependency deobfuscation and the deobfParams task.
|
||||
mappingsVersion = 12
|
||||
|
||||
# Defines other MCP mappings for dependency deobfuscation.
|
||||
remoteMappings = https\://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/
|
||||
|
||||
# Select a default username for testing your mod. You can always override this per-run by running
|
||||
# `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE.
|
||||
developmentEnvironmentUserName = Developer
|
||||
|
||||
# Define a source file of your project with:
|
||||
# public static final String VERSION = "GRADLETOKEN_VERSION";
|
||||
# The string's content will be replaced with your mod's version when compiled. You should use this to specify your mod's
|
||||
# version in @Mod([...], version = VERSION, [...])
|
||||
# Leave these properties empty to skip individual token replacements
|
||||
# Generate a class with String fields for the mod id, name, version and group name named with the fields below
|
||||
# Enables using modern Java syntax (up to version 17) via Jabel, while still targeting JVM 8.
|
||||
# See https://github.com/bsideup/jabel for details on how this works.
|
||||
enableModernJavaSyntax = true
|
||||
|
||||
# Enables injecting missing generics into the decompiled source code for a better coding experience.
|
||||
# Turns most publicly visible List, Map, etc. into proper List<E>, Map<K, V> types.
|
||||
enableGenericInjection = true
|
||||
|
||||
# Generate a class with a String field for the mod version named as defined below.
|
||||
# If generateGradleTokenClass is empty or not missing, no such class will be generated.
|
||||
# If gradleTokenVersion is empty or missing, the field will not be present in the class.
|
||||
generateGradleTokenClass = codechicken.nei.Tags
|
||||
gradleTokenModId = MODID
|
||||
gradleTokenModName = MODNAME
|
||||
|
||||
# Name of the token containing the project's current version to generate/replace.
|
||||
gradleTokenVersion = VERSION
|
||||
gradleTokenGroupName = GROUPNAME
|
||||
|
||||
# [DEPRECATED] Mod ID replacement token.
|
||||
gradleTokenModId =
|
||||
|
||||
# [DEPRECATED] Mod name replacement token.
|
||||
gradleTokenModName =
|
||||
|
||||
# [DEPRECATED] Mod Group replacement token.
|
||||
gradleTokenGroupName =
|
||||
|
||||
# [DEPRECATED]
|
||||
# Multiple source files can be defined here by providing a comma-seperated list: Class1.java,Class2.java,Class3.java
|
||||
# Multiple source files can be defined here by providing a comma-separated list: Class1.java,Class2.java,Class3.java
|
||||
# public static final String VERSION = "GRADLETOKEN_VERSION";
|
||||
# The string's content will be replaced with your mod's version when compiled. You should use this to specify your mod's
|
||||
# version in @Mod([...], version = VERSION, [...])
|
||||
# Leave these properties empty to skip individual token replacements
|
||||
# version in @Mod([...], version = VERSION, [...]).
|
||||
# Leave these properties empty to skip individual token replacements.
|
||||
replaceGradleTokenInFile =
|
||||
|
||||
# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can
|
||||
# leave this property empty.
|
||||
# Example value: apiPackage = api + modGroup = com.myname.mymodid -> com.myname.mymodid.api
|
||||
# Example value: (apiPackage = api) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.api
|
||||
apiPackage =
|
||||
|
||||
# Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/META-INF/
|
||||
# Example value: mymodid_at.cfg
|
||||
# There can be multiple files in a space-separated list.
|
||||
# Example value: mymodid_at.cfg nei_at.cfg
|
||||
accessTransformersFile = nei_at.cfg
|
||||
|
||||
# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled!
|
||||
usesMixins = false
|
||||
# Specify the location of your implementation of IMixinPlugin. Leave it empty otherwise.
|
||||
|
||||
# Set to a non-empty string to configure mixins in a separate source set under src/VALUE, instead of src/main.
|
||||
# This can speed up compile times thanks to not running the mixin annotation processor on all input sources.
|
||||
# Mixin classes will have access to "main" classes, but not the other way around.
|
||||
separateMixinSourceSet =
|
||||
|
||||
# Adds some debug arguments like verbose output and class export.
|
||||
usesMixinDebug = false
|
||||
|
||||
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
|
||||
mixinPlugin =
|
||||
|
||||
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
|
||||
mixinsPackage =
|
||||
|
||||
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
|
||||
# This parameter is for legacy compatibility only
|
||||
# Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin
|
||||
# Example value: (coreModClass = asm.FMLPlugin) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.asm.FMLPlugin
|
||||
coreModClass = asm.NEICorePlugin
|
||||
|
||||
# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class
|
||||
# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false!
|
||||
containsMixinsAndOrCoreModOnly = true
|
||||
|
||||
# If enabled, you may use 'shadowImplementation' for dependencies. They will be integrated in your jar. It is your
|
||||
# responsibility check the licence and request permission for distribution, if required.
|
||||
# Enables Mixins even if this mod doesn't use them, useful if one of the dependencies uses mixins.
|
||||
forceEnableMixins = false
|
||||
|
||||
# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated into your jar. It is your
|
||||
# responsibility to check the license and request permission for distribution if required.
|
||||
usesShadowedDependencies = true
|
||||
|
||||
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
|
||||
# If disabled, won't remove unused classes from shadowed dependencies. Some libraries use reflection to access
|
||||
# their own classes, making the minimization unreliable.
|
||||
minimizeShadowedDependencies = true
|
||||
|
||||
# The project's numeric ID on CurseForge. You can find this in the About Project box.
|
||||
# Leave this empty if you don't want to publish on CurseForge.
|
||||
curseForgeProjectId = 358228
|
||||
# If disabled, won't rename the shadowed classes.
|
||||
relocateShadowedDependencies = true
|
||||
|
||||
# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge.
|
||||
# Syntax: type1:name1;type2:name2;...
|
||||
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
|
||||
# and the name is the CurseForge project id of the other mod.
|
||||
curseForgeRelations = requiredDependency:codechickencore-unofficial;requiredDependency:codechickenlib-unofficial
|
||||
# Adds CurseMaven, Modrinth, and some more well-known 1.7.10 repositories.
|
||||
includeWellKnownRepositories = true
|
||||
|
||||
# A list of repositories to exclude from the includeWellKnownRepositories setting. Should be a space separated
|
||||
# list of strings, with the acceptable keys being(case does not matter):
|
||||
# cursemaven
|
||||
# modrinth
|
||||
excludeWellKnownRepositories =
|
||||
|
||||
# Publishing to modrinth requires you to set the MODRINTH_TOKEN environment variable to your current modrinth API token.
|
||||
# Change these to your Maven coordinates if you want to publish to a custom Maven repository instead of the default GTNH Maven.
|
||||
# Authenticate with the MAVEN_USER and MAVEN_PASSWORD environment variables.
|
||||
# If you need a more complex setup disable maven publishing here and add a publishing repository to addon.gradle.
|
||||
usesMavenPublishing = true
|
||||
|
||||
# Maven repository to publish the mod to.
|
||||
# mavenPublishUrl = https\://nexus.gtnewhorizons.com/repository/releases/
|
||||
|
||||
# Publishing to Modrinth requires you to set the MODRINTH_TOKEN environment variable to your current Modrinth API token.
|
||||
#
|
||||
# The project's ID on Modrinth. Can be either the slug or the ID.
|
||||
# Leave this empty if you don't want to publish on Modrinth.
|
||||
|
||||
# Leave this empty if you don't want to publish to Modrinth.
|
||||
modrinthProjectId = notenoughitems-unofficial
|
||||
|
||||
# The project's relations on Modrinth. You can use this to refer to other projects on Modrinth.
|
||||
@@ -92,7 +150,54 @@ modrinthProjectId = notenoughitems-unofficial
|
||||
# Where scope can be one of [required, optional, incompatible, embedded],
|
||||
# type can be one of [project, version],
|
||||
# and the name is the Modrinth project or version slug/id of the other mod.
|
||||
# Example: required-project:fplib;optional-project:gasstation;incompatible-project:gregtech
|
||||
# Note: UniMixins is automatically set as a required dependency if usesMixins = true.
|
||||
modrinthRelations = required-project\:codechickencore-unofficial
|
||||
|
||||
modrinthRelations = required-project:codechickenlib-unofficial;required-project:codechickencore-unofficial
|
||||
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
|
||||
#
|
||||
# The project's numeric ID on CurseForge. You can find this in the About Project box.
|
||||
# Leave this empty if you don't want to publish on CurseForge.
|
||||
curseForgeProjectId = 358228
|
||||
|
||||
# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge.
|
||||
# Syntax: type1:name1;type2:name2;...
|
||||
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
|
||||
# and the name is the CurseForge project slug of the other mod.
|
||||
# Example: requiredDependency:railcraft;embeddedLibrary:cofhlib;incompatible:buildcraft
|
||||
# Note: UniMixins is automatically set as a required dependency if usesMixins = true.
|
||||
curseForgeRelations = requiredDependency\:codechickencore-unofficial
|
||||
|
||||
# Optional parameter to customize the produced artifacts. Use this to preserve artifact naming when migrating older
|
||||
# projects. New projects should not use this parameter.
|
||||
# customArchiveBaseName =
|
||||
|
||||
# Optional parameter to have the build automatically fail if an illegal version is used.
|
||||
# This can be useful if you e.g. only want to allow versions in the form of '1.1.xxx'.
|
||||
# The check is ONLY performed if the version is a git tag.
|
||||
# Note: the specified string must be escaped, so e.g. 1\\.1\\.\\d+ instead of 1\.1\.\d+
|
||||
# versionPattern =
|
||||
|
||||
# Uncomment to prevent the source code from being published.
|
||||
# noPublishedSources = true
|
||||
|
||||
# Uncomment this to disable Spotless checks.
|
||||
# This should only be uncommented to keep it easier to sync with upstream/other forks.
|
||||
# That is, if there is no other active fork/upstream, NEVER change this.
|
||||
# disableSpotless = true
|
||||
|
||||
# Uncomment this to disable Checkstyle checks (currently wildcard import check).
|
||||
# disableCheckstyle = true
|
||||
|
||||
# Override the IDEA build type. Valid values are: "" (leave blank, do not override), "idea" (force use native IDEA build), "gradle"
|
||||
# (force use delegated build).
|
||||
# This is meant to be set in $HOME/.gradle/gradle.properties.
|
||||
# e.g. add "systemProp.org.gradle.project.ideaOverrideBuildType=idea" will override the build type to be native build.
|
||||
# WARNING: If you do use this option, it will overwrite whatever you have in your existing projects. This might not be what you want!
|
||||
# Usually there is no need to uncomment this here as other developers do not necessarily use the same build type as you.
|
||||
# ideaOverrideBuildType = idea
|
||||
|
||||
# Whether IDEA should run spotless checks when pressing the Build button.
|
||||
# This is meant to be set in $HOME/.gradle/gradle.properties.
|
||||
# ideaCheckSpotlessOnBuild = true
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+2
-1
@@ -1,6 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -15,6 +15,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
@@ -55,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -83,10 +85,8 @@ done
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -133,10 +133,13 @@ location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
@@ -144,7 +147,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
@@ -152,7 +155,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@@ -197,11 +200,15 @@ if "$cygwin" || "$msys" ; then
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
|
||||
Vendored
+12
-10
@@ -13,6 +13,8 @@
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
||||
+5
-1
@@ -1,4 +1,8 @@
|
||||
// Add any additional repositiroes for your dependencies here
|
||||
// Add any additional repositories for your dependencies here
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
name = "Modrinth"
|
||||
url = "https://api.modrinth.com/maven"
|
||||
}
|
||||
}
|
||||
+5
-10
@@ -4,10 +4,10 @@ pluginManagement {
|
||||
maven {
|
||||
// RetroFuturaGradle
|
||||
name "GTNH Maven"
|
||||
url "http://jenkins.usrv.eu:8081/nexus/content/groups/public/"
|
||||
allowInsecureProtocol = true
|
||||
url "https://nexus.gtnewhorizons.com/repository/public/"
|
||||
mavenContent {
|
||||
includeGroup("com.gtnewhorizons.retrofuturagradle")
|
||||
includeGroup("com.gtnewhorizons")
|
||||
includeGroupByRegex("com\\.gtnewhorizons\\..+")
|
||||
}
|
||||
}
|
||||
gradlePluginPortal()
|
||||
@@ -17,15 +17,10 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'com.diffplug.blowdryerSetup' version '1.6.0'
|
||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.4.0' // Provides java toolchains
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.42'
|
||||
}
|
||||
|
||||
blowdryerSetup {
|
||||
repoSubfolder 'gtnhShared'
|
||||
github('GTNewHorizons/ExampleMod1.7.10', 'tag', '0.2.0')
|
||||
//devLocal '.' // Use this when testing config updates locally
|
||||
}
|
||||
|
||||
|
||||
rootProject.name = "NotEnoughItems"
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
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 : '^&' | '^' ;
|
||||
PREFIX : CLEAN_SYMBOL {searchParser.hasRedefinedPrefix(getText().charAt(0))}? ;
|
||||
OR : '|' ;
|
||||
LEFT_BRACKET : '{' ;
|
||||
RIGHT_BRACKET : '}' ;
|
||||
PLAIN_TEXT : (CLEAN_SYMBOL | ESCAPED_SYMBOL)+ {!searchParser.hasRedefinedPrefix(getText().charAt(0))}? ;
|
||||
NEWLINE_OR_TAB : [\t\r\n] -> skip ;
|
||||
SPACE : ' ' ;
|
||||
|
||||
fragment ESCAPED_SYMBOL : '\\' . ;
|
||||
fragment CLEAN_SYMBOL : ~[-<>^{}|/\\ "] ;
|
||||
|
||||
mode REGEX;
|
||||
|
||||
REGEX_CONTENT : (~[/] | '\\/')+ ;
|
||||
REGEX_RIGHT : '/' -> popMode ;
|
||||
|
||||
mode QUOTED;
|
||||
|
||||
QUOTED_CONTENT : (~["] | '\\"')+ ;
|
||||
QUOTE_RIGHT : '"' -> popMode ;
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
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]
|
||||
| PLAIN_TEXT
|
||||
;
|
||||
|
||||
regex[Character prefix]
|
||||
: REGEX_LEFT REGEX_CONTENT REGEX_RIGHT?
|
||||
;
|
||||
|
||||
quoted[Character prefix]
|
||||
: QUOTE_LEFT QUOTED_CONTENT QUOTE_RIGHT?
|
||||
;
|
||||
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.drawable.DrawableBuilder;
|
||||
import codechicken.nei.drawable.DrawableResource;
|
||||
import codechicken.nei.guihook.IContainerTooltipHandler;
|
||||
import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.GuiUsageRecipe;
|
||||
|
||||
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 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 drawSplittingLine() {
|
||||
float alpha = (this.splittingLineColor >> 24 & 255) / 255.0F;
|
||||
float red = (this.splittingLineColor >> 16 & 255) / 255.0F;
|
||||
float green = (this.splittingLineColor >> 8 & 255) / 255.0F;
|
||||
float blue = (this.splittingLineColor & 255) / 255.0F;
|
||||
|
||||
int width = this.grid.columns * ItemsGrid.SLOT_SIZE;
|
||||
int repeat = width / 6;
|
||||
int shiftX = this.x + (this.w - width) / 2;
|
||||
|
||||
GL11.glColor4f(red, green, blue, alpha);
|
||||
for (int i = 0; i < repeat; i++) {
|
||||
DASH.draw(shiftX + i * 6, 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())) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import static codechicken.lib.gui.GuiDraw.getMousePosition;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.client.settings.GameSettings;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.guihook.IContainerInputHandler;
|
||||
|
||||
public class AutoFocusWidget implements IContainerInputHandler {
|
||||
|
||||
/**
|
||||
* Implement this interface on a GuiContainer to enable the autofocus search in NEI (if the autofocus option is
|
||||
* enabled) without needing to add the classname to the config file .
|
||||
*/
|
||||
public interface INEIAutoFocusSearchEnable {
|
||||
}
|
||||
|
||||
public static AutoFocusWidget instance = new AutoFocusWidget();
|
||||
|
||||
public static List<String> enableAutoFocusPrefixes = new ArrayList<>();
|
||||
|
||||
protected boolean autofocus = false;
|
||||
protected Point mouse;
|
||||
|
||||
public AutoFocusWidget() {
|
||||
GuiContainerManager.addInputHandler(this);
|
||||
}
|
||||
|
||||
public void load(GuiContainer gui) {
|
||||
this.autofocus = LayoutManager.searchField.isVisible() && NEIClientConfig.searchWidgetAutofocus() != 0
|
||||
&& isAllowedGuiAutoSearchFocus(gui);
|
||||
this.mouse = getMousePosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyTyped(GuiContainer gui, char keyChar, int keyCode) {
|
||||
|
||||
if (this.autofocus) {
|
||||
this.autofocus = false;
|
||||
|
||||
if (!this.mouse.equals(getMousePosition())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.searchWidgetAutofocus() == 2
|
||||
&& GameSettings.isKeyDown(Minecraft.getMinecraft().gameSettings.keyBindInventory)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (keyCode == Keyboard.KEY_RETURN || keyCode == Keyboard.KEY_NUMPADENTER
|
||||
|| keyCode == Keyboard.KEY_ESCAPE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LayoutManager.searchField.setFocus(true);
|
||||
LayoutManager.searchField.handleKeyPress(keyCode, keyChar);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
|
||||
this.autofocus = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
|
||||
this.autofocus = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKeyTyped(GuiContainer gui, char keyChar, int keyID) {}
|
||||
|
||||
@Override
|
||||
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
|
||||
this.autofocus = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseDragged(GuiContainer gui, int mousex, int mousey, int button, long heldTime) {
|
||||
this.autofocus = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
|
||||
this.autofocus = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseUp(GuiContainer gui, int mousex, int mousey, int button) {
|
||||
this.autofocus = false;
|
||||
}
|
||||
|
||||
protected boolean isAllowedGuiAutoSearchFocus(GuiContainer gui) {
|
||||
if (gui instanceof INEIAutoFocusSearchEnable) {
|
||||
return true;
|
||||
}
|
||||
String guiClassName = gui.getClass().getName();
|
||||
for (String prefix : enableAutoFocusPrefixes) {
|
||||
if (guiClassName.startsWith(prefix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiChest;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
|
||||
import codechicken.nei.api.API;
|
||||
import codechicken.nei.api.IBookmarkContainerHandler;
|
||||
|
||||
public class BookmarkContainerInfo {
|
||||
|
||||
private static final HashMap<Class<? extends GuiContainer>, IBookmarkContainerHandler> handlerMap = new HashMap<>();
|
||||
|
||||
public static void registerBookmarkContainerHandler(Class<? extends GuiContainer> classz,
|
||||
IBookmarkContainerHandler handler) {
|
||||
handlerMap.put(classz, handler);
|
||||
}
|
||||
|
||||
public static boolean hasBookmarkContainerHandler(Class<? extends GuiContainer> classz) {
|
||||
return handlerMap.containsKey(classz);
|
||||
}
|
||||
|
||||
public static IBookmarkContainerHandler getBookmarkContainerHandler(GuiContainer gui) {
|
||||
if (gui != null) {
|
||||
return handlerMap.get(gui.getClass());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
API.registerBookmarkContainerHandler(GuiChest.class, new DefaultBookmarkContainerHandler());
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -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,67 +1,66 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.entity.EntityPlayerSP;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.GuiErrorScreen;
|
||||
import net.minecraft.client.gui.GuiMainMenu;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.GuiSelectWorld;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.GuiOpenEvent;
|
||||
import net.minecraftforge.client.event.RenderWorldLastEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import codechicken.core.ClassDiscoverer;
|
||||
import codechicken.core.ClientUtils;
|
||||
import codechicken.core.GuiModListScroll;
|
||||
import codechicken.lib.packet.PacketCustom;
|
||||
import codechicken.nei.api.API;
|
||||
import codechicken.nei.api.IConfigureNEI;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.recipe.GuiRecipeTab;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import cpw.mods.fml.client.CustomModLoadingErrorDisplayException;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModClassLoader;
|
||||
import cpw.mods.fml.common.discovery.ASMDataTable;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import cpw.mods.fml.common.gameevent.TickEvent;
|
||||
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class ClientHandler {
|
||||
|
||||
private static String[] defaultHandlerOrdering = {
|
||||
"# Each line in this file should either be a comment (starts with '#') or an ordering.",
|
||||
"# Ordering lines are <handler ID>,<ordering number>.",
|
||||
"# Handlers will be sorted in order of number ascending, so smaller numbers first.",
|
||||
"# Any handlers that are missing from this file will be assigned to 0.", "# Negative numbers are fine.",
|
||||
"# If you delete this file, it will be regenerated with all registered handler IDs.", };
|
||||
private static ClientHandler instance;
|
||||
|
||||
private ArrayList<EntityItem> SMPmagneticItems = new ArrayList<>();
|
||||
private final ArrayList<EntityItem> SMPmagneticItems = new ArrayList<>();
|
||||
private World lastworld;
|
||||
private GuiScreen lastGui;
|
||||
|
||||
public void addSMPMagneticItem(int i, World world) {
|
||||
WorldClient cworld = (WorldClient) world;
|
||||
@@ -144,57 +143,83 @@ public class ClientHandler {
|
||||
|
||||
public static void preInit() {
|
||||
loadSerialHandlers();
|
||||
loadHiddenItems();
|
||||
loadHeightHackHandlers();
|
||||
loadHiddenHandlers();
|
||||
loadEnableAutoFocus();
|
||||
loadGuiCraftablesBlacklist();
|
||||
ItemInfo.preInit();
|
||||
StackInfo.loadGuidFilters();
|
||||
}
|
||||
|
||||
public static void loadSerialHandlers() {
|
||||
File file = NEIClientConfig.serialHandlersFile;
|
||||
public static void loadSettingsFile(String resource, Consumer<Stream<String>> callback) {
|
||||
loadSettingsFile(resource, (file, writer) -> {
|
||||
String folder = resource.substring(resource.lastIndexOf(".") + 1);
|
||||
URL defaultResource = ClientHandler.class.getResource("/assets/nei/" + folder + "/" + resource);
|
||||
|
||||
if (defaultResource != null) {
|
||||
try {
|
||||
IOUtils.copy(defaultResource.openStream(), writer);
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
}, callback);
|
||||
}
|
||||
|
||||
public static void loadSettingsFile(String resource, BiConsumer<File, FileWriter> createDefault,
|
||||
Consumer<Stream<String>> callback) {
|
||||
File file = new File(NEIClientConfig.configDir, resource);
|
||||
|
||||
if (!file.exists()) {
|
||||
try (FileWriter writer = new FileWriter(file)) {
|
||||
NEIClientConfig.logger.info("Creating default serial handlers list {}", file);
|
||||
URL defaultSerialHandlersResource = ClientHandler.class
|
||||
.getResource("/assets/nei/cfg/serialhandlers.cfg");
|
||||
if (defaultSerialHandlersResource != null) {
|
||||
IOUtils.copy(defaultSerialHandlersResource.openStream(), writer);
|
||||
}
|
||||
NEIClientConfig.logger.info("Creating default '{}' {}", resource, file);
|
||||
createDefault.accept(file, writer);
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to save default serial handlers list to file {}", file, e);
|
||||
NEIClientConfig.logger.error("Failed to save default '{}' to file {}", resource, file, e);
|
||||
}
|
||||
}
|
||||
|
||||
try (FileReader reader = new FileReader(file)) {
|
||||
NEIClientConfig.logger.info("Loading serial handlers from file {}", file);
|
||||
NEIClientConfig.serialHandlers = IOUtils.readLines(reader).stream().filter((line) -> !line.startsWith("#"))
|
||||
.collect(Collectors.toCollection(HashSet::new));
|
||||
NEIClientConfig.logger.info("Loading '{}' file {}", resource, file);
|
||||
callback.accept(
|
||||
IOUtils.readLines(reader).stream().filter(line -> !line.startsWith("#") && !line.trim().isEmpty()));
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to load serial handlers from file {}", file, e);
|
||||
NEIClientConfig.logger.error("Failed to load '{}' file {}", resource, file, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadHeightHackHandlers() {
|
||||
File file = NEIClientConfig.heightHackHandlersFile;
|
||||
if (!file.exists()) {
|
||||
try (FileWriter writer = new FileWriter(file)) {
|
||||
NEIClientConfig.logger.info("Creating default height hack handlers list {}", file);
|
||||
URL defaultHeightHackHandlersResource = ClientHandler.class
|
||||
.getResource("/assets/nei/cfg/heighthackhandlers.cfg");
|
||||
if (defaultHeightHackHandlersResource != null) {
|
||||
IOUtils.copy(defaultHeightHackHandlersResource.openStream(), writer);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to save default height hack handlers list to file {}", file, e);
|
||||
}
|
||||
}
|
||||
public static void loadSerialHandlers() {
|
||||
loadSettingsFile(
|
||||
"serialhandlers.cfg",
|
||||
lines -> NEIClientConfig.serialHandlers = lines.collect(Collectors.toCollection(HashSet::new)));
|
||||
}
|
||||
|
||||
try (FileReader reader = new FileReader(file)) {
|
||||
NEIClientConfig.logger.info("Loading height hack handlers from file {}", file);
|
||||
NEIClientConfig.heightHackHandlerRegex = IOUtils.readLines(reader).stream()
|
||||
.filter((line) -> !line.startsWith("#")).map(Pattern::compile)
|
||||
.collect(Collectors.toCollection(HashSet::new));
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to load height hack handlers from file {}", file, e);
|
||||
}
|
||||
public static void loadHeightHackHandlers() {
|
||||
loadSettingsFile(
|
||||
"heighthackhandlers.cfg",
|
||||
lines -> NEIClientConfig.heightHackHandlerRegex = lines.map(Pattern::compile)
|
||||
.collect(Collectors.toCollection(HashSet::new)));
|
||||
}
|
||||
|
||||
public static void loadHiddenHandlers() {
|
||||
loadSettingsFile(
|
||||
"hiddenhandlers.cfg",
|
||||
lines -> NEIClientConfig.hiddenHandlers = lines.collect(Collectors.toCollection(HashSet::new)));
|
||||
}
|
||||
|
||||
public static void loadEnableAutoFocus() {
|
||||
loadSettingsFile(
|
||||
"enableautofocus.cfg",
|
||||
lines -> AutoFocusWidget.enableAutoFocusPrefixes = lines.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public static void loadGuiCraftablesBlacklist() {
|
||||
loadSettingsFile(
|
||||
"guicraftablesblacklist.cfg",
|
||||
lines -> ItemCraftablesPanel.guiBlacklist = lines.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public static void loadHiddenItems() {
|
||||
loadSettingsFile("hiddenitems.cfg", lines -> lines.forEach(API::hideItem));
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
@@ -211,53 +236,60 @@ public class ClientHandler {
|
||||
}
|
||||
|
||||
public static void postInit() {
|
||||
loadHandlerOrdering();
|
||||
GuiContainerManager.registerReloadResourceListener();
|
||||
}
|
||||
|
||||
public static void loadHandlerOrdering() {
|
||||
File file = NEIClientConfig.handlerOrderingFile;
|
||||
if (!file.exists()) {
|
||||
try (FileWriter writer = new FileWriter(file)) {
|
||||
NEIClientConfig.logger.info("Creating default handler ordering CSV {}", file);
|
||||
|
||||
List<String> toWrite = Lists.newArrayList(defaultHandlerOrdering);
|
||||
GuiRecipeTab.handlerMap.keySet().stream().sorted()
|
||||
.forEach(handlerId -> toWrite.add(String.format("%s,0", handlerId)));
|
||||
final String COMMA_DELIMITER = ",";
|
||||
final String[] defaultHandlerOrdering = {
|
||||
"# Each line in this file should either be a comment (starts with '#') or an ordering.",
|
||||
"# Ordering lines are <handler ID>,<ordering number>.",
|
||||
"# Handlers will be sorted in order of number ascending, so smaller numbers first.",
|
||||
"# Any handlers that are missing from this file will be assigned to 0.", "# Negative numbers are fine.",
|
||||
"# If you delete this file, it will be regenerated with all registered handler IDs.", };
|
||||
|
||||
loadSettingsFile("handlerordering.csv", (file, writer) -> {
|
||||
List<String> toWrite = Lists.newArrayList(defaultHandlerOrdering);
|
||||
GuiRecipeTab.handlerMap.keySet().stream().sorted()
|
||||
.forEach(handlerId -> toWrite.add(String.format("%s" + COMMA_DELIMITER + "0", handlerId)));
|
||||
try {
|
||||
IOUtils.writeLines(toWrite, "\n", writer);
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to save default handler ordering to file {}", file, e);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {}
|
||||
}, lines -> lines.map(line -> line.split(COMMA_DELIMITER)).filter(parts -> parts.length == 2).forEach(parts -> {
|
||||
String handlerId = parts[0];
|
||||
int ordering = Integer.parseInt(parts[1]);
|
||||
NEIClientConfig.handlerOrdering.put(handlerId, ordering);
|
||||
}));
|
||||
}
|
||||
|
||||
URL url;
|
||||
try {
|
||||
url = file.toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
NEIClientConfig.logger.info("Invalid URL for handler ordering CSV.");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
public static void loadPluginsList() {
|
||||
final boolean jarjar = Launch.blackboard.getOrDefault("jarjar.rfbPluginLoaded", Boolean.FALSE) == Boolean.TRUE;
|
||||
if (!jarjar) {
|
||||
// Do the old style class discovery
|
||||
final ClassDiscoverer classDiscoverer = new ClassDiscoverer(
|
||||
test -> test.startsWith("NEI") && test.endsWith("Config.class"),
|
||||
IConfigureNEI.class);
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) {
|
||||
NEIClientConfig.logger.info("Loading handler ordering from file {}", file);
|
||||
CSVParser csvParser = CSVFormat.EXCEL.withCommentMarker('#').parse(reader);
|
||||
for (CSVRecord record : csvParser) {
|
||||
final String handlerId = record.get(0);
|
||||
NEIClientConfig.pluginsList.addAll(classDiscoverer.findClasses());
|
||||
NEIClientConfig.logger
|
||||
.info("Loading NEI Plugins via ClassDiscoverer: " + NEIClientConfig.pluginsList.size());
|
||||
|
||||
int ordering;
|
||||
} else {
|
||||
// If JarJar's loaded, the ASMDataTable now includes interfaces in addition to Annotations, so use that
|
||||
// instead Includes a small change in behavior of no longer requiring the class to start with NEI and end
|
||||
// with Config; This could easily be changed if desired, but the previous behavior was likely to speed
|
||||
// things up by limiting the scope when looking at all of the jars and classes in the classpath.
|
||||
final ASMDataTable dataTable = NEIModContainer.getAsmDataTable();
|
||||
final ModClassLoader modClassLoader = (ModClassLoader) Loader.instance().getModClassLoader();
|
||||
for (ASMDataTable.ASMData asmData : dataTable.getAll(IConfigureNEI.class.getName().replace('.', '/'))) {
|
||||
final String className = asmData.getClassName().replace('/', '.');
|
||||
try {
|
||||
ordering = Integer.parseInt(record.get(1));
|
||||
} catch (NumberFormatException e) {
|
||||
NEIClientConfig.logger.error("Error parsing CSV record {}: {}", record, e);
|
||||
continue;
|
||||
NEIClientConfig.pluginsList.add(Class.forName(className, true, modClassLoader));
|
||||
} catch (ClassNotFoundException e) {
|
||||
NEIClientConfig.logger.error("Failed to load plugin class {}", className, e);
|
||||
}
|
||||
|
||||
NEIClientConfig.handlerOrdering.put(handlerId, ordering);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.info("Error parsing CSV");
|
||||
e.printStackTrace();
|
||||
NEIClientConfig.logger.info("Loading NEI Plugins via JarJar: " + NEIClientConfig.pluginsList.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,18 +313,19 @@ public class ClientHandler {
|
||||
if (mc.currentScreen == null) NEIController.processCreativeCycling(mc.thePlayer.inventory);
|
||||
|
||||
updateMagnetMode(mc.theWorld, mc.thePlayer);
|
||||
} else {
|
||||
lastworld = null;
|
||||
}
|
||||
}
|
||||
|
||||
GuiScreen gui = mc.currentScreen;
|
||||
if (gui != lastGui) {
|
||||
if (gui instanceof GuiMainMenu) lastworld = null;
|
||||
else if (gui instanceof GuiSelectWorld) NEIClientConfig.reloadSaves();
|
||||
else if (gui == null) {
|
||||
/* prevent WorldClient reference being held in the Gui */
|
||||
NEIController.manager = null;
|
||||
}
|
||||
@SubscribeEvent
|
||||
public void onGuiScreen(GuiOpenEvent event) {
|
||||
if (event.gui instanceof GuiSelectWorld) {
|
||||
NEIClientConfig.reloadSaves();
|
||||
} else if (event.gui == null) {
|
||||
/* prevent WorldClient reference being held in the Gui */
|
||||
NEIController.manager = null;
|
||||
}
|
||||
lastGui = gui;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@@ -305,21 +338,29 @@ public class ClientHandler {
|
||||
if (NEIClientConfig.isEnabled()) WorldOverlayRenderer.render(event.partialTicks);
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@SubscribeEvent
|
||||
public void onWorldUnload(WorldEvent.Unload event) {
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
if (event.world == mc.theWorld) {
|
||||
NEIClientConfig.unloadWorld();
|
||||
ItemMobSpawner.clearEntityReferences();
|
||||
}
|
||||
}
|
||||
|
||||
public void loadWorld(World world, boolean fromServer) {
|
||||
if (world != lastworld) {
|
||||
SMPmagneticItems.clear();
|
||||
WorldOverlayRenderer.reset();
|
||||
|
||||
if (!NEIClientConfig.getBooleanSetting("world.overlays.lock")) {
|
||||
WorldOverlayRenderer.reset();
|
||||
}
|
||||
if (!fromServer) {
|
||||
NEIClientConfig.setHasSMPCounterPart(false);
|
||||
NEIClientConfig.setInternalEnabled(false);
|
||||
|
||||
if (!Minecraft.getMinecraft().isSingleplayer()) // wait for server to initiate in singleplayer
|
||||
NEIClientConfig.loadWorld("remote/" + ClientUtils.getServerIP().replace(':', '~'));
|
||||
|
||||
ItemMobSpawner.clearEntityReferences(world);
|
||||
}
|
||||
|
||||
lastworld = world;
|
||||
}
|
||||
}
|
||||
@@ -346,9 +387,10 @@ public class ClientHandler {
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
CustomModLoadingErrorDisplayException e = new CustomModLoadingErrorDisplayException() {
|
||||
|
||||
private static final long serialVersionUID = -5593387489666663375L;
|
||||
|
||||
@Override
|
||||
public void initGui(GuiErrorScreen errorScreen, FontRenderer fontRenderer) {
|
||||
Minecraft.getMinecraft().displayGuiScreen(errorGui);
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTBase.NBTPrimitive;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.StatCollector;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import codechicken.nei.ItemList.AnyMultiItemFilter;
|
||||
import codechicken.nei.ItemList.EverythingItemFilter;
|
||||
import codechicken.nei.ItemList.NothingItemFilter;
|
||||
import codechicken.nei.PresetsList.Preset;
|
||||
import codechicken.nei.PresetsList.PresetMode;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.util.ItemStackFilterParser;
|
||||
|
||||
public class CollapsibleItems {
|
||||
|
||||
protected static class GroupItem {
|
||||
|
||||
public String guid;
|
||||
public ItemFilter filter;
|
||||
public boolean expanded = false;
|
||||
public String displayName = "";
|
||||
|
||||
public void setFilter(String filter) {
|
||||
this.filter = ItemStackFilterParser.parse(filter.trim());
|
||||
this.guid = this.filter != null ? UUID.nameUUIDFromBytes(filter.getBytes()).toString() : "";
|
||||
}
|
||||
|
||||
public void setFilter(ItemFilter filter, String guid) {
|
||||
this.filter = filter;
|
||||
this.guid = guid;
|
||||
}
|
||||
|
||||
public boolean matches(ItemStack stack) {
|
||||
return this.filter.matches(stack);
|
||||
}
|
||||
}
|
||||
|
||||
private static final String STATE_KEY = "collapsibleitems";
|
||||
|
||||
protected static File statesFile;
|
||||
protected static final List<GroupItem> groups = new ArrayList<>();
|
||||
protected static final Map<ItemStack, Integer> cache = new ConcurrentHashMap<>();
|
||||
|
||||
private CollapsibleItems() {}
|
||||
|
||||
public static void load() {
|
||||
CollapsibleItems.groups.clear();
|
||||
CollapsibleItems.cache.clear();
|
||||
|
||||
for (int i = PresetsList.presets.size() - 1; i >= 0; i--) {
|
||||
Preset preset = PresetsList.presets.get(i);
|
||||
if (preset.enabled && preset.mode == PresetMode.GROUP) {
|
||||
GroupItem group = new GroupItem();
|
||||
group.setFilter(preset, UUID.nameUUIDFromBytes(preset.items.toString().getBytes()).toString());
|
||||
group.displayName = preset.name;
|
||||
addGroup(group);
|
||||
}
|
||||
}
|
||||
|
||||
if (NEIClientConfig.enableCollapsibleItems()) {
|
||||
ClientHandler.loadSettingsFile(
|
||||
"collapsibleitems.cfg",
|
||||
lines -> parseFile(lines.collect(Collectors.toCollection(ArrayList::new))));
|
||||
}
|
||||
|
||||
loadStates();
|
||||
}
|
||||
|
||||
private static void parseFile(List<String> itemStrings) {
|
||||
final JsonParser parser = new JsonParser();
|
||||
GroupItem group = new GroupItem();
|
||||
|
||||
for (String itemStr : itemStrings) {
|
||||
try {
|
||||
|
||||
if (itemStr.startsWith("; ")) {
|
||||
JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
|
||||
|
||||
if (settings.get("displayName") != null) {
|
||||
group.displayName = settings.get("displayName").getAsString();
|
||||
}
|
||||
|
||||
if (settings.get("unlocalizedName") != null) {
|
||||
String unlocalizedName = settings.get("unlocalizedName").getAsString();
|
||||
String displayName = StatCollector.translateToLocal(unlocalizedName);
|
||||
|
||||
if (!displayName.equals(unlocalizedName)) {
|
||||
group.displayName = displayName;
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.get("expanded") != null) {
|
||||
group.expanded = settings.get("expanded").getAsBoolean();
|
||||
}
|
||||
|
||||
} else {
|
||||
group.setFilter(itemStr);
|
||||
}
|
||||
|
||||
if (group != null && group.filter != null) {
|
||||
addGroup(group);
|
||||
group = new GroupItem();
|
||||
}
|
||||
|
||||
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
|
||||
NEIClientConfig.logger.error("Failed to load collapsible items from json string:\n{}", itemStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addGroup(GroupItem group) {
|
||||
if (group == null || group.filter == null
|
||||
|| group.filter instanceof EverythingItemFilter
|
||||
|| group.filter instanceof NothingItemFilter)
|
||||
return;
|
||||
CollapsibleItems.groups.add(group);
|
||||
}
|
||||
|
||||
public static boolean isEmpty() {
|
||||
return CollapsibleItems.groups.isEmpty();
|
||||
}
|
||||
|
||||
public static ItemFilter getItemFilter() {
|
||||
AnyMultiItemFilter filter = new AnyMultiItemFilter();
|
||||
|
||||
for (GroupItem group : CollapsibleItems.groups) {
|
||||
filter.filters.add(group.filter);
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
public static void clearCache() {
|
||||
CollapsibleItems.cache.clear();
|
||||
}
|
||||
|
||||
public static void putItem(ItemStack stack) {
|
||||
int groupIndex = -1;
|
||||
|
||||
for (int i = 0; i < CollapsibleItems.groups.size() && groupIndex == -1; i++) {
|
||||
if (CollapsibleItems.groups.get(i).matches(stack)) {
|
||||
groupIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (groupIndex != -1) {
|
||||
CollapsibleItems.cache.put(stack, groupIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getGroupIndex(ItemStack stack) {
|
||||
|
||||
if (stack == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return CollapsibleItems.cache.getOrDefault(stack, -1);
|
||||
}
|
||||
|
||||
public static String getDisplayName(int groupIndex) {
|
||||
|
||||
if (groupIndex < CollapsibleItems.groups.size()) {
|
||||
return CollapsibleItems.groups.get(groupIndex).displayName;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isExpanded(int groupIndex) {
|
||||
|
||||
if (groupIndex < CollapsibleItems.groups.size()) {
|
||||
return CollapsibleItems.groups.get(groupIndex).expanded;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void setExpanded(int groupIndex, boolean expanded) {
|
||||
|
||||
if (groupIndex < CollapsibleItems.groups.size()) {
|
||||
CollapsibleItems.groups.get(groupIndex).expanded = expanded;
|
||||
}
|
||||
}
|
||||
|
||||
public static void toggleGroups(Boolean expanded) {
|
||||
|
||||
if (expanded == null) {
|
||||
expanded = CollapsibleItems.groups.stream().noneMatch(g -> g.expanded);
|
||||
}
|
||||
|
||||
for (GroupItem group : CollapsibleItems.groups) {
|
||||
group.expanded = expanded;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void saveStates() {
|
||||
NBTTagCompound list = new NBTTagCompound();
|
||||
|
||||
for (GroupItem group : CollapsibleItems.groups) {
|
||||
list.setBoolean(group.guid, group.expanded);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.world != null) {
|
||||
NEIClientConfig.world.nbt.setTag(STATE_KEY, list);
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadStates() {
|
||||
|
||||
try {
|
||||
|
||||
if (NEIClientConfig.world.nbt.hasKey(STATE_KEY)) {
|
||||
NBTTagCompound states = NEIClientConfig.world.nbt.getCompoundTag(STATE_KEY);
|
||||
@SuppressWarnings("unchecked")
|
||||
final Map<String, NBTPrimitive> list = (Map<String, NBTPrimitive>) states.tagMap;
|
||||
final Map<String, GroupItem> mapping = new HashMap<>();
|
||||
|
||||
for (GroupItem group : CollapsibleItems.groups) {
|
||||
mapping.put(group.guid, group);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, NBTPrimitive> nbtEntry : list.entrySet()) {
|
||||
if (mapping.containsKey(nbtEntry.getKey())) {
|
||||
mapping.get(nbtEntry.getKey()).expanded = nbtEntry.getValue().func_150290_f() == 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.error("Error loading collapsible items states", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -81,7 +81,6 @@ public class ContainerPotionCreator extends ContainerExtended {
|
||||
public void markDirty() {
|
||||
super.markDirty();
|
||||
NEIClientConfig.global.nbt.setTag("potionStore", tag);
|
||||
NEIClientConfig.global.saveNBT();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +116,6 @@ public class ContainerPotionCreator extends ContainerExtended {
|
||||
if (!player.worldObj.isRemote) InventoryUtils.dropOnClose(player, potionInv);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void handleServerPacket(PacketCustom packet) {
|
||||
ItemStack potion = potionInv.getStackInSlot(0);
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.nei.api.IBookmarkContainerHandler;
|
||||
|
||||
public class DefaultBookmarkContainerHandler implements IBookmarkContainerHandler {
|
||||
|
||||
@Override
|
||||
public void pullBookmarkItemsFromContainer(GuiContainer guiContainer, ArrayList<ItemStack> bookmarkItems) {
|
||||
FastTransferManager manager = new FastTransferManager();
|
||||
LinkedList<ItemStack> containerStacks = manager.saveContainer(guiContainer.inventorySlots);
|
||||
|
||||
for (ItemStack bookmarkItem : bookmarkItems) {
|
||||
|
||||
int bookmarkSizeBackup = bookmarkItem.stackSize;
|
||||
|
||||
for (int i = 0; i < containerStacks.size() - 4 * 9; i++) { // Last 36 slots are player inventory
|
||||
ItemStack containerItem = containerStacks.get(i);
|
||||
|
||||
if (containerItem == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bookmarkItem.isItemEqual(containerItem)) {
|
||||
if (bookmarkItem.stackSize <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
int transferAmount = Math.min(bookmarkItem.stackSize, containerItem.stackSize);
|
||||
|
||||
manager.transferItems(guiContainer, i, transferAmount);
|
||||
bookmarkItem.stackSize -= transferAmount;
|
||||
|
||||
if (bookmarkItem.stackSize == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bookmarkItem.stackSize = bookmarkSizeBackup;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -184,6 +184,12 @@ public class FastTransferManager {
|
||||
moveOutputSet(window, fromSlot, toSlot);
|
||||
}
|
||||
|
||||
public void transferItems(GuiContainer window, int fromSlot, int itemCount) {
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
transferItem(window, fromSlot);
|
||||
}
|
||||
}
|
||||
|
||||
public void moveOutputSet(GuiContainer window, int fromSlot, int toSlot) {
|
||||
if (NEIClientUtils.getHeldItem() != null) return;
|
||||
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.fluids.FluidRegistry;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import codechicken.core.CommonUtils;
|
||||
import codechicken.nei.api.API;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.NBTJson;
|
||||
|
||||
public class FavoriteRecipes {
|
||||
|
||||
private static final Set<NBTTagCompound> tools = new HashSet<>();
|
||||
private static final Map<NBTTagCompound, RecipeId> items = new HashMap<>();
|
||||
private static final Map<String, RecipeId> fluids = new HashMap<>();
|
||||
private static File favoriteFile;
|
||||
|
||||
static {
|
||||
API.addSubset("Favorites", FavoriteRecipes::contains);
|
||||
}
|
||||
|
||||
private FavoriteRecipes() {}
|
||||
|
||||
public static void load() {
|
||||
String worldPath = "global";
|
||||
|
||||
if (NEIClientConfig.getBooleanSetting("inventory.favorites.worldSpecific")) {
|
||||
worldPath = NEIClientConfig.getWorldPath();
|
||||
}
|
||||
|
||||
final File dir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
|
||||
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
favoriteFile = new File(dir, "favorites.ini");
|
||||
|
||||
if (!favoriteFile.exists()) {
|
||||
final File globalFavorites = new File(CommonUtils.getMinecraftDir(), "saves/NEI/global/favorites.ini");
|
||||
final File configFavorites = new File(NEIClientConfig.configDir, "favorites.ini");
|
||||
final File defaultFavorites = configFavorites.exists() ? configFavorites : globalFavorites;
|
||||
|
||||
if (defaultFavorites.exists()) {
|
||||
|
||||
try {
|
||||
if (favoriteFile.createNewFile()) {
|
||||
InputStream src = new FileInputStream(defaultFavorites);
|
||||
OutputStream dst = new FileOutputStream(favoriteFile);
|
||||
|
||||
IOUtils.copy(src, dst);
|
||||
|
||||
src.close();
|
||||
dst.close();
|
||||
}
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
loadData();
|
||||
}
|
||||
|
||||
private static void loadData() {
|
||||
|
||||
if (favoriteFile == null || !favoriteFile.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> itemStrings;
|
||||
|
||||
try (FileInputStream reader = new FileInputStream(favoriteFile)) {
|
||||
NEIClientConfig.logger.info("Loading favorites from file {}", favoriteFile);
|
||||
itemStrings = IOUtils.readLines(reader, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to load favorites from file {}", favoriteFile, e);
|
||||
return;
|
||||
}
|
||||
|
||||
final JsonParser parser = new JsonParser();
|
||||
items.clear();
|
||||
|
||||
for (String itemStr : itemStrings) {
|
||||
|
||||
if (itemStr.isEmpty() || itemStr.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
JsonObject jsonObject = parser.parse(itemStr).getAsJsonObject();
|
||||
|
||||
if (jsonObject.get("item") != null && jsonObject.get("recipeId") != null) {
|
||||
final NBTTagCompound itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject.get("item"));
|
||||
final RecipeId recipeId = RecipeId.of(jsonObject.getAsJsonObject("recipeId"));
|
||||
final ItemStack stack = StackInfo.loadFromNBT(itemStackNBT);
|
||||
|
||||
if (stack != null) {
|
||||
final String fluidKey = getFluidKey(stack);
|
||||
|
||||
if (fluidKey != null) {
|
||||
fluids.put(fluidKey, recipeId);
|
||||
}
|
||||
}
|
||||
|
||||
items.put(itemStackNBT, recipeId);
|
||||
|
||||
if (NEIServerUtils.isItemTool(stack)) {
|
||||
tools.add(itemStackNBT);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
|
||||
NEIClientConfig.logger.error("Failed to load favorite from json string:\n{}", itemStr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SubsetWidget.updateHiddenItems();
|
||||
}
|
||||
|
||||
public static RecipeId getFavorite(ItemStack stack) {
|
||||
|
||||
if (NEIClientConfig.favoritesEnabled() && stack != null) {
|
||||
RecipeId recipeId = items.get(StackInfo.itemStackToNBT(stack, false));
|
||||
|
||||
if (recipeId == null) {
|
||||
recipeId = fluids.get(getFluidKey(stack));
|
||||
}
|
||||
|
||||
if (recipeId != null) {
|
||||
return recipeId;
|
||||
}
|
||||
|
||||
if (NEIServerUtils.isItemTool(stack)
|
||||
&& (stack.stackTagCompound == null || !stack.stackTagCompound.hasKey("GT.ToolStats"))) {
|
||||
for (NBTTagCompound nbt : tools) {
|
||||
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(stack, StackInfo.loadFromNBT(nbt))) {
|
||||
return items.get(nbt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ItemStack getFavorite(RecipeId recipeId) {
|
||||
if (NEIClientConfig.favoritesEnabled()) {
|
||||
final Optional<Map.Entry<NBTTagCompound, RecipeId>> result = items.entrySet().stream()
|
||||
.filter(entry -> entry.getValue().equals(recipeId)).findAny();
|
||||
|
||||
if (result.isPresent()) {
|
||||
return StackInfo.loadFromNBT(result.get().getKey());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean contains(ItemStack stack) {
|
||||
return getFavorite(stack) != null;
|
||||
}
|
||||
|
||||
public static void setFavorite(ItemStack stack, RecipeId recipeId) {
|
||||
final NBTTagCompound itemStackNBT = StackInfo.itemStackToNBT(stack, false);
|
||||
final String fluidKey = getFluidKey(stack);
|
||||
|
||||
items.entrySet().removeIf(entry -> entry.getKey().equals(itemStackNBT) || entry.getValue().equals(recipeId));
|
||||
fluids.entrySet().removeIf(entry -> entry.getKey().equals(fluidKey) || entry.getValue().equals(recipeId));
|
||||
|
||||
if (recipeId != null) {
|
||||
items.put(itemStackNBT, recipeId);
|
||||
|
||||
if (NEIServerUtils.isItemTool(stack)) {
|
||||
tools.add(itemStackNBT);
|
||||
}
|
||||
|
||||
if (fluidKey != null) {
|
||||
fluids.put(fluidKey, recipeId);
|
||||
}
|
||||
}
|
||||
|
||||
SubsetWidget.updateHiddenItems();
|
||||
ItemList.updateFilter.restart();
|
||||
}
|
||||
|
||||
private static String getFluidKey(ItemStack stack) {
|
||||
final FluidStack fluid = StackInfo.getFluid(stack);
|
||||
|
||||
if (fluid != null) {
|
||||
return FluidRegistry.getFluidName(fluid);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void save() {
|
||||
|
||||
if (favoriteFile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<String> strings = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<NBTTagCompound, RecipeId> entry : items.entrySet()) {
|
||||
|
||||
try {
|
||||
final JsonObject line = new JsonObject();
|
||||
|
||||
line.add("item", NBTJson.toJsonObject(entry.getKey()));
|
||||
line.add("recipeId", entry.getValue().toJsonObject());
|
||||
|
||||
strings.add(NBTJson.toJson(line));
|
||||
} catch (JsonSyntaxException e) {
|
||||
NEIClientConfig.logger.error("Failed to stringify favorites ItemStack to json string");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
try (FileOutputStream output = new FileOutputStream(favoriteFile)) {
|
||||
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to save favorites list to file {}", favoriteFile, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.gui.GuiTextField;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.util.ChatAllowedCharacters;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class FormattedTextField extends GuiTextField {
|
||||
|
||||
public static interface TextFormatter {
|
||||
|
||||
TextFormatter DEFAULT = (text) -> text;
|
||||
|
||||
public String format(String text);
|
||||
}
|
||||
|
||||
protected FontRenderer fontRenderer;
|
||||
protected String rawText = "";
|
||||
protected String formattedText = "";
|
||||
protected String placeholder = "";
|
||||
protected boolean editable = true;
|
||||
protected int editableColor = 14737632;
|
||||
protected int notEditableColor = 7368816;
|
||||
protected TextFormatter formatter = TextFormatter.DEFAULT;
|
||||
protected int lineScrollOffset = 0;
|
||||
protected int frame = 0;
|
||||
|
||||
public FormattedTextField(FontRenderer fontRenderer, int xPosition, int yPosition, int width, int height) {
|
||||
super(fontRenderer, xPosition, yPosition, width, height);
|
||||
this.fontRenderer = fontRenderer;
|
||||
}
|
||||
|
||||
public void setFormatter(TextFormatter formatter) {
|
||||
this.formatter = formatter;
|
||||
}
|
||||
|
||||
public TextFormatter getFormatter() {
|
||||
return this.formatter;
|
||||
}
|
||||
|
||||
public void setPlaceholder(String placeholder) {
|
||||
this.placeholder = placeholder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCursorCounter() {
|
||||
super.updateCursorCounter();
|
||||
++this.frame;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFocused(boolean focus) {
|
||||
if (focus && !this.isFocused()) {
|
||||
this.frame = 0;
|
||||
}
|
||||
|
||||
super.setFocused(focus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectionPos(int p_146199_1_) {
|
||||
String text = this.getText();
|
||||
int j = text.length();
|
||||
|
||||
super.setSelectionPos(p_146199_1_);
|
||||
|
||||
p_146199_1_ = Math.max(0, Math.min(p_146199_1_, j));
|
||||
|
||||
if (this.fontRenderer != null) {
|
||||
|
||||
if (this.lineScrollOffset > j) {
|
||||
this.lineScrollOffset = j;
|
||||
}
|
||||
|
||||
int k = this.getWidth();
|
||||
String s = this.fontRenderer.trimStringToWidth(text.substring(this.lineScrollOffset), k);
|
||||
int l = s.length() + this.lineScrollOffset;
|
||||
|
||||
if (p_146199_1_ == this.lineScrollOffset) {
|
||||
this.lineScrollOffset -= this.fontRenderer.trimStringToWidth(text, k, true).length();
|
||||
}
|
||||
|
||||
if (p_146199_1_ > l) {
|
||||
this.lineScrollOffset += p_146199_1_ - l;
|
||||
} else if (p_146199_1_ <= this.lineScrollOffset) {
|
||||
this.lineScrollOffset -= this.lineScrollOffset - p_146199_1_;
|
||||
}
|
||||
|
||||
this.lineScrollOffset = Math.max(0, Math.min(this.lineScrollOffset, j));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextColor(int p_146193_1_) {
|
||||
super.setTextColor(p_146193_1_);
|
||||
this.editableColor = p_146193_1_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisabledTextColour(int p_146204_1_) {
|
||||
super.setDisabledTextColour(p_146204_1_);
|
||||
this.notEditableColor = p_146204_1_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean p_146184_1_) {
|
||||
super.setEnabled(p_146184_1_);
|
||||
this.editable = p_146184_1_;
|
||||
}
|
||||
|
||||
protected boolean beforeWrite(String text) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeText(String textPart) {
|
||||
String newText = "";
|
||||
String substr = ChatAllowedCharacters.filerAllowedCharacters(textPart);
|
||||
int cursorPosition = getCursorPosition();
|
||||
int maxStringLength = getMaxStringLength();
|
||||
String text = getText();
|
||||
|
||||
if (text.isEmpty()) {
|
||||
newText = substr.substring(0, Math.min(maxStringLength, substr.length()));
|
||||
cursorPosition = newText.length();
|
||||
} else {
|
||||
int selectionEnd = getSelectionEnd();
|
||||
String textStart = text.substring(0, Math.min(cursorPosition, selectionEnd));
|
||||
String textEnd = text.substring(Math.max(cursorPosition, selectionEnd));
|
||||
newText = textStart + substr + textEnd;
|
||||
|
||||
if (newText.length() > maxStringLength) {
|
||||
newText = newText.substring(0, maxStringLength);
|
||||
}
|
||||
|
||||
cursorPosition = Math.min(textStart.length() + substr.length(), newText.length());
|
||||
}
|
||||
|
||||
if (beforeWrite(newText)) {
|
||||
setText(newText);
|
||||
setCursorPosition(cursorPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNthWordFromPos(int p_146183_1_, int p_146183_2_) {
|
||||
return this.func_146197_a(p_146183_1_, p_146183_2_, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawTextBox() {
|
||||
|
||||
if (!this.getVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.getEnableBackgroundDrawing()) {
|
||||
drawRect(
|
||||
this.xPosition - 1,
|
||||
this.yPosition - 1,
|
||||
this.xPosition + this.width + 1,
|
||||
this.yPosition + this.height + 1,
|
||||
-6250336);
|
||||
drawRect(
|
||||
this.xPosition,
|
||||
this.yPosition,
|
||||
this.xPosition + this.width,
|
||||
this.yPosition + this.height,
|
||||
-16777216);
|
||||
}
|
||||
|
||||
if (!this.rawText.equals(getText())) {
|
||||
this.rawText = getText();
|
||||
this.formattedText = this.formatter.format(this.rawText);
|
||||
if (!EnumChatFormatting.getTextWithoutFormattingCodes(this.formattedText).toLowerCase()
|
||||
.equals(this.rawText.toLowerCase())) {
|
||||
this.formattedText = this.rawText;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isFocused() && this.formattedText.isEmpty()) {
|
||||
int x = getEnableBackgroundDrawing() ? this.xPosition + 4 : this.xPosition;
|
||||
int y = getEnableBackgroundDrawing() ? this.yPosition + (this.height - 8) / 2 : this.yPosition;
|
||||
this.fontRenderer.drawStringWithShadow(
|
||||
this.fontRenderer.trimStringToWidth(this.placeholder, this.getWidth()),
|
||||
x,
|
||||
y,
|
||||
this.notEditableColor);
|
||||
return;
|
||||
}
|
||||
|
||||
int firstCharacterIndex = getFormattedTextShift(this.lineScrollOffset);
|
||||
String rawTextClipped = this.fontRenderer
|
||||
.trimStringToWidth(this.rawText.substring(this.lineScrollOffset), this.getWidth());
|
||||
String textClipped = this.formattedText
|
||||
.substring(firstCharacterIndex, getFormattedTextShift(this.lineScrollOffset + rawTextClipped.length()));
|
||||
int cursorPosition = getFormattedTextShift(getCursorPosition());
|
||||
int selectionEnd = getFormattedTextShift(getSelectionEnd());
|
||||
|
||||
int color = this.editable ? this.editableColor : this.notEditableColor;
|
||||
int cursorA = cursorPosition - firstCharacterIndex;
|
||||
int cursorB = selectionEnd - firstCharacterIndex;
|
||||
boolean flag = cursorA >= 0 && cursorA <= textClipped.length();
|
||||
boolean flag1 = isFocused() && this.frame / 6 % 2 == 0 && flag;
|
||||
boolean flag2 = getCursorPosition() < this.rawText.length() || this.rawText.length() >= getMaxStringLength();
|
||||
int x = getEnableBackgroundDrawing() ? this.xPosition + 4 : this.xPosition;
|
||||
int y = getEnableBackgroundDrawing() ? this.yPosition + (this.height - 8) / 2 : this.yPosition;
|
||||
int x2 = x;
|
||||
|
||||
if (cursorB > textClipped.length()) {
|
||||
cursorB = textClipped.length();
|
||||
}
|
||||
|
||||
if (textClipped.length() > 0) {
|
||||
String s1 = flag ? textClipped.substring(0, cursorA) : textClipped;
|
||||
String colorA = getPreviousColor(firstCharacterIndex);
|
||||
x2 = this.fontRenderer.drawStringWithShadow(colorA + s1, x, y, color);
|
||||
}
|
||||
|
||||
int k1 = x2;
|
||||
|
||||
if (!flag) {
|
||||
k1 = cursorA > 0 ? x + this.width : x;
|
||||
} else if (flag2) {
|
||||
k1 = x2 - 1;
|
||||
--x2;
|
||||
}
|
||||
|
||||
if (textClipped.length() > 0 && flag && cursorA < textClipped.length()) {
|
||||
String colorB = getPreviousColor(firstCharacterIndex + cursorA);
|
||||
this.fontRenderer.drawStringWithShadow(colorB + textClipped.substring(cursorA), x2, y, color);
|
||||
}
|
||||
|
||||
if (flag1) {
|
||||
if (flag2) {
|
||||
Gui.drawRect(k1, y - 1, k1 + 1, y + 1 + this.fontRenderer.FONT_HEIGHT, -3092272);
|
||||
} else {
|
||||
this.fontRenderer.drawStringWithShadow("_", k1, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
if (cursorB != cursorA) {
|
||||
int l1 = x + this.fontRenderer.getStringWidth(textClipped.substring(0, cursorB));
|
||||
drawCursorVertical(k1, y - 1, l1 - 1, y + 1 + this.fontRenderer.FONT_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawCursorVertical(int x1, int y1, int x2, int y2) {
|
||||
int i1;
|
||||
|
||||
if (x1 < x2) {
|
||||
i1 = x1;
|
||||
x1 = x2;
|
||||
x2 = i1;
|
||||
}
|
||||
|
||||
if (y1 < y2) {
|
||||
i1 = y1;
|
||||
y1 = y2;
|
||||
y2 = i1;
|
||||
}
|
||||
|
||||
if (x2 > this.xPosition + this.width) {
|
||||
x2 = this.xPosition + this.width;
|
||||
}
|
||||
|
||||
if (x1 > this.xPosition + this.width) {
|
||||
x1 = this.xPosition + this.width;
|
||||
}
|
||||
|
||||
Tessellator tessellator = Tessellator.instance;
|
||||
GL11.glColor4f(0.0F, 0.0F, 255.0F, 255.0F);
|
||||
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
GL11.glEnable(GL11.GL_COLOR_LOGIC_OP);
|
||||
GL11.glLogicOp(GL11.GL_OR_REVERSE);
|
||||
tessellator.startDrawingQuads();
|
||||
tessellator.addVertex((double) x1, (double) y2, 0.0D);
|
||||
tessellator.addVertex((double) x2, (double) y2, 0.0D);
|
||||
tessellator.addVertex((double) x2, (double) y1, 0.0D);
|
||||
tessellator.addVertex((double) x1, (double) y1, 0.0D);
|
||||
tessellator.draw();
|
||||
GL11.glDisable(GL11.GL_COLOR_LOGIC_OP);
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
private int getFormattedTextShift(int position) {
|
||||
int shift = 0;
|
||||
|
||||
for (int i = 0; i < position; i++) {
|
||||
while (this.formattedText.length() > i + shift && this.formattedText.charAt(i + shift) == '\u00a7') {
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return position + shift;
|
||||
}
|
||||
|
||||
private String getPreviousColor(int position) {
|
||||
while (position >= 0) {
|
||||
if (this.formattedText.charAt(position) == '\u00a7') {
|
||||
return this.formattedText.substring(position, position + 2);
|
||||
}
|
||||
position--;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -62,7 +62,6 @@ public class GuiEnchantmentModifier extends GuiContainer {
|
||||
|
||||
public static void toggleEnchantmentValidation() {
|
||||
NEIClientConfig.world.nbt.setBoolean("validateenchantments", !validateEnchantments());
|
||||
NEIClientConfig.world.saveNBT();
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton guibutton) {
|
||||
|
||||
@@ -12,10 +12,11 @@ import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.render.CCRenderState;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.AutoFocusWidget.INEIAutoFocusSearchEnable;
|
||||
import codechicken.nei.api.INEIGuiHandler;
|
||||
import codechicken.nei.api.TaggedInventoryArea;
|
||||
|
||||
public class GuiExtendedCreativeInv extends GuiContainer implements INEIGuiHandler {
|
||||
public class GuiExtendedCreativeInv extends GuiContainer implements INEIGuiHandler, INEIAutoFocusSearchEnable {
|
||||
|
||||
public GuiExtendedCreativeInv(Container par1Container) {
|
||||
super(par1Container);
|
||||
@@ -59,13 +60,13 @@ public class GuiExtendedCreativeInv extends GuiContainer implements INEIGuiHandl
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleMouseClick(Slot p_146984_1_, int p_146984_2_, int p_146984_3_, int p_146984_4_) {
|
||||
protected void handleMouseClick(Slot slotIn, int slotId, int clickedButton, int clickType) {
|
||||
|
||||
// Hack for armor slots, because they are outside the container
|
||||
if (p_146984_1_ != null && p_146984_4_ == 4 && p_146984_1_.xDisplayPosition < 0) {
|
||||
p_146984_4_ = 0;
|
||||
if (slotIn != null && clickType == 4 && slotIn.xDisplayPosition < 0) {
|
||||
clickType = 0;
|
||||
}
|
||||
|
||||
super.handleMouseClick(p_146984_1_, p_146984_2_, p_146984_3_, p_146984_4_);
|
||||
super.handleMouseClick(slotIn, slotId, clickedButton, clickType);
|
||||
}
|
||||
}
|
||||
@@ -15,14 +15,13 @@ public class GuiNEIButton extends GuiButton {
|
||||
super(i, j, k, l, i1, s);
|
||||
}
|
||||
|
||||
public void drawButton(Minecraft minecraft, int i, int j) {
|
||||
public void drawButton(Minecraft minecraft, int x, int y) {
|
||||
if (!visible) return;
|
||||
|
||||
FontRenderer fontrenderer = minecraft.fontRenderer;
|
||||
minecraft.renderEngine.bindTexture(guiTex);
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
boolean flag = i >= xPosition && j >= yPosition && i < xPosition + width && j < yPosition + height;
|
||||
int k = getHoverState(flag);
|
||||
boolean mouseOver = x >= xPosition && y >= yPosition && x < xPosition + width && y < yPosition + height;
|
||||
int k = getHoverState(mouseOver);
|
||||
drawTexturedModalRect(xPosition, yPosition, 0, 46 + k * 20, width / 2, height / 2); // top left
|
||||
drawTexturedModalRect(xPosition + width / 2, yPosition, 200 - width / 2, 46 + k * 20, width / 2, height / 2); // top
|
||||
// right
|
||||
@@ -40,25 +39,27 @@ public class GuiNEIButton extends GuiButton {
|
||||
46 + k * 20 + 20 - height / 2,
|
||||
width / 2,
|
||||
height / 2); // bottom right
|
||||
mouseDragged(minecraft, i, j);
|
||||
mouseDragged(minecraft, x, y);
|
||||
|
||||
if (!enabled) drawCenteredString(
|
||||
fontrenderer,
|
||||
displayString,
|
||||
xPosition + width / 2,
|
||||
yPosition + (height - 8) / 2,
|
||||
0xffa0a0a0);
|
||||
else if (flag) drawCenteredString(
|
||||
fontrenderer,
|
||||
displayString,
|
||||
xPosition + width / 2,
|
||||
yPosition + (height - 8) / 2,
|
||||
0xffffa0);
|
||||
else drawCenteredString(
|
||||
fontrenderer,
|
||||
displayString,
|
||||
xPosition + width / 2,
|
||||
yPosition + (height - 8) / 2,
|
||||
0xe0e0e0);
|
||||
drawContent(minecraft, x, y, mouseOver);
|
||||
}
|
||||
|
||||
protected int getTextColour(boolean mouseOver) {
|
||||
int color = 0xe0e0e0;
|
||||
|
||||
if (!enabled) {
|
||||
color = 0xffa0a0a0;
|
||||
} else if (mouseOver) {
|
||||
color = 0xffffa0;
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
protected void drawContent(Minecraft minecraft, int y, int x, boolean mouseOver) {
|
||||
FontRenderer fontrenderer = minecraft.fontRenderer;
|
||||
int color = getTextColour(mouseOver);
|
||||
|
||||
drawCenteredString(fontrenderer, displayString, xPosition + width / 2, yPosition + (height - 8) / 2, color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import static codechicken.nei.NEIClientUtils.translate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.guihook.IContainerInputHandler;
|
||||
import codechicken.nei.guihook.IContainerTooltipHandler;
|
||||
import codechicken.nei.recipe.AutoCraftingManager;
|
||||
|
||||
public class HeldItemHandler implements IContainerInputHandler, IContainerTooltipHandler {
|
||||
|
||||
protected HeldItemHandler() {
|
||||
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
HeldItemHandler instance = new HeldItemHandler();
|
||||
GuiContainerManager.addInputHandler(instance);
|
||||
GuiContainerManager.addTooltipHandler(instance);
|
||||
}
|
||||
|
||||
protected boolean contains(int mousex, int mousey) {
|
||||
return NEIClientUtils.getHeldItem() != null && !ItemPanels.bookmarkPanel.inEditingState()
|
||||
&& !AutoCraftingManager.processing()
|
||||
&& (ItemPanels.bookmarkPanel.contains(mousex, mousey) || ItemPanels.itemPanel.contains(mousex, mousey)
|
||||
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
|
||||
|
||||
if (contains(mousex, mousey)) {
|
||||
|
||||
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")) {
|
||||
if (button == 1) {
|
||||
NEIClientUtils.decreaseSlotStack(-999);
|
||||
} else {
|
||||
NEIClientUtils.deleteHeldItem();
|
||||
}
|
||||
} else {
|
||||
NEIClientUtils.dropHeldItem();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyTyped(GuiContainer gui, char keyChar, int keyCode) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKeyTyped(GuiContainer gui, char keyChar, int keyID) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseDragged(GuiContainer gui, int mousex, int mousey, int button, long heldTime) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseUp(GuiContainer gui, int mousex, int mousey, int button) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
|
||||
|
||||
if (contains(mousex, mousey)) {
|
||||
currenttip.clear();
|
||||
|
||||
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")) {
|
||||
currenttip.add(EnumChatFormatting.RED + translate("itempanel.deleteItem"));
|
||||
}
|
||||
}
|
||||
|
||||
return currenttip;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
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;
|
||||
|
||||
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) {
|
||||
int maxSlotIndex = this.rows * this.columns;
|
||||
final AtomicInteger slotIndex = new AtomicInteger(0);
|
||||
final List<CraftablesGridSlot> gridMask = new ArrayList<>();
|
||||
this.realItems.clear();
|
||||
|
||||
if (!ItemCraftablesPanel.this.availableRecipes.isEmpty()) {
|
||||
ItemCraftablesPanel.this.availableRecipes.entrySet().stream()
|
||||
.sorted(Map.Entry.comparingByKey(ItemSorter.instance)).forEach(entry -> {
|
||||
this.realItems.add(entry.getKey());
|
||||
gridMask.add(
|
||||
new CraftablesGridSlot(
|
||||
slotIndex.get(),
|
||||
slotIndex.get(),
|
||||
entry.getKey(),
|
||||
entry.getValue()));
|
||||
slotIndex.incrementAndGet();
|
||||
});
|
||||
|
||||
this.gridMask = gridMask.subList(0, Math.min(gridMask.size(), maxSlotIndex));
|
||||
} else {
|
||||
this.gridMask = Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
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 ItemStackAmount inv = AutoCraftingManager.getInventoryItems(firstGui);
|
||||
|
||||
if (this.lastGuiContainer != (this.lastGuiContainer = firstGui)
|
||||
|| !inv.equals(this.lastPlayerInventory)) {
|
||||
this.lastPlayerInventory = inv;
|
||||
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<>();
|
||||
|
||||
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()) {
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.ItemsGrid.MouseContext;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
|
||||
public class ItemHistoryPanel extends AbstractSubpanel<ItemsGrid<ItemHistoryPanel.HistoryGridSlot, MouseContext>> {
|
||||
|
||||
public static class HistoryGridSlot extends ItemsGridSlot {
|
||||
|
||||
public HistoryGridSlot(int slotIndex, int itemIndex, ItemStack item) {
|
||||
super(slotIndex, itemIndex, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeId getRecipeId() {
|
||||
return FavoriteRecipes.getFavorite(this.item);
|
||||
}
|
||||
}
|
||||
|
||||
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<>();
|
||||
for (int slotIndex = 0; slotIndex < Math.min(size(), this.rows * this.columns); slotIndex++) {
|
||||
this.gridMask.add(new HistoryGridSlot(slotIndex, slotIndex, getItem(slotIndex)));
|
||||
}
|
||||
}
|
||||
|
||||
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 (this.grid.size() > 0) {
|
||||
super.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.splittingLineColor = NEIClientConfig.getSetting("inventory.history.color").getHexValue();
|
||||
super.update();
|
||||
}
|
||||
|
||||
public void addItem(ItemStack stack) {
|
||||
if (stack != null) {
|
||||
ItemStack is = StackInfo.withAmount(stack, 0);
|
||||
|
||||
this.grid.realItems.removeIf(historyStack -> StackInfo.equalItemAndNBT(historyStack, stack, true));
|
||||
this.grid.realItems.add(0, is);
|
||||
|
||||
if (this.grid.realItems.size() > Math.max(50, this.grid.rows * this.grid.columns)) {
|
||||
this.grid.realItems.remove(this.grid.realItems.size() - 1);
|
||||
}
|
||||
|
||||
this.grid.onItemsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +1,24 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ForkJoinWorkerThread;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.IIcon;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
@@ -20,7 +28,8 @@ import codechicken.nei.ThreadOperationTimer.TimeoutException;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.recipe.InformationHandler;
|
||||
import codechicken.nei.search.TooltipFilter;
|
||||
|
||||
public class ItemList {
|
||||
|
||||
@@ -36,11 +45,11 @@ public class ItemList {
|
||||
* Updates to this should be synchronised on this
|
||||
*/
|
||||
public static final List<ItemFilterProvider> itemFilterers = new LinkedList<>();
|
||||
|
||||
public static final List<ItemsLoadedCallback> loadCallbacks = new LinkedList<>();
|
||||
|
||||
private static final HashSet<Item> erroredItems = new HashSet<>();
|
||||
private static final HashSet<String> stackTraces = new HashSet<>();
|
||||
private static Map<ItemStack, Integer> ordering = new HashMap<>();
|
||||
/**
|
||||
* Unlike {@link LayoutManager#itemsLoaded}, this indicates whether item loading is actually finished or not.
|
||||
*/
|
||||
@@ -62,6 +71,20 @@ public class ItemList {
|
||||
}
|
||||
}
|
||||
|
||||
public static class NegatedItemFilter implements ItemFilter {
|
||||
|
||||
public ItemFilter filter;
|
||||
|
||||
public NegatedItemFilter(ItemFilter filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(ItemStack item) {
|
||||
return this.filter == null || !this.filter.matches(item);
|
||||
}
|
||||
}
|
||||
|
||||
public static class PatternItemFilter implements ItemFilter {
|
||||
|
||||
public Pattern pattern;
|
||||
@@ -72,7 +95,20 @@ public class ItemList {
|
||||
|
||||
@Override
|
||||
public boolean matches(ItemStack item) {
|
||||
return pattern.matcher(ItemInfo.getSearchName(item)).find();
|
||||
String displayName = EnumChatFormatting.getTextWithoutFormattingCodes(item.getDisplayName());
|
||||
|
||||
if (displayName != null && !displayName.isEmpty() && this.pattern.matcher(displayName).find()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.hasDisplayName()) {
|
||||
displayName = EnumChatFormatting
|
||||
.getTextWithoutFormattingCodes(item.getItem().getItemStackDisplayName(item));
|
||||
|
||||
return displayName != null && !displayName.isEmpty() && this.pattern.matcher(displayName).find();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +120,10 @@ public class ItemList {
|
||||
this.filters = filters;
|
||||
}
|
||||
|
||||
public AllMultiItemFilter(ItemFilter... filters) {
|
||||
this(new LinkedList<>(Arrays.asList(filters)));
|
||||
}
|
||||
|
||||
public AllMultiItemFilter() {
|
||||
this(new LinkedList<>());
|
||||
}
|
||||
@@ -91,9 +131,10 @@ public class ItemList {
|
||||
@Override
|
||||
public boolean matches(ItemStack item) {
|
||||
for (ItemFilter filter : filters) try {
|
||||
if (!filter.matches(item)) return false;
|
||||
if (filter != null && !filter.matches(item)) return false;
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.error("Exception filtering " + item + " with " + filter, e);
|
||||
NEIClientConfig.logger
|
||||
.error("Exception filtering " + item + " with " + filter + " (" + e.getMessage() + ")", e);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -115,9 +156,10 @@ public class ItemList {
|
||||
@Override
|
||||
public boolean matches(ItemStack item) {
|
||||
for (ItemFilter filter : filters) try {
|
||||
if (filter.matches(item)) return true;
|
||||
if (filter != null && filter.matches(item)) return true;
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.error("Exception filtering " + item + " with " + filter, e);
|
||||
NEIClientConfig.logger
|
||||
.error("Exception filtering " + item + " with " + filter + " (" + e.getMessage() + ")", e);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -132,9 +174,10 @@ public class ItemList {
|
||||
public static boolean itemMatchesAll(ItemStack item, List<ItemFilter> filters) {
|
||||
for (ItemFilter filter : filters) {
|
||||
try {
|
||||
if (!filter.matches(item)) return false;
|
||||
if (filter != null && !filter.matches(item)) return false;
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.error("Exception filtering " + item + " with " + filter, e);
|
||||
NEIClientConfig.logger
|
||||
.error("Exception filtering " + item + " with " + filter + " (" + e.getMessage() + ")", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +199,9 @@ public class ItemList {
|
||||
public static List<ItemFilter> getItemFilters() {
|
||||
LinkedList<ItemFilter> filters = new LinkedList<>();
|
||||
synchronized (itemFilterers) {
|
||||
for (ItemFilterProvider p : itemFilterers) filters.add(p.getFilter());
|
||||
for (ItemFilterProvider p : itemFilterers) {
|
||||
filters.add(p.getFilter());
|
||||
}
|
||||
}
|
||||
return filters;
|
||||
}
|
||||
@@ -168,10 +213,9 @@ public class ItemList {
|
||||
for (int damage = 0; damage < 16; damage++) try {
|
||||
ItemStack itemstack = new ItemStack(item, 1, damage);
|
||||
IIcon icon = item.getIconIndex(itemstack);
|
||||
String name = GuiContainerManager.concatenatedDisplayName(itemstack, false);
|
||||
String name = getTooltip(itemstack);
|
||||
String s = name + "@" + (icon == null ? 0 : icon.hashCode());
|
||||
if (!damageIconSet.contains(s)) {
|
||||
damageIconSet.add(s);
|
||||
if (damageIconSet.add(s)) {
|
||||
permutations.add(itemstack);
|
||||
}
|
||||
} catch (TimeoutException t) {
|
||||
@@ -185,43 +229,127 @@ public class ItemList {
|
||||
}
|
||||
}
|
||||
|
||||
private String getTooltip(ItemStack stack) {
|
||||
try {
|
||||
return String.join("\n", stack.getTooltip(Minecraft.getMinecraft().thePlayer, false));
|
||||
} catch (Throwable ignored) {}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private void updateOrdering(List<ItemStack> items) {
|
||||
final Map<ItemStack, Integer> newOrdering = new HashMap<>();
|
||||
ItemSorter.sort(items);
|
||||
|
||||
if (!CollapsibleItems.isEmpty()) {
|
||||
final HashMap<Integer, Integer> groups = new HashMap<>();
|
||||
int orderIndex = 0;
|
||||
|
||||
for (ItemStack stack : items) {
|
||||
final int groupIndex = CollapsibleItems.getGroupIndex(stack);
|
||||
|
||||
if (groupIndex == -1) {
|
||||
newOrdering.put(stack, orderIndex++);
|
||||
} else {
|
||||
|
||||
if (!groups.containsKey(groupIndex)) {
|
||||
groups.put(groupIndex, orderIndex++);
|
||||
}
|
||||
|
||||
newOrdering.put(stack, groups.get(groupIndex));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int orderIndex = 0;
|
||||
|
||||
for (ItemStack stack : items) {
|
||||
newOrdering.put(stack, orderIndex++);
|
||||
}
|
||||
}
|
||||
|
||||
ItemList.ordering = newOrdering;
|
||||
}
|
||||
|
||||
private List<ItemStack> getPermutations(Item item) {
|
||||
final List<ItemStack> permutations = new LinkedList<>(ItemInfo.itemOverrides.get(item));
|
||||
|
||||
if (permutations.isEmpty()) {
|
||||
item.getSubItems(item, null, permutations);
|
||||
}
|
||||
|
||||
if (permutations.isEmpty()) {
|
||||
damageSearch(item, permutations);
|
||||
}
|
||||
|
||||
permutations.addAll(ItemInfo.itemVariants.get(item));
|
||||
|
||||
return permutations.stream()
|
||||
.filter(
|
||||
stack -> stack.getItem() != null && stack.getItem().delegate.name() != null
|
||||
&& !ItemInfo.isHidden(stack))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// Generate itemlist, permutations, orders, collapsibleitems, and informationhandler stacks
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void execute() {
|
||||
// System.out.println("Executing NEI Item Loading");
|
||||
if (!NEIClientConfig.isEnabled() || NEIClientUtils.mc().thePlayer == null) return;
|
||||
|
||||
ThreadOperationTimer timer = getTimer(NEIClientConfig.getItemLoadingTimeout());
|
||||
LayoutManager.itemsLoaded = true;
|
||||
loadFinished = false;
|
||||
|
||||
LinkedList<ItemStack> items = new LinkedList<>();
|
||||
LinkedList<ItemStack> permutations = new LinkedList<>();
|
||||
SearchField.searchParser.clearCache();
|
||||
ItemSorter.instance.ordering.clear();
|
||||
CollapsibleItems.clearCache();
|
||||
TooltipFilter.clearCache();
|
||||
InformationHandler.clearCache();
|
||||
|
||||
List<ItemStack> items = new ArrayList<>();
|
||||
ListMultimap<Item, ItemStack> itemMap = ArrayListMultimap.create();
|
||||
ItemStackSet unique = new ItemStackSet();
|
||||
|
||||
timer.setLimit(NEIClientConfig.getItemLoadingTimeout());
|
||||
for (Item item : (Iterable<Item>) Item.itemRegistry) {
|
||||
if (interrupted()) return;
|
||||
|
||||
if (item == null || erroredItems.contains(item)) continue;
|
||||
StreamSupport.stream(((Iterable<Item>) Item.itemRegistry).spliterator(), true).forEach(item -> {
|
||||
if (item == null || item.delegate.name() == null || erroredItems.contains(item)) return;
|
||||
|
||||
try {
|
||||
timer.reset(item);
|
||||
|
||||
permutations.clear();
|
||||
permutations.addAll(ItemInfo.itemOverrides.get(item));
|
||||
|
||||
if (permutations.isEmpty()) item.getSubItems(item, null, permutations);
|
||||
|
||||
if (permutations.isEmpty()) damageSearch(item, permutations);
|
||||
|
||||
permutations.addAll(ItemInfo.itemVariants.get(item));
|
||||
|
||||
List<ItemStack> permutations = getPermutations(item);
|
||||
timer.reset();
|
||||
|
||||
items.addAll(permutations);
|
||||
itemMap.putAll(item, permutations);
|
||||
for (ItemStack stack : permutations) {
|
||||
if (!unique.contains(stack)) {
|
||||
|
||||
synchronized (unique) {
|
||||
unique.add(stack);
|
||||
}
|
||||
|
||||
synchronized (items) {
|
||||
items.add(stack);
|
||||
}
|
||||
|
||||
CollapsibleItems.putItem(stack);
|
||||
TooltipFilter.getSearchTooltip(stack);
|
||||
InformationHandler.populateStacks(stack);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (itemMap) {
|
||||
itemMap.putAll(item, permutations);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
NEIServerConfig.logger.error("Removing item: " + item + " from list.", t);
|
||||
NEIServerConfig.logger.error("Removing item: {} from list.", item, t);
|
||||
erroredItems.add(item);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
int index = 0;
|
||||
for (Item item : (Iterable<Item>) Item.itemRegistry) {
|
||||
for (ItemStack stack : itemMap.get(item)) {
|
||||
ItemSorter.instance.ordering.put(stack, index++);
|
||||
}
|
||||
}
|
||||
|
||||
if (interrupted()) return;
|
||||
@@ -229,32 +357,48 @@ public class ItemList {
|
||||
ItemList.itemMap = itemMap;
|
||||
for (ItemsLoadedCallback callback : loadCallbacks) callback.itemsLoaded();
|
||||
|
||||
updateFilter.restart();
|
||||
if (interrupted()) return;
|
||||
updateOrdering(ItemList.items);
|
||||
|
||||
loadFinished = true;
|
||||
|
||||
SubsetWidget.updateHiddenItems();
|
||||
ItemPanels.bookmarkPanel.load();
|
||||
updateFilter.restart();
|
||||
}
|
||||
};
|
||||
|
||||
public static ForkJoinPool getPool(int poolSize) {
|
||||
public static ForkJoinPool forkJoinPool;
|
||||
|
||||
static {
|
||||
final ForkJoinPool.ForkJoinWorkerThreadFactory factory = new ForkJoinPool.ForkJoinWorkerThreadFactory() {
|
||||
|
||||
private int workerId;
|
||||
|
||||
@Override
|
||||
public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
|
||||
final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);
|
||||
worker.setName("NEI-worker-thread-" + workerId++);
|
||||
return worker;
|
||||
}
|
||||
};
|
||||
int poolSize = Runtime.getRuntime().availableProcessors() * 2 / 3;
|
||||
if (poolSize < 1) poolSize = 1;
|
||||
|
||||
return new ForkJoinPool(poolSize);
|
||||
forkJoinPool = new ForkJoinPool(poolSize, factory, null, false);
|
||||
}
|
||||
|
||||
public static final int numProcessors = Runtime.getRuntime().availableProcessors();
|
||||
public static ForkJoinPool forkJoinPool = getPool(numProcessors * 2 / 3);
|
||||
|
||||
public static final RestartableTask updateFilter = new RestartableTask("NEI Item Filtering") {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
// System.out.println("Executing NEI Item Filtering");
|
||||
ArrayList<ItemStack> filtered;
|
||||
|
||||
if (!loadFinished) return;
|
||||
ItemFilter filter = getItemListFilter();
|
||||
ArrayList<ItemStack> filtered;
|
||||
|
||||
try {
|
||||
filtered = ItemList.forkJoinPool.submit(
|
||||
() -> items.parallelStream().filter(PresetsWidget::matches).filter(filter::matches)
|
||||
() -> items.parallelStream().filter(filter::matches)
|
||||
.collect(Collectors.toCollection(ArrayList::new)))
|
||||
.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
@@ -264,8 +408,11 @@ public class ItemList {
|
||||
}
|
||||
|
||||
if (interrupted()) return;
|
||||
ItemSorter.sort(filtered);
|
||||
|
||||
filtered.sort(Comparator.comparingInt(ItemList.ordering::get));
|
||||
|
||||
if (interrupted()) return;
|
||||
|
||||
ItemPanel.updateItemList(filtered);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,32 +16,31 @@ import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntityMobSpawner;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.MinecraftForgeClient;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class ItemMobSpawner extends ItemBlock {
|
||||
|
||||
private static Map<Integer, EntityLiving> entityHashMap;
|
||||
private static Map<Integer, String> IDtoNameMap;
|
||||
private static final Map<Integer, EntityLiving> entityHashMap = new HashMap<>();
|
||||
private static final Map<Integer, String> IDtoNameMap = new HashMap<>();
|
||||
public static int idPig;
|
||||
private static boolean loaded;
|
||||
|
||||
public ItemMobSpawner() {
|
||||
super(Blocks.mob_spawner);
|
||||
|
||||
hasSubtypes = true;
|
||||
MinecraftForgeClient.registerItemRenderer(this, new SpawnerRenderer());
|
||||
|
||||
entityHashMap = new HashMap<>();
|
||||
IDtoNameMap = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* These are ASM translated from BlockMobSpawner
|
||||
*/
|
||||
public static int placedX;
|
||||
|
||||
public static int placedY;
|
||||
public static int placedZ;
|
||||
|
||||
@@ -68,23 +67,26 @@ public class ItemMobSpawner extends ItemBlock {
|
||||
return false;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
public void addInformation(ItemStack itemstack, EntityPlayer par2EntityPlayer, List list, boolean par4) {
|
||||
public void addInformation(ItemStack itemstack, EntityPlayer par2EntityPlayer, List<String> list, boolean par4) {
|
||||
setDefaultTag(itemstack);
|
||||
int meta = itemstack.getItemDamage();
|
||||
if (meta == 0) {
|
||||
meta = idPig;
|
||||
}
|
||||
Entity e = getEntity(meta);
|
||||
list.add("\u00A7" + (e instanceof IMob ? "4" : "3") + IDtoNameMap.get(meta));
|
||||
list.add(
|
||||
(e instanceof IMob ? EnumChatFormatting.DARK_RED : EnumChatFormatting.DARK_AQUA)
|
||||
+ IDtoNameMap.get(meta));
|
||||
}
|
||||
|
||||
public static EntityLiving getEntity(int ID) {
|
||||
EntityLiving e = entityHashMap.get(ID);
|
||||
if (e == null) {
|
||||
loadSpawners();
|
||||
Class<?> clazz = EntityList.IDtoClassMapping.get(ID);
|
||||
World world = NEIClientUtils.mc().theWorld;
|
||||
loadSpawners(world);
|
||||
Class<?> clazz = (Class<?>) EntityList.IDtoClassMapping.get(ID);
|
||||
try {
|
||||
e = (EntityLiving) clazz.getConstructor(new Class[] { World.class }).newInstance(world);
|
||||
} catch (Throwable t) {
|
||||
@@ -98,43 +100,35 @@ public class ItemMobSpawner extends ItemBlock {
|
||||
return e;
|
||||
}
|
||||
|
||||
public static void clearEntityReferences(World newWorld) {
|
||||
entityHashMap.values().removeIf(e -> e.worldObj != newWorld);
|
||||
public static void clearEntityReferences() {
|
||||
entityHashMap.clear();
|
||||
}
|
||||
|
||||
private void setDefaultTag(ItemStack itemstack) {
|
||||
if (!IDtoNameMap.containsKey(itemstack.getItemDamage())) itemstack.setItemDamage(idPig);
|
||||
}
|
||||
|
||||
public static void loadSpawners(World world) {
|
||||
public static void loadSpawners() {
|
||||
if (loaded) return;
|
||||
loaded = true;
|
||||
HashMap<Class<Entity>, String> classToStringMapping = (HashMap<Class<Entity>, String>) EntityList.classToStringMapping;
|
||||
HashMap<Class<Entity>, Integer> classToIDMapping = (HashMap<Class<Entity>, Integer>) EntityList.classToIDMapping;
|
||||
for (Class<Entity> eclass : classToStringMapping.keySet()) {
|
||||
if (!EntityLiving.class.isAssignableFrom(eclass)) continue;
|
||||
try {
|
||||
EntityLiving entityliving = (EntityLiving) eclass.getConstructor(new Class[] { World.class })
|
||||
.newInstance(world);
|
||||
entityliving.isChild();
|
||||
|
||||
int id = classToIDMapping.get(eclass);
|
||||
String name = classToStringMapping.get(eclass);
|
||||
|
||||
for (Map.Entry<Class<? extends Entity>, String> entry : EntityList.classToStringMapping.entrySet()) {
|
||||
final Class<? extends Entity> clazz = entry.getKey();
|
||||
if (EntityLiving.class.isAssignableFrom(clazz)) {
|
||||
Integer id = (Integer) EntityList.classToIDMapping.get(clazz);
|
||||
if (id == null) continue;
|
||||
String name = entry.getValue();
|
||||
if (name == null) continue;
|
||||
if (name.equals("EnderDragon")) continue;
|
||||
|
||||
IDtoNameMap.put(id, name);
|
||||
|
||||
if (name.equals("Pig")) idPig = id;
|
||||
} catch (Throwable ignored) {}
|
||||
if (clazz != EntityPig.class || name.equals("Pig")) {
|
||||
IDtoNameMap.put(id, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IDtoNameMap.entrySet()
|
||||
.removeIf(e -> getEntity(e.getKey()).getClass() == EntityPig.class && !e.getValue().equals("Pig"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getSubItems(Item item, CreativeTabs tab, List list) {
|
||||
public void getSubItems(Item item, CreativeTabs tab, List<ItemStack> list) {
|
||||
if (!NEIClientConfig.hasSMPCounterPart()) list.add(new ItemStack(item));
|
||||
else for (int i : IDtoNameMap.keySet()) list.add(new ItemStack(item, 1, i));
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import static codechicken.lib.gui.GuiDraw.drawRect;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.ItemsPanelGrid.ItemsPanelGridSlot;
|
||||
import codechicken.nei.util.NEIMouseUtils;
|
||||
|
||||
public class ItemPanel extends PanelWidget {
|
||||
public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
|
||||
|
||||
/**
|
||||
* Backwards compat :-/
|
||||
@@ -31,66 +32,50 @@ public class ItemPanel extends PanelWidget {
|
||||
return super.getStackMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
public Button more;
|
||||
public Button less;
|
||||
public ItemQuantityField quantity;
|
||||
public ItemHistoryPanel historyPanel = new ItemHistoryPanel();
|
||||
public ItemCraftablesPanel craftablesPanel = new ItemCraftablesPanel();
|
||||
protected Button toggleGroups;
|
||||
|
||||
public static class ItemPanelSlot {
|
||||
@Deprecated
|
||||
public static class ItemPanelSlot extends ItemsPanelGridSlot {
|
||||
|
||||
public ItemStack item;
|
||||
public int slotIndex;
|
||||
|
||||
public ItemPanelSlot(int idx, ItemStack stack) {
|
||||
slotIndex = idx;
|
||||
item = stack;
|
||||
@Deprecated
|
||||
public ItemPanelSlot(int idx, ItemStack item) {
|
||||
this(idx, 0, item);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public ItemPanelSlot(int idx) {
|
||||
this(idx, ItemPanels.itemPanel.getGrid().getItem(idx));
|
||||
}
|
||||
}
|
||||
|
||||
protected static class ItemPanelGrid extends ItemsGrid {
|
||||
|
||||
public ArrayList<ItemStack> newItems;
|
||||
|
||||
public void setItems(ArrayList<ItemStack> items) {
|
||||
newItems = items;
|
||||
this(idx, 0, ItemPanels.itemPanel.getGrid().getItem(idx));
|
||||
}
|
||||
|
||||
public void refresh(GuiContainer gui) {
|
||||
private ItemPanelSlot(int slotIndex, int itemIndex, ItemStack item) {
|
||||
super(slotIndex, itemIndex, item);
|
||||
}
|
||||
|
||||
if (newItems != null) {
|
||||
realItems = newItems;
|
||||
newItems = null;
|
||||
onGridChanged();
|
||||
protected static ItemPanelSlot of(ItemsPanelGridSlot slot) {
|
||||
|
||||
if (slot != null) {
|
||||
ItemPanelSlot customSlot = new ItemPanelSlot(slot.slotIndex, slot.itemIndex, slot.item);
|
||||
customSlot.groupIndex = slot.groupIndex;
|
||||
customSlot.displayName = slot.displayName;
|
||||
customSlot.bgItemStack = slot.bgItemStack;
|
||||
customSlot.groupSize = slot.groupSize;
|
||||
customSlot.extended = slot.extended;
|
||||
customSlot.bgColor = slot.bgColor;
|
||||
return customSlot;
|
||||
}
|
||||
|
||||
super.refresh(gui);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawSlotOutline(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {
|
||||
if (PresetsWidget.inEditMode()) {
|
||||
if (!PresetsWidget.isHidden(getItem(slotIdx))) drawRect(rect.x, rect.y, rect.w, rect.h, 0xee555555);
|
||||
} else {
|
||||
super.drawSlotOutline(focused, slotIdx, rect);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessageOnEmpty() {
|
||||
return ItemList.loadFinished ? null : NEIClientUtils.translate("itempanel.loading");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ItemPanel() {
|
||||
grid = new ItemPanelGrid();
|
||||
this.grid = new ItemsPanelGrid();
|
||||
}
|
||||
|
||||
public static void updateItemList(ArrayList<ItemStack> newItems) {
|
||||
((ItemPanelGrid) ItemPanels.itemPanel.getGrid()).setItems(newItems);
|
||||
ItemPanels.itemPanel.getGrid().setItems(newItems);
|
||||
ItemPanels.itemPanel.realItems = newItems;
|
||||
}
|
||||
|
||||
@@ -98,126 +83,193 @@ public class ItemPanel extends PanelWidget {
|
||||
public void init() {
|
||||
super.init();
|
||||
|
||||
more = new Button("+") {
|
||||
toggleGroups = new Button("G") {
|
||||
|
||||
@Override
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
if (rightclick) return false;
|
||||
|
||||
int modifier = NEIClientUtils.controlKey() ? 64 : NEIClientUtils.shiftKey() ? 10 : 1;
|
||||
int quantity = NEIClientConfig.getItemQuantity() + modifier;
|
||||
|
||||
if (quantity < 0) {
|
||||
quantity = 0;
|
||||
}
|
||||
|
||||
ItemPanels.itemPanel.quantity.setText(Integer.toString(quantity));
|
||||
return true;
|
||||
public String getRenderLabel() {
|
||||
return NEIClientUtils.translate("itempanel.collapsed.button");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getButtonTip() {
|
||||
return NEIClientUtils.translate("itempanel.collapsed.button.tip");
|
||||
}
|
||||
};
|
||||
less = new Button("-") {
|
||||
|
||||
@Override
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
if (rightclick) return false;
|
||||
|
||||
int modifier = NEIClientUtils.controlKey() ? -64 : NEIClientUtils.shiftKey() ? -10 : -1;
|
||||
int quantity = NEIClientConfig.getItemQuantity() + modifier;
|
||||
|
||||
if (quantity < 0) {
|
||||
quantity = 0;
|
||||
}
|
||||
|
||||
ItemPanels.itemPanel.quantity.setText(Integer.toString(quantity));
|
||||
CollapsibleItems.toggleGroups(rightclick ? false : null);
|
||||
ItemList.updateFilter.restart();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
quantity = new ItemQuantityField("quantity");
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void scroll(int i) {
|
||||
grid.shiftPage(i);
|
||||
@Override
|
||||
public ItemPanelSlot getSlotMouseOver(int mousex, int mousey) {
|
||||
// use ItemPanelSlot for Backwards compat
|
||||
return ItemPanelSlot.of(this.grid.getSlotMouseOver(mousex, mousey));
|
||||
}
|
||||
|
||||
public String getLabelText() {
|
||||
return String.format("(%d/%d)", getPage(), Math.max(1, getNumPages()));
|
||||
return String.format("%d/%d", getPage(), Math.max(1, getNumPages()));
|
||||
}
|
||||
|
||||
protected String getPositioningSettingName() {
|
||||
return "world.panels.items";
|
||||
public Rectangle4i calculateBounds() {
|
||||
final GuiContainer gui = NEIClientUtils.getGuiContainer();
|
||||
final int width = (gui.width - gui.xSize) / 2 - PADDING * 2;
|
||||
final Rectangle4i bounds = new Rectangle4i(
|
||||
(gui.width + gui.xSize) / 2 + PADDING,
|
||||
PADDING,
|
||||
(gui.width - 176) / 2 - PADDING * 2,
|
||||
gui.height - PADDING * 2);
|
||||
|
||||
int paddingLeft = (int) Math
|
||||
.ceil(bounds.w * NEIClientConfig.getSetting("world.panels.items.left").getIntValue() / 100000.0);
|
||||
int paddingTop = (int) Math
|
||||
.ceil(bounds.h * NEIClientConfig.getSetting("world.panels.items.top").getIntValue() / 100000.0);
|
||||
int paddingRight = (int) Math
|
||||
.ceil(bounds.w * NEIClientConfig.getSetting("world.panels.items.right").getIntValue() / 100000.0);
|
||||
int paddingBottom = (int) Math
|
||||
.ceil(bounds.h * NEIClientConfig.getSetting("world.panels.items.bottom").getIntValue() / 100000.0);
|
||||
|
||||
bounds.h = Math.max(ItemsGrid.SLOT_SIZE, bounds.h - paddingTop - paddingBottom);
|
||||
bounds.y = bounds.y + Math.min(paddingTop, bounds.h - ItemsGrid.SLOT_SIZE);
|
||||
|
||||
bounds.w = Math.max(ItemsGrid.SLOT_SIZE, Math.min(bounds.w - paddingLeft - paddingRight, width - paddingRight));
|
||||
bounds.x = bounds.x + Math.max(0, width - bounds.w - paddingRight);
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public int getMarginLeft(GuiContainer gui) {
|
||||
return (gui.width + gui.xSize) / 2 + PADDING;
|
||||
}
|
||||
@Override
|
||||
protected int resizeHeader(GuiContainer gui) {
|
||||
int marginTop = super.resizeHeader(gui);
|
||||
|
||||
public int getMarginTop(GuiContainer gui) {
|
||||
return PADDING;
|
||||
}
|
||||
toggleGroups.w = pageNext.w;
|
||||
toggleGroups.h = pageNext.h;
|
||||
toggleGroups.y = pageNext.y;
|
||||
toggleGroups.x = pageNext.x - toggleGroups.w - 2;
|
||||
|
||||
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 marginTop;
|
||||
}
|
||||
|
||||
protected int resizeFooter(GuiContainer gui) {
|
||||
if (!NEIClientConfig.showItemQuantityWidget() && NEIClientConfig.isSearchWidgetCentered()) return 0;
|
||||
int footerY = y + h;
|
||||
int footerHeight = 0;
|
||||
|
||||
final int BUTTON_SIZE = 20;
|
||||
more.w = less.w = BUTTON_SIZE;
|
||||
quantity.h = BUTTON_SIZE;
|
||||
|
||||
if (NEIClientConfig.isSearchWidgetCentered()) {
|
||||
more.h = less.h = BUTTON_SIZE;
|
||||
more.x = x + w - BUTTON_SIZE;
|
||||
more.y = less.y = quantity.y = y + h - BUTTON_SIZE;
|
||||
less.x = x;
|
||||
quantity.x = x + BUTTON_SIZE + 2;
|
||||
quantity.w = more.x - quantity.x - 2;
|
||||
} else {
|
||||
quantity.x = (int) (x + (w * 0.7)) + 3;
|
||||
quantity.y = y + h - BUTTON_SIZE;
|
||||
quantity.w = (int) ((w * 0.3) - BUTTON_SIZE - 1);
|
||||
|
||||
more.h = less.h = BUTTON_SIZE / 2;
|
||||
more.y = y + h - (more.h * 2);
|
||||
|
||||
less.x = more.x = quantity.x + quantity.w;
|
||||
less.y = more.y + more.h;
|
||||
if (grid.getPerPage() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return BUTTON_SIZE + 2;
|
||||
if (NEIClientConfig.showItemQuantityWidget() || !NEIClientConfig.isSearchWidgetCentered()) {
|
||||
footerY = LayoutManager.quantity.y;
|
||||
footerHeight = LayoutManager.quantity.h + PanelWidget.PADDING;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.showHistoryPanelWidget()) {
|
||||
historyPanel.x = x;
|
||||
|
||||
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 footerHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible() {
|
||||
super.setVisible();
|
||||
|
||||
if (grid.getPerPage() > 0 && NEIClientConfig.showItemQuantityWidget()) {
|
||||
LayoutManager.addWidget(more);
|
||||
LayoutManager.addWidget(less);
|
||||
LayoutManager.addWidget(quantity);
|
||||
}
|
||||
}
|
||||
if (grid.getPerPage() > 0) {
|
||||
|
||||
protected ItemStack getDraggedStackWithQuantity(int mouseDownSlot) {
|
||||
ItemStack stack = grid.getItem(mouseDownSlot);
|
||||
|
||||
if (stack != null) {
|
||||
int amount = NEIClientConfig.showItemQuantityWidget() ? NEIClientConfig.getItemQuantity() : 0;
|
||||
|
||||
if (amount == 0) {
|
||||
amount = stack.getMaxStackSize();
|
||||
if (!CollapsibleItems.isEmpty() && !grid.isEmpty()) {
|
||||
LayoutManager.addWidget(toggleGroups);
|
||||
}
|
||||
|
||||
return NEIServerUtils.copyStack(stack, amount);
|
||||
if (NEIClientConfig.showCraftablesPanelWidget()) {
|
||||
LayoutManager.addWidget(craftablesPanel);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.showHistoryPanelWidget()) {
|
||||
LayoutManager.addWidget(historyPanel);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(GuiContainer gui) {
|
||||
super.resize(gui);
|
||||
this.historyPanel.resize(gui);
|
||||
this.craftablesPanel.resize(gui);
|
||||
}
|
||||
|
||||
protected ItemStack getDraggedStackWithQuantity(ItemStack itemStack) {
|
||||
return ItemQuantityField.prepareStackWithQuantity(itemStack, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
|
||||
List<String> currenttip) {
|
||||
|
||||
if (!this.grid.forceExpand && !currenttip.isEmpty()) {
|
||||
final ItemsPanelGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (hoverSlot != null && hoverSlot.groupIndex >= 0
|
||||
&& NEIClientConfig.getBooleanSetting("inventory.collapsibleItems.customName")
|
||||
&& !hoverSlot.extended
|
||||
&& !"".equals(hoverSlot.displayName)) {
|
||||
currenttip.clear();
|
||||
currenttip.add(hoverSlot.displayName + GuiDraw.TOOLTIP_LINESPACE);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return super.handleItemTooltip(gui, itemstack, mousex, mousey, currenttip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleClick(int mousex, int mousey, int button) {
|
||||
|
||||
if (button == 0 && !this.grid.forceExpand && NEIClientUtils.altKey()) {
|
||||
final ItemsPanelGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (hoverSlot != null && hoverSlot.groupIndex >= 0) {
|
||||
CollapsibleItems.setExpanded(hoverSlot.groupIndex, !hoverSlot.extended);
|
||||
this.grid.setItems(this.grid.rawItems);
|
||||
NEIClientUtils.playClickSound();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.handleClick(mousex, mousey, button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
|
||||
final ItemsPanelGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (!this.grid.forceExpand && hoverSlot != null && hoverSlot.groupIndex >= 0 && hoverSlot.groupSize > 1) {
|
||||
final String message = hoverSlot.extended ? "itempanel.collapsed.hint.collapse"
|
||||
: "itempanel.collapsed.hint.expand";
|
||||
hotkeys.put(
|
||||
NEIClientUtils.getKeyName(NEIClientUtils.ALT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate(message, hoverSlot.groupSize));
|
||||
}
|
||||
|
||||
return hotkeys;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,11 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import static codechicken.nei.NEIClientUtils.translate;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
|
||||
public class ItemQuantityField extends TextField {
|
||||
|
||||
@@ -10,18 +15,84 @@ public class ItemQuantityField extends TextField {
|
||||
field.setDisabledTextColour(0xFF303030);
|
||||
}
|
||||
|
||||
public int intValue() {
|
||||
return intValue(text());
|
||||
@Override
|
||||
protected void initInternalTextField() {
|
||||
field = new FormattedTextField(Minecraft.getMinecraft().fontRenderer, 0, 0, 0, 0) {
|
||||
|
||||
{
|
||||
setPlaceholder(NEIClientUtils.translate("itempanel.quantity.default"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
String text = super.getText();
|
||||
return !isFocused() && "0".equals(text) ? "" : text;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean beforeWrite(String text) {
|
||||
if (text == null || text.isEmpty()) return true;
|
||||
try {
|
||||
return Integer.parseInt(text) >= 0;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean textboxKeyTyped(char keyChar, int keyID) {
|
||||
if (!isFocused()) return false;
|
||||
|
||||
if (super.textboxKeyTyped(keyChar, keyID)) {
|
||||
return true;
|
||||
} else if (keyID == Keyboard.KEY_DOWN) {
|
||||
setText(Integer.toString(Math.max(0, getInteger() - 1)));
|
||||
return true;
|
||||
} else if (keyID == Keyboard.KEY_UP) {
|
||||
setText(Integer.toString(getInteger() + 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private int getInteger() {
|
||||
try {
|
||||
return Math.max(0, Integer.parseInt(text()));
|
||||
} catch (NumberFormatException nfe) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
field.setMaxStringLength(maxSearchLength);
|
||||
field.setCursorPositionZero();
|
||||
}
|
||||
|
||||
public int intValue(String s) {
|
||||
private int getInteger() {
|
||||
try {
|
||||
return Math.max(0, Integer.parseInt(s));
|
||||
return Math.max(0, Integer.parseInt(text()));
|
||||
} catch (NumberFormatException nfe) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static ItemStack prepareStackWithQuantity(ItemStack stack, long amount) {
|
||||
if (stack == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (amount == 0) {
|
||||
amount = NEIClientConfig.showItemQuantityWidget() ? NEIClientConfig.getItemQuantity() : 0;
|
||||
|
||||
if (amount == 0) {
|
||||
amount = StackInfo.itemStackToNBT(stack).hasKey("gtFluidName") ? 144 : stack.getMaxStackSize();
|
||||
}
|
||||
}
|
||||
|
||||
return StackInfo.withAmount(stack, amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gainFocus() {
|
||||
if (text().equals("0")) {
|
||||
@@ -36,20 +107,22 @@ public class ItemQuantityField extends TextField {
|
||||
|
||||
@Override
|
||||
public void onTextChange(String oldText) {
|
||||
NEIClientUtils.setItemQuantity(intValue());
|
||||
NEIClientUtils.setItemQuantity(getInteger());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mousex, int mousey) {
|
||||
public boolean onMouseWheel(int i, int mx, int my) {
|
||||
if (!contains(mx, my)) return false;
|
||||
int multiplier = 1;
|
||||
|
||||
if (!focused() && intValue() == 0) {
|
||||
field.setText(translate("itempanel.quantity.default"));
|
||||
field.setEnabled(false);
|
||||
super.draw(mousex, mousey);
|
||||
field.setEnabled(true);
|
||||
field.setText("0");
|
||||
} else {
|
||||
super.draw(mousex, mousey);
|
||||
if (NEIClientUtils.shiftKey()) {
|
||||
multiplier = 10;
|
||||
} else if (NEIClientUtils.controlKey()) {
|
||||
multiplier = 64;
|
||||
}
|
||||
|
||||
setText(Integer.toString(Math.max(0, getInteger() + i * multiplier)));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,19 +4,19 @@ import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.StatCollector;
|
||||
|
||||
import codechicken.lib.config.ConfigTagParent;
|
||||
import codechicken.nei.ItemList.ItemsLoadedCallback;
|
||||
import codechicken.nei.api.API;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.config.GuiItemSorter;
|
||||
import codechicken.nei.config.OptionOpenGui;
|
||||
|
||||
public class ItemSorter implements Comparator<ItemStack>, ItemsLoadedCallback {
|
||||
public class ItemSorter implements Comparator<ItemStack> {
|
||||
|
||||
public static class SortEntry {
|
||||
|
||||
@@ -44,12 +44,10 @@ public class ItemSorter implements Comparator<ItemStack>, ItemsLoadedCallback {
|
||||
public static final ItemSorter instance = new ItemSorter();
|
||||
|
||||
// optimisations
|
||||
public HashMap<ItemStack, Integer> ordering = null;
|
||||
public Map<ItemStack, Integer> ordering = new HashMap<>();
|
||||
|
||||
public static void sort(ArrayList<ItemStack> items) {
|
||||
public static void sort(List<ItemStack> items) {
|
||||
try {
|
||||
// items = (ArrayList<ItemStack>)
|
||||
// items.parallelStream().sorted(instance).collect(Collectors.toList());
|
||||
items.sort(instance);
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.error("Exception sorting item list", e);
|
||||
@@ -65,14 +63,6 @@ public class ItemSorter implements Comparator<ItemStack>, ItemsLoadedCallback {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void itemsLoaded() {
|
||||
HashMap<ItemStack, Integer> newMap = new HashMap<>();
|
||||
int i = 0;
|
||||
for (ItemStack stack : ItemList.items) newMap.put(stack, i++);
|
||||
ordering = newMap;
|
||||
}
|
||||
|
||||
public static SortEntry find(String name) {
|
||||
for (SortEntry e : entries) if (e.name.equals(name)) return e;
|
||||
|
||||
@@ -123,8 +113,8 @@ public class ItemSorter implements Comparator<ItemStack>, ItemsLoadedCallback {
|
||||
return compareInt(id1, id2);
|
||||
});
|
||||
API.addSortOption("nei.itemsort.name", (o1, o2) -> {
|
||||
String name1 = ItemInfo.getSearchName(o1);
|
||||
String name2 = ItemInfo.getSearchName(o2);
|
||||
String name1 = o1.getDisplayName();
|
||||
String name2 = o2.getDisplayName();
|
||||
return name1.compareTo(name2);
|
||||
});
|
||||
tag.getTag("inventory.itemsort").setDefaultValue(getSaveString(list));
|
||||
@@ -136,7 +126,6 @@ public class ItemSorter implements Comparator<ItemStack>, ItemsLoadedCallback {
|
||||
list = fromSaveString(activeTag().getValue());
|
||||
}
|
||||
});
|
||||
ItemList.loadCallbacks.add(instance);
|
||||
}
|
||||
|
||||
public static String getSaveString(List<SortEntry> list) {
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
|
||||
public class ItemStackAmount {
|
||||
|
||||
private final Map<NBTTagCompound, Long> itemMap = new LinkedHashMap<>();
|
||||
|
||||
public void putAll(ItemStackAmount amounts) {
|
||||
for (Map.Entry<NBTTagCompound, Long> entry : amounts.itemMap.entrySet()) {
|
||||
this.itemMap.put(entry.getKey(), entry.getValue() + this.itemMap.getOrDefault(entry.getKey(), 0L));
|
||||
}
|
||||
}
|
||||
|
||||
public void addAll(Iterable<ItemStack> items) {
|
||||
for (ItemStack stack : items) {
|
||||
add(stack);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(ItemStack item) {
|
||||
add(item, (long) StackInfo.getAmount(item));
|
||||
}
|
||||
|
||||
public void add(ItemStack stack, Long value) {
|
||||
if (stack == null || stack.getItem() == null) return;
|
||||
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
|
||||
|
||||
if (key != null) {
|
||||
this.itemMap.put(key, value + this.itemMap.getOrDefault(key, 0L));
|
||||
}
|
||||
}
|
||||
|
||||
public Long get(ItemStack stack) {
|
||||
if (stack == null || stack.getItem() == null) return null;
|
||||
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
|
||||
|
||||
return this.itemMap.get(key);
|
||||
}
|
||||
|
||||
public void put(ItemStack stack, long value) {
|
||||
if (stack == null || stack.getItem() == null) return;
|
||||
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
|
||||
|
||||
if (key != null) {
|
||||
this.itemMap.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public long getOrDefault(ItemStack stack, long defaultAmount) {
|
||||
final Long e = get(stack);
|
||||
|
||||
return e == null ? defaultAmount : e;
|
||||
}
|
||||
|
||||
public boolean contains(ItemStack stack) {
|
||||
return get(stack) != null;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.itemMap.clear();
|
||||
}
|
||||
|
||||
public Long remove(ItemStack stack) {
|
||||
if (stack == null || stack.getItem() == null) return null;
|
||||
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
|
||||
|
||||
return this.itemMap.remove(key);
|
||||
}
|
||||
|
||||
public boolean removeIf(Predicate<Map.Entry<NBTTagCompound, Long>> predicate) {
|
||||
return this.itemMap.entrySet().removeIf(predicate);
|
||||
}
|
||||
|
||||
public Set<Map.Entry<NBTTagCompound, Long>> entrySet() {
|
||||
return this.itemMap.entrySet();
|
||||
}
|
||||
|
||||
public List<ItemStack> values() {
|
||||
List<ItemStack> list = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<NBTTagCompound, Long> entry : this.itemMap.entrySet()) {
|
||||
list.add(StackInfo.loadFromNBT(entry.getKey(), Math.max(0, entry.getValue())));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.itemMap.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return this.itemMap.isEmpty();
|
||||
}
|
||||
|
||||
@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);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ItemStackAmount of(ItemStackMap<Long> map) {
|
||||
ItemStackAmount result = new ItemStackAmount();
|
||||
|
||||
for (ItemStackMap.Entry<Long> entry : map.entries()) {
|
||||
result.put(entry.key, entry.value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ItemStackAmount of(Iterable<ItemStack> items) {
|
||||
ItemStackAmount result = new ItemStackAmount();
|
||||
|
||||
for (ItemStack stack : items) {
|
||||
result.add(stack);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,9 +5,11 @@ import static codechicken.lib.inventory.InventoryUtils.newItemStack;
|
||||
import static net.minecraftforge.oredict.OreDictionary.WILDCARD_VALUE;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -24,8 +26,13 @@ public class ItemStackMap<T> {
|
||||
|
||||
public final int damage;
|
||||
public final NBTTagCompound tag;
|
||||
private final int hashCode;
|
||||
|
||||
public StackMetaKey(int damage, NBTTagCompound tag) {
|
||||
if (tag != null && tag.hasNoTags()) {
|
||||
tag = null;
|
||||
}
|
||||
this.hashCode = Objects.hashCode(damage, tag);
|
||||
this.damage = damage;
|
||||
this.tag = tag;
|
||||
}
|
||||
@@ -35,7 +42,7 @@ public class ItemStackMap<T> {
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(damage, tag);
|
||||
return this.hashCode;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
@@ -191,7 +198,7 @@ public class ItemStackMap<T> {
|
||||
WILDCARD_TAG.setBoolean("*", true);
|
||||
}
|
||||
|
||||
private final HashMap<Item, DetailMap> itemMap = new HashMap<>();
|
||||
private final Map<Item, DetailMap> itemMap = new LinkedHashMap<>();
|
||||
private int size;
|
||||
|
||||
public T get(ItemStack key) {
|
||||
@@ -203,6 +210,11 @@ public class ItemStackMap<T> {
|
||||
return map == null ? null : map.get(key);
|
||||
}
|
||||
|
||||
public T getOrDefault(ItemStack key, T defaultValue) {
|
||||
T e = get(key);
|
||||
return e == null ? defaultValue : e;
|
||||
}
|
||||
|
||||
public void put(ItemStack key, T value) {
|
||||
if (key == null || key.getItem() == null) return;
|
||||
|
||||
@@ -211,8 +223,22 @@ public class ItemStackMap<T> {
|
||||
map.put(key, value);
|
||||
}
|
||||
|
||||
public T computeIfAbsent(ItemStack key, Function<ItemStack, ? extends T> mappingFunction) {
|
||||
T value;
|
||||
if ((value = get(key)) == null) {
|
||||
T newValue;
|
||||
if ((newValue = mappingFunction.apply(key)) != null) {
|
||||
put(key, newValue);
|
||||
return newValue;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
itemMap.clear();
|
||||
size = 0;
|
||||
}
|
||||
|
||||
public T remove(ItemStack key) {
|
||||
|
||||
@@ -27,6 +27,16 @@ public class ItemStackSet extends ItemStackMap<ItemStack> implements ItemFilter
|
||||
put(item, item);
|
||||
}
|
||||
|
||||
public ItemStackSet addAll(Iterable<ItemStack> items) {
|
||||
for (ItemStack item : items) add(item);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStackSet removeAll(Iterable<ItemStack> items) {
|
||||
for (ItemStack item : items) remove(item);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean contains(ItemStack item) {
|
||||
return get(item) != null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.guihook.IContainerInputHandler;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
|
||||
public class ItemZoom extends Widget implements IContainerInputHandler {
|
||||
|
||||
public static final int MIN_ZOOM = 0;
|
||||
public static final int MAX_ZOOM = 1000;
|
||||
|
||||
private static final int MIN_SCALE = 2;
|
||||
private static final int SLOT_SIZE = 16;
|
||||
|
||||
private Boolean previousKeyboardRepeatEnabled = null;
|
||||
|
||||
private ItemStack stack = null;
|
||||
private String displayName = "";
|
||||
private int availableAreaWidth = 0;
|
||||
private float xPosition = 0;
|
||||
private float yPosition = 0;
|
||||
private float scale = 1;
|
||||
|
||||
public ItemZoom() {
|
||||
GuiContainerManager.addInputHandler(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mx, int my) {
|
||||
|
||||
if (this.stack != null && this.availableAreaWidth >= SLOT_SIZE * 2
|
||||
&& (NEIClientConfig.getBooleanSetting("inventory.itemzoom.enabled")
|
||||
|| NEIClientConfig.isKeyHashDown("gui.itemzoom_hold"))
|
||||
&& GuiContainerManager.shouldShowTooltip(NEIClientUtils.getGuiContainer())) {
|
||||
final float inverseScaleFactor = 1.0f / this.scale;
|
||||
final float screenScale = getScreenScale();
|
||||
final float size = SLOT_SIZE * this.scale;
|
||||
int shiftText = 10;
|
||||
|
||||
GL11.glPushMatrix();
|
||||
GL11.glScaled(screenScale, screenScale, 1);
|
||||
GL11.glScaled(this.scale, this.scale, 2);
|
||||
GL11.glTranslated(this.xPosition * inverseScaleFactor, this.yPosition * inverseScaleFactor, 0);
|
||||
|
||||
GuiContainerManager.drawItem(0, 0, this.stack, false, "");
|
||||
|
||||
GL11.glPopMatrix();
|
||||
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
GuiContainerManager.enable2DRender();
|
||||
|
||||
if (NEIClientConfig.getBooleanSetting("inventory.itemzoom.showName")) {
|
||||
String dispalyName = NEIClientUtils
|
||||
.cropText(GuiDraw.fontRenderer, this.displayName, this.availableAreaWidth);
|
||||
GuiDraw.drawStringC(
|
||||
dispalyName,
|
||||
(int) ((this.xPosition + size / 2) * screenScale),
|
||||
(int) ((this.yPosition + size) * screenScale) + shiftText,
|
||||
NEIClientConfig.getSetting("inventory.itemzoom.nameColor").getHexValue());
|
||||
shiftText += GuiDraw.fontRenderer.FONT_HEIGHT;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.getBooleanSetting("inventory.itemzoom.enabled")
|
||||
&& NEIClientConfig.getBooleanSetting("inventory.itemzoom.helpText")) {
|
||||
String keyName = NEIClientConfig.getKeyName("gui.itemzoom_toggle");
|
||||
|
||||
if (keyName != null) {
|
||||
String helpText = NEIClientUtils.translate("itemzoom.toggle", keyName);
|
||||
List<String> lines = GuiDraw.fontRenderer
|
||||
.listFormattedStringToWidth(helpText, this.availableAreaWidth);
|
||||
|
||||
for (String line : lines) {
|
||||
GuiDraw.drawStringC(
|
||||
line,
|
||||
(int) ((this.xPosition + size / 2) * screenScale),
|
||||
(int) ((this.yPosition + size) * screenScale) + 10 + shiftText,
|
||||
0x66555555);
|
||||
shiftText += GuiDraw.fontRenderer.FONT_HEIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GL11.glPopAttrib();
|
||||
}
|
||||
}
|
||||
|
||||
public void resize(GuiContainer gui) {
|
||||
final ItemStack stack = getStackMouseOver(gui);
|
||||
|
||||
if (stack != null && (!NEIClientConfig.getBooleanSetting("inventory.itemzoom.onlySolid")
|
||||
|| Block.getBlockFromItem(stack.getItem()).getMaterial().isSolid())) {
|
||||
final float screenScale = 1.0f / getScreenScale();
|
||||
final float availableAreaWidth = (gui.width - gui.xSize) / 2 * screenScale;
|
||||
final float availableAreaHeight = gui.height * screenScale;
|
||||
final Point mouse = GuiDraw.getMousePosition();
|
||||
|
||||
this.scale = Math.round(getZoomAmount(gui) * getPointSize(gui) / SLOT_SIZE);
|
||||
this.yPosition = (availableAreaHeight - this.scale * SLOT_SIZE) / 2;
|
||||
this.xPosition = (availableAreaWidth - this.scale * SLOT_SIZE) / 2;
|
||||
this.availableAreaWidth = (int) (availableAreaWidth / screenScale);
|
||||
|
||||
if (availableAreaWidth / screenScale >= mouse.x) {
|
||||
this.xPosition += gui.width * screenScale - availableAreaWidth;
|
||||
}
|
||||
|
||||
try {
|
||||
this.displayName = stack.getDisplayName();
|
||||
} catch (Throwable ignored) {
|
||||
this.displayName = "Unnamed";
|
||||
}
|
||||
|
||||
this.stack = StackInfo.loadFromNBT(StackInfo.itemStackToNBT(stack), 0);
|
||||
} else {
|
||||
this.stack = null;
|
||||
this.displayName = "";
|
||||
}
|
||||
}
|
||||
|
||||
private float getPointSize(GuiContainer gui) {
|
||||
final float screenScale = 1.0f / getScreenScale();
|
||||
final float availableAreaWidth = (gui.width - (gui.xSize + gui.width) / 2) * screenScale;
|
||||
return availableAreaWidth / MAX_ZOOM;
|
||||
}
|
||||
|
||||
private float getScreenScale() {
|
||||
return Minecraft.getMinecraft().currentScreen.width * 1f / Minecraft.getMinecraft().displayWidth;
|
||||
}
|
||||
|
||||
private int getZoomAmount(GuiContainer gui) {
|
||||
return Math.max(
|
||||
Math.round(SLOT_SIZE * MIN_SCALE / getPointSize(gui)),
|
||||
NEIClientConfig.getIntSetting("inventory.itemzoom.zoom"));
|
||||
}
|
||||
|
||||
private void increaseZoom(GuiContainer gui) {
|
||||
final float pointSize = getPointSize(gui);
|
||||
final float scale = Math.round(getZoomAmount(gui) * pointSize / SLOT_SIZE);
|
||||
|
||||
NEIClientConfig.setIntSetting(
|
||||
"inventory.itemzoom.zoom",
|
||||
Math.min(MAX_ZOOM, Math.round((scale + 1) / (pointSize / SLOT_SIZE))));
|
||||
}
|
||||
|
||||
private void decreaseZoom(GuiContainer gui) {
|
||||
final float pointSize = getPointSize(gui);
|
||||
final float scale = Math.round(getZoomAmount(gui) * pointSize / SLOT_SIZE);
|
||||
|
||||
NEIClientConfig.setIntSetting(
|
||||
"inventory.itemzoom.zoom",
|
||||
Math.max(MIN_ZOOM, Math.round(Math.max(MIN_SCALE, scale - 1) / (pointSize / SLOT_SIZE))));
|
||||
}
|
||||
|
||||
private ItemStack getStackMouseOver(GuiContainer gui) {
|
||||
|
||||
if (NEIClientConfig.getBooleanSetting("inventory.itemzoom.neiOnly")) {
|
||||
final Point mouse = GuiDraw.getMousePosition();
|
||||
ItemStack stack = ItemPanels.itemPanel.getStackMouseOver(mouse.x, mouse.y);
|
||||
|
||||
if (stack == null) {
|
||||
stack = ItemPanels.bookmarkPanel.getStackMouseOver(mouse.x, mouse.y);
|
||||
}
|
||||
|
||||
if (stack == null) {
|
||||
stack = ItemPanels.itemPanel.historyPanel.getStackMouseOver(mouse.x, mouse.y);
|
||||
}
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
return GuiContainerManager.getStackMouseOver(gui);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyTyped(GuiContainer gui, char keyChar, int keyCode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKeyTyped(GuiContainer gui, char keyChar, int keyID) {}
|
||||
|
||||
@Override
|
||||
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.itemzoom_toggle")) {
|
||||
NEIClientConfig.getSetting("inventory.itemzoom.enabled")
|
||||
.setBooleanValue(!NEIClientConfig.getBooleanSetting("inventory.itemzoom.enabled"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.stack != null && NEIClientConfig.isKeyHashDown("gui.itemzoom_hold")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.stack != null && NEIClientConfig.isKeyHashDown("gui.itemzoom_zoom_in")) {
|
||||
increaseZoom(gui);
|
||||
previousKeyboardRepeatEnabled = Keyboard.areRepeatEventsEnabled();
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.stack != null && NEIClientConfig.isKeyHashDown("gui.itemzoom_zoom_out")) {
|
||||
decreaseZoom(gui);
|
||||
previousKeyboardRepeatEnabled = Keyboard.areRepeatEventsEnabled();
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (previousKeyboardRepeatEnabled != null) {
|
||||
Keyboard.enableRepeatEvents(previousKeyboardRepeatEnabled);
|
||||
previousKeyboardRepeatEnabled = null;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {}
|
||||
|
||||
@Override
|
||||
public void onMouseUp(GuiContainer gui, int mousex, int mousey, int button) {}
|
||||
|
||||
@Override
|
||||
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {}
|
||||
|
||||
@Override
|
||||
public void onMouseDragged(GuiContainer gui, int mousex, int mousey, int button, long heldTime) {}
|
||||
|
||||
}
|
||||
@@ -1,40 +1,267 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import static codechicken.lib.gui.GuiDraw.drawRect;
|
||||
import static codechicken.lib.gui.GuiDraw.getMousePosition;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.shader.Framebuffer;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.ItemPanel.ItemPanelSlot;
|
||||
import codechicken.nei.api.GuiInfo;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.recipe.BookmarkRecipeId;
|
||||
import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
|
||||
public class ItemsGrid {
|
||||
public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends ItemsGrid.MouseContext> {
|
||||
|
||||
public static final int SLOT_SIZE = 18;
|
||||
protected static class ScreenCapture {
|
||||
|
||||
private long nextCacheRefresh = 0;
|
||||
private Framebuffer framebuffer;
|
||||
|
||||
public ScreenCapture() {
|
||||
this.framebuffer = new Framebuffer(1, 1, true);
|
||||
this.framebuffer.setFramebufferColor(0.0F, 0.0F, 0.0F, 0.0F);
|
||||
Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
|
||||
}
|
||||
|
||||
protected int getGridRenderingCacheFPS(int mode) {
|
||||
return mode == 1 ? NEIClientConfig.getIntSetting("inventory.gridRenderingCacheFPS") : 0;
|
||||
}
|
||||
|
||||
public boolean needRefresh(int mode) {
|
||||
final Minecraft minecraft = Minecraft.getMinecraft();
|
||||
return this.nextCacheRefresh == 0 || this.framebuffer.framebufferWidth != minecraft.displayWidth
|
||||
|| framebuffer.framebufferHeight != minecraft.displayHeight
|
||||
|| getGridRenderingCacheFPS(mode) > 0 && this.nextCacheRefresh < System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void refreshBuffer() {
|
||||
this.nextCacheRefresh = 0;
|
||||
}
|
||||
|
||||
public void captureScreen(Runnable callback, int mode) {
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
|
||||
resetFramebuffer();
|
||||
this.framebuffer.bindFramebuffer(false);
|
||||
|
||||
/* Set up some rendering state needed for items to work correctly */
|
||||
GL11.glDisable(GL11.GL_BLEND);
|
||||
GL11.glDepthMask(true);
|
||||
OpenGlHelper.glBlendFunc(
|
||||
GL11.GL_SRC_ALPHA,
|
||||
GL11.GL_ONE_MINUS_SRC_ALPHA,
|
||||
GL11.GL_SRC_ALPHA,
|
||||
GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
|
||||
callback.run();
|
||||
|
||||
GL11.glPopAttrib();
|
||||
|
||||
Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
|
||||
this.nextCacheRefresh = System.currentTimeMillis() + (1000 / Math.max(1, getGridRenderingCacheFPS(mode)));
|
||||
}
|
||||
|
||||
private void resetFramebuffer() {
|
||||
final Minecraft minecraft = Minecraft.getMinecraft();
|
||||
|
||||
if (this.framebuffer.framebufferWidth != minecraft.displayWidth
|
||||
|| framebuffer.framebufferHeight != minecraft.displayHeight) {
|
||||
this.framebuffer.createBindFramebuffer(minecraft.displayWidth, minecraft.displayHeight);
|
||||
this.framebuffer.setFramebufferFilter(GL11.GL_NEAREST);
|
||||
} else {
|
||||
this.framebuffer.framebufferClear();
|
||||
}
|
||||
|
||||
// copy depth buffer from MC (fix Angelica)
|
||||
OpenGlHelper.func_153171_g(GL30.GL_READ_FRAMEBUFFER, minecraft.getFramebuffer().framebufferObject);
|
||||
OpenGlHelper.func_153171_g(GL30.GL_DRAW_FRAMEBUFFER, this.framebuffer.framebufferObject);
|
||||
GL30.glBlitFramebuffer(
|
||||
0,
|
||||
0,
|
||||
minecraft.displayWidth,
|
||||
minecraft.displayHeight,
|
||||
0,
|
||||
0,
|
||||
minecraft.displayWidth,
|
||||
minecraft.displayHeight,
|
||||
GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT,
|
||||
GL11.GL_NEAREST);
|
||||
}
|
||||
|
||||
public void renderCapturedScreen() {
|
||||
this.framebuffer.bindFramebufferTexture();
|
||||
|
||||
final Tessellator tessellator = Tessellator.instance;
|
||||
final Minecraft minecraft = Minecraft.getMinecraft();
|
||||
final ScaledResolution scaledresolution = new ScaledResolution(
|
||||
minecraft,
|
||||
minecraft.displayWidth,
|
||||
minecraft.displayHeight);
|
||||
|
||||
/* Set up some rendering state needed for items to work correctly */
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
OpenGlHelper
|
||||
.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
|
||||
tessellator.startDrawingQuads();
|
||||
|
||||
tessellator.addVertexWithUV(0, scaledresolution.getScaledHeight_double(), 0.0, 0, 0);
|
||||
tessellator.addVertexWithUV(
|
||||
scaledresolution.getScaledWidth_double(),
|
||||
scaledresolution.getScaledHeight_double(),
|
||||
0.0,
|
||||
1,
|
||||
0);
|
||||
tessellator.addVertexWithUV(scaledresolution.getScaledWidth_double(), 0, 0.0, 1, 1);
|
||||
tessellator.addVertexWithUV(0, 0, 0, 0, 1);
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
this.framebuffer.unbindFramebufferTexture();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class ItemsGridSlot {
|
||||
|
||||
protected static final float DEFAULT_SLOT_SIZE = 18f;
|
||||
protected static final float LINE_WIDTH = 0.75f;
|
||||
|
||||
public final ItemStack item;
|
||||
public final int slotIndex;
|
||||
public final int itemIndex;
|
||||
|
||||
public Color borderColor = Color.BLACK;
|
||||
|
||||
public boolean borderLeft = false;
|
||||
public boolean borderTop = false;
|
||||
public boolean borderRight = false;
|
||||
public boolean borderBottom = false;
|
||||
|
||||
public ItemsGridSlot(int slotIndex, int itemIndex, ItemStack itemStack) {
|
||||
this.slotIndex = slotIndex;
|
||||
this.itemIndex = itemIndex;
|
||||
this.item = itemStack;
|
||||
}
|
||||
|
||||
public ItemStack getItemStack() {
|
||||
return this.item;
|
||||
}
|
||||
|
||||
public <M extends MouseContext> void beforeDraw(Rectangle4i rect, M mouseContext) {
|
||||
if (mouseContext != null && mouseContext.slotIndex == this.slotIndex) {
|
||||
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, HIGHLIGHT_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
public <M extends MouseContext> void afterDraw(Rectangle4i rect, M mouseContext) {}
|
||||
|
||||
public RecipeId getRecipeId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void drawItem(Rectangle4i rect) {
|
||||
drawItem(getItemStack(), rect);
|
||||
}
|
||||
|
||||
protected void drawItem(ItemStack stack, Rectangle4i rect) {
|
||||
|
||||
if (rect.w != DEFAULT_SLOT_SIZE) {
|
||||
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
|
||||
GL11.glTranslatef(rect.x + 1, rect.y + 1, 0);
|
||||
GL11.glScaled(panelFactor, panelFactor, 1);
|
||||
|
||||
GuiContainerManager.drawItem(0, 0, stack, true, "");
|
||||
|
||||
GL11.glScaled(1f / panelFactor, 1f / panelFactor, 1);
|
||||
GL11.glTranslatef(-1 * (rect.x + 1), -1 * (rect.y + 1), 0);
|
||||
} else {
|
||||
GuiContainerManager.drawItem(rect.x + 1, rect.y + 1, stack, true, "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void drawBorder(Rectangle4i rect) {
|
||||
float halfLineWidth = LINE_WIDTH / 2f;
|
||||
|
||||
if (this.borderLeft) {
|
||||
NEIClientUtils
|
||||
.drawRect(rect.x - halfLineWidth, rect.y + halfLineWidth, LINE_WIDTH, rect.h, this.borderColor);
|
||||
}
|
||||
|
||||
if (this.borderRight) {
|
||||
NEIClientUtils.drawRect(
|
||||
rect.x + rect.w - halfLineWidth,
|
||||
rect.y - halfLineWidth,
|
||||
LINE_WIDTH,
|
||||
rect.h,
|
||||
this.borderColor);
|
||||
}
|
||||
|
||||
if (this.borderTop) {
|
||||
NEIClientUtils
|
||||
.drawRect(rect.x - halfLineWidth, rect.y - halfLineWidth, rect.w, LINE_WIDTH, this.borderColor);
|
||||
}
|
||||
|
||||
if (this.borderBottom) {
|
||||
NEIClientUtils.drawRect(
|
||||
rect.x + halfLineWidth,
|
||||
rect.y + rect.h - halfLineWidth,
|
||||
rect.w,
|
||||
LINE_WIDTH,
|
||||
this.borderColor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class MouseContext {
|
||||
|
||||
public final int slotIndex;
|
||||
public final int columnIndex;
|
||||
public final int rowIndex;
|
||||
|
||||
public MouseContext(int slotIndex, int rowIndex, int columnIndex) {
|
||||
this.slotIndex = slotIndex;
|
||||
this.rowIndex = rowIndex;
|
||||
this.columnIndex = columnIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.rowIndex, this.slotIndex, this.columnIndex);
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (obj instanceof MouseContext context) {
|
||||
return this.columnIndex == context.columnIndex && this.rowIndex == context.rowIndex
|
||||
&& this.slotIndex == context.slotIndex;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static int SLOT_SIZE = 18;
|
||||
public static final Color HIGHLIGHT_COLOR = new Color(0xee555555, true);
|
||||
|
||||
protected int width;
|
||||
protected int height;
|
||||
@@ -51,33 +278,33 @@ public class ItemsGrid {
|
||||
|
||||
protected int rows;
|
||||
protected int columns;
|
||||
protected boolean showRecipeTooltips = false;
|
||||
|
||||
protected boolean[] invalidSlotMap;
|
||||
|
||||
protected Label messageLabel = new Label(getMessageOnEmpty(), true);
|
||||
|
||||
@Nullable
|
||||
private Framebuffer framebuffer = null;
|
||||
|
||||
protected boolean refreshBuffer = true;
|
||||
protected ScreenCapture screenCapture = null;
|
||||
|
||||
public ArrayList<ItemStack> getItems() {
|
||||
return realItems;
|
||||
}
|
||||
|
||||
public ItemStack getItem(int idx) {
|
||||
return realItems.get(idx);
|
||||
public ItemStack getItem(int itemIndex) {
|
||||
return realItems.get(itemIndex);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return realItems.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return realItems.isEmpty();
|
||||
}
|
||||
|
||||
public int indexOf(ItemStack stackA, boolean useNBT) {
|
||||
|
||||
for (int idx = 0; idx < realItems.size(); idx++) {
|
||||
if (StackInfo.equalItemAndNBT(stackA, getItem(idx), useNBT)) {
|
||||
if (StackInfo.equalItemAndNBT(stackA, realItems.get(idx), useNBT)) {
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
@@ -114,6 +341,14 @@ public class ItemsGrid {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public int getLastRowIndex() {
|
||||
final List<T> mask = getMask();
|
||||
|
||||
return this.columns > 0 && !mask.isEmpty()
|
||||
? (int) Math.ceil((float) (mask.get(mask.size() - 1).slotIndex + 1) / this.columns) - 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
public void setGridSize(int mleft, int mtop, int w, int h) {
|
||||
marginLeft = mleft;
|
||||
marginTop = mtop;
|
||||
@@ -156,11 +391,13 @@ public class ItemsGrid {
|
||||
}
|
||||
|
||||
protected void onGridChanged() {
|
||||
refreshBuffer = true;
|
||||
if (this.screenCapture != null) {
|
||||
this.screenCapture.refreshBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
public void setShowRecipeTooltips(boolean show) {
|
||||
this.showRecipeTooltips = show;
|
||||
public void onItemsChanged() {
|
||||
onGridChanged();
|
||||
}
|
||||
|
||||
public void refresh(GuiContainer gui) {
|
||||
@@ -176,11 +413,13 @@ public class ItemsGrid {
|
||||
invalidSlotMap = new boolean[rows * columns];
|
||||
perPage = columns * rows;
|
||||
|
||||
if (NEIClientConfig.optimizeGuiOverlapComputation()) {
|
||||
checkGuiOverlap(gui, 0, columns - 2, 1);
|
||||
checkGuiOverlap(gui, columns - 1, 1, -1);
|
||||
} else {
|
||||
checkGuiOverlap(gui, 0, columns, 1);
|
||||
if (gui != null) {
|
||||
if (NEIClientConfig.optimizeGuiOverlapComputation()) {
|
||||
checkGuiOverlap(gui, 0, columns - 2, 1);
|
||||
checkGuiOverlap(gui, columns - 1, 1, -1);
|
||||
} else {
|
||||
checkGuiOverlap(gui, 0, columns, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (oldRows != rows || oldColumns != columns || !Arrays.equals(oldSlotMap, invalidSlotMap)) {
|
||||
@@ -196,9 +435,9 @@ public class ItemsGrid {
|
||||
|
||||
for (int r = 0; r < rows; r++) {
|
||||
final int idx = columns * r + c;
|
||||
if (GuiInfo.hideItemPanelSlot(gui, getSlotRect(r, c)) && idx >= 0
|
||||
&& idx < invalidSlotMap.length
|
||||
&& !invalidSlotMap[idx]) {
|
||||
if (idx >= 0 && idx < invalidSlotMap.length
|
||||
&& !invalidSlotMap[idx]
|
||||
&& GuiInfo.hideItemPanelSlot(gui, getSlotRect(r, c))) {
|
||||
invalidSlotMap[idx] = true;
|
||||
validColumn = false;
|
||||
perPage--;
|
||||
@@ -207,20 +446,37 @@ public class ItemsGrid {
|
||||
}
|
||||
}
|
||||
|
||||
public Rectangle4i getItemRect(int idx) {
|
||||
final List<Integer> mask = getMask();
|
||||
|
||||
for (int i = 0; i < mask.size(); i++) {
|
||||
if (mask.get(i) != null && idx == mask.get(i)) {
|
||||
return getSlotRect(i);
|
||||
}
|
||||
public T getSlotMouseOver(int mousex, int mousey) {
|
||||
if (!contains(mousex, mousey)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
final int overRow = getRowIndex(mousey);
|
||||
final int overColumn = getColumnIndex(mousex);
|
||||
final int slt = columns * overRow + overColumn;
|
||||
|
||||
if (overRow >= rows || overColumn >= columns) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getSlotBySlotIndex(slt);
|
||||
}
|
||||
|
||||
public Rectangle4i getSlotRect(int i) {
|
||||
return getSlotRect(i / columns, i % columns);
|
||||
public T getSlotBySlotIndex(int slotIndex) {
|
||||
return getMask().stream().filter(item -> item.slotIndex == slotIndex).findAny().orElse(null);
|
||||
}
|
||||
|
||||
public T getSlotByItemIndex(int itemIndex) {
|
||||
return getMask().stream().filter(item -> item.itemIndex == itemIndex).findAny().orElse(null);
|
||||
}
|
||||
|
||||
public Rectangle4i getItemRect(int itemIndex) {
|
||||
final T item = getSlotByItemIndex(itemIndex);
|
||||
return item != null ? getSlotRect(item.slotIndex) : null;
|
||||
}
|
||||
|
||||
public Rectangle4i getSlotRect(int slotIndex) {
|
||||
return getSlotRect(slotIndex / columns, slotIndex % columns);
|
||||
}
|
||||
|
||||
public Rectangle4i getSlotRect(int row, int column) {
|
||||
@@ -231,191 +487,49 @@ public class ItemsGrid {
|
||||
SLOT_SIZE);
|
||||
}
|
||||
|
||||
public int getRowIndex(int mousey) {
|
||||
return (mousey - this.marginTop) / SLOT_SIZE;
|
||||
}
|
||||
|
||||
public int getColumnIndex(int mousex) {
|
||||
return (mousex - this.marginLeft - this.paddingLeft) / SLOT_SIZE;
|
||||
}
|
||||
|
||||
public boolean isInvalidSlot(int index) {
|
||||
return invalidSlotMap[index];
|
||||
}
|
||||
|
||||
protected List<Integer> getMask() {
|
||||
List<Integer> mask = new ArrayList<>();
|
||||
public abstract List<T> getMask();
|
||||
|
||||
int idx = page * perPage;
|
||||
for (int i = 0; i < rows * columns && idx < size(); i++) {
|
||||
mask.add(isInvalidSlot(i) ? null : idx++);
|
||||
protected abstract M getMouseContext(int mousex, int mousey);
|
||||
|
||||
protected void beforeDrawItems(int mousex, int mousey, M mouseContext) {
|
||||
for (T item : getMask()) {
|
||||
item.beforeDraw(getSlotRect(item.slotIndex), mouseContext);
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
private void drawSlotOutlines(int mousex, int mousey) {
|
||||
ItemPanelSlot focused = getSlotMouseOver(mousex, mousey);
|
||||
final List<Integer> mask = getMask();
|
||||
|
||||
for (int i = 0; i < mask.size(); i++) {
|
||||
if (mask.get(i) != null) {
|
||||
drawSlotOutline(focused, mask.get(i), getSlotRect(i));
|
||||
}
|
||||
for (T item : getMask()) {
|
||||
item.drawBorder(getSlotRect(item.slotIndex));
|
||||
}
|
||||
}
|
||||
|
||||
private int recipeTooltipSlotIdx = -1;
|
||||
private int recipeTooltipLines = 2;
|
||||
private Runnable recipeTooltipUpdater = null;
|
||||
private GuiRecipe<?> recipeTooltipGui = null;
|
||||
|
||||
public void update() {
|
||||
if (recipeTooltipUpdater != null) {
|
||||
recipeTooltipUpdater.run();
|
||||
recipeTooltipUpdater = null;
|
||||
}
|
||||
if (recipeTooltipGui != null) {
|
||||
recipeTooltipGui.updateAsTooltip();
|
||||
protected void afterDrawItems(int mousex, int mousey, M mouseContext) {
|
||||
for (T item : getMask()) {
|
||||
item.afterDraw(getSlotRect(item.slotIndex), mouseContext);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> List<T> listOrEmptyList(final List<T> listOrNull) {
|
||||
return listOrNull == null ? Collections.emptyList() : listOrNull;
|
||||
public void update() {}
|
||||
|
||||
protected void drawItems() {
|
||||
|
||||
for (T item : getMask()) {
|
||||
item.drawItem(getSlotRect(item.slotIndex));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void drawRecipeTooltip(int mousex, int mousey, List<String> itemTooltip) {
|
||||
if (!NEIClientConfig.isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Minecraft mc = Minecraft.getMinecraft();
|
||||
ItemPanelSlot focused = getSlotMouseOver(mousex, mousey);
|
||||
if (focused == null) {
|
||||
recipeTooltipSlotIdx = -1;
|
||||
recipeTooltipGui = null;
|
||||
return;
|
||||
}
|
||||
final List<Integer> mask = getMask();
|
||||
|
||||
int slotIdx = -1;
|
||||
for (int i = 0; i < mask.size(); i++) {
|
||||
if (mask.get(i) == null) {
|
||||
continue;
|
||||
}
|
||||
if (focused.slotIndex != mask.get(i)) {
|
||||
continue;
|
||||
}
|
||||
slotIdx = i;
|
||||
break;
|
||||
}
|
||||
if (slotIdx == -1) {
|
||||
recipeTooltipSlotIdx = -1;
|
||||
recipeTooltipGui = null;
|
||||
return;
|
||||
}
|
||||
|
||||
final Point mouseover = getMousePosition();
|
||||
final ItemPanelSlot panelSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
final BookmarkRecipeId recipeId;
|
||||
if (panelSlot != null) {
|
||||
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(panelSlot.slotIndex);
|
||||
} else {
|
||||
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(focused.item);
|
||||
}
|
||||
if (recipeId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (slotIdx != recipeTooltipSlotIdx) {
|
||||
recipeTooltipSlotIdx = slotIdx;
|
||||
recipeTooltipGui = null;
|
||||
recipeTooltipUpdater = () -> {
|
||||
recipeTooltipGui = GuiCraftingRecipe.createRecipeGui("item", false, false, false, focused.item);
|
||||
if (recipeTooltipGui != null) {
|
||||
recipeTooltipGui.limitToOneRecipe();
|
||||
recipeTooltipGui.initGui(true);
|
||||
recipeTooltipGui.guiTop = 0;
|
||||
recipeTooltipGui.guiLeft = 0;
|
||||
}
|
||||
recipeTooltipLines = Math.max(1, itemTooltip.size());
|
||||
};
|
||||
}
|
||||
if (recipeTooltipGui == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
GL11.glPushMatrix();
|
||||
final float tooltipYOffset;
|
||||
if (mousey - marginTop > height / 2) {
|
||||
tooltipYOffset = mousey - recipeTooltipGui.getHeightAsWidget() + 8;
|
||||
} else {
|
||||
tooltipYOffset = mousey + ((recipeTooltipLines < 2) ? 1 : 3 + ((recipeTooltipLines - 1) * 10));
|
||||
}
|
||||
GL11.glTranslatef(mousex, tooltipYOffset, 500);
|
||||
|
||||
final GuiContainer gui;
|
||||
if (mc.currentScreen instanceof GuiRecipe) {
|
||||
gui = ((GuiRecipe<?>) mc.currentScreen).firstGui;
|
||||
} else if (mc.currentScreen instanceof GuiContainer) {
|
||||
gui = (GuiContainer) mc.currentScreen;
|
||||
} else {
|
||||
gui = null;
|
||||
}
|
||||
recipeTooltipGui.drawGuiContainerBackgroundLayer(0.0f, -100, -100);
|
||||
if (recipeTooltipGui.slotcontainer != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Slot> slots = (List<Slot>) recipeTooltipGui.slotcontainer.inventorySlots;
|
||||
for (Slot slot : slots) {
|
||||
if (slot != null && slot.getStack() != null) {
|
||||
GuiContainerManager.drawItem(slot.xDisplayPosition, slot.yDisplayPosition, slot.getStack());
|
||||
}
|
||||
}
|
||||
}
|
||||
recipeTooltipGui.drawGuiContainerForegroundLayer(-100, -100);
|
||||
for (GuiButton btn : recipeTooltipGui.getOverlayButtons()) {
|
||||
btn.drawButton(mc, -100, -100);
|
||||
}
|
||||
GL11.glPopMatrix();
|
||||
}
|
||||
|
||||
protected void drawSlotOutline(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {
|
||||
if (focused != null && focused.slotIndex == slotIdx) {
|
||||
drawRect(rect.x, rect.y, rect.w, rect.h, 0xee555555); // highlight
|
||||
}
|
||||
}
|
||||
|
||||
private void blitExistingBuffer() {
|
||||
Minecraft minecraft = Minecraft.getMinecraft();
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
OpenGlHelper.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
getFrameBuffer().bindFramebufferTexture();
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
ScaledResolution res = new ScaledResolution(minecraft, minecraft.displayWidth, minecraft.displayHeight);
|
||||
Tessellator tessellator = Tessellator.instance;
|
||||
tessellator.startDrawingQuads();
|
||||
tessellator.addVertexWithUV(0, res.getScaledHeight_double(), 0.0, 0, 0);
|
||||
tessellator.addVertexWithUV(res.getScaledWidth_double(), res.getScaledHeight_double(), 0.0, 1, 0);
|
||||
tessellator.addVertexWithUV(res.getScaledWidth_double(), 0, 0.0, 1, 1);
|
||||
tessellator.addVertexWithUV(0, 0, 0, 0, 1);
|
||||
tessellator.draw();
|
||||
OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
}
|
||||
|
||||
private Framebuffer getFrameBuffer() {
|
||||
|
||||
if (framebuffer == null) {
|
||||
framebuffer = new Framebuffer(1, 1, true);
|
||||
framebuffer.setFramebufferColor(0.0F, 0.0F, 0.0F, 0.0F);
|
||||
}
|
||||
|
||||
return framebuffer;
|
||||
}
|
||||
|
||||
private void drawItems() {
|
||||
GuiContainerManager.enableMatrixStackLogging();
|
||||
|
||||
final List<Integer> mask = getMask();
|
||||
for (int i = 0; i < mask.size(); i++) {
|
||||
if (mask.get(i) != null) {
|
||||
drawItem(getSlotRect(i), mask.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
GuiContainerManager.disableMatrixStackLogging();
|
||||
protected int getGridRenderingCacheMode() {
|
||||
return NEIClientConfig.getGridRenderingCacheMode();
|
||||
}
|
||||
|
||||
public void draw(int mousex, int mousey) {
|
||||
@@ -423,47 +537,33 @@ public class ItemsGrid {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.shouldCacheItemRendering()) {
|
||||
final int gridRenderingCacheMode = getGridRenderingCacheMode();
|
||||
final M mouseContext = getMouseContext(mousex, mousey);
|
||||
|
||||
if (refreshBuffer) {
|
||||
Minecraft minecraft = Minecraft.getMinecraft();
|
||||
Framebuffer framebuffer = getFrameBuffer();
|
||||
framebuffer.createBindFramebuffer(minecraft.displayWidth, minecraft.displayHeight);
|
||||
framebuffer.framebufferClear();
|
||||
framebuffer.bindFramebuffer(false);
|
||||
beforeDrawItems(mousex, mousey, mouseContext);
|
||||
|
||||
/* Set up some rendering state needed for items to work correctly */
|
||||
GL11.glDisable(GL11.GL_BLEND);
|
||||
GL11.glDepthMask(true);
|
||||
OpenGlHelper.glBlendFunc(
|
||||
GL11.GL_SRC_ALPHA,
|
||||
GL11.GL_ONE_MINUS_SRC_ALPHA,
|
||||
GL11.GL_SRC_ALPHA,
|
||||
GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
if (gridRenderingCacheMode > 0) {
|
||||
|
||||
drawItems();
|
||||
|
||||
Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
|
||||
refreshBuffer = false;
|
||||
if (this.screenCapture == null) {
|
||||
this.screenCapture = new ScreenCapture();
|
||||
}
|
||||
|
||||
drawSlotOutlines(mousex, mousey);
|
||||
blitExistingBuffer();
|
||||
if (this.screenCapture.needRefresh(gridRenderingCacheMode)) {
|
||||
this.screenCapture.captureScreen(() -> {
|
||||
GuiContainerManager.enableMatrixStackLogging();
|
||||
drawItems();
|
||||
GuiContainerManager.disableMatrixStackLogging();
|
||||
}, gridRenderingCacheMode);
|
||||
}
|
||||
|
||||
this.screenCapture.renderCapturedScreen();
|
||||
} else {
|
||||
drawSlotOutlines(mousex, mousey);
|
||||
GuiContainerManager.enableMatrixStackLogging();
|
||||
drawItems();
|
||||
GuiContainerManager.disableMatrixStackLogging();
|
||||
}
|
||||
}
|
||||
|
||||
public void postDrawTooltips(int mousex, int mousey, List<String> tooltip) {
|
||||
if (NEIClientConfig.showRecipeTooltips() && showRecipeTooltips) {
|
||||
try {
|
||||
drawRecipeTooltip(mousex, mousey, tooltip);
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.warn("Cannot draw recipe tooltip", e);
|
||||
}
|
||||
}
|
||||
afterDrawItems(mousex, mousey, mouseContext);
|
||||
}
|
||||
|
||||
public void setVisible() {
|
||||
@@ -472,45 +572,18 @@ public class ItemsGrid {
|
||||
}
|
||||
}
|
||||
|
||||
protected void drawItem(Rectangle4i rect, int idx) {
|
||||
GuiContainerManager.drawItem(rect.x + 1, rect.y + 1, getItem(idx));
|
||||
}
|
||||
|
||||
public ItemPanelSlot getSlotMouseOver(int mousex, int mousey) {
|
||||
if (!contains(mousex, mousey)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int overRow = (int) ((mousey - marginTop) / SLOT_SIZE);
|
||||
final int overColumn = (int) ((mousex - marginLeft - paddingLeft) / SLOT_SIZE);
|
||||
final int slt = columns * overRow + overColumn;
|
||||
|
||||
if (overRow >= rows || overColumn >= columns) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final List<Integer> mask = getMask();
|
||||
|
||||
if (mask.size() > slt && mask.get(slt) != null) {
|
||||
final int idx = mask.get(slt);
|
||||
|
||||
return new ItemPanelSlot(idx, getItem(idx));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean contains(int px, int py) {
|
||||
final Rectangle4i rect = new Rectangle4i(
|
||||
marginLeft + paddingLeft,
|
||||
marginTop,
|
||||
columns * SLOT_SIZE,
|
||||
rows * SLOT_SIZE);
|
||||
|
||||
if (!(new Rectangle4i(marginLeft + paddingLeft, marginTop, columns * SLOT_SIZE, height)).contains(px, py)) {
|
||||
if (!rect.contains(px, py)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int r = (int) ((py - marginTop) / SLOT_SIZE);
|
||||
final int c = (int) ((px - marginLeft - paddingLeft) / SLOT_SIZE);
|
||||
final int slt = columns * r + c;
|
||||
|
||||
return r >= rows || c >= columns || !isInvalidSlot(slt);
|
||||
return !isInvalidSlot(columns * getRowIndex(py) + getColumnIndex(px));
|
||||
}
|
||||
|
||||
public String getMessageOnEmpty() {
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
|
||||
public class ItemsPanelGrid extends ItemsGrid<ItemsPanelGrid.ItemsPanelGridSlot, ItemsPanelGrid.MouseContext> {
|
||||
|
||||
public static class ItemsPanelGridSlot extends ItemsGridSlot {
|
||||
|
||||
protected static final float LINE_WIDTH = 0.75f;
|
||||
|
||||
public int groupIndex = -1;
|
||||
public String displayName = "";
|
||||
public ItemStack bgItemStack;
|
||||
public int groupSize = 1;
|
||||
public boolean extended = false;
|
||||
|
||||
public Color bgColor = null;
|
||||
|
||||
public ItemsPanelGridSlot(int slotIndex, int itemIndex, ItemStack itemStack) {
|
||||
super(slotIndex, itemIndex, itemStack);
|
||||
}
|
||||
|
||||
public ItemStack getBGItem() {
|
||||
return this.bgItemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeId getRecipeId() {
|
||||
return FavoriteRecipes.getFavorite(this.item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeDraw(Rectangle4i rect, MouseContext mouseContext) {
|
||||
super.beforeDraw(rect, mouseContext);
|
||||
|
||||
if (this.bgColor != null) {
|
||||
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, this.bgColor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawItem(Rectangle4i rect) {
|
||||
|
||||
if (!this.extended && getBGItem() != null) {
|
||||
GuiContainerManager.drawItems.zLevel -= 10F;
|
||||
super.drawItem(getBGItem(), rect.offset(1, -1));
|
||||
GuiContainerManager.drawItems.zLevel += 10F;
|
||||
super.drawItem(getItemStack(), rect.offset(-2, 2));
|
||||
} else {
|
||||
super.drawItem(rect);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ArrayList<ItemStack> newItems;
|
||||
public ArrayList<ItemStack> rawItems;
|
||||
protected List<ItemsPanelGridSlot> gridMask;
|
||||
|
||||
protected final Map<Integer, Integer> itemToGroup = new HashMap<>();
|
||||
protected final Map<Integer, List<ItemStack>> groupItems = new HashMap<>();
|
||||
protected boolean forceExpand = false;
|
||||
|
||||
public void setItems(ArrayList<ItemStack> items) {
|
||||
newItems = items;
|
||||
}
|
||||
|
||||
public static void updateScale() {
|
||||
SLOT_SIZE = 2 + (int) Math.ceil(8f * NEIClientConfig.getIntSetting("inventory.itempanelScale") / 100) * 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(GuiContainer gui) {
|
||||
|
||||
if (this.newItems != null) {
|
||||
this.groupItems.clear();
|
||||
this.itemToGroup.clear();
|
||||
this.forceExpand = false;
|
||||
|
||||
if (!CollapsibleItems.isEmpty() && !this.newItems.isEmpty()) {
|
||||
final Set<Integer> groups = new HashSet<>();
|
||||
boolean outsideGroup = false;
|
||||
|
||||
this.realItems = new ArrayList<>();
|
||||
this.rawItems = new ArrayList<>(this.newItems);
|
||||
|
||||
for (ItemStack stack : this.newItems) {
|
||||
final int groupIndex = CollapsibleItems.getGroupIndex(stack);
|
||||
|
||||
if (groupIndex == -1) {
|
||||
this.realItems.add(stack);
|
||||
outsideGroup = true;
|
||||
} else {
|
||||
|
||||
if (!groups.contains(groupIndex) || CollapsibleItems.isExpanded(groupIndex)) {
|
||||
this.itemToGroup.put(this.realItems.size(), groupIndex);
|
||||
this.realItems.add(stack);
|
||||
groups.add(groupIndex);
|
||||
}
|
||||
|
||||
this.groupItems.computeIfAbsent(groupIndex, gi -> new ArrayList<>()).add(stack);
|
||||
}
|
||||
}
|
||||
|
||||
// automatically opens if there are elements from only one group
|
||||
if (!outsideGroup && groups.size() == 1) {
|
||||
final int groupIndex = groups.iterator().next();
|
||||
this.realItems = new ArrayList<>(this.newItems);
|
||||
this.itemToGroup.clear();
|
||||
this.forceExpand = true;
|
||||
|
||||
for (int itemIndex = 0; itemIndex < this.realItems.size(); itemIndex++) {
|
||||
this.itemToGroup.put(itemIndex, groupIndex);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.realItems = new ArrayList<>(this.newItems);
|
||||
}
|
||||
|
||||
this.newItems = null;
|
||||
onItemsChanged();
|
||||
}
|
||||
|
||||
super.refresh(gui);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onGridChanged() {
|
||||
this.gridMask = null;
|
||||
super.onGridChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemsPanelGridSlot> getMask() {
|
||||
|
||||
if (this.gridMask == null) {
|
||||
this.gridMask = new ArrayList<>();
|
||||
int itemIndex = page * perPage;
|
||||
|
||||
for (int slotIndex = 0; slotIndex < rows * columns && itemIndex < size(); slotIndex++) {
|
||||
if (!isInvalidSlot(slotIndex)) {
|
||||
this.gridMask.add(new ItemsPanelGridSlot(slotIndex, itemIndex, getItem(itemIndex)));
|
||||
itemIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
calculateGroupBorders(this.gridMask);
|
||||
}
|
||||
|
||||
return this.gridMask;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MouseContext getMouseContext(int mousex, int mousey) {
|
||||
final ItemsPanelGridSlot hovered = getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (hovered != null) {
|
||||
return new MouseContext(
|
||||
hovered.slotIndex,
|
||||
hovered.slotIndex / this.columns,
|
||||
hovered.slotIndex % this.columns);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void calculateGroupBorders(List<ItemsPanelGridSlot> gridMask) {
|
||||
|
||||
if (gridMask.isEmpty() || this.groupItems.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Color collapsedBGColor = new Color(
|
||||
NEIClientConfig.getSetting("inventory.collapsibleItems.collapsedColor").getHexValue(),
|
||||
true);
|
||||
final Color expandedBGColor = new Color(
|
||||
NEIClientConfig.getSetting("inventory.collapsibleItems.expandedColor").getHexValue(),
|
||||
true);
|
||||
final Color collapsedBorderColor = darkerColor(collapsedBGColor);
|
||||
final Color expandedBorderColor = darkerColor(expandedBGColor);
|
||||
final Map<Integer, Integer> borderGrid = new HashMap<>();
|
||||
|
||||
for (ItemsPanelGridSlot item : gridMask) {
|
||||
borderGrid.put(item.slotIndex, this.itemToGroup.getOrDefault(item.itemIndex, -1));
|
||||
}
|
||||
|
||||
for (ItemsPanelGridSlot item : gridMask) {
|
||||
final int groupIndex = borderGrid.get(item.slotIndex);
|
||||
final List<ItemStack> groupItems = this.groupItems.get(groupIndex);
|
||||
|
||||
if (groupItems == null || groupItems.size() == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int column = item.slotIndex % this.columns;
|
||||
int row = item.slotIndex / this.columns;
|
||||
int prevSlotIndex = (row - 1) * this.columns + column;
|
||||
int nextSlotIndex = (row + 1) * this.columns + column;
|
||||
|
||||
item.groupIndex = groupIndex;
|
||||
item.groupSize = groupItems.size();
|
||||
item.bgItemStack = groupItems.get(groupItems.size() - 1);
|
||||
item.displayName = CollapsibleItems.getDisplayName(groupIndex);
|
||||
item.extended = this.forceExpand || CollapsibleItems.isExpanded(groupIndex);
|
||||
item.bgColor = item.extended ? expandedBGColor : collapsedBGColor;
|
||||
|
||||
item.borderColor = item.extended ? expandedBorderColor : collapsedBorderColor;
|
||||
item.borderLeft = column == 0 || borderGrid.getOrDefault(item.slotIndex - 1, -1) != groupIndex;
|
||||
item.borderRight = column + 1 == this.columns
|
||||
|| borderGrid.getOrDefault(item.slotIndex + 1, -1) != groupIndex;
|
||||
item.borderTop = borderGrid.getOrDefault(prevSlotIndex, -1) != groupIndex;
|
||||
item.borderBottom = borderGrid.getOrDefault(nextSlotIndex, -1) != groupIndex;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Color darkerColor(Color color) {
|
||||
return new Color(
|
||||
color.getRed(),
|
||||
color.getGreen(),
|
||||
color.getBlue(),
|
||||
Math.min((int) (color.getAlpha() + (255f / 5) * 2), 255));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessageOnEmpty() {
|
||||
return ItemList.loadFinished ? null : NEIClientUtils.translate("itempanel.loading");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import static codechicken.lib.gui.GuiDraw.fontRenderer;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.lib.gui.GuiDraw.ITooltipLineHandler;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.ReadableNumberConverter;
|
||||
|
||||
public class ItemsTooltipLineHandler implements ITooltipLineHandler {
|
||||
|
||||
protected static final int SLOT_SIZE = 18;
|
||||
protected static final int MAX_COLUMNS = 11;
|
||||
protected static final int MARGIN_TOP = 2;
|
||||
|
||||
protected String label;
|
||||
protected EnumChatFormatting labelColor = EnumChatFormatting.GRAY;
|
||||
protected List<ItemStack> items;
|
||||
protected int activeStackIndex = -1;
|
||||
protected Dimension size = new Dimension();
|
||||
protected boolean saveStackSize = false;
|
||||
protected int columns = 0;
|
||||
protected int count = 0;
|
||||
protected int rows = 0;
|
||||
protected int length = 0;
|
||||
|
||||
public ItemsTooltipLineHandler(String label, List<ItemStack> items) {
|
||||
this(label, items, true, 5);
|
||||
}
|
||||
|
||||
public ItemsTooltipLineHandler(String label, List<ItemStack> items, boolean saveStackSize, int maxRows) {
|
||||
this.label = label;
|
||||
this.items = groupingItemStacks(items);
|
||||
this.saveStackSize = saveStackSize;
|
||||
this.length = this.items.size();
|
||||
|
||||
if (this.length > 0) {
|
||||
this.columns = Math.min(MAX_COLUMNS, this.length);
|
||||
this.rows = Math.min(maxRows, (int) Math.ceil((float) this.length / this.columns));
|
||||
|
||||
this.size.width = Math.max(this.columns * SLOT_SIZE, fontRenderer.getStringWidth(this.label) + 15);
|
||||
this.size.height = this.rows * SLOT_SIZE + fontRenderer.FONT_HEIGHT + 2 + MARGIN_TOP;
|
||||
|
||||
this.count = Math.min(
|
||||
this.length,
|
||||
Math.min(
|
||||
this.columns * this.rows,
|
||||
this.length > MAX_COLUMNS * maxRows ? (MAX_COLUMNS * maxRows) : Integer.MAX_VALUE));
|
||||
|
||||
if (this.items.size() > this.count) {
|
||||
String text = "+" + (this.items.size() - this.count);
|
||||
this.count -= (int) Math.ceil((float) (fontRenderer.getStringWidth(text) - 2) / SLOT_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setActiveStack(ItemStack activeStack) {
|
||||
final ItemStack realStack = items.stream().filter(stack -> StackInfo.equalItemAndNBT(stack, activeStack, true))
|
||||
.findFirst().orElse(null);
|
||||
this.activeStackIndex = items.indexOf(realStack);
|
||||
}
|
||||
|
||||
public ItemStack getActiveStack() {
|
||||
return this.activeStackIndex == -1 ? null : this.items.get(this.activeStackIndex);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return this.items.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public void setLabelColor(EnumChatFormatting color) {
|
||||
this.labelColor = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int x, int y) {
|
||||
if (this.length == 0) return;
|
||||
|
||||
y += MARGIN_TOP;
|
||||
|
||||
fontRenderer.drawStringWithShadow(this.labelColor + this.label + ":", x, y, 0);
|
||||
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
GL11.glPushMatrix();
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
|
||||
GL11.glScaled(1, 1, 3);
|
||||
GL11.glTranslatef(x, y + fontRenderer.FONT_HEIGHT + 2, 0);
|
||||
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
|
||||
|
||||
int indexShift = 0;
|
||||
|
||||
if (this.activeStackIndex != -1) {
|
||||
indexShift = Math.max(0, Math.min(this.items.size() - this.count, this.activeStackIndex - this.count + 2));
|
||||
}
|
||||
|
||||
for (int index = 0; index < this.count && index + indexShift < this.items.size(); index++) {
|
||||
ItemStack drawStack = this.items.get(index + indexShift);
|
||||
int col = index % this.columns;
|
||||
int row = index / this.columns;
|
||||
|
||||
String stackSize = !this.saveStackSize || drawStack.stackSize == 0 ? ""
|
||||
: ReadableNumberConverter.INSTANCE.toWideReadableForm(drawStack.stackSize);
|
||||
|
||||
if (this.activeStackIndex == index + indexShift) {
|
||||
NEIClientUtils.gl2DRenderContext(
|
||||
() -> GuiDraw.drawRect(col * SLOT_SIZE - 1, row * SLOT_SIZE - 1, 18, 18, 0x66555555));
|
||||
}
|
||||
|
||||
drawItem(col * SLOT_SIZE, row * SLOT_SIZE, drawStack, stackSize);
|
||||
}
|
||||
|
||||
if (this.count < this.items.size()) {
|
||||
final String text = "+" + (this.items.size() - this.count);
|
||||
|
||||
NEIClientUtils.gl2DRenderContext(() -> {
|
||||
fontRenderer.drawStringWithShadow(
|
||||
text,
|
||||
MAX_COLUMNS * SLOT_SIZE - fontRenderer.getStringWidth(text) - 2,
|
||||
(this.rows - 1) * SLOT_SIZE + (SLOT_SIZE - fontRenderer.FONT_HEIGHT) / 2,
|
||||
0xee555555);
|
||||
});
|
||||
}
|
||||
|
||||
GL11.glPopMatrix();
|
||||
GL11.glPopAttrib();
|
||||
}
|
||||
|
||||
protected void drawItem(int x, int y, ItemStack drawStack, String stackSize) {
|
||||
GuiContainerManager.drawItem(x, y, drawStack, true, stackSize);
|
||||
}
|
||||
|
||||
private List<ItemStack> groupingItemStacks(List<ItemStack> items) {
|
||||
final List<ItemStack> result = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<NBTTagCompound, Long> entry : ItemStackAmount.of(items).entrySet()) {
|
||||
final ItemStack stack = StackInfo.loadFromNBT(entry.getKey(), Math.max(0, entry.getValue()));
|
||||
|
||||
if (entry.getKey().hasKey("gtFluidName")) {
|
||||
stack.stackSize = 0;
|
||||
}
|
||||
result.add(stack);
|
||||
}
|
||||
|
||||
if (result.isEmpty()) {
|
||||
result.addAll(items);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 < Keyboard.KEYBOARD_SIZE ? Keyboard.isKeyDown(keyCode) : null;
|
||||
final KeyState state = entry.getValue();
|
||||
|
||||
if (down) {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
// Simple LRUCache
|
||||
public class LRUCache<K, V> extends LinkedHashMap<K, V> {
|
||||
|
||||
private final int capacity;
|
||||
|
||||
public LRUCache(int capacity) {
|
||||
super(capacity, 0.75f, true);
|
||||
this.capacity = capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
|
||||
return size() > capacity;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import static codechicken.nei.NEIClientConfig.isEnabled;
|
||||
import static codechicken.nei.NEIClientConfig.isHidden;
|
||||
import static codechicken.nei.NEIClientConfig.showIDs;
|
||||
import static codechicken.nei.NEIClientConfig.toggleBooleanSetting;
|
||||
import static codechicken.nei.NEIClientConfig.world;
|
||||
import static codechicken.nei.NEIClientUtils.cycleGamemode;
|
||||
import static codechicken.nei.NEIClientUtils.decreaseSlotStack;
|
||||
import static codechicken.nei.NEIClientUtils.deleteEverything;
|
||||
@@ -32,8 +31,11 @@ import static codechicken.nei.NEIClientUtils.toggleMagnetMode;
|
||||
import static codechicken.nei.NEIClientUtils.toggleRaining;
|
||||
import static codechicken.nei.NEIClientUtils.translate;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -63,6 +65,7 @@ import codechicken.nei.guihook.IContainerDrawHandler;
|
||||
import codechicken.nei.guihook.IContainerInputHandler;
|
||||
import codechicken.nei.guihook.IContainerObjectHandler;
|
||||
import codechicken.nei.guihook.IContainerTooltipHandler;
|
||||
import codechicken.nei.recipe.AutoCraftingManager;
|
||||
import codechicken.nei.recipe.GuiRecipeTab;
|
||||
import codechicken.nei.recipe.RecipeCatalysts;
|
||||
|
||||
@@ -77,28 +80,23 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
/**
|
||||
* Sorted bottom first
|
||||
*/
|
||||
private static TreeSet<Widget> drawWidgets = new TreeSet<>(new WidgetZOrder(false));
|
||||
private static Set<Widget> drawWidgets = new TreeSet<>(new WidgetZOrder(false));
|
||||
/**
|
||||
* Sorted top first
|
||||
*/
|
||||
private static TreeSet<Widget> controlWidgets = new TreeSet<>(new WidgetZOrder(true));
|
||||
private static Set<Widget> controlWidgets = new TreeSet<>(new WidgetZOrder(true));
|
||||
|
||||
public static ItemPanel itemPanel;
|
||||
public static BookmarkPanel bookmarkPanel;
|
||||
public static SubsetWidget dropDown;
|
||||
public static PresetsWidget presetsPanel;
|
||||
public static SearchField searchField;
|
||||
public static ItemZoom itemZoom;
|
||||
|
||||
public static ButtonCycled options;
|
||||
public static ButtonCycled bookmarksButton;
|
||||
|
||||
@Deprecated
|
||||
public static Button more;
|
||||
|
||||
@Deprecated
|
||||
public static Button less;
|
||||
|
||||
@Deprecated
|
||||
public static ItemQuantityField quantity;
|
||||
|
||||
public static Button delete;
|
||||
@@ -138,16 +136,14 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
|
||||
@Override
|
||||
public void onPreDraw(GuiContainer gui) {
|
||||
if (!isHidden() && isEnabled() && gui instanceof InventoryEffectRenderer) // Reset the gui to the center of the
|
||||
// screen, for potion effect offsets
|
||||
// etc
|
||||
{
|
||||
// Reset the gui to the center of the screen, for potion effect offsets etc
|
||||
if (isEnabled() && gui instanceof InventoryEffectRenderer) {
|
||||
gui.guiLeft = (gui.width - gui.xSize) / 2;
|
||||
gui.guiTop = (gui.height - gui.ySize) / 2;
|
||||
|
||||
if (gui instanceof GuiContainerCreative && gui.buttonList.size() >= 2) {
|
||||
GuiButton button1 = (GuiButton) gui.buttonList.get(0);
|
||||
GuiButton button2 = (GuiButton) gui.buttonList.get(1);
|
||||
GuiButton button1 = gui.buttonList.get(0);
|
||||
GuiButton button2 = gui.buttonList.get(1);
|
||||
button1.xPosition = gui.guiLeft;
|
||||
button2.xPosition = gui.guiLeft + gui.xSize - 20;
|
||||
}
|
||||
@@ -168,14 +164,18 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
|
||||
if (isHidden()) return;
|
||||
|
||||
for (Widget widget : controlWidgets) widget.onGuiClick(mousex, mousey);
|
||||
for (Widget widget : controlWidgets) {
|
||||
widget.onGuiClick(mousex, mousey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
|
||||
if (isHidden()) return false;
|
||||
|
||||
if (!isEnabled()) return options.contains(mousex, mousey) && options.handleClick(mousex, mousey, button);
|
||||
if (!isEnabled()) {
|
||||
return options.contains(mousex, mousey) && options.handleClick(mousex, mousey, button);
|
||||
}
|
||||
|
||||
for (Widget widget : controlWidgets) {
|
||||
widget.onGuiClick(mousex, mousey);
|
||||
@@ -189,10 +189,22 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
|
||||
@Override
|
||||
public boolean objectUnderMouse(GuiContainer gui, int mousex, int mousey) {
|
||||
if (!isHidden() && isEnabled())
|
||||
for (Widget widget : drawWidgets) if (widget.contains(mousex, mousey)) return true;
|
||||
return getWidgetUnderMouse(mousex, mousey) != null;
|
||||
}
|
||||
|
||||
return false;
|
||||
public Widget getWidgetUnderMouse(int mousex, int mousey) {
|
||||
|
||||
if (isHidden() || !isEnabled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Widget widget : controlWidgets) {
|
||||
if (widget.contains(mousex, mousey)) {
|
||||
return widget;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean keyTyped(GuiContainer gui, char keyChar, int keyID) {
|
||||
@@ -217,12 +229,11 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.hide_bookmarks")) {
|
||||
toggleBooleanSetting("inventory.bookmarksEnabled");
|
||||
toggleBooleanSetting("inventory.bookmarks.enabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.next_tooltip")) {
|
||||
GuiContainerManager.incrementTooltipPage();
|
||||
if (NEIClientConfig.isKeyHashDown("gui.next_tooltip") && GuiContainerManager.incrementTooltipPage()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -248,12 +259,12 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
|
||||
@Override
|
||||
public ItemStack getStackUnderMouse(GuiContainer gui, int mousex, int mousey) {
|
||||
if (!isHidden() && isEnabled()) {
|
||||
for (Widget widget : drawWidgets) {
|
||||
ItemStack stack = widget.getStackMouseOver(mousex, mousey);
|
||||
if (stack != null) return stack;
|
||||
}
|
||||
final Widget focused = getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
if (focused != null) {
|
||||
return focused.getStackMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -282,16 +293,32 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
|
||||
@Override
|
||||
public void postRenderTooltips(GuiContainer gui, int mousex, int mousey, List<String> tooltip) {
|
||||
if (!isHidden() && isEnabled()) {
|
||||
for (Widget widget : drawWidgets) widget.postDrawTooltips(mousex, mousey, tooltip);
|
||||
|
||||
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
|
||||
final Widget focused = getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
if (focused != null) {
|
||||
focused.postDrawTooltips(mousex, mousey, tooltip);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
|
||||
|
||||
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
|
||||
for (Widget widget : drawWidgets) currenttip = widget.handleTooltip(mousex, mousey, currenttip);
|
||||
final Widget focused = getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
if (focused != null) {
|
||||
currenttip = focused.handleTooltip(mousex, mousey, currenttip);
|
||||
|
||||
if (focused instanceof IContainerTooltipHandler tip) {
|
||||
currenttip = tip.handleTooltip(gui, mousex, mousey, currenttip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return currenttip;
|
||||
}
|
||||
|
||||
@@ -308,29 +335,55 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
currenttip.set(0, mainname);
|
||||
}
|
||||
|
||||
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
|
||||
final Point mouse = GuiDraw.getMousePosition();
|
||||
final Widget focused = getWidgetUnderMouse(mouse.x, mouse.y);
|
||||
|
||||
if (focused instanceof IContainerTooltipHandler tip) {
|
||||
currenttip = tip.handleItemDisplayName(gui, stack, currenttip);
|
||||
}
|
||||
}
|
||||
|
||||
return currenttip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
|
||||
List<String> currenttip) {
|
||||
|
||||
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
|
||||
final Widget focused = getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
if (focused instanceof IContainerTooltipHandler tip) {
|
||||
currenttip = tip.handleItemTooltip(gui, itemstack, mousex, mousey, currenttip);
|
||||
}
|
||||
}
|
||||
|
||||
return currenttip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
|
||||
|
||||
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
|
||||
final Widget focused = getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
if (focused instanceof IContainerTooltipHandler tip) {
|
||||
hotkeys = tip.handleHotkeys(gui, mousex, mousey, hotkeys);
|
||||
}
|
||||
}
|
||||
|
||||
return hotkeys;
|
||||
}
|
||||
|
||||
public static void layout(GuiContainer gui) {
|
||||
VisiblityData visiblity = new VisiblityData();
|
||||
|
||||
if (isHidden()) visiblity.showNEI = false;
|
||||
|
||||
if (isBookmarkPanelHidden()) visiblity.showBookmarkPanel = false;
|
||||
|
||||
if (gui.height - gui.ySize <= 40) visiblity.showSearchSection = false;
|
||||
|
||||
if (visiblity.showBookmarkPanel || gui.guiTop <= 20) visiblity.showSubsetDropdown = false;
|
||||
|
||||
if (!visiblity.showBookmarkPanel || gui.guiTop <= 20) visiblity.showPresetsDropdown = false;
|
||||
|
||||
if (gui.guiLeft - 4 < 76) visiblity.showWidgets = false;
|
||||
visiblity.showNEI = !isHidden();
|
||||
visiblity.showBookmarkPanel = !isBookmarkPanelHidden();
|
||||
visiblity.showSearchSection = !(gui.height - gui.ySize <= 40 && NEIClientConfig.isSearchWidgetCentered());
|
||||
visiblity.showSubsetDropdown = NEIClientConfig.showSubsetWidget()
|
||||
&& (gui.guiTop > 20 || visiblity.showSearchSection && !NEIClientConfig.subsetWidgetOnTop());
|
||||
visiblity.showWidgets = gui.guiLeft - 4 > 76;
|
||||
|
||||
try {
|
||||
GuiInfo.readLock.lock();
|
||||
@@ -353,9 +406,11 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
bookmarkPanel = ItemPanels.bookmarkPanel;
|
||||
bookmarkPanel.init();
|
||||
|
||||
itemZoom = new ItemZoom();
|
||||
|
||||
dropDown = new SubsetWidget();
|
||||
presetsPanel = new PresetsWidget();
|
||||
searchField = new SearchField("search");
|
||||
API.addItemFilter(searchField);
|
||||
|
||||
options = new ButtonCycled(3) {
|
||||
|
||||
@@ -377,7 +432,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
@Override
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
if (!rightclick) {
|
||||
if (Keyboard.getEventKeyState() && getIsAccessibleControlEventKey()) {
|
||||
if (Keyboard.getEventKeyState() && getIsAccessibleControlEventKey()
|
||||
&& NEIClientConfig.canChangeCheatMode()) {
|
||||
NEIClientConfig.cycleSetting("inventory.cheatmode", 3);
|
||||
} else {
|
||||
if (Keyboard.getEventKeyState() && (Keyboard.getEventKey() == Keyboard.KEY_LSHIFT
|
||||
@@ -401,7 +457,10 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
else if (cheatMode == 2) modeColor = EnumChatFormatting.RED.toString();
|
||||
String controlKeyLocalization = translate(Minecraft.isRunningOnMac ? "key.ctrl.mac" : "key.ctrl");
|
||||
tooltip.add(modeColor + translate("inventory.options.tip.cheatmode." + cheatMode));
|
||||
tooltip.add(modeColor + translate("inventory.options.tip.cheatmode.disable", controlKeyLocalization));
|
||||
if (NEIClientConfig.canChangeCheatMode()) {
|
||||
tooltip.add(
|
||||
modeColor + translate("inventory.options.tip.cheatmode.disable", controlKeyLocalization));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -420,7 +479,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
|
||||
@Override
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
NEIClientConfig.toggleBooleanSetting("inventory.bookmarksEnabled");
|
||||
NEIClientConfig.toggleBooleanSetting("inventory.bookmarks.enabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -434,9 +493,43 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
}
|
||||
};
|
||||
|
||||
more = ItemPanels.itemPanel.more;
|
||||
less = ItemPanels.itemPanel.less;
|
||||
quantity = ItemPanels.itemPanel.quantity;
|
||||
more = new Button("+") {
|
||||
|
||||
@Override
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
if (rightclick) return false;
|
||||
|
||||
int modifier = NEIClientUtils.controlKey() ? 64 : NEIClientUtils.shiftKey() ? 10 : 1;
|
||||
int quantity = NEIClientConfig.getItemQuantity() + modifier;
|
||||
|
||||
if (quantity < 0) {
|
||||
quantity = 0;
|
||||
}
|
||||
|
||||
LayoutManager.quantity.setText(Integer.toString(quantity));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
less = new Button("-") {
|
||||
|
||||
@Override
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
if (rightclick) return false;
|
||||
|
||||
int modifier = NEIClientUtils.controlKey() ? -64 : NEIClientUtils.shiftKey() ? -10 : -1;
|
||||
int quantity = NEIClientConfig.getItemQuantity() + modifier;
|
||||
|
||||
if (quantity < 0) {
|
||||
quantity = 0;
|
||||
}
|
||||
|
||||
LayoutManager.quantity.setText(Integer.toString(quantity));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
quantity = new ItemQuantityField("quantity");
|
||||
|
||||
delete = new Button() {
|
||||
|
||||
@Override
|
||||
@@ -612,12 +705,12 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
|
||||
if (!itemsLoaded) {
|
||||
ItemList.loadItems.restart();
|
||||
itemsLoaded = true;
|
||||
}
|
||||
overlayRenderer = null;
|
||||
|
||||
overlayRenderer = null;
|
||||
getLayoutStyle().init();
|
||||
layout(gui);
|
||||
AutoFocusWidget.instance.load(gui);
|
||||
}
|
||||
|
||||
NEIController.load(gui);
|
||||
@@ -649,14 +742,15 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
|
||||
addWidget(options);
|
||||
addWidget(bookmarksButton);
|
||||
|
||||
if (visiblity.showItemPanel && NEIClientConfig.showItemQuantityWidget()) {
|
||||
addWidget(quantity);
|
||||
addWidget(more);
|
||||
addWidget(less);
|
||||
}
|
||||
|
||||
if (visiblity.showItemPanel) {
|
||||
|
||||
if (PresetsWidget.inEditMode()) {
|
||||
drawWidgets.add(itemPanel);
|
||||
} else {
|
||||
addWidget(itemPanel);
|
||||
}
|
||||
|
||||
addWidget(itemPanel);
|
||||
itemPanel.setVisible();
|
||||
}
|
||||
|
||||
@@ -665,13 +759,13 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
bookmarkPanel.setVisible();
|
||||
}
|
||||
|
||||
if (visiblity.showPresetsDropdown) {
|
||||
addWidget(presetsPanel);
|
||||
}
|
||||
|
||||
searchField.setVisible(visiblity.showSearchSection);
|
||||
if (visiblity.showSearchSection) {
|
||||
if (visiblity.showSearchSection && NEIClientConfig.isSearchWidgetCentered()
|
||||
|| visiblity.showItemPanel && !NEIClientConfig.isSearchWidgetCentered()) {
|
||||
searchField.setVisible(true);
|
||||
addWidget(searchField);
|
||||
} else {
|
||||
searchField.setVisible(false);
|
||||
searchField.setFocus(false);
|
||||
}
|
||||
|
||||
if (visiblity.showUtilityButtons) {
|
||||
@@ -686,6 +780,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
if (canPerformAction("delete")) addWidget(delete);
|
||||
}
|
||||
|
||||
addWidget(itemZoom);
|
||||
|
||||
if (visiblity.showSubsetDropdown) {
|
||||
// Bookmarks or Subset/dropdown
|
||||
addWidget(dropDown);
|
||||
@@ -720,7 +816,9 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
|
||||
if (isHidden() || !isEnabled()) return false;
|
||||
|
||||
for (Widget widget : drawWidgets) if (widget.onMouseWheel(scrolled, mousex, mousey)) return true;
|
||||
for (Widget widget : controlWidgets) {
|
||||
if (widget.onMouseWheel(scrolled, mousex, mousey)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -730,7 +828,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
|
||||
@Override
|
||||
public boolean shouldShowTooltip(GuiContainer gui) {
|
||||
return itemPanel.draggedStack == null && bookmarkPanel.sortedStackIndex == -1;
|
||||
return itemPanel.draggedStack == null && !bookmarkPanel.inEditingState() && !AutoCraftingManager.processing();
|
||||
}
|
||||
|
||||
/** Note: this method isn't actually used by this mod, but NEI add-ons might need it. */
|
||||
@@ -753,17 +851,19 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
|
||||
@Override
|
||||
public void renderSlotOverlay(GuiContainer window, Slot slot) {
|
||||
ItemStack item = slot.getStack();
|
||||
if (world.nbt.getBoolean("searchinventories") && (item == null ? !getSearchExpression().equals("")
|
||||
: !((SearchField) searchField).getFilter().matches(item))) {
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
GL11.glDisable(GL11.GL_DEPTH_TEST);
|
||||
GL11.glTranslatef(0, 0, 150);
|
||||
drawRect(slot.xDisplayPosition, slot.yDisplayPosition, 16, 16, 0x80000000);
|
||||
GL11.glTranslatef(0, 0, -150);
|
||||
GL11.glEnable(GL11.GL_LIGHTING);
|
||||
GL11.glEnable(GL11.GL_DEPTH_TEST);
|
||||
|
||||
if (SearchField.searchInventories()) {
|
||||
ItemStack item = slot.getStack();
|
||||
|
||||
if (item == null ? !getSearchExpression().equals("") : !searchField.getFilter().matches(item)) {
|
||||
NEIClientUtils.gl2DRenderContext(() -> {
|
||||
GL11.glTranslatef(0, 0, 150);
|
||||
drawRect(slot.xDisplayPosition, slot.yDisplayPosition, 16, 16, 0x80000000);
|
||||
GL11.glTranslatef(0, 0, -150);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void drawIcon(int x, int y, Image image) {
|
||||
@@ -819,9 +919,15 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
drawTexturedModalRect(x2, y2, tx2, ty2, w2, h2); // bottom right
|
||||
}
|
||||
|
||||
public static void drawItemPresenceOverlay(int slotX, int slotY, boolean isPresent) {
|
||||
Image icon = itemPresenceOverlays[isPresent ? 1 : 0];
|
||||
drawIcon(slotX + 16 - icon.width, slotY + 16 - icon.height, icon);
|
||||
public static void drawItemPresenceOverlay(int slotX, int slotY, boolean isPresent, boolean slotHighlight) {
|
||||
|
||||
if (slotHighlight) {
|
||||
NEIClientUtils.gl2DRenderContext(() -> drawRect(slotX, slotY, 16, 16, isPresent ? 0x8000AA00 : 0x80AA0000));
|
||||
} else {
|
||||
Image icon = itemPresenceOverlays[isPresent ? 1 : 0];
|
||||
drawIcon(slotX + 16 - icon.width, slotY + 16 - icon.height, icon);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static LayoutManager instance() {
|
||||
|
||||
@@ -1,34 +1,20 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import static codechicken.lib.gui.GuiDraw.drawStringC;
|
||||
import static codechicken.nei.LayoutManager.bookmarkPanel;
|
||||
import static codechicken.nei.LayoutManager.bookmarksButton;
|
||||
import static codechicken.nei.LayoutManager.delete;
|
||||
import static codechicken.nei.LayoutManager.dropDown;
|
||||
import static codechicken.nei.LayoutManager.gamemode;
|
||||
import static codechicken.nei.LayoutManager.heal;
|
||||
import static codechicken.nei.LayoutManager.itemPanel;
|
||||
import static codechicken.nei.LayoutManager.itemPresenceOverlays;
|
||||
import static codechicken.nei.LayoutManager.magnet;
|
||||
import static codechicken.nei.LayoutManager.options;
|
||||
import static codechicken.nei.LayoutManager.presetsPanel;
|
||||
import static codechicken.nei.LayoutManager.rain;
|
||||
import static codechicken.nei.LayoutManager.searchField;
|
||||
import static codechicken.nei.LayoutManager.timeButtons;
|
||||
import static codechicken.nei.NEIClientConfig.canPerformAction;
|
||||
import static codechicken.nei.NEIClientConfig.disabledActions;
|
||||
import static codechicken.nei.NEIClientConfig.getMagnetMode;
|
||||
import static codechicken.nei.NEIClientConfig.isEnabled;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.api.LayoutStyle;
|
||||
import codechicken.nei.drawable.DrawableBuilder;
|
||||
|
||||
public class LayoutStyleMinecraft extends LayoutStyle {
|
||||
|
||||
protected static final int BUTTON_SIZE = 20;
|
||||
protected static final int MARGIN = 2;
|
||||
|
||||
public int buttonCount;
|
||||
public int leftSize;
|
||||
public int numButtons;
|
||||
@@ -40,19 +26,21 @@ public class LayoutStyleMinecraft extends LayoutStyle {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
delete.icon = new Image(144, 12, 12, 12);
|
||||
rain.icon = new Image(120, 12, 12, 12);
|
||||
gamemode.icons[0] = new Image(132, 12, 12, 12);
|
||||
gamemode.icons[1] = new Image(156, 12, 12, 12);
|
||||
gamemode.icons[2] = new Image(168, 12, 12, 12);
|
||||
magnet.icon = new Image(180, 24, 12, 12);
|
||||
timeButtons[0].icon = new Image(132, 24, 12, 12);
|
||||
timeButtons[1].icon = new Image(120, 24, 12, 12);
|
||||
timeButtons[2].icon = new Image(144, 24, 12, 12);
|
||||
timeButtons[3].icon = new Image(156, 24, 12, 12);
|
||||
heal.icon = new Image(168, 24, 12, 12);
|
||||
itemPresenceOverlays[0] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 0, 40, 8, 8).build();
|
||||
itemPresenceOverlays[1] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 8, 40, 8, 8).build();
|
||||
LayoutManager.delete.icon = new Image(144, 12, 12, 12);
|
||||
LayoutManager.rain.icon = new Image(120, 12, 12, 12);
|
||||
LayoutManager.gamemode.icons[0] = new Image(132, 12, 12, 12);
|
||||
LayoutManager.gamemode.icons[1] = new Image(156, 12, 12, 12);
|
||||
LayoutManager.gamemode.icons[2] = new Image(168, 12, 12, 12);
|
||||
LayoutManager.magnet.icon = new Image(180, 24, 12, 12);
|
||||
LayoutManager.timeButtons[0].icon = new Image(132, 24, 12, 12);
|
||||
LayoutManager.timeButtons[1].icon = new Image(120, 24, 12, 12);
|
||||
LayoutManager.timeButtons[2].icon = new Image(144, 24, 12, 12);
|
||||
LayoutManager.timeButtons[3].icon = new Image(156, 24, 12, 12);
|
||||
LayoutManager.heal.icon = new Image(168, 24, 12, 12);
|
||||
LayoutManager.itemPresenceOverlays[0] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 0, 40, 8, 8)
|
||||
.build();
|
||||
LayoutManager.itemPresenceOverlays[1] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 8, 40, 8, 8)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,90 +52,178 @@ public class LayoutStyleMinecraft extends LayoutStyle {
|
||||
public void layout(GuiContainer gui, VisiblityData visiblity) {
|
||||
reset();
|
||||
|
||||
leftSize = ItemPanels.bookmarkPanel.getWidth(gui);
|
||||
numButtons = Math.max(leftSize / 18, 1);
|
||||
leftSize = (gui.width - gui.xSize) / 2 - 4;
|
||||
numButtons = Math.max(leftSize / 20, 1);
|
||||
|
||||
delete.state = 0x4;
|
||||
if (NEIController.getDeleteMode()) delete.state |= 1;
|
||||
else if (!visiblity.enableDeleteMode) delete.state |= 2;
|
||||
|
||||
rain.state = 0x4;
|
||||
if (disabledActions.contains("rain")) rain.state |= 2;
|
||||
else if (NEIClientUtils.isRaining()) rain.state |= 1;
|
||||
|
||||
gamemode.state = 0x4;
|
||||
if (NEIClientUtils.getGamemode() != 0) {
|
||||
gamemode.state |= 0x1;
|
||||
gamemode.index = NEIClientUtils.getGamemode() - 1;
|
||||
} else {
|
||||
if (NEIClientUtils.isValidGamemode("creative")) gamemode.index = 0;
|
||||
else if (NEIClientUtils.isValidGamemode("creative+")) gamemode.index = 1;
|
||||
else if (NEIClientUtils.isValidGamemode("adventure")) gamemode.index = 2;
|
||||
LayoutManager.delete.state = 0x4;
|
||||
if (NEIController.getDeleteMode()) {
|
||||
LayoutManager.delete.state |= 1;
|
||||
} else if (!visiblity.enableDeleteMode) {
|
||||
LayoutManager.delete.state |= 2;
|
||||
}
|
||||
bookmarksButton.index = NEIClientConfig.isBookmarkPanelHidden() ? 0 : 1;
|
||||
options.index = NEIClientConfig.getCheatMode();
|
||||
|
||||
magnet.state = 0x4 | (getMagnetMode() ? 1 : 0);
|
||||
LayoutManager.rain.state = 0x4;
|
||||
if (NEIClientConfig.disabledActions.contains("rain")) {
|
||||
LayoutManager.rain.state |= 2;
|
||||
} else if (NEIClientUtils.isRaining()) {
|
||||
LayoutManager.rain.state |= 1;
|
||||
}
|
||||
|
||||
if (canPerformAction("delete")) layoutButton(delete);
|
||||
if (canPerformAction("rain")) layoutButton(rain);
|
||||
if (NEIClientUtils.isValidGamemode("creative") || NEIClientUtils.isValidGamemode("creative+")
|
||||
|| NEIClientUtils.isValidGamemode("adventure"))
|
||||
layoutButton(gamemode);
|
||||
if (canPerformAction("magnet")) layoutButton(magnet);
|
||||
if (canPerformAction("time")) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
timeButtons[i].state = disabledActions.contains(NEIActions.timeZones[i]) ? 2 : 0;
|
||||
layoutButton(timeButtons[i]);
|
||||
LayoutManager.gamemode.state = 0x4;
|
||||
if (NEIClientUtils.getGamemode() != 0) {
|
||||
LayoutManager.gamemode.state |= 0x1;
|
||||
LayoutManager.gamemode.index = NEIClientUtils.getGamemode() - 1;
|
||||
} else {
|
||||
if (NEIClientUtils.isValidGamemode("creative")) {
|
||||
LayoutManager.gamemode.index = 0;
|
||||
} else if (NEIClientUtils.isValidGamemode("creative+")) {
|
||||
LayoutManager.gamemode.index = 1;
|
||||
} else if (NEIClientUtils.isValidGamemode("adventure")) {
|
||||
LayoutManager.gamemode.index = 2;
|
||||
}
|
||||
}
|
||||
if (canPerformAction("heal")) layoutButton(heal);
|
||||
LayoutManager.bookmarksButton.index = NEIClientConfig.isBookmarkPanelHidden() ? 0 : 1;
|
||||
LayoutManager.options.index = NEIClientConfig.getCheatMode();
|
||||
|
||||
itemPanel.resize(gui);
|
||||
bookmarkPanel.resize(gui);
|
||||
LayoutManager.magnet.state = 0x4 | (NEIClientConfig.getMagnetMode() ? 1 : 0);
|
||||
|
||||
options.x = isEnabled() ? 0 : 6;
|
||||
options.y = isEnabled() ? gui.height - 22 : gui.height - 28;
|
||||
options.w = 22;
|
||||
options.h = 22;
|
||||
if (NEIClientConfig.canPerformAction("delete")) {
|
||||
layoutButton(LayoutManager.delete);
|
||||
}
|
||||
|
||||
bookmarksButton.x = 24 + (isEnabled() ? 0 : 6);
|
||||
bookmarksButton.y = isEnabled() ? gui.height - 22 : gui.height - 28;
|
||||
bookmarksButton.w = 22;
|
||||
bookmarksButton.h = 22;
|
||||
if (NEIClientConfig.canPerformAction("rain")) {
|
||||
layoutButton(LayoutManager.rain);
|
||||
}
|
||||
|
||||
dropDown.h = 18;
|
||||
dropDown.w = 150;
|
||||
dropDown.y = 0;
|
||||
dropDown.x = (gui.width - gui.xSize) / 2 + gui.xSize - dropDown.w;
|
||||
if (NEIClientUtils.isValidGamemode("creative") || NEIClientUtils.isValidGamemode("creative+")
|
||||
|| NEIClientUtils.isValidGamemode("adventure")) {
|
||||
layoutButton(LayoutManager.gamemode);
|
||||
}
|
||||
|
||||
presetsPanel.h = 16;
|
||||
presetsPanel.w = 150;
|
||||
presetsPanel.y = 2;
|
||||
presetsPanel.x = (gui.width - gui.xSize) / 2 + gui.xSize - presetsPanel.w;
|
||||
if (NEIClientConfig.canPerformAction("magnet")) {
|
||||
layoutButton(LayoutManager.magnet);
|
||||
}
|
||||
|
||||
searchField.h = 20;
|
||||
if (NEIClientConfig.isSearchWidgetCentered()) {
|
||||
searchField.w = 150;
|
||||
searchField.x = (gui.width - searchField.w) / 2;
|
||||
if (NEIClientConfig.canPerformAction("time")) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
LayoutManager.timeButtons[i].state = NEIClientConfig.disabledActions.contains(NEIActions.timeZones[i])
|
||||
? 2
|
||||
: 0;
|
||||
layoutButton(LayoutManager.timeButtons[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (NEIClientConfig.canPerformAction("heal")) {
|
||||
layoutButton(LayoutManager.heal);
|
||||
}
|
||||
|
||||
layoutFooter(gui, visiblity);
|
||||
|
||||
LayoutManager.itemPanel.resize(gui);
|
||||
LayoutManager.bookmarkPanel.resize(gui);
|
||||
LayoutManager.itemZoom.resize(gui);
|
||||
}
|
||||
|
||||
protected void layoutFooter(GuiContainer gui, VisiblityData visiblity) {
|
||||
|
||||
LayoutManager.options.x = MARGIN;
|
||||
LayoutManager.options.y = gui.height - BUTTON_SIZE - MARGIN;
|
||||
LayoutManager.options.w = LayoutManager.options.h = BUTTON_SIZE;
|
||||
|
||||
LayoutManager.bookmarksButton.x = LayoutManager.options.x + LayoutManager.options.w + MARGIN;
|
||||
LayoutManager.bookmarksButton.y = gui.height - BUTTON_SIZE - MARGIN;
|
||||
LayoutManager.bookmarksButton.w = LayoutManager.bookmarksButton.h = BUTTON_SIZE;
|
||||
|
||||
final Rectangle4i searchArea = getSearchFieldArea(gui);
|
||||
final Rectangle4i quantityArea = getQuantityFieldArea(visiblity);
|
||||
|
||||
LayoutManager.searchField.x = searchArea.x;
|
||||
LayoutManager.searchField.y = searchArea.y;
|
||||
LayoutManager.searchField.w = searchArea.w;
|
||||
LayoutManager.searchField.h = searchArea.h;
|
||||
|
||||
if (!NEIClientConfig.subsetWidgetOnTop() && visiblity.showSubsetDropdown) {
|
||||
LayoutManager.dropDown.x = searchArea.x;
|
||||
LayoutManager.dropDown.y = searchArea.y;
|
||||
LayoutManager.dropDown.h = LayoutManager.dropDown.w = BUTTON_SIZE;
|
||||
|
||||
LayoutManager.searchField.x += BUTTON_SIZE;
|
||||
LayoutManager.searchField.w -= BUTTON_SIZE;
|
||||
} else {
|
||||
searchField.w = (int) (itemPanel.w * (NEIClientConfig.showItemQuantityWidget() ? 0.7 : 1));
|
||||
searchField.x = itemPanel.x;
|
||||
LayoutManager.dropDown.h = 16;
|
||||
LayoutManager.dropDown.w = 150;
|
||||
LayoutManager.dropDown.y = MARGIN;
|
||||
LayoutManager.dropDown.x = (gui.width - LayoutManager.dropDown.w) / 2;
|
||||
}
|
||||
searchField.y = gui.height - searchField.h - 2;
|
||||
|
||||
if (!visiblity.showItemSection) {
|
||||
searchField.setFocus(false);
|
||||
if (quantityArea.w == ItemPanels.itemPanel.w) {
|
||||
LayoutManager.more.w = LayoutManager.less.w = BUTTON_SIZE;
|
||||
LayoutManager.more.h = LayoutManager.less.h = LayoutManager.quantity.h = quantityArea.h;
|
||||
LayoutManager.more.y = LayoutManager.less.y = LayoutManager.quantity.y = quantityArea.y;
|
||||
|
||||
LayoutManager.less.x = quantityArea.x;
|
||||
LayoutManager.more.x = quantityArea.x2() - BUTTON_SIZE;
|
||||
|
||||
LayoutManager.quantity.x = LayoutManager.less.x + LayoutManager.less.w + 1;
|
||||
LayoutManager.quantity.w = LayoutManager.more.x - LayoutManager.quantity.x - 1;
|
||||
} else {
|
||||
LayoutManager.quantity.x = quantityArea.x;
|
||||
LayoutManager.quantity.w = quantityArea.w - 18;
|
||||
LayoutManager.quantity.y = LayoutManager.more.y = quantityArea.y;
|
||||
LayoutManager.quantity.h = quantityArea.h;
|
||||
|
||||
LayoutManager.more.w = LayoutManager.less.w = 18;
|
||||
LayoutManager.more.x = LayoutManager.less.x = LayoutManager.quantity.x + LayoutManager.quantity.w;
|
||||
LayoutManager.more.h = LayoutManager.less.h = LayoutManager.quantity.h / 2;
|
||||
LayoutManager.less.y = LayoutManager.more.y + LayoutManager.more.h;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Rectangle4i getSearchFieldArea(GuiContainer gui) {
|
||||
final Rectangle4i area = new Rectangle4i(0, 0, 0, BUTTON_SIZE);
|
||||
|
||||
if (NEIClientConfig.isSearchWidgetCentered()) {
|
||||
area.w = Math.min(gui.xSize, 176) - MARGIN * 2;
|
||||
area.x = (gui.width - area.w) / 2;
|
||||
area.y = gui.height - BUTTON_SIZE - MARGIN;
|
||||
} else if (NEIClientConfig.showItemQuantityWidget()) {
|
||||
area.w = ItemPanels.itemPanel.w - (int) Math.max(BUTTON_SIZE * 2.5f, ItemPanels.itemPanel.w * 0.3f) - 1;
|
||||
area.x = ItemPanels.itemPanel.x;
|
||||
area.y = ItemPanels.itemPanel.y + ItemPanels.itemPanel.h - BUTTON_SIZE;
|
||||
} else {
|
||||
area.w = ItemPanels.itemPanel.w;
|
||||
area.x = ItemPanels.itemPanel.x;
|
||||
area.y = ItemPanels.itemPanel.y + ItemPanels.itemPanel.h - BUTTON_SIZE;
|
||||
}
|
||||
|
||||
return area;
|
||||
}
|
||||
|
||||
private Rectangle4i getQuantityFieldArea(VisiblityData visiblity) {
|
||||
final Rectangle4i area = new Rectangle4i(0, 0, 0, BUTTON_SIZE);
|
||||
|
||||
if (!visiblity.showSearchSection || NEIClientConfig.isSearchWidgetCentered()) {
|
||||
area.w = ItemPanels.itemPanel.w;
|
||||
area.x = ItemPanels.itemPanel.x;
|
||||
} else {
|
||||
area.w = (int) Math.max(BUTTON_SIZE * 2.5f, ItemPanels.itemPanel.w * 0.3f);
|
||||
area.x = ItemPanels.itemPanel.x + ItemPanels.itemPanel.w - area.w;
|
||||
}
|
||||
|
||||
area.y = ItemPanels.itemPanel.y + ItemPanels.itemPanel.h - BUTTON_SIZE;
|
||||
|
||||
return area;
|
||||
}
|
||||
|
||||
public void layoutButton(Button button) {
|
||||
button.x = 2 + (buttonCount % numButtons) * 19;
|
||||
button.y = 2 + (buttonCount / numButtons) * 18;
|
||||
|
||||
button.h = 17;
|
||||
button.w = button.contentWidth() + 6;
|
||||
|
||||
button.x = MARGIN + (buttonCount % numButtons) * (button.w + MARGIN);
|
||||
button.y = MARGIN + (buttonCount / numButtons) * (button.h + MARGIN);
|
||||
|
||||
buttonCount++;
|
||||
}
|
||||
|
||||
@@ -181,9 +257,16 @@ public class LayoutStyleMinecraft extends LayoutStyle {
|
||||
|
||||
@Override
|
||||
public void drawSubsetTag(String text, int x, int y, int w, int h, int state, boolean mouseover) {
|
||||
if (state == 1) GL11.glColor4f(0.65F, 0.65F, 0.65F, 1.0F);
|
||||
else GL11.glColor4f(1, 1, 1, 1);
|
||||
if (state == 1) {
|
||||
GL11.glColor4f(0.65F, 0.65F, 0.65F, 1.0F);
|
||||
} else {
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
LayoutManager.drawButtonBackground(x, y, w, h, false, state == 0 ? 0 : 1);
|
||||
if (text != null) drawStringC(text, x, y, w, h, state == 2 ? 0xFFE0E0E0 : 0xFFA0A0A0);
|
||||
|
||||
if (text != null) {
|
||||
drawStringC(text, x, y, w, h, mouseover ? 0xFFFFFFA0 : (state == 2 ? 0xFFE0E0E0 : 0xFFA0A0A0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import static codechicken.nei.PacketIDs.C2S;
|
||||
import static codechicken.nei.PacketIDs.S2C;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.inventory.GuiInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -20,37 +23,37 @@ public class NEICPH implements IClientPacketHandler {
|
||||
@Override
|
||||
public void handlePacket(PacketCustom packet, Minecraft mc, INetHandlerPlayClient netHandler) {
|
||||
switch (packet.getType()) {
|
||||
case 1:
|
||||
case S2C.SEND_SERVER_SIDE_CHECK:
|
||||
handleSMPCheck(packet.readUByte(), packet.readString(), mc.theWorld);
|
||||
break;
|
||||
case 10:
|
||||
case S2C.SEND_LOGIN_STATE:
|
||||
handleLoginState(packet);
|
||||
break;
|
||||
case 11:
|
||||
case S2C.SEND_ACTION_DISABLED:
|
||||
handleActionDisabled(packet);
|
||||
break;
|
||||
case 12:
|
||||
case S2C.SEND_ACTION_ENABLED:
|
||||
handleActionEnabled(packet);
|
||||
break;
|
||||
case 13:
|
||||
case S2C.SEND_MAGNETIC_ITEM:
|
||||
ClientHandler.instance().addSMPMagneticItem(packet.readInt(), mc.theWorld);
|
||||
break;
|
||||
case 14:
|
||||
case S2C.SEND_GAME_MODE:
|
||||
handleGamemode(mc, packet.readUByte());
|
||||
break;
|
||||
case 21:
|
||||
case S2C.OPEN_ENCHANTMENT_GUI:
|
||||
ClientUtils.openSMPGui(
|
||||
packet.readUByte(),
|
||||
new GuiEnchantmentModifier(mc.thePlayer.inventory, mc.theWorld, 0, 0, 0));
|
||||
break;
|
||||
case 23:
|
||||
case S2C.SET_CREATIVE_PLUS_MODE:
|
||||
if (packet.readBoolean()) ClientUtils.openSMPGui(
|
||||
packet.readUByte(),
|
||||
new GuiExtendedCreativeInv(
|
||||
new ContainerCreativeInv(mc.thePlayer, new ExtendedCreativeInv(null, Side.CLIENT))));
|
||||
else mc.displayGuiScreen(new GuiInventory(mc.thePlayer));
|
||||
break;
|
||||
case 24:
|
||||
case S2C.OPEN_POTION_GUI:
|
||||
ClientUtils.openSMPGui(packet.readUByte(), new GuiPotionCreator(mc.thePlayer.inventory));
|
||||
break;
|
||||
}
|
||||
@@ -102,7 +105,7 @@ public class NEICPH implements IClientPacketHandler {
|
||||
try {
|
||||
ClientHandler.instance().loadWorld(world, true);
|
||||
NEIClientConfig.setHasSMPCounterPart(true);
|
||||
NEIClientConfig.loadWorld(getSaveName(worldName));
|
||||
NEIClientConfig.loadWorld(getSaveName());
|
||||
sendRequestLoginInfo();
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.error("Error handling SMP Check", e);
|
||||
@@ -110,14 +113,14 @@ public class NEICPH implements IClientPacketHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private static String getSaveName(String worldName) {
|
||||
private static String getSaveName() {
|
||||
if (Minecraft.getMinecraft().isSingleplayer()) return "local/" + ClientUtils.getWorldSaveName();
|
||||
|
||||
return "remote/" + ClientUtils.getServerIP().replace(':', '~') + "/" + worldName;
|
||||
return "remote/" + ClientUtils.getServerIP().replace(':', '~');
|
||||
}
|
||||
|
||||
public static void sendGiveItem(ItemStack spawnstack, boolean infinite, boolean doSpawn) {
|
||||
PacketCustom packet = new PacketCustom(channel, 1);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.GIVE_ITEM);
|
||||
packet.writeItemStack(spawnstack, true);
|
||||
packet.writeBoolean(infinite);
|
||||
packet.writeBoolean(doSpawn);
|
||||
@@ -125,7 +128,7 @@ public class NEICPH implements IClientPacketHandler {
|
||||
}
|
||||
|
||||
public static void sendDeleteAllItems() {
|
||||
PacketCustom packet = new PacketCustom(channel, 4);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.DELETE_ALL_ITEMS);
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
@@ -139,18 +142,18 @@ public class NEICPH implements IClientPacketHandler {
|
||||
sendSetSlot(slot, item, false);
|
||||
}
|
||||
|
||||
PacketCustom packet = new PacketCustom(channel, 11);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.REQUEST_CONTAINER_CONTENTS);
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
public static void sendRequestContainer() {
|
||||
PacketCustom packet = new PacketCustom(channel, 16);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.REQUEST_CONTAINER);
|
||||
packet.writeInt(Minecraft.getMinecraft().thePlayer.openContainer.getInventory().size());
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
public static void sendSetSlot(int slot, ItemStack stack, boolean container) {
|
||||
PacketCustom packet = new PacketCustom(channel, 5);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.SET_SLOT);
|
||||
packet.writeBoolean(container);
|
||||
packet.writeShort(slot);
|
||||
packet.writeItemStack(stack);
|
||||
@@ -158,38 +161,44 @@ public class NEICPH implements IClientPacketHandler {
|
||||
}
|
||||
|
||||
private static void sendRequestLoginInfo() {
|
||||
PacketCustom packet = new PacketCustom(channel, 10);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.REQUEST_LOGIN_INFO);
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
public static void sendToggleMagnetMode() {
|
||||
PacketCustom packet = new PacketCustom(channel, 6);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.TOGGLE_MAGNET);
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
public static void sendSetTime(int hour) {
|
||||
PacketCustom packet = new PacketCustom(channel, 7);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.SET_TIME);
|
||||
packet.writeByte(hour);
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
public static void sendHeal() {
|
||||
PacketCustom packet = new PacketCustom(channel, 8);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.HEAL);
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
public static void sendToggleRain() {
|
||||
PacketCustom packet = new PacketCustom(channel, 9);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.TOGGLE_RAIN);
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
public static void sendChatLink(ItemStack stackover) {
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.SEND_CHAT_ITEM_LINK);
|
||||
packet.writeItemStack(stackover);
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
public static void sendOpenEnchantmentWindow() {
|
||||
PacketCustom packet = new PacketCustom(channel, 21);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.REQUEST_ENCHANTMENT_GUI);
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
public static void sendModifyEnchantment(int enchID, int level, boolean add) {
|
||||
PacketCustom packet = new PacketCustom(channel, 22);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.MODIFY_ENCHANTMENT);
|
||||
packet.writeByte(enchID);
|
||||
packet.writeByte(level);
|
||||
packet.writeBoolean(add);
|
||||
@@ -197,30 +206,30 @@ public class NEICPH implements IClientPacketHandler {
|
||||
}
|
||||
|
||||
public static void sendSetPropertyDisabled(String name, boolean enable) {
|
||||
PacketCustom packet = new PacketCustom(channel, 12);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.CHANGE_PROPERTY);
|
||||
packet.writeString(name);
|
||||
packet.writeBoolean(enable);
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
public static void sendGamemode(int mode) {
|
||||
new PacketCustom(channel, 13).writeByte(mode).sendToServer();
|
||||
new PacketCustom(channel, C2S.SET_GAME_MODE).writeByte(mode).sendToServer();
|
||||
}
|
||||
|
||||
public static void sendCreativeInv(boolean open) {
|
||||
PacketCustom packet = new PacketCustom(channel, 23);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.SET_CREATIVE_PLUS_MODE);
|
||||
packet.writeBoolean(open);
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
public static void sendCreativeScroll(int steps) {
|
||||
PacketCustom packet = new PacketCustom(channel, 14);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.CYCLE_CREATIVE_INV);
|
||||
packet.writeInt(steps);
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
public static void sendMobSpawnerID(int x, int y, int z, String mobtype) {
|
||||
PacketCustom packet = new PacketCustom(channel, 15);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.SEND_MOB_SPAWNER_ID);
|
||||
packet.writeCoord(x, y, z);
|
||||
packet.writeString(mobtype);
|
||||
packet.sendToServer();
|
||||
@@ -231,13 +240,13 @@ public class NEICPH implements IClientPacketHandler {
|
||||
InventoryUtils.readItemStacksFromTag(
|
||||
potionStore,
|
||||
NEIClientConfig.global.nbt.getCompoundTag("potionStore").getTagList("items", 10));
|
||||
PacketCustom packet = new PacketCustom(channel, 24);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.REQUEST_POTION_GUI);
|
||||
for (ItemStack stack : potionStore) packet.writeItemStack(stack);
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
public static void sendDummySlotSet(int slotNumber, ItemStack stack) {
|
||||
PacketCustom packet = new PacketCustom(channel, 25);
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.SET_DUMMY_SLOT);
|
||||
packet.writeShort(slotNumber);
|
||||
packet.writeItemStack(stack, true);
|
||||
packet.sendToServer();
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -8,6 +8,7 @@ import static codechicken.nei.NEIClientConfig.hasSMPCounterPart;
|
||||
import static codechicken.nei.NEIClientConfig.invCreativeMode;
|
||||
import static codechicken.nei.NEIClientConfig.world;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.math.BigInteger;
|
||||
@@ -25,43 +26,79 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ChatComponentTranslation;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.lib.inventory.InventoryRange;
|
||||
import codechicken.lib.inventory.InventoryUtils;
|
||||
import codechicken.lib.util.LangProxy;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.api.GuiInfo;
|
||||
import codechicken.nei.api.IInfiniteItemHandler;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.util.NEIKeyboardUtils;
|
||||
import codechicken.nei.util.NEIMouseUtils;
|
||||
|
||||
public class NEIClientUtils extends NEIServerUtils {
|
||||
|
||||
public static class Alignment {
|
||||
|
||||
public final int x, y;
|
||||
|
||||
public static final Alignment TopLeft = new Alignment(-1, -1);
|
||||
public static final Alignment TopCenter = new Alignment(0, -1);
|
||||
public static final Alignment TopRight = new Alignment(1, -1);
|
||||
public static final Alignment CenterLeft = new Alignment(-1, 0);
|
||||
public static final Alignment Center = new Alignment(0, 0);
|
||||
public static final Alignment CenterRight = new Alignment(1, 0);
|
||||
public static final Alignment BottomLeft = new Alignment(-1, 1);
|
||||
public static final Alignment BottomCenter = new Alignment(0, 1);
|
||||
public static final Alignment BottomRight = new Alignment(1, 1);
|
||||
|
||||
public Alignment(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public float getX(float parentWidth, float childWidth) {
|
||||
final float x = (this.x + 1) / 2f;
|
||||
return parentWidth * x - childWidth * x;
|
||||
}
|
||||
|
||||
public float getY(float parentHeight, float childHeight) {
|
||||
final float y = (this.y + 1) / 2f;
|
||||
return parentHeight * y - childHeight * y;
|
||||
}
|
||||
}
|
||||
|
||||
public static LangProxy lang = new LangProxy("nei");
|
||||
|
||||
/** Formats a number with group separator and at most 2 fraction digits. */
|
||||
private static final Map<Locale, DecimalFormat> decimalFormatters = new HashMap<>();
|
||||
|
||||
public static final int ALT_HASH = 1 << 27;
|
||||
public static final int SHIFT_HASH = 1 << 26;
|
||||
public static final int CTRL_HASH = 1 << 25;
|
||||
public static final int ALT_HASH = NEIKeyboardUtils.ALT_HASH;
|
||||
public static final int SHIFT_HASH = NEIKeyboardUtils.SHIFT_HASH;
|
||||
public static final int CTRL_HASH = NEIKeyboardUtils.CTRL_HASH;
|
||||
|
||||
public static Minecraft mc() {
|
||||
return Minecraft.getMinecraft();
|
||||
@@ -308,7 +345,7 @@ public class NEIClientUtils extends NEIServerUtils {
|
||||
}
|
||||
|
||||
public static void sendCommand(String command, Object... args) {
|
||||
if (command.length() == 0) return;
|
||||
if (command.isEmpty()) return;
|
||||
|
||||
NumberFormat numberformat = NumberFormat.getIntegerInstance();
|
||||
numberformat.setGroupingUsed(false);
|
||||
@@ -333,6 +370,10 @@ public class NEIClientUtils extends NEIServerUtils {
|
||||
else sendCommand(getStringSetting("command.heal"), mc().thePlayer.getCommandSenderName());
|
||||
}
|
||||
|
||||
public static void sendChatItemLink(ItemStack stackover) {
|
||||
if (hasSMPCounterPart()) NEICPH.sendChatLink(stackover);
|
||||
}
|
||||
|
||||
public static void toggleMagnetMode() {
|
||||
if (hasSMPCounterPart()) NEICPH.sendToggleMagnetMode();
|
||||
}
|
||||
@@ -367,18 +408,23 @@ public class NEIClientUtils extends NEIServerUtils {
|
||||
}
|
||||
|
||||
public static String cropText(FontRenderer fontRenderer, String text, int containerWidth) {
|
||||
|
||||
int textWidth = fontRenderer.getStringWidth(text);
|
||||
|
||||
if (textWidth > containerWidth) {
|
||||
textWidth += fontRenderer.getStringWidth("...");
|
||||
int dots = fontRenderer.getStringWidth("...");
|
||||
|
||||
while (textWidth > containerWidth) {
|
||||
textWidth -= fontRenderer.getCharWidth(text.charAt(text.length() - 1));
|
||||
text = text.substring(0, text.length() - 1);
|
||||
if (containerWidth > dots) {
|
||||
textWidth += dots;
|
||||
|
||||
while (textWidth > containerWidth) {
|
||||
textWidth -= fontRenderer.getCharWidth(text.charAt(text.length() - 1));
|
||||
text = text.substring(0, text.length() - 1);
|
||||
}
|
||||
|
||||
return text + "...";
|
||||
}
|
||||
|
||||
return text + "...";
|
||||
return "...";
|
||||
}
|
||||
|
||||
return text;
|
||||
@@ -394,7 +440,6 @@ public class NEIClientUtils extends NEIServerUtils {
|
||||
|
||||
public static void setItemQuantity(int i) {
|
||||
world.nbt.setInteger("quantity", i);
|
||||
world.saveNBT();
|
||||
}
|
||||
|
||||
public static GuiContainer getGuiContainer() {
|
||||
@@ -434,11 +479,7 @@ public class NEIClientUtils extends NEIServerUtils {
|
||||
if (Keyboard.getEventKeyState()) {
|
||||
final int keycode = Keyboard.getEventKey();
|
||||
|
||||
if (keycode != Keyboard.KEY_LSHIFT && keycode != Keyboard.KEY_RSHIFT
|
||||
&& keycode != Keyboard.KEY_LCONTROL
|
||||
&& keycode != Keyboard.KEY_RCONTROL
|
||||
&& keycode != Keyboard.KEY_LMENU
|
||||
&& keycode != Keyboard.KEY_RMENU) {
|
||||
if (!NEIKeyboardUtils.isHashKey(keycode)) {
|
||||
return getMetaHash() + keycode;
|
||||
}
|
||||
}
|
||||
@@ -446,6 +487,22 @@ public class NEIClientUtils extends NEIServerUtils {
|
||||
return Keyboard.CHAR_NONE;
|
||||
}
|
||||
|
||||
public static String getKeyName(int keyBind, int mouseBind) {
|
||||
StringJoiner keyText = new StringJoiner(" + ");
|
||||
String keyHash = keyBind == Keyboard.KEY_NONE ? "" : NEIKeyboardUtils.getKeyName(keyBind);
|
||||
String mouseHash = mouseBind == NEIMouseUtils.MOUSE_BTN_NONE ? "" : NEIMouseUtils.getKeyName(mouseBind);
|
||||
|
||||
if (!keyHash.isEmpty()) {
|
||||
keyText.add(keyHash);
|
||||
}
|
||||
|
||||
if (!mouseHash.isEmpty()) {
|
||||
keyText.add(mouseHash);
|
||||
}
|
||||
|
||||
return keyText.toString();
|
||||
}
|
||||
|
||||
public static void playClickSound() {
|
||||
mc().getSoundHandler()
|
||||
.playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F));
|
||||
@@ -457,16 +514,9 @@ public class NEIClientUtils extends NEIServerUtils {
|
||||
String stackTrace = cause + sw;
|
||||
if (buffer.contains(stackTrace)) return;
|
||||
|
||||
System.err.println("Error while rendering: " + cause);
|
||||
System.err.println("Error while rendering: " + cause + " (" + e.getMessage() + ")");
|
||||
e.printStackTrace();
|
||||
buffer.add(stackTrace);
|
||||
|
||||
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
|
||||
if (player != null) {
|
||||
IChatComponent chat = new ChatComponentTranslation("nei.chat.render.error");
|
||||
chat.getChatStyle().setColor(EnumChatFormatting.RED);
|
||||
player.addChatComponentMessage(chat);
|
||||
}
|
||||
}
|
||||
|
||||
public static void reportErrorBuffered(Throwable e, Set<String> buffer, ItemStack cause) {
|
||||
@@ -476,4 +526,66 @@ public class NEIClientUtils extends NEIServerUtils {
|
||||
reportErrorBuffered(e, buffer, "null");
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawRect(double left, double top, double width, double height, Color color) {
|
||||
Tessellator tessellator = Tessellator.instance;
|
||||
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
OpenGlHelper.glBlendFunc(770, 771, 1, 0);
|
||||
GL11.glColor4f(color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
|
||||
tessellator.startDrawingQuads();
|
||||
tessellator.addVertex(left, top + height, 0.0D);
|
||||
tessellator.addVertex(left + width, top + height, 0.0D);
|
||||
tessellator.addVertex(left + width, top, 0.0D);
|
||||
tessellator.addVertex(left, top, 0.0D);
|
||||
tessellator.draw();
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
GL11.glDisable(GL11.GL_BLEND);
|
||||
}
|
||||
|
||||
public static void drawNEIOverlayText(String text, Rectangle4i rect, float scale, int color, boolean shadow,
|
||||
Alignment alignment) {
|
||||
final float screenScale = mc().currentScreen.width * 1f / mc().displayWidth;
|
||||
final double smallTextScale = Math
|
||||
.max(screenScale, (Math.max(scale, 1f) * (GuiDraw.fontRenderer.getUnicodeFlag() ? 3F / 4F : 1F / 2F)));
|
||||
|
||||
NEIClientUtils.gl2DRenderContext(() -> {
|
||||
final int width = GuiDraw.fontRenderer.getStringWidth(text);
|
||||
final float partW = rect.w / 2f;
|
||||
final float partH = rect.h / 2f;
|
||||
final double offsetX = Math
|
||||
.ceil(rect.x + partW + partW * alignment.x - (width / 2f * (alignment.x + 1)) * smallTextScale);
|
||||
final double offsetY = Math.ceil(
|
||||
rect.y + partH
|
||||
+ partH * alignment.y
|
||||
- (GuiDraw.fontRenderer.FONT_HEIGHT / 2f * (alignment.y + 1)) * smallTextScale);
|
||||
|
||||
GL11.glTranslated(offsetX, offsetY, 0);
|
||||
GL11.glScaled(smallTextScale, smallTextScale, 1);
|
||||
GuiDraw.fontRenderer.drawString(text, 0, 0, color, shadow);
|
||||
GL11.glScaled(1 / smallTextScale, 1 / smallTextScale, 1);
|
||||
GL11.glTranslated(-1 * offsetX, -1 * offsetY, 0);
|
||||
});
|
||||
}
|
||||
|
||||
public static void drawNEIOverlayText(String text, int x, int y) {
|
||||
drawNEIOverlayText(text, new Rectangle4i(x, y, 16, 16), 0.5f, 0xFDD835, false, Alignment.TopLeft);
|
||||
}
|
||||
|
||||
public static void gl2DRenderContext(Runnable callback) {
|
||||
boolean isLighting = GL11.glGetBoolean(GL11.GL_LIGHTING);
|
||||
boolean isDepthTest = GL11.glGetBoolean(GL11.GL_DEPTH_TEST);
|
||||
boolean isAlphaTest = GL11.glGetBoolean(GL11.GL_ALPHA_TEST);
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
GL11.glEnable(GL11.GL_ALPHA_TEST);
|
||||
GL11.glDisable(GL11.GL_DEPTH_TEST);
|
||||
|
||||
callback.run();
|
||||
|
||||
if (isLighting) GL11.glEnable(GL11.GL_LIGHTING);
|
||||
if (isDepthTest) GL11.glEnable(GL11.GL_DEPTH_TEST);
|
||||
if (!isAlphaTest) GL11.glDisable(GL11.GL_ALPHA_TEST);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,16 +11,22 @@ import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.inventory.SlotCrafting;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.client.ClientCommandHandler;
|
||||
|
||||
import codechicken.core.CommonUtils;
|
||||
import codechicken.nei.api.API;
|
||||
import codechicken.nei.api.GuiInfo;
|
||||
import codechicken.nei.api.IInfiniteItemHandler;
|
||||
import codechicken.nei.api.INEIGuiHandler;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.commands.CommandBookmarkAdd;
|
||||
import codechicken.nei.commands.CommandRecipeId;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.guihook.IContainerInputHandler;
|
||||
import codechicken.nei.guihook.IContainerSlotClickHandler;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class NEIController implements IContainerSlotClickHandler, IContainerInputHandler {
|
||||
|
||||
@@ -39,6 +45,8 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
|
||||
public static void load() {
|
||||
GuiContainerManager.addSlotClickHandler(instance);
|
||||
GuiContainerManager.addInputHandler(instance);
|
||||
|
||||
if (CommonUtils.isClient()) registerClientCommands();
|
||||
}
|
||||
|
||||
public static void load(GuiContainer gui) {
|
||||
@@ -56,6 +64,12 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
|
||||
return gui.field_147007_t && gui.field_147008_s.size() > 1;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static void registerClientCommands() {
|
||||
ClientCommandHandler.instance.registerCommand(new CommandBookmarkAdd());
|
||||
ClientCommandHandler.instance.registerCommand(new CommandRecipeId());
|
||||
}
|
||||
|
||||
public static void updateUnlimitedItems(InventoryPlayer inventory) {
|
||||
if (!NEIClientConfig.canPerformAction("item") || !NEIClientConfig.hasSMPCounterPart()) return;
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
@@ -20,8 +25,10 @@ import cpw.mods.fml.common.DummyModContainer;
|
||||
import cpw.mods.fml.common.LoadController;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModMetadata;
|
||||
import cpw.mods.fml.common.discovery.ASMDataTable;
|
||||
import cpw.mods.fml.common.event.FMLInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLInterModComms;
|
||||
import cpw.mods.fml.common.event.FMLLoadCompleteEvent;
|
||||
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.versioning.ArtifactVersion;
|
||||
@@ -33,6 +40,9 @@ public class NEIModContainer extends DummyModContainer {
|
||||
public static LinkedList<IConfigureNEI> plugins = new LinkedList<>();
|
||||
|
||||
private static boolean gregTech5Loaded;
|
||||
private static boolean gtnhLibLoaded;
|
||||
|
||||
private static ASMDataTable asmDataTable;
|
||||
|
||||
public NEIModContainer() {
|
||||
super(getModMetadata());
|
||||
@@ -54,16 +64,23 @@ public class NEIModContainer extends DummyModContainer {
|
||||
return gregTech5Loaded;
|
||||
}
|
||||
|
||||
public static boolean isGTNHLibLoaded() {
|
||||
return gtnhLibLoaded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ArtifactVersion> getRequirements() {
|
||||
Set<ArtifactVersion> deps = new HashSet<>();
|
||||
deps.add(VersionParser.parseVersionReference("CodeChickenCore@[" + CodeChickenCorePlugin.version + ",)"));
|
||||
deps.add(VersionParser.parseVersionReference("CodeChickenCore@[" + codechicken.core.asm.Tags.VERSION + ",)"));
|
||||
return deps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ArtifactVersion> getDependencies() {
|
||||
return new LinkedList<>(getRequirements());
|
||||
List<ArtifactVersion> deps = new ArrayList<>();
|
||||
deps.add(VersionParser.parseVersionReference("CodeChickenCore@[" + codechicken.core.asm.Tags.VERSION + ",)"));
|
||||
deps.add(VersionParser.parseVersionReference("gtnhlib@[0.6.0,)"));
|
||||
return deps;
|
||||
}
|
||||
|
||||
private String description;
|
||||
@@ -101,7 +118,9 @@ public class NEIModContainer extends DummyModContainer {
|
||||
@Subscribe
|
||||
public void preInit(FMLPreInitializationEvent event) {
|
||||
gregTech5Loaded = Loader.isModLoaded("gregtech") && !Loader.isModLoaded("gregapi_post");
|
||||
gtnhLibLoaded = Loader.isModLoaded("gtnhlib");
|
||||
if (CommonUtils.isClient()) ClientHandler.preInit();
|
||||
asmDataTable = event.getAsmData();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@@ -114,11 +133,20 @@ public class NEIModContainer extends DummyModContainer {
|
||||
@Subscribe
|
||||
public void postInit(FMLPostInitializationEvent event) {
|
||||
if (CommonUtils.isClient()) {
|
||||
GuiRecipeTab.loadHandlerInfo();
|
||||
ClientHandler.postInit();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void loadComplete(FMLLoadCompleteEvent event) {
|
||||
if (CommonUtils.isClient()) {
|
||||
GuiRecipeTab.loadHandlerInfo();
|
||||
ClientHandler.loadPluginsList();
|
||||
ClientHandler.loadHandlerOrdering();
|
||||
asmDataTable = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void handleIMCMessages(FMLInterModComms.IMCEvent event) {
|
||||
IMCHandler.processIMC(event.getMessages());
|
||||
@@ -138,4 +166,8 @@ public class NEIModContainer extends DummyModContainer {
|
||||
public Class<?> getCustomResourcePackClass() {
|
||||
return getSource().isDirectory() ? FMLFolderResourcePack.class : FMLFileResourcePack.class;
|
||||
}
|
||||
|
||||
public static ASMDataTable getAsmDataTable() {
|
||||
return asmDataTable;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import static codechicken.nei.PacketIDs.C2S;
|
||||
import static codechicken.nei.PacketIDs.S2C;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -28,66 +31,73 @@ public class NEISPH implements IServerPacketHandler {
|
||||
if (!NEIServerConfig.authenticatePacket(sender, packet)) return;
|
||||
|
||||
switch (packet.getType()) {
|
||||
case 1:
|
||||
case C2S.GIVE_ITEM:
|
||||
handleGiveItem(sender, packet);
|
||||
break;
|
||||
case 4:
|
||||
case C2S.DELETE_ALL_ITEMS:
|
||||
NEIServerUtils.deleteAllItems(sender);
|
||||
break;
|
||||
case 5:
|
||||
case C2S.SET_SLOT:
|
||||
setInventorySlot(sender, packet);
|
||||
break;
|
||||
case 6:
|
||||
case C2S.TOGGLE_MAGNET:
|
||||
NEIServerUtils.toggleMagnetMode(sender);
|
||||
break;
|
||||
case 7:
|
||||
case C2S.SET_TIME:
|
||||
NEIServerUtils.setHourForward(sender.worldObj, packet.readUByte(), true);
|
||||
break;
|
||||
case 8:
|
||||
case C2S.HEAL:
|
||||
NEIServerUtils.healPlayer(sender);
|
||||
break;
|
||||
case 9:
|
||||
case C2S.TOGGLE_RAIN:
|
||||
NEIServerUtils.toggleRaining(sender.worldObj, true);
|
||||
break;
|
||||
case 10:
|
||||
case C2S.REQUEST_LOGIN_INFO:
|
||||
sendLoginState(sender);
|
||||
break;
|
||||
case 11:
|
||||
case C2S.REQUEST_CONTAINER_CONTENTS:
|
||||
sender.sendContainerAndContentsToPlayer(sender.openContainer, sender.openContainer.getInventory());
|
||||
break;
|
||||
case 12:
|
||||
case C2S.CHANGE_PROPERTY:
|
||||
handlePropertyChange(sender, packet);
|
||||
break;
|
||||
case 13:
|
||||
case C2S.SET_GAME_MODE:
|
||||
NEIServerUtils.setGamemode(sender, packet.readUByte());
|
||||
break;
|
||||
case 14:
|
||||
case C2S.CYCLE_CREATIVE_INV:
|
||||
NEIServerUtils.cycleCreativeInv(sender, packet.readInt());
|
||||
break;
|
||||
case 15:
|
||||
case C2S.SEND_MOB_SPAWNER_ID:
|
||||
handleMobSpawnerID(sender.worldObj, packet.readCoord(), packet.readString());
|
||||
break;
|
||||
case 16:
|
||||
case C2S.REQUEST_CONTAINER:
|
||||
handleRequestContainer(sender, packet.readInt());
|
||||
break;
|
||||
case 21:
|
||||
case C2S.REQUEST_ENCHANTMENT_GUI:
|
||||
openEnchantmentGui(sender);
|
||||
break;
|
||||
case 22:
|
||||
case C2S.MODIFY_ENCHANTMENT:
|
||||
modifyEnchantment(sender, packet.readUByte(), packet.readUByte(), packet.readBoolean());
|
||||
break;
|
||||
case 23:
|
||||
case C2S.SET_CREATIVE_PLUS_MODE:
|
||||
processCreativeInv(sender, packet.readBoolean());
|
||||
break;
|
||||
case 24:
|
||||
case C2S.REQUEST_POTION_GUI:
|
||||
openPotionGui(sender, packet);
|
||||
break;
|
||||
case 25:
|
||||
case C2S.SET_DUMMY_SLOT:
|
||||
handleDummySlotSet(sender, packet);
|
||||
break;
|
||||
case C2S.SEND_CHAT_ITEM_LINK:
|
||||
handleSendChatItemLink(sender, packet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSendChatItemLink(EntityPlayerMP sender, PacketCustom packet) {
|
||||
NEIServerUtils.sendChatItemLink(sender, packet.readItemStack());
|
||||
}
|
||||
|
||||
private void handleDummySlotSet(EntityPlayerMP sender, PacketCustom packet) {
|
||||
int slotNumber = packet.readShort();
|
||||
ItemStack stack = packet.readItemStack(true);
|
||||
@@ -126,14 +136,14 @@ public class NEISPH implements IServerPacketHandler {
|
||||
NEIServerConfig.forPlayer(sender.getCommandSenderName()),
|
||||
Side.SERVER)),
|
||||
(player, windowId) -> {
|
||||
PacketCustom packet = new PacketCustom(channel, 23);
|
||||
PacketCustom packet = new PacketCustom(channel, S2C.SET_CREATIVE_PLUS_MODE);
|
||||
packet.writeBoolean(true);
|
||||
packet.writeByte(windowId);
|
||||
packet.sendToPlayer(player);
|
||||
});
|
||||
} else {
|
||||
sender.closeContainer();
|
||||
PacketCustom packet = new PacketCustom(channel, 23);
|
||||
PacketCustom packet = new PacketCustom(channel, S2C.SET_CREATIVE_PLUS_MODE);
|
||||
packet.writeBoolean(false);
|
||||
packet.sendToPlayer(sender);
|
||||
}
|
||||
@@ -169,7 +179,7 @@ public class NEISPH implements IServerPacketHandler {
|
||||
player,
|
||||
new ContainerEnchantmentModifier(player.inventory, player.worldObj, 0, 0, 0),
|
||||
(player1, windowId) -> {
|
||||
PacketCustom packet = new PacketCustom(channel, 21);
|
||||
PacketCustom packet = new PacketCustom(channel, S2C.OPEN_ENCHANTMENT_GUI);
|
||||
packet.writeByte(windowId);
|
||||
packet.sendToPlayer(player1);
|
||||
});
|
||||
@@ -179,18 +189,19 @@ public class NEISPH implements IServerPacketHandler {
|
||||
InventoryBasic b = new InventoryBasic("potionStore", true, 9);
|
||||
for (int i = 0; i < b.getSizeInventory(); i++) b.setInventorySlotContents(i, packet.readItemStack());
|
||||
ServerUtils.openSMPContainer(player, new ContainerPotionCreator(player.inventory, b), (player1, windowId) -> {
|
||||
PacketCustom packet1 = new PacketCustom(channel, 24);
|
||||
PacketCustom packet1 = new PacketCustom(channel, S2C.OPEN_POTION_GUI);
|
||||
packet1.writeByte(windowId);
|
||||
packet1.sendToPlayer(player1);
|
||||
});
|
||||
}
|
||||
|
||||
public static void sendActionDisabled(int dim, String name, boolean disable) {
|
||||
new PacketCustom(channel, 11).writeString(name).writeBoolean(disable).sendToDimension(dim);
|
||||
new PacketCustom(channel, S2C.SEND_ACTION_DISABLED).writeString(name).writeBoolean(disable)
|
||||
.sendToDimension(dim);
|
||||
}
|
||||
|
||||
public static void sendActionEnabled(EntityPlayerMP player, String name, boolean enable) {
|
||||
new PacketCustom(channel, 12).writeString(name).writeBoolean(enable).sendToPlayer(player);
|
||||
new PacketCustom(channel, S2C.SEND_ACTION_ENABLED).writeString(name).writeBoolean(enable).sendToPlayer(player);
|
||||
}
|
||||
|
||||
private void sendLoginState(EntityPlayerMP player) {
|
||||
@@ -209,7 +220,7 @@ public class NEISPH implements IServerPacketHandler {
|
||||
if (!NEIServerConfig.isPlayerInList(player.getCommandSenderName(), entry.value, true))
|
||||
bannedItems.add(entry.key);
|
||||
|
||||
PacketCustom packet = new PacketCustom(channel, 10);
|
||||
PacketCustom packet = new PacketCustom(channel, S2C.SEND_LOGIN_STATE);
|
||||
|
||||
packet.writeByte(actions.size());
|
||||
for (String s : actions) packet.writeString(s);
|
||||
@@ -228,7 +239,7 @@ public class NEISPH implements IServerPacketHandler {
|
||||
|
||||
public static void sendHasServerSideTo(EntityPlayerMP player) {
|
||||
NEIServerConfig.logger.debug("Sending serverside check to: " + player.getCommandSenderName());
|
||||
PacketCustom packet = new PacketCustom(channel, 1);
|
||||
PacketCustom packet = new PacketCustom(channel, S2C.SEND_SERVER_SIDE_CHECK);
|
||||
packet.writeByte(NEIActions.protocol);
|
||||
packet.writeString(CommonUtils.getWorldName(player.worldObj));
|
||||
|
||||
@@ -236,7 +247,7 @@ public class NEISPH implements IServerPacketHandler {
|
||||
}
|
||||
|
||||
public static void sendAddMagneticItemTo(EntityPlayerMP player, EntityItem item) {
|
||||
PacketCustom packet = new PacketCustom(channel, 13);
|
||||
PacketCustom packet = new PacketCustom(channel, S2C.SEND_MAGNETIC_ITEM);
|
||||
packet.writeInt(item.getEntityId());
|
||||
|
||||
packet.sendToPlayer(player);
|
||||
|
||||
@@ -21,6 +21,8 @@ import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
import net.minecraftforge.permission.PermissionLevel;
|
||||
import net.minecraftforge.permission.PermissionManager;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
@@ -44,6 +46,8 @@ public class NEIServerConfig {
|
||||
public static HashMap<String, PlayerSave> playerSaves = new HashMap<>();
|
||||
public static ItemStackMap<Set<String>> bannedItems = new ItemStackMap<>();
|
||||
|
||||
private static boolean doesPermAPIExist = false;
|
||||
|
||||
public static void load(World world) {
|
||||
if (MinecraftServer.getServer() != server) {
|
||||
logger.debug("Loading NEI Server");
|
||||
@@ -53,6 +57,16 @@ public class NEIServerConfig {
|
||||
dimTags.clear();
|
||||
loadConfig();
|
||||
loadBannedItems();
|
||||
|
||||
try {
|
||||
Class.forName("net.minecraftforge.permission.PermissionManager");
|
||||
doesPermAPIExist = true;
|
||||
|
||||
NEIActions.baseActions().forEach(
|
||||
action -> {
|
||||
PermissionManager.registerPermission("nei.permissions." + action, PermissionLevel.OP);
|
||||
});
|
||||
} catch (ClassNotFoundException ignored) {}
|
||||
}
|
||||
loadWorld(world);
|
||||
}
|
||||
@@ -121,7 +135,12 @@ public class NEIServerConfig {
|
||||
}
|
||||
|
||||
public static boolean canPlayerPerformAction(String playername, String name) {
|
||||
return isPlayerInList(playername, getPlayerList("permissions." + NEIActions.base(name)), true);
|
||||
String node = "permissions." + NEIActions.base(name);
|
||||
boolean hasPerm = doesPermAPIExist
|
||||
? PermissionManager.checkPermission(ServerUtils.getPlayer(playername), "nei." + node)
|
||||
: false;
|
||||
|
||||
return hasPerm || isPlayerInList(playername, getPlayerList(node), true);
|
||||
}
|
||||
|
||||
public static boolean isPlayerInList(String playername, Set<String> list, boolean allowCards) {
|
||||
@@ -197,7 +216,7 @@ public class NEIServerConfig {
|
||||
FileReader r = new FileReader(file);
|
||||
int line = 0;
|
||||
for (String s : IOUtils.readLines(r)) {
|
||||
if (s.charAt(0) == '#' || s.trim().length() == 0) continue;
|
||||
if (s.charAt(0) == '#' || s.trim().isEmpty()) continue;
|
||||
int delim = s.lastIndexOf('=');
|
||||
if (delim < 0) {
|
||||
logger.error("line " + line + ": Missing =");
|
||||
|
||||
@@ -17,6 +17,7 @@ import net.minecraft.enchantment.Enchantment;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.event.ClickEvent;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -42,12 +43,26 @@ import codechicken.core.ServerUtils;
|
||||
import codechicken.lib.inventory.InventoryRange;
|
||||
import codechicken.lib.inventory.InventoryUtils;
|
||||
import codechicken.lib.packet.PacketCustom;
|
||||
import codechicken.nei.PacketIDs.S2C;
|
||||
import codechicken.nei.util.NBTHelper;
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper;
|
||||
|
||||
public class NEIServerUtils {
|
||||
|
||||
private static Class<?> gtMetaBaseItem;
|
||||
|
||||
static {
|
||||
try {
|
||||
final ClassLoader loader = NEIServerUtils.class.getClassLoader();
|
||||
NEIServerUtils.gtMetaBaseItem = ReflectionHelper
|
||||
.getClass(loader, "gregtech.api.items.MetaBaseItem", "gregtech.api.items.GT_MetaBase_Item");
|
||||
} catch (Exception ignored) {
|
||||
/* Do nothing */
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isRaining(World world) {
|
||||
return world.getWorldInfo().isRaining();
|
||||
}
|
||||
@@ -68,6 +83,18 @@ public class NEIServerUtils {
|
||||
player.extinguish();
|
||||
}
|
||||
|
||||
public static void sendChatItemLink(EntityPlayerMP sender, ItemStack stackover) {
|
||||
ServerUtils.sendChatToAll(
|
||||
new ChatComponentTranslation(
|
||||
"nei.chat.item_link.text",
|
||||
sender.getDisplayName(),
|
||||
stackover.func_151000_E().setChatStyle(
|
||||
stackover.func_151000_E().getChatStyle().setChatClickEvent(
|
||||
new ClickEvent(
|
||||
ClickEvent.Action.RUN_COMMAND,
|
||||
"/nei_bookmark " + stackover.writeToNBT(new NBTTagCompound()))))));
|
||||
}
|
||||
|
||||
public static long getTime(World world) {
|
||||
return world.getWorldInfo().getWorldTime();
|
||||
}
|
||||
@@ -88,9 +115,8 @@ public class NEIServerUtils {
|
||||
else return player.inventory.getStackInSlot(slot);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void deleteAllItems(EntityPlayerMP player) {
|
||||
for (Slot slot : (List<Slot>) player.openContainer.inventorySlots) slot.putStack(null);
|
||||
for (Slot slot : player.openContainer.inventorySlots) slot.putStack(null);
|
||||
|
||||
player.sendContainerAndContentsToPlayer(player.openContainer, player.openContainer.getInventory());
|
||||
}
|
||||
@@ -146,7 +172,7 @@ public class NEIServerUtils {
|
||||
|
||||
/**
|
||||
* NBT-friendly version of {@link #areStacksSameType(ItemStack, ItemStack)}
|
||||
*
|
||||
*
|
||||
* @param stack1 The {@link ItemStack} being compared.
|
||||
* @param stack2 The {@link ItemStack} to compare to.
|
||||
* @return whether the two items are the same in terms of itemID, damage and NBT.
|
||||
@@ -177,19 +203,35 @@ public class NEIServerUtils {
|
||||
|
||||
/**
|
||||
* NBT-friendly version of {@link #areStacksSameTypeCrafting(ItemStack, ItemStack)}
|
||||
*
|
||||
*
|
||||
* @param stack1 The {@link ItemStack} being compared.
|
||||
* @param stack2 The {@link ItemStack} to compare to.
|
||||
* @return whether the two items are the same from the perspective of a crafting inventory.
|
||||
*/
|
||||
public static boolean areStacksSameTypeCraftingWithNBT(ItemStack stack1, ItemStack stack2) {
|
||||
return stack1 != null && stack2 != null
|
||||
&& stack1.getItem() == stack2.getItem()
|
||||
&& (stack1.getItemDamage() == stack2.getItemDamage()
|
||||
|| stack1.getItemDamage() == OreDictionary.WILDCARD_VALUE
|
||||
|| stack2.getItemDamage() == OreDictionary.WILDCARD_VALUE
|
||||
|| stack1.getItem().isDamageable())
|
||||
&& NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound());
|
||||
|
||||
if (NEIServerUtils.areStacksSameTypeCrafting(stack2, stack1)) {
|
||||
if (NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound())) return true;
|
||||
if (isItemTool(stack1)
|
||||
&& (stack1.stackTagCompound == null || stack1.stackTagCompound.hasKey("GT.ToolStats"))
|
||||
&& (stack2.stackTagCompound == null || stack2.stackTagCompound.hasKey("GT.ToolStats")))
|
||||
return true;
|
||||
return stack1.getMaxStackSize() == 1 && stack2.getMaxStackSize() == 1
|
||||
&& (stack1.stackTagCompound == null ^ stack2.stackTagCompound == null);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* GT Items don't have any NBT set for the recipe, so if either of the stacks has a NULL nbt, and the other doesn't,
|
||||
* pretend they stack
|
||||
*
|
||||
* @param ItemStack stack
|
||||
* @return
|
||||
*/
|
||||
public static boolean isItemTool(ItemStack stack) {
|
||||
return NEIServerUtils.gtMetaBaseItem != null && NEIServerUtils.gtMetaBaseItem.isInstance(stack.getItem());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,7 +337,7 @@ public class NEIServerUtils {
|
||||
player.theItemInWorldManager.setGameType(getGameType(mode));
|
||||
|
||||
// tell the client to change it
|
||||
new PacketCustom(NEISPH.channel, 14).writeByte(mode).sendToPlayer(player);
|
||||
new PacketCustom(NEISPH.channel, S2C.SEND_GAME_MODE).writeByte(mode).sendToPlayer(player);
|
||||
player.addChatMessage(new ChatComponentTranslation("nei.chat.gamemode." + mode));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package codechicken.nei;
|
||||
|
||||
public final class PacketIDs {
|
||||
|
||||
public static final class C2S {
|
||||
|
||||
public static final int GIVE_ITEM = 1;
|
||||
public static final int DELETE_ALL_ITEMS = 4;
|
||||
public static final int SET_SLOT = 5;
|
||||
public static final int TOGGLE_MAGNET = 6;
|
||||
public static final int SET_TIME = 7;
|
||||
public static final int HEAL = 8;
|
||||
public static final int TOGGLE_RAIN = 9;
|
||||
public static final int REQUEST_LOGIN_INFO = 10;
|
||||
public static final int REQUEST_CONTAINER_CONTENTS = 11;
|
||||
public static final int CHANGE_PROPERTY = 12;
|
||||
public static final int SET_GAME_MODE = 13;
|
||||
public static final int CYCLE_CREATIVE_INV = 14;
|
||||
public static final int SEND_MOB_SPAWNER_ID = 15;
|
||||
public static final int REQUEST_CONTAINER = 16;
|
||||
public static final int REQUEST_ENCHANTMENT_GUI = 21;
|
||||
public static final int MODIFY_ENCHANTMENT = 22;
|
||||
public static final int SET_CREATIVE_PLUS_MODE = 23;
|
||||
public static final int REQUEST_POTION_GUI = 24;
|
||||
public static final int SET_DUMMY_SLOT = 25;
|
||||
public static final int SEND_CHAT_ITEM_LINK = 26;
|
||||
}
|
||||
|
||||
public static final class S2C {
|
||||
|
||||
public static final int SEND_SERVER_SIDE_CHECK = 1;
|
||||
public static final int SEND_LOGIN_STATE = 10;
|
||||
public static final int SEND_ACTION_DISABLED = 11;
|
||||
public static final int SEND_ACTION_ENABLED = 12;
|
||||
public static final int SEND_MAGNETIC_ITEM = 13;
|
||||
public static final int SEND_GAME_MODE = 14;
|
||||
public static final int OPEN_ENCHANTMENT_GUI = 21;
|
||||
public static final int SET_CREATIVE_PLUS_MODE = 23;
|
||||
public static final int OPEN_POTION_GUI = 24;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,24 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.ItemPanel.ItemPanelSlot;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.api.GuiInfo;
|
||||
import codechicken.nei.api.INEIGuiHandler;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.guihook.IContainerTooltipHandler;
|
||||
import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.GuiUsageRecipe;
|
||||
|
||||
public abstract class PanelWidget extends Widget {
|
||||
public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ? extends ItemsGrid.MouseContext>>
|
||||
extends Widget implements IContainerTooltipHandler {
|
||||
|
||||
protected static final int PADDING = 2;
|
||||
|
||||
@@ -26,100 +29,76 @@ public abstract class PanelWidget extends Widget {
|
||||
public Button pageNext;
|
||||
public Label pageLabel;
|
||||
|
||||
protected ItemsGrid grid;
|
||||
protected T grid;
|
||||
|
||||
public ArrayList<ItemStack> getItems() {
|
||||
return grid.getItems();
|
||||
return this.grid.getItems();
|
||||
}
|
||||
|
||||
public ItemsGrid getGrid() {
|
||||
return grid;
|
||||
public T getGrid() {
|
||||
return this.grid;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
pageLabel = new Label("0/0", true);
|
||||
|
||||
pagePrev = new Button("Prev") {
|
||||
pagePrev = new Button("<") {
|
||||
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
if (!rightclick) {
|
||||
|
||||
if (rightclick) {
|
||||
grid.setPage(0);
|
||||
} else {
|
||||
grid.shiftPage(-1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRenderLabel() {
|
||||
return "<";
|
||||
public void draw(int mousex, int mousey) {
|
||||
this.state = grid.getNumPages() <= 1 ? 2 : 0;
|
||||
super.draw(mousex, mousey);
|
||||
}
|
||||
};
|
||||
pageNext = new Button("Next") {
|
||||
pageNext = new Button(">") {
|
||||
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
if (!rightclick) {
|
||||
|
||||
if (rightclick) {
|
||||
grid.setPage(grid.getNumPages() - 1);
|
||||
} else {
|
||||
grid.shiftPage(1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRenderLabel() {
|
||||
return ">";
|
||||
public void draw(int mousex, int mousey) {
|
||||
this.state = grid.getNumPages() <= 1 ? 2 : 0;
|
||||
super.draw(mousex, mousey);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public abstract String getLabelText();
|
||||
|
||||
protected abstract String getPositioningSettingName();
|
||||
|
||||
public abstract int getMarginLeft(GuiContainer gui);
|
||||
|
||||
public abstract int getMarginTop(GuiContainer gui);
|
||||
|
||||
public abstract int getWidth(GuiContainer gui);
|
||||
|
||||
public abstract int getHeight(GuiContainer gui);
|
||||
public abstract Rectangle4i calculateBounds();
|
||||
|
||||
public void resize(GuiContainer gui) {
|
||||
final Rectangle4i margin = new Rectangle4i(
|
||||
getMarginLeft(gui),
|
||||
getMarginTop(gui),
|
||||
getWidth(gui),
|
||||
getHeight(gui));
|
||||
final Rectangle4i bounds = calculateBounds();
|
||||
|
||||
final int minWidth = 5 * ItemsGrid.SLOT_SIZE;
|
||||
final int minHeight = 9 * ItemsGrid.SLOT_SIZE;
|
||||
|
||||
final String settingName = getPositioningSettingName();
|
||||
int paddingLeft = (int) Math
|
||||
.ceil(margin.w * NEIClientConfig.getSetting(settingName + ".left").getIntValue() / 100000.0);
|
||||
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 - minHeight) / 2;
|
||||
|
||||
paddingLeft = Math.min(paddingLeft, Math.max(0, margin.w - paddingRight - minWidth));
|
||||
paddingRight = Math.min(paddingRight, Math.max(0, margin.w - paddingLeft - minWidth));
|
||||
paddingTop = Math.min(margin.h - minHeight, Math.max(0, paddingTop + deltaHeight));
|
||||
paddingBottom = Math.min(margin.h - paddingTop - minHeight, Math.max(0, paddingBottom - deltaHeight));
|
||||
|
||||
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);
|
||||
|
||||
grid.setGridSize(x, y + header, w, h - header - footer);
|
||||
grid.refresh(gui);
|
||||
this.grid.setGridSize(x, y + header, w, h - header - footer);
|
||||
this.grid.refresh(gui);
|
||||
}
|
||||
|
||||
protected int resizeHeader(GuiContainer gui) {
|
||||
@@ -164,22 +143,22 @@ public abstract class PanelWidget extends Widget {
|
||||
protected abstract int resizeFooter(GuiContainer gui);
|
||||
|
||||
public void setVisible() {
|
||||
if (grid.getPerPage() > 0) {
|
||||
if (this.grid.getPerPage() > 0 && !this.grid.isEmpty()) {
|
||||
LayoutManager.addWidget(pagePrev);
|
||||
LayoutManager.addWidget(pageNext);
|
||||
LayoutManager.addWidget(pageLabel);
|
||||
grid.setVisible();
|
||||
this.grid.setVisible();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
grid.update();
|
||||
this.grid.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mousex, int mousey) {
|
||||
grid.draw(mousex, mousey);
|
||||
this.grid.draw(mousex, mousey);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -191,60 +170,35 @@ public abstract class PanelWidget extends Widget {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDrawTooltips(int mx, int my, List<String> tooltip) {
|
||||
grid.postDrawTooltips(mx, my, tooltip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(int mousex, int mousey, int button, long heldTime) {
|
||||
if (this.grid.getSlotBySlotIndex(mouseDownSlot) == null) {
|
||||
mouseDownSlot = -1;
|
||||
}
|
||||
|
||||
if (mouseDownSlot >= 0 && draggedStack == null
|
||||
&& NEIClientUtils.getHeldItem() == null
|
||||
&& NEIClientConfig.hasSMPCounterPart()) {
|
||||
ItemPanelSlot mouseOverSlot = getSlotMouseOver(mousex, mousey);
|
||||
ItemsGridSlot mouseOverSlot = this.grid.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (mouseOverSlot == null || mouseOverSlot.slotIndex != mouseDownSlot || heldTime > 500) {
|
||||
draggedStack = getDraggedStackWithQuantity(mouseDownSlot);
|
||||
draggedStack = getDraggedStackWithQuantity(this.grid.getSlotBySlotIndex(mouseDownSlot).getItemStack());
|
||||
mouseDownSlot = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract ItemStack getDraggedStackWithQuantity(int mouseDownSlot);
|
||||
protected abstract ItemStack getDraggedStackWithQuantity(ItemStack itemStack);
|
||||
|
||||
@Override
|
||||
public boolean handleClick(int mousex, int mousey, int button) {
|
||||
|
||||
if (handleClickExt(mousex, mousey, button)) return true;
|
||||
|
||||
if (NEIClientUtils.getHeldItem() != null) {
|
||||
|
||||
if (!grid.contains(mousex, mousey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")) {
|
||||
if (button == 1) {
|
||||
NEIClientUtils.decreaseSlotStack(-999);
|
||||
} else {
|
||||
NEIClientUtils.deleteHeldItem();
|
||||
}
|
||||
} else {
|
||||
NEIClientUtils.dropHeldItem();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ItemPanelSlot hoverSlot = getSlotMouseOver(mousex, mousey);
|
||||
ItemsGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
|
||||
if (hoverSlot != null) {
|
||||
|
||||
if (button == 2) {
|
||||
|
||||
if (hoverSlot.item != null) {
|
||||
draggedStack = getDraggedStackWithQuantity(hoverSlot.slotIndex);
|
||||
}
|
||||
|
||||
draggedStack = getDraggedStackWithQuantity(hoverSlot.getItemStack());
|
||||
} else {
|
||||
mouseDownSlot = hoverSlot.slotIndex;
|
||||
}
|
||||
@@ -259,7 +213,7 @@ public abstract class PanelWidget extends Widget {
|
||||
public boolean handleClickExt(int mouseX, int mouseY, int button) {
|
||||
|
||||
if (ItemPanels.itemPanel.draggedStack != null && ItemPanels.bookmarkPanel.contains(mouseX, mouseY)) {
|
||||
ItemPanels.bookmarkPanel.addOrRemoveItem(ItemPanels.itemPanel.draggedStack, null, null, false, true);
|
||||
ItemPanels.bookmarkPanel.addItem(ItemPanels.itemPanel.draggedStack);
|
||||
ItemPanels.itemPanel.draggedStack = null;
|
||||
return true;
|
||||
}
|
||||
@@ -325,24 +279,23 @@ public abstract class PanelWidget extends Widget {
|
||||
|
||||
@Override
|
||||
public void mouseUp(int mousex, int mousey, int button) {
|
||||
ItemPanelSlot hoverSlot = getSlotMouseOver(mousex, mousey);
|
||||
final ItemsGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (hoverSlot != null && hoverSlot.slotIndex == mouseDownSlot && draggedStack == null) {
|
||||
ItemStack item = hoverSlot.item;
|
||||
|
||||
if (NEIController.manager.window instanceof GuiRecipe || !NEIClientConfig.canCheatItem(item)) {
|
||||
if (NEIController.manager.window instanceof GuiRecipe || NEIClientUtils.shiftKey()
|
||||
|| !NEIClientConfig.canCheatItem(hoverSlot.getItemStack())) {
|
||||
|
||||
if (button == 0) {
|
||||
GuiCraftingRecipe.openRecipeGui("item", item);
|
||||
GuiCraftingRecipe.openRecipeGui("item", hoverSlot.getItemStack().copy());
|
||||
} else if (button == 1) {
|
||||
GuiUsageRecipe.openRecipeGui("item", item);
|
||||
GuiUsageRecipe.openRecipeGui("item", hoverSlot.getItemStack().copy());
|
||||
}
|
||||
|
||||
mouseDownSlot = -1;
|
||||
return;
|
||||
} else {
|
||||
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.getItemStack()), button, -1);
|
||||
}
|
||||
|
||||
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.slotIndex), button, -1);
|
||||
}
|
||||
|
||||
mouseDownSlot = -1;
|
||||
@@ -352,20 +305,22 @@ public abstract class PanelWidget extends Widget {
|
||||
public boolean onMouseWheel(int i, int mousex, int mousey) {
|
||||
if (!contains(mousex, mousey)) return false;
|
||||
|
||||
grid.shiftPage(-i);
|
||||
this.grid.shiftPage(-i);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyPress(int keyID, char keyChar) {
|
||||
final Point mouse = GuiDraw.getMousePosition();
|
||||
if (!contains(mouse.x, mouse.y)) return false;
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.next")) {
|
||||
grid.shiftPage(1);
|
||||
this.grid.shiftPage(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.prev")) {
|
||||
grid.shiftPage(-1);
|
||||
this.grid.shiftPage(-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -374,24 +329,28 @@ public abstract class PanelWidget extends Widget {
|
||||
|
||||
@Override
|
||||
public ItemStack getStackMouseOver(int mousex, int mousey) {
|
||||
ItemPanelSlot slot = getSlotMouseOver(mousex, mousey);
|
||||
return slot == null ? null : slot.item;
|
||||
final ItemsGridSlot slot = this.grid.getSlotMouseOver(mousex, mousey);
|
||||
return slot == null ? null : slot.getItemStack();
|
||||
}
|
||||
|
||||
public ItemPanelSlot getSlotMouseOver(int mousex, int mousey) {
|
||||
return grid.getSlotMouseOver(mousex, mousey);
|
||||
public ItemStack getStackMouseOverWithQuantity(int mousex, int mousey) {
|
||||
final ItemStack hoverSlot = getStackMouseOver(mousex, mousey);
|
||||
return hoverSlot != null ? getDraggedStackWithQuantity(hoverSlot) : null;
|
||||
}
|
||||
|
||||
abstract ItemsGridSlot getSlotMouseOver(int mousex, int mousey);
|
||||
|
||||
public int getPage() {
|
||||
return grid.getPage();
|
||||
return this.grid.getPage();
|
||||
}
|
||||
|
||||
public int getNumPages() {
|
||||
return grid.getNumPages();
|
||||
return this.grid.getNumPages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int px, int py) {
|
||||
return grid.contains(px, py);
|
||||
return this.grid.contains(px, py);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +1,21 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
|
||||
/**
|
||||
* Simply an {@link ItemStack} with position. Mainly used in the recipe handlers.
|
||||
*/
|
||||
@@ -26,8 +34,11 @@ public class PositionedStack {
|
||||
relx = x;
|
||||
rely = y;
|
||||
|
||||
if (genPerms) generatePermutations();
|
||||
else setPermutationToRender(0);
|
||||
if (genPerms) {
|
||||
generatePermutations();
|
||||
} else {
|
||||
setPermutationToRender(0);
|
||||
}
|
||||
}
|
||||
|
||||
public PositionedStack(Object object, int x, int y) {
|
||||
@@ -37,7 +48,7 @@ public class PositionedStack {
|
||||
public void generatePermutations() {
|
||||
if (permutated) return;
|
||||
|
||||
ArrayList<ItemStack> stacks = new ArrayList<>();
|
||||
List<ItemStack> stacks = new ArrayList<>();
|
||||
for (ItemStack item : items) {
|
||||
if (item == null || item.getItem() == null) continue;
|
||||
|
||||
@@ -72,15 +83,57 @@ public class PositionedStack {
|
||||
}
|
||||
|
||||
public PositionedStack copy() {
|
||||
return new PositionedStack(items, relx, rely);
|
||||
PositionedStack pStack = new PositionedStack(
|
||||
Arrays.stream(this.items).map(ItemStack::copy).toArray(ItemStack[]::new),
|
||||
relx,
|
||||
rely,
|
||||
false);
|
||||
pStack.permutated = this.permutated;
|
||||
return pStack;
|
||||
}
|
||||
|
||||
public List<ItemStack> getFilteredPermutations() {
|
||||
return getFilteredPermutations(null);
|
||||
}
|
||||
|
||||
public List<ItemStack> getFilteredPermutations(ItemFilter additionalFilter) {
|
||||
List<ItemStack> items = Arrays.asList(this.items);
|
||||
|
||||
items = filteringPermutations(items, item -> !ItemInfo.isHidden(item));
|
||||
items = filteringPermutations(items, PresetsList.getItemFilter());
|
||||
items = filteringPermutations(items, GuiRecipe.getSearchItemFilter());
|
||||
items = filteringPermutations(items, additionalFilter);
|
||||
|
||||
items.sort(Comparator.comparing(FavoriteRecipes::contains).reversed());
|
||||
return items;
|
||||
}
|
||||
|
||||
private List<ItemStack> filteringPermutations(List<ItemStack> items, ItemFilter filter) {
|
||||
if (filter == null) return items;
|
||||
final List<ItemStack> filteredItems = items.stream().filter(filter::matches).collect(Collectors.toList());
|
||||
return filteredItems.isEmpty() ? items : filteredItems;
|
||||
}
|
||||
|
||||
public boolean setPermutationToRender(ItemStack ingredient) {
|
||||
|
||||
for (int index = 0; index < this.items.length; index++) {
|
||||
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(this.items[index], ingredient)) {
|
||||
setPermutationToRender(index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setPermutationToRender(int index) {
|
||||
item = items[index].copy();
|
||||
if (item.getItem() == null) item = new ItemStack(Blocks.fire);
|
||||
else if (item.getItemDamage() == OreDictionary.WILDCARD_VALUE && item.getItem() != null
|
||||
&& item.getItem().isRepairable())
|
||||
item.setItemDamage(0);
|
||||
this.item = this.items[index].copy();
|
||||
|
||||
if (this.item.getItem() == null) {
|
||||
this.item = new ItemStack(Blocks.fire);
|
||||
} else if (this.item.getItemDamage() == OreDictionary.WILDCARD_VALUE && this.item.getItem().isRepairable()) {
|
||||
this.item.setItemDamage(0);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(ItemStack ingredient) {
|
||||
@@ -93,7 +146,7 @@ public class PositionedStack {
|
||||
* NBT-friendly version of {@link #contains(ItemStack)}
|
||||
*/
|
||||
public boolean containsWithNBT(ItemStack ingredient) {
|
||||
for (ItemStack item : items) if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(item, ingredient)) return true;
|
||||
for (ItemStack item : items) if (StackInfo.equalItemAndNBT(item, ingredient, true)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import codechicken.core.CommonUtils;
|
||||
import codechicken.nei.SubsetWidget.SubsetTag;
|
||||
import codechicken.nei.api.API;
|
||||
import codechicken.nei.api.IRecipeFilter;
|
||||
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.NBTJson;
|
||||
|
||||
public class PresetsList {
|
||||
|
||||
public enum PresetMode {
|
||||
SUBSET,
|
||||
HIDE,
|
||||
REMOVE,
|
||||
GROUP;
|
||||
}
|
||||
|
||||
public static class Preset implements ItemFilter {
|
||||
|
||||
public String name = "";
|
||||
public boolean enabled = true;
|
||||
public PresetMode mode = PresetMode.HIDE;
|
||||
public Set<String> items = new HashSet<>();
|
||||
|
||||
public static String getIdentifier(ItemStack stack) {
|
||||
return StackInfo.getItemStackGUID(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(ItemStack item) {
|
||||
return items.contains(Preset.getIdentifier(item));
|
||||
}
|
||||
|
||||
public Preset copy() {
|
||||
Preset preset = new Preset();
|
||||
|
||||
preset.name = name;
|
||||
preset.enabled = enabled;
|
||||
preset.mode = mode;
|
||||
preset.items = new HashSet<>(items);
|
||||
|
||||
return preset;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class PresetRecipeFilter implements IRecipeFilterProvider, IRecipeFilter {
|
||||
|
||||
public Set<String> cache;
|
||||
|
||||
public IRecipeFilter getRecipeFilter() {
|
||||
|
||||
if (cache == null) {
|
||||
cache = PresetsList.presets.stream().filter(p -> p.enabled && p.mode == PresetMode.REMOVE)
|
||||
.flatMap(p -> p.items.stream()).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
return cache.isEmpty() ? null : this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(IRecipeHandler handler, int recipeIndex) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return result == null && others.isEmpty();
|
||||
}
|
||||
|
||||
private boolean matchPositionedStack(List<PositionedStack> items, boolean dir) {
|
||||
for (PositionedStack pStack : items) {
|
||||
if (matchPositionedStack(pStack) == dir) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean matchPositionedStack(PositionedStack pStack) {
|
||||
for (ItemStack stack : pStack.items) {
|
||||
if (!cache.contains(Preset.getIdentifier(stack))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static class ItemPanelFilter implements ItemFilterProvider, ItemFilter {
|
||||
|
||||
public Set<String> cache;
|
||||
|
||||
public ItemFilter getFilter() {
|
||||
|
||||
if (cache == null) {
|
||||
cache = PresetsList.presets.stream()
|
||||
.filter(p -> p.enabled && (p.mode == PresetMode.HIDE || p.mode == PresetMode.REMOVE))
|
||||
.flatMap(p -> p.items.stream()).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
return cache.isEmpty() ? null : this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(ItemStack stack) {
|
||||
return !cache.contains(Preset.getIdentifier(stack));
|
||||
}
|
||||
}
|
||||
|
||||
public static final List<Preset> presets = new ArrayList<>();
|
||||
protected static PresetRecipeFilter recipeFilter = new PresetRecipeFilter();
|
||||
protected static ItemPanelFilter itemFilter = new ItemPanelFilter();
|
||||
|
||||
static {
|
||||
API.addItemFilter(itemFilter);
|
||||
API.addRecipeFilter(recipeFilter);
|
||||
}
|
||||
|
||||
public static ItemFilter getItemFilter() {
|
||||
return itemFilter.getFilter();
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
final File presetsFile = new File(CommonUtils.getMinecraftDir(), "saves/NEI/global/presets.ini");
|
||||
|
||||
if (presetsFile == null || !presetsFile.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> itemStrings;
|
||||
try (FileInputStream reader = new FileInputStream(presetsFile)) {
|
||||
NEIClientConfig.logger.info("Loading presets from file {}", presetsFile);
|
||||
itemStrings = IOUtils.readLines(reader, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to load presets from file {}", presetsFile, e);
|
||||
return;
|
||||
}
|
||||
|
||||
JsonParser parser = new JsonParser();
|
||||
Preset preset = new Preset();
|
||||
presets.clear();
|
||||
|
||||
for (String itemStr : itemStrings) {
|
||||
|
||||
try {
|
||||
|
||||
if (itemStr.isEmpty()) {
|
||||
itemStr = "; {}";
|
||||
}
|
||||
|
||||
if (itemStr.startsWith("; ")) {
|
||||
JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
|
||||
|
||||
if (!preset.items.isEmpty()) {
|
||||
// do not create empty namespaces
|
||||
presets.add(preset);
|
||||
preset = new Preset();
|
||||
}
|
||||
|
||||
if (settings.has("name")) {
|
||||
preset.name = settings.get("name").getAsString();
|
||||
}
|
||||
|
||||
if (settings.has("enabled")) {
|
||||
preset.enabled = settings.get("enabled").getAsBoolean();
|
||||
}
|
||||
|
||||
if (settings.has("mode")) {
|
||||
preset.mode = PresetMode.valueOf(settings.get("mode").getAsString());
|
||||
}
|
||||
|
||||
} else {
|
||||
preset.items.add(itemStr);
|
||||
}
|
||||
|
||||
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
|
||||
NEIClientConfig.logger.error("Failed to load presets ItemStack from json string:\n{}", itemStr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!preset.items.isEmpty()) {
|
||||
presets.add(preset);
|
||||
}
|
||||
|
||||
updateSubsets();
|
||||
}
|
||||
|
||||
public static void savePresets() {
|
||||
final File presetsFile = new File(CommonUtils.getMinecraftDir(), "saves/NEI/global/presets.ini");
|
||||
final List<String> strings = new ArrayList<>();
|
||||
|
||||
for (Preset preset : presets) {
|
||||
JsonObject settings = new JsonObject();
|
||||
|
||||
settings.add("name", new JsonPrimitive(preset.name));
|
||||
settings.add("enabled", new JsonPrimitive(preset.enabled));
|
||||
settings.add("mode", new JsonPrimitive(preset.mode.toString()));
|
||||
|
||||
strings.add("; " + NBTJson.toJson(settings));
|
||||
strings.addAll(preset.items);
|
||||
}
|
||||
|
||||
try (FileOutputStream output = new FileOutputStream(presetsFile)) {
|
||||
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to save presets list to file {}", presetsFile, e);
|
||||
}
|
||||
|
||||
recipeFilter.cache = null;
|
||||
itemFilter.cache = null;
|
||||
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))));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,922 +0,0 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import static codechicken.nei.NEIClientUtils.translate;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import codechicken.core.CommonUtils;
|
||||
import codechicken.core.gui.GuiScrollSlot;
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.ItemPanel.ItemPanelSlot;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.NBTJson;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
|
||||
public class PresetsWidget extends Widget {
|
||||
|
||||
public static class PresetTag implements ItemFilter {
|
||||
|
||||
public String filename = null;
|
||||
public String displayName = "";
|
||||
public boolean whitelist = true;
|
||||
public HashSet<String> items;
|
||||
|
||||
public PresetTag(String displayName) {
|
||||
this(displayName, new HashSet<>(), false, null);
|
||||
}
|
||||
|
||||
public PresetTag(String displayName, HashSet<String> items) {
|
||||
this(displayName, items, true, null);
|
||||
}
|
||||
|
||||
public PresetTag(String displayName, HashSet<String> items, boolean whitelist, String filename) {
|
||||
this.displayName = displayName;
|
||||
this.items = items != null ? items : new HashSet<>();
|
||||
this.whitelist = whitelist;
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public boolean matches(final ItemStack stack) {
|
||||
return items.contains(StackInfo.getItemStackGUID(stack)) == whitelist;
|
||||
}
|
||||
|
||||
public static PresetTag loadFromFile(File file) {
|
||||
if (!file.isFile() || !file.exists() || file.getName().equals("selected.ini")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
List<String> itemStrings;
|
||||
try (FileInputStream input = new FileInputStream(file)) {
|
||||
NEIClientConfig.logger.info("Loading presets from file {}", file);
|
||||
itemStrings = IOUtils.readLines(input, "UTF-8");
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to load presets from file {}", file, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
final JsonParser parser = new JsonParser();
|
||||
final JsonObject metaObject = parser.parse(itemStrings.remove(0)).getAsJsonObject();
|
||||
final String displayName = metaObject.get("displayName").getAsString();
|
||||
final boolean whitelist = metaObject.get("whitelist").getAsBoolean();
|
||||
final HashSet<String> items = new HashSet<>();
|
||||
|
||||
for (String itemStr : itemStrings) {
|
||||
items.add(itemStr);
|
||||
}
|
||||
|
||||
return new PresetTag(displayName, items, whitelist, file.getName());
|
||||
} catch (Throwable th) {
|
||||
NEIClientConfig.logger.error("Failed to load presets ItemStack from file", file);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void deleteFile() {
|
||||
if (presetsDir == null || filename == null) return;
|
||||
final File tagFile = new File(presetsDir, filename);
|
||||
|
||||
if (tagFile.exists()) {
|
||||
tagFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public void saveToFile() {
|
||||
if (presetsDir == null) return;
|
||||
|
||||
if (filename == null) {
|
||||
final String sanitized = displayName.replaceAll("[^_\\-.0-9a-zA-Z]", "_");
|
||||
int index = 1;
|
||||
|
||||
filename = sanitized + ".ini";
|
||||
|
||||
while ((new File(presetsDir, filename)).exists() || filename.equals("selected.ini")) {
|
||||
filename = sanitized + " (" + index + ").ini";
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
final List<String> strings = new ArrayList<>();
|
||||
final JsonObject row = new JsonObject();
|
||||
|
||||
row.add("displayName", new JsonPrimitive(displayName));
|
||||
row.add("whitelist", new JsonPrimitive(whitelist));
|
||||
|
||||
strings.add(NBTJson.toJson(row));
|
||||
|
||||
try {
|
||||
strings.addAll(items);
|
||||
} catch (JsonSyntaxException e) {
|
||||
NEIClientConfig.logger.error("Failed to stringify presets ItemStack to json string");
|
||||
}
|
||||
|
||||
final File tagFile = new File(presetsDir, filename);
|
||||
|
||||
try (FileOutputStream output = new FileOutputStream(tagFile)) {
|
||||
IOUtils.writeLines(strings, "\n", output, "UTF-8");
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Filed to save presets list to file {}", tagFile, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public PresetTag copy() {
|
||||
return new PresetTag(displayName, (HashSet) items.clone(), whitelist, null);
|
||||
}
|
||||
}
|
||||
|
||||
protected static class SubsetListBox extends GuiScrollSlot {
|
||||
|
||||
protected final List<PresetTag> presets = new ArrayList<>();
|
||||
protected final List<PresetTag> selected = new ArrayList<>();
|
||||
protected int lastSelectedIndex = 0;
|
||||
|
||||
public SubsetListBox(File presetsDir) {
|
||||
super(0, 0, 0, 0);
|
||||
setSmoothScroll(false);
|
||||
|
||||
try {
|
||||
|
||||
presets.addAll(
|
||||
ItemList.forkJoinPool.submit(
|
||||
() -> Arrays.asList(presetsDir.listFiles()).parallelStream()
|
||||
.map(f -> PresetTag.loadFromFile(f)).filter(p -> p != null)
|
||||
.collect(Collectors.toCollection(ArrayList::new)))
|
||||
.get());
|
||||
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
selected.addAll(loadSelFromFile(presetsDir, presets));
|
||||
sort();
|
||||
}
|
||||
|
||||
public SubsetListBox() {
|
||||
super(0, 0, 0, 0);
|
||||
setSmoothScroll(false);
|
||||
}
|
||||
|
||||
public void addTag(final PresetTag tag, boolean sel) {
|
||||
presets.add(tag);
|
||||
|
||||
if (sel) {
|
||||
selected.add(tag);
|
||||
}
|
||||
}
|
||||
|
||||
protected List<PresetTag> getPresets() {
|
||||
return presets;
|
||||
}
|
||||
|
||||
protected List<PresetTag> getSelected() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
public void replaceSeleted(final PresetTag tag) {
|
||||
|
||||
if (selected.size() == 1) {
|
||||
selected.get(0).deleteFile();
|
||||
presets.set(presets.indexOf(selected.get(0)), tag);
|
||||
selected.set(0, tag);
|
||||
} else {
|
||||
presets.add(tag);
|
||||
selected.add(tag);
|
||||
}
|
||||
|
||||
tag.saveToFile();
|
||||
saveSelToFile();
|
||||
sort();
|
||||
}
|
||||
|
||||
public void sort() {
|
||||
presets.sort((o1, o2) -> o1.displayName.compareTo(o2.displayName));
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
presets.clear();
|
||||
selected.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlotHeight(int slot) {
|
||||
return 18;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getNumSlots() {
|
||||
return presets.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void slotClicked(int slot, int button, int mx, int my, int count) {
|
||||
|
||||
if (slot >= presets.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PresetTag tag = presets.get(slot);
|
||||
final int width = windowBounds().width;
|
||||
|
||||
final Rectangle4i direction = new Rectangle4i(0, 0, 18, 18);
|
||||
final Rectangle4i delete = new Rectangle4i(width - 18, 0, 18, 18);
|
||||
final Rectangle4i option = new Rectangle4i(18, 0, width - 18 - 18, 18);
|
||||
|
||||
if (option.contains(mx, my)) {
|
||||
final boolean sel = selected.contains(tag);
|
||||
|
||||
if (NEIClientUtils.controlKey()) {
|
||||
|
||||
if (sel) {
|
||||
selected.remove(tag);
|
||||
} else {
|
||||
selected.add(tag);
|
||||
}
|
||||
|
||||
} else if (NEIClientUtils.shiftKey()) {
|
||||
selected.clear();
|
||||
|
||||
for (int i = Math.min(lastSelectedIndex, slot); i <= Math.max(lastSelectedIndex, slot); i++) {
|
||||
if (!selected.contains(presets.get(i))) {
|
||||
selected.add(presets.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
final int size = selected.size();
|
||||
selected.clear();
|
||||
|
||||
if (!sel || size > 1) {
|
||||
selected.add(tag);
|
||||
}
|
||||
}
|
||||
|
||||
if (selected.isEmpty()) {
|
||||
lastSelectedIndex = 0;
|
||||
} else if (!NEIClientUtils.shiftKey()) {
|
||||
lastSelectedIndex = slot;
|
||||
}
|
||||
|
||||
} else if (delete.contains(mx, my)) {
|
||||
presets.remove(tag);
|
||||
selected.remove(tag);
|
||||
tag.deleteFile();
|
||||
} else if (direction.contains(mx, my)) {
|
||||
tag.whitelist = !tag.whitelist;
|
||||
tag.saveToFile();
|
||||
}
|
||||
|
||||
saveSelToFile();
|
||||
PresetsWidget.edit = null;
|
||||
PresetsWidget.openListBox = !presets.isEmpty()
|
||||
&& (NEIClientUtils.controlKey() || NEIClientUtils.shiftKey() || !option.contains(mx, my));
|
||||
ItemList.updateFilter.restart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawSlot(int slot, int x, int y, int mx, int my, float frame) {
|
||||
if (slot >= presets.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int width = windowBounds().width;
|
||||
final Rectangle4i direction = new Rectangle4i(x, y, 18, 18);
|
||||
final Rectangle4i delete = new Rectangle4i(x + width - 18, y, 18, 18);
|
||||
final Rectangle4i option = new Rectangle4i(x + 18, y, width - 18 - 18, 18);
|
||||
final PresetTag tag = presets.get(slot);
|
||||
|
||||
final int optionState = selected.contains(tag) ? 0 : option.contains(x + mx, y + my) ? 1 : 2;
|
||||
final int directionState = direction.contains(x + mx, y + my) ? 1 : 2;
|
||||
final int deleteState = delete.contains(x + mx, y + my) ? 1 : 2;
|
||||
|
||||
final String displayName = NEIClientUtils
|
||||
.cropText(PresetsWidget.fontRenderer, tag.displayName, option.w - 6);
|
||||
final String dirName = tag.whitelist ? translate("presets.whitelist.label")
|
||||
: translate("presets.blacklist.label");
|
||||
|
||||
// blacklist or whitelist
|
||||
LayoutManager.getLayoutStyle()
|
||||
.drawSubsetTag(null, direction.x, direction.y, direction.w, direction.h, directionState, false);
|
||||
GuiDraw.drawString(dirName, direction.x + 6, direction.y + 5, directionState == 2 ? 0xFFE0E0E0 : 0xFFFFA0);
|
||||
|
||||
// option name
|
||||
LayoutManager.getLayoutStyle()
|
||||
.drawSubsetTag(null, option.x, option.y, option.w, option.h, optionState, false);
|
||||
GuiDraw.drawString(displayName, option.x + 3, option.y + 5, optionState == 2 ? 0xFFE0E0E0 : 0xFFFFA0);
|
||||
|
||||
// remove icon
|
||||
LayoutManager.getLayoutStyle()
|
||||
.drawSubsetTag(null, delete.x, delete.y, delete.w, delete.h, deleteState, false);
|
||||
GuiDraw.drawString("✕", delete.x + 6, delete.y + 5, deleteState == 2 ? 0xFFE0E0E0 : 0x601010);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOverlay(float frame) {}
|
||||
|
||||
@Override
|
||||
public void drawBackground(float frame) {
|
||||
drawRect(x, y, x + width, y + height, 0xFF202020);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScrollbar(float frame) {
|
||||
if (hasScrollbar()) {
|
||||
super.drawScrollbar(frame);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int scrollbarGuideAlignment() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected List<PresetTag> loadSelFromFile(File presetsDir, List<PresetTag> presets) {
|
||||
final File file = new File(presetsDir, "selected.ini");
|
||||
List<PresetTag> selected = new ArrayList<>();
|
||||
|
||||
if (file.exists()) {
|
||||
|
||||
try {
|
||||
|
||||
List<String> itemStrings;
|
||||
try (FileInputStream input = new FileInputStream(file)) {
|
||||
NEIClientConfig.logger.info("Loading presets selected from file {}", file);
|
||||
itemStrings = IOUtils.readLines(input, "UTF-8");
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to load presets selected from file {}", file, e);
|
||||
return selected;
|
||||
}
|
||||
|
||||
final HashMap<String, PresetTag> map = new HashMap<>();
|
||||
|
||||
for (PresetTag tag : presets) {
|
||||
map.put(tag.filename, tag);
|
||||
}
|
||||
|
||||
for (String filename : itemStrings) {
|
||||
if (map.containsKey(filename)) {
|
||||
selected.add(map.get(filename));
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Throwable th) {
|
||||
NEIClientConfig.logger.error("Failed to load presets selected from file", file);
|
||||
}
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
public void saveSelToFile() {
|
||||
|
||||
final File file = new File(presetsDir, "selected.ini");
|
||||
final List<String> list = new ArrayList<>();
|
||||
|
||||
for (final PresetTag tag : selected) {
|
||||
list.add(tag.filename);
|
||||
}
|
||||
|
||||
try (FileOutputStream output = new FileOutputStream(file)) {
|
||||
IOUtils.writeLines(list, "\n", output, "UTF-8");
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Filed to save presets selected list to file {}", file, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static class MouseSelection {
|
||||
|
||||
public int startX = -1;
|
||||
public int startY = -1;
|
||||
public int startIndex = -1;
|
||||
public int endIndex = -1;
|
||||
public HashSet<ItemStack> items = new HashSet<>();
|
||||
public boolean append = true;
|
||||
|
||||
public MouseSelection(int slotIndex, boolean append) {
|
||||
final ItemsGrid grid = ItemPanels.itemPanel.getGrid();
|
||||
final Rectangle4i rec = grid.getItemRect(slotIndex);
|
||||
|
||||
this.append = append;
|
||||
endIndex = slotIndex;
|
||||
startIndex = slotIndex;
|
||||
startX = rec.x;
|
||||
startY = rec.y;
|
||||
}
|
||||
}
|
||||
|
||||
protected static final FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer;
|
||||
protected static SubsetListBox listbox = new SubsetListBox();
|
||||
protected static File presetsDir;
|
||||
|
||||
protected static boolean openListBox = false;
|
||||
protected static PresetTag edit;
|
||||
protected long lastclicktime;
|
||||
protected static MouseSelection mouseSelection;
|
||||
|
||||
protected static final Button dropdown = new Button() {
|
||||
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
if (!rightclick) {
|
||||
openListBox = !openListBox;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRenderLabel() {
|
||||
return "...";
|
||||
}
|
||||
};
|
||||
|
||||
protected static final Label selectedValue = new Label("", false) {
|
||||
|
||||
@Override
|
||||
public void draw(int mousex, int mousey) {
|
||||
final String text = NEIClientUtils.cropText(fontRenderer, this.text, w);
|
||||
|
||||
if (text.equals(this.text)) {
|
||||
GuiDraw.drawString(text, x + w - fontRenderer.getStringWidth(text), y + (h - 8) / 2, colour);
|
||||
} else {
|
||||
GuiDraw.drawString(text, x, y + (h - 8) / 2, colour);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(int mx, int my, List<String> tooltip) {
|
||||
if (contains(mx, my) && listbox.getSelected().size() <= 1) {
|
||||
tooltip.add(translate("presets.label.tooltip"));
|
||||
}
|
||||
|
||||
return tooltip;
|
||||
}
|
||||
};
|
||||
|
||||
protected static final TextField selectedDisplayName = new TextField("") {
|
||||
|
||||
public void onTextChange(String oldText) {
|
||||
if (edit != null) {
|
||||
edit.displayName = text();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mousex, int mousey) {
|
||||
super.draw(mousex, mousey);
|
||||
|
||||
if (text().isEmpty()) {
|
||||
GuiDraw.drawGradientRect(x - 1, y - 1, 1, h + 2, 0xFFcc3300, 0xFFcc3300); // Left
|
||||
GuiDraw.drawGradientRect(x - 1, y - 1, w + 2, 1, 0xFFcc3300, 0xFFcc3300); // Top
|
||||
GuiDraw.drawGradientRect(x + w, y - 1, 1, h + 2, 0xFFcc3300, 0xFFcc3300); // Left
|
||||
GuiDraw.drawGradientRect(x - 1, y + h, w + 2, 1, 0xFFcc3300, 0xFFcc3300); // Bottom
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(int mx, int my, List<String> tooltip) {
|
||||
if (contains(mx, my) && listbox.getSelected().size() <= 1) {
|
||||
tooltip.add(translate("presets.textfield.tooltip.1"));
|
||||
tooltip.add(translate("presets.textfield.tooltip.2"));
|
||||
}
|
||||
|
||||
return tooltip;
|
||||
}
|
||||
};
|
||||
|
||||
protected static final Button selectedState = new Button("B") {
|
||||
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
if (!rightclick && edit != null) {
|
||||
edit.whitelist = !edit.whitelist;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRenderLabel() {
|
||||
return edit != null && edit.whitelist ? translate("presets.whitelist.label")
|
||||
: translate("presets.blacklist.label");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTooltips(List<String> tooltip) {
|
||||
if (edit != null) {
|
||||
tooltip.add(
|
||||
edit.whitelist ? translate("presets.whitelist.tooltip")
|
||||
: translate("presets.blacklist.tooltip"));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
protected static void setEditedTag(final PresetTag tag) {
|
||||
edit = tag;
|
||||
openListBox = false;
|
||||
selectedDisplayName.setText(tag != null ? tag.displayName : "");
|
||||
ItemList.updateFilter.restart();
|
||||
}
|
||||
|
||||
public static void addTag(final PresetTag tag) {
|
||||
addTag(tag, false);
|
||||
}
|
||||
|
||||
public static void addTag(final PresetTag tag, boolean sel) {
|
||||
listbox.addTag(tag, sel);
|
||||
}
|
||||
|
||||
public static boolean inEditMode() {
|
||||
return edit != null;
|
||||
}
|
||||
|
||||
public static boolean isHidden(final ItemStack item) {
|
||||
|
||||
if (edit != null) {
|
||||
|
||||
if (mouseSelection != null && mouseSelection.items.contains(item)) {
|
||||
return mouseSelection.append != edit.whitelist;
|
||||
}
|
||||
|
||||
return !edit.matches(item);
|
||||
}
|
||||
|
||||
if (!listbox.getSelected().isEmpty()) {
|
||||
final List<PresetTag> selected = listbox.getSelected();
|
||||
|
||||
for (int idx = 0; idx < selected.size(); idx++) {
|
||||
if (!selected.get(idx).matches(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void setHidden(final ItemStack stack, final boolean append) {
|
||||
if (edit == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NEIClientUtils.shiftKey()) {
|
||||
final ArrayList<ItemStack> items = ItemPanels.itemPanel.getItems();
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
if (stack.getItem().equals(items.get(i).getItem())) {
|
||||
hideItem(items.get(i), append);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (NEIClientUtils.controlKey()) {
|
||||
final String modId = getModId(stack);
|
||||
|
||||
if (modId == null) {
|
||||
hideItem(stack, append);
|
||||
} else {
|
||||
final ArrayList<ItemStack> items = ItemPanels.itemPanel.getItems();
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
final String mod = getModId(items.get(i));
|
||||
if (mod != null && mod.equals(modId)) {
|
||||
hideItem(items.get(i), append);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
hideItem(stack, append);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void hideItem(final ItemStack stack, boolean append) {
|
||||
final String guid = StackInfo.getItemStackGUID(stack);
|
||||
|
||||
if (append) {
|
||||
edit.items.add(guid);
|
||||
} else {
|
||||
edit.items.remove(guid);
|
||||
}
|
||||
}
|
||||
|
||||
protected static String getModId(final ItemStack stack) {
|
||||
try {
|
||||
return GameRegistry.findUniqueIdentifierFor(stack.getItem()).modId;
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void loadPresets(final String worldPath) {
|
||||
final File dir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
|
||||
presetsDir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath + "/presets");
|
||||
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
if (!presetsDir.exists()) {
|
||||
presetsDir.mkdirs();
|
||||
}
|
||||
|
||||
listbox = new SubsetListBox(presetsDir);
|
||||
|
||||
edit = null;
|
||||
openListBox = false;
|
||||
selectedDisplayName.setText("");
|
||||
|
||||
ItemList.updateFilter.restart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mx, int my) {
|
||||
|
||||
if (edit != null) {
|
||||
|
||||
selectedState.x = x;
|
||||
selectedState.y = y;
|
||||
selectedState.w = selectedState.h = h;
|
||||
selectedState.draw(mx, my);
|
||||
|
||||
selectedDisplayName.y = y;
|
||||
selectedDisplayName.h = h;
|
||||
selectedDisplayName.x = selectedState.x + selectedState.w + 1;
|
||||
selectedDisplayName.w = w - h * 2 - 5;
|
||||
selectedDisplayName.draw(mx, my);
|
||||
|
||||
} else {
|
||||
final List<PresetTag> selected = listbox.getSelected();
|
||||
final int size = selected.size();
|
||||
|
||||
selectedValue.text = size > 1 ? translate("presets.label.selected", size)
|
||||
: (size == 1 ? selected.get(0).displayName : "");
|
||||
selectedValue.y = y;
|
||||
selectedValue.h = h;
|
||||
selectedValue.w = w - h - 4;
|
||||
selectedValue.x = x;
|
||||
|
||||
selectedValue.draw(mx, my);
|
||||
}
|
||||
|
||||
dropdown.y = y;
|
||||
dropdown.w = dropdown.h = h;
|
||||
dropdown.x = x + w - dropdown.w;
|
||||
dropdown.state = edit != null || listbox.getNumSlots() == 0 ? 2 : 0;
|
||||
dropdown.draw(mx, my);
|
||||
|
||||
if (openListBox) {
|
||||
final int scrollbarWidth = listbox.hasScrollbar() ? listbox.scrollbarDim().width : 0;
|
||||
|
||||
listbox.setSize(
|
||||
x,
|
||||
y + h + 1,
|
||||
w,
|
||||
Math.min(((LayoutManager.searchField.y - h - y) / 18) * 18, listbox.contentHeight()));
|
||||
|
||||
listbox.setMargins(0, 0, scrollbarWidth, 0);
|
||||
listbox.draw(mx, my, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int px, int py) {
|
||||
return super.contains(px, py) || openListBox && listbox.contains(px, py);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleClick(int mx, int my, int button) {
|
||||
|
||||
if (openListBox && listbox.contains(mx, my)) {
|
||||
listbox.mouseClicked(mx, my, button);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (edit != null) {
|
||||
|
||||
if (selectedState.contains(mx, my)) {
|
||||
selectedState.handleClick(mx, my, button);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (selectedDisplayName.contains(mx, my)) {
|
||||
selectedDisplayName.handleClick(mx, my, button);
|
||||
return true;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (button == 0 && dropdown.contains(mx, my)) {
|
||||
openListBox = !openListBox;
|
||||
return true;
|
||||
}
|
||||
|
||||
openListBox = false;
|
||||
|
||||
if (button == 0 && selectedValue.contains(mx, my)) {
|
||||
|
||||
if (System.currentTimeMillis() - lastclicktime < 400) { // double click
|
||||
final List<PresetTag> selected = listbox.getSelected();
|
||||
final int size = selected.size();
|
||||
|
||||
if (size <= 1) {
|
||||
setEditedTag(size == 1 ? selected.get(0).copy() : new PresetTag(""));
|
||||
}
|
||||
}
|
||||
|
||||
lastclicktime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
return contains(mx, my);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleClickExt(int mx, int my, int button) {
|
||||
|
||||
if (edit != null && mouseSelection == null) {
|
||||
ItemPanelSlot slot = ItemPanels.itemPanel.getSlotMouseOver(mx, my);
|
||||
|
||||
if (slot != null && button != 2) {
|
||||
mouseSelection = new MouseSelection(slot.slotIndex, button == 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyPress(int keyID, char keyChar) {
|
||||
if (keyID == Keyboard.KEY_ESCAPE) {
|
||||
openListBox = false;
|
||||
}
|
||||
|
||||
if (edit == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (selectedDisplayName.focused() && (keyID == Keyboard.KEY_RETURN || keyID == Keyboard.KEY_NUMPADENTER)
|
||||
&& !selectedDisplayName.text().isEmpty()) {
|
||||
selectedDisplayName.handleKeyPress(keyID, keyChar);
|
||||
selectedDisplayName.setFocus(false);
|
||||
listbox.replaceSeleted(edit);
|
||||
setEditedTag(null);
|
||||
return true;
|
||||
} else if (selectedDisplayName.focused()) {
|
||||
return selectedDisplayName.handleKeyPress(keyID, keyChar);
|
||||
} else if (keyID == Keyboard.KEY_ESCAPE && !(NEIClientUtils.mc().currentScreen instanceof GuiRecipe)) {
|
||||
setEditedTag(null);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(int mx, int my, int button, long heldTime) {
|
||||
|
||||
if (openListBox) {
|
||||
listbox.mouseDragged(mx, my, button, heldTime);
|
||||
}
|
||||
|
||||
if (edit != null && button != 2 && mouseSelection != null) {
|
||||
final ItemPanelSlot slot = ItemPanels.itemPanel.getSlotMouseOver(mx, my);
|
||||
|
||||
if (slot != null && slot.slotIndex != mouseSelection.endIndex) {
|
||||
final ItemsGrid grid = ItemPanels.itemPanel.getGrid();
|
||||
mouseSelection.endIndex = slot.slotIndex;
|
||||
mouseSelection.items.clear();
|
||||
|
||||
final Rectangle4i rec = grid.getItemRect(slot.slotIndex);
|
||||
final Rectangle4i sel = new Rectangle4i(
|
||||
Math.min(rec.x, mouseSelection.startX),
|
||||
Math.min(rec.y, mouseSelection.startY),
|
||||
Math.max(rec.x, mouseSelection.startX) - Math.min(rec.x, mouseSelection.startX),
|
||||
Math.max(rec.y, mouseSelection.startY) - Math.min(rec.y, mouseSelection.startY));
|
||||
|
||||
for (int x = sel.x; x <= sel.x + sel.w; x += ItemsGrid.SLOT_SIZE) {
|
||||
for (int y = sel.y; y <= sel.y + sel.h; y += ItemsGrid.SLOT_SIZE) {
|
||||
ItemStack stack = ItemPanels.itemPanel.getStackMouseOver(x, y);
|
||||
|
||||
if (stack != null) {
|
||||
mouseSelection.items.add(stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseUp(int mx, int my, int button) {
|
||||
|
||||
if (openListBox) {
|
||||
listbox.mouseMovedOrUp(mx, my, button);
|
||||
}
|
||||
|
||||
if (edit != null && mouseSelection != null) {
|
||||
ItemPanelSlot hoverSlot = ItemPanels.itemPanel.getSlotMouseOver(mx, my);
|
||||
|
||||
if (hoverSlot != null && hoverSlot.slotIndex == mouseSelection.startIndex) {
|
||||
setHidden(hoverSlot.item, button == 0);
|
||||
} else if (!mouseSelection.items.isEmpty()) {
|
||||
|
||||
for (ItemStack stack : mouseSelection.items) {
|
||||
hideItem(stack, mouseSelection.append);
|
||||
}
|
||||
}
|
||||
|
||||
mouseSelection = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMouseWheel(int i, int mx, int my) {
|
||||
|
||||
if (openListBox && listbox.hasScrollbar() && listbox.contains(mx, my)) {
|
||||
listbox.scroll(-i);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClick(int mx, int my) {
|
||||
|
||||
if (!contains(mx, my)) {
|
||||
openListBox = false;
|
||||
}
|
||||
|
||||
selectedDisplayName.onGuiClick(mx, my);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(int mx, int my, List<String> tooltip) {
|
||||
|
||||
if (edit != null) {
|
||||
|
||||
if (selectedState.contains(mx, my)) {
|
||||
return selectedState.handleTooltip(mx, my, tooltip);
|
||||
}
|
||||
|
||||
if (selectedDisplayName.contains(mx, my)) {
|
||||
return selectedDisplayName.handleTooltip(mx, my, tooltip);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (selectedValue.contains(mx, my)) {
|
||||
return selectedValue.handleTooltip(mx, my, tooltip);
|
||||
}
|
||||
}
|
||||
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
public static boolean matches(ItemStack stack) {
|
||||
|
||||
if (edit != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final List<PresetTag> selected = listbox.getSelected();
|
||||
|
||||
for (int idx = 0; idx < selected.size(); idx++) {
|
||||
if (!selected.get(idx).matches(stack)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
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 implements ItemFilterProvider, IRecipeFilterProvider {
|
||||
|
||||
private static final TextHistory history = new TextHistory();
|
||||
|
||||
public RecipeSearchField(String ident) {
|
||||
super(ident);
|
||||
this.field.setVisible(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initInternalTextField() {
|
||||
final GuiSearchField field = new GuiSearchField();
|
||||
field.setMaxStringLength(maxSearchLength);
|
||||
field.setCursorPositionZero();
|
||||
field.setSkipRecipeTokens(true);
|
||||
((SearchTextFormatter) field.getFormatter()).setContextToken("<>");
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return this.field.getVisible();
|
||||
}
|
||||
|
||||
public void setVisible(boolean visible) {
|
||||
this.field.setVisible(visible);
|
||||
}
|
||||
|
||||
protected abstract boolean noResults();
|
||||
|
||||
@Override
|
||||
public int getTextColour() {
|
||||
if (!text().isEmpty() && !noResults()) {
|
||||
return focused() ? 0xFFcc3300 : 0xFF993300;
|
||||
} else {
|
||||
return focused() ? 0xFFE0E0E0 : 0xFF909090;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lastKeyTyped(int keyID, char keyChar) {
|
||||
|
||||
if (focused() && NEIClientConfig.isKeyHashDown("gui.getprevioussearch")) {
|
||||
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
|
||||
}
|
||||
|
||||
if (focused() && NEIClientConfig.isKeyHashDown("gui.getnextsearch")) {
|
||||
handleNavigateHistory(TextHistory.Direction.NEXT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filterText(String s) {
|
||||
return EnumChatFormatting.getTextWithoutFormattingCodes(s);
|
||||
}
|
||||
|
||||
@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();
|
||||
|
||||
if (previousFocus != focus) {
|
||||
history.add(text());
|
||||
}
|
||||
|
||||
super.setFocus(focus);
|
||||
}
|
||||
|
||||
private boolean handleNavigateHistory(TextHistory.Direction direction) {
|
||||
if (focused()) {
|
||||
return history.get(direction, text()).map(newText -> {
|
||||
setText(newText);
|
||||
return true;
|
||||
}).orElse(false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +1,26 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import static codechicken.nei.NEIClientConfig.world;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.nei.ItemList.AnyMultiItemFilter;
|
||||
import codechicken.nei.ItemList.EverythingItemFilter;
|
||||
import codechicken.nei.ItemList.PatternItemFilter;
|
||||
import codechicken.nei.api.API;
|
||||
import codechicken.nei.ItemList.NothingItemFilter;
|
||||
import codechicken.nei.SearchTokenParser.ISearchParserProvider;
|
||||
import codechicken.nei.SearchTokenParser.SearchMode;
|
||||
import codechicken.nei.api.IRecipeFilter;
|
||||
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.TextHistory;
|
||||
|
||||
public class SearchField extends TextField implements ItemFilterProvider {
|
||||
@@ -23,6 +28,7 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
/**
|
||||
* Interface for returning a custom filter based on search field text
|
||||
*/
|
||||
@Deprecated
|
||||
public static interface ISearchProvider {
|
||||
|
||||
/**
|
||||
@@ -36,34 +42,115 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
public ItemFilter getFilter(String searchText);
|
||||
}
|
||||
|
||||
private static class DefaultSearchProvider implements ISearchProvider {
|
||||
public static class SearchParserProvider implements ISearchParserProvider {
|
||||
|
||||
@Override
|
||||
public boolean isPrimary() {
|
||||
return false;
|
||||
protected final Function<Pattern, ItemFilter> createFilter;
|
||||
protected final String name;
|
||||
protected final char prefix;
|
||||
protected final EnumChatFormatting highlightedColor;
|
||||
|
||||
public SearchParserProvider(char prefix, String name, EnumChatFormatting highlightedColor,
|
||||
Function<Pattern, ItemFilter> createFilter) {
|
||||
this.prefix = prefix;
|
||||
this.name = name;
|
||||
this.highlightedColor = highlightedColor;
|
||||
this.createFilter = createFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter getFilter(String searchText) {
|
||||
Pattern pattern = getPattern(searchText);
|
||||
return pattern == null ? null : new PatternItemFilter(pattern);
|
||||
Pattern pattern = SearchField.getPattern(searchText);
|
||||
|
||||
if (pattern != null) {
|
||||
return this.createFilter(pattern);
|
||||
}
|
||||
|
||||
return new NothingItemFilter();
|
||||
}
|
||||
|
||||
protected ItemFilter createFilter(Pattern pattern) {
|
||||
final ItemFilter filter = this.createFilter.apply(pattern);
|
||||
|
||||
return filter == null ? new NothingItemFilter() : filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getPrefix() {
|
||||
return this.prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumChatFormatting getHighlightedColor() {
|
||||
return this.highlightedColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchMode getSearchMode() {
|
||||
return SearchMode.fromInt(NEIClientConfig.getIntSetting("inventory.search." + this.name + "SearchMode"));
|
||||
}
|
||||
}
|
||||
|
||||
public static class GuiSearchField extends FormattedTextField implements ItemFilterProvider, IRecipeFilterProvider {
|
||||
|
||||
protected final SearchTokenParser searchParser;
|
||||
protected boolean skipRecipeTokens = false;
|
||||
|
||||
public GuiSearchField() {
|
||||
this(SearchField.searchParser);
|
||||
}
|
||||
|
||||
public GuiSearchField(SearchTokenParser searchParser) {
|
||||
super(Minecraft.getMinecraft().fontRenderer, 0, 0, 0, 0);
|
||||
this.searchParser = searchParser;
|
||||
setFormatter(new SearchTextFormatter(searchParser));
|
||||
setDisabledTextColour(0xFF303030);
|
||||
setPlaceholder(NEIClientUtils.translate("inventory.search.placeholder"));
|
||||
}
|
||||
|
||||
public 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, this.skipRecipeTokens);
|
||||
}
|
||||
|
||||
public IRecipeFilter getRecipeFilter(String filterText) {
|
||||
return this.searchParser.getRecipeFilter(filterText);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static List<ISearchProvider> searchProviders = new LinkedList<>();
|
||||
public static final SearchTokenParser searchParser = new SearchTokenParser();
|
||||
private static final TextHistory history = new TextHistory();
|
||||
private boolean isVisible = true;
|
||||
|
||||
long lastclicktime;
|
||||
private long lastclicktime;
|
||||
|
||||
public SearchField(String ident) {
|
||||
super(ident);
|
||||
API.addItemFilter(this);
|
||||
API.addSearchProvider(new DefaultSearchProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initInternalTextField() {
|
||||
field = new GuiSearchField();
|
||||
field.setMaxStringLength(maxSearchLength);
|
||||
field.setCursorPositionZero();
|
||||
}
|
||||
|
||||
public static boolean searchInventories() {
|
||||
return world.nbt.getBoolean("searchinventories");
|
||||
return NEIClientConfig.world.nbt.getBoolean("searchinventories");
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
@@ -76,7 +163,8 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
|
||||
@Override
|
||||
public int getTextColour() {
|
||||
if (ItemPanels.itemPanel.getItems().isEmpty()) {
|
||||
if (ItemPanels.itemPanel.getItems().isEmpty()
|
||||
&& (!this.field.getText().isEmpty() || !NEIClientConfig.hideItemsUntilSearching())) {
|
||||
return focused() ? 0xFFcc3300 : 0xFF993300;
|
||||
} else {
|
||||
return focused() ? 0xFFE0E0E0 : 0xFF909090;
|
||||
@@ -85,14 +173,37 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
|
||||
@Override
|
||||
public void draw(int mousex, int mousey) {
|
||||
|
||||
super.draw(mousex, mousey);
|
||||
|
||||
if (searchInventories()) {
|
||||
GuiDraw.drawGradientRect(x - 1, y - 1, 1, h + 2, 0xFFFFFF00, 0xFFC0B000); // Left
|
||||
GuiDraw.drawGradientRect(x - 1, y - 1, w + 2, 1, 0xFFFFFF00, 0xFFC0B000); // Top
|
||||
GuiDraw.drawGradientRect(x + w, y - 1, 1, h + 2, 0xFFFFFF00, 0xFFC0B000); // Left
|
||||
GuiDraw.drawGradientRect(x - 1, y + h, w + 2, 1, 0xFFFFFF00, 0xFFC0B000); // Bottom
|
||||
GuiDraw.drawGradientRect(
|
||||
field.xPosition - 1,
|
||||
field.yPosition - 1,
|
||||
1,
|
||||
field.height + 2,
|
||||
0xFFFFFF00,
|
||||
0xFFC0B000); // Left
|
||||
GuiDraw.drawGradientRect(
|
||||
field.xPosition - 1,
|
||||
field.yPosition - 1,
|
||||
field.width + 2,
|
||||
1,
|
||||
0xFFFFFF00,
|
||||
0xFFC0B000); // Top
|
||||
GuiDraw.drawGradientRect(
|
||||
field.xPosition + field.width,
|
||||
field.yPosition - 1,
|
||||
1,
|
||||
field.height + 2,
|
||||
0xFFFFFF00,
|
||||
0xFFC0B000); // Left
|
||||
GuiDraw.drawGradientRect(
|
||||
field.xPosition - 1,
|
||||
field.yPosition + field.height,
|
||||
field.width + 2,
|
||||
1,
|
||||
0xFFFFFF00,
|
||||
0xFFC0B000); // Bottom
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +212,6 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
if (button == 0) {
|
||||
if (focused() && (System.currentTimeMillis() - lastclicktime < 400)) { // double click
|
||||
NEIClientConfig.world.nbt.setBoolean("searchinventories", !searchInventories());
|
||||
NEIClientConfig.world.saveNBT();
|
||||
}
|
||||
lastclicktime = System.currentTimeMillis();
|
||||
}
|
||||
@@ -111,10 +221,11 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
@Override
|
||||
public void onTextChange(String oldText) {
|
||||
final String newText = text();
|
||||
if (newText.length() > 0) NEIClientConfig.logger.debug("Searching for " + text());
|
||||
|
||||
NEIClientConfig.setSearchExpression(newText);
|
||||
ItemList.updateFilter.restart();
|
||||
if (!newText.equals(oldText)) {
|
||||
if (newText.length() > 0) NEIClientConfig.logger.debug("Searching for " + newText);
|
||||
NEIClientConfig.setSearchExpression(newText);
|
||||
ItemList.updateFilter.restart();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,11 +234,11 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
if (isVisible() && NEIClientConfig.isKeyHashDown("gui.search")) {
|
||||
setFocus(true);
|
||||
}
|
||||
if (NEIClientConfig.isKeyHashDown("gui.getprevioussearch") && focused()) {
|
||||
if (focused() && NEIClientConfig.isKeyHashDown("gui.getprevioussearch")) {
|
||||
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.getnextsearch") && focused()) {
|
||||
if (focused() && NEIClientConfig.isKeyHashDown("gui.getnextsearch")) {
|
||||
handleNavigateHistory(TextHistory.Direction.NEXT);
|
||||
}
|
||||
}
|
||||
@@ -138,36 +249,106 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
}
|
||||
|
||||
public static Pattern getPattern(String search) {
|
||||
switch (NEIClientConfig.getIntSetting("inventory.searchmode")) {
|
||||
return getPattern(search, NEIClientConfig.getIntSetting("inventory.search.patternMode"));
|
||||
}
|
||||
|
||||
public static Pattern getPattern(String search, int patternMode) {
|
||||
switch (patternMode) {
|
||||
case 0: // plain
|
||||
search = "\\Q" + search + "\\E";
|
||||
search = Pattern.quote(search);
|
||||
break;
|
||||
case 1: // extended
|
||||
|
||||
if (search.length() >= 3 && search.startsWith("r/") && search.endsWith("/")) {
|
||||
search = search.substring(2, search.length() - 1);
|
||||
} else {
|
||||
final Matcher matcher = Pattern.compile("(\\?|\\*)").matcher(search);
|
||||
final StringBuilder cleanedString = new StringBuilder();
|
||||
int lastEndIndex = 0;
|
||||
|
||||
while (matcher.find()) {
|
||||
cleanedString.append(Pattern.quote(search.substring(lastEndIndex, matcher.start())));
|
||||
|
||||
switch (matcher.group(0).charAt(0)) {
|
||||
case '?':
|
||||
cleanedString.append(".");
|
||||
break;
|
||||
case '*':
|
||||
cleanedString.append(".+?");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
lastEndIndex = matcher.end();
|
||||
}
|
||||
|
||||
search = cleanedString + Pattern.quote(search.substring(lastEndIndex, search.length()));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// regex and extended+
|
||||
if (!search.isEmpty()) {
|
||||
try {
|
||||
return Pattern.compile(search, Pattern.MULTILINE | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
|
||||
} catch (PatternSyntaxException ignored) {}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getEscapedSearchText(ItemStack stack) {
|
||||
final FluidStack fluidStack = StackInfo.getFluid(stack);
|
||||
String displayName;
|
||||
|
||||
if (fluidStack != null) {
|
||||
displayName = fluidStack.getLocalizedName();
|
||||
} else {
|
||||
displayName = stack.getDisplayName();
|
||||
}
|
||||
|
||||
return getEscapedSearchText(displayName);
|
||||
}
|
||||
|
||||
public static String getEscapedSearchText(String text) {
|
||||
text = EnumChatFormatting.getTextWithoutFormattingCodes(text);
|
||||
|
||||
switch (NEIClientConfig.getIntSetting("inventory.search.patternMode")) {
|
||||
case 1:
|
||||
search = search.replace(".", "").replace("?", ".").replace("*", ".+?");
|
||||
text = text.replaceAll("[\\?|\\*]", "\\\\$0");
|
||||
break;
|
||||
case 2:
|
||||
text = text.replaceAll("[{}()\\[\\].+*?^$\\\\|]", "\\\\$0");
|
||||
break;
|
||||
case 3:
|
||||
text = text.replaceAll("\"", "\\\\$0");
|
||||
text = "\"" + text + "\"";
|
||||
return text;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Pattern pattern = null;
|
||||
try {
|
||||
pattern = Pattern.compile(search);
|
||||
} catch (PatternSyntaxException ignored) {}
|
||||
return pattern == null || pattern.toString().length() == 0 ? null : pattern;
|
||||
if (text.contains(" ") && NEIClientConfig.getBooleanSetting("inventory.search.quoteDropItemName")) {
|
||||
text = "\"" + text + "\"";
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter getFilter() {
|
||||
String s_filter = text().toLowerCase();
|
||||
|
||||
List<ItemFilter> primary = new LinkedList<>();
|
||||
List<ItemFilter> secondary = new LinkedList<>();
|
||||
for (ISearchProvider p : searchProviders) {
|
||||
ItemFilter filter = p.getFilter(s_filter);
|
||||
if (filter != null) (p.isPrimary() ? primary : secondary).add(filter);
|
||||
if (field.getText().isEmpty() && NEIClientConfig.hideItemsUntilSearching()) {
|
||||
return new NothingItemFilter();
|
||||
}
|
||||
|
||||
if (!primary.isEmpty()) return new AnyMultiItemFilter(primary);
|
||||
if (!secondary.isEmpty()) return new AnyMultiItemFilter(secondary);
|
||||
return new EverythingItemFilter();
|
||||
return ((GuiSearchField) field).getFilter();
|
||||
}
|
||||
|
||||
public static ItemFilter getFilter(String filterText) {
|
||||
return SearchField.searchParser.getFilter(filterText);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import codechicken.nei.FormattedTextField.TextFormatter;
|
||||
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 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 (String[] orQuery : searchParser.splitByDelimiters(text, "|", false)) {
|
||||
final String filterText = orQuery[1];
|
||||
|
||||
formattedText.append(SearchExpressionUtils.HIGHLIGHTS.OR + orQuery[0]);
|
||||
|
||||
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()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return formattedText.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.Language;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import codechicken.nei.ItemList.AllMultiItemFilter;
|
||||
import codechicken.nei.ItemList.AnyMultiItemFilter;
|
||||
import codechicken.nei.ItemList.EverythingItemFilter;
|
||||
import codechicken.nei.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 {
|
||||
|
||||
public enum SearchMode {
|
||||
|
||||
ALWAYS,
|
||||
PREFIX,
|
||||
NEVER;
|
||||
|
||||
public static SearchMode fromInt(int value) {
|
||||
return switch (value) {
|
||||
case 0 -> ALWAYS;
|
||||
case 1 -> PREFIX;
|
||||
default -> NEVER;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static interface ISearchParserProvider {
|
||||
|
||||
public ItemFilter getFilter(String searchText);
|
||||
|
||||
public static List<Language> getAllLanguages() {
|
||||
return new ArrayList<>(Minecraft.getMinecraft().getLanguageManager().getLanguages());
|
||||
}
|
||||
|
||||
default List<Language> getMatchingLanguages() {
|
||||
return getAllLanguages();
|
||||
}
|
||||
|
||||
public char getPrefix();
|
||||
|
||||
public EnumChatFormatting getHighlightedColor();
|
||||
|
||||
public SearchMode getSearchMode();
|
||||
}
|
||||
|
||||
private static class ProvidersCache {
|
||||
|
||||
public String languageCode = null;
|
||||
public List<ISearchParserProvider> providers = new ArrayList<>();
|
||||
|
||||
public void clear() {
|
||||
this.languageCode = null;
|
||||
this.providers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static class IsRegisteredItemFilter implements ItemFilter {
|
||||
|
||||
public ItemFilter filter;
|
||||
|
||||
public IsRegisteredItemFilter(ItemFilter filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(ItemStack item) {
|
||||
return item != null && item.getItem() != null
|
||||
&& item.getItem().delegate.name() != null
|
||||
&& this.filter.matches(item);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public SearchTokenParser() {
|
||||
this(new ArrayList<>());
|
||||
}
|
||||
|
||||
public void addProvider(ISearchParserProvider provider) {
|
||||
this.searchProviders.add(provider);
|
||||
clearCache();
|
||||
}
|
||||
|
||||
public void clearCache() {
|
||||
this.providersCache.clear();
|
||||
this.filtersCache.clear();
|
||||
this.recipesCache.clear();
|
||||
this.prefixes = null;
|
||||
}
|
||||
|
||||
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<>();
|
||||
|
||||
for (int index = this.searchProviders.size() - 1; index >= 0; index--) {
|
||||
ISearchParserProvider provider = this.searchProviders.get(index);
|
||||
|
||||
if (provider.getMatchingLanguages().contains(currentLanguage)) {
|
||||
if (provider.getSearchMode() == SearchMode.PREFIX && !providers.containsKey(provider.getPrefix())) {
|
||||
providers.put(provider.getPrefix(), provider);
|
||||
} else if (provider.getSearchMode() == SearchMode.ALWAYS) {
|
||||
providersCache.providers.add(provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
providersCache.providers.addAll(providers.values());
|
||||
}
|
||||
|
||||
return providersCache.providers;
|
||||
}
|
||||
|
||||
public boolean hasRedefinedPrefix(char ch) {
|
||||
return getPrefixes().indexOf(ch) >= 0;
|
||||
}
|
||||
|
||||
public ISearchParserProvider getProvider(char ch) {
|
||||
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();
|
||||
|
||||
if (filterText == null || filterText.isEmpty()) {
|
||||
return new RecipeFilter(FilterContext.ANY, true, new EverythingItemFilter());
|
||||
}
|
||||
|
||||
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 int spaceMode = NEIClientConfig.getIntSetting("inventory.search.spaceMode");
|
||||
final String prefixes = getPrefixes();
|
||||
SearchToken lastToken = null;
|
||||
int lastEnd = 0;
|
||||
|
||||
for (String[] part : splitByDelimiters(filterText, "-!" + prefixes, true)) {
|
||||
final SearchToken token = createToken(lastEnd, part, prefixes);
|
||||
final int length = part[0].length() + part[1].length();
|
||||
|
||||
if (token.isSimpleFilter() && token.rawText.isEmpty()) {
|
||||
lastEnd += length;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spaceMode == 0) { // and
|
||||
tokens.add(lastToken = token);
|
||||
} else if (spaceMode == 1) { // space
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
lastEnd += length;
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private SearchToken createToken(int lastEnd, String[] part, String prefixes) {
|
||||
final SearchToken token = new SearchToken();
|
||||
String pref = part[0];
|
||||
String query = part[1].trim();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.boss.BossStatus;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.IItemRenderer;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
@@ -27,21 +26,16 @@ public class SpawnerRenderer implements IItemRenderer {
|
||||
|
||||
public void renderInventoryItem(RenderBlocks render, ItemStack item) {
|
||||
int meta = item.getItemDamage();
|
||||
|
||||
if (meta == 0) meta = ItemMobSpawner.idPig;
|
||||
|
||||
String bossName = BossStatus.bossName;
|
||||
int bossTimeout = BossStatus.statusBarTime;
|
||||
boolean bossHasColorModifier = BossStatus.hasColorModifier;
|
||||
Entity entity = ItemMobSpawner.getEntity(meta);
|
||||
try {
|
||||
World world = NEIClientUtils.mc().theWorld;
|
||||
ItemMobSpawner.loadSpawners(world);
|
||||
CCRenderState.changeTexture(TextureMap.locationBlocksTexture);
|
||||
render.renderBlockAsItem(Blocks.mob_spawner, 0, 1F);
|
||||
entity.setWorld(render.minecraftRB.theWorld);
|
||||
GL11.glPushMatrix();
|
||||
|
||||
Entity entity = ItemMobSpawner.getEntity(meta);
|
||||
entity.setWorld(world);
|
||||
float f1 = 0.4375F;
|
||||
if (entity.getShadowSize() > 1.5) f1 = 0.1F;
|
||||
GL11.glRotatef((float) (ClientUtils.getRenderTime() * 10), 0.0F, 1.0F, 0.0F);
|
||||
@@ -51,7 +45,6 @@ public class SpawnerRenderer implements IItemRenderer {
|
||||
entity.setLocationAndAngles(0, 0, 0, 0.0F, 0.0F);
|
||||
RenderManager.instance.renderEntityWithPosYaw(entity, 0.0D, 0.0D, 0.0D, 0.0F, 0);
|
||||
GL11.glPopMatrix();
|
||||
|
||||
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
|
||||
OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit);
|
||||
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
@@ -64,7 +57,6 @@ public class SpawnerRenderer implements IItemRenderer {
|
||||
BossStatus.hasColorModifier = bossHasColorModifier;
|
||||
}
|
||||
|
||||
@SuppressWarnings("incomplete-switch")
|
||||
@Override
|
||||
public void renderItem(ItemRenderType type, ItemStack item, Object... data) {
|
||||
switch (type) {
|
||||
@@ -75,6 +67,8 @@ public class SpawnerRenderer implements IItemRenderer {
|
||||
case ENTITY:
|
||||
renderInventoryItem((RenderBlocks) data[0], item);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -9,7 +9,7 @@ public abstract class TextField extends Widget {
|
||||
|
||||
protected GuiTextField field;
|
||||
|
||||
private static final int maxSearchLength = 256;
|
||||
protected static final int maxSearchLength = 256;
|
||||
|
||||
public boolean centered;
|
||||
public String identifier;
|
||||
|
||||
@@ -6,9 +6,9 @@ import cpw.mods.fml.common.FMLCommonHandler;
|
||||
|
||||
public class ThreadOperationTimer extends Thread {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class TimeoutException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -8621458005263888185L;
|
||||
public final Object operation;
|
||||
|
||||
public TimeoutException(String msg, Object op) {
|
||||
|
||||
@@ -15,10 +15,6 @@ public class VisiblityData {
|
||||
* Subset dropdown
|
||||
*/
|
||||
public boolean showSubsetDropdown = true;
|
||||
/**
|
||||
* Presets dropdown
|
||||
*/
|
||||
public boolean showPresetsDropdown = true;
|
||||
/**
|
||||
* Item and search section
|
||||
*/
|
||||
@@ -44,7 +40,6 @@ public class VisiblityData {
|
||||
public void translateDependancies() {
|
||||
if (!showNEI) showWidgets = false;
|
||||
if (!showWidgets) showItemSection = showUtilityButtons = false;
|
||||
if (!showItemSection)
|
||||
showBookmarkPanel = showSubsetDropdown = showPresetsDropdown = showSearchSection = showItemPanel = false;
|
||||
if (!showItemSection) showBookmarkPanel = showSubsetDropdown = showSearchSection = showItemPanel = false;
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,6 @@ public class WidgetZOrder implements Comparator<Widget> {
|
||||
}
|
||||
|
||||
public int compare(Widget w1, Widget w2) {
|
||||
return w1.z != w2.z ? ((topfirst ? w1.z > w2.z : w1.z < w2.z) ? 1 : -1) : 1;
|
||||
return w1.z != w2.z ? ((topfirst ? w1.z < w2.z : w1.z > w2.z) ? 1 : -1) : 1;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EnumCreatureType;
|
||||
import net.minecraft.entity.passive.EntityPig;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.ChatComponentText;
|
||||
import net.minecraft.world.EnumSkyBlock;
|
||||
import net.minecraft.world.SpawnerAnimals;
|
||||
import net.minecraft.world.World;
|
||||
@@ -16,6 +17,7 @@ import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.math.MathHelper;
|
||||
import codechicken.nei.KeyManager.IKeyStateTracker;
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper;
|
||||
|
||||
public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
|
||||
@@ -25,21 +27,29 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
private static byte[] mobSpawnCache;
|
||||
private static long mobOverlayUpdateTime;
|
||||
private static String oregenPatternName;
|
||||
private static boolean hasOregenPatternBeenSet = false;
|
||||
|
||||
public static void reset() {
|
||||
mobOverlay = 0;
|
||||
chunkOverlay = 0;
|
||||
hasOregenPatternBeenSet = false;
|
||||
oregenPatternName = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
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.chunkoverlay").down)
|
||||
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)
|
||||
NEIClientUtils.printChatMessage(
|
||||
new ChatComponentText(NEIClientUtils.translate("chat.chunkoverlay." + chunkOverlay)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void render(float frame) {
|
||||
@@ -67,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;
|
||||
@@ -88,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;
|
||||
@@ -171,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;
|
||||
@@ -198,7 +220,9 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
GL11.glLineWidth(1.5F);
|
||||
GL11.glBegin(GL11.GL_LINES);
|
||||
|
||||
final Tessellator tess = Tessellator.instance;
|
||||
tess.startDrawing(GL11.GL_LINES);
|
||||
|
||||
for (int cx = -4; cx <= 4; cx++) for (int cz = -4; cz <= 4; cz++) {
|
||||
double x1 = ((entity.chunkCoordX + cx) << 4) - intOffsetX;
|
||||
@@ -224,22 +248,22 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
|
||||
double dist = Math.pow(1.5, -(cx * cx + cz * cz));
|
||||
|
||||
GL11.glColor4d(0.9, 0, 0, dist);
|
||||
tess.setColorRGBA_F(0.9F, 0, 0, (float) dist);
|
||||
if (cx >= 0 && cz >= 0) {
|
||||
GL11.glVertex3d(x2, y1, z2);
|
||||
GL11.glVertex3d(x2, y2, z2);
|
||||
tess.addVertex(x2, y1, z2);
|
||||
tess.addVertex(x2, y2, z2);
|
||||
}
|
||||
if (cx >= 0 && cz <= 0) {
|
||||
GL11.glVertex3d(x2, y1, z1);
|
||||
GL11.glVertex3d(x2, y2, z1);
|
||||
tess.addVertex(x2, y1, z1);
|
||||
tess.addVertex(x2, y2, z1);
|
||||
}
|
||||
if (cx <= 0 && cz >= 0) {
|
||||
GL11.glVertex3d(x1, y1, z2);
|
||||
GL11.glVertex3d(x1, y2, z2);
|
||||
tess.addVertex(x1, y1, z2);
|
||||
tess.addVertex(x1, y2, z2);
|
||||
}
|
||||
if (cx <= 0 && cz <= 0) {
|
||||
GL11.glVertex3d(x1, y1, z1);
|
||||
GL11.glVertex3d(x1, y2, z1);
|
||||
tess.addVertex(x1, y1, z1);
|
||||
tess.addVertex(x1, y2, z1);
|
||||
}
|
||||
|
||||
if (cx == 0 && cz == 0) {
|
||||
@@ -260,40 +284,31 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
y1 -= intOffsetY;
|
||||
y2 -= intOffsetY;
|
||||
|
||||
GL11.glColor4d(0, 0.9, 0, 0.4);
|
||||
tess.setColorRGBA_F(0, 0.9F, 0, 0.4F);
|
||||
for (double y = (int) y1; y <= y2; y++) {
|
||||
GL11.glVertex3d(x2, y, z1);
|
||||
GL11.glVertex3d(x2, y, z2);
|
||||
GL11.glVertex3d(x1, y, z1);
|
||||
GL11.glVertex3d(x1, y, z2);
|
||||
GL11.glVertex3d(x1, y, z2);
|
||||
GL11.glVertex3d(x2, y, z2);
|
||||
GL11.glVertex3d(x1, y, z1);
|
||||
GL11.glVertex3d(x2, y, z1);
|
||||
tess.addVertex(x2, y, z1);
|
||||
tess.addVertex(x2, y, z2);
|
||||
tess.addVertex(x1, y, z1);
|
||||
tess.addVertex(x1, y, z2);
|
||||
tess.addVertex(x1, y, z2);
|
||||
tess.addVertex(x2, y, z2);
|
||||
tess.addVertex(x1, y, z1);
|
||||
tess.addVertex(x2, y, z1);
|
||||
}
|
||||
for (double h = 1; h <= 15; h++) {
|
||||
GL11.glVertex3d(x1 + h, y1, z1);
|
||||
GL11.glVertex3d(x1 + h, y2, z1);
|
||||
GL11.glVertex3d(x1 + h, y1, z2);
|
||||
GL11.glVertex3d(x1 + h, y2, z2);
|
||||
GL11.glVertex3d(x1, y1, z1 + h);
|
||||
GL11.glVertex3d(x1, y2, z1 + h);
|
||||
GL11.glVertex3d(x2, y1, z1 + h);
|
||||
GL11.glVertex3d(x2, y2, z1 + h);
|
||||
tess.addVertex(x1 + h, y1, z1);
|
||||
tess.addVertex(x1 + h, y2, z1);
|
||||
tess.addVertex(x1 + h, y1, z2);
|
||||
tess.addVertex(x1 + h, y2, z2);
|
||||
tess.addVertex(x1, y1, z1 + h);
|
||||
tess.addVertex(x1, y2, z1 + h);
|
||||
tess.addVertex(x2, y1, z1 + h);
|
||||
tess.addVertex(x2, y2, z1 + h);
|
||||
}
|
||||
} else if (chunkOverlay == 3) {
|
||||
if (!hasOregenPatternBeenSet) {
|
||||
try {
|
||||
oregenPatternName = ((Enum<?>) Class.forName("gregtech.common.GT_Worldgenerator")
|
||||
.getDeclaredField("oregenPattern").get(null)).name();
|
||||
} catch (Exception ignored) {
|
||||
oregenPatternName = "AXISSYMMETRICAL";
|
||||
}
|
||||
hasOregenPatternBeenSet = true;
|
||||
}
|
||||
int gx1;
|
||||
int gz1;
|
||||
if (oregenPatternName.equals("EQUAL_SPACING")) {
|
||||
if (getOregenPatternName().equals("EQUAL_SPACING")) {
|
||||
// gt oregen uses new regular pattern
|
||||
gx1 = ((Math.floorDiv(entity.chunkCoordX, 3) * 3) << 4) - intOffsetX;
|
||||
gz1 = ((Math.floorDiv(entity.chunkCoordZ, 3) * 3) << 4) - intOffsetZ;
|
||||
@@ -313,55 +328,71 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
int gx2 = gx1 + 48;
|
||||
int gz2 = gz1 + 48;
|
||||
|
||||
GL11.glColor4d(0, 0.9, 0, 0.4);
|
||||
tess.setColorRGBA_F(0, 0.9F, 0, 0.4F);
|
||||
for (double y = (int) y1; y <= y2; y++) {
|
||||
GL11.glVertex3d(gx2, y, gz1);
|
||||
GL11.glVertex3d(gx2, y, gz2);
|
||||
GL11.glVertex3d(gx1, y, gz1);
|
||||
GL11.glVertex3d(gx1, y, gz2);
|
||||
GL11.glVertex3d(gx1, y, gz2);
|
||||
GL11.glVertex3d(gx2, y, gz2);
|
||||
GL11.glVertex3d(gx1, y, gz1);
|
||||
GL11.glVertex3d(gx2, y, gz1);
|
||||
tess.addVertex(gx2, y, gz1);
|
||||
tess.addVertex(gx2, y, gz2);
|
||||
tess.addVertex(gx1, y, gz1);
|
||||
tess.addVertex(gx1, y, gz2);
|
||||
tess.addVertex(gx1, y, gz2);
|
||||
tess.addVertex(gx2, y, gz2);
|
||||
tess.addVertex(gx1, y, gz1);
|
||||
tess.addVertex(gx2, y, gz1);
|
||||
}
|
||||
for (double h = 4; h <= 44; h += 4) {
|
||||
if (h % 16 == 0) {
|
||||
continue;
|
||||
}
|
||||
GL11.glVertex3d(gx1 + h, y1, gz1);
|
||||
GL11.glVertex3d(gx1 + h, y2, gz1);
|
||||
GL11.glVertex3d(gx1 + h, y1, gz2);
|
||||
GL11.glVertex3d(gx1 + h, y2, gz2);
|
||||
GL11.glVertex3d(gx1, y1, gz1 + h);
|
||||
GL11.glVertex3d(gx1, y2, gz1 + h);
|
||||
GL11.glVertex3d(gx2, y1, gz1 + h);
|
||||
GL11.glVertex3d(gx2, y2, gz1 + h);
|
||||
tess.addVertex(gx1 + h, y1, gz1);
|
||||
tess.addVertex(gx1 + h, y2, gz1);
|
||||
tess.addVertex(gx1 + h, y1, gz2);
|
||||
tess.addVertex(gx1 + h, y2, gz2);
|
||||
tess.addVertex(gx1, y1, gz1 + h);
|
||||
tess.addVertex(gx1, y2, gz1 + h);
|
||||
tess.addVertex(gx2, y1, gz1 + h);
|
||||
tess.addVertex(gx2, y2, gz1 + h);
|
||||
}
|
||||
|
||||
GL11.glColor4d(0, 0, 0.9, 0.4);
|
||||
tess.setColorRGBA_F(0, 0, 0.9F, 0.4F);
|
||||
gx1 += 23;
|
||||
gz1 += 23;
|
||||
gx2 = gx1 + 1;
|
||||
gz2 = gz1 + 1;
|
||||
|
||||
GL11.glVertex3d(gx1, y1, gz1);
|
||||
GL11.glVertex3d(gx1, y2, gz1);
|
||||
GL11.glVertex3d(gx2, y1, gz1);
|
||||
GL11.glVertex3d(gx2, y2, gz1);
|
||||
GL11.glVertex3d(gx1, y1, gz2);
|
||||
GL11.glVertex3d(gx1, y2, gz2);
|
||||
GL11.glVertex3d(gx2, y1, gz2);
|
||||
GL11.glVertex3d(gx2, y2, gz2);
|
||||
tess.addVertex(gx1, y1, gz1);
|
||||
tess.addVertex(gx1, y2, gz1);
|
||||
tess.addVertex(gx2, y1, gz1);
|
||||
tess.addVertex(gx2, y2, gz1);
|
||||
tess.addVertex(gx1, y1, gz2);
|
||||
tess.addVertex(gx1, y2, gz2);
|
||||
tess.addVertex(gx2, y1, gz2);
|
||||
tess.addVertex(gx2, y2, gz2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GL11.glEnd();
|
||||
tess.draw();
|
||||
GL11.glEnable(GL11.GL_LIGHTING);
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
GL11.glDisable(GL11.GL_BLEND);
|
||||
}
|
||||
|
||||
private static String getOregenPatternName() {
|
||||
|
||||
if (oregenPatternName == null) {
|
||||
try {
|
||||
final ClassLoader loader = WorldOverlayRenderer.class.getClassLoader();
|
||||
final Class<?> gtWorldGenerator = ReflectionHelper
|
||||
.getClass(loader, "gregtech.common.GTWorldgenerator", "gregtech.common.GT_Worldgenerator");
|
||||
oregenPatternName = ((Enum<?>) gtWorldGenerator.getDeclaredField("oregenPattern").get(null)).name();
|
||||
} catch (Exception ignored) {
|
||||
oregenPatternName = "AXISSYMMETRICAL";
|
||||
}
|
||||
}
|
||||
|
||||
return oregenPatternName;
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
KeyManager.trackers.add(new WorldOverlayRenderer());
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package codechicken.nei.api;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
@@ -14,6 +15,7 @@ import org.lwjgl.input.Keyboard;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import codechicken.nei.BookmarkContainerInfo;
|
||||
import codechicken.nei.ItemList;
|
||||
import codechicken.nei.ItemSorter;
|
||||
import codechicken.nei.ItemStackSet;
|
||||
@@ -24,13 +26,16 @@ import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.OffsetPositioner;
|
||||
import codechicken.nei.SearchField;
|
||||
import codechicken.nei.SearchField.ISearchProvider;
|
||||
import codechicken.nei.SearchTokenParser.ISearchParserProvider;
|
||||
import codechicken.nei.SubsetWidget;
|
||||
import codechicken.nei.SubsetWidget.SubsetTag;
|
||||
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
|
||||
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
|
||||
import codechicken.nei.config.Option;
|
||||
import codechicken.nei.config.OptionKeyBind;
|
||||
import codechicken.nei.recipe.CatalystInfo;
|
||||
import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.GuiUsageRecipe;
|
||||
import codechicken.nei.recipe.ICraftingHandler;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
@@ -38,6 +43,7 @@ import codechicken.nei.recipe.IUsageHandler;
|
||||
import codechicken.nei.recipe.RecipeCatalysts;
|
||||
import codechicken.nei.recipe.RecipeInfo;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.ItemStackFilterParser;
|
||||
|
||||
/**
|
||||
* This is the main class that handles item property configuration. WARNING: DO NOT access this class until the world
|
||||
@@ -147,19 +153,32 @@ public class API {
|
||||
}
|
||||
}
|
||||
|
||||
public static void hideItem(String rule) {
|
||||
ItemFilter filter = ItemStackFilterParser.parse(rule);
|
||||
if (filter != null) {
|
||||
ItemInfo.hiddenItemsRules.filters.add(filter);
|
||||
LayoutManager.markItemsDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or replace the name normally shown on the item tooltip
|
||||
*/
|
||||
public static void setOverrideName(ItemStack item, String name) {
|
||||
if (!name.equals(ItemInfo.nameOverrides.get(item))) {
|
||||
ItemInfo.nameOverrides.put(item, name);
|
||||
String existing = ItemInfo.nameOverrides.get(item);
|
||||
if (!Objects.equals(name, existing)) {
|
||||
if (name == null) {
|
||||
ItemInfo.nameOverrides.remove(item);
|
||||
} else {
|
||||
ItemInfo.nameOverrides.put(item, name);
|
||||
}
|
||||
LayoutManager.markItemsDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an item to the item panel. Any items added using this function will override the default search pattern.
|
||||
*
|
||||
*
|
||||
* @param item an item with data
|
||||
*/
|
||||
public static void addItemListEntry(ItemStack item) {
|
||||
@@ -182,7 +201,7 @@ public class API {
|
||||
|
||||
/**
|
||||
* Add a custom KeyBinding to be configured in the Controls menu.
|
||||
*
|
||||
*
|
||||
* @param ident An identifier for your key, eg "shoot"
|
||||
* @param defaultKey The default value, commonly obtained from {@link Keyboard}
|
||||
*/
|
||||
@@ -194,7 +213,7 @@ public class API {
|
||||
|
||||
/**
|
||||
* Add a custom KeyBinding to be configured in the Controls menu.
|
||||
*
|
||||
*
|
||||
* @param ident An identifier for your key, eg "shoot"
|
||||
* @param defaultKey The default value, commonly obtained from {@link Keyboard}
|
||||
*/
|
||||
@@ -209,7 +228,7 @@ public class API {
|
||||
|
||||
/**
|
||||
* Add a new Layout Style for the NEI interface
|
||||
*
|
||||
*
|
||||
* @param styleID The Unique ID to be used for storing your style in the config and cycling through avaliable styles
|
||||
* @param style The style to add.
|
||||
*/
|
||||
@@ -219,7 +238,7 @@ public class API {
|
||||
|
||||
/**
|
||||
* Registers a new Infinite Item Handler.
|
||||
*
|
||||
*
|
||||
* @param handler The handler to be registered.
|
||||
*/
|
||||
public static void addInfiniteItemHandler(IInfiniteItemHandler handler) {
|
||||
@@ -228,7 +247,7 @@ public class API {
|
||||
|
||||
/**
|
||||
* Registers a new Infinite Item Handler.
|
||||
*
|
||||
*
|
||||
* @param block The block to handle, null for all.
|
||||
* @param handler The handler to be registered.
|
||||
*/
|
||||
@@ -238,7 +257,7 @@ public class API {
|
||||
|
||||
/**
|
||||
* Tells NEI not to perform any Fast Transfer operations on slots of a particular class
|
||||
*
|
||||
*
|
||||
* @param slotClass The class of slot to be exempted
|
||||
*/
|
||||
public static void addFastTransferExemptSlot(Class<? extends Slot> slotClass) {
|
||||
@@ -247,7 +266,7 @@ public class API {
|
||||
|
||||
/**
|
||||
* Register a new text handler for the block highlight tooltip with a layout specification (HEADER, BODY or FOOTER).
|
||||
*
|
||||
*
|
||||
* @param handler The handler to be registered.
|
||||
* @param layout A HUDAugmenterRegistry.Layout entry. HEADER is displayed before BODY which is displayed before
|
||||
* FOOTER.
|
||||
@@ -258,16 +277,22 @@ public class API {
|
||||
|
||||
/**
|
||||
* Register a mode handler for overriding NEI recipe/utility/cheat mode settings.
|
||||
*
|
||||
*
|
||||
* @param handler The handler to be registered.
|
||||
*/
|
||||
public static void registerModeHandler(INEIModeHandler handler) {
|
||||
NEIInfo.modeHandlers.add(handler);
|
||||
}
|
||||
|
||||
public static void addRecipeFilter(IRecipeFilterProvider filterProvider) {
|
||||
synchronized (GuiRecipe.recipeFilterers) {
|
||||
GuiRecipe.recipeFilterers.add(filterProvider);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a filter provider for the item panel.
|
||||
*
|
||||
*
|
||||
* @param filterProvider The filter provider to be registered.
|
||||
*/
|
||||
public static void addItemFilter(ItemFilterProvider filterProvider) {
|
||||
@@ -278,7 +303,7 @@ public class API {
|
||||
|
||||
/**
|
||||
* Adds a new tag to the item subset dropdown.
|
||||
*
|
||||
*
|
||||
* @param name The fully qualified name, Eg Blocks.MobSpawners. NOT case sensitive
|
||||
* @param filter A filter for matching items that fit in this subset
|
||||
*/
|
||||
@@ -288,7 +313,7 @@ public class API {
|
||||
|
||||
/**
|
||||
* Adds a new tag to the item subset dropdown.
|
||||
*
|
||||
*
|
||||
* @param name The fully qualified name, Eg Blocks.MobSpawners. NOT case sensitive
|
||||
* @param items An iterable of itemstacks to be added as a subset
|
||||
*/
|
||||
@@ -305,16 +330,19 @@ public class API {
|
||||
SubsetWidget.addTag(tag);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void addSearchProvider(ISearchProvider provider) {}
|
||||
|
||||
/**
|
||||
* Adds a new search provider to the search field
|
||||
*/
|
||||
public static void addSearchProvider(ISearchProvider provider) {
|
||||
SearchField.searchProviders.add(provider);
|
||||
public static void addSearchProvider(ISearchParserProvider provider) {
|
||||
SearchField.searchParser.addProvider(provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new sorting option to the item panel sort menu
|
||||
*
|
||||
*
|
||||
* @param name A unique id for this sort option. Will be used in the config for saving and translated in the options
|
||||
* gui. Note that if the translation key name.tip exists, it will be used for a tooltip
|
||||
*/
|
||||
@@ -325,7 +353,7 @@ public class API {
|
||||
/**
|
||||
* Adds an additional item list entry for an item, sorted after the rest of the items are found through the normal
|
||||
* process
|
||||
*
|
||||
*
|
||||
* @param item The item to add the variant for
|
||||
* @param variant The stack to appear in the item panel
|
||||
*/
|
||||
@@ -344,7 +372,7 @@ public class API {
|
||||
* Adds an association between an ingredient and what it can craft. (i.e. Furnace ItemStack -> Smelting and Fuel
|
||||
* Recipes) Allows players to see what ingredient they need to craft in order to make recipes from a recipe
|
||||
* category.
|
||||
*
|
||||
*
|
||||
* @param stack the ingredient that can craft recipes (like a furnace or crafting table)
|
||||
* @param handler the recipe category handled by the ingredient
|
||||
* @param priority higher priority comes first, default to 0
|
||||
@@ -365,7 +393,7 @@ public class API {
|
||||
* Adds an association between an ingredient and what it can craft. (i.e. Furnace ItemStack -> Smelting and Fuel
|
||||
* Recipes) Allows players to see what ingredient they need to craft in order to make recipes from a recipe
|
||||
* category.
|
||||
*
|
||||
*
|
||||
* @param stack the ingredient that can craft recipes (like a furnace or crafting table)
|
||||
* @param handlerID recipe category identifier (see also {@link RecipeCatalysts#getRecipeID(IRecipeHandler)})
|
||||
* @param priority higher priority comes first, default to 0
|
||||
@@ -390,6 +418,11 @@ public class API {
|
||||
RecipeCatalysts.removeRecipeCatalyst(handlerID, stack);
|
||||
}
|
||||
|
||||
public static void registerBookmarkContainerHandler(Class<? extends GuiContainer> gui,
|
||||
IBookmarkContainerHandler handler) {
|
||||
BookmarkContainerInfo.registerBookmarkContainerHandler(gui, handler);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void addRecipeCatalyst(List<ItemStack> stacks, IRecipeHandler handler) {
|
||||
for (ItemStack stack : stacks) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package codechicken.nei.api;
|
||||
|
||||
import static codechicken.lib.gui.GuiDraw.drawRect;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -7,13 +9,14 @@ import net.minecraft.inventory.Slot;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
|
||||
public class DefaultOverlayRenderer implements IRecipeOverlayRenderer {
|
||||
|
||||
public DefaultOverlayRenderer(List<PositionedStack> ai, IStackPositioner positioner) {
|
||||
positioner = this.positioner = positioner;
|
||||
this.positioner = positioner;
|
||||
ingreds = new ArrayList<>();
|
||||
for (PositionedStack stack : ai) ingreds.add(stack.copy());
|
||||
ingreds = positioner.positionStacks(ingreds);
|
||||
@@ -21,20 +24,22 @@ public class DefaultOverlayRenderer implements IRecipeOverlayRenderer {
|
||||
|
||||
@Override
|
||||
public void renderOverlay(GuiContainerManager gui, Slot slot) {
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
GL11.glBlendFunc(770, 1);
|
||||
GL11.glColor4d(0.6, 0.6, 0.6, 0.7);
|
||||
|
||||
GuiContainerManager.setColouredItemRender(true);
|
||||
for (PositionedStack stack : ingreds) {
|
||||
if (stack.relx == slot.xDisplayPosition && stack.rely == slot.yDisplayPosition)
|
||||
if (stack.relx == slot.xDisplayPosition && stack.rely == slot.yDisplayPosition && !slot.getHasStack()) {
|
||||
GuiContainerManager.drawItem(stack.relx, stack.rely, stack.item);
|
||||
drawHover(stack.relx, stack.rely);
|
||||
}
|
||||
}
|
||||
GuiContainerManager.setColouredItemRender(false);
|
||||
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
GL11.glDisable(GL11.GL_BLEND);
|
||||
GL11.glEnable(GL11.GL_LIGHTING);
|
||||
GL11.glPopAttrib();
|
||||
}
|
||||
|
||||
private static void drawHover(int x, int y) {
|
||||
NEIClientUtils.gl2DRenderContext(() -> drawRect(x, y, 16, 16, 0x66555555));
|
||||
}
|
||||
|
||||
final IStackPositioner positioner;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package codechicken.nei.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public interface IBookmarkContainerHandler {
|
||||
|
||||
default List<ItemStack> getStorageStacks(GuiContainer guiContainer) {
|
||||
final List<Slot> slots = guiContainer.inventorySlots.inventorySlots;
|
||||
final List<ItemStack> stacks = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < slots.size() - 4 * 9; i++) {
|
||||
if (slots.get(i).getHasStack()) {
|
||||
stacks.add(slots.get(i).getStack());
|
||||
}
|
||||
}
|
||||
|
||||
return stacks;
|
||||
}
|
||||
|
||||
void pullBookmarkItemsFromContainer(GuiContainer guiContainer, ArrayList<ItemStack> realItems);
|
||||
}
|
||||
@@ -1,10 +1,60 @@
|
||||
package codechicken.nei.api;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.recipe.GuiOverlayButton.ItemOverlayState;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
|
||||
public interface IOverlayHandler {
|
||||
|
||||
void overlayRecipe(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, boolean shift);
|
||||
void overlayRecipe(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, boolean maxTransfer);
|
||||
|
||||
default int transferRecipe(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, int multiplier) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
default boolean canFillCraftingGrid(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex) {
|
||||
return true;
|
||||
}
|
||||
|
||||
default boolean craft(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, int multiplier) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean canCraft(GuiContainer firstGui, IRecipeHandler handler, int recipeIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default List<ItemOverlayState> presenceOverlay(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex) {
|
||||
final List<ItemOverlayState> itemPresenceSlots = new ArrayList<>();
|
||||
final List<PositionedStack> ingredients = recipe.getIngredientStacks(recipeIndex);
|
||||
final List<ItemStack> invStacks = firstGui.inventorySlots.inventorySlots.stream()
|
||||
.filter(
|
||||
s -> s != null && s.getStack() != null
|
||||
&& s.getStack().stackSize > 0
|
||||
&& s.isItemValid(s.getStack())
|
||||
&& s.canTakeStack(firstGui.mc.thePlayer))
|
||||
.map(s -> s.getStack().copy()).collect(Collectors.toList());
|
||||
|
||||
for (PositionedStack stack : ingredients) {
|
||||
Optional<ItemStack> used = invStacks.stream().filter(is -> is.stackSize > 0 && stack.contains(is))
|
||||
.findAny();
|
||||
|
||||
itemPresenceSlots.add(new ItemOverlayState(stack, used.isPresent()));
|
||||
|
||||
if (used.isPresent()) {
|
||||
ItemStack is = used.get();
|
||||
is.stackSize -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return itemPresenceSlots;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package codechicken.nei.api;
|
||||
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
|
||||
public interface IRecipeFilter {
|
||||
|
||||
public static interface IRecipeFilterProvider {
|
||||
|
||||
public IRecipeFilter getRecipeFilter();
|
||||
}
|
||||
|
||||
public boolean matches(IRecipeHandler handler, int recipeIndex);
|
||||
|
||||
}
|
||||
@@ -6,9 +6,18 @@ import net.minecraftforge.fluids.FluidStack;
|
||||
|
||||
public interface IStackStringifyHandler {
|
||||
|
||||
public NBTTagCompound convertItemStackToNBT(ItemStack stack, boolean saveStackSize);
|
||||
default NBTTagCompound convertItemStackToNBT(ItemStack stack, boolean saveStackSize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ItemStack convertNBTToItemStack(NBTTagCompound nbtTag);
|
||||
default ItemStack convertNBTToItemStack(NBTTagCompound nbtTag) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default FluidStack getFluid(ItemStack stack) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default void pauseItemDamageSound(boolean pause) {}
|
||||
|
||||
public FluidStack getFluid(ItemStack stack);
|
||||
}
|
||||
@@ -5,8 +5,8 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
@@ -44,12 +44,16 @@ import com.google.common.collect.ArrayListMultimap;
|
||||
import codechicken.core.featurehack.GameDataManipulator;
|
||||
import codechicken.nei.InfiniteStackSizeHandler;
|
||||
import codechicken.nei.InfiniteToolHandler;
|
||||
import codechicken.nei.ItemList;
|
||||
import codechicken.nei.ItemList.AnyMultiItemFilter;
|
||||
import codechicken.nei.ItemList.PatternItemFilter;
|
||||
import codechicken.nei.ItemMobSpawner;
|
||||
import codechicken.nei.ItemStackMap;
|
||||
import codechicken.nei.ItemStackSet;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.PopupInputHandler;
|
||||
import codechicken.nei.PresetsList;
|
||||
import codechicken.nei.SearchField.SearchParserProvider;
|
||||
import codechicken.nei.SearchTokenParser.SearchMode;
|
||||
import codechicken.nei.config.ArrayDumper;
|
||||
import codechicken.nei.config.HandlerDumper;
|
||||
import codechicken.nei.config.ItemPanelDumper;
|
||||
@@ -57,6 +61,10 @@ import codechicken.nei.config.RegistryDumper;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.recipe.BrewingRecipeHandler;
|
||||
import codechicken.nei.recipe.RecipeItemInputHandler;
|
||||
import codechicken.nei.search.IdentifierFilter;
|
||||
import codechicken.nei.search.ModNameFilter;
|
||||
import codechicken.nei.search.OreDictionaryFilter;
|
||||
import codechicken.nei.search.TooltipFilter;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
@@ -76,6 +84,7 @@ public class ItemInfo {
|
||||
public static final ArrayListMultimap<Layout, IHighlightHandler> highlightHandlers = ArrayListMultimap.create();
|
||||
public static final ItemStackMap<String> nameOverrides = new ItemStackMap<>();
|
||||
public static final ItemStackSet hiddenItems = new ItemStackSet();
|
||||
public static final AnyMultiItemFilter hiddenItemsRules = new AnyMultiItemFilter();
|
||||
public static final ItemStackSet finiteItems = new ItemStackSet();
|
||||
public static final ArrayListMultimap<Item, ItemStack> itemOverrides = ArrayListMultimap.create();
|
||||
public static final ArrayListMultimap<Item, ItemStack> itemVariants = ArrayListMultimap.create();
|
||||
@@ -86,40 +95,11 @@ public class ItemInfo {
|
||||
|
||||
public static final HashMap<Item, String> itemOwners = new HashMap<>();
|
||||
|
||||
private static class ItemStackKey {
|
||||
|
||||
public final ItemStack stack;
|
||||
|
||||
public ItemStackKey(ItemStack stack) {
|
||||
this.stack = stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (this.stack == null) return 1;
|
||||
int hashCode = 1;
|
||||
hashCode = 31 * hashCode + stack.stackSize;
|
||||
hashCode = 31 * hashCode + Item.getIdFromItem(stack.getItem());
|
||||
hashCode = 31 * hashCode + stack.getItemDamage();
|
||||
hashCode = 31 * hashCode + (!stack.hasTagCompound() ? 0 : stack.getTagCompound().hashCode());
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof ItemStackKey)) return false;
|
||||
return ItemStack.areItemStacksEqual(this.stack, ((ItemStackKey) o).stack);
|
||||
}
|
||||
}
|
||||
|
||||
// lookup optimisation
|
||||
public static final ConcurrentHashMap<ItemStackKey, String> itemSearchNames = new ConcurrentHashMap<>();
|
||||
|
||||
public static boolean isHidden(ItemStack stack) {
|
||||
return hiddenItems.contains(stack);
|
||||
return hiddenItems.contains(stack) || hiddenItemsRules.matches(stack);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static boolean isHidden(Item item) {
|
||||
return hiddenItems.containsAll(item);
|
||||
}
|
||||
@@ -144,37 +124,38 @@ public class ItemInfo {
|
||||
addMobSpawnerItem();
|
||||
}
|
||||
|
||||
public static void load(World world) {
|
||||
public static void load() {
|
||||
addVanillaBlockProperties();
|
||||
addDefaultDropDowns();
|
||||
searchItems();
|
||||
parseModItems();
|
||||
ItemMobSpawner.loadSpawners(world);
|
||||
ItemMobSpawner.loadSpawners();
|
||||
addSpawnEggs();
|
||||
addInfiniteHandlers();
|
||||
addInputHandlers();
|
||||
addIDDumps();
|
||||
addHiddenItemFilter();
|
||||
addSearchOptimisation();
|
||||
addSearchProviders();
|
||||
RecipeItemInputHandler.load();
|
||||
PresetsList.load();
|
||||
}
|
||||
|
||||
private static void addSearchOptimisation() {
|
||||
ItemList.loadCallbacks.add(ItemInfo::populateSearchMap);
|
||||
}
|
||||
private static void addSearchProviders() {
|
||||
API.addSearchProvider(
|
||||
new SearchParserProvider('\0', "default", EnumChatFormatting.RESET, PatternItemFilter::new) {
|
||||
|
||||
private static void populateSearchMap() {
|
||||
/* Create a snapshot of the current keys in the cache */
|
||||
HashSet<ItemStackKey> oldItems = new HashSet<>(itemSearchNames.keySet());
|
||||
for (ItemStack stack : ItemList.items) {
|
||||
/* Populate each entry and remove it from the snapshot */
|
||||
getSearchName(stack);
|
||||
oldItems.remove(new ItemStackKey(stack));
|
||||
}
|
||||
itemSearchNames.keySet().removeAll(oldItems);
|
||||
}
|
||||
@Override
|
||||
public SearchMode getSearchMode() {
|
||||
return SearchMode.ALWAYS;
|
||||
}
|
||||
|
||||
private static void addHiddenItemFilter() {
|
||||
API.addItemFilter(() -> item -> !hiddenItems.contains(item));
|
||||
});
|
||||
API.addSearchProvider(
|
||||
new SearchParserProvider('@', "modName", EnumChatFormatting.LIGHT_PURPLE, ModNameFilter::new));
|
||||
API.addSearchProvider(
|
||||
new SearchParserProvider('$', "oreDict", EnumChatFormatting.AQUA, OreDictionaryFilter::new));
|
||||
API.addSearchProvider(new SearchParserProvider('#', "tooltip", EnumChatFormatting.YELLOW, TooltipFilter::new));
|
||||
API.addSearchProvider(
|
||||
new SearchParserProvider('&', "identifier", EnumChatFormatting.GOLD, IdentifierFilter::new));
|
||||
}
|
||||
|
||||
private static void addIDDumps() {
|
||||
@@ -209,7 +190,7 @@ public class ItemInfo {
|
||||
public String[] dump(Block block, int id, String name) {
|
||||
final Item item = Item.getItemFromBlock(block);
|
||||
return new String[] { name, Integer.toString(id), Boolean.toString(item != null),
|
||||
ItemInfo.itemOwners.get(block), block.getClass().getCanonicalName(),
|
||||
ItemInfo.itemOwners.get(item), block.getClass().getCanonicalName(),
|
||||
item != null ? EnumChatFormatting.getTextWithoutFormattingCodes(
|
||||
GuiContainerManager.itemDisplayNameShort(new ItemStack(item))) : "null" };
|
||||
}
|
||||
@@ -288,7 +269,8 @@ public class ItemInfo {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void parseModItems() {
|
||||
HashMap<String, ItemStackSet> modSubsets = new HashMap<>();
|
||||
final Map<String, ItemStackSet> modSubsets = new HashMap<>();
|
||||
|
||||
for (Item item : (Iterable<Item>) Item.itemRegistry) {
|
||||
UniqueIdentifier ident = null;
|
||||
try {
|
||||
@@ -300,14 +282,12 @@ public class ItemInfo {
|
||||
continue;
|
||||
}
|
||||
|
||||
String modId = ident.modId;
|
||||
itemOwners.put(item, modId);
|
||||
ItemStackSet itemset = modSubsets.get(modId);
|
||||
if (itemset == null) modSubsets.put(modId, itemset = new ItemStackSet());
|
||||
itemset.with(item);
|
||||
itemOwners.put(item, ident.modId);
|
||||
modSubsets.computeIfAbsent(ident.modId, i -> new ItemStackSet()).with(item);
|
||||
}
|
||||
|
||||
API.addSubset("Mod.Minecraft", modSubsets.remove("minecraft"));
|
||||
|
||||
for (Entry<String, ItemStackSet> entry : modSubsets.entrySet()) {
|
||||
ModContainer mc = FMLCommonHandler.instance().findContainerFor(entry.getKey());
|
||||
if (mc == null) NEIClientConfig.logger.error("Missing container for " + entry.getKey());
|
||||
@@ -316,7 +296,6 @@ public class ItemInfo {
|
||||
}
|
||||
|
||||
private static void addInputHandlers() {
|
||||
GuiContainerManager.addInputHandler(new RecipeItemInputHandler());
|
||||
GuiContainerManager.addInputHandler(new PopupInputHandler());
|
||||
}
|
||||
|
||||
@@ -344,44 +323,29 @@ public class ItemInfo {
|
||||
}
|
||||
|
||||
private static void addDefaultDropDowns() {
|
||||
final Item mob_spawner = Item.getItemFromBlock(Blocks.mob_spawner);
|
||||
API.addSubset("Items", item -> Block.getBlockFromItem(item.getItem()) == Blocks.air);
|
||||
API.addSubset("Blocks", item -> Block.getBlockFromItem(item.getItem()) != Blocks.air);
|
||||
API.addSubset("Blocks.MobSpawners", ItemStackSet.of(Blocks.mob_spawner));
|
||||
API.addSubset("Blocks.MobSpawners", item -> item.getItem() == mob_spawner);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void searchItems() {
|
||||
ItemStackSet tools = new ItemStackSet();
|
||||
ItemStackSet picks = new ItemStackSet();
|
||||
ItemStackSet shovels = new ItemStackSet();
|
||||
ItemStackSet axes = new ItemStackSet();
|
||||
ItemStackSet hoes = new ItemStackSet();
|
||||
ItemStackSet swords = new ItemStackSet();
|
||||
ItemStackSet chest = new ItemStackSet();
|
||||
ItemStackSet helmets = new ItemStackSet();
|
||||
ItemStackSet legs = new ItemStackSet();
|
||||
ItemStackSet boots = new ItemStackSet();
|
||||
ItemStackSet other = new ItemStackSet();
|
||||
ItemStackSet ranged = new ItemStackSet();
|
||||
ItemStackSet food = new ItemStackSet();
|
||||
ItemStackSet potioningredients = new ItemStackSet();
|
||||
|
||||
ArrayList<ItemStackSet> creativeTabRanges = new ArrayList<>(CreativeTabs.creativeTabArray.length);
|
||||
List<ItemStack> stackList = new LinkedList<>();
|
||||
final Map<Integer, ItemStackSet> creativeTabRanges = new HashMap<>();
|
||||
final List<ItemStack> stackList = new LinkedList<>();
|
||||
|
||||
for (Item item : (Iterable<Item>) Item.itemRegistry) {
|
||||
if (item == null) continue;
|
||||
|
||||
for (CreativeTabs itemTab : item.getCreativeTabs()) {
|
||||
if (itemTab != null) {
|
||||
while (itemTab.getTabIndex() >= creativeTabRanges.size()) creativeTabRanges.add(null);
|
||||
ItemStackSet set = creativeTabRanges.get(itemTab.getTabIndex());
|
||||
if (set == null) creativeTabRanges.set(itemTab.getTabIndex(), set = new ItemStackSet());
|
||||
final ItemStackSet itemset = creativeTabRanges
|
||||
.computeIfAbsent(itemTab.getTabIndex(), i -> new ItemStackSet());
|
||||
|
||||
try {
|
||||
stackList.clear();
|
||||
item.getSubItems(item, itemTab, stackList);
|
||||
for (ItemStack stack : stackList) set.add(stack);
|
||||
itemset.addAll(stackList);
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger
|
||||
.error("Error loading sub-items for: " + item + ". Tab: " + itemTab.getTabLabel(), e);
|
||||
@@ -389,41 +353,13 @@ public class ItemInfo {
|
||||
}
|
||||
}
|
||||
|
||||
if (item.isDamageable()) {
|
||||
tools.with(item);
|
||||
if (item instanceof ItemPickaxe) picks.with(item);
|
||||
else if (item instanceof ItemSpade) shovels.with(item);
|
||||
else if (item instanceof ItemAxe) axes.with(item);
|
||||
else if (item instanceof ItemHoe) hoes.with(item);
|
||||
else if (item instanceof ItemSword) swords.with(item);
|
||||
else if (item instanceof ItemArmor) switch (((ItemArmor) item).armorType) {
|
||||
case 0:
|
||||
helmets.with(item);
|
||||
break;
|
||||
case 1:
|
||||
chest.with(item);
|
||||
break;
|
||||
case 2:
|
||||
legs.with(item);
|
||||
break;
|
||||
case 3:
|
||||
boots.with(item);
|
||||
break;
|
||||
}
|
||||
else if (item == Items.arrow || item == Items.bow) ranged.with(item);
|
||||
else if (item == Items.fishing_rod || item == Items.flint_and_steel || item == Items.shears)
|
||||
other.with(item);
|
||||
}
|
||||
|
||||
if (item instanceof ItemFood) food.with(item);
|
||||
|
||||
try {
|
||||
LinkedList<ItemStack> subItems = new LinkedList<>();
|
||||
final List<ItemStack> subItems = new LinkedList<>();
|
||||
item.getSubItems(item, null, subItems);
|
||||
|
||||
for (ItemStack stack : subItems) {
|
||||
if (item.isPotionIngredient(stack) && item.getPotionEffect(stack) != null) {
|
||||
BrewingRecipeHandler.ingredients.add(stack);
|
||||
potioningredients.add(stack);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,25 +367,33 @@ public class ItemInfo {
|
||||
NEIClientConfig.logger.error("Error loading brewing ingredients for: " + item, e);
|
||||
}
|
||||
}
|
||||
API.addSubset("Items.Tools.Pickaxes", picks);
|
||||
API.addSubset("Items.Tools.Shovels", shovels);
|
||||
API.addSubset("Items.Tools.Axes", axes);
|
||||
API.addSubset("Items.Tools.Hoes", hoes);
|
||||
API.addSubset("Items.Tools.Other", other);
|
||||
API.addSubset("Items.Weapons.Swords", swords);
|
||||
API.addSubset("Items.Weapons.Ranged", ranged);
|
||||
API.addSubset("Items.Armor.Chestplates", chest);
|
||||
API.addSubset("Items.Armor.Leggings", legs);
|
||||
API.addSubset("Items.Armor.Helmets", helmets);
|
||||
API.addSubset("Items.Armor.Boots", boots);
|
||||
API.addSubset("Items.Food", food);
|
||||
API.addSubset("Items.Potions.Ingredients", potioningredients);
|
||||
|
||||
API.addSubset("Items.Tools.Pickaxes", item -> item.getItem() instanceof ItemPickaxe);
|
||||
API.addSubset("Items.Tools.Shovels", item -> item.getItem() instanceof ItemSpade);
|
||||
API.addSubset("Items.Tools.Axes", item -> item.getItem() instanceof ItemAxe);
|
||||
API.addSubset("Items.Tools.Hoes", item -> item.getItem() instanceof ItemHoe);
|
||||
API.addSubset(
|
||||
"Items.Tools.Other",
|
||||
item -> item.getItem() == Items.fishing_rod || item.getItem() == Items.flint_and_steel
|
||||
|| item.getItem() == Items.shears);
|
||||
API.addSubset("Items.Weapons.Swords", item -> item.getItem() instanceof ItemSword);
|
||||
API.addSubset("Items.Weapons.Ranged", item -> item.getItem() == Items.arrow || item.getItem() == Items.bow);
|
||||
API.addSubset("Items.Armor.Helmets", item -> item.getItem() instanceof ItemArmor armor && armor.armorType == 0);
|
||||
API.addSubset(
|
||||
"Items.Armor.Chestplates",
|
||||
item -> item.getItem() instanceof ItemArmor armor && armor.armorType == 1);
|
||||
API.addSubset(
|
||||
"Items.Armor.Leggings",
|
||||
item -> item.getItem() instanceof ItemArmor armor && armor.armorType == 2);
|
||||
API.addSubset("Items.Armor.Boots", item -> item.getItem() instanceof ItemArmor armor && armor.armorType == 3);
|
||||
API.addSubset("Items.Food", item -> item.getItem() instanceof ItemFood);
|
||||
API.addSubset("Items.Potions.Ingredients", BrewingRecipeHandler.ingredients);
|
||||
|
||||
for (CreativeTabs tab : CreativeTabs.creativeTabArray) {
|
||||
if (tab.getTabIndex() >= creativeTabRanges.size()) continue;
|
||||
ItemStackSet set = creativeTabRanges.get(tab.getTabIndex());
|
||||
if (set != null && !set.isEmpty())
|
||||
API.addSubset("CreativeTabs." + I18n.format(tab.getTranslatedTabLabel()), set);
|
||||
final ItemStackSet itemset = creativeTabRanges.get(tab.getTabIndex());
|
||||
if (itemset != null && !itemset.isEmpty()) {
|
||||
API.addSubset("CreativeTabs." + I18n.format(tab.getTranslatedTabLabel()), itemset);
|
||||
}
|
||||
}
|
||||
|
||||
BrewingRecipeHandler.searchPotions();
|
||||
@@ -460,7 +404,6 @@ public class ItemInfo {
|
||||
addEntityEgg(EntityIronGolem.class, 0xC5C2C1, 0xffe1cc);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void addEntityEgg(Class<?> entity, int i, int j) {
|
||||
int id = (Integer) EntityList.classToIDMapping.get(entity);
|
||||
EntityList.entityEggs.put(id, new EntityEggInfo(id, i, j));
|
||||
@@ -516,10 +459,8 @@ public class ItemInfo {
|
||||
return retString;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String getSearchName(ItemStack stack) {
|
||||
return itemSearchNames.computeIfAbsent(
|
||||
new ItemStackKey(stack),
|
||||
key -> EnumChatFormatting.getTextWithoutFormattingCodes(
|
||||
GuiContainerManager.concatenatedDisplayName(key.stack, true).toLowerCase()));
|
||||
return GuiContainerManager.concatenatedDisplayName(stack, true).toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,44 @@
|
||||
package codechicken.nei.api;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.nei.BookmarkContainerInfo;
|
||||
import codechicken.nei.FavoriteRecipes;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.ItemQuantityField;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.LayoutManager;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.SearchField;
|
||||
import codechicken.nei.bookmark.BookmarkGrid;
|
||||
import codechicken.nei.bookmark.BookmarkGroup;
|
||||
import codechicken.nei.bookmark.BookmarkItem;
|
||||
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;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.RecipeHandlerRef;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.recipe.chain.RecipeChainMath;
|
||||
import codechicken.nei.util.NEIMouseUtils;
|
||||
|
||||
public abstract class ShortcutInputHandler {
|
||||
|
||||
@@ -24,22 +48,63 @@ public abstract class ShortcutInputHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.overlay_hide")) {
|
||||
return hideOverlayRecipe();
|
||||
if (NEIClientConfig.isKeyHashDown("gui.overlay") && stackover == null
|
||||
&& LayoutManager.overlayRenderer != null) {
|
||||
LayoutManager.overlayRenderer = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (stackover == null) {
|
||||
final int groupId = ItemPanels.bookmarkPanel.getHoveredGroupId(true);
|
||||
|
||||
if (groupId != -1) {
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.remove_recipe")) {
|
||||
ItemPanels.bookmarkPanel.removeGroup(groupId);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.bookmark_pull_items")) {
|
||||
return ItemPanels.bookmarkPanel.pullBookmarkItems(groupId, NEIClientUtils.shiftKey());
|
||||
}
|
||||
|
||||
if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft_items")
|
||||
&& NEIClientUtils.shiftKey()
|
||||
&& ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)) {
|
||||
final RecipeChainMath math = ItemPanels.bookmarkPanel.getGrid().createRecipeChainMath(groupId);
|
||||
|
||||
if (math != null) {
|
||||
|
||||
if (!NEIClientUtils.controlKey()) {
|
||||
autocraftingIgnoreInventory(math);
|
||||
}
|
||||
|
||||
AutoCraftingManager.runProcessing(math);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
stackover = stackover.copy();
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.overlay")) {
|
||||
return openOverlayRecipe(stackover, false);
|
||||
return openOverlayRecipe(stackover);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.overlay_use")) {
|
||||
return openOverlayRecipe(stackover, true);
|
||||
if (NEIClientConfig.isKeyHashDown("gui.copy_name")) {
|
||||
return copyItemStackName(stackover);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.copy_oredict")) {
|
||||
return copyItemStackOreDictionary(stackover);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.chat_link_item")) {
|
||||
return sendItemStackChatLink(stackover);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.recipe")) {
|
||||
@@ -50,20 +115,21 @@ 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, false, false);
|
||||
return saveRecipeInBookmark(stackover, NEIClientUtils.shiftKey(), NEIClientUtils.controlKey());
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.bookmark_recipe")) {
|
||||
return saveRecipeInBookmark(stackover, true, false);
|
||||
if (NEIClientConfig.isKeyHashDown("gui.bookmark_pull_items")) {
|
||||
return pullRecipeItems(stackover, NEIClientUtils.shiftKey());
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.bookmark_count")) {
|
||||
return saveRecipeInBookmark(stackover, false, true);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.bookmark_recipe_count")) {
|
||||
return saveRecipeInBookmark(stackover, true, true);
|
||||
if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft_items")
|
||||
&& NEIClientUtils.shiftKey()) {
|
||||
return runAutoCrafting(stackover, !NEIClientUtils.controlKey());
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -77,7 +143,6 @@ public abstract class ShortcutInputHandler {
|
||||
|
||||
if (stackover != null) {
|
||||
final int button = Mouse.getEventButton();
|
||||
stackover = stackover.copy();
|
||||
|
||||
if (button == 0) {
|
||||
return GuiCraftingRecipe.openRecipeGui("item", stackover);
|
||||
@@ -89,43 +154,477 @@ public abstract class ShortcutInputHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean hideOverlayRecipe() {
|
||||
|
||||
if (LayoutManager.overlayRenderer != null) {
|
||||
LayoutManager.overlayRenderer = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
private static boolean copyItemStackName(ItemStack stackover) {
|
||||
GuiScreen.setClipboardString(SearchField.getEscapedSearchText(stackover));
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean openOverlayRecipe(ItemStack stack, boolean shift) {
|
||||
final GuiContainer gui = NEIClientUtils.getGuiContainer();
|
||||
private static boolean sendItemStackChatLink(ItemStack stackover) {
|
||||
if (stackover == null) return false;
|
||||
|
||||
if (gui == null || gui instanceof GuiRecipe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return GuiCraftingRecipe.openRecipeGui("item", true, shift, stack);
|
||||
NEIClientUtils.sendChatItemLink(stackover); // I wish clients could just send formatted messages
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean saveRecipeInBookmark(ItemStack stack, boolean saveIngredients, boolean saveStackSize) {
|
||||
private static boolean copyItemStackOreDictionary(ItemStack stackover) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (stack != null) {
|
||||
final GuiContainer gui = NEIClientUtils.getGuiContainer();
|
||||
List<PositionedStack> ingredients = null;
|
||||
String handlerName = "";
|
||||
for (int id : OreDictionary.getOreIDs(stackover)) {
|
||||
String oreDictionaryName = OreDictionary.getOreName(id);
|
||||
if (!"Unknown".equals(oreDictionaryName)) {
|
||||
builder.append(oreDictionaryName).append(",");
|
||||
}
|
||||
}
|
||||
|
||||
if (builder.length() > 0) {
|
||||
builder.deleteCharAt(builder.length() - 1);
|
||||
}
|
||||
|
||||
GuiScreen.setClipboardString(builder.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean runAutoCrafting(ItemStack stackover, boolean ignoreInventory) {
|
||||
final RecipeId recipeId = GuiCraftingRecipe.getRecipeId(NEIClientUtils.getGuiContainer(), stackover);
|
||||
|
||||
if (recipeId != null) {
|
||||
final Point mouseover = GuiDraw.getMousePosition();
|
||||
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
RecipeChainMath math = null;
|
||||
|
||||
if (slot == null) {
|
||||
final Recipe recipe = Recipe.of(recipeId);
|
||||
if (recipe != null) {
|
||||
math = RecipeChainMath.of(recipe, 1);
|
||||
}
|
||||
} else if (slot.getRecipeId() != null && !slot.isIngredient()) {
|
||||
|
||||
if (slot.getGroup().crafting == null) {
|
||||
final Recipe recipe = Recipe.of(slot.getRecipeId());
|
||||
if (recipe != null) {
|
||||
math = RecipeChainMath.of(recipe, slot != null ? slot.getMultiplier() : 1);
|
||||
}
|
||||
} else {
|
||||
math = ItemPanels.bookmarkPanel.getGrid()
|
||||
.createRecipeChainMath(slot.getGroupId(), slot.getRecipeId());
|
||||
}
|
||||
|
||||
if (gui instanceof GuiRecipe) {
|
||||
ingredients = ((GuiRecipe<?>) gui).getFocusedRecipeIngredients();
|
||||
handlerName = ((GuiRecipe<?>) gui).getHandlerName();
|
||||
stack.stackSize = ((GuiRecipe<?>) gui).prepareFocusedRecipeResultStackSize(stack);
|
||||
}
|
||||
|
||||
ItemPanels.bookmarkPanel.addOrRemoveItem(stack, handlerName, ingredients, saveIngredients, saveStackSize);
|
||||
if (math != null) {
|
||||
|
||||
if (ignoreInventory) {
|
||||
autocraftingIgnoreInventory(math);
|
||||
}
|
||||
|
||||
AutoCraftingManager.runProcessing(math);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean openOverlayRecipe(ItemStack stackover) {
|
||||
final GuiContainer gui = NEIClientUtils.getGuiContainer();
|
||||
final RecipeId recipeId = GuiCraftingRecipe.getRecipeId(gui, stackover);
|
||||
|
||||
if (recipeId != null) {
|
||||
final RecipeHandlerRef handlerRef = RecipeHandlerRef.of(recipeId);
|
||||
|
||||
if (handlerRef != null) {
|
||||
|
||||
if (NEIClientUtils.shiftKey() && handlerRef.canFillCraftingGrid(gui)) {
|
||||
int multiplier = 0;
|
||||
|
||||
if (NEIClientUtils.controlKey()) {
|
||||
final Point mouseover = GuiDraw.getMousePosition();
|
||||
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel
|
||||
.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
multiplier = slot != null ? (int) Math.min(64, slot.getMultiplier()) : 1;
|
||||
}
|
||||
|
||||
handlerRef.fillCraftingGrid(gui, multiplier);
|
||||
} else if (!NEIClientUtils.shiftKey() && handlerRef.canUseOverlayRenderer(gui)) {
|
||||
handlerRef.useOverlayRenderer(gui);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean 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 (!ItemPanels.bookmarkPanel.removeSlot(mousePos.x, mousePos.y, saveIngredients)) {
|
||||
final Recipe recipe = getFocusedRecipe(stackover, mousePos.x, mousePos.y, saveIngredients);
|
||||
|
||||
if (recipe != null && saveIngredients) {
|
||||
|
||||
if (!ItemPanels.bookmarkPanel.removeRecipe(recipe.getRecipeId(), BookmarkGrid.DEFAULT_GROUP_ID)) {
|
||||
final Recipe singleRecipe = Recipe.of(
|
||||
Arrays.asList(recipe.getResult(stackover)),
|
||||
recipe.getHandlerName(),
|
||||
recipe.getIngredients());
|
||||
singleRecipe.setCustomRecipeId(recipe.getRecipeId());
|
||||
|
||||
ItemPanels.bookmarkPanel
|
||||
.addRecipe(singleRecipe, saveStackSize ? 1 : 0, BookmarkGrid.DEFAULT_GROUP_ID);
|
||||
}
|
||||
|
||||
} else {
|
||||
final RecipeId recipeId = recipe != null ? recipe.getRecipeId() : null;
|
||||
final boolean existsRecipe = recipeId != null
|
||||
&& ItemPanels.bookmarkPanel.existsRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID)
|
||||
|| NEIClientConfig.getBooleanSetting("inventory.bookmarks.bookmarkItemsWithRecipe");
|
||||
|
||||
if (!ItemPanels.bookmarkPanel
|
||||
.removeItem(stackover, existsRecipe ? recipeId : null, BookmarkGrid.DEFAULT_GROUP_ID)) {
|
||||
saveStackSize = saveStackSize || saveIngredients
|
||||
|| ItemPanels.bookmarkPanel.existsRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID);
|
||||
|
||||
if (!saveStackSize) {
|
||||
stackover = StackInfo.withAmount(stackover, 0);
|
||||
} else if (ItemPanels.itemPanel.contains(mousePos.x, mousePos.y)
|
||||
|| ItemPanels.itemPanel.historyPanel.contains(mousePos.x, mousePos.y)) {
|
||||
stackover = ItemQuantityField.prepareStackWithQuantity(stackover, 0);
|
||||
}
|
||||
|
||||
ItemPanels.bookmarkPanel
|
||||
.addItem(stackover, existsRecipe ? recipeId : null, BookmarkGrid.DEFAULT_GROUP_ID);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Recipe getFocusedRecipe(ItemStack stackover, int mousex, int mousey, boolean useFavorites) {
|
||||
final GuiContainer gui = NEIClientUtils.getGuiContainer();
|
||||
Recipe recipe = null;
|
||||
|
||||
if (useFavorites) {
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
|
||||
return recipe;
|
||||
}
|
||||
|
||||
private static boolean pullRecipeItems(ItemStack stackover, boolean shift) {
|
||||
final Point mousePos = GuiDraw.getMousePosition();
|
||||
|
||||
if (ItemPanels.bookmarkPanel.contains(mousePos.x, mousePos.y)) {
|
||||
stackover = ItemPanels.bookmarkPanel.getStackMouseOverWithQuantity(mousePos.x, mousePos.y);
|
||||
} else if (ItemPanels.itemPanel.contains(mousePos.x, mousePos.y)) {
|
||||
stackover = ItemPanels.itemPanel.getStackMouseOverWithQuantity(mousePos.x, mousePos.y);
|
||||
} else if (ItemPanels.itemPanel.historyPanel.contains(mousePos.x, mousePos.y)) {
|
||||
stackover = ItemPanels.itemPanel.historyPanel.getStackMouseOverWithQuantity(mousePos.x, mousePos.y);
|
||||
} else {
|
||||
stackover = ItemQuantityField.prepareStackWithQuantity(stackover, 0);
|
||||
}
|
||||
|
||||
final RecipeChainMath math = RecipeChainMath
|
||||
.of(Arrays.asList(BookmarkItem.of(-3, stackover)), Collections.emptySet());
|
||||
return ItemPanels.bookmarkPanel.pullBookmarkItems(math, shift);
|
||||
}
|
||||
|
||||
public static Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, ItemStack stack) {
|
||||
final int groupId = ItemPanels.bookmarkPanel.getHoveredGroupId(true);
|
||||
final Map<String, String> hotkeys = new HashMap<>();
|
||||
|
||||
if (groupId != -1) {
|
||||
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName("gui.remove_recipe"),
|
||||
NEIClientUtils.translate("bookmark.group.remove_recipe"));
|
||||
|
||||
if (BookmarkContainerInfo.getBookmarkContainerHandler(gui) != null) {
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName("gui.bookmark_pull_items"),
|
||||
NEIClientUtils.translate("bookmark.group.pull_items"));
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName("gui.bookmark_pull_items", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("bookmark.group.pull_items_shift"));
|
||||
}
|
||||
|
||||
if (NEIClientConfig.autocraftingEnabled() && ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)) {
|
||||
hotkeys.put(
|
||||
NEIClientConfig
|
||||
.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
|
||||
NEIClientUtils.translate("bookmark.group.craft_missing"));
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("bookmark.group.craft_all"));
|
||||
}
|
||||
}
|
||||
|
||||
if (stack == null) {
|
||||
return hotkeys;
|
||||
}
|
||||
|
||||
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mousex, mousey);
|
||||
final RecipeId recipeId = getHotkeyRecipeId(gui, mousex, mousey, stack, slot);
|
||||
|
||||
if (slot != null) {
|
||||
final BookmarkGroup group = slot.getGroup();
|
||||
|
||||
if (group.crafting != null && group.collapsed) {
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("bookmark.group.remove_recipe"));
|
||||
} else if (slot.getRecipeId() == null) {
|
||||
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.isIngredient()) {
|
||||
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.isIngredient && !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(
|
||||
NEIClientConfig.getKeyName("gui.bookmark_pull_items"),
|
||||
NEIClientUtils.translate("bookmark.group.pull_items"));
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName("gui.bookmark_pull_items", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("bookmark.group.pull_items_shift"));
|
||||
}
|
||||
|
||||
} else {
|
||||
hotkeys.put(NEIClientConfig.getKeyName("gui.bookmark"), NEIClientUtils.translate("bookmark.add_item"));
|
||||
|
||||
if (StackInfo.getAmount(stack) > 0) {
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.CTRL_HASH),
|
||||
NEIClientUtils.translate("bookmark.add_item_with_count"));
|
||||
}
|
||||
|
||||
if (recipeId != null) {
|
||||
hotkeys.put(
|
||||
NEIClientConfig
|
||||
.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH + NEIClientUtils.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"));
|
||||
hotkeys.put(NEIClientConfig.getKeyName("gui.usage"), NEIClientUtils.translate("itempanel.open_usage"));
|
||||
|
||||
hotkeys.put(NEIClientConfig.getKeyName("gui.copy_name"), NEIClientUtils.translate("itempanel.copy_name"));
|
||||
hotkeys.put(NEIClientConfig.getKeyName("gui.copy_oredict"), NEIClientUtils.translate("itempanel.copy_oredict"));
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName("gui.chat_link_item"),
|
||||
NEIClientUtils.translate("itempanel.chat_link_item"));
|
||||
|
||||
if (!(gui instanceof GuiRecipe) && NEIClientConfig.canCheatItem(stack)) {
|
||||
hotkeys.put(
|
||||
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("itempanel.open_crafting"));
|
||||
hotkeys.put(
|
||||
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_RMB),
|
||||
NEIClientUtils.translate("itempanel.open_usage"));
|
||||
} else {
|
||||
hotkeys.put(
|
||||
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("itempanel.open_crafting"));
|
||||
hotkeys.put(
|
||||
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_RMB),
|
||||
NEIClientUtils.translate("itempanel.open_usage"));
|
||||
}
|
||||
|
||||
if (recipeId != null) {
|
||||
final RecipeHandlerRef handlerRef = RecipeHandlerRef.of(recipeId);
|
||||
|
||||
if (handlerRef != null) {
|
||||
|
||||
if (handlerRef.canUseOverlayRenderer(gui)) {
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName("gui.overlay"),
|
||||
NEIClientUtils.translate("itempanel.overlay_recipe"));
|
||||
}
|
||||
|
||||
if (handlerRef.canFillCraftingGrid(gui)) {
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName("gui.overlay", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("itempanel.fill_crafting_grid"));
|
||||
|
||||
if (handlerRef.allowedTransferAlghoritm(gui)) {
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName(
|
||||
"gui.overlay",
|
||||
NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
|
||||
NEIClientUtils.translate("itempanel.fill_crafting_grid_quantity"));
|
||||
}
|
||||
}
|
||||
|
||||
if (NEIClientConfig.autocraftingEnabled()) {
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName(
|
||||
"gui.craft_items",
|
||||
NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
|
||||
NEIClientUtils.translate("itempanel.craft_missing"));
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("itempanel.craft_all"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return hotkeys;
|
||||
}
|
||||
|
||||
private static void autocraftingIgnoreInventory(RecipeChainMath math) {
|
||||
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
|
||||
final List<ItemStack> playerInventory = AutoCraftingManager.getInventoryItems(guiContainer).values();
|
||||
final RecipeId rootRecipeId = math.createMasterRoot();
|
||||
|
||||
for (BookmarkItem item : math.recipeIngredients) {
|
||||
if (item.amount > 0 && rootRecipeId.equals(item.recipeId)) {
|
||||
long amount = 0;
|
||||
|
||||
for (ItemStack stack : playerInventory) {
|
||||
if (NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack, item.itemStack)) {
|
||||
amount += StackInfo.getAmount(stack);
|
||||
}
|
||||
}
|
||||
|
||||
if (amount >= item.amount) {
|
||||
item.factor = item.amount = amount + item.amount - (amount % item.amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static RecipeId getHotkeyRecipeId(GuiContainer gui, int mousex, int mousey, ItemStack stack,
|
||||
BookmarksGridSlot slot) {
|
||||
|
||||
if (slot != null) {
|
||||
return slot.isIngredient() ? null : slot.getRecipeId();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,14 @@ import static codechicken.lib.asm.InsnComparator.getControlFlowLabels;
|
||||
import static codechicken.lib.asm.InsnComparator.matches;
|
||||
import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
|
||||
import static org.objectweb.asm.ClassWriter.COMPUTE_MAXS;
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||
import static org.objectweb.asm.Opcodes.ACC_STATIC;
|
||||
import static org.objectweb.asm.Opcodes.ALOAD;
|
||||
import static org.objectweb.asm.Opcodes.ASM5;
|
||||
import static org.objectweb.asm.Opcodes.ILOAD;
|
||||
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
|
||||
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
|
||||
import static org.objectweb.asm.Opcodes.IRETURN;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -59,16 +66,6 @@ public class NEITransformer implements IClassTransformer {
|
||||
"func_149689_a",
|
||||
"(Lnet/minecraft/world/World;IIILnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;)V"),
|
||||
asmblocks.get("spawnerPlaced")));
|
||||
|
||||
// Make MobSpawnerBaseLogic use getSpawnerWorld when creating new entities
|
||||
transformer.add(
|
||||
new MethodReplacer(
|
||||
new ObfMapping(
|
||||
"net/minecraft/tileentity/MobSpawnerBaseLogic",
|
||||
"func_98281_h",
|
||||
"()Lnet/minecraft/entity/Entity;"),
|
||||
asmblocks.get("d_spawnerWorld"),
|
||||
asmblocks.get("spawnerWorld")));
|
||||
}
|
||||
|
||||
// Removes trailing seperators from NBTTagList/Compound.toString because OCD
|
||||
@@ -416,7 +413,7 @@ public class NEITransformer implements IClassTransformer {
|
||||
if (name.equals("net.minecraftforge.oredict.OreDictionary")) {
|
||||
ClassReader cr = new ClassReader(bytes);
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
cr.accept(new OreDictionaryVisitor(ASM5, cw), ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||
cr.accept(new OreDictionaryVisitor(ASM5, cw), 0);
|
||||
bytes = cw.toByteArray();
|
||||
}
|
||||
bytes = transformSubclasses(name, bytes);
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
package codechicken.nei.asm;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
import static org.objectweb.asm.Opcodes.ACC_FINAL;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
|
||||
import static org.objectweb.asm.Opcodes.ACC_STATIC;
|
||||
import static org.objectweb.asm.Opcodes.ALOAD;
|
||||
import static org.objectweb.asm.Opcodes.ASTORE;
|
||||
import static org.objectweb.asm.Opcodes.ATHROW;
|
||||
import static org.objectweb.asm.Opcodes.CHECKCAST;
|
||||
import static org.objectweb.asm.Opcodes.DUP;
|
||||
import static org.objectweb.asm.Opcodes.GETSTATIC;
|
||||
import static org.objectweb.asm.Opcodes.GOTO;
|
||||
import static org.objectweb.asm.Opcodes.IFNONNULL;
|
||||
import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
|
||||
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
|
||||
import static org.objectweb.asm.Opcodes.MONITORENTER;
|
||||
import static org.objectweb.asm.Opcodes.MONITOREXIT;
|
||||
import static org.objectweb.asm.Opcodes.NEW;
|
||||
import static org.objectweb.asm.Opcodes.PUTSTATIC;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,384 @@
|
||||
package codechicken.nei.bookmark;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
|
||||
import codechicken.nei.ItemSorter;
|
||||
import codechicken.nei.bookmark.RecipeChainDetails.BookmarkChainItem;
|
||||
import codechicken.nei.bookmark.RecipeChainDetails.CalculatedType;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
|
||||
public class BookmarkGridGenerator {
|
||||
|
||||
protected final BookmarkGrid grid;
|
||||
public List<BookmarksGridSlot> gridMask = null;
|
||||
|
||||
public final Map<Integer, Integer> rowToGroupId = new HashMap<>();
|
||||
public final Map<Integer, RecipeId> itemToRecipe = new HashMap<>();
|
||||
|
||||
public final Map<Integer, Integer> slotToItem = new LinkedHashMap<>();
|
||||
public final Map<Integer, Integer> itemToSlot = new LinkedHashMap<>();
|
||||
|
||||
public final Map<Integer, BookmarkChainItem> caclulatedItems = new HashMap<>();
|
||||
|
||||
public int pageCount = 0;
|
||||
public int maxAbsoluteSlotIndex = 0;
|
||||
|
||||
public BookmarkGridGenerator(BookmarkGrid grid) {
|
||||
this.grid = grid;
|
||||
}
|
||||
|
||||
public int getRowGroupId(int rowIndex) {
|
||||
final int absoluteRowIndex = rowIndex + (this.grid.getPage() - 1) * this.grid.getRows();
|
||||
return rowToGroupId.getOrDefault(absoluteRowIndex, BookmarkGrid.DEFAULT_GROUP_ID);
|
||||
}
|
||||
|
||||
public void generate() {
|
||||
BookmarkItem prevBookmarkItem = null;
|
||||
Map<Integer, String> borderGrid = new HashMap<>();
|
||||
int gridColumns = this.grid.getColumns();
|
||||
int size = this.grid.size();
|
||||
int absoluteSlotIndex = -2;
|
||||
int itemIndex = 0;
|
||||
|
||||
this.pageCount = 0;
|
||||
this.maxAbsoluteSlotIndex = 0;
|
||||
this.gridMask = new ArrayList<>();
|
||||
this.itemToRecipe.clear();
|
||||
this.caclulatedItems.clear();
|
||||
this.slotToItem.clear();
|
||||
this.itemToSlot.clear();
|
||||
this.rowToGroupId.clear();
|
||||
|
||||
if (this.grid.isEmpty() || this.grid.getPerPage() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (itemIndex < size && absoluteSlotIndex != -1) {
|
||||
final BookmarkItem bookmarkItem = this.grid.getBookmarkItem(itemIndex);
|
||||
final BookmarkGroup group = this.grid.getGroup(bookmarkItem.groupId);
|
||||
|
||||
if (group.crafting != null && (!group.crafting.calculatedItems.containsKey(itemIndex)
|
||||
|| bookmarkItem.recipeId != null && !bookmarkItem.recipeId
|
||||
.equals(group.crafting.itemToRecipe.getOrDefault(itemIndex, bookmarkItem.recipeId)))) {
|
||||
itemIndex++;
|
||||
} else if (group.collapsed) {
|
||||
final List<Integer> results = getGroupResults(bookmarkItem.groupId, itemIndex, size);
|
||||
final String groupKey = "group:" + bookmarkItem.groupId;
|
||||
|
||||
for (int index = 0; index < results.size(); index++) {
|
||||
final int collapsedItemIndex = results.get(index);
|
||||
final BookmarkItem item = this.grid.getBookmarkItem(collapsedItemIndex);
|
||||
final int nextSlotIndex = nextSlotIndex(
|
||||
absoluteSlotIndex + 1,
|
||||
prevBookmarkItem,
|
||||
item,
|
||||
BookmarkViewMode.DEFAULT);
|
||||
|
||||
if (nextSlotIndex == -1 || index > 0 && (nextSlotIndex % gridColumns) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
prevBookmarkItem = item;
|
||||
absoluteSlotIndex = nextSlotIndex;
|
||||
this.slotToItem.put(absoluteSlotIndex, collapsedItemIndex);
|
||||
this.itemToSlot.put(collapsedItemIndex, absoluteSlotIndex);
|
||||
this.caclulatedItems.put(collapsedItemIndex, getItem(group, collapsedItemIndex));
|
||||
borderGrid.put(absoluteSlotIndex, groupKey);
|
||||
}
|
||||
|
||||
while (itemIndex < size && this.grid.getBookmarkItem(itemIndex).groupId == bookmarkItem.groupId) {
|
||||
itemIndex++;
|
||||
}
|
||||
|
||||
} else if (group.crafting != null && group.viewMode == BookmarkViewMode.DEFAULT) {
|
||||
final List<Integer> results = getGroupResults(bookmarkItem.groupId, itemIndex, size);
|
||||
List<Integer> shadows;
|
||||
|
||||
for (int index = 0; index < results.size() && absoluteSlotIndex != -1; index++) {
|
||||
final int collapsedItemIndex = results.get(index);
|
||||
final BookmarkItem item = this.grid.getBookmarkItem(collapsedItemIndex);
|
||||
|
||||
if ((absoluteSlotIndex = nextSlotIndex(
|
||||
absoluteSlotIndex + 1,
|
||||
prevBookmarkItem,
|
||||
item,
|
||||
BookmarkViewMode.DEFAULT)) != -1) {
|
||||
prevBookmarkItem = item;
|
||||
this.slotToItem.put(absoluteSlotIndex, collapsedItemIndex);
|
||||
this.itemToSlot.put(collapsedItemIndex, absoluteSlotIndex);
|
||||
this.caclulatedItems.put(collapsedItemIndex, getItem(group, collapsedItemIndex));
|
||||
|
||||
if (!(shadows = getShadows(group, item.recipeId)).isEmpty()) {
|
||||
borderGrid.put(absoluteSlotIndex, "recipe:" + shadows.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (itemIndex < size && this.grid.getBookmarkItem(itemIndex).groupId == bookmarkItem.groupId) {
|
||||
itemIndex++;
|
||||
}
|
||||
|
||||
} else if (group.crafting != null && group.crafting.itemToRecipe.values().contains(bookmarkItem.recipeId)) {
|
||||
absoluteSlotIndex = generateCollapsedRecipe(prevBookmarkItem, itemIndex, absoluteSlotIndex, borderGrid);
|
||||
prevBookmarkItem = bookmarkItem;
|
||||
|
||||
while (itemIndex < size && bookmarkItem.equalsRecipe(this.grid.getBookmarkItem(itemIndex))) {
|
||||
itemIndex++;
|
||||
}
|
||||
|
||||
} else if ((absoluteSlotIndex = nextSlotIndex(
|
||||
absoluteSlotIndex + 1,
|
||||
prevBookmarkItem,
|
||||
bookmarkItem,
|
||||
group.viewMode)) != -1) {
|
||||
prevBookmarkItem = bookmarkItem;
|
||||
this.slotToItem.put(absoluteSlotIndex, itemIndex);
|
||||
this.itemToSlot.put(itemIndex, absoluteSlotIndex);
|
||||
this.caclulatedItems.put(itemIndex, getItem(group, itemIndex));
|
||||
itemIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
this.maxAbsoluteSlotIndex = this.slotToItem.keySet().stream().mapToInt(index -> index).max().orElse(-1) + 1;
|
||||
generateGroups();
|
||||
splitGridMask();
|
||||
calculateGroupBorders(borderGrid);
|
||||
}
|
||||
|
||||
private List<Integer> getGroupResults(int groupId, int itemIndex, int size) {
|
||||
final BookmarkGroup group = this.grid.getGroup(groupId);
|
||||
final List<Integer> results = new ArrayList<>();
|
||||
|
||||
while (itemIndex < size) {
|
||||
final BookmarkItem bookmarkItem = this.grid.getBookmarkItem(itemIndex);
|
||||
|
||||
if (bookmarkItem == null || bookmarkItem.groupId != groupId) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!bookmarkItem.isIngredient
|
||||
&& (group.crafting == null || group.crafting.calculatedItems.containsKey(itemIndex))) {
|
||||
results.add(itemIndex);
|
||||
}
|
||||
|
||||
itemIndex++;
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private int generateCollapsedRecipe(BookmarkItem prevBookmarkItem, int itemIndex, int absoluteSlotIndex,
|
||||
Map<Integer, String> borderGrid) {
|
||||
final BookmarkItem bookmarkItem = this.grid.getBookmarkItem(itemIndex);
|
||||
final BookmarkGroup group = this.grid.getGroup(bookmarkItem.groupId);
|
||||
final List<Integer> shadows = getShadows(group, bookmarkItem.recipeId);
|
||||
final String borderId = "recipe:" + shadows.get(0);
|
||||
|
||||
shadows.sort(generateSortingComparator(group.crafting.calculatedItems));
|
||||
|
||||
for (int shadowIndex : shadows) {
|
||||
final boolean isIngredient = shadows.get(0) != shadowIndex
|
||||
|| group.crafting.calculatedItems.get(shadowIndex).calculatedType == CalculatedType.INGREDIENT;
|
||||
final BookmarkItem shadowBookmarkItem = BookmarkItem.of(
|
||||
bookmarkItem.groupId,
|
||||
bookmarkItem.itemStack,
|
||||
1,
|
||||
bookmarkItem.recipeId,
|
||||
isIngredient,
|
||||
Collections.emptyMap());
|
||||
|
||||
if ((absoluteSlotIndex = nextSlotIndex(
|
||||
absoluteSlotIndex + 1,
|
||||
prevBookmarkItem,
|
||||
shadowBookmarkItem,
|
||||
group.viewMode)) != -1) {
|
||||
this.slotToItem.put(absoluteSlotIndex, shadowIndex);
|
||||
this.itemToSlot.put(shadowIndex, absoluteSlotIndex);
|
||||
this.caclulatedItems.put(shadowIndex, getItem(group, shadowIndex));
|
||||
this.itemToRecipe.put(shadowIndex, bookmarkItem.recipeId);
|
||||
borderGrid.put(absoluteSlotIndex, borderId);
|
||||
prevBookmarkItem = shadowBookmarkItem;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return absoluteSlotIndex;
|
||||
}
|
||||
|
||||
private List<Integer> getShadows(BookmarkGroup group, RecipeId recipeId) {
|
||||
return group.crafting.itemToRecipe.entrySet().stream().filter(entry -> recipeId.equals(entry.getValue()))
|
||||
.map(entry -> entry.getKey()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private int nextSlotIndex(int index, BookmarkItem previousMeta, BookmarkItem meta, BookmarkViewMode viewMode) {
|
||||
int gridColumns = this.grid.getColumns();
|
||||
int maxIndex = this.grid.getRows() * gridColumns;
|
||||
int j = 0;
|
||||
|
||||
index = Math.max(0, index);
|
||||
|
||||
while (j++ < maxIndex) {
|
||||
boolean isFirstColumn = (index % gridColumns) == 0;
|
||||
|
||||
if (this.grid.isInvalidSlot(index % maxIndex)) {
|
||||
index++;
|
||||
} else if (!isFirstColumn && (previousMeta == null || previousMeta.groupId != meta.groupId)) {
|
||||
// new group must start on a new line
|
||||
index++;
|
||||
} else if (viewMode == BookmarkViewMode.DEFAULT) {
|
||||
return index;
|
||||
} else if (isFirstColumn && (meta.recipeId == null || previousMeta == null
|
||||
|| previousMeta.groupId != meta.groupId
|
||||
|| !meta.recipeId.equals(previousMeta.recipeId)
|
||||
|| index + 1 < maxIndex && this.grid.isInvalidSlot((index + 1) % maxIndex))) {
|
||||
// In first column must be an item without recipe, a recipe result, or an ingredient
|
||||
// if the second column is occupied
|
||||
return index;
|
||||
} else
|
||||
if (!isFirstColumn && meta.recipeId != null && meta.recipeId.equals(previousMeta.recipeId)) {
|
||||
return index;
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void generateGroups() {
|
||||
int gridColumns = this.grid.getColumns();
|
||||
int previousGroupId = BookmarkGrid.DEFAULT_GROUP_ID;
|
||||
|
||||
for (int absoluteSlotIndex = 0; absoluteSlotIndex < this.maxAbsoluteSlotIndex; absoluteSlotIndex++) {
|
||||
int absoluteRowIndex = absoluteSlotIndex / gridColumns;
|
||||
if (this.rowToGroupId.getOrDefault(absoluteRowIndex, BookmarkGrid.DEFAULT_GROUP_ID)
|
||||
== BookmarkGrid.DEFAULT_GROUP_ID) {
|
||||
int groupId = BookmarkGrid.DEFAULT_GROUP_ID;
|
||||
|
||||
if (this.slotToItem.containsKey(absoluteSlotIndex)) {
|
||||
groupId = this.caclulatedItems.get(this.slotToItem.get(absoluteSlotIndex)).getItem().groupId;
|
||||
}
|
||||
|
||||
this.rowToGroupId.put(absoluteRowIndex, groupId);
|
||||
|
||||
if (groupId != BookmarkGrid.DEFAULT_GROUP_ID && previousGroupId == (previousGroupId = groupId)) {
|
||||
while ((--absoluteRowIndex) >= 0
|
||||
&& this.rowToGroupId.get(absoluteRowIndex) == BookmarkGrid.DEFAULT_GROUP_ID) {
|
||||
this.rowToGroupId.put(absoluteRowIndex, groupId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Comparator<Integer> generateSortingComparator(Map<Integer, BookmarkChainItem> calculatedItems) {
|
||||
return Comparator.comparingInt((Integer index) -> calculatedItems.get(index).calculatedType.toInt())
|
||||
.thenComparing(index -> StackInfo.getFluid(calculatedItems.get(index).getItem().itemStack) != null)
|
||||
.thenComparing(
|
||||
(i1, i2) -> ItemSorter.instance.compare(
|
||||
calculatedItems.get(i1).getItem().itemStack,
|
||||
calculatedItems.get(i2).getItem().itemStack));
|
||||
}
|
||||
|
||||
private void splitGridMask() {
|
||||
int gridColumns = this.grid.getColumns();
|
||||
int rows = this.grid.getRows();
|
||||
int perPage = rows * gridColumns;
|
||||
|
||||
this.pageCount = (int) Math.ceil(this.maxAbsoluteSlotIndex / (float) perPage);
|
||||
int page = Math.max(0, Math.min(this.grid.getPage(), this.pageCount) - 1);
|
||||
|
||||
for (int absoluteSlotIndex = page * perPage; absoluteSlotIndex
|
||||
< Math.min(this.maxAbsoluteSlotIndex, (page + 1) * perPage); absoluteSlotIndex++) {
|
||||
if (this.slotToItem.get(absoluteSlotIndex) != null) {
|
||||
this.gridMask
|
||||
.add(getBookmarkGridSlot(absoluteSlotIndex % perPage, this.slotToItem.get(absoluteSlotIndex)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BookmarkChainItem getItem(BookmarkGroup group, int itemIndex) {
|
||||
if (group.crafting != null) {
|
||||
return group.crafting.calculatedItems.get(itemIndex);
|
||||
} else {
|
||||
BookmarkChainItem item = BookmarkChainItem.of(this.grid.getBookmarkItem(itemIndex));
|
||||
item.setRealAmount(item.getShiftAmount());
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
private BookmarksGridSlot getBookmarkGridSlot(int slotIndex, int itemIndex) {
|
||||
final BookmarkChainItem chainItem = this.caclulatedItems.get(itemIndex);
|
||||
final BookmarkGroup group = this.grid.getGroup(chainItem.getItem().groupId);
|
||||
|
||||
if (group.crafting == null) {
|
||||
return new BookmarksGridSlot(
|
||||
slotIndex,
|
||||
itemIndex,
|
||||
chainItem.getRealAmount(),
|
||||
0,
|
||||
0,
|
||||
chainItem.getItem(),
|
||||
null,
|
||||
group);
|
||||
} else {
|
||||
return new BookmarksGridSlot(
|
||||
slotIndex,
|
||||
itemIndex,
|
||||
chainItem.getRealAmount(),
|
||||
chainItem.getShiftAmount(),
|
||||
chainItem.getCalculatedAmount(),
|
||||
chainItem.getItem(),
|
||||
chainItem.calculatedType,
|
||||
group);
|
||||
}
|
||||
}
|
||||
|
||||
protected void calculateGroupBorders(Map<Integer, String> borderGrid) {
|
||||
int gridColumns = this.grid.getColumns();
|
||||
int page = Math.max(1, Math.min(this.grid.getPage(), this.pageCount)) - 1;
|
||||
int shiftIndex = page * this.grid.getRows() * gridColumns;
|
||||
|
||||
for (BookmarksGridSlot slot : this.gridMask) {
|
||||
if (borderGrid.get(shiftIndex + slot.slotIndex) == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String groupIndex = borderGrid.get(shiftIndex + slot.slotIndex);
|
||||
int column = slot.slotIndex % gridColumns;
|
||||
int row = slot.slotIndex / gridColumns;
|
||||
int prevSlotIndex = shiftIndex + (row - 1) * gridColumns + column;
|
||||
int nextSlotIndex = shiftIndex + (row + 1) * gridColumns + column;
|
||||
BookmarkGroup group = slot.getGroup();
|
||||
|
||||
if (group.crafting == null) {
|
||||
slot.borderColor = BookmarkGrid.GROUP_NONE_COLOR;
|
||||
} else if (group.collapsed) {
|
||||
slot.borderColor = BookmarkGrid.GROUP_CHAIN_COLOR;
|
||||
} else {
|
||||
slot.borderColor = BookmarkGrid.RECIPE_COLOR;
|
||||
}
|
||||
|
||||
slot.borderLeft = column == 0 || !groupIndex.equals(borderGrid.get(shiftIndex + slot.slotIndex - 1));
|
||||
slot.borderRight = column + 1 == gridColumns
|
||||
|| !groupIndex.equals(borderGrid.get(shiftIndex + slot.slotIndex + 1));
|
||||
|
||||
slot.borderTop = !groupIndex.equals(borderGrid.get(prevSlotIndex));
|
||||
slot.borderBottom = !groupIndex.equals(borderGrid.get(nextSlotIndex));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package codechicken.nei.bookmark;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
|
||||
public class BookmarkGroup {
|
||||
|
||||
public RecipeChainDetails crafting = null;
|
||||
public BookmarkViewMode viewMode;
|
||||
public boolean collapsed = false;
|
||||
public Set<RecipeId> collapsedRecipes = new HashSet<>();
|
||||
|
||||
public BookmarkGroup(BookmarkViewMode viewMode) {
|
||||
this.viewMode = viewMode;
|
||||
}
|
||||
|
||||
public BookmarkGroup(BookmarkViewMode viewMode, boolean crafting) {
|
||||
this.viewMode = viewMode;
|
||||
setCraftingMode(crafting);
|
||||
}
|
||||
|
||||
public void toggleViewMode() {
|
||||
if (this.viewMode == BookmarkViewMode.DEFAULT) {
|
||||
this.viewMode = BookmarkViewMode.TODO_LIST;
|
||||
} else {
|
||||
this.viewMode = BookmarkViewMode.DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
public void setCraftingMode(boolean crafting) {
|
||||
if ((this.crafting != null) != crafting) {
|
||||
this.crafting = crafting ? new RecipeChainDetails() : null;
|
||||
}
|
||||
}
|
||||
|
||||
public void toggleCraftingMode() {
|
||||
setCraftingMode(this.crafting == null);
|
||||
}
|
||||
|
||||
public void toggleCollapsedState() {
|
||||
this.collapsed = !this.collapsed;
|
||||
}
|
||||
|
||||
public void toggleCollapsedRecipe(RecipeId recipeId) {
|
||||
if (this.collapsedRecipes.contains(recipeId)) {
|
||||
this.collapsedRecipes.remove(recipeId);
|
||||
} else {
|
||||
this.collapsedRecipes.add(recipeId);
|
||||
}
|
||||
}
|
||||
|
||||
public BookmarkGroup copy() {
|
||||
return new BookmarkGroup(this.viewMode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
package codechicken.nei.bookmark;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.recipe.Recipe;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.Recipe.RecipeIngredient;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
|
||||
public class BookmarkItem {
|
||||
|
||||
private static Map<ItemStack, String> fuzzyPermutations = new HashMap<>();
|
||||
|
||||
public int groupId;
|
||||
|
||||
public long amount = 0L;
|
||||
public final int fluidCellAmount;
|
||||
public ItemStack itemStack;
|
||||
public Map<String, ItemStack> permutations;
|
||||
|
||||
public long factor;
|
||||
public RecipeId recipeId;
|
||||
public boolean isIngredient = false;
|
||||
|
||||
protected BookmarkItem(int groupId, long amount, int fluidCellAmount, ItemStack itemStack,
|
||||
Map<String, ItemStack> permutations, long factor, RecipeId recipeId, boolean isIngredient) {
|
||||
this.groupId = groupId;
|
||||
|
||||
this.amount = amount;
|
||||
this.fluidCellAmount = fluidCellAmount;
|
||||
this.itemStack = itemStack;
|
||||
this.permutations = permutations;
|
||||
|
||||
this.factor = factor;
|
||||
this.recipeId = recipeId;
|
||||
this.isIngredient = isIngredient;
|
||||
}
|
||||
|
||||
public static BookmarkItem of(int groupId, ItemStack stack, long factor, RecipeId recipeId, boolean isIngredient,
|
||||
Map<String, ItemStack> permutations) {
|
||||
final FluidStack fluidStack = StackInfo.getFluid(stack);
|
||||
int fluidCellAmount = 1;
|
||||
long amount;
|
||||
|
||||
if (fluidStack != null) {
|
||||
amount = fluidStack.amount * (long) Math.max(0, stack.stackSize);
|
||||
fluidCellAmount = Math.max(1, StackInfo.isFluidContainer(stack) ? fluidStack.amount : 1);
|
||||
} else {
|
||||
amount = StackInfo.getAmount(stack);
|
||||
}
|
||||
|
||||
return new BookmarkItem(
|
||||
groupId,
|
||||
amount,
|
||||
fluidCellAmount,
|
||||
stack,
|
||||
permutations,
|
||||
factor * fluidCellAmount,
|
||||
recipeId,
|
||||
isIngredient);
|
||||
}
|
||||
|
||||
public static BookmarkItem of(int groupId, ItemStack stack, long factor, RecipeId recipeId, boolean isIngredient) {
|
||||
return of(groupId, stack, factor, recipeId, isIngredient, generatePermutations(stack, recipeId, isIngredient));
|
||||
}
|
||||
|
||||
public static BookmarkItem of(int groupId, ItemStack stack) {
|
||||
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(stack);
|
||||
final long factor = nbTag.hasKey("gtFluidName") ? Math.min(144, nbTag.getInteger("Count")) : 1;
|
||||
return BookmarkItem
|
||||
.of(groupId, stack, factor, null, false, Collections.singletonMap(getItemGUID(stack), stack));
|
||||
}
|
||||
|
||||
public BookmarkItem copyWithAmount(long amount) {
|
||||
return new BookmarkItem(
|
||||
this.groupId,
|
||||
amount,
|
||||
this.fluidCellAmount,
|
||||
this.itemStack,
|
||||
this.permutations,
|
||||
this.factor,
|
||||
this.recipeId,
|
||||
this.isIngredient);
|
||||
}
|
||||
|
||||
public BookmarkItem copy() {
|
||||
return copyWithAmount(this.amount);
|
||||
}
|
||||
|
||||
public static Map<String, ItemStack> generatePermutations(ItemStack stack, RecipeId recipeId,
|
||||
boolean isIngredient) {
|
||||
|
||||
if (isIngredient && recipeId != null) {
|
||||
return generatePermutations(stack, Recipe.of(recipeId));
|
||||
}
|
||||
|
||||
return Collections.singletonMap(getItemGUID(stack), stack);
|
||||
}
|
||||
|
||||
public static Map<String, ItemStack> generatePermutations(ItemStack stack, Recipe recipe) {
|
||||
|
||||
if (recipe != null) {
|
||||
final RecipeIngredient ingr = recipe.getIngredients().stream()
|
||||
.filter(ingredient -> ingredient.contains(stack)).findAny().orElse(null);
|
||||
|
||||
if (ingr != null) {
|
||||
final Map<String, ItemStack> permutations = new HashMap<>();
|
||||
for (ItemStack ingrStack : ingr.getPermutations()) {
|
||||
permutations.put(getItemGUID(ingrStack), ingrStack);
|
||||
}
|
||||
return permutations;
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.singletonMap(getItemGUID(stack), stack);
|
||||
}
|
||||
|
||||
private static synchronized String getItemGUID(ItemStack stack) {
|
||||
final FluidStack fluidStack = StackInfo.getFluid(stack);
|
||||
|
||||
if (fluidStack != null) {
|
||||
return fluidStack.getFluid().getName() + ":" + fluidStack.tag;
|
||||
} else {
|
||||
|
||||
for (Map.Entry<ItemStack, String> entry : BookmarkItem.fuzzyPermutations.entrySet()) {
|
||||
if (NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack, entry.getKey())) {
|
||||
BookmarkItem.fuzzyPermutations.put(stack, entry.getValue());
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
final String stackGUID = StackInfo.getItemStackGUID(stack);
|
||||
BookmarkItem.fuzzyPermutations.put(stack, stackGUID);
|
||||
|
||||
return stackGUID;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsItems(BookmarkItem item) {
|
||||
return this.permutations.keySet().stream().anyMatch(item.permutations::containsKey);
|
||||
}
|
||||
|
||||
public ItemStack getItemStack() {
|
||||
return getItemStack(this.amount);
|
||||
}
|
||||
|
||||
public ItemStack getItemStack(long amount) {
|
||||
return StackInfo.withAmount(this.itemStack, getStackSize(amount));
|
||||
}
|
||||
|
||||
public long getStackSize() {
|
||||
return getStackSize(this.amount);
|
||||
}
|
||||
|
||||
public long getStackSize(long amount) {
|
||||
return (long) (this.factor > 0 ? Math.ceil(amount / (double) this.fluidCellAmount) : 0);
|
||||
}
|
||||
|
||||
public long getMultiplier() {
|
||||
return getMultiplier(this.amount);
|
||||
}
|
||||
|
||||
public long getMultiplier(long amount) {
|
||||
return (long) (this.factor > 0 ? Math.ceil(amount / (double) this.factor) : 0);
|
||||
}
|
||||
|
||||
public long getFactor() {
|
||||
return this.factor / this.fluidCellAmount;
|
||||
}
|
||||
|
||||
public boolean equalsRecipe(BookmarkItem meta) {
|
||||
return equalsRecipe(meta.recipeId, meta.groupId);
|
||||
}
|
||||
|
||||
public boolean equalsRecipe(RecipeId recipeId, int groupId) {
|
||||
return groupId == this.groupId && recipeId != null && recipeId.equals(this.recipeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.groupId, this.fluidCellAmount, this.isIngredient, this.recipeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
|
||||
if (object instanceof BookmarkItem item) {
|
||||
return this.groupId == item.groupId && this.isIngredient == item.isIngredient
|
||||
&& this.fluidCellAmount == item.fluidCellAmount
|
||||
&& StackInfo.equalItemAndNBT(this.itemStack, item.itemStack, true)
|
||||
&& (this.recipeId == item.recipeId || this.recipeId != null && this.recipeId.equals(item.recipeId));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,366 @@
|
||||
package codechicken.nei.bookmark;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.NBTJson;
|
||||
|
||||
public class BookmarkStorage {
|
||||
|
||||
protected List<BookmarkGrid> namespaces = new ArrayList<>();
|
||||
protected int activeNamespaceIndex = 0;
|
||||
protected File bookmarkFile = null;
|
||||
|
||||
public BookmarkStorage() {
|
||||
this.namespaces.add(new BookmarkGrid());
|
||||
}
|
||||
|
||||
public boolean prevNamespace() {
|
||||
getNamespaceSize();
|
||||
removeEmptyNamespaces();
|
||||
|
||||
if (this.activeNamespaceIndex == 0) {
|
||||
setNamespace(getNamespaceSize() - 1);
|
||||
} else {
|
||||
setNamespace(this.activeNamespaceIndex - 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean nextNamespace() {
|
||||
|
||||
if (removeEmptyNamespaces()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.activeNamespaceIndex == getNamespaceSize() - 1) {
|
||||
setNamespace(0);
|
||||
} else {
|
||||
setNamespace(this.activeNamespaceIndex + 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setNamespace(int namespaceIndex) {
|
||||
this.activeNamespaceIndex = Math.min(namespaceIndex, this.namespaces.size() - 1);
|
||||
BookmarkGrid grid = this.namespaces.get(this.activeNamespaceIndex);
|
||||
|
||||
if (grid.size() == 0 && this.activeNamespaceIndex > 0) {
|
||||
grid.setViewMode(
|
||||
BookmarkGrid.DEFAULT_GROUP_ID,
|
||||
this.namespaces.get(this.activeNamespaceIndex - 1).getViewMode(BookmarkGrid.DEFAULT_GROUP_ID));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int getNamespaceSize() {
|
||||
|
||||
if (this.namespaces.get(this.namespaces.size() - 1).size() > 0) {
|
||||
this.namespaces.add(new BookmarkGrid());
|
||||
} else if (this.activeNamespaceIndex == this.namespaces.size() - 2 && getActiveGrid().size() == 0) {
|
||||
this.namespaces.remove(this.namespaces.size() - 1);
|
||||
}
|
||||
|
||||
return this.namespaces.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return this.namespaces.size() <= 1 && getActiveGrid().isEmpty();
|
||||
}
|
||||
|
||||
public int getActiveIndex() {
|
||||
return this.activeNamespaceIndex;
|
||||
}
|
||||
|
||||
public BookmarkGrid getActiveGrid() {
|
||||
return this.namespaces.get(this.activeNamespaceIndex);
|
||||
}
|
||||
|
||||
private boolean removeEmptyNamespaces() {
|
||||
|
||||
if (this.activeNamespaceIndex != this.namespaces.size() - 1 && getActiveGrid().size() == 0) {
|
||||
this.namespaces.remove(this.activeNamespaceIndex);
|
||||
setNamespace(this.activeNamespaceIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void load(File bookmarkFile) {
|
||||
|
||||
if (bookmarkFile.equals(this.bookmarkFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> itemStrings = Collections.emptyList();
|
||||
|
||||
if (bookmarkFile.exists()) {
|
||||
try (FileInputStream reader = new FileInputStream(bookmarkFile)) {
|
||||
NEIClientConfig.logger.info("Loading bookmarks from file {}", bookmarkFile);
|
||||
itemStrings = IOUtils.readLines(reader, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to load bookmarks from file {}", bookmarkFile, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final JsonParser parser = new JsonParser();
|
||||
final List<BookmarkGrid> namespaces = new ArrayList<>();
|
||||
NBTTagCompound navigation = new NBTTagCompound();
|
||||
namespaces.add(new BookmarkGrid());
|
||||
BookmarkGrid grid = namespaces.get(0);
|
||||
|
||||
if (NEIClientConfig.world.nbt.hasKey("bookmark")) {
|
||||
navigation = NEIClientConfig.world.nbt.getCompoundTag("bookmark");
|
||||
}
|
||||
|
||||
for (String itemStr : itemStrings) {
|
||||
|
||||
try {
|
||||
|
||||
if (itemStr.isEmpty()) {
|
||||
itemStr = "; {}";
|
||||
}
|
||||
|
||||
if (itemStr.startsWith("; ")) {
|
||||
JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
|
||||
|
||||
if (grid.size() > 0) {
|
||||
// do not create empty namespaces
|
||||
grid = new BookmarkGrid();
|
||||
namespaces.add(grid);
|
||||
}
|
||||
|
||||
if (navigation.hasKey("namespacePage." + (namespaces.size() - 1))) {
|
||||
grid.setPage(navigation.getInteger("namespacePage." + (namespaces.size() - 1)));;
|
||||
}
|
||||
|
||||
if (settings.get("viewmode") != null) {
|
||||
grid.groups.get(BookmarkGrid.DEFAULT_GROUP_ID).viewMode = BookmarkViewMode
|
||||
.valueOf(settings.get("viewmode").getAsString());
|
||||
} else if (settings.get("groups") instanceof JsonObject jsonObject) {
|
||||
BookmarkGroup group;
|
||||
|
||||
for (Map.Entry<String, JsonElement> jsonEntry : jsonObject.entrySet()) {
|
||||
if (jsonEntry.getValue() instanceof JsonObject value) {
|
||||
group = new BookmarkGroup(
|
||||
value.has("viewmode")
|
||||
? BookmarkViewMode.valueOf(value.get("viewmode").getAsString())
|
||||
: BookmarkViewMode.DEFAULT,
|
||||
value.has("crafting") && value.get("crafting").getAsBoolean());
|
||||
|
||||
group.collapsed = value.has("collapsed") && value.get("collapsed").getAsBoolean();
|
||||
|
||||
if (value.has("collapsedRecipes")) {
|
||||
for (JsonElement recipeId : value.get("collapsedRecipes").getAsJsonArray()) {
|
||||
if (recipeId instanceof JsonObject item) {
|
||||
group.collapsedRecipes.add(RecipeId.of(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grid.groups.put(Integer.valueOf(jsonEntry.getKey()), group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!addItemToGrid(grid, parser.parse(itemStr).getAsJsonObject())) {
|
||||
NEIClientConfig.logger.warn(
|
||||
"Failed to load bookmarked ItemStack from json string, the item no longer exists:\n{}",
|
||||
itemStr);
|
||||
}
|
||||
|
||||
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
|
||||
NEIClientConfig.logger.error("Failed to load bookmarked ItemStack from json string:\n{}", itemStr);
|
||||
}
|
||||
}
|
||||
|
||||
prepareOldRecipeFormat(namespaces);
|
||||
|
||||
for (BookmarkGrid gr : namespaces) {
|
||||
gr.onItemsChanged();
|
||||
}
|
||||
|
||||
this.namespaces = namespaces;
|
||||
|
||||
if (navigation.hasKey("namespaceIndex")) {
|
||||
setNamespace(navigation.getInteger("namespaceIndex"));
|
||||
} else {
|
||||
setNamespace(0);
|
||||
}
|
||||
|
||||
this.bookmarkFile = bookmarkFile;
|
||||
}
|
||||
|
||||
private boolean addItemToGrid(BookmarkGrid grid, JsonObject jsonObject) {
|
||||
NBTTagCompound itemStackNBT;
|
||||
|
||||
if (jsonObject.get("item") != null) {
|
||||
itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject.get("item"));
|
||||
} else { // old format
|
||||
itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject);
|
||||
}
|
||||
|
||||
ItemStack itemStack = StackInfo.loadFromNBT(itemStackNBT);
|
||||
|
||||
if (itemStack != null) {
|
||||
RecipeId recipeId = null;
|
||||
boolean isFluid = itemStackNBT.hasKey("gtFluidName");
|
||||
int groupId = jsonObject.has("groupId") ? jsonObject.get("groupId").getAsInt()
|
||||
: BookmarkGrid.DEFAULT_GROUP_ID;
|
||||
int factor = jsonObject.has("factor") ? Math.abs(jsonObject.get("factor").getAsInt()) : (isFluid ? 144 : 1);
|
||||
boolean isIngredient = jsonObject.has("ingredient") && jsonObject.get("ingredient").getAsBoolean();
|
||||
|
||||
if (jsonObject.get("recipeId") instanceof JsonObject recipeJson) {
|
||||
recipeId = RecipeId.of(recipeJson);
|
||||
}
|
||||
|
||||
if (!grid.groups.containsKey(groupId)) {
|
||||
groupId = BookmarkGrid.DEFAULT_GROUP_ID;
|
||||
}
|
||||
|
||||
grid.addItem(BookmarkItem.of(groupId, itemStack, factor, recipeId, isIngredient), false);
|
||||
}
|
||||
|
||||
return itemStack != null;
|
||||
}
|
||||
|
||||
private void prepareOldRecipeFormat(List<BookmarkGrid> namespaces) {
|
||||
|
||||
for (BookmarkGrid grid : namespaces) {
|
||||
if (grid.bookmarkItems.stream()
|
||||
.noneMatch(item -> item.recipeId != null && item.recipeId.getResult() == null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Map<String, RecipeId> recipes = new HashMap<>();
|
||||
|
||||
for (BookmarkItem item : grid.bookmarkItems) {
|
||||
if (item.recipeId != null && !item.isIngredient && item.recipeId.getResult() == null) {
|
||||
final JsonObject recipeJson = item.recipeId.toJsonObject();
|
||||
final String recipeGUID = item.groupId + ":" + NBTJson.toJson(recipeJson);
|
||||
|
||||
if (!recipes.containsKey(recipeGUID)) {
|
||||
recipeJson.add("result", NBTJson.toJsonObject(StackInfo.itemStackToNBT(item.itemStack)));
|
||||
recipes.put(recipeGUID, item.recipeId = RecipeId.of(recipeJson));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (BookmarkItem item : grid.bookmarkItems) {
|
||||
if (item.recipeId != null && item.recipeId.getResult() == null) {
|
||||
final JsonObject recipeJson = item.recipeId.toJsonObject();
|
||||
final String recipeGUID = item.groupId + ":" + NBTJson.toJson(recipeJson);
|
||||
|
||||
if (recipes.containsKey(recipeGUID)) {
|
||||
item.recipeId = recipes.get(recipeGUID).copy();
|
||||
item.permutations = BookmarkItem
|
||||
.generatePermutations(item.itemStack, item.recipeId, item.isIngredient);
|
||||
} else {
|
||||
item.recipeId = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void save() {
|
||||
|
||||
if (this.bookmarkFile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> strings = new ArrayList<>();
|
||||
NBTTagCompound navigation = new NBTTagCompound();
|
||||
navigation.setInteger("namespaceIndex", this.activeNamespaceIndex);
|
||||
|
||||
for (int grpIdx = 0; grpIdx < namespaces.size(); grpIdx++) {
|
||||
BookmarkGrid grid = namespaces.get(grpIdx);
|
||||
JsonObject settings = new JsonObject();
|
||||
JsonObject groups = new JsonObject();
|
||||
|
||||
for (int groupId : grid.groups.keySet()) {
|
||||
BookmarkGroup group = grid.groups.get(groupId);
|
||||
JsonObject groupJson = new JsonObject();
|
||||
groupJson.add("viewmode", new JsonPrimitive(group.viewMode.toString()));
|
||||
groupJson.add("crafting", new JsonPrimitive(group.crafting != null));
|
||||
groupJson.add("collapsed", new JsonPrimitive(group.collapsed));
|
||||
|
||||
if (!group.collapsedRecipes.isEmpty()) {
|
||||
JsonArray collapsedRecipes = new JsonArray();
|
||||
for (RecipeId recipeId : group.collapsedRecipes) {
|
||||
collapsedRecipes.add(recipeId.toJsonObject());
|
||||
}
|
||||
groupJson.add("collapsedRecipes", collapsedRecipes);
|
||||
}
|
||||
|
||||
groups.add(String.valueOf(groupId), groupJson);
|
||||
}
|
||||
|
||||
settings.add("groups", groups);
|
||||
strings.add("; " + NBTJson.toJson(settings));
|
||||
|
||||
navigation.setInteger("namespacePage." + grpIdx, grid.getPage() - 1);
|
||||
|
||||
for (BookmarkItem item : grid.bookmarkItems) {
|
||||
try {
|
||||
JsonObject row = new JsonObject();
|
||||
|
||||
row.add("item", NBTJson.toJsonObject(StackInfo.itemStackToNBT(item.getItemStack())));
|
||||
row.add("factor", new JsonPrimitive(item.getFactor()));
|
||||
row.add("ingredient", new JsonPrimitive(item.isIngredient));
|
||||
|
||||
if (item.groupId != BookmarkGrid.DEFAULT_GROUP_ID) {
|
||||
row.add("groupId", new JsonPrimitive(item.groupId));
|
||||
}
|
||||
|
||||
if (item.recipeId != null) {
|
||||
row.add("recipeId", item.recipeId.toJsonObject());
|
||||
}
|
||||
|
||||
strings.add(NBTJson.toJson(row));
|
||||
} catch (JsonSyntaxException e) {
|
||||
NEIClientConfig.logger.error("Failed to stringify bookmarked ItemStack to json string");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try (FileOutputStream output = new FileOutputStream(bookmarkFile)) {
|
||||
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
|
||||
NEIClientConfig.world.nbt.setTag("bookmark", navigation);
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to save bookmarks list to file {}", bookmarkFile, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
package codechicken.nei.bookmark;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.ItemsGrid.MouseContext;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.NEIClientUtils.Alignment;
|
||||
import codechicken.nei.bookmark.BookmarkGrid.BookmarkMouseContext;
|
||||
import codechicken.nei.bookmark.RecipeChainDetails.CalculatedType;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.ReadableNumberConverter;
|
||||
|
||||
public class BookmarksGridSlot extends ItemsGridSlot {
|
||||
|
||||
protected enum ShownItemType {
|
||||
REAL,
|
||||
SHIFT,
|
||||
CALCULATED
|
||||
}
|
||||
|
||||
protected static final float LINE_WIDTH = 0.75f;
|
||||
|
||||
protected static final Color INGREDIENTS_COLOR = new Color(0x6645DA75, true);
|
||||
|
||||
protected static final Color RESULTS_COLOR = new Color(0x9966CCFF, true);
|
||||
protected static final Color RESULTS_BG_COLOR = new Color(0x3366CCFF, true);
|
||||
protected static final Color RESULTS_BG_FLUID_COLOR = new Color(0x5566CCFF, true);
|
||||
|
||||
protected static final Color REMAINDER_COLOR = new Color(0x55A033A0, true);
|
||||
protected static final Color REMAINDER_BG_COLOR = new Color(0x33A033A0, true);
|
||||
protected static final Color REMAINDER_BG_FLUID_COLOR = new Color(0x44A033A0, true);
|
||||
|
||||
protected final ItemStack emptyItemStack;
|
||||
protected final long realAmount;
|
||||
protected final long shiftAmount;
|
||||
protected final long calculatedAmount;
|
||||
|
||||
protected final long realMultiplier;
|
||||
protected final long calculatedMultiplier;
|
||||
|
||||
protected final BookmarkGroup group;
|
||||
protected final boolean isFluidDisplay;
|
||||
protected final CalculatedType calculatedType;
|
||||
protected final CalculatedType realType;
|
||||
protected final BookmarkItem bookmarkItem;
|
||||
|
||||
protected final boolean isOutputRecipe;
|
||||
protected final boolean isFirstOutput;
|
||||
protected final int rowIndex;
|
||||
|
||||
public BookmarksGridSlot(int slotIndex, int itemIndex, long realAmount, long shiftAmount, long calculatedAmount,
|
||||
BookmarkItem bookmarkItem, CalculatedType calculatedType, BookmarkGroup group) {
|
||||
super(
|
||||
slotIndex,
|
||||
itemIndex,
|
||||
calculatedType != null ? bookmarkItem.getItemStack(calculatedAmount)
|
||||
: bookmarkItem.getItemStack(realAmount));
|
||||
|
||||
this.emptyItemStack = bookmarkItem.getItemStack(0);
|
||||
this.realAmount = realAmount;
|
||||
this.shiftAmount = shiftAmount;
|
||||
this.calculatedAmount = calculatedAmount;
|
||||
|
||||
this.group = group;
|
||||
this.calculatedType = calculatedType;
|
||||
this.bookmarkItem = bookmarkItem;
|
||||
|
||||
this.isOutputRecipe = group.crafting != null && group.crafting.outputRecipes.contains(bookmarkItem.recipeId);
|
||||
this.isFluidDisplay = StackInfo.itemStackToNBT(bookmarkItem.itemStack).hasKey("gtFluidName");
|
||||
|
||||
this.realMultiplier = bookmarkItem.getMultiplier(realAmount);
|
||||
this.calculatedMultiplier = bookmarkItem.getMultiplier(calculatedAmount);
|
||||
|
||||
if (this.group.crafting != null && this.group.crafting.calculatedItems.containsKey(this.itemIndex)) {
|
||||
this.realType = this.group.crafting.calculatedItems.get(this.itemIndex).calculatedType
|
||||
== CalculatedType.INGREDIENT ? CalculatedType.INGREDIENT : CalculatedType.RESULT;
|
||||
} else {
|
||||
this.realType = this.bookmarkItem.isIngredient
|
||||
|| this.group.crafting != null && this.bookmarkItem.recipeId == null ? CalculatedType.INGREDIENT
|
||||
: CalculatedType.RESULT;
|
||||
}
|
||||
|
||||
final BookmarkGrid grid = ItemPanels.bookmarkPanel.getGrid();
|
||||
final BookmarkItem prevItem = grid.getCalculatedItem(
|
||||
grid.gridGenerator.slotToItem.getOrDefault(grid.gridGenerator.itemToSlot.get(this.itemIndex) - 1, -1));
|
||||
this.isFirstOutput = this.itemIndex >= 0 && !this.bookmarkItem.isIngredient
|
||||
&& ((this.slotIndex % grid.getColumns()) == 0 || group.viewMode == BookmarkViewMode.DEFAULT)
|
||||
&& (prevItem == null || prevItem.isIngredient || !this.bookmarkItem.equalsRecipe(prevItem));
|
||||
this.rowIndex = this.slotIndex / grid.getColumns();
|
||||
}
|
||||
|
||||
public long getMultiplier() {
|
||||
return this.calculatedType != null ? this.calculatedMultiplier : this.realMultiplier;
|
||||
}
|
||||
|
||||
public BookmarkItem getBookmarkItem() {
|
||||
return this.bookmarkItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeId getRecipeId() {
|
||||
return this.bookmarkItem.recipeId;
|
||||
}
|
||||
|
||||
public boolean isIngredient() {
|
||||
return this.bookmarkItem.isIngredient;
|
||||
}
|
||||
|
||||
public BookmarkGroup getGroup() {
|
||||
return this.group;
|
||||
}
|
||||
|
||||
public int getGroupId() {
|
||||
return this.bookmarkItem.groupId;
|
||||
}
|
||||
|
||||
protected ShownItemType getShownItemType(BookmarkMouseContext mouseContext) {
|
||||
|
||||
if (mouseContext != null) {
|
||||
if (this.showShiftItem(mouseContext)) {
|
||||
return ShownItemType.SHIFT;
|
||||
} else if (this.showRealItem(mouseContext)) {
|
||||
return ShownItemType.REAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.calculatedType != null) {
|
||||
return ShownItemType.CALCULATED;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean showShiftItem(BookmarkMouseContext mouseContext) {
|
||||
|
||||
if (!mouseContext.shiftKey || this.bookmarkItem.groupId != mouseContext.groupId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.group.crafting != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.bookmarkItem.equalsRecipe(mouseContext.recipeId, mouseContext.groupId);
|
||||
}
|
||||
|
||||
protected boolean showRealItem(BookmarkMouseContext mouseContext) {
|
||||
|
||||
if (!mouseContext.controlKey || this.bookmarkItem.groupId != mouseContext.groupId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.slotIndex == mouseContext.slotIndex || this.group.collapsed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mouseContext.recipeId == null && this.group.viewMode == BookmarkViewMode.TODO_LIST
|
||||
&& mouseContext.rowIndex == this.rowIndex) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.bookmarkItem.equalsRecipe(mouseContext.recipeId, mouseContext.groupId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.group.crafting != null && mouseContext.recipeId != null
|
||||
&& mouseContext.recipeId.equals(this.group.crafting.itemToRecipe.get(this.itemIndex));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawItem(Rectangle4i rect) {
|
||||
super.drawItem(this.emptyItemStack, rect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <M extends MouseContext> void beforeDraw(Rectangle4i rect, M mouseContext) {
|
||||
final ShownItemType shownItemType = getShownItemType((BookmarkMouseContext) mouseContext);
|
||||
boolean showMarker = NEIClientConfig.showRecipeMarkerMode() == 2;
|
||||
CalculatedType calculatedType = null;
|
||||
|
||||
if (shownItemType == ShownItemType.REAL) {
|
||||
calculatedType = this.realType;
|
||||
} else if (shownItemType == ShownItemType.SHIFT) {
|
||||
|
||||
if (this.calculatedType != null) {
|
||||
calculatedType = this.shiftAmount > 0 ? this.calculatedType : null;
|
||||
showMarker = false;
|
||||
} else if (group.crafting == null) {
|
||||
calculatedType = this.realType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!this.bookmarkItem.isIngredient && this.bookmarkItem.recipeId != null
|
||||
&& calculatedType == null
|
||||
&& showMarker
|
||||
&& (mouseContext == null || mouseContext.slotIndex != this.slotIndex)) {
|
||||
drawMerkerBackground(rect);
|
||||
}
|
||||
|
||||
if (calculatedType == null || !drawBackground(rect, calculatedType)) {
|
||||
super.beforeDraw(rect, mouseContext);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean drawBackground(Rectangle4i rect, CalculatedType calculatedType) {
|
||||
|
||||
switch (calculatedType) {
|
||||
case INGREDIENT:
|
||||
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, INGREDIENTS_COLOR);
|
||||
break;
|
||||
case RESULT:
|
||||
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, RESULTS_COLOR);
|
||||
break;
|
||||
case REMAINDER:
|
||||
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, REMAINDER_COLOR);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void drawMerkerBackground(Rectangle4i rect) {
|
||||
Color color = this.isFluidDisplay ? RESULTS_BG_FLUID_COLOR : RESULTS_BG_COLOR;
|
||||
|
||||
if (this.shiftAmount > 0 && this.calculatedType == CalculatedType.REMAINDER) {
|
||||
color = this.isFluidDisplay ? REMAINDER_BG_FLUID_COLOR : REMAINDER_BG_COLOR;
|
||||
}
|
||||
|
||||
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <M extends MouseContext> void afterDraw(Rectangle4i rect, M mouseContext) {
|
||||
final ShownItemType shownItemType = getShownItemType((BookmarkMouseContext) mouseContext);
|
||||
|
||||
drawStackSize(rect, shownItemType);
|
||||
|
||||
if (this.bookmarkItem.isIngredient || this.bookmarkItem.recipeId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isFirstOutput) {
|
||||
if (shownItemType == ShownItemType.REAL) {
|
||||
drawMarker(
|
||||
rect,
|
||||
"x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(this.realMultiplier),
|
||||
0xFFFFFF);
|
||||
} else if (shownItemType == ShownItemType.SHIFT) {
|
||||
drawMarker(rect, "x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(getMultiplier()), 0xFFFFFF);
|
||||
} else if (this.isOutputRecipe || this.realMultiplier > 1) {
|
||||
drawMarker(
|
||||
rect,
|
||||
"x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(this.realMultiplier),
|
||||
NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue());
|
||||
} else if (NEIClientConfig.showRecipeMarkerMode() == 1) {
|
||||
drawMarker(
|
||||
rect,
|
||||
"R",
|
||||
NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue());
|
||||
}
|
||||
} else if (NEIClientConfig.showRecipeMarkerMode() == 1) {
|
||||
drawMarker(rect, "R", NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void drawMarker(Rectangle4i rect, String text, int color) {
|
||||
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
|
||||
NEIClientUtils.drawNEIOverlayText(
|
||||
text,
|
||||
new Rectangle4i(rect.x + 1, rect.y + 1, rect.w - 2, rect.h - 2),
|
||||
panelFactor,
|
||||
color,
|
||||
true,
|
||||
Alignment.TopLeft);
|
||||
}
|
||||
|
||||
protected void drawStackSize(Rectangle4i rect, ShownItemType shownItemType) {
|
||||
long amount = this.calculatedAmount;
|
||||
|
||||
if (shownItemType == null || shownItemType == ShownItemType.REAL || this.calculatedType == null) {
|
||||
amount = this.realAmount;
|
||||
} else if (shownItemType == ShownItemType.SHIFT) {
|
||||
amount = this.shiftAmount;
|
||||
}
|
||||
|
||||
if (amount > 0 || shownItemType == ShownItemType.REAL && this.bookmarkItem.factor > 0) {
|
||||
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
|
||||
final long stackSize = this.bookmarkItem.getStackSize(amount);
|
||||
String amountString = "";
|
||||
|
||||
if (stackSize < 10_000) {
|
||||
amountString = String.valueOf(stackSize);
|
||||
} else {
|
||||
amountString = ReadableNumberConverter.INSTANCE.toWideReadableForm(stackSize);
|
||||
}
|
||||
|
||||
if (this.isFluidDisplay) {
|
||||
amountString += "L";
|
||||
}
|
||||
|
||||
NEIClientUtils.drawNEIOverlayText(
|
||||
amountString,
|
||||
new Rectangle4i(rect.x + 1, rect.y + 1, rect.w - 2, rect.h - 2),
|
||||
panelFactor,
|
||||
0xFFFFFF,
|
||||
true,
|
||||
this.isFluidDisplay ? Alignment.BottomLeft : Alignment.BottomRight);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
package codechicken.nei.bookmark;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
|
||||
public class GroupingItem {
|
||||
|
||||
public static class PointEntry {
|
||||
|
||||
public int cursorRowIndex;
|
||||
public int topRowIndex;
|
||||
public int bottomRowIndex;
|
||||
|
||||
public PointEntry(int clickSlotIndex, int topSlotIndex, int bottomSlotIndex) {
|
||||
this.cursorRowIndex = clickSlotIndex;
|
||||
this.topRowIndex = topSlotIndex;
|
||||
this.bottomRowIndex = bottomSlotIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public BookmarkGrid grid;
|
||||
|
||||
public int groupId = -1;
|
||||
public PointEntry startPoint;
|
||||
public PointEntry endPoint;
|
||||
|
||||
public GroupingItem(BookmarkGrid grid, int groupId, int overRowIndex) {
|
||||
this.groupId = groupId;
|
||||
this.grid = grid;
|
||||
setStartPoint(overRowIndex);
|
||||
}
|
||||
|
||||
public void setStartPoint(int overRowIndex) {
|
||||
|
||||
if (this.grid.getRowItemIndex(overRowIndex, true) != Integer.MIN_VALUE) {
|
||||
this.startPoint = new PointEntry(
|
||||
overRowIndex + getRowShift(),
|
||||
getTopRowIndex(overRowIndex),
|
||||
getBottomRowIndex(overRowIndex));
|
||||
} else {
|
||||
this.startPoint = new PointEntry(overRowIndex + getRowShift(), -1, -1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setEndPoint(int overRowIndex) {
|
||||
if (this.grid.getRowItemIndex(overRowIndex, true) != Integer.MIN_VALUE) {
|
||||
this.endPoint = new PointEntry(
|
||||
overRowIndex + getRowShift(),
|
||||
getTopRowIndex(overRowIndex),
|
||||
getBottomRowIndex(overRowIndex));
|
||||
}
|
||||
}
|
||||
|
||||
public int getStartSlotIndex() {
|
||||
return this.startPoint.cursorRowIndex - getRowShift();
|
||||
}
|
||||
|
||||
public int getEndSlotIndex() {
|
||||
return this.endPoint != null ? this.endPoint.cursorRowIndex - getRowShift() : 0;
|
||||
}
|
||||
|
||||
public boolean hasEndRow() {
|
||||
return this.endPoint != null;
|
||||
}
|
||||
|
||||
private int getRowShift() {
|
||||
return (this.grid.getPage() - 1) * this.grid.getRows();
|
||||
}
|
||||
|
||||
public Map<Integer, Integer> prepareGroups(Map<Integer, Integer> groups) {
|
||||
final int topRowIndex = Math.min(this.startPoint.topRowIndex, this.endPoint.topRowIndex);
|
||||
final int bottomRowIndex = Math.max(this.startPoint.bottomRowIndex, this.endPoint.bottomRowIndex);
|
||||
groups = new HashMap<>(groups);
|
||||
|
||||
if (this.groupId != BookmarkGrid.DEFAULT_GROUP_ID) {
|
||||
|
||||
if (this.startPoint.cursorRowIndex > this.endPoint.cursorRowIndex) {
|
||||
int rowIndex = this.endPoint.topRowIndex - 1;
|
||||
|
||||
while (groups.containsKey(rowIndex) && groups.get(rowIndex) == this.groupId) {
|
||||
groups.put(rowIndex--, BookmarkGrid.DEFAULT_GROUP_ID);
|
||||
}
|
||||
|
||||
} else if (this.startPoint.cursorRowIndex < this.endPoint.cursorRowIndex) {
|
||||
int rowIndex = this.endPoint.bottomRowIndex + 1;
|
||||
|
||||
while (groups.containsKey(rowIndex) && groups.get(rowIndex) == this.groupId) {
|
||||
groups.put(rowIndex++, BookmarkGrid.DEFAULT_GROUP_ID);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (groups.containsKey(topRowIndex - 1)
|
||||
&& groups.get(topRowIndex - 1).equals(groups.get(bottomRowIndex + 1))) {
|
||||
int groupId = groups.get(bottomRowIndex);
|
||||
int rowIndex = bottomRowIndex + 1;
|
||||
|
||||
while (groups.containsKey(rowIndex) && groups.get(rowIndex) == groupId) {
|
||||
groups.put(rowIndex, -1 * groups.get(rowIndex));
|
||||
rowIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int rowIndex = topRowIndex; rowIndex <= bottomRowIndex && groups.containsKey(rowIndex); rowIndex++) {
|
||||
groups.put(rowIndex, this.groupId);
|
||||
}
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
protected int getTopRowIndex(int overRowIndex) {
|
||||
final int rowShift = getRowShift();
|
||||
int itemIndex = this.grid.getRowItemIndex(overRowIndex, true);
|
||||
|
||||
if (itemIndex == Integer.MIN_VALUE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
final BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
|
||||
|
||||
if (item.recipeId != null) {
|
||||
final List<Integer> sortedItems = this.grid.getSortedItems();
|
||||
final BookmarkGroup group = this.grid.getGroup(item.groupId);
|
||||
final boolean isCollapsedGroup = group.collapsed
|
||||
|| group.crafting != null && group.viewMode == BookmarkViewMode.DEFAULT;
|
||||
final RecipeId recipeId = group.crafting != null
|
||||
? group.crafting.itemToRecipe.getOrDefault(itemIndex, item.recipeId)
|
||||
: item.recipeId;
|
||||
final Set<RecipeId> recipeRelations = group.crafting != null
|
||||
? group.crafting.recipeRelations.getOrDefault(recipeId, Collections.singleton(recipeId))
|
||||
: Collections.singleton(recipeId);
|
||||
|
||||
for (Integer rItemIndex : sortedItems) {
|
||||
final BookmarkItem rItem = this.grid.getCalculatedItem(rItemIndex);
|
||||
|
||||
if (rItem.groupId == item.groupId && (isCollapsedGroup || recipeRelations.contains(rItem.recipeId))) {
|
||||
return this.grid.getAbsoluteSlotIndex(rItemIndex) / this.grid.getColumns();
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rowShift + overRowIndex;
|
||||
}
|
||||
|
||||
protected int getBottomRowIndex(int overRowIndex) {
|
||||
final int rowShift = getRowShift();
|
||||
final int itemIndex = this.grid.getRowItemIndex(overRowIndex, false);
|
||||
|
||||
if (itemIndex == Integer.MIN_VALUE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
final BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
|
||||
|
||||
if (item.recipeId != null) {
|
||||
final List<Integer> sortedItems = this.grid.getSortedItems();
|
||||
final BookmarkGroup group = this.grid.getGroup(item.groupId);
|
||||
final boolean isCollapsedGroup = group.collapsed
|
||||
|| group.crafting != null && group.viewMode == BookmarkViewMode.DEFAULT;
|
||||
final RecipeId recipeId = group.crafting != null
|
||||
? group.crafting.itemToRecipe.getOrDefault(itemIndex, item.recipeId)
|
||||
: item.recipeId;
|
||||
final Set<RecipeId> recipeRelations = group.crafting != null
|
||||
? group.crafting.recipeRelations.getOrDefault(recipeId, Collections.singleton(recipeId))
|
||||
: Collections.singleton(recipeId);
|
||||
|
||||
for (int index = sortedItems.size() - 1; index >= 0; index--) {
|
||||
final int rItemIndex = sortedItems.get(index);
|
||||
final BookmarkItem rItem = this.grid.getCalculatedItem(rItemIndex);
|
||||
|
||||
if (rItem.groupId == item.groupId && (isCollapsedGroup || recipeRelations.contains(rItem.recipeId))) {
|
||||
return this.grid.getAbsoluteSlotIndex(rItemIndex) / this.grid.getColumns();
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rowShift + overRowIndex;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,375 @@
|
||||
package codechicken.nei.bookmark;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.recipe.chain.RecipeChainMath;
|
||||
|
||||
public class RecipeChainDetails {
|
||||
|
||||
public enum CalculatedType {
|
||||
|
||||
INGREDIENT,
|
||||
RESULT,
|
||||
REMAINDER;
|
||||
|
||||
public int toInt() {
|
||||
switch (this) {
|
||||
case RESULT:
|
||||
return 0;
|
||||
case REMAINDER:
|
||||
return 1;
|
||||
case INGREDIENT:
|
||||
return 2;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BookmarkChainItem {
|
||||
|
||||
private final BookmarkItem item;
|
||||
|
||||
private long realAmount = 0L;
|
||||
private long shiftAmount = 0L;
|
||||
private long calculatedAmount = 0L;
|
||||
|
||||
public CalculatedType calculatedType;
|
||||
|
||||
protected BookmarkChainItem(BookmarkItem item, long shiftItem, long calculatedItem,
|
||||
CalculatedType calculatedType) {
|
||||
this.item = item.copy();
|
||||
this.shiftAmount = shiftItem;
|
||||
this.calculatedAmount = calculatedItem;
|
||||
this.calculatedType = calculatedType;
|
||||
}
|
||||
|
||||
public static BookmarkChainItem of(BookmarkItem item, long shiftItem, long calculatedAmount,
|
||||
CalculatedType calculatedType) {
|
||||
return new BookmarkChainItem(item, shiftItem, calculatedAmount, calculatedType);
|
||||
}
|
||||
|
||||
public static BookmarkChainItem of(BookmarkItem item, long shiftItem, CalculatedType calculatedType) {
|
||||
return new BookmarkChainItem(item, shiftItem, item.amount, calculatedType);
|
||||
}
|
||||
|
||||
public static BookmarkChainItem of(BookmarkItem item) {
|
||||
return new BookmarkChainItem(
|
||||
item,
|
||||
item.amount,
|
||||
item.amount,
|
||||
item.isIngredient ? CalculatedType.INGREDIENT : CalculatedType.RESULT);
|
||||
}
|
||||
|
||||
public ItemStack getItemStack(long amount) {
|
||||
return this.item.getItemStack(amount);
|
||||
}
|
||||
|
||||
public void setRealAmount(long amount) {
|
||||
this.realAmount = amount;
|
||||
}
|
||||
|
||||
public long getRealAmount() {
|
||||
return this.realAmount;
|
||||
}
|
||||
|
||||
public long getShiftAmount() {
|
||||
return this.shiftAmount;
|
||||
}
|
||||
|
||||
public long getCalculatedAmount() {
|
||||
return this.calculatedAmount;
|
||||
}
|
||||
|
||||
public BookmarkItem getItem() {
|
||||
return this.item;
|
||||
}
|
||||
|
||||
public void append(long amount, long calculatedAmount) {
|
||||
this.shiftAmount += amount;
|
||||
this.calculatedAmount += calculatedAmount;
|
||||
this.item.amount = this.calculatedAmount;
|
||||
}
|
||||
}
|
||||
|
||||
public final Map<Integer, BookmarkChainItem> calculatedItems = new HashMap<>();
|
||||
public final Map<Integer, RecipeId> itemToRecipe = new HashMap<>();
|
||||
public final Set<RecipeId> outputRecipes = new HashSet<>();
|
||||
public final Set<RecipeId> recipeInMiddle = new HashSet<>();
|
||||
|
||||
public final Map<RecipeId, Set<RecipeId>> recipeRelations = new HashMap<>();
|
||||
|
||||
public void refresh(Map<Integer, BookmarkItem> chainItems, Set<RecipeId> collapsedRecipes) {
|
||||
final Map<BookmarkItem, Integer> sortingChainItems = new HashMap<>();
|
||||
|
||||
for (Map.Entry<Integer, BookmarkItem> entry : chainItems.entrySet()) {
|
||||
sortingChainItems.put(entry.getValue(), entry.getKey());
|
||||
}
|
||||
|
||||
this.itemToRecipe.clear();
|
||||
this.outputRecipes.clear();
|
||||
this.recipeInMiddle.clear();
|
||||
this.calculatedItems.clear();
|
||||
this.recipeRelations.clear();
|
||||
final RecipeChainMath math = RecipeChainMath.of(new ArrayList<>(chainItems.values()), collapsedRecipes)
|
||||
.refresh();
|
||||
|
||||
this.outputRecipes.addAll(math.outputRecipes.keySet());
|
||||
|
||||
for (BookmarkItem item : math.preferredItems.values()) {
|
||||
if (item != null && item.recipeId != null) {
|
||||
this.recipeInMiddle.add(item.recipeId);
|
||||
}
|
||||
}
|
||||
|
||||
for (BookmarkItem item : math.initialItems) {
|
||||
this.calculatedItems.put(
|
||||
sortingChainItems.get(item),
|
||||
BookmarkChainItem.of(item, math.requiredAmount.getOrDefault(item, 0L), CalculatedType.INGREDIENT));
|
||||
}
|
||||
|
||||
if (collapsedRecipes.isEmpty()) {
|
||||
|
||||
for (BookmarkItem item : math.recipeResults) {
|
||||
generateResult(math, item, sortingChainItems.get(item));
|
||||
}
|
||||
|
||||
for (BookmarkItem item : math.recipeIngredients) {
|
||||
generateIngredient(math, item, sortingChainItems.get(item));
|
||||
}
|
||||
|
||||
} else {
|
||||
final Set<RecipeId> topLevelRecipes = findTopLevelRecipes(math, collapsedRecipes);
|
||||
|
||||
for (RecipeId recipeId : collapsedRecipes) {
|
||||
this.recipeRelations.put(
|
||||
recipeId,
|
||||
getRecipeRelations(math, recipeId, topLevelRecipes, new HashSet<>(Arrays.asList(recipeId))));
|
||||
generateCollapsedRecipe(math, recipeId, topLevelRecipes, sortingChainItems);
|
||||
generateShadowItems(recipeId, chainItems.values(), sortingChainItems);
|
||||
}
|
||||
|
||||
for (BookmarkItem item : math.recipeResults) {
|
||||
if (!collapsedRecipes.contains(item.recipeId) && topLevelRecipes.contains(item.recipeId)) {
|
||||
generateResult(math, item, sortingChainItems.get(item));
|
||||
}
|
||||
}
|
||||
|
||||
for (BookmarkItem item : math.recipeIngredients) {
|
||||
if (!collapsedRecipes.contains(item.recipeId) && topLevelRecipes.contains(item.recipeId)) {
|
||||
generateIngredient(math, item, sortingChainItems.get(item));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (Map.Entry<Integer, BookmarkItem> entry : chainItems.entrySet()) {
|
||||
final int itemIndex = entry.getKey();
|
||||
if (itemIndex >= 0 && this.calculatedItems.containsKey(itemIndex)) {
|
||||
final BookmarkItem item = entry.getValue();
|
||||
if (this.recipeInMiddle.contains(item.recipeId)) {
|
||||
this.calculatedItems.get(itemIndex)
|
||||
.setRealAmount(Math.max(0, item.factor * (item.getMultiplier() - 1)));
|
||||
} else {
|
||||
this.calculatedItems.get(itemIndex).setRealAmount(item.amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Set<RecipeId> getRecipeRelations(RecipeChainMath math, RecipeId recipeId, Set<RecipeId> topLevelRecipes,
|
||||
Set<RecipeId> recipes) {
|
||||
|
||||
for (BookmarkItem item : math.recipeIngredients) {
|
||||
if (item.recipeId.equals(recipeId)) {
|
||||
final BookmarkItem prefItem = math.preferredItems.get(item);
|
||||
if (prefItem != null && !topLevelRecipes.contains(prefItem.recipeId)
|
||||
&& recipes.add(prefItem.recipeId)) {
|
||||
getRecipeRelations(math, prefItem.recipeId, topLevelRecipes, recipes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return recipes;
|
||||
}
|
||||
|
||||
private void generateCollapsedRecipe(RecipeChainMath math, RecipeId recipeId, Set<RecipeId> topLevelRecipes,
|
||||
Map<BookmarkItem, Integer> sortingChainItems) {
|
||||
|
||||
final List<BookmarkChainItem> items = collectItems(
|
||||
math,
|
||||
recipeId,
|
||||
this.recipeRelations.get(recipeId),
|
||||
topLevelRecipes);
|
||||
|
||||
for (BookmarkChainItem value : items) {
|
||||
int itemIndex = sortingChainItems.get(value.getItem());
|
||||
|
||||
if (value.getItem().isIngredient || !recipeId.equals(value.getItem().recipeId)) {
|
||||
itemIndex *= -1;
|
||||
}
|
||||
|
||||
if (!value.getItem().isIngredient && !math.outputRecipes.containsKey(value.getItem().recipeId)) {
|
||||
value.calculatedType = CalculatedType.REMAINDER;
|
||||
}
|
||||
|
||||
this.itemToRecipe.put(itemIndex, recipeId);
|
||||
this.calculatedItems.put(itemIndex, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateShadowItems(RecipeId recipeId, Iterable<BookmarkItem> chainItems,
|
||||
Map<BookmarkItem, Integer> sortingChainItems) {
|
||||
final Set<RecipeId> recipeRelations = this.recipeRelations.get(recipeId);
|
||||
final List<BookmarkItem> subChainItems = new ArrayList<>();
|
||||
|
||||
for (BookmarkItem item : chainItems) {
|
||||
if (recipeRelations.contains(item.recipeId)) {
|
||||
subChainItems.add(item.copyWithAmount(recipeId.equals(item.recipeId) ? item.amount : 0));
|
||||
}
|
||||
}
|
||||
|
||||
final RecipeChainMath math = RecipeChainMath.of(subChainItems, Collections.emptySet()).refresh();
|
||||
final List<BookmarkChainItem> items = collectItems(
|
||||
math,
|
||||
recipeId,
|
||||
this.recipeRelations.get(recipeId),
|
||||
Collections.emptySet());
|
||||
|
||||
for (BookmarkChainItem value : items) {
|
||||
int itemIndex = sortingChainItems.get(value.getItem());
|
||||
|
||||
if (value.getItem().isIngredient || !recipeId.equals(value.getItem().recipeId)) {
|
||||
itemIndex *= -1;
|
||||
}
|
||||
|
||||
if (this.calculatedItems.containsKey(itemIndex)) {
|
||||
this.calculatedItems.get(itemIndex).setRealAmount(value.getShiftAmount());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private List<BookmarkChainItem> collectItems(RecipeChainMath math, RecipeId recipeId, Set<RecipeId> recipeRelations,
|
||||
Set<RecipeId> topLevelRecipes) {
|
||||
final Map<String, BookmarkChainItem> items = new HashMap<>();
|
||||
final Map<RecipeId, Long> multiplier = new HashMap<>();
|
||||
|
||||
for (RecipeId relRecipeId : recipeRelations) {
|
||||
for (BookmarkItem item : math.recipeResults) {
|
||||
if (item.recipeId.equals(relRecipeId)) {
|
||||
final long amount = item.amount - math.requiredAmount.getOrDefault(item, 0L);
|
||||
|
||||
if (item.recipeId.equals(recipeId)) {
|
||||
multiplier.put(item.recipeId, item.getMultiplier());
|
||||
items.computeIfAbsent(
|
||||
StackInfo.getItemStackGUID(item.itemStack),
|
||||
is -> BookmarkChainItem.of(item, 0, 0, CalculatedType.RESULT))
|
||||
.append(amount, item.amount);
|
||||
} else if (amount > 0) {
|
||||
items.computeIfAbsent(
|
||||
StackInfo.getItemStackGUID(item.itemStack),
|
||||
is -> BookmarkChainItem.of(item, 0, 0, CalculatedType.RESULT)).append(amount, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (BookmarkItem item : math.recipeIngredients) {
|
||||
if (item.recipeId.equals(relRecipeId)) {
|
||||
final BookmarkItem prefItem = math.preferredItems.get(item);
|
||||
final long amount = math.requiredAmount.containsKey(prefItem) ? 0
|
||||
: math.requiredAmount.getOrDefault(item, item.amount);
|
||||
final long refAmount = prefItem != null && !topLevelRecipes.contains(prefItem.recipeId)
|
||||
? math.requiredAmount.getOrDefault(prefItem, 0L)
|
||||
: 0;
|
||||
|
||||
if (amount != 0 || item.amount > refAmount && math.requiredAmount.containsKey(prefItem)
|
||||
|| recipeId.equals(item.recipeId) && multiplier.get(recipeId) == 0) {
|
||||
items.computeIfAbsent(
|
||||
StackInfo.getItemStackGUID(item.itemStack),
|
||||
is -> BookmarkChainItem.of(item, 0, 0, CalculatedType.INGREDIENT))
|
||||
.append(amount, item.amount - refAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<>(items.values());
|
||||
}
|
||||
|
||||
private void generateResult(RecipeChainMath math, BookmarkItem item, int itemIndex) {
|
||||
final long amount = item.amount - math.requiredAmount.getOrDefault(item, 0L);
|
||||
final CalculatedType calculatedType = math.outputRecipes.containsKey(item.recipeId) ? CalculatedType.RESULT
|
||||
: CalculatedType.REMAINDER;
|
||||
|
||||
this.calculatedItems.put(itemIndex, BookmarkChainItem.of(item, amount, calculatedType));
|
||||
}
|
||||
|
||||
private void generateIngredient(RecipeChainMath math, BookmarkItem item, int itemIndex) {
|
||||
final BookmarkItem prefItem = math.preferredItems.get(item);
|
||||
final long amount = math.requiredAmount.containsKey(prefItem) ? 0
|
||||
: math.requiredAmount.getOrDefault(item, item.amount);
|
||||
|
||||
this.calculatedItems.put(itemIndex, BookmarkChainItem.of(item, amount, CalculatedType.INGREDIENT));
|
||||
}
|
||||
|
||||
private Set<RecipeId> findTopLevelRecipes(RecipeChainMath math, Set<RecipeId> collapsedRecipes) {
|
||||
final Set<RecipeId> result = new HashSet<>(math.outputRecipes.keySet());
|
||||
|
||||
for (BookmarkItem item : math.recipeResults) {
|
||||
if (!result.contains(item.recipeId)) {
|
||||
final Set<RecipeId> parents = getRecipeParents(
|
||||
math,
|
||||
item.recipeId,
|
||||
new HashSet<>(),
|
||||
new HashSet<>(Arrays.asList(item.recipeId)));
|
||||
|
||||
if (parents.size() != 1 || parents.stream().noneMatch(collapsedRecipes::contains)) {
|
||||
result.add(item.recipeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Set<RecipeId> getRecipeParents(RecipeChainMath math, RecipeId recipeId, Set<RecipeId> parents,
|
||||
Set<RecipeId> visited) {
|
||||
final Set<RecipeId> recipeIds = math.preferredItems.entrySet().stream()
|
||||
.filter(
|
||||
entry -> entry.getValue() != null && recipeId.equals(entry.getValue().recipeId)
|
||||
&& !visited.contains(entry.getKey().recipeId))
|
||||
.map(entry -> entry.getKey().recipeId).collect(Collectors.toSet());
|
||||
|
||||
visited.addAll(recipeIds);
|
||||
|
||||
if (recipeIds.isEmpty()) {
|
||||
parents.add(recipeId);
|
||||
} else {
|
||||
|
||||
for (RecipeId ingrRecipeId : recipeIds) {
|
||||
if (math.outputRecipes.containsKey(ingrRecipeId)) {
|
||||
parents.add(ingrRecipeId);
|
||||
} else {
|
||||
getRecipeParents(math, ingrRecipeId, parents, visited);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return parents;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package codechicken.nei.bookmark;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
|
||||
public class SortableGroup {
|
||||
|
||||
public int groupId;
|
||||
public BookmarkGrid grid;
|
||||
|
||||
public int shiftX = 0;
|
||||
public int shiftY = 0;
|
||||
|
||||
public SortableGroup(BookmarkGrid grid, int groupId) {
|
||||
this.grid = grid;
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public void postDraw(int mousex, int mousey) {
|
||||
Point startRect = null;
|
||||
|
||||
GuiContainerManager.drawItems.zLevel += 100;
|
||||
|
||||
for (BookmarksGridSlot slot : this.grid.getMask()) {
|
||||
if (slot.getGroupId() == this.groupId) {
|
||||
final Rectangle4i rect = this.grid.getSlotRect(slot.slotIndex);
|
||||
|
||||
if (startRect == null) {
|
||||
startRect = new Point(rect.x - this.shiftX, rect.y - this.shiftY);
|
||||
}
|
||||
|
||||
GuiContainerManager.drawItem(
|
||||
mousex + rect.x - startRect.x + 1,
|
||||
mousey + rect.y - startRect.y + 1,
|
||||
slot.getItemStack(),
|
||||
true,
|
||||
"");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (startRect != null) {
|
||||
int startRowIndex = -1;
|
||||
int endRowIndex = 0;
|
||||
|
||||
for (int rowIndex = 0; rowIndex < this.grid.getRows(); rowIndex++) {
|
||||
if (this.grid.getRowGroupId(rowIndex) == this.groupId) {
|
||||
|
||||
if (startRowIndex == -1) {
|
||||
startRowIndex = rowIndex;
|
||||
}
|
||||
|
||||
endRowIndex = rowIndex;
|
||||
}
|
||||
}
|
||||
|
||||
GL11.glPushMatrix();
|
||||
GL11.glTranslated(mousex - startRect.x, mousey - startRect.y, 0);
|
||||
this.grid.drawGroup(this.groupId, startRowIndex, endRowIndex);
|
||||
GL11.glPopMatrix();
|
||||
}
|
||||
|
||||
GuiContainerManager.drawItems.zLevel -= 100;
|
||||
}
|
||||
|
||||
public List<BookmarkItem> getBookmarkItems() {
|
||||
final List<BookmarkItem> items = new ArrayList<>();
|
||||
|
||||
for (BookmarkItem item : this.grid.bookmarkItems) {
|
||||
if (item.groupId == this.groupId) {
|
||||
items.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
package codechicken.nei.bookmark;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
|
||||
import codechicken.nei.ItemsGrid;
|
||||
import codechicken.nei.bookmark.RecipeChainDetails.BookmarkChainItem;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
|
||||
public class SortableItem {
|
||||
|
||||
public final BookmarkGrid grid;
|
||||
public final BookmarkItem bookmarkItem;
|
||||
public final boolean moveRecipe;
|
||||
public final boolean crossGroup;
|
||||
public final boolean isCollapsedRecipe;
|
||||
public List<Integer> items = new ArrayList<>();
|
||||
|
||||
public int shiftX = -8;
|
||||
public int shiftY = -8;
|
||||
|
||||
public SortableItem(BookmarkGrid grid, BookmarkItem bookmarkItem) {
|
||||
final BookmarkGroup group = grid.getGroup(bookmarkItem.groupId);
|
||||
|
||||
this.grid = grid;
|
||||
this.bookmarkItem = bookmarkItem.copy();
|
||||
this.moveRecipe = bookmarkItem.recipeId != null && !bookmarkItem.isIngredient
|
||||
&& (group.viewMode == BookmarkViewMode.TODO_LIST || group.crafting != null);
|
||||
this.crossGroup = !group.collapsed && group.viewMode == BookmarkViewMode.TODO_LIST
|
||||
&& !this.bookmarkItem.isIngredient;
|
||||
this.isCollapsedRecipe = group.crafting != null && group.crafting.itemToRecipe.values().stream()
|
||||
.anyMatch(recipeId -> this.bookmarkItem.equalsRecipe(recipeId, this.bookmarkItem.groupId));
|
||||
|
||||
this.update();
|
||||
}
|
||||
|
||||
public void postDraw(int mousex, int mousey) {
|
||||
Point startRect = null;
|
||||
|
||||
GuiContainerManager.drawItems.zLevel += 100;
|
||||
|
||||
for (Integer itemIndex : this.grid.getSortedItems()) {
|
||||
if (this.items.contains(itemIndex)) {
|
||||
final BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
|
||||
final int slotIndex = this.grid.gridGenerator.itemToSlot.get(itemIndex);
|
||||
final Rectangle4i rect = this.grid
|
||||
.getSlotRect(slotIndex % (this.grid.getRows() * this.grid.getColumns()));
|
||||
|
||||
if (startRect == null) {
|
||||
startRect = new Point(rect.x - this.shiftX, rect.y - this.shiftY);
|
||||
}
|
||||
|
||||
GuiContainerManager.drawItem(
|
||||
mousex + rect.x - startRect.x + 1,
|
||||
mousey + rect.y - startRect.y + 1,
|
||||
item.getItemStack(),
|
||||
true,
|
||||
"");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
GuiContainerManager.drawItems.zLevel -= 100;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
final BookmarkGroup group = this.grid.getGroup(this.bookmarkItem.groupId);
|
||||
|
||||
this.items.clear();
|
||||
|
||||
if (group.collapsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Map.Entry<Integer, BookmarkChainItem> entry : this.grid.gridGenerator.caclulatedItems.entrySet()) {
|
||||
if (containsItem(entry.getValue().getItem())) {
|
||||
this.items.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isCollapsedRecipe && group.crafting != null) {
|
||||
for (Map.Entry<Integer, RecipeId> entry : group.crafting.itemToRecipe.entrySet()) {
|
||||
if (this.bookmarkItem.equalsRecipe(entry.getValue(), this.bookmarkItem.groupId)) {
|
||||
this.items.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return this.items.isEmpty();
|
||||
}
|
||||
|
||||
public int getItemIndex() {
|
||||
return this.items.isEmpty() ? -1 : this.items.get(0);
|
||||
}
|
||||
|
||||
private boolean canInsert(BookmarkGroup group) {
|
||||
return group.viewMode == BookmarkViewMode.TODO_LIST && !group.collapsed;
|
||||
}
|
||||
|
||||
public void mouseDragged(int mousex, int mousey) {
|
||||
final BookmarkViewMode sortViewMode = this.grid.getViewMode(this.bookmarkItem.groupId);
|
||||
BookmarksGridSlot mouseOverSlot = this.grid.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (this.crossGroup) {
|
||||
final Rectangle4i topLeftSlot = this.grid.getSlotRect(0);
|
||||
mouseOverSlot = this.grid.getSlotMouseOver(topLeftSlot.x, mousey);
|
||||
|
||||
if (mouseOverSlot != null) {
|
||||
float ySlot = (float) (mousey - topLeftSlot.y) / ItemsGrid.SLOT_SIZE;
|
||||
int overRowIndex = (int) ySlot;
|
||||
int beforeGroupId = this.grid.getRowGroupId(overRowIndex - 1);
|
||||
int afterGroupId = this.grid.getRowGroupId(overRowIndex + 1);
|
||||
int overGroupId = mouseOverSlot.getGroupId();
|
||||
ySlot -= overRowIndex;
|
||||
|
||||
if (overGroupId == this.bookmarkItem.groupId && !this.items.contains(mouseOverSlot.itemIndex)) {
|
||||
this.grid.moveItem(this, mouseOverSlot.itemIndex);
|
||||
} else if (ySlot <= 0.25) {
|
||||
final BookmarkGroup group = this.grid.getGroup(beforeGroupId);
|
||||
|
||||
if (beforeGroupId != overGroupId && canInsert(group)
|
||||
&& !existsRecipe(this.bookmarkItem.recipeId, beforeGroupId)) {
|
||||
this.grid.moveItem(this, overRowIndex, beforeGroupId, false);
|
||||
}
|
||||
|
||||
} else if (ySlot > 0.25 && ySlot <= 0.5) {
|
||||
|
||||
if (beforeGroupId == overGroupId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (overGroupId != BookmarkGrid.DEFAULT_GROUP_ID
|
||||
&& beforeGroupId != BookmarkGrid.DEFAULT_GROUP_ID) {
|
||||
beforeGroupId = BookmarkGrid.DEFAULT_GROUP_ID;
|
||||
}
|
||||
|
||||
if (overGroupId == BookmarkGrid.DEFAULT_GROUP_ID && beforeGroupId != BookmarkGrid.DEFAULT_GROUP_ID
|
||||
&& afterGroupId != BookmarkGrid.DEFAULT_GROUP_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (canInsert(this.grid.getGroup(beforeGroupId))
|
||||
&& !existsRecipe(this.bookmarkItem.recipeId, beforeGroupId)) {
|
||||
this.grid.moveItem(this, overRowIndex, beforeGroupId, false);
|
||||
}
|
||||
|
||||
} else if (ySlot > 0.5 && ySlot < 0.75) {
|
||||
|
||||
if (afterGroupId == overGroupId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (overGroupId != BookmarkGrid.DEFAULT_GROUP_ID && afterGroupId != BookmarkGrid.DEFAULT_GROUP_ID) {
|
||||
afterGroupId = BookmarkGrid.DEFAULT_GROUP_ID;
|
||||
}
|
||||
|
||||
if (overGroupId == BookmarkGrid.DEFAULT_GROUP_ID && beforeGroupId != BookmarkGrid.DEFAULT_GROUP_ID
|
||||
&& afterGroupId != BookmarkGrid.DEFAULT_GROUP_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (canInsert(this.grid.getGroup(afterGroupId))
|
||||
&& !existsRecipe(this.bookmarkItem.recipeId, afterGroupId)) {
|
||||
this.grid.moveItem(this, overRowIndex, afterGroupId, true);
|
||||
}
|
||||
|
||||
} else if (ySlot >= 0.75) {
|
||||
final BookmarkGroup group = this.grid.getGroup(afterGroupId);
|
||||
|
||||
if (afterGroupId != overGroupId && canInsert(group)
|
||||
&& !existsRecipe(this.bookmarkItem.recipeId, afterGroupId)) {
|
||||
this.grid.moveItem(this, overRowIndex, afterGroupId, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
final int overRowIndex = this.grid.getHoveredRowIndex(false);
|
||||
final int overGroupId = this.grid.getRowGroupId(overRowIndex);
|
||||
|
||||
if (overRowIndex != -1 && overGroupId == this.bookmarkItem.groupId) {
|
||||
final int absoluteSlotIndex = ((this.grid.getPage() - 1) * this.grid.getRows() + overRowIndex)
|
||||
* this.grid.getColumns();
|
||||
|
||||
if (absoluteSlotIndex < this.grid.gridGenerator.itemToSlot.getOrDefault(getItemIndex(), -1)) {
|
||||
this.grid.moveItem(this, overRowIndex, overGroupId, true);
|
||||
} else {
|
||||
this.grid.moveItem(this, overRowIndex, overGroupId, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if (mouseOverSlot != null && !this.items.contains(mouseOverSlot.itemIndex)
|
||||
&& mouseOverSlot.getGroupId() == this.bookmarkItem.groupId
|
||||
&& (sortViewMode == BookmarkViewMode.DEFAULT || sortViewMode == BookmarkViewMode.TODO_LIST
|
||||
&& mouseOverSlot.getBookmarkItem().equalsRecipe(this.bookmarkItem))) {
|
||||
this.grid.moveItem(this, mouseOverSlot.itemIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean existsRecipe(RecipeId recipeId, int groupId) {
|
||||
if (recipeId == null) return false;
|
||||
|
||||
for (int itemIndex = 0; itemIndex < this.grid.bookmarkItems.size(); itemIndex++) {
|
||||
if (!this.items.contains(itemIndex)
|
||||
&& this.grid.bookmarkItems.get(itemIndex).equalsRecipe(recipeId, groupId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<BookmarkItem> getBookmarkItems() {
|
||||
final BookmarkGroup group = this.grid.getGroup(this.bookmarkItem.groupId);
|
||||
final List<BookmarkItem> items = new ArrayList<>();
|
||||
final List<RecipeId> recipeRelations = new ArrayList<>();
|
||||
|
||||
if (this.isCollapsedRecipe && group.crafting != null) {
|
||||
recipeRelations.addAll(
|
||||
group.crafting.recipeRelations.getOrDefault(this.bookmarkItem.recipeId, Collections.emptySet()));
|
||||
}
|
||||
|
||||
for (BookmarkItem item : this.grid.bookmarkItems) {
|
||||
if (containsItem(item)
|
||||
|| item.groupId == this.bookmarkItem.groupId && recipeRelations.contains(item.recipeId)) {
|
||||
items.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
public boolean containsItem(BookmarkItem slotItem) {
|
||||
return this.moveRecipe ? this.bookmarkItem.equalsRecipe(slotItem) : this.bookmarkItem.equals(slotItem);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package codechicken.nei.commands;
|
||||
|
||||
import net.minecraft.command.CommandBase;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.JsonToNBT;
|
||||
import net.minecraft.nbt.NBTException;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.ChatComponentText;
|
||||
import net.minecraft.util.ChatComponentTranslation;
|
||||
|
||||
import codechicken.nei.ItemPanels;
|
||||
|
||||
public class CommandBookmarkAdd extends CommandBase {
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return "nei_bookmark";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandUsage(ICommandSender sender) {
|
||||
return "/nei_bookmark <nbt>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRequiredPermissionLevel() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processCommand(ICommandSender sender, String[] args) {
|
||||
|
||||
if (args.length < 1 || args[0].length() < 3) {
|
||||
sender.addChatMessage(new ChatComponentText("§c/nei_bookmark <nbt>"));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ItemPanels.bookmarkPanel.addItem(
|
||||
ItemStack.loadItemStackFromNBT((NBTTagCompound) JsonToNBT.func_150315_a(String.join(" ", args))));
|
||||
sender.addChatMessage(new ChatComponentTranslation("nei.chat.bookmark_added.text"));
|
||||
} catch (NBTException e) {
|
||||
sender.addChatMessage(new ChatComponentText(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
package codechicken.nei.commands;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.command.CommandBase;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.ChatComponentTranslation;
|
||||
import net.minecraft.util.ChatStyle;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import codechicken.core.CommonUtils;
|
||||
import codechicken.nei.ClientHandler;
|
||||
import codechicken.nei.ItemList;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiRecipeTab;
|
||||
import codechicken.nei.recipe.ICraftingHandler;
|
||||
import codechicken.nei.recipe.Recipe;
|
||||
import codechicken.nei.recipe.RecipeHandlerQuery;
|
||||
import codechicken.nei.util.NBTJson;
|
||||
|
||||
public class CommandRecipeId extends CommandBase {
|
||||
|
||||
protected static class ProcessDiffThread extends Thread {
|
||||
|
||||
protected final ICommandSender sender;
|
||||
protected final File prevFile;
|
||||
protected final File currFile;
|
||||
protected final File diffFile;
|
||||
|
||||
public ProcessDiffThread(ICommandSender sender, File prevFile, File currFile, File diffFile) {
|
||||
this.sender = sender;
|
||||
this.prevFile = prevFile;
|
||||
this.currFile = currFile;
|
||||
this.diffFile = diffFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
sendChatInfoMessage(sender, "nei.chat.recipeid.diff.start");
|
||||
|
||||
final Set<String> prevRecipes = loadFileContent(this.prevFile);
|
||||
final Set<String> currRecipes = loadFileContent(this.currFile);
|
||||
final Set<String> notAllowedRecipes = prevRecipes.stream().filter(recipe -> !currRecipes.contains(recipe))
|
||||
.collect(Collectors.toCollection(TreeSet::new));
|
||||
final List<String> subsetsList = new ArrayList<>();
|
||||
|
||||
generateSubsets(notAllowedRecipes).forEach((handlerName, recipes) -> {
|
||||
subsetsList.add("; " + handlerName);
|
||||
subsetsList.addAll(recipes);
|
||||
});
|
||||
|
||||
saveFile(this.diffFile, subsetsList);
|
||||
saveFile(getFile("not-allowed-recipes"), new ArrayList<>(notAllowedRecipes));
|
||||
|
||||
sendChatInfoMessage(sender, "nei.chat.recipeid.diff.finish");
|
||||
}
|
||||
|
||||
private Set<String> loadFileContent(File file) {
|
||||
try (FileReader reader = new FileReader(file)) {
|
||||
return new HashSet<>(IOUtils.readLines(reader));
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to load '{}' file {}", file.getName(), file, e);
|
||||
}
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
private Map<String, Set<String>> generateSubsets(Set<String> notAllowedRecipes) {
|
||||
final JsonParser parser = new JsonParser();
|
||||
final Map<String, Set<String>> subsetsBuilder = new TreeMap<>();
|
||||
|
||||
for (String recipeStr : notAllowedRecipes) {
|
||||
try {
|
||||
final NBTTagCompound nbtRecipe = (NBTTagCompound) NBTJson.toNbt(parser.parse(recipeStr));
|
||||
|
||||
if (nbtRecipe.hasKey("result")) {
|
||||
final NBTTagCompound nbtStack = nbtRecipe.getCompoundTag("result");
|
||||
nbtStack.removeTag("Count");
|
||||
subsetsBuilder.computeIfAbsent(nbtRecipe.getString("handlerName"), rn -> new TreeSet<>())
|
||||
.add(NBTJson.toJson(nbtStack));
|
||||
} else {
|
||||
NEIClientConfig.logger.error("Found Broken RecipeId {}", recipeStr);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
NEIClientConfig.logger.error("Found Broken RecipeId {}", recipeStr, ex);
|
||||
}
|
||||
}
|
||||
|
||||
return subsetsBuilder;
|
||||
}
|
||||
|
||||
private void saveFile(File file, List<String> content) {
|
||||
try (FileOutputStream output = new FileOutputStream(file)) {
|
||||
IOUtils.writeLines(content, "\n", output, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to save recipeid diff list to file {}", file, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static class ProcessDumpThread extends Thread {
|
||||
|
||||
private ArrayList<ICraftingHandler> craftinghandlers = new ArrayList<>();
|
||||
private ArrayList<ICraftingHandler> serialCraftingHandlers = new ArrayList<>();
|
||||
protected final ICommandSender sender;
|
||||
protected final File currFile;
|
||||
|
||||
public ProcessDumpThread(ICommandSender sender, File currFile) {
|
||||
this.sender = sender;
|
||||
this.currFile = currFile;
|
||||
ClientHandler.loadSettingsFile("recipeidblacklist.cfg", lines -> {
|
||||
final Set<String> names = lines.collect(Collectors.toSet());
|
||||
|
||||
this.craftinghandlers = GuiCraftingRecipe.craftinghandlers.stream()
|
||||
.filter(h -> !names.contains(GuiRecipeTab.getHandlerInfo(h).getHandlerName()))
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
|
||||
this.serialCraftingHandlers = GuiCraftingRecipe.serialCraftingHandlers.stream()
|
||||
.filter(h -> !names.contains(GuiRecipeTab.getHandlerInfo(h).getHandlerName()))
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
NEIClientConfig.logger.info("Start processing recipe handlers!");
|
||||
sendChatInfoMessage(sender, "nei.chat.recipeid.dump.start");
|
||||
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(currFile.toPath(), StandardCharsets.UTF_8)) {
|
||||
int total = ItemList.items.size();
|
||||
int count = 0;
|
||||
|
||||
for (ItemStack stack : ItemList.items) {
|
||||
|
||||
if (count % 1000 == 0) {
|
||||
NEIClientConfig.logger.info(
|
||||
"({}/{}). Processing {} crafting recipes...",
|
||||
count,
|
||||
total,
|
||||
stack.getDisplayName());
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
for (ICraftingHandler handler : getCraftingHandlers(stack)) {
|
||||
for (int index = 0, num = handler.numRecipes(); index < num; index++) {
|
||||
try {
|
||||
final Recipe recipe = Recipe.of(handler, index);
|
||||
if (!recipe.getIngredients().isEmpty() && !recipe.getResults().isEmpty()) {
|
||||
writer.write(NBTJson.toJson(recipe.getRecipeId().toJsonObject()));
|
||||
writer.newLine();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
NEIClientConfig.logger.error(
|
||||
"Found Broken RecipeId {}:{}",
|
||||
GuiRecipeTab.getHandlerInfo(handler).getHandlerName(),
|
||||
stack,
|
||||
ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.error("Error dumping RecipeId", e);
|
||||
}
|
||||
|
||||
NEIClientConfig.logger.info("Finished processing recipe handlers!");
|
||||
sendChatInfoMessage(sender, "nei.chat.recipeid.dump.finish");
|
||||
}
|
||||
|
||||
private ArrayList<ICraftingHandler> getCraftingHandlers(Object... results) {
|
||||
return new RecipeHandlerQuery<>(
|
||||
h -> h.getRecipeHandler("item", results),
|
||||
this.craftinghandlers,
|
||||
this.serialCraftingHandlers,
|
||||
"Error while looking up crafting recipe",
|
||||
"outputId: item",
|
||||
"results: " + Arrays.toString(results))
|
||||
.runWithProfiling(NEIClientUtils.translate("recipe.concurrent.crafting"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return "recipeid";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandUsage(ICommandSender sender) {
|
||||
return "/recipeid dump <filename> OR /recipeid diff <prev-filename> <curr-filename> [subset name]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRequiredPermissionLevel() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processCommand(ICommandSender sender, String[] args) {
|
||||
final String command = args.length == 0 ? null : args[0];
|
||||
|
||||
if ("dump".equals(command)) {
|
||||
processDumpCommand(sender, args);
|
||||
} else if ("diff".equals(command)) {
|
||||
processDiffCommand(sender, args);
|
||||
} else {
|
||||
sendChatErrorMessage(sender, getCommandUsage(sender));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void processDiffCommand(ICommandSender sender, String[] args) {
|
||||
|
||||
if (args.length > 4) {
|
||||
sendChatErrorMessage(sender, "nei.chat.recipeid.many_params", getCommandUsage(sender));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length < 3) {
|
||||
sendChatErrorMessage(sender, getCommandUsage(sender));
|
||||
return;
|
||||
}
|
||||
|
||||
final File prevFilename = getFile(args[1]);
|
||||
final File currFilename = getFile(args[2]);
|
||||
final File diffFilename = getFile(args.length > 3 ? args[3] : "changelog");
|
||||
|
||||
if (!prevFilename.exists()) {
|
||||
sendChatErrorMessage(sender, "nei.chat.recipeid.not_found", prevFilename.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!currFilename.exists()) {
|
||||
sendChatErrorMessage(sender, "nei.chat.recipeid.not_found", currFilename.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
(new ProcessDiffThread(sender, prevFilename, currFilename, diffFilename)).start();
|
||||
}
|
||||
|
||||
protected void processDumpCommand(ICommandSender sender, String[] args) {
|
||||
|
||||
if (args.length > 2) {
|
||||
sendChatErrorMessage(sender, "nei.chat.recipeid.many_params", getCommandUsage(sender));
|
||||
return;
|
||||
}
|
||||
|
||||
final File dir = new File(CommonUtils.getMinecraftDir(), "recipeid");
|
||||
final String currFilename = args.length == 2 ? args[1] : "recipeId";
|
||||
if (!dir.exists()) dir.mkdirs();
|
||||
|
||||
(new ProcessDumpThread(sender, getFile(currFilename))).start();
|
||||
}
|
||||
|
||||
private static File getFile(String filename) {
|
||||
return new File(CommonUtils.getMinecraftDir(), "recipeid/" + filename + ".json");
|
||||
}
|
||||
|
||||
private static void sendChatInfoMessage(ICommandSender sender, String translationKey, Object... args) {
|
||||
sender.addChatMessage(
|
||||
new ChatComponentTranslation(translationKey, args)
|
||||
.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.AQUA)));
|
||||
}
|
||||
|
||||
private static void sendChatErrorMessage(ICommandSender sender, String translationKey, Object... args) {
|
||||
sender.addChatMessage(
|
||||
new ChatComponentTranslation(translationKey, args)
|
||||
.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.RED)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -113,8 +113,13 @@ public class GuiItemSorter extends GuiOptionPane {
|
||||
if (nslot != list.indexOf(dragged.e)) {
|
||||
list.remove(dragged.e);
|
||||
list.add(nslot, dragged.e);
|
||||
|
||||
opt.getTag().setValue(ItemSorter.getSaveString(list));
|
||||
if (opt.activeTag() == opt.getTag()) ItemSorter.list = new ArrayList<>(list);
|
||||
LayoutManager.markItemsDirty();
|
||||
|
||||
if (opt.activeTag() == opt.getTag()) {
|
||||
ItemSorter.list = new ArrayList<>(list);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package codechicken.nei.config;
|
||||
|
||||
import static codechicken.lib.gui.GuiDraw.getMousePosition;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
@@ -14,6 +12,7 @@ import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
|
||||
import codechicken.core.gui.GuiScreenWidget;
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.lib.render.CCRenderState;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.ItemPanels;
|
||||
@@ -114,8 +113,8 @@ public class GuiPanelSettings extends GuiScreenWidget {
|
||||
}
|
||||
|
||||
protected int[] getPaddings() {
|
||||
final int minWidth = 5 * ItemsGrid.SLOT_SIZE;
|
||||
final int minHeight = 9 * ItemsGrid.SLOT_SIZE;
|
||||
final int minWidth = ItemsGrid.SLOT_SIZE;
|
||||
final int minHeight = ItemsGrid.SLOT_SIZE;
|
||||
|
||||
int paddingLeft = (int) Math.ceil(margin.w * opt.renderTag(name + ".left").getIntValue() / 100000.0);
|
||||
int paddingTop = (int) Math.ceil(margin.h * opt.renderTag(name + ".top").getIntValue() / 100000.0);
|
||||
@@ -123,7 +122,7 @@ public class GuiPanelSettings extends GuiScreenWidget {
|
||||
int paddingBottom = (int) Math.ceil(margin.h * opt.renderTag(name + ".bottom").getIntValue() / 100000.0);
|
||||
|
||||
if (dragDir != null) {
|
||||
final Point mouse = getMousePosition();
|
||||
final Point mouse = GuiDraw.getMousePosition();
|
||||
Point drag = new Point(mouse.x - dragDown.x, mouse.y - dragDown.y);
|
||||
|
||||
if (dragDir == "left") {
|
||||
@@ -161,16 +160,15 @@ 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 ArrayList<ItemStack> items = ItemPanels.itemPanel.getItems();
|
||||
final List<ItemStack> items = ItemPanels.itemPanel.getItems();
|
||||
if (items.isEmpty()) return;
|
||||
|
||||
for (int r = 0; r < rows; r++) {
|
||||
for (int c = 0; c < columns; c++) {
|
||||
|
||||
GuiContainerManager.drawItem(
|
||||
drawItem(
|
||||
x + paddingLeft + ItemsGrid.SLOT_SIZE * c + 1,
|
||||
y + PANEL_SIZE + 2 + ItemsGrid.SLOT_SIZE * r + 1,
|
||||
items.get((r * columns + c) % items.size()));
|
||||
@@ -178,6 +176,21 @@ public class GuiPanelSettings extends GuiScreenWidget {
|
||||
}
|
||||
}
|
||||
|
||||
protected void drawItem(int x, int y, ItemStack stack) {
|
||||
final float scale = ItemsGrid.SLOT_SIZE / 18f;
|
||||
final float inverseScaleFactor = 1.0f / scale;
|
||||
final float shiftX = x * inverseScaleFactor;
|
||||
final float shiftY = y * inverseScaleFactor;
|
||||
|
||||
GL11.glScaled(scale, scale, 1);
|
||||
GL11.glTranslated(shiftX, shiftY, 0);
|
||||
|
||||
GuiContainerManager.drawItem(0, 0, stack, true, "");
|
||||
|
||||
GL11.glTranslated(-1 * shiftX, -1 * shiftY, 0);
|
||||
GL11.glScaled(inverseScaleFactor, inverseScaleFactor, 1);
|
||||
}
|
||||
|
||||
public boolean contains(int pointX, int pointY) {
|
||||
return (new Rectangle4i(x, y, w, h)).contains(pointX, pointY);
|
||||
}
|
||||
@@ -185,7 +198,7 @@ public class GuiPanelSettings extends GuiScreenWidget {
|
||||
protected void mouseClicked(int x, int y, int button) {
|
||||
|
||||
if (contains(x, y)) {
|
||||
dragDown = getMousePosition();
|
||||
dragDown = GuiDraw.getMousePosition();
|
||||
|
||||
if (leftButton.contains(x, y)) {
|
||||
dragDir = "left";
|
||||
|
||||
@@ -97,7 +97,7 @@ public class HandlerDumper extends DataDumper {
|
||||
}
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Filed to save dump handler list to file {}", file, e);
|
||||
NEIClientConfig.logger.error("Failed to save dump handler list to file {}", file, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 216 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user