mirror of
https://github.com/GTNewHorizons/NotEnoughItems.git
synced 2026-11-15 17:54:50 +00:00
Compare commits
256
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a533c8994 | ||
|
|
d70a47a3a4 | ||
|
|
6c3db443d7 | ||
|
|
a51836fe9b | ||
|
|
139ca22e51 | ||
|
|
10fc78bdcf | ||
|
|
5fb5ab6698 | ||
|
|
f47a8766a9 | ||
|
|
4cc72444d9 | ||
|
|
b48956ef94 | ||
|
|
583d28ed12 | ||
|
|
384813347c | ||
|
|
2b28068382 | ||
|
|
2c204c25aa | ||
|
|
5e6ff1d63b | ||
|
|
53ce50b35a | ||
|
|
835c4f7e01 | ||
|
|
f8c1f39faf | ||
|
|
4c4716e64f | ||
|
|
c84ac27a18 | ||
|
|
47baee272c | ||
|
|
f55dc716e3 | ||
|
|
26beb079f0 | ||
|
|
841b73c6fe | ||
|
|
0c7eeebb1f | ||
|
|
65b56735a7 | ||
|
|
ff428bf538 | ||
|
|
a406021f26 | ||
|
|
8500ac57eb | ||
|
|
d97123ec13 | ||
|
|
434931bfac | ||
|
|
860011036b | ||
|
|
937c1858a4 | ||
|
|
4562ecf087 | ||
|
|
d621d5d5bd | ||
|
|
3175b316af | ||
|
|
61930ac7a8 | ||
|
|
fcbf1dcade | ||
|
|
3fa69e826c | ||
|
|
31fff21a55 | ||
|
|
2e9ab88692 | ||
|
|
a02d293d44 | ||
|
|
1265113390 | ||
|
|
4ffd614017 | ||
|
|
41554f4c5b | ||
|
|
2104184077 | ||
|
|
d5f25a4be8 | ||
|
|
ccbf94790a | ||
|
|
2f4f72a2d6 | ||
|
|
f8cec9a78c | ||
|
|
fb43a662eb | ||
|
|
b2e0b8878a | ||
|
|
374f019103 | ||
|
|
5dfcff6f30 | ||
|
|
bd17301cb9 | ||
|
|
96ccd4e109 | ||
|
|
b30ca57e68 | ||
|
|
8f949bc1d1 | ||
|
|
d25365942a | ||
|
|
eb58e1dabc | ||
|
|
f4601e7eed | ||
|
|
ba48806667 | ||
|
|
70c332796a | ||
|
|
bcc25d4369 | ||
|
|
10a3109714 | ||
|
|
b60769864f | ||
|
|
6bc899769f | ||
|
|
0ba14091fb | ||
|
|
6ed0be7961 | ||
|
|
d40b951cce | ||
|
|
ecdf7892ce | ||
|
|
1eaaac94bc | ||
|
|
e99167dddb | ||
|
|
34cb0dc43f | ||
|
|
acaad4bf91 | ||
|
|
3de75f4e26 | ||
|
|
47497090ea | ||
|
|
8b45a1757f | ||
|
|
2782f8252e | ||
|
|
a5538b2566 | ||
|
|
a1f324b796 | ||
|
|
f3b6be26df | ||
|
|
9c764e3682 | ||
|
|
08605c3d73 | ||
|
|
9ec1e0f0cd | ||
|
|
e61151186c | ||
|
|
f7787a9a22 | ||
|
|
a91083bb5a | ||
|
|
51f830bdf6 | ||
|
|
9326ac48ad | ||
|
|
c125b71ae0 | ||
|
|
805b90d6f8 | ||
|
|
900b9f90e7 | ||
|
|
06d4a96c3a | ||
|
|
9a5a4a77ef | ||
|
|
4d874ec910 | ||
|
|
7f0f2466a5 | ||
|
|
83e1966ff2 | ||
|
|
548f754823 | ||
|
|
e036fd14a8 | ||
|
|
463f4c9b60 | ||
|
|
5070fde640 | ||
|
|
454b4f7e1d | ||
|
|
7b83456f01 | ||
|
|
4b7b84b031 | ||
|
|
75309b81ec | ||
|
|
24e46bb43e | ||
|
|
2ba0773401 | ||
|
|
eac913c80c | ||
|
|
126f0ea73c | ||
|
|
cd4668ec84 | ||
|
|
7c247dd0d2 | ||
|
|
87b549fab5 | ||
|
|
8ed1f7a043 | ||
|
|
f2efa35654 | ||
|
|
bcef287e71 | ||
|
|
7f555f7a7f | ||
|
|
9fd38da205 | ||
|
|
2fa5563408 | ||
|
|
541c0e2def | ||
|
|
ac868097e7 | ||
|
|
2f0de0b6a8 | ||
|
|
32bc29e654 | ||
|
|
ef8a7d8bd5 | ||
|
|
adc5a5df16 | ||
|
|
a828ff227a | ||
|
|
9b6f98330e | ||
|
|
667c8cb5b6 | ||
|
|
a186f69444 | ||
|
|
16f4f20239 | ||
|
|
bac207cacb | ||
|
|
630e856d83 | ||
|
|
42d96aed0c | ||
|
|
bd6384bf24 | ||
|
|
af9726d356 | ||
|
|
1e1d2f1076 | ||
|
|
7cb94fb22a | ||
|
|
87aa4f9ed5 | ||
|
|
9760fd3eaf | ||
|
|
1054871982 | ||
|
|
d90a667f68 | ||
|
|
69e6df5848 | ||
|
|
25fa7ce44e | ||
|
|
e3cd7b860d | ||
|
|
2a3aabc073 | ||
|
|
76db43c835 | ||
|
|
40e53eea7a | ||
|
|
6c4d16d6b9 | ||
|
|
4a2abe9fd7 | ||
|
|
d47417302e | ||
|
|
e13401ded8 | ||
|
|
7ada842ef3 | ||
|
|
fe0c5d4e50 | ||
|
|
2ea9ae1eb9 | ||
|
|
f7f0596fda | ||
|
|
d5e919a9cd | ||
|
|
a0ed5da699 | ||
|
|
99fb5a656e | ||
|
|
4b663222b1 | ||
|
|
3e5d0088bc | ||
|
|
948be399d2 | ||
|
|
5f6091924d | ||
|
|
c5bd1f897a | ||
|
|
61d4b6ab62 | ||
|
|
791d05d5f5 | ||
|
|
66001275c4 | ||
|
|
db6b83c906 | ||
|
|
58ef6c85e0 | ||
|
|
ab0aeef872 | ||
|
|
23b7c69e2f | ||
|
|
bb89384493 | ||
|
|
e96e4dfdde | ||
|
|
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 |
No files matched your search
@@ -0,0 +1,17 @@
|
||||
name: Optimize images
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master, main, release/** ]
|
||||
paths:
|
||||
- "**/*.png"
|
||||
|
||||
push:
|
||||
branches: [ master, main, release/** ]
|
||||
paths:
|
||||
- "**/*.png"
|
||||
|
||||
jobs:
|
||||
optimize-images:
|
||||
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/optimize-images.yml@master
|
||||
secrets: inherit
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
compileJava {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
generateGrammarSource {
|
||||
maxHeapSize = "128m"
|
||||
arguments += ['-package', 'codechicken.nei.search', '-visitor', '-no-listener']
|
||||
outputDirectory = file("${projectDir}/build/generated/sources/search/antlr/codechicken/nei/search/")
|
||||
}
|
||||
|
||||
compileJava.dependsOn generateGrammarSource
|
||||
sourcesJar.dependsOn generateGrammarSource
|
||||
|
||||
sourcesJar {
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java.srcDirs += ["build/generated/sources/search/antlr/"]
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events "passed", "skipped", "failed"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
//version: 1707058017
|
||||
|
||||
plugins {
|
||||
id 'antlr'
|
||||
id 'com.gtnewhorizons.gtnhconvention'
|
||||
}
|
||||
+31
-2
@@ -1,8 +1,37 @@
|
||||
// Add your dependencies here
|
||||
configurations.create('gtnhlibEmbed') {
|
||||
canBeConsumed = false
|
||||
canBeResolved = true
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api('com.github.GTNewHorizons:CodeChickenCore:1.4.1:dev')
|
||||
implementation('com.github.GTNewHorizons:GTNHLib:0.6.5:dev')
|
||||
api('com.github.GTNewHorizons:CodeChickenCore:1.4.17:dev')
|
||||
devOnlyNonPublishable('com.github.GTNewHorizons:GTNHLib:0.11.37:dev')
|
||||
|
||||
shadowImplementation('org.apache.commons:commons-csv:1.10.0')
|
||||
|
||||
compileOnly('maven.modrinth:forge-essentials:7.5.1')
|
||||
compileOnly('com.cardinalstar.cubicchunks:CubicChunks1710:v0.1.14-alpha:dev')
|
||||
|
||||
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");
|
||||
|
||||
compileOnly("com.github.GTNewHorizons:GTNHLib:0.11.37") { transitive = false }
|
||||
gtnhlibEmbed("com.github.GTNewHorizons:GTNHLib:0.11.37") { transitive = false }
|
||||
}
|
||||
|
||||
[tasks.jar, tasks.shadowJar].each {
|
||||
it.configure {
|
||||
from({ project.configurations.getByName('gtnhlibEmbed').collect { zipTree(it) } }) {
|
||||
include 'com/gtnewhorizon/gtnhlib/color/ColorResource.class'
|
||||
include 'com/gtnewhorizon/gtnhlib/color/ColorResource$*.class'
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
-6
@@ -14,7 +14,7 @@ modId = NotEnoughItems
|
||||
modGroup = codechicken.nei
|
||||
|
||||
# Whether to use modGroup as the maven publishing group.
|
||||
# Due to a history of using JitPack, the default is com.github.GTNewHorizons for all mods.
|
||||
# When false, com.github.GTNewHorizons is used.
|
||||
useModGroupForPublishing = false
|
||||
|
||||
# Updates your build.gradle and settings.gradle automatically whenever an update is available.
|
||||
@@ -39,9 +39,33 @@ remoteMappings = https\://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/co
|
||||
# `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE.
|
||||
developmentEnvironmentUserName = Developer
|
||||
|
||||
# Enables using modern Java syntax (up to version 17) via Jabel, while still targeting JVM 8.
|
||||
# See https://github.com/bsideup/jabel for details on how this works.
|
||||
enableModernJavaSyntax = true
|
||||
# Enables modern Java syntax support. Valid values:
|
||||
# - false: No modern syntax, Java 8 only
|
||||
# - jabel: Jabel syntax-only support, compiles to J8 bytecode
|
||||
# - jvmDowngrader: Full modern Java via JVM Downgrader (syntax + stdlib APIs)
|
||||
# - modern: Native modern Java bytecode, no downgrading
|
||||
enableModernJavaSyntax = jabel
|
||||
|
||||
# If set, ignores the above setting and compiles with the given toolchain. This may cause unexpected issues,
|
||||
# and should *not* be used in most situations. -1 disables this.
|
||||
# forceToolchainVersion = -1
|
||||
|
||||
# Target JVM version for JVM Downgrader bytecode downgrading.
|
||||
# Only used when enableModernJavaSyntax = jvmDowngrader
|
||||
# downgradeTargetVersion = 8
|
||||
|
||||
# Comma-separated list of Java versions for multi-release jar support (JVM Downgrader only).
|
||||
# Classes will be available in META-INF/versions/N/ for each version N in this list.
|
||||
# Default: "21,25" (J25+ gets native classes, J21-24 gets partial downgrade, J8-20 gets full downgrade).
|
||||
# jvmDowngraderMultiReleaseVersions = 21,25
|
||||
|
||||
# Specifies how JVM Downgrader API stubs are provided. Options:
|
||||
# - shade: Shade minimized stubs into the jar
|
||||
# - gtnhlib: GTNHLib provides stubs at runtime (adds version constraint)
|
||||
# - external: Another dependency provides stubs (no constraint, no warning)
|
||||
# - (empty): Warning reminding you to configure stubs
|
||||
# Note: 'shade' option requires you to verify license compliance, see: https://github.com/unimined/JvmDowngrader/blob/main/LICENSE.md
|
||||
# jvmDowngraderStubsProvider =
|
||||
|
||||
# Enables injecting missing generics into the decompiled source code for a better coding experience.
|
||||
# Turns most publicly visible List, Map, etc. into proper List<E>, Map<K, V> types.
|
||||
@@ -96,7 +120,9 @@ usesMixinDebug = false
|
||||
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
|
||||
mixinPlugin =
|
||||
|
||||
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
|
||||
# Specify the package that contains all of your Mixins. The package must exist or
|
||||
# the build will fail. If you have a package property defined in your mixins.<modid>.json,
|
||||
# it must match with this or the build will fail.
|
||||
mixinsPackage =
|
||||
|
||||
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
|
||||
@@ -151,7 +177,7 @@ modrinthProjectId = notenoughitems-unofficial
|
||||
# type can be one of [project, version],
|
||||
# and the name is the Modrinth project or version slug/id of the other mod.
|
||||
# Example: required-project:fplib;optional-project:gasstation;incompatible-project:gregtech
|
||||
# Note: GTNH Mixins is automatically set as a required dependency if usesMixins = true
|
||||
# Note: UniMixins is automatically set as a required dependency if usesMixins = true.
|
||||
modrinthRelations = required-project\:codechickencore-unofficial
|
||||
|
||||
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
|
||||
@@ -172,6 +198,12 @@ curseForgeRelations = requiredDependency\:codechickencore-unofficial
|
||||
# projects. New projects should not use this parameter.
|
||||
# customArchiveBaseName =
|
||||
|
||||
# Optional parameter to customize the default working directory used by the runClient* tasks. Relative to the project directory.
|
||||
# runClientWorkingDirectory = run/client
|
||||
|
||||
# Optional parameter to customize the default working directory used by the runServer* tasks. Relative to the project directory.
|
||||
# runServerWorkingDirectory = run/server
|
||||
|
||||
# Optional parameter to have the build automatically fail if an illegal version is used.
|
||||
# This can be useful if you e.g. only want to allow versions in the form of '1.1.xxx'.
|
||||
# The check is ONLY performed if the version is a git tag.
|
||||
@@ -201,3 +233,6 @@ curseForgeRelations = requiredDependency\:codechickencore-unofficial
|
||||
# This is meant to be set in $HOME/.gradle/gradle.properties.
|
||||
# ideaCheckSpotlessOnBuild = true
|
||||
|
||||
# Non-GTNH properties
|
||||
org.gradle.configuration-cache = true
|
||||
org.gradle.parallel = true
|
||||
@@ -0,0 +1,12 @@
|
||||
#This file is generated by updateDaemonJvm
|
||||
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/97d46b5ff4df0bf61e95652a190a5567/redirect
|
||||
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/9ef54a08e06b0754cee9fc95ed3a3134/redirect
|
||||
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/97d46b5ff4df0bf61e95652a190a5567/redirect
|
||||
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/9ef54a08e06b0754cee9fc95ed3a3134/redirect
|
||||
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/1df82b76031285ef2e6a4f59ffe9299d/redirect
|
||||
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/c7d5be6a02945ac2e045048ee54a7d32/redirect
|
||||
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/97d46b5ff4df0bf61e95652a190a5567/redirect
|
||||
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/9ef54a08e06b0754cee9fc95ed3a3134/redirect
|
||||
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/643f404f769811f5f265fd66f7af5d89/redirect
|
||||
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/38256085a73e137cb4937ea9c4807fec/redirect
|
||||
toolchainVersion=25
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
# Copyright © 2015 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -57,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -86,8 +86,7 @@ done
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
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
|
||||
@@ -115,7 +114,6 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@@ -173,7 +171,6 @@ fi
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
@@ -206,15 +203,14 @@ fi
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# * 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" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
||||
Vendored
+1
-2
@@ -70,11 +70,10 @@ goto fail
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
||||
+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"
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -17,7 +17,7 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.31'
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.29'
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
lexer grammar SearchExpressionLexer;
|
||||
|
||||
// Antlr4 generates imports with .*
|
||||
@header {
|
||||
// CHECKSTYLE:OFF
|
||||
import codechicken.nei.SearchTokenParser;
|
||||
}
|
||||
|
||||
@members {
|
||||
private SearchTokenParser searchParser;
|
||||
|
||||
public SearchExpressionLexer(CharStream input, SearchTokenParser searchParser) {
|
||||
this(input);
|
||||
this.searchParser = searchParser;
|
||||
}
|
||||
}
|
||||
|
||||
// Lexer rules
|
||||
REGEX_LEFT : 'r'? '/' -> pushMode(REGEX) ;
|
||||
QUOTE_LEFT : '"' -> pushMode(QUOTED) ;
|
||||
|
||||
DASH : '-' ;
|
||||
|
||||
RECIPE_INGREDIENTS : '<&' | '<' ;
|
||||
RECIPE_RESULT : '>&' | '>' ;
|
||||
RECIPE_OTHERS : '^&' | '^' ;
|
||||
|
||||
OR : '|' ;
|
||||
LEFT_BRACKET : '{' ;
|
||||
RIGHT_BRACKET : '}' ;
|
||||
NEWLINE_OR_TAB : [\t\r\n] -> skip ;
|
||||
SPACE : ' ' ;
|
||||
ESCAPED_SYMBOL : '\\' . ;
|
||||
|
||||
PREFIX : CLEAN_SYMBOL {searchParser.hasRedefinedPrefix(getText().charAt(0))}? ;
|
||||
CLEAN_SYMBOL : ~[-<>^{}|/\\ "] ;
|
||||
|
||||
mode REGEX;
|
||||
|
||||
REGEX_CONTENT : (~[/] | '\\/')+ ;
|
||||
REGEX_RIGHT : '/' -> popMode ;
|
||||
|
||||
mode QUOTED;
|
||||
|
||||
QUOTED_CONTENT : (~["] | '\\"')+ ;
|
||||
QUOTE_RIGHT : '"' -> popMode ;
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
parser grammar SearchExpressionParser;
|
||||
|
||||
// Antlr4 generates imports with .*
|
||||
@header {
|
||||
// CHECKSTYLE:OFF
|
||||
}
|
||||
|
||||
options { tokenVocab=SearchExpressionLexer; }
|
||||
|
||||
// Parser rules
|
||||
|
||||
// Should only be used for recipes. Thanks to antlr inability to properly
|
||||
// inherit grammars, this is included where it's not supposed to be
|
||||
recipeSearchExpression
|
||||
: recipeClauseExpression*
|
||||
;
|
||||
|
||||
recipeClauseExpression
|
||||
: ingredientsPrefix=RECIPE_INGREDIENTS searchExpression[0, $ingredientsPrefix.getText().length() > 1]
|
||||
| resultPrefix=RECIPE_RESULT searchExpression[1, $resultPrefix.getText().length() > 1]
|
||||
| othersPrefix=RECIPE_OTHERS searchExpression[2, $othersPrefix.getText().length() > 1]
|
||||
| searchExpression[3, false]
|
||||
;
|
||||
|
||||
// General search expression rules
|
||||
searchExpression[int type, boolean allRecipe]
|
||||
: orExpression
|
||||
;
|
||||
|
||||
orExpression
|
||||
: sequenceExpression (OR sequenceExpression)*
|
||||
;
|
||||
|
||||
sequenceExpression
|
||||
: (SPACE* unaryExpression SPACE*)+
|
||||
;
|
||||
|
||||
unaryExpression
|
||||
: LEFT_BRACKET orExpression RIGHT_BRACKET?
|
||||
| prefixedExpression
|
||||
| negateExpression
|
||||
| token['\0']
|
||||
;
|
||||
|
||||
negateExpression
|
||||
: DASH unaryExpression
|
||||
;
|
||||
|
||||
prefixedExpression
|
||||
locals [
|
||||
Character prefix
|
||||
]
|
||||
: prefixToken=PREFIX { $prefix = $prefixToken.getText().charAt(0); } token[$prefix]
|
||||
;
|
||||
|
||||
token[Character prefix]
|
||||
: regex[prefix]
|
||||
| quoted[prefix]
|
||||
| plainText
|
||||
;
|
||||
|
||||
regex[Character prefix]
|
||||
: REGEX_LEFT REGEX_CONTENT REGEX_RIGHT?
|
||||
;
|
||||
|
||||
quoted[Character prefix]
|
||||
: QUOTE_LEFT QUOTED_CONTENT QUOTE_RIGHT?
|
||||
;
|
||||
|
||||
plainText
|
||||
: (CLEAN_SYMBOL | ESCAPED_SYMBOL)+
|
||||
;
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.api.GuiInfo;
|
||||
import codechicken.nei.api.ShortcutInputHandler;
|
||||
import codechicken.nei.drawable.DrawableBuilder;
|
||||
import codechicken.nei.drawable.DrawableResource;
|
||||
import codechicken.nei.guihook.IContainerTooltipHandler;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
|
||||
public abstract class AbstractSubpanel<T extends ItemsGrid<? extends ItemsGridSlot, ? extends ItemsGrid.MouseContext>>
|
||||
extends Widget implements IContainerTooltipHandler {
|
||||
|
||||
final DrawableResource DASH = new DrawableBuilder("nei:textures/dash.png", 0, 0, 6, 1).setTextureSize(6, 1).build();
|
||||
|
||||
protected int mouseDownItemIndex = -1;
|
||||
protected int splittingLineColor = 0xffffffff;
|
||||
protected int linePaddingStart = 0;
|
||||
protected T grid;
|
||||
|
||||
public boolean isEmpty() {
|
||||
return this.grid.isEmpty();
|
||||
}
|
||||
|
||||
public void draw(int mousex, int mousey) {
|
||||
drawSplittingLine();
|
||||
this.grid.draw(mousex, mousey);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
this.grid.update();
|
||||
}
|
||||
|
||||
public abstract int setPanelWidth(int width);
|
||||
|
||||
public void resize(GuiContainer gui) {
|
||||
this.grid.setGridSize(x, y + 4, w, h - 8);
|
||||
this.grid.refresh(gui);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackMouseOver(int mousex, int mousey) {
|
||||
final ItemsGridSlot slot = getSlotMouseOver(mousex, mousey);
|
||||
return slot == null ? null : slot.getItemStack();
|
||||
}
|
||||
|
||||
public ItemsGridSlot getSlotMouseOver(int mousex, int mousey) {
|
||||
return this.grid.getSlotMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
protected void updateLinePadding() {
|
||||
GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
|
||||
this.linePaddingStart = 0;
|
||||
|
||||
while (GuiInfo
|
||||
.hideItemPanelSlot(guiContainer, new Rectangle4i(this.x + this.linePaddingStart, this.y - 1, 10, 2))) {
|
||||
this.linePaddingStart += 10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void drawSplittingLine() {
|
||||
float alpha = (this.splittingLineColor >> 24 & 255) / 255.0F;
|
||||
float red = (this.splittingLineColor >> 16 & 255) / 255.0F;
|
||||
float green = (this.splittingLineColor >> 8 & 255) / 255.0F;
|
||||
float blue = (this.splittingLineColor & 255) / 255.0F;
|
||||
|
||||
int width = this.grid.columns * ItemsGrid.SLOT_SIZE - this.linePaddingStart;
|
||||
int repeat = width / 6;
|
||||
int shiftX = this.x + this.linePaddingStart + (this.w - width) / 2;
|
||||
|
||||
GL11.glColor4f(red, green, blue, alpha);
|
||||
for (int i = 0; i < repeat; i++) {
|
||||
DASH.draw(shiftX + i * 6, this.y);
|
||||
}
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(int mousex, int mousey, int button, long heldTime) {
|
||||
|
||||
if (this.mouseDownItemIndex >= 0 && ItemPanels.itemPanel.draggedStack == null
|
||||
&& NEIClientUtils.getHeldItem() == null
|
||||
&& NEIClientConfig.hasSMPCounterPart()) {
|
||||
|
||||
final ItemsGridSlot mouseOverSlot = getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (mouseOverSlot == null || mouseOverSlot.itemIndex != this.mouseDownItemIndex || heldTime > 500) {
|
||||
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(
|
||||
this.grid.getItem(this.mouseDownItemIndex));
|
||||
this.mouseDownItemIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleClick(int mousex, int mousey, int button) {
|
||||
if (handleClickExt(mousex, mousey, button)) return true;
|
||||
|
||||
final ItemsGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
|
||||
if (hoverSlot != null) {
|
||||
|
||||
if (button == 2) {
|
||||
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(hoverSlot.getItemStack());
|
||||
} else {
|
||||
mouseDownItemIndex = hoverSlot.itemIndex;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected abstract ItemStack getDraggedStackWithQuantity(ItemStack itemStack);
|
||||
|
||||
public ItemStack getStackMouseOverWithQuantity(int mousex, int mousey) {
|
||||
final ItemStack hoverSlot = getStackMouseOver(mousex, mousey);
|
||||
return hoverSlot != null ? getDraggedStackWithQuantity(hoverSlot) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseUp(int mousex, int mousey, int button) {
|
||||
final ItemsGridSlot hoverSlot = getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (hoverSlot != null && hoverSlot.itemIndex == this.mouseDownItemIndex
|
||||
&& ItemPanels.itemPanel.draggedStack == null) {
|
||||
|
||||
if (NEIController.manager.window instanceof GuiRecipe || NEIClientUtils.shiftKey()
|
||||
|| !NEIClientConfig.canCheatItem(hoverSlot.getItemStack())) {
|
||||
ShortcutInputHandler.handleMouseClick(hoverSlot.getItemStack().copy());
|
||||
} else {
|
||||
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.getItemStack()), button, -1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.mouseDownItemIndex = -1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,319 +0,0 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
|
||||
import codechicken.nei.BookmarkPanel.ItemStackMetadata;
|
||||
import codechicken.nei.recipe.BookmarkRecipeId;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
|
||||
public class BookmarkCraftingChain {
|
||||
|
||||
public HashMap<ItemStack, ItemStack> calculatedItems = new HashMap<>();
|
||||
public HashMap<ItemStack, Integer> multiplier = new HashMap<>();
|
||||
|
||||
public HashMap<ItemStack, ItemStack> inputs = new HashMap<>();
|
||||
public HashMap<ItemStack, ItemStack> outputs = new HashMap<>();
|
||||
public HashMap<ItemStack, ItemStack> remainder = new HashMap<>();
|
||||
public HashMap<ItemStack, ItemStack> intermediate = new HashMap<>();
|
||||
|
||||
protected static class CraftingChainItem {
|
||||
|
||||
public String guid;
|
||||
public int stackIndex = 0;
|
||||
public int recipeIndex = 0;
|
||||
public int factor = 0;
|
||||
public int count = 0;
|
||||
public boolean ingredient = false;
|
||||
public int fluidCellAmount = 1;
|
||||
public ItemStack stack = null;
|
||||
|
||||
public CraftingChainItem(ItemStack stack, ItemStackMetadata stackMetadata) {
|
||||
FluidStack fluid = StackInfo.getFluid(stack);
|
||||
this.recipeIndex = getRecipeIndex(stackMetadata.recipeId);
|
||||
this.ingredient = stackMetadata.ingredient;
|
||||
this.stack = stack;
|
||||
|
||||
if (fluid != null) {
|
||||
this.stackIndex = getStackIndex(fluid);
|
||||
this.count = fluid.amount * Math.max(0, stack.stackSize);
|
||||
this.fluidCellAmount = StackInfo.isFluidContainer(stack) ? fluid.amount : 1;
|
||||
this.factor = this.fluidCellAmount * stackMetadata.factor;
|
||||
} else {
|
||||
this.stackIndex = getStackIndex(stack);
|
||||
this.count = StackInfo.itemStackToNBT(stack).getInteger("Count");
|
||||
this.factor = stackMetadata.factor;
|
||||
}
|
||||
|
||||
this.guid = this.stackIndex + " " + this.recipeIndex;
|
||||
}
|
||||
|
||||
public ItemStack getItemStack(long count) {
|
||||
return StackInfo.loadFromNBT(
|
||||
StackInfo.itemStackToNBT(this.stack),
|
||||
this.factor > 0 ? (count / this.fluidCellAmount) : 0);
|
||||
}
|
||||
|
||||
public static void clearStatic() {
|
||||
itemCache.clear();
|
||||
fluidCache.clear();
|
||||
recipeCache.clear();
|
||||
}
|
||||
|
||||
private static HashMap<ItemStack, Integer> itemCache = new HashMap<>();
|
||||
|
||||
private static int getStackIndex(ItemStack stackA) {
|
||||
|
||||
if (!itemCache.containsKey(stackA)) {
|
||||
|
||||
for (ItemStack item : itemCache.keySet()) {
|
||||
if (StackInfo.equalItemAndNBT(stackA, item, true)) {
|
||||
itemCache.put(stackA, itemCache.get(item));
|
||||
return itemCache.get(stackA);
|
||||
}
|
||||
}
|
||||
|
||||
itemCache.put(stackA, itemCache.size() + fluidCache.size());
|
||||
}
|
||||
|
||||
return itemCache.get(stackA);
|
||||
}
|
||||
|
||||
private static HashMap<FluidStack, Integer> fluidCache = new HashMap<>();
|
||||
|
||||
private static int getStackIndex(FluidStack fluidA) {
|
||||
|
||||
if (!fluidCache.containsKey(fluidA)) {
|
||||
for (FluidStack item : fluidCache.keySet()) {
|
||||
if (fluidA.isFluidEqual(item)) {
|
||||
fluidCache.put(fluidA, fluidCache.get(item));
|
||||
return fluidCache.get(fluidA);
|
||||
}
|
||||
}
|
||||
|
||||
fluidCache.put(fluidA, itemCache.size() + fluidCache.size());
|
||||
}
|
||||
|
||||
return fluidCache.get(fluidA);
|
||||
}
|
||||
|
||||
private static HashMap<BookmarkRecipeId, Integer> recipeCache = new HashMap<>();
|
||||
|
||||
private static int getRecipeIndex(BookmarkRecipeId recipe) {
|
||||
|
||||
if (recipe == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!recipeCache.containsKey(recipe)) {
|
||||
for (BookmarkRecipeId item : recipeCache.keySet()) {
|
||||
if (item.equals(recipe)) {
|
||||
recipeCache.put(recipe, recipeCache.get(item));
|
||||
return recipeCache.get(recipe);
|
||||
}
|
||||
}
|
||||
|
||||
recipeCache.put(recipe, recipeCache.size());
|
||||
}
|
||||
|
||||
return recipeCache.get(recipe);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static class CraftingChainRequest {
|
||||
|
||||
public List<CraftingChainItem> items = new ArrayList<>();
|
||||
|
||||
public HashMap<Integer, Integer> multiplier = new HashMap<>();
|
||||
public HashMap<String, Long> counts = new HashMap<>();
|
||||
|
||||
public HashMap<Integer, HashSet<CraftingChainItem>> inputs = new HashMap<>();
|
||||
public HashMap<Integer, HashSet<CraftingChainItem>> outputs = new HashMap<>();
|
||||
|
||||
public HashSet<Integer> initialItems = new HashSet<>();
|
||||
public HashSet<Integer> startedIngrs = new HashSet<>();
|
||||
|
||||
public CraftingChainRequest(List<ItemStack> items, List<ItemStackMetadata> metadata) {
|
||||
HashSet<Integer> inputs = new HashSet<>();
|
||||
HashSet<Integer> outputs = new HashSet<>();
|
||||
|
||||
for (int index = 0; index < items.size(); index++) {
|
||||
CraftingChainItem item = new CraftingChainItem(items.get(index), metadata.get(index));
|
||||
item.guid = item.ingredient ? "i" + item.guid : "r" + item.guid;
|
||||
this.items.add(item);
|
||||
|
||||
if (this.multiplier.get(item.recipeIndex) == null) {
|
||||
this.multiplier.put(item.recipeIndex, 0);
|
||||
}
|
||||
|
||||
this.counts.put(item.guid, this.counts.getOrDefault(item.guid, 0L) + item.count);
|
||||
|
||||
if (item.ingredient) {
|
||||
inputs.add(item.recipeIndex);
|
||||
|
||||
if (this.inputs.get(item.stackIndex) == null) {
|
||||
this.inputs.put(item.stackIndex, new HashSet<>());
|
||||
}
|
||||
|
||||
this.inputs.get(item.stackIndex).add(item);
|
||||
} else {
|
||||
outputs.add(item.recipeIndex);
|
||||
|
||||
if (this.outputs.get(item.stackIndex) == null) {
|
||||
this.outputs.put(item.stackIndex, new HashSet<>());
|
||||
}
|
||||
|
||||
this.outputs.get(item.stackIndex).add(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (int recipeIndex : this.multiplier.keySet()) {
|
||||
if (recipeIndex == -1 || !inputs.contains(recipeIndex) || !outputs.contains(recipeIndex)) {
|
||||
this.initialItems.add(recipeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
for (CraftingChainItem item : this.items) {
|
||||
if (item.ingredient == false && !this.initialItems.contains(item.recipeIndex)) {
|
||||
this.startedIngrs.add(item.stackIndex);
|
||||
}
|
||||
}
|
||||
|
||||
CraftingChainItem.clearStatic();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void refresh(List<ItemStack> items, List<ItemStackMetadata> metadata) {
|
||||
CraftingChainRequest request = new CraftingChainRequest(items, metadata);
|
||||
HashMap<Integer, Long> iShift = new HashMap<>();
|
||||
HashMap<Integer, Long> oShift = new HashMap<>();
|
||||
boolean change = true;
|
||||
int iteration = 100;
|
||||
|
||||
while (--iteration > 0 && change) {
|
||||
change = false;
|
||||
for (int stackIndex : request.startedIngrs) {
|
||||
change = calculateShift(request, stackIndex) || change;
|
||||
}
|
||||
}
|
||||
|
||||
this.inputs.clear();
|
||||
this.outputs.clear();
|
||||
this.remainder.clear();
|
||||
this.intermediate.clear();
|
||||
this.calculatedItems.clear();
|
||||
this.multiplier.clear();
|
||||
|
||||
for (CraftingChainItem item : request.items) {
|
||||
if (request.initialItems.contains(item.recipeIndex)) {
|
||||
long iCount = calculateCount(request, request.inputs.get(item.stackIndex))
|
||||
- iShift.getOrDefault(item.stackIndex, 0L);
|
||||
this.calculatedItems.put(item.stack, item.stack);
|
||||
|
||||
if (iCount == 0) {
|
||||
this.inputs.put(item.stack, item.getItemStack(0));
|
||||
} else {
|
||||
long count = Math.min(iCount, item.count);
|
||||
this.inputs.put(item.stack, item.getItemStack(count));
|
||||
iShift.put(item.stackIndex, iShift.getOrDefault(item.stackIndex, 0L) + count);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (CraftingChainItem item : request.items) {
|
||||
if (!request.initialItems.contains(item.recipeIndex)) {
|
||||
long count = item.count + item.factor * request.multiplier.get(item.recipeIndex);
|
||||
this.calculatedItems.put(item.stack, item.getItemStack(count));
|
||||
|
||||
if (item.ingredient) { // input
|
||||
long oCount = calculateCount(request, request.outputs.get(item.stackIndex))
|
||||
- oShift.getOrDefault(item.stackIndex, 0L);
|
||||
|
||||
if (oCount < count) {
|
||||
this.inputs.put(item.stack, item.getItemStack(count - oCount));
|
||||
oShift.put(item.stackIndex, oShift.getOrDefault(item.stackIndex, 0L) + oCount);
|
||||
} else if (oCount >= count) {
|
||||
this.intermediate.put(item.stack, item.getItemStack(0));
|
||||
oShift.put(item.stackIndex, oShift.getOrDefault(item.stackIndex, 0L) + count);
|
||||
}
|
||||
|
||||
} else { // output
|
||||
long iCalcCount = calculateCount(request, request.inputs.get(item.stackIndex));
|
||||
long iCount = iCalcCount - iShift.getOrDefault(item.stackIndex, 0L);
|
||||
this.multiplier.put(item.stack, item.factor > 0 ? (int) (count / item.factor) : 0);
|
||||
|
||||
if (iCount >= count) {
|
||||
this.intermediate.put(item.stack, item.getItemStack(0));
|
||||
iShift.put(item.stackIndex, iShift.getOrDefault(item.stackIndex, 0L) + count);
|
||||
} else if (iCalcCount > 0) {
|
||||
this.remainder.put(item.stack, item.getItemStack(count - iCount));
|
||||
iShift.put(item.stackIndex, iShift.getOrDefault(item.stackIndex, 0L) + iCount);
|
||||
} else {
|
||||
this.outputs.put(item.stack, item.getItemStack(count - iCount));
|
||||
iShift.put(item.stackIndex, iShift.getOrDefault(item.stackIndex, 0L) + iCount);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean calculateShift(CraftingChainRequest request, int stackIndex) {
|
||||
|
||||
if (!request.outputs.containsKey(stackIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int minRecipeIndex = 0;
|
||||
int minShift = Integer.MAX_VALUE;
|
||||
|
||||
for (CraftingChainItem item : request.outputs.get(stackIndex)) {
|
||||
if (!request.initialItems.contains(item.recipeIndex) && item.factor > 0) {
|
||||
long ingrCount = calculateCount(request, request.inputs.get(item.stackIndex), item.recipeIndex);
|
||||
long outputCount = calculateCount(request, request.outputs.get(item.stackIndex));
|
||||
long shift = (long) Math.ceil((ingrCount - outputCount) / (double) item.factor);
|
||||
|
||||
if (shift > 0 && shift < minShift) {
|
||||
minShift = (int) shift;
|
||||
minRecipeIndex = item.recipeIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minShift < Integer.MAX_VALUE) {
|
||||
request.multiplier.put(minRecipeIndex, request.multiplier.get(minRecipeIndex) + minShift);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private long calculateCount(CraftingChainRequest request, HashSet<CraftingChainItem> items) {
|
||||
return calculateCount(request, items, -1);
|
||||
}
|
||||
|
||||
private long calculateCount(CraftingChainRequest request, HashSet<CraftingChainItem> items, int recipeIndex) {
|
||||
long count = 0L;
|
||||
|
||||
if (items != null) {
|
||||
for (CraftingChainItem item : items) {
|
||||
if (item.recipeIndex != recipeIndex || recipeIndex == -1) {
|
||||
count += request.counts.get(item.guid) + item.factor * request.multiplier.get(item.recipeIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||
@@ -57,6 +57,10 @@ public abstract class Button extends Widget {
|
||||
return label;
|
||||
}
|
||||
|
||||
public int getRenderLabelColor() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public final String label;
|
||||
public Image icon;
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -19,13 +22,17 @@ 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.gui.inventory.GuiContainer;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.GuiOpenEvent;
|
||||
import net.minecraftforge.client.event.RenderWorldLastEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
@@ -36,9 +43,9 @@ 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.GuiInfo;
|
||||
import codechicken.nei.api.IConfigureNEI;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
@@ -46,6 +53,9 @@ 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;
|
||||
@@ -57,7 +67,6 @@ public class ClientHandler {
|
||||
private static ClientHandler instance;
|
||||
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,6 +153,8 @@ public class ClientHandler {
|
||||
loadHeightHackHandlers();
|
||||
loadHiddenHandlers();
|
||||
loadEnableAutoFocus();
|
||||
loadGuiCraftablesBlacklist();
|
||||
loadDefaultBookmarkContainers();
|
||||
ItemInfo.preInit();
|
||||
StackInfo.loadGuidFilters();
|
||||
}
|
||||
@@ -161,11 +172,34 @@ public class ClientHandler {
|
||||
}, callback);
|
||||
}
|
||||
|
||||
public static void loadSettingsFile(String resource, BiConsumer<File, FileWriter> createDefault,
|
||||
public static boolean loadSettingsResource(String resource, Consumer<Stream<String>> callback) {
|
||||
final ResourceLocation location = new ResourceLocation("nei", resource);
|
||||
|
||||
try {
|
||||
final IResource res = Minecraft.getMinecraft().getResourceManager().getResource(location);
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(res.getInputStream(), StandardCharsets.UTF_8))) {
|
||||
NEIClientConfig.logger.info("Loading '{}' from jar {}", resource, location);
|
||||
callback.accept(
|
||||
IOUtils.readLines(reader).stream()
|
||||
.map(line -> line.contains("#") ? line.substring(0, line.indexOf('#')) : line)
|
||||
.map(String::trim).filter(line -> !line.isEmpty()));
|
||||
return true;
|
||||
}
|
||||
|
||||
} catch (Exception io) {
|
||||
NEIClientConfig.logger.error("Failed to load '{}' file {}", resource, location);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean loadSettingsFile(String resource, BiConsumer<File, FileWriter> createDefault,
|
||||
Consumer<Stream<String>> callback) {
|
||||
File file = new File(NEIClientConfig.configDir, resource);
|
||||
|
||||
if (!file.exists()) {
|
||||
if (!file.exists() && createDefault != null) {
|
||||
try (FileWriter writer = new FileWriter(file)) {
|
||||
NEIClientConfig.logger.info("Creating default '{}' {}", resource, file);
|
||||
createDefault.accept(file, writer);
|
||||
@@ -174,13 +208,20 @@ public class ClientHandler {
|
||||
}
|
||||
}
|
||||
|
||||
try (FileReader reader = new FileReader(file)) {
|
||||
NEIClientConfig.logger.info("Loading '{}' file {}", resource, file);
|
||||
callback.accept(
|
||||
IOUtils.readLines(reader).stream().filter(line -> !line.startsWith("#") && !line.trim().isEmpty()));
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to load '{}' file {}", resource, file, e);
|
||||
if (file.exists()) {
|
||||
try (FileReader reader = new FileReader(file)) {
|
||||
NEIClientConfig.logger.info("Loading '{}' file {}", resource, file);
|
||||
callback.accept(
|
||||
IOUtils.readLines(reader).stream()
|
||||
.map(line -> line.contains("#") ? line.substring(0, line.indexOf('#')) : line)
|
||||
.map(String::trim).filter(line -> !line.isEmpty()));
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to load '{}' file {}", resource, file, e);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void loadSerialHandlers() {
|
||||
@@ -205,8 +246,27 @@ public class ClientHandler {
|
||||
public static void loadEnableAutoFocus() {
|
||||
loadSettingsFile(
|
||||
"enableautofocus.cfg",
|
||||
lines -> AutoFocusWidget.enableAutoFocusPrefixes = lines
|
||||
.collect(Collectors.toCollection(ArrayList::new)));
|
||||
lines -> AutoFocusWidget.enableAutoFocusPrefixes = lines.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public static void loadGuiCraftablesBlacklist() {
|
||||
loadSettingsFile(
|
||||
"guicraftablesblacklist.cfg",
|
||||
lines -> ItemCraftablesPanel.guiBlacklist = lines.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public static void loadDefaultBookmarkContainers() {
|
||||
loadSettingsFile("defaultbookmarkcontainers.cfg", lines -> {
|
||||
for (String clazz : lines.collect(Collectors.toList())) {
|
||||
try {
|
||||
API.registerBookmarkContainerHandler(
|
||||
(Class<? extends GuiContainer>) Class.forName(clazz),
|
||||
new DefaultBookmarkContainerHandler());
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.error("Failed to load class '{}' for defaultbookmarkcontainers.cfg", clazz);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void loadHiddenItems() {
|
||||
@@ -216,7 +276,6 @@ public class ClientHandler {
|
||||
public static void load() {
|
||||
instance = new ClientHandler();
|
||||
|
||||
GuiModListScroll.register("NotEnoughItems");
|
||||
PacketCustom.assignHandler(NEICPH.channel, new NEICPH());
|
||||
FMLCommonHandler.instance().bus().register(instance);
|
||||
MinecraftForge.EVENT_BUS.register(instance);
|
||||
@@ -254,11 +313,34 @@ public class ClientHandler {
|
||||
}
|
||||
|
||||
public static void loadPluginsList() {
|
||||
final ClassDiscoverer classDiscoverer = new ClassDiscoverer(
|
||||
test -> test.startsWith("NEI") && test.endsWith("Config.class"),
|
||||
IConfigureNEI.class);
|
||||
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);
|
||||
|
||||
NEIClientConfig.pluginsList.addAll(classDiscoverer.findClasses());
|
||||
NEIClientConfig.pluginsList.addAll(classDiscoverer.findClasses());
|
||||
NEIClientConfig.logger
|
||||
.info("Loading NEI Plugins via ClassDiscoverer: " + NEIClientConfig.pluginsList.size());
|
||||
|
||||
} 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 {
|
||||
NEIClientConfig.pluginsList.add(Class.forName(className, true, modClassLoader));
|
||||
} catch (ClassNotFoundException e) {
|
||||
NEIClientConfig.logger.error("Failed to load plugin class {}", className, e);
|
||||
}
|
||||
}
|
||||
NEIClientConfig.logger.info("Loading NEI Plugins via JarJar: " + NEIClientConfig.pluginsList.size());
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@@ -281,18 +363,20 @@ 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;
|
||||
GuiInfo.clearGuiHandlers();
|
||||
}
|
||||
lastGui = gui;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@@ -311,14 +395,16 @@ public class ClientHandler {
|
||||
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);
|
||||
@@ -326,8 +412,6 @@ public class ClientHandler {
|
||||
if (!Minecraft.getMinecraft().isSingleplayer()) // wait for server to initiate in singleplayer
|
||||
NEIClientConfig.loadWorld("remote/" + ClientUtils.getServerIP().replace(':', '~'));
|
||||
}
|
||||
ItemMobSpawner.clearEntityReferences(world);
|
||||
|
||||
lastworld = world;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ public class CollapsibleItems {
|
||||
group.setFilter(itemStr);
|
||||
}
|
||||
|
||||
if (group != null && group.filter != null) {
|
||||
if (group.filter != null) {
|
||||
addGroup(group);
|
||||
group = new GroupItem();
|
||||
}
|
||||
@@ -150,10 +150,16 @@ public class CollapsibleItems {
|
||||
}
|
||||
|
||||
public static void putItem(ItemStack stack) {
|
||||
final GroupItem group = CollapsibleItems.groups.stream().filter(g -> g.matches(stack)).findFirst().orElse(null);
|
||||
int groupIndex = -1;
|
||||
|
||||
if (group != null) {
|
||||
CollapsibleItems.cache.put(stack, CollapsibleItems.groups.indexOf(group));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.color.ColorResource;
|
||||
|
||||
public class ColorUtils {
|
||||
|
||||
private static final ColorResource.Factory color = new ColorResource.Factory("nei");
|
||||
|
||||
public static final ColorResource
|
||||
// spotless:off
|
||||
textGray = color.rgb("textGray", "0x404040"),
|
||||
textLightGray = color.rgb("textLightGray", "0x606060"),
|
||||
recipeTitle = color.rgb("recipeTitle", "0xFFFFFF"),
|
||||
recipeTitleHover = color.rgb("recipeTitleHover", "0xFFFF55"),
|
||||
subsetWidget = color.rgb("subsetWidget", "0xAA00AA"),
|
||||
recipeBadge = color.rgb("recipeBadge", "0xFDD835"),
|
||||
buttonLabelNormal = color.rgb("buttonLabelNormal", "0xE0E0E0"),
|
||||
buttonLabelHover = color.rgb("buttonLabelHover", "0xFFFFA0"),
|
||||
buttonLabelDisabled = color.rgb("buttonLabelDisabled", "0x601010"),
|
||||
buttonLabelInactive = color.rgb("buttonLabelInactive", "0xA0A0A0");
|
||||
// spotless:on
|
||||
}
|
||||
@@ -79,14 +79,13 @@ public class ContainerCreativeInv extends Container {
|
||||
@Override
|
||||
public ItemStack transferStackInSlot(EntityPlayer par1EntityPlayer, int slotIndex) {
|
||||
ItemStack transferredStack = null;
|
||||
Slot slot = (Slot) inventorySlots.get(slotIndex);
|
||||
Slot slot = inventorySlots.get(slotIndex);
|
||||
|
||||
if (slot != null && slot.getHasStack()) {
|
||||
ItemStack stack = slot.getStack();
|
||||
transferredStack = stack.copy();
|
||||
|
||||
if (stack.getItem() instanceof ItemArmor) {
|
||||
ItemArmor armor = (ItemArmor) stack.getItem();
|
||||
if (stack.getItem() instanceof ItemArmor armor) {
|
||||
if (!getSlot(90 + armor.armorType).getHasStack()) {
|
||||
getSlot(90 + armor.armorType).putStack(transferredStack);
|
||||
slot.putStack(null);
|
||||
|
||||
@@ -8,7 +8,6 @@ import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.inventory.ContainerEnchantment;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
@@ -164,14 +163,14 @@ public class ContainerEnchantmentModifier extends ContainerEnchantment {
|
||||
|
||||
public boolean addEnchantment(int e, int level) {
|
||||
if (e < Enchantment.enchantmentsList.length && Enchantment.enchantmentsList[e] != null) {
|
||||
((Slot) inventorySlots.get(0)).getStack().addEnchantment(Enchantment.enchantmentsList[e], level);
|
||||
inventorySlots.get(0).getStack().addEnchantment(Enchantment.enchantmentsList[e], level);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void removeEnchantment(int e) {
|
||||
ItemStack stack = ((Slot) inventorySlots.get(0)).getStack();
|
||||
ItemStack stack = inventorySlots.get(0).getStack();
|
||||
NBTTagList nbttaglist = stack.getEnchantmentTagList();
|
||||
if (nbttaglist != null) {
|
||||
for (int i = 0; i < nbttaglist.tagCount(); i++) {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.nei.api.IBookmarkContainerHandler;
|
||||
@@ -12,36 +13,18 @@ public class DefaultBookmarkContainerHandler implements IBookmarkContainerHandle
|
||||
|
||||
@Override
|
||||
public void pullBookmarkItemsFromContainer(GuiContainer guiContainer, ArrayList<ItemStack> bookmarkItems) {
|
||||
FastTransferManager manager = new FastTransferManager();
|
||||
LinkedList<ItemStack> containerStacks = manager.saveContainer(guiContainer.inventorySlots);
|
||||
final List<Slot> slots = guiContainer.inventorySlots.inventorySlots;
|
||||
final FastTransferManager manager = new FastTransferManager();
|
||||
|
||||
for (ItemStack bookmarkItem : bookmarkItems) {
|
||||
|
||||
int bookmarkSizeBackup = bookmarkItem.stackSize;
|
||||
|
||||
for (int i = 0; i < containerStacks.size() - 4 * 9; i++) { // Last 36 slots are player inventory
|
||||
ItemStack containerItem = containerStacks.get(i);
|
||||
|
||||
if (containerItem == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bookmarkItem.isItemEqual(containerItem)) {
|
||||
if (bookmarkItem.stackSize <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
int transferAmount = Math.min(bookmarkItem.stackSize, containerItem.stackSize);
|
||||
|
||||
for (int i = 0; i < slots.size() - 4 * 9; i++) {
|
||||
final Slot slot = slots.get(i);
|
||||
if (slot.getHasStack() && bookmarkItem.isItemEqual(slot.getStack())) {
|
||||
final int transferAmount = Math.min(bookmarkItem.stackSize, slot.getStack().stackSize);
|
||||
manager.transferItems(guiContainer, i, transferAmount);
|
||||
bookmarkItem.stackSize -= transferAmount;
|
||||
|
||||
if (bookmarkItem.stackSize == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bookmarkItem.stackSize = bookmarkSizeBackup;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ public class DefaultHighlightHandler implements IHighlightHandler {
|
||||
String name = null;
|
||||
try {
|
||||
String s = GuiContainerManager.itemDisplayNameShort(stack);
|
||||
if (s != null && !s.endsWith("Unnamed")) name = s;
|
||||
if (!s.endsWith("Unnamed")) name = s;
|
||||
|
||||
if (name != null) currenttip.add(name);
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
|
||||
public class DoubleFilteredFilter implements ItemFilter {
|
||||
|
||||
private ItemFilter filter;
|
||||
private ItemList.PatternItemFilter patternFilter;
|
||||
|
||||
public DoubleFilteredFilter(ItemFilter filter, String itemFilter) {
|
||||
this.filter = filter;
|
||||
this.patternFilter = new ItemList.PatternItemFilter(SearchField.getPattern(itemFilter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(ItemStack item) {
|
||||
if (filter.matches(item)) {
|
||||
return patternFilter.matches(item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,9 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import net.minecraft.client.entity.EntityPlayerSP;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -89,7 +91,7 @@ public class FastTransferManager {
|
||||
|
||||
public static void clearSlots(Container container) {
|
||||
for (int slotNo = 0; slotNo < container.inventorySlots.size(); slotNo++)
|
||||
((Slot) container.inventorySlots.get(slotNo)).putStack(null);
|
||||
container.inventorySlots.get(slotNo).putStack(null);
|
||||
}
|
||||
|
||||
public void performMassTransfer(GuiContainer window, int fromSlot, int toSlot, ItemStack heldStack) {
|
||||
@@ -281,6 +283,27 @@ public class FastTransferManager {
|
||||
GuiContainerManager.getManager(window).handleSlotClick(slotIndex, button, modifier);
|
||||
}
|
||||
|
||||
public static int dropHeldItem(GuiContainer window) {
|
||||
final EntityPlayerSP player = window.mc.thePlayer;
|
||||
final ItemStack held = player.inventory.getItemStack();
|
||||
|
||||
if (held == null) return -1;
|
||||
|
||||
for (int i = 0; i < window.inventorySlots.inventorySlots.size(); i++) {
|
||||
final Slot slot = window.inventorySlots.inventorySlots.get(i);
|
||||
|
||||
if (slot.inventory instanceof InventoryPlayer && !slot.getHasStack() && slot.isItemValid(held)) {
|
||||
clickSlot(window, i, 0, 0);
|
||||
|
||||
if (player.inventory.getItemStack() == null) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private boolean fillZoneWithHeldItem(GuiContainer window, int zoneIndex) {
|
||||
for (int transferTo : slotZones.get(zoneIndex)) {
|
||||
ItemStack held = NEIClientUtils.getHeldItem();
|
||||
|
||||
@@ -0,0 +1,389 @@
|
||||
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.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import codechicken.core.CommonUtils;
|
||||
import codechicken.nei.api.API;
|
||||
import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiRecipeTab;
|
||||
import codechicken.nei.recipe.ICraftingHandler;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.RecipeHandlerRef;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.FavoriteStorage;
|
||||
import codechicken.nei.util.NBTJson;
|
||||
|
||||
public class FavoriteRecipes {
|
||||
|
||||
protected static final class FastKey {
|
||||
|
||||
public final ItemStack stack;
|
||||
private int hash;
|
||||
|
||||
public FastKey(ItemStack stack) {
|
||||
this.stack = stack;
|
||||
|
||||
this.hash = 31 + Item.getIdFromItem(stack.getItem());
|
||||
this.hash = 31 * this.hash + stack.getItemDamage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
||||
if (o instanceof FastKey k && this.stack.getItem() == k.stack.getItem()
|
||||
&& this.stack.getItemDamage() == k.stack.getItemDamage()) {
|
||||
return this.stack == k.stack || Objects.equals(this.stack.stackTagCompound, k.stack.stackTagCompound);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final RestartableTask singleRecipeFavoritesTask = new RestartableTask(
|
||||
"Generate Single-Recipe Favorites") {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
final List<ICraftingHandler> handlers = GuiCraftingRecipe.getCraftingHandlers("all");
|
||||
final Map<FastKey, RecipeHandlerRef> autogeneratedRecipes = new HashMap<>();
|
||||
final Set<FastKey> whitelistItems = new HashSet<>(ItemList.items.size());
|
||||
final FavoriteStorage storage = new FavoriteStorage();
|
||||
|
||||
for (ItemStack stack : ItemList.items) {
|
||||
whitelistItems.add(new FastKey(stack));
|
||||
}
|
||||
|
||||
if (interrupted()) return;
|
||||
|
||||
for (ICraftingHandler handler : handlers) {
|
||||
if (!GuiRecipeTab.getHandlerInfo(handler).getShowFavoritesButton()) continue;
|
||||
|
||||
for (int i = 0; i < handler.numRecipes(); i++) {
|
||||
RecipeHandlerRef ref = null;
|
||||
|
||||
for (PositionedStack result : getOutputs(handler, i)) {
|
||||
ItemStack stack = StackInfo.getItemStackWithMinimumDamage(result.items);
|
||||
final FastKey key = new FastKey(stack);
|
||||
|
||||
if (!whitelistItems.contains(key)) continue;
|
||||
|
||||
if (autogeneratedRecipes.get(key) == null) {
|
||||
|
||||
if (ref == null) {
|
||||
ref = RecipeHandlerRef.of(handler, i);
|
||||
}
|
||||
|
||||
autogeneratedRecipes.put(key, ref);
|
||||
} else {
|
||||
autogeneratedRecipes.remove(key);
|
||||
whitelistItems.remove(key);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (interrupted()) return;
|
||||
}
|
||||
|
||||
final Map<RecipeHandlerRef, RecipeId> recipesCache = new HashMap<>();
|
||||
|
||||
for (Map.Entry<FastKey, RecipeHandlerRef> entry : autogeneratedRecipes.entrySet()) {
|
||||
final RecipeId recipeId = recipesCache
|
||||
.computeIfAbsent(entry.getValue(), r -> RecipeId.of(r.handler, r.recipeIndex));
|
||||
storage.add(entry.getKey().stack, recipeId);
|
||||
}
|
||||
|
||||
FavoriteRecipes.autoFavorites = storage;
|
||||
updateSubsetVisibility();
|
||||
}
|
||||
|
||||
protected List<PositionedStack> getOutputs(IRecipeHandler handler, int recipeIndex) {
|
||||
final PositionedStack pStackResult = handler.getResultStack(recipeIndex);
|
||||
return pStackResult != null ? Collections.singletonList(pStackResult) : handler.getOtherStacks(recipeIndex);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public static final String FAVORITE_ITEM = "FavoriteItem";
|
||||
private static final FavoriteStorage manualFavorites = new FavoriteStorage();
|
||||
private static FavoriteStorage autoFavorites = new FavoriteStorage();
|
||||
private static File favoriteFile;
|
||||
private static int revision = 0;
|
||||
|
||||
static {
|
||||
API.addSubset("Favorites.Manual", manualFavorites::contains);
|
||||
API.addSubset("Favorites.Generated", stack -> FavoriteRecipes.autoFavorites.contains(stack));
|
||||
}
|
||||
|
||||
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();
|
||||
boolean hasErrors = false;
|
||||
|
||||
manualFavorites.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 (recipeId == null || stack == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FAVORITE_ITEM.equals(recipeId.getHandlerName()) || RecipeHandlerRef.of(recipeId) != null) {
|
||||
manualFavorites.add(stack, recipeId);
|
||||
} else {
|
||||
hasErrors = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.error("Failed to load favorite from json string: {}", itemStr);
|
||||
hasErrors = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (hasErrors) {
|
||||
|
||||
try {
|
||||
Files.copy(
|
||||
favoriteFile,
|
||||
new File(favoriteFile.getAbsolutePath() + ".backup-" + System.currentTimeMillis()));
|
||||
NEIClientConfig.logger.info("Backed up invalid favorite file to {}", favoriteFile);
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to backup invalid favorite file to {}", favoriteFile, e);
|
||||
}
|
||||
|
||||
save();
|
||||
}
|
||||
|
||||
loadAutoGeneratedRecipes();
|
||||
}
|
||||
|
||||
public static RecipeId getGeneratedFavorite(ItemStack stack) {
|
||||
if (NEIClientConfig.favoritesEnabled() && stack != null) {
|
||||
return autoFavorites.getRecipeId(stack);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ItemStack getGeneratedFavorite(RecipeId recipeId) {
|
||||
if (NEIClientConfig.favoritesEnabled() && recipeId != null) {
|
||||
return autoFavorites.getItemStack(recipeId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static RecipeId getManualFavorite(ItemStack stack) {
|
||||
if (NEIClientConfig.favoritesEnabled() && stack != null) {
|
||||
return manualFavorites.getRecipeId(stack);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ItemStack getManualFavorite(RecipeId recipeId) {
|
||||
if (NEIClientConfig.favoritesEnabled() && recipeId != null) {
|
||||
return manualFavorites.getItemStack(recipeId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static RecipeId getFavorite(ItemStack stack) {
|
||||
|
||||
if (NEIClientConfig.favoritesEnabled() && stack != null) {
|
||||
final RecipeId recipeId = manualFavorites.getRecipeId(stack);
|
||||
return recipeId != null ? recipeId : autoFavorites.getRecipeId(stack);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ItemStack getFavorite(RecipeId recipeId) {
|
||||
|
||||
if (NEIClientConfig.favoritesEnabled() && recipeId != null) {
|
||||
final ItemStack stack = manualFavorites.getItemStack(recipeId);
|
||||
return stack != null ? stack : autoFavorites.getItemStack(recipeId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int size() {
|
||||
return manualFavorites.size() + autoFavorites.size();
|
||||
}
|
||||
|
||||
public static void reload() {
|
||||
save();
|
||||
load();
|
||||
}
|
||||
|
||||
public static boolean containsManual(ItemStack stack) {
|
||||
return getManualFavorite(stack) != null;
|
||||
}
|
||||
|
||||
public static boolean contains(ItemStack stack) {
|
||||
return getFavorite(stack) != null;
|
||||
}
|
||||
|
||||
public static void setFavorite(ItemStack stack, RecipeId recipeId) {
|
||||
if (stack == null) return;
|
||||
|
||||
manualFavorites.removeItemStack(stack);
|
||||
|
||||
if (recipeId != null) {
|
||||
manualFavorites.removeRecipeId(recipeId);
|
||||
manualFavorites.add(stack, recipeId);
|
||||
}
|
||||
|
||||
updateSubsetVisibility();
|
||||
}
|
||||
|
||||
public static void loadAutoGeneratedRecipes() {
|
||||
if (ItemList.loadFinished
|
||||
&& NEIClientConfig.getBooleanSetting("inventory.favorites.generateSingleRecipeFavorites")) {
|
||||
singleRecipeFavoritesTask.restart();
|
||||
} else {
|
||||
singleRecipeFavoritesTask.stop();
|
||||
autoFavorites.clear();
|
||||
|
||||
updateSubsetVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
protected static void updateSubsetVisibility() {
|
||||
SubsetWidget.updateHiddenItems();
|
||||
FavoriteRecipes.revision++;
|
||||
}
|
||||
|
||||
public static int getRevision() {
|
||||
return revision;
|
||||
}
|
||||
|
||||
public static void save() {
|
||||
|
||||
if (favoriteFile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<String> strings = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<NBTTagCompound, RecipeId> entry : manualFavorites.getAllFavorites()) {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@ 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;
|
||||
@@ -20,6 +21,7 @@ public class FormattedTextField extends GuiTextField {
|
||||
protected FontRenderer fontRenderer;
|
||||
protected String rawText = "";
|
||||
protected String formattedText = "";
|
||||
protected String placeholder = "";
|
||||
protected boolean editable = true;
|
||||
protected int editableColor = 14737632;
|
||||
protected int notEditableColor = 7368816;
|
||||
@@ -36,6 +38,14 @@ public class FormattedTextField extends GuiTextField {
|
||||
this.formatter = formatter;
|
||||
}
|
||||
|
||||
public TextFormatter getFormatter() {
|
||||
return this.formatter;
|
||||
}
|
||||
|
||||
public void setPlaceholder(String placeholder) {
|
||||
this.placeholder = placeholder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCursorCounter() {
|
||||
super.updateCursorCounter();
|
||||
@@ -51,6 +61,11 @@ public class FormattedTextField extends GuiTextField {
|
||||
super.setFocused(focus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(String rawText) {
|
||||
super.setText(EnumChatFormatting.getTextWithoutFormattingCodes(rawText));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectionPos(int p_146199_1_) {
|
||||
String text = this.getText();
|
||||
@@ -102,89 +117,140 @@ public class FormattedTextField extends GuiTextField {
|
||||
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()) {
|
||||
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.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 (!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);
|
||||
}
|
||||
}
|
||||
|
||||
int firstCharacterIndex = getFormattedTextShift(this.lineScrollOffset);
|
||||
String rawTextClipped = this.fontRenderer
|
||||
.trimStringToWidth(this.rawText.substring(this.lineScrollOffset), this.getWidth());
|
||||
String textClipped = this.formattedText.substring(
|
||||
firstCharacterIndex,
|
||||
getFormattedTextShift(this.lineScrollOffset + rawTextClipped.length()));
|
||||
int cursorPosition = getFormattedTextShift(this.getCursorPosition());
|
||||
int selectionEnd = getFormattedTextShift(this.getSelectionEnd());
|
||||
|
||||
int color = this.editable ? this.editableColor : this.notEditableColor;
|
||||
int cursorA = cursorPosition - firstCharacterIndex;
|
||||
int cursorB = selectionEnd - firstCharacterIndex;
|
||||
boolean flag = cursorA >= 0 && cursorA <= textClipped.length();
|
||||
boolean flag1 = this.isFocused() && this.frame / 6 % 2 == 0 && flag;
|
||||
boolean flag2 = this.getCursorPosition() < this.rawText.length()
|
||||
|| this.rawText.length() >= this.getMaxStringLength();
|
||||
int x = this.getEnableBackgroundDrawing() ? this.xPosition + 4 : this.xPosition;
|
||||
int y = this.getEnableBackgroundDrawing() ? this.yPosition + (this.height - 8) / 2 : this.yPosition;
|
||||
int x2 = x;
|
||||
|
||||
if (cursorB > textClipped.length()) {
|
||||
cursorB = textClipped.length();
|
||||
}
|
||||
|
||||
if (textClipped.length() > 0) {
|
||||
String s1 = flag ? textClipped.substring(0, cursorA) : textClipped;
|
||||
String colorA = getPreviousColor(firstCharacterIndex);
|
||||
x2 = this.fontRenderer.drawStringWithShadow(colorA + s1, x, y, color);
|
||||
}
|
||||
|
||||
int k1 = x2;
|
||||
|
||||
if (!flag) {
|
||||
k1 = cursorA > 0 ? x + this.width : x;
|
||||
} else if (flag2) {
|
||||
k1 = x2 - 1;
|
||||
--x2;
|
||||
}
|
||||
|
||||
if (textClipped.length() > 0 && flag && cursorA < textClipped.length()) {
|
||||
String colorB = getPreviousColor(firstCharacterIndex + cursorA);
|
||||
this.fontRenderer.drawStringWithShadow(colorB + textClipped.substring(cursorA), x2, y, color);
|
||||
}
|
||||
|
||||
if (flag1) {
|
||||
if (flag2) {
|
||||
Gui.drawRect(k1, y - 1, k1 + 1, y + 1 + this.fontRenderer.FONT_HEIGHT, -3092272);
|
||||
} else {
|
||||
this.fontRenderer.drawStringWithShadow("_", k1, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
if (cursorB != cursorA) {
|
||||
int l1 = x + this.fontRenderer.getStringWidth(textClipped.substring(0, cursorB));
|
||||
drawCursorVertical(k1, y - 1, l1 - 1, y + 1 + this.fontRenderer.FONT_HEIGHT);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +278,7 @@ public class FormattedTextField extends GuiTextField {
|
||||
}
|
||||
|
||||
Tessellator tessellator = Tessellator.instance;
|
||||
GL11.glColor4f(0.0F, 0.0F, 255.0F, 255.0F);
|
||||
GL11.glColor4f(0.0F, 0.0F, 1.0F, 1.0F);
|
||||
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
GL11.glEnable(GL11.GL_COLOR_LOGIC_OP);
|
||||
GL11.glLogicOp(GL11.GL_OR_REVERSE);
|
||||
@@ -230,15 +296,26 @@ public class FormattedTextField extends GuiTextField {
|
||||
int shift = 0;
|
||||
|
||||
for (int i = 0; i < position; i++) {
|
||||
while (this.formattedText.length() > i + shift && this.formattedText.charAt(i + shift) == '\u00a7') {
|
||||
while (this.formattedText.length() > i + shift + 1 && this.formattedText.charAt(i + shift) == '\u00a7'
|
||||
&& isFormattingCode(this.formattedText.charAt(i + shift + 1))) {
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return position + shift;
|
||||
return Math.min(position + shift, this.formattedText.length());
|
||||
}
|
||||
|
||||
private static boolean isFormattingCode(char c) {
|
||||
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')
|
||||
|| (c >= 'k' && c <= 'o')
|
||||
|| c == 'r'
|
||||
|| (c >= 'A' && c <= 'F')
|
||||
|| (c >= 'K' && c <= 'O')
|
||||
|| c == 'R';
|
||||
}
|
||||
|
||||
private String getPreviousColor(int position) {
|
||||
position = Math.min(position, this.formattedText.length() - 1);
|
||||
while (position >= 0) {
|
||||
if (this.formattedText.charAt(position) == '\u00a7') {
|
||||
return this.formattedText.substring(position, position + 2);
|
||||
|
||||
@@ -24,8 +24,8 @@ public class GuiEnchantmentModifier extends GuiContainer {
|
||||
|
||||
@Override
|
||||
protected void drawGuiContainerForegroundLayer(int par1, int par2) {
|
||||
fontRendererObj.drawString(translate("enchant"), 12, 6, 0x404040);
|
||||
fontRendererObj.drawString(translate("enchant.level"), 19, 20, 0x404040);
|
||||
fontRendererObj.drawString(translate("enchant"), 12, 6, ColorUtils.textGray.getColor());
|
||||
fontRendererObj.drawString(translate("enchant.level"), 19, 20, ColorUtils.textGray.getColor());
|
||||
}
|
||||
|
||||
protected void drawGuiContainerBackgroundLayer(float f, int i, int j) {
|
||||
@@ -39,7 +39,11 @@ public class GuiEnchantmentModifier extends GuiContainer {
|
||||
container.drawScrollBar(this);
|
||||
|
||||
String levelstring = "" + container.level;
|
||||
fontRendererObj.drawString(levelstring, 33 - fontRendererObj.getStringWidth(levelstring) / 2, 34, 0xFF606060);
|
||||
fontRendererObj.drawString(
|
||||
levelstring,
|
||||
33 - fontRendererObj.getStringWidth(levelstring) / 2,
|
||||
34,
|
||||
ColorUtils.textLightGray.getColor());
|
||||
|
||||
GL11.glTranslatef(-guiLeft, -guiTop, 0);
|
||||
}
|
||||
@@ -78,8 +82,8 @@ public class GuiEnchantmentModifier extends GuiContainer {
|
||||
|
||||
private void changeLevel(int i) {
|
||||
container.level += i;
|
||||
((GuiButton) buttonList.get(0)).enabled = container.level != 1;
|
||||
((GuiButton) buttonList.get(1)).enabled = container.level != 10;
|
||||
buttonList.get(0).enabled = container.level != 1;
|
||||
buttonList.get(1).enabled = container.level != 10;
|
||||
}
|
||||
|
||||
protected void mouseClicked(int i, int j, int k) {
|
||||
|
||||
@@ -45,15 +45,14 @@ public class GuiNEIButton extends GuiButton {
|
||||
}
|
||||
|
||||
protected int getTextColour(boolean mouseOver) {
|
||||
int color = 0xe0e0e0;
|
||||
|
||||
if (!enabled) {
|
||||
color = 0xffa0a0a0;
|
||||
return ColorUtils.buttonLabelInactive.getColor();
|
||||
} else if (mouseOver) {
|
||||
color = 0xffffa0;
|
||||
return ColorUtils.buttonLabelHover.getColor();
|
||||
}
|
||||
|
||||
return color;
|
||||
return ColorUtils.buttonLabelNormal.getColor();
|
||||
}
|
||||
|
||||
protected void drawContent(Minecraft minecraft, int y, int x, boolean mouseOver) {
|
||||
|
||||
@@ -289,10 +289,10 @@ public class GuiPotionCreator extends GuiContainerWidget {
|
||||
CCRenderState.changeTexture("nei:textures/gui/potion.png");
|
||||
drawTexturedModalRect(0, 0, 0, 0, xSize, ySize);
|
||||
|
||||
FontUtils.drawCenteredString(translate("potion.favourite"), xSize / 2, 4, 0x404040);
|
||||
fontRendererObj.drawString(translate("potion.duration"), 12, 40, 0x404040);
|
||||
fontRendererObj.drawString(translate("potion.level"), 19, 73, 0x404040);
|
||||
FontUtils.drawCenteredString(translateAmplifier(amplifier), 33, 86, 0xFF606060);
|
||||
FontUtils.drawCenteredString(translate("potion.favourite"), xSize / 2, 4, ColorUtils.textGray.getColor());
|
||||
fontRendererObj.drawString(translate("potion.duration"), 12, 40, ColorUtils.textGray.getColor());
|
||||
fontRendererObj.drawString(translate("potion.level"), 19, 73, ColorUtils.textGray.getColor());
|
||||
FontUtils.drawCenteredString(translateAmplifier(amplifier), 33, 86, ColorUtils.textGray.getColor());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,7 +28,7 @@ public class HUDRenderer implements IKeyStateTracker {
|
||||
|
||||
@Override
|
||||
public void tickKeyStates() {
|
||||
if (KeyManager.keyStates.get("world.highlight_tips").down) {
|
||||
if (KeyManager.isPressed("world.highlight_tips")) {
|
||||
ConfigTag tag = NEIClientConfig.getSetting("world.highlight_tips");
|
||||
tag.setBooleanValue(!tag.getBooleanValue());
|
||||
}
|
||||
@@ -42,13 +42,11 @@ public class HUDRenderer implements IKeyStateTracker {
|
||||
&& mc.objectMouseOver != null
|
||||
&& mc.objectMouseOver.typeOfHit == MovingObjectType.BLOCK) {
|
||||
World world = mc.theWorld;
|
||||
ItemStack[] items = ItemInfo.getIdentifierItems(world, mc.thePlayer, mc.objectMouseOver)
|
||||
.toArray(new ItemStack[0]);
|
||||
final List<ItemStack> items = ItemInfo.getIdentifierItems(world, mc.thePlayer, mc.objectMouseOver);
|
||||
|
||||
if (items.length == 0) return;
|
||||
|
||||
ItemStack stack = StackInfo.getItemStackWithMinimumDamage(items);
|
||||
if (items.isEmpty()) return;
|
||||
|
||||
final ItemStack stack = StackInfo.getItemStackWithMinimumDamage(items.toArray(new ItemStack[0]));
|
||||
renderOverlay(stack, ItemInfo.getText(stack, world, mc.thePlayer, mc.objectMouseOver), getPositioning());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@ import static codechicken.nei.NEIClientUtils.translate;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.guihook.IContainerInputHandler;
|
||||
import codechicken.nei.guihook.IContainerTooltipHandler;
|
||||
import codechicken.nei.recipe.AutoCraftingManager;
|
||||
|
||||
public class HeldItemHandler implements IContainerInputHandler, IContainerTooltipHandler {
|
||||
|
||||
@@ -25,9 +25,10 @@ public class HeldItemHandler implements IContainerInputHandler, IContainerToolti
|
||||
}
|
||||
|
||||
protected boolean contains(int mousex, int mousey) {
|
||||
return NEIClientUtils.getHeldItem() != null
|
||||
&& (ItemPanels.bookmarkPanel.contains(mousex, mousey) || ItemPanels.itemPanel.contains(mousex, mousey)
|
||||
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey));
|
||||
return NEIClientUtils.getHeldItem() != null && !ItemPanels.bookmarkPanel.inEditingState()
|
||||
&& !AutoCraftingManager.processing()
|
||||
&& (ItemPanels.bookmarkPanel.contains(mousex, mousey)
|
||||
|| ItemPanels.itemPanel.containsWithSubpanels(mousex, mousey));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -35,7 +36,8 @@ public class HeldItemHandler implements IContainerInputHandler, IContainerToolti
|
||||
|
||||
if (contains(mousex, mousey)) {
|
||||
|
||||
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")) {
|
||||
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")
|
||||
|| NEIClientUtils.mc().playerController.isInCreativeMode()) {
|
||||
if (button == 1) {
|
||||
NEIClientUtils.decreaseSlotStack(-999);
|
||||
} else {
|
||||
@@ -94,24 +96,14 @@ public class HeldItemHandler implements IContainerInputHandler, IContainerToolti
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleItemDisplayName(GuiContainer gui, ItemStack itemstack, List<String> currenttip) {
|
||||
return currenttip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
|
||||
List<String> currenttip) {
|
||||
return currenttip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
|
||||
|
||||
if (contains(mousex, mousey)) {
|
||||
currenttip.clear();
|
||||
|
||||
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")) {
|
||||
if (NEIClientConfig.canPerformAction("delete") && NEIClientConfig.canPerformAction("item")
|
||||
|| NEIClientUtils.mc().playerController.isInCreativeMode()) {
|
||||
currenttip.add(EnumChatFormatting.RED + translate("itempanel.deleteItem"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import net.minecraft.client.gui.GuiRepair;
|
||||
import net.minecraft.client.gui.inventory.GuiBrewingStand;
|
||||
import net.minecraft.client.gui.inventory.GuiCrafting;
|
||||
import net.minecraft.client.gui.inventory.GuiFurnace;
|
||||
import net.minecraft.client.gui.inventory.GuiInventory;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
import codechicken.nei.api.API;
|
||||
import codechicken.nei.recipe.BrewingOverlayHandler;
|
||||
import codechicken.nei.recipe.BrewingRecipeHandler;
|
||||
import codechicken.nei.recipe.DefaultOverlayHandler;
|
||||
import codechicken.nei.recipe.FireworkRecipeHandler;
|
||||
import codechicken.nei.recipe.FuelRecipeHandler;
|
||||
import codechicken.nei.recipe.FurnaceRecipeHandler;
|
||||
import codechicken.nei.recipe.InformationHandler;
|
||||
import codechicken.nei.recipe.ProfilerRecipeHandler;
|
||||
import codechicken.nei.recipe.RepairOverlayHandler;
|
||||
import codechicken.nei.recipe.RepairRecipeHandler;
|
||||
import codechicken.nei.recipe.ShapedRecipeHandler;
|
||||
import codechicken.nei.recipe.ShapelessRecipeHandler;
|
||||
import cpw.mods.fml.common.event.FMLInterModComms;
|
||||
|
||||
public class IMCForNEI {
|
||||
|
||||
public static void IMCSender() {
|
||||
|
||||
API.registerRecipeHandler(new ShapedRecipeHandler());
|
||||
API.registerUsageHandler(new ShapedRecipeHandler());
|
||||
sendHandler("codechicken.nei.recipe.ShapedRecipeHandler", "minecraft:crafting_table");
|
||||
|
||||
API.registerRecipeHandler(new ShapelessRecipeHandler());
|
||||
API.registerUsageHandler(new ShapelessRecipeHandler());
|
||||
sendHandler("codechicken.nei.recipe.ShapelessRecipeHandler", "minecraft:crafting_table");
|
||||
|
||||
API.registerRecipeHandler(new FireworkRecipeHandler());
|
||||
API.registerUsageHandler(new FireworkRecipeHandler());
|
||||
sendHandler("codechicken.nei.recipe.FireworkRecipeHandler", "minecraft:fireworks");
|
||||
|
||||
API.registerRecipeHandler(new FurnaceRecipeHandler());
|
||||
API.registerUsageHandler(new FurnaceRecipeHandler());
|
||||
sendHandler("codechicken.nei.recipe.FurnaceRecipeHandler", "minecraft:furnace");
|
||||
|
||||
API.registerRecipeHandler(new BrewingRecipeHandler());
|
||||
API.registerUsageHandler(new BrewingRecipeHandler());
|
||||
sendHandler("codechicken.nei.recipe.BrewingRecipeHandler", "minecraft:brewing_stand");
|
||||
|
||||
API.registerRecipeHandler(new FuelRecipeHandler());
|
||||
API.registerUsageHandler(new FuelRecipeHandler());
|
||||
sendFuelRecipeHandler();
|
||||
|
||||
API.registerRecipeHandler(new InformationHandler());
|
||||
API.registerUsageHandler(new InformationHandler());
|
||||
sendInformationHandler();
|
||||
|
||||
API.registerRecipeHandler(new RepairRecipeHandler());
|
||||
API.registerUsageHandler(new RepairRecipeHandler());
|
||||
sendRepairHandler();
|
||||
sendCatalyst("repair", "minecraft:anvil");
|
||||
|
||||
API.registerGuiOverlay(GuiCrafting.class, "crafting");
|
||||
API.registerGuiOverlay(GuiInventory.class, "crafting2x2", 63, 20);
|
||||
API.registerGuiOverlay(GuiFurnace.class, "smelting");
|
||||
API.registerGuiOverlay(GuiFurnace.class, "fuel");
|
||||
API.registerGuiOverlay(GuiBrewingStand.class, "brewing");
|
||||
API.registerGuiOverlay(GuiRepair.class, "repair", 2, 37);
|
||||
|
||||
API.registerGuiOverlayHandler(GuiCrafting.class, new DefaultOverlayHandler(), "crafting");
|
||||
API.registerGuiOverlayHandler(GuiInventory.class, new DefaultOverlayHandler(63, 20), "crafting2x2");
|
||||
API.registerGuiOverlayHandler(GuiBrewingStand.class, new BrewingOverlayHandler(), "brewing");
|
||||
API.registerGuiOverlayHandler(GuiRepair.class, new RepairOverlayHandler(), "repair");
|
||||
|
||||
API.registerRecipeHandler(new ProfilerRecipeHandler(true));
|
||||
API.registerUsageHandler(new ProfilerRecipeHandler(false));
|
||||
sendProfilerRecipeHandler();
|
||||
}
|
||||
|
||||
private static void sendHandler(String aName, String aBlock) {
|
||||
NBTTagCompound aNBT = new NBTTagCompound();
|
||||
aNBT.setString("handler", aName);
|
||||
aNBT.setString("modName", "Minecraft");
|
||||
aNBT.setString("modId", "minecraft");
|
||||
aNBT.setString("itemName", aBlock);
|
||||
aNBT.setInteger("handlerWidth", 166);
|
||||
aNBT.setInteger("handlerHeight", 65);
|
||||
aNBT.setBoolean("multipleWidgetsAllowed", true);
|
||||
aNBT.setInteger("yShift", 0);
|
||||
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
|
||||
}
|
||||
|
||||
private static void sendRepairHandler() {
|
||||
NBTTagCompound aNBT = new NBTTagCompound();
|
||||
aNBT.setString("handler", "codechicken.nei.recipe.RepairRecipeHandler");
|
||||
aNBT.setString("modName", "Minecraft");
|
||||
aNBT.setString("modId", "minecraft");
|
||||
aNBT.setString("itemName", "minecraft:anvil");
|
||||
aNBT.setInteger("handlerHeight", 39);
|
||||
aNBT.setInteger("handlerWidth", 166);
|
||||
aNBT.setBoolean("multipleWidgetsAllowed", true);
|
||||
aNBT.setBoolean("showFavoritesButton", false);
|
||||
aNBT.setInteger("yShift", 0);
|
||||
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
|
||||
}
|
||||
|
||||
private static void sendFuelRecipeHandler() {
|
||||
NBTTagCompound aNBT = new NBTTagCompound();
|
||||
aNBT.setString("handler", "codechicken.nei.recipe.FuelRecipeHandler");
|
||||
aNBT.setString("modName", "Minecraft");
|
||||
aNBT.setString("modId", "minecraft");
|
||||
aNBT.setString("imageResource", "nei:textures/nei_tabbed_sprites.png");
|
||||
aNBT.setInteger("imageX", 80);
|
||||
aNBT.setInteger("imageY", 0);
|
||||
aNBT.setInteger("imageWidth", 14);
|
||||
aNBT.setInteger("imageHeight", 14);
|
||||
aNBT.setInteger("handlerHeight", 65);
|
||||
aNBT.setInteger("handlerWidth", 166);
|
||||
aNBT.setBoolean("multipleWidgetsAllowed", true);
|
||||
aNBT.setInteger("yShift", 0);
|
||||
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
|
||||
}
|
||||
|
||||
private static void sendInformationHandler() {
|
||||
NBTTagCompound aNBT = new NBTTagCompound();
|
||||
aNBT.setString("handler", "codechicken.nei.recipe.InformationHandler");
|
||||
aNBT.setString("modName", "Not Enough Items");
|
||||
aNBT.setString("modId", "nei");
|
||||
aNBT.setString("imageResource", "nei:textures/nei_tabbed_sprites.png");
|
||||
aNBT.setInteger("imageX", 96);
|
||||
aNBT.setInteger("imageY", 0);
|
||||
aNBT.setInteger("imageWidth", 16);
|
||||
aNBT.setInteger("imageHeight", 16);
|
||||
aNBT.setInteger("handlerHeight", 65);
|
||||
aNBT.setInteger("handlerWidth", 166);
|
||||
aNBT.setBoolean("multipleWidgetsAllowed", true);
|
||||
aNBT.setInteger("yShift", 0);
|
||||
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
|
||||
}
|
||||
|
||||
private static void sendProfilerRecipeHandler() {
|
||||
NBTTagCompound aNBT = new NBTTagCompound();
|
||||
aNBT.setString("handler", "codechicken.nei.recipe.ProfilerRecipeHandler");
|
||||
aNBT.setString("modName", "Not Enough Items");
|
||||
aNBT.setString("modId", "nei");
|
||||
aNBT.setString("itemName", "minecraft:clock");
|
||||
aNBT.setInteger("handlerHeight", 16);
|
||||
aNBT.setInteger("handlerWidth", 166);
|
||||
aNBT.setBoolean("multipleWidgetsAllowed", true);
|
||||
aNBT.setInteger("yShift", 0);
|
||||
FMLInterModComms.sendMessage("NotEnoughItems", "registerHandlerInfo", aNBT);
|
||||
}
|
||||
|
||||
private static void sendCatalyst(String aName, String aStack) {
|
||||
NBTTagCompound aNBT = new NBTTagCompound();
|
||||
aNBT.setString("handlerID", aName);
|
||||
aNBT.setString("itemName", aStack);
|
||||
aNBT.setInteger("priority", 0);
|
||||
FMLInterModComms.sendMessage("NotEnoughItems", "registerCatalystInfo", aNBT);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,14 +30,7 @@ public class InfiniteStackSizeHandler implements IInfiniteItemHandler {
|
||||
|
||||
@Override
|
||||
public void replenishInfiniteStack(InventoryPlayer inv, int slotNo) {
|
||||
ItemStack stack = inv.getStackInSlot(slotNo);
|
||||
stack.stackSize = 111;
|
||||
|
||||
for (int i = 0; i < inv.getSizeInventory(); i++) {
|
||||
if (i == slotNo) continue;
|
||||
|
||||
if (NEIServerUtils.areStacksSameType(stack, inv.getStackInSlot(i))) inv.setInventorySlotContents(i, null);
|
||||
}
|
||||
inv.getStackInSlot(slotNo).stackSize = 111;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.ItemsGrid.MouseContext;
|
||||
import codechicken.nei.NEIClientUtils.Alignment;
|
||||
import codechicken.nei.recipe.AutoCraftingManager;
|
||||
import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.ICraftingHandler;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
import codechicken.nei.recipe.Recipe;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.RecipeInfo;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.ReadableNumberConverter;
|
||||
|
||||
public class ItemCraftablesPanel
|
||||
extends AbstractSubpanel<ItemsGrid<ItemCraftablesPanel.CraftablesGridSlot, MouseContext>> {
|
||||
|
||||
public static class CraftablesGridSlot extends ItemsGridSlot {
|
||||
|
||||
protected final long realAmount;
|
||||
protected final boolean isFluidDisplay;
|
||||
protected final RecipeId recipeId;
|
||||
|
||||
public CraftablesGridSlot(int slotIndex, int itemIndex, ItemStack itemStack, RecipeId recipeId) {
|
||||
super(slotIndex, itemIndex, itemStack);
|
||||
this.realAmount = StackInfo.getAmount(itemStack);
|
||||
this.isFluidDisplay = StackInfo.itemStackToNBT(itemStack).hasKey("gtFluidName");
|
||||
this.recipeId = recipeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeId getRecipeId() {
|
||||
return this.recipeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <M extends MouseContext> void afterDraw(Rectangle4i rect, M mouseContext) {
|
||||
drawStackSize(rect);
|
||||
}
|
||||
|
||||
protected void drawStackSize(Rectangle4i rect) {
|
||||
long stackSize = this.realAmount;
|
||||
|
||||
if (stackSize > 1) {
|
||||
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
|
||||
String amountString = "";
|
||||
|
||||
if (stackSize < 10_000) {
|
||||
amountString = String.valueOf(stackSize);
|
||||
} else {
|
||||
amountString = ReadableNumberConverter.INSTANCE.toWideReadableForm(stackSize);
|
||||
}
|
||||
|
||||
if (this.isFluidDisplay) {
|
||||
amountString += "L";
|
||||
}
|
||||
|
||||
NEIClientUtils.drawNEIOverlayText(
|
||||
amountString,
|
||||
new Rectangle4i(rect.x + 1, rect.y + 1, rect.w - 2, rect.h - 2),
|
||||
panelFactor,
|
||||
0xFFFFFF,
|
||||
true,
|
||||
this.isFluidDisplay ? Alignment.BottomLeft : Alignment.BottomRight);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static List<String> guiBlacklist = new ArrayList<>();
|
||||
private final int MIN_DELAY = 600;
|
||||
|
||||
private Map<String, ArrayList<ICraftingHandler>> identHandlers = new HashMap<>();
|
||||
private Map<ItemStack, RecipeId> availableRecipes = new HashMap<>();
|
||||
|
||||
private GuiContainer lastGuiContainer = null;
|
||||
private ItemStackAmount lastPlayerInventory = null;
|
||||
private long lastPlayerInventorySync = 0;
|
||||
private int lastFavoritesCount = 0;
|
||||
|
||||
public ItemCraftablesPanel() {
|
||||
this.grid = new ItemsGrid<>() {
|
||||
|
||||
protected List<CraftablesGridSlot> gridMask;
|
||||
|
||||
@Override
|
||||
protected void onGridChanged() {
|
||||
this.gridMask = null;
|
||||
super.onGridChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CraftablesGridSlot> getMask() {
|
||||
|
||||
if (this.gridMask == null) {
|
||||
final int maxSlotIndex = this.rows * this.columns;
|
||||
final List<CraftablesGridSlot> gridMask = new ArrayList<>();
|
||||
this.realItems.clear();
|
||||
|
||||
if (!ItemCraftablesPanel.this.availableRecipes.isEmpty()) {
|
||||
final List<Map.Entry<ItemStack, RecipeId>> entries = ItemCraftablesPanel.this.availableRecipes
|
||||
.entrySet().stream()
|
||||
.sorted(
|
||||
Map.Entry.comparingByKey(
|
||||
Comparator.comparing(FavoriteRecipes::containsManual)
|
||||
.thenComparing(FavoriteRecipes::contains).reversed()
|
||||
.thenComparing(ItemSorter.instance)))
|
||||
.limit(maxSlotIndex).collect(Collectors.toList());
|
||||
int slotIndex = 0;
|
||||
int itemIndex = 0;
|
||||
|
||||
for (Map.Entry<ItemStack, RecipeId> entry : entries) {
|
||||
if (!isInvalidSlot(slotIndex)) {
|
||||
this.realItems.add(entry.getKey());
|
||||
gridMask.add(
|
||||
new CraftablesGridSlot(
|
||||
slotIndex,
|
||||
itemIndex++,
|
||||
entry.getKey(),
|
||||
entry.getValue()));
|
||||
}
|
||||
if (slotIndex++ >= maxSlotIndex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.gridMask = gridMask;
|
||||
} else {
|
||||
this.gridMask = Collections.emptyList();
|
||||
}
|
||||
|
||||
ItemCraftablesPanel.this.updateLinePadding();
|
||||
}
|
||||
|
||||
return this.gridMask;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MouseContext getMouseContext(int mousex, int mousey) {
|
||||
final ItemsGridSlot hovered = getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (hovered != null) {
|
||||
return new MouseContext(
|
||||
hovered.slotIndex,
|
||||
hovered.slotIndex / this.columns,
|
||||
hovered.slotIndex % this.columns);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack getDraggedStackWithQuantity(ItemStack itemStack) {
|
||||
return ItemQuantityField.prepareStackWithQuantity(itemStack, StackInfo.getAmount(itemStack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mousex, int mousey) {
|
||||
if (!this.availableRecipes.isEmpty()) {
|
||||
super.draw(mousex, mousey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setPanelWidth(int width) {
|
||||
if (getGuiContainer() != this.lastGuiContainer) updateCraftables();
|
||||
|
||||
final int columns = width / ItemsGrid.SLOT_SIZE;
|
||||
final int useRows = NEIClientConfig.getIntSetting("inventory.craftables.useRows");
|
||||
final int rows = (int) Math.min(Math.ceil(this.availableRecipes.size() * 1f / columns), useRows);
|
||||
|
||||
this.w = width;
|
||||
this.h = 8 + ItemsGrid.SLOT_SIZE * Math.max(rows, 1);
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
this.splittingLineColor = NEIClientConfig.getSetting("inventory.craftables.color").getHexValue();
|
||||
updateCraftables();
|
||||
super.update();
|
||||
}
|
||||
|
||||
private void updateCraftables() {
|
||||
|
||||
if (!NEIClientConfig.showCraftablesPanelWidget()) {
|
||||
clearCraftables();
|
||||
} else if (this.lastPlayerInventory == null
|
||||
|| Math.abs(System.currentTimeMillis() - this.lastPlayerInventorySync) >= MIN_DELAY) {
|
||||
final GuiContainer firstGui = getGuiContainer();
|
||||
this.lastPlayerInventorySync = System.currentTimeMillis();
|
||||
|
||||
if (firstGui != null && !ItemCraftablesPanel.guiBlacklist.contains(firstGui.getClass().getName())) {
|
||||
final boolean showOnlyFavorites = NEIClientConfig
|
||||
.getBooleanSetting("inventory.craftables.favoritesOnly");
|
||||
final ItemStackAmount inv = AutoCraftingManager.getInventoryItems(firstGui);
|
||||
|
||||
if (this.lastGuiContainer != firstGui
|
||||
|| showOnlyFavorites && this.lastFavoritesCount != FavoriteRecipes.size()
|
||||
|| !inv.equals(this.lastPlayerInventory)) {
|
||||
this.lastPlayerInventory = inv;
|
||||
this.lastGuiContainer = firstGui;
|
||||
this.lastFavoritesCount = FavoriteRecipes.size();
|
||||
this.availableRecipes = generateCraftables(firstGui);
|
||||
this.grid.onGridChanged();
|
||||
}
|
||||
|
||||
} else {
|
||||
clearCraftables();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void clearCraftables() {
|
||||
if (!this.availableRecipes.isEmpty()) {
|
||||
this.availableRecipes = Collections.emptyMap();
|
||||
this.lastPlayerInventory = null;
|
||||
this.grid.onGridChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private GuiContainer getGuiContainer() {
|
||||
final GuiContainer firstGui = NEIClientUtils.getGuiContainer();
|
||||
return (firstGui instanceof GuiRecipe<?>gui) ? gui.firstGui : firstGui;
|
||||
}
|
||||
|
||||
private Map<ItemStack, RecipeId> generateCraftables(GuiContainer firstGui) {
|
||||
final List<IRecipeHandler> availableHandlers = getAvailableHandlers(firstGui);
|
||||
final Map<ItemStack, RecipeId> availableRecipes = new HashMap<>();
|
||||
|
||||
if (!availableHandlers.isEmpty()) {
|
||||
final List<ItemStack> invStacks = ItemCraftablesPanel.this.lastPlayerInventory.values();
|
||||
|
||||
for (IRecipeHandler handler : availableHandlers) {
|
||||
availableRecipes.putAll(filterHandlerRecipes(handler, firstGui, invStacks));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return availableRecipes;
|
||||
}
|
||||
|
||||
private List<IRecipeHandler> getAvailableHandlers(GuiContainer firstGui) {
|
||||
final List<IRecipeHandler> availableHandlers = new ArrayList<>();
|
||||
|
||||
for (String ident : RecipeInfo.getOverlayHandlerIdents(firstGui)) {
|
||||
availableHandlers.addAll(identHandlers.computeIfAbsent(ident, GuiCraftingRecipe::getCraftingHandlers));
|
||||
}
|
||||
|
||||
return availableHandlers;
|
||||
}
|
||||
|
||||
private Map<ItemStack, RecipeId> filterHandlerRecipes(IRecipeHandler handler, GuiContainer firstGui,
|
||||
List<ItemStack> invStacks) {
|
||||
final Map<ItemStack, RecipeId> availableRecipes = new HashMap<>();
|
||||
final boolean showOnlyFavorites = NEIClientConfig.getBooleanSetting("inventory.craftables.favoritesOnly");
|
||||
|
||||
IntStream.range(0, handler.numRecipes()).parallel().forEach(recipeIndex -> {
|
||||
if (existsIngredients(firstGui, handler.getIngredientStacks(recipeIndex), invStacks)) {
|
||||
final Recipe recipe = Recipe.of(handler, recipeIndex);
|
||||
|
||||
if (!recipe.getResults().isEmpty()
|
||||
&& (!showOnlyFavorites || FavoriteRecipes.getFavorite(recipe.getRecipeId()) != null)) {
|
||||
synchronized (availableRecipes) {
|
||||
availableRecipes.put(recipe.getResult(), recipe.getRecipeId());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return availableRecipes;
|
||||
}
|
||||
|
||||
private boolean existsIngredients(GuiContainer firstGui, List<PositionedStack> ingredients,
|
||||
List<ItemStack> invStacks) {
|
||||
final Map<ItemStack, Integer> usedItems = new HashMap<>();
|
||||
|
||||
for (PositionedStack pStack : ingredients) {
|
||||
final ItemStack used = invStacks.stream().filter(
|
||||
is -> usedItems.getOrDefault(is, is.stackSize) >= pStack.item.stackSize && pStack.contains(is))
|
||||
.findAny().orElse(null);
|
||||
|
||||
if (used != null) {
|
||||
usedItems.put(used, usedItems.getOrDefault(used, used.stackSize) - pStack.item.stackSize);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return !usedItems.isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,189 +1,118 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.nei.ItemPanel.ItemPanelSlot;
|
||||
import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.GuiUsageRecipe;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.ItemsGrid.MouseContext;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
|
||||
public class ItemHistoryPanel extends Widget {
|
||||
public class ItemHistoryPanel extends AbstractSubpanel<ItemsGrid<ItemHistoryPanel.HistoryGridSlot, MouseContext>> {
|
||||
|
||||
protected int mouseDownSlot = -1;
|
||||
protected ItemsGrid grid;
|
||||
public static class HistoryGridSlot extends ItemsGridSlot {
|
||||
|
||||
public ItemHistoryPanel() {
|
||||
grid = new ItemsGrid();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return grid.isEmpty();
|
||||
}
|
||||
|
||||
public void draw(int mousex, int mousey) {
|
||||
|
||||
if (NEIClientConfig.getIntSetting("inventory.history.splittingMode") == 0) {
|
||||
GuiDraw.drawRect(x, y, w, h, NEIClientConfig.getSetting("inventory.history.historyColor").getHexValue());
|
||||
} else {
|
||||
drawSplittingArea(x, y, w, h, NEIClientConfig.getSetting("inventory.history.historyColor").getHexValue());
|
||||
public HistoryGridSlot(int slotIndex, int itemIndex, ItemStack item) {
|
||||
super(slotIndex, itemIndex, item);
|
||||
}
|
||||
|
||||
grid.draw(mousex, mousey);
|
||||
@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<>();
|
||||
int itemIndex = 0;
|
||||
for (int slotIndex = 0; slotIndex < this.rows * this.columns && itemIndex < size(); slotIndex++) {
|
||||
if (!isInvalidSlot(slotIndex)) {
|
||||
this.gridMask.add(new HistoryGridSlot(slotIndex, itemIndex, getItem(itemIndex)));
|
||||
itemIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
ItemHistoryPanel.this.updateLinePadding();
|
||||
}
|
||||
|
||||
return this.gridMask;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MouseContext getMouseContext(int mousex, int mousey) {
|
||||
final HistoryGridSlot hovered = getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (hovered != null) {
|
||||
return new MouseContext(
|
||||
hovered.slotIndex,
|
||||
hovered.slotIndex / this.columns,
|
||||
hovered.slotIndex % this.columns);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack getDraggedStackWithQuantity(ItemStack itemStack) {
|
||||
return ItemQuantityField.prepareStackWithQuantity(itemStack, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mousex, int mousey) {
|
||||
if (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() {
|
||||
grid.update();
|
||||
this.splittingLineColor = NEIClientConfig.getSetting("inventory.history.color").getHexValue();
|
||||
super.update();
|
||||
}
|
||||
|
||||
public void addItem(ItemStack stack) {
|
||||
if (stack != null) {
|
||||
ItemStack is = StackInfo.loadFromNBT(StackInfo.itemStackToNBT(stack), 0);
|
||||
ItemStack is = StackInfo.withAmount(stack, 0);
|
||||
|
||||
grid.realItems.removeIf(historyStack -> StackInfo.equalItemAndNBT(historyStack, stack, true));
|
||||
grid.realItems.add(0, is);
|
||||
this.grid.realItems.removeIf(historyStack -> StackInfo.equalItemAndNBT(historyStack, stack, true));
|
||||
this.grid.realItems.add(0, is);
|
||||
|
||||
if (grid.realItems.size() > Math.max(50, grid.rows * grid.columns)) {
|
||||
grid.realItems.remove(grid.realItems.size() - 1);
|
||||
if (this.grid.realItems.size() > Math.max(50, this.grid.rows * this.grid.columns)) {
|
||||
this.grid.realItems.remove(this.grid.realItems.size() - 1);
|
||||
}
|
||||
|
||||
grid.onItemsChanged();
|
||||
this.grid.onItemsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void resize(GuiContainer gui) {
|
||||
grid.setGridSize(x, y, w, h);
|
||||
grid.refresh(gui);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackMouseOver(int mousex, int mousey) {
|
||||
ItemPanelSlot slot = getSlotMouseOver(mousex, mousey);
|
||||
return slot == null ? null : slot.item;
|
||||
}
|
||||
|
||||
public ItemPanelSlot getSlotMouseOver(int mousex, int mousey) {
|
||||
return grid.getSlotMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
private void drawSplittingArea(int x, int y, int width, int height, int color) {
|
||||
|
||||
float alpha = (color >> 24 & 255) / 255.0F;
|
||||
float red = (color >> 16 & 255) / 255.0F;
|
||||
float green = (color >> 8 & 255) / 255.0F;
|
||||
float blue = (color & 255) / 255.0F;
|
||||
|
||||
GL11.glPushMatrix();
|
||||
|
||||
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
GL11.glEnable(GL11.GL_LINE_STIPPLE);
|
||||
GL11.glColor4f(red, green, blue, alpha);
|
||||
GL11.glLineWidth(2F);
|
||||
GL11.glLineStipple(2, (short) 0x00FF);
|
||||
|
||||
GL11.glBegin(GL11.GL_LINE_LOOP);
|
||||
|
||||
GL11.glVertex2i(x, y);
|
||||
GL11.glVertex2i(x + width, y);
|
||||
GL11.glVertex2i(x + width, y + height);
|
||||
GL11.glVertex2i(x, y + height);
|
||||
|
||||
GL11.glEnd();
|
||||
|
||||
GL11.glLineStipple(1, (short) 0xFFFF);
|
||||
GL11.glLineWidth(1F);
|
||||
GL11.glDisable(GL11.GL_LINE_STIPPLE);
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
GL11.glColor4f(1F, 1F, 1F, 1F);
|
||||
|
||||
GL11.glPopMatrix();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(int mousex, int mousey, int button, long heldTime) {
|
||||
|
||||
if (mouseDownSlot >= 0 && ItemPanels.itemPanel.draggedStack == null
|
||||
&& NEIClientUtils.getHeldItem() == null
|
||||
&& NEIClientConfig.hasSMPCounterPart()) {
|
||||
|
||||
ItemPanelSlot mouseOverSlot = getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (mouseOverSlot == null || mouseOverSlot.slotIndex != mouseDownSlot || heldTime > 500) {
|
||||
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(mouseDownSlot);
|
||||
mouseDownSlot = -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleClick(int mousex, int mousey, int button) {
|
||||
if (handleClickExt(mousex, mousey, button)) return true;
|
||||
|
||||
ItemPanelSlot hoverSlot = getSlotMouseOver(mousex, mousey);
|
||||
if (hoverSlot != null) {
|
||||
|
||||
if (button == 2) {
|
||||
|
||||
if (hoverSlot.item != null) {
|
||||
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(hoverSlot.slotIndex);
|
||||
}
|
||||
|
||||
} else {
|
||||
mouseDownSlot = hoverSlot.slotIndex;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseUp(int mousex, int mousey, int button) {
|
||||
ItemPanelSlot hoverSlot = getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (hoverSlot != null && hoverSlot.slotIndex == mouseDownSlot && ItemPanels.itemPanel.draggedStack == null) {
|
||||
ItemStack item = hoverSlot.item.copy();
|
||||
|
||||
if (NEIController.manager.window instanceof GuiRecipe || NEIClientUtils.shiftKey()
|
||||
|| !NEIClientConfig.canCheatItem(item)) {
|
||||
|
||||
if (button == 0) {
|
||||
GuiCraftingRecipe.openRecipeGui("item", item);
|
||||
} else if (button == 1) {
|
||||
GuiUsageRecipe.openRecipeGui("item", item);
|
||||
}
|
||||
|
||||
mouseDownSlot = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.slotIndex), button, -1);
|
||||
}
|
||||
|
||||
mouseDownSlot = -1;
|
||||
}
|
||||
|
||||
protected ItemStack getDraggedStackWithQuantity(int mouseDownSlot) {
|
||||
ItemStack stack = grid.getItem(mouseDownSlot);
|
||||
|
||||
if (stack != null) {
|
||||
int amount = NEIClientConfig.showItemQuantityWidget() ? NEIClientConfig.getItemQuantity() : 0;
|
||||
|
||||
if (amount == 0) {
|
||||
amount = stack.getMaxStackSize();
|
||||
}
|
||||
|
||||
return NEIServerUtils.copyStack(stack, amount);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,32 +2,23 @@ package codechicken.nei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ForkJoinWorkerThread;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.IIcon;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
|
||||
import codechicken.nei.ThreadOperationTimer.TimeoutException;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.search.TooltipFilter;
|
||||
import codechicken.nei.util.ItemUntranslator;
|
||||
|
||||
public class ItemList {
|
||||
|
||||
@@ -45,9 +36,6 @@ public class ItemList {
|
||||
public static final List<ItemFilterProvider> itemFilterers = new LinkedList<>();
|
||||
public static final List<ItemsLoadedCallback> loadCallbacks = new LinkedList<>();
|
||||
|
||||
private static final HashSet<Item> erroredItems = new HashSet<>();
|
||||
private static final HashSet<String> stackTraces = new HashSet<>();
|
||||
private static HashMap<ItemStack, Integer> ordering = new HashMap<>();
|
||||
/**
|
||||
* Unlike {@link LayoutManager#itemsLoaded}, this indicates whether item loading is actually finished or not.
|
||||
*/
|
||||
@@ -95,7 +83,13 @@ public class ItemList {
|
||||
public boolean matches(ItemStack item) {
|
||||
String displayName = EnumChatFormatting.getTextWithoutFormattingCodes(item.getDisplayName());
|
||||
|
||||
if (displayName != null && !displayName.isEmpty() && pattern.matcher(displayName).find()) {
|
||||
if (displayName != null && !displayName.isEmpty() && this.pattern.matcher(displayName).find()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
displayName = ItemUntranslator.getInstance().getItemStackDisplayName(item);
|
||||
|
||||
if (!displayName.isEmpty() && this.pattern.matcher(displayName).find()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -103,7 +97,15 @@ public class ItemList {
|
||||
displayName = EnumChatFormatting
|
||||
.getTextWithoutFormattingCodes(item.getItem().getItemStackDisplayName(item));
|
||||
|
||||
return displayName != null && !displayName.isEmpty() && pattern.matcher(displayName).find();
|
||||
if (displayName != null && !displayName.isEmpty() && this.pattern.matcher(displayName).find()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (String alias : ItemInfo.getAliases(item)) {
|
||||
if (this.pattern.matcher(alias).find()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -204,171 +206,6 @@ public class ItemList {
|
||||
return filters;
|
||||
}
|
||||
|
||||
public static final RestartableTask loadItems = new RestartableTask("NEI Item Loading") {
|
||||
|
||||
private void damageSearch(Item item, List<ItemStack> permutations) {
|
||||
HashSet<String> damageIconSet = new HashSet<>();
|
||||
for (int damage = 0; damage < 16; damage++) try {
|
||||
ItemStack itemstack = new ItemStack(item, 1, damage);
|
||||
IIcon icon = item.getIconIndex(itemstack);
|
||||
String name = getTooltip(itemstack);
|
||||
String s = name + "@" + (icon == null ? 0 : icon.hashCode());
|
||||
if (!damageIconSet.contains(s)) {
|
||||
damageIconSet.add(s);
|
||||
permutations.add(itemstack);
|
||||
}
|
||||
} catch (TimeoutException t) {
|
||||
throw t;
|
||||
} catch (Throwable t) {
|
||||
NEIServerUtils.logOnce(
|
||||
t,
|
||||
stackTraces,
|
||||
"Ommiting " + item + ":" + damage + " " + item.getClass().getSimpleName(),
|
||||
item.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private String getTooltip(ItemStack stack) {
|
||||
try {
|
||||
return String.join("\n", stack.getTooltip(Minecraft.getMinecraft().thePlayer, false));
|
||||
} catch (Throwable ignored) {}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private void updateOrdering(List<ItemStack> items) {
|
||||
ItemSorter.sort(items);
|
||||
|
||||
HashMap<ItemStack, Integer> newOrdering = new HashMap<>();
|
||||
|
||||
if (!CollapsibleItems.isEmpty()) {
|
||||
HashMap<Integer, Integer> groups = new HashMap<>();
|
||||
int orderIndex = 0;
|
||||
|
||||
for (ItemStack stack : items) {
|
||||
final int groupIndex = CollapsibleItems.getGroupIndex(stack);
|
||||
|
||||
if (groupIndex == -1) {
|
||||
newOrdering.put(stack, orderIndex++);
|
||||
} else {
|
||||
|
||||
if (!groups.containsKey(groupIndex)) {
|
||||
groups.put(groupIndex, orderIndex++);
|
||||
}
|
||||
|
||||
newOrdering.put(stack, groups.get(groupIndex));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int orderIndex = 0;
|
||||
|
||||
for (ItemStack stack : items) {
|
||||
newOrdering.put(stack, orderIndex++);
|
||||
}
|
||||
}
|
||||
|
||||
ItemList.ordering = newOrdering;
|
||||
}
|
||||
|
||||
private List<ItemStack> getPermutations(Item item) {
|
||||
final List<ItemStack> permutations = new LinkedList<>(ItemInfo.itemOverrides.get(item));
|
||||
|
||||
if (permutations.isEmpty()) {
|
||||
item.getSubItems(item, null, permutations);
|
||||
}
|
||||
|
||||
if (permutations.isEmpty()) {
|
||||
damageSearch(item, permutations);
|
||||
}
|
||||
|
||||
permutations.addAll(ItemInfo.itemVariants.get(item));
|
||||
|
||||
return permutations.stream()
|
||||
.filter(
|
||||
stack -> stack.getItem() != null && stack.getItem().delegate.name() != null
|
||||
&& !ItemInfo.isHidden(stack))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// For optimization it generate itemslist, permutations, orders & collapsibleitems
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void execute() {
|
||||
if (!NEIClientConfig.isEnabled()) return;
|
||||
|
||||
ThreadOperationTimer timer = getTimer(NEIClientConfig.getItemLoadingTimeout());
|
||||
LayoutManager.itemsLoaded = true;
|
||||
loadFinished = false;
|
||||
|
||||
SearchField.searchParser.clearCache();
|
||||
ItemSorter.instance.ordering.clear();
|
||||
CollapsibleItems.clearCache();
|
||||
TooltipFilter.clearCache();
|
||||
|
||||
List<ItemStack> items = new ArrayList<>();
|
||||
ListMultimap<Item, ItemStack> itemMap = ArrayListMultimap.create();
|
||||
ItemStackSet unique = new ItemStackSet();
|
||||
|
||||
timer.setLimit(NEIClientConfig.getItemLoadingTimeout());
|
||||
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);
|
||||
List<ItemStack> permutations = getPermutations(item);
|
||||
timer.reset();
|
||||
|
||||
for (ItemStack stack : permutations) {
|
||||
if (!unique.contains(stack)) {
|
||||
|
||||
synchronized (unique) {
|
||||
unique.add(stack);
|
||||
}
|
||||
|
||||
synchronized (items) {
|
||||
items.add(stack);
|
||||
}
|
||||
|
||||
CollapsibleItems.putItem(stack);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (itemMap) {
|
||||
itemMap.putAll(item, permutations);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
NEIServerConfig.logger.error("Removing item: {} 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;
|
||||
ItemList.items = items;
|
||||
ItemList.itemMap = itemMap;
|
||||
for (ItemsLoadedCallback callback : loadCallbacks) callback.itemsLoaded();
|
||||
|
||||
if (interrupted()) return;
|
||||
updateOrdering(ItemList.items);
|
||||
|
||||
new Thread(
|
||||
() -> ItemList.items.parallelStream().forEach(TooltipFilter::getSearchTooltip),
|
||||
"NEI Tooltip Filter Loader").start();
|
||||
|
||||
loadFinished = true;
|
||||
|
||||
SubsetWidget.updateHiddenItems();
|
||||
updateFilter.restart();
|
||||
}
|
||||
};
|
||||
|
||||
public static ForkJoinPool forkJoinPool;
|
||||
|
||||
static {
|
||||
@@ -388,36 +225,12 @@ public class ItemList {
|
||||
forkJoinPool = new ForkJoinPool(poolSize, factory, null, false);
|
||||
}
|
||||
|
||||
public static final RestartableTask updateFilter = new RestartableTask("NEI Item Filtering") {
|
||||
// The item list pipeline lives in ItemListLoader; these references are kept for backward compatibility.
|
||||
public static final RestartableTask loadItems = ItemListLoader.loadItems;
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
public static final RestartableTask refreshItems = ItemListLoader.refreshItems;
|
||||
|
||||
if (!loadFinished) return;
|
||||
ItemFilter filter = getItemListFilter();
|
||||
ArrayList<ItemStack> filtered;
|
||||
|
||||
try {
|
||||
filtered = ItemList.forkJoinPool.submit(
|
||||
() -> items.parallelStream().filter(filter::matches)
|
||||
.collect(Collectors.toCollection(ArrayList::new)))
|
||||
.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
filtered = new ArrayList<>();
|
||||
e.printStackTrace();
|
||||
stop();
|
||||
}
|
||||
|
||||
if (interrupted()) return;
|
||||
|
||||
Comparator<ItemStack> comparator = Comparator.comparingInt(ItemList.ordering::get);
|
||||
filtered.sort(comparator::compare);
|
||||
|
||||
if (interrupted()) return;
|
||||
|
||||
ItemPanel.updateItemList(filtered);
|
||||
}
|
||||
};
|
||||
public static final RestartableTask updateFilter = ItemListLoader.updateFilter;
|
||||
|
||||
/**
|
||||
* @deprecated Use updateFilter.restart()
|
||||
|
||||
@@ -0,0 +1,375 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraftforge.fluids.IFluidContainerItem;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
|
||||
import codechicken.nei.ItemList.ItemsLoadedCallback;
|
||||
import codechicken.nei.ThreadOperationTimer.TimeoutException;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.recipe.InformationHandler;
|
||||
import codechicken.nei.recipe.RecipeHandlerRef;
|
||||
import codechicken.nei.recipe.RepairRecipeHandler;
|
||||
import codechicken.nei.search.TooltipFilter;
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
|
||||
public class ItemListLoader {
|
||||
|
||||
private static final HashSet<Item> erroredItems = new HashSet<>();
|
||||
private static final HashSet<String> stackTraces = new HashSet<>();
|
||||
private static Map<ItemStack, Integer> ordering = new HashMap<>();
|
||||
|
||||
private ItemListLoader() {}
|
||||
|
||||
private static void damageSearch(Item item, List<ItemStack> permutations) {
|
||||
final Set<String> damageIconSet = new HashSet<>();
|
||||
final EntityPlayer player = Minecraft.getMinecraft().thePlayer;
|
||||
|
||||
for (int damage = 0; damage < 16; damage++) {
|
||||
try {
|
||||
final ItemStack itemstack = new ItemStack(item, 1, damage);
|
||||
final IIcon icon = item.getIconIndex(itemstack);
|
||||
final String key = itemstack.getDisplayName() + "@"
|
||||
+ (icon == null ? 0 : icon.hashCode())
|
||||
+ "@"
|
||||
+ getInformation(itemstack, player);
|
||||
|
||||
if (damageIconSet.add(key)) {
|
||||
permutations.add(itemstack);
|
||||
}
|
||||
} catch (TimeoutException t) {
|
||||
throw t;
|
||||
} catch (Throwable t) {
|
||||
NEIServerUtils.logOnce(
|
||||
t,
|
||||
stackTraces,
|
||||
"Ommiting " + item + ":" + damage + " " + item.getClass().getSimpleName(),
|
||||
item.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getInformation(ItemStack stack, EntityPlayer player) {
|
||||
try {
|
||||
final List<String> tooltip = new ArrayList<>();
|
||||
stack.getItem().addInformation(stack, player, tooltip, false);
|
||||
return String.join("\n", tooltip);
|
||||
} catch (Throwable ignored) {}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private static void updateOrdering(List<ItemStack> items) {
|
||||
final Map<ItemStack, Integer> newOrdering = new HashMap<>();
|
||||
|
||||
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++);
|
||||
}
|
||||
}
|
||||
|
||||
ordering = newOrdering;
|
||||
}
|
||||
|
||||
private static 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());
|
||||
}
|
||||
|
||||
private static void runChecked(ItemStack stack, Runnable action, String reason) {
|
||||
int hashOld = 0;
|
||||
if (stack.hasTagCompound()) {
|
||||
hashOld = stack.stackTagCompound.hashCode();
|
||||
}
|
||||
|
||||
action.run();
|
||||
|
||||
if (stack.hasTagCompound() && hashOld != stack.stackTagCompound.hashCode()) {
|
||||
FMLLog.warning(
|
||||
"NEI: Forced tag update with reason (" + reason + ") for " + stack + "(" + stack.getItem() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
private static void forceTagCompoundInitialization(ItemStack stack) {
|
||||
Item item = stack.getItem();
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
if (item instanceof IFluidContainerItem fluidItem) {
|
||||
runChecked(stack, () -> fluidItem.getFluid(stack), "getFluid");
|
||||
}
|
||||
runChecked(stack, () -> item.isDamaged(stack), "isDamaged");
|
||||
runChecked(stack, () -> item.getDamage(stack), "getDamage");
|
||||
runChecked(stack, () -> item.showDurabilityBar(stack), "showDurabilityBar");
|
||||
runChecked(stack, () -> item.getAttributeModifiers(stack), "getAttributeModifiers");
|
||||
runChecked(stack, () -> item.getDurabilityForDisplay(stack), "getDurabilityForDisplay");
|
||||
runChecked(stack, () -> item.getItemStackLimit(stack), "getItemStackLimit");
|
||||
runChecked(stack, () -> item.getToolClasses(stack), "getToolClasses");
|
||||
runChecked(stack, () -> item.getUnlocalizedNameInefficiently(stack), "getUnlocalizedNameInefficiently");
|
||||
runChecked(stack, () -> item.hasEffect(stack), "hasEffect");
|
||||
runChecked(stack, () -> item.getDigSpeed(stack, Blocks.stone, 0), "getDigSpeed");
|
||||
|
||||
/*
|
||||
* unused... for now runChecked(stack, () -> GameRegistry.getFuelValue(stack), "getFuelValue");
|
||||
* runChecked(stack, () -> item.getUnlocalizedName(stack), "getUnlocalizedName"); runChecked(stack, () ->
|
||||
* item.doesContainerItemLeaveCraftingGrid(stack), "doesContainerItemLeaveCraftingGrid"); runChecked(stack, ()
|
||||
* -> item.getItemUseAction(stack), "getItemUseAction"); runChecked(stack, () ->
|
||||
* item.getMaxItemUseDuration(stack), "getMaxItemUseDuration"); runChecked(stack, () ->
|
||||
* item.getPotionEffect(stack), "getPotionEffect"); runChecked(stack, () -> item.isPotionIngredient(stack),
|
||||
* "isPotionIngredient"); runChecked(stack, () -> item.getRarity(stack), "getRarity"); runChecked(stack, () ->
|
||||
* item.hasCustomEntity(stack), "hasCustomEntity"); runChecked(stack, () -> item.getSmeltingExperience(stack),
|
||||
* "getSmeltingExperience"); runChecked(stack, () -> item.getMaxDamage(stack), "getMaxDamage");
|
||||
* runChecked(stack, () -> item.getDamage(stack), "getDamage"); runChecked(stack, stack::isItemDamaged,
|
||||
* "isItemDamaged"); runChecked(stack, () -> item.hasEffect(stack, 0), "hasEffect"); runChecked(stack, () ->
|
||||
* item.getItemEnchantability(stack), "getItemEnchantability"); runChecked(stack, () ->
|
||||
* item.isBeaconPayment(stack), "isBeaconPayment"); runChecked(stack, () -> item.getDamage(stack), "getDamage");
|
||||
* runChecked(stack, () -> item.getDamage(stack), "getDamage"); runChecked(stack, () -> item.getDamage(stack),
|
||||
* "getDamage");
|
||||
*/
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static List<ItemStack> gatherItems(ThreadOperationTimer timer) {
|
||||
ItemSorter.instance.ordering.clear();
|
||||
|
||||
List<ItemStack> items = new ArrayList<>();
|
||||
ListMultimap<Item, ItemStack> itemMap = ArrayListMultimap.create();
|
||||
ItemStackSet unique = new ItemStackSet();
|
||||
|
||||
final List<Item> registryItems = new ArrayList<>();
|
||||
for (Item item : (Iterable<Item>) Item.itemRegistry) registryItems.add(item);
|
||||
|
||||
registryItems.parallelStream().forEach(item -> {
|
||||
if (item == null || item.delegate.name() == null || erroredItems.contains(item)) return;
|
||||
|
||||
try {
|
||||
timer.reset(item);
|
||||
List<ItemStack> permutations = getPermutations(item);
|
||||
timer.reset();
|
||||
|
||||
synchronized (itemMap) {
|
||||
itemMap.putAll(item, permutations);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
NEIServerConfig.logger.error(
|
||||
"Removing item: {} from list.\n{}: {}",
|
||||
item,
|
||||
t.getMessage(),
|
||||
Throwables.getStackTraceAsString(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 (!unique.contains(stack)) {
|
||||
unique.add(stack);
|
||||
items.add(stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ItemList.itemMap = itemMap;
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private static void buildItemCaches(List<ItemStack> items) {
|
||||
SearchField.searchParser.clearCache();
|
||||
TooltipFilter.clearCache();
|
||||
InformationHandler.clearCache();
|
||||
|
||||
items.parallelStream().forEach(stack -> {
|
||||
try {
|
||||
forceTagCompoundInitialization(stack);
|
||||
InformationHandler.populateStacks(stack);
|
||||
} catch (Throwable t) {
|
||||
NEIServerConfig.logger.error(
|
||||
"Failed to build caches for: {}\n{}: {}",
|
||||
stack,
|
||||
t.getMessage(),
|
||||
Throwables.getStackTraceAsString(t));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void indexCollapsibleItems(List<ItemStack> items) {
|
||||
CollapsibleItems.clearCache();
|
||||
items.parallelStream().forEach(CollapsibleItems::putItem);
|
||||
}
|
||||
|
||||
public static final RestartableTask loadItems = new RestartableTask("NEI Item Loading") {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
if (!NEIClientConfig.isEnabled() || NEIClientUtils.mc().thePlayer == null) return;
|
||||
|
||||
final ThreadOperationTimer timer = getTimer(NEIClientConfig.getItemLoadingTimeout());
|
||||
LayoutManager.itemsLoaded = true;
|
||||
ItemList.loadFinished = false;
|
||||
warmTooltips.stop();
|
||||
|
||||
List<ItemStack> items = gatherItems(timer);
|
||||
|
||||
if (interrupted()) return;
|
||||
buildItemCaches(items);
|
||||
indexCollapsibleItems(items);
|
||||
|
||||
if (interrupted()) return;
|
||||
ItemSorter.sort(items);
|
||||
|
||||
if (interrupted()) return;
|
||||
ItemList.items = items;
|
||||
for (ItemsLoadedCallback callback : ItemList.loadCallbacks) callback.itemsLoaded();
|
||||
|
||||
if (interrupted()) return;
|
||||
updateOrdering(ItemList.items);
|
||||
|
||||
ItemList.loadFinished = true;
|
||||
|
||||
RepairRecipeHandler.findRepairRecipesOnceParallel();
|
||||
RecipeHandlerRef.clearCache();
|
||||
FavoriteRecipes.reload();
|
||||
SubsetWidget.updateHiddenItems();
|
||||
updateFilter.restart();
|
||||
warmTooltips.restart();
|
||||
loadBookmarks.restart();
|
||||
}
|
||||
};
|
||||
|
||||
public static final RestartableTask warmTooltips = new RestartableTask("NEI Tooltip Caching") {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
if (!ItemList.loadFinished) return;
|
||||
// Use the common pool, not ItemList.forkJoinPool, so it does not queue behind updateFilter.
|
||||
ItemList.items.parallelStream().forEach(stack -> {
|
||||
if (interrupted()) return;
|
||||
try {
|
||||
TooltipFilter.getSearchTooltip(stack);
|
||||
} catch (Throwable ignored) {}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
public static final RestartableTask loadBookmarks = new RestartableTask("NEI Bookmark Loading") {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
ItemPanels.bookmarkPanel.load();
|
||||
}
|
||||
};
|
||||
|
||||
public static final RestartableTask refreshItems = new RestartableTask("NEI Item Reordering") {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
if (!ItemList.loadFinished) return;
|
||||
|
||||
final List<ItemStack> items = new ArrayList<>(ItemList.items);
|
||||
|
||||
indexCollapsibleItems(items);
|
||||
|
||||
if (interrupted()) return;
|
||||
ItemSorter.sort(items);
|
||||
|
||||
if (interrupted()) return;
|
||||
ItemList.items = items;
|
||||
updateOrdering(ItemList.items);
|
||||
|
||||
FavoriteRecipes.reload();
|
||||
SubsetWidget.updateHiddenItems();
|
||||
updateFilter.restart();
|
||||
loadBookmarks.restart();
|
||||
}
|
||||
};
|
||||
|
||||
public static final RestartableTask updateFilter = new RestartableTask("NEI Item Filtering") {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
|
||||
if (!ItemList.loadFinished) return;
|
||||
ItemFilter filter = ItemList.getItemListFilter();
|
||||
ArrayList<ItemStack> filtered;
|
||||
|
||||
try {
|
||||
filtered = ItemList.forkJoinPool.submit(
|
||||
() -> ItemList.items.parallelStream().filter(filter::matches)
|
||||
.collect(Collectors.toCollection(ArrayList::new)))
|
||||
.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
filtered = new ArrayList<>();
|
||||
e.printStackTrace();
|
||||
stop();
|
||||
}
|
||||
|
||||
if (interrupted()) return;
|
||||
|
||||
filtered.sort(Comparator.comparingInt(ordering::get));
|
||||
|
||||
if (interrupted()) return;
|
||||
|
||||
ItemPanel.updateItemList(filtered);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
import net.minecraft.entity.Entity;
|
||||
@@ -15,125 +17,313 @@ import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityMobSpawner;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.MinecraftForgeClient;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class ItemMobSpawner extends ItemBlock {
|
||||
|
||||
private static final Map<Integer, EntityLiving> entityHashMap = new HashMap<>();
|
||||
private static final Map<Integer, String> IDtoNameMap = new HashMap<>();
|
||||
public static int idPig;
|
||||
private static boolean loaded;
|
||||
private static final Map<Integer, EntityLiving> entityHashMap = new ConcurrentHashMap<>();
|
||||
private static final Map<Integer, String> IDtoNameMap = new ConcurrentHashMap<>();
|
||||
private static final Map<Class<? extends Entity>, String> ENTITY_CLASS_TO_NAME_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
public static int idPig = 90;
|
||||
private static volatile boolean loaded = false;
|
||||
|
||||
// For asm
|
||||
public static int placedX;
|
||||
public static int placedY;
|
||||
public static int placedZ;
|
||||
|
||||
public static void setLastPlacedPosition(int x, int y, int z) {
|
||||
placedX = x;
|
||||
placedY = y;
|
||||
placedZ = z;
|
||||
}
|
||||
|
||||
public static int[] getLastPlacedPosition() {
|
||||
return new int[] { placedX, placedY, placedZ };
|
||||
}
|
||||
|
||||
public ItemMobSpawner() {
|
||||
super(Blocks.mob_spawner);
|
||||
|
||||
hasSubtypes = true;
|
||||
MinecraftForgeClient.registerItemRenderer(this, new SpawnerRenderer());
|
||||
}
|
||||
|
||||
/**
|
||||
* These are ASM translated from BlockMobSpawner
|
||||
*/
|
||||
public static int placedX;
|
||||
|
||||
public static int placedY;
|
||||
public static int placedZ;
|
||||
|
||||
@Override
|
||||
public IIcon getIconFromDamage(int par1) {
|
||||
public IIcon getIconFromDamage(int meta) {
|
||||
return Blocks.mob_spawner.getBlockTextureFromSide(0);
|
||||
}
|
||||
|
||||
public boolean onItemUse(ItemStack itemstack, EntityPlayer entityplayer, World world, int x, int y, int z, int par7,
|
||||
float par8, float par9, float par10) {
|
||||
if (super.onItemUse(itemstack, entityplayer, world, x, y, z, par7, par8, par9, par10) && world.isRemote) {
|
||||
TileEntityMobSpawner tileentitymobspawner = (TileEntityMobSpawner) world
|
||||
.getTileEntity(placedX, placedY, placedZ);
|
||||
if (tileentitymobspawner != null) {
|
||||
setDefaultTag(itemstack);
|
||||
String mobtype = IDtoNameMap.get(itemstack.getItemDamage());
|
||||
if (mobtype != null) {
|
||||
NEICPH.sendMobSpawnerID(placedX, placedY, placedZ, mobtype);
|
||||
tileentitymobspawner.func_145881_a().setEntityName(mobtype);
|
||||
@Override
|
||||
public boolean onItemUse(ItemStack itemstack, EntityPlayer entityplayer, World world, int x, int y, int z, int side,
|
||||
float hitX, float hitY, float hitZ) {
|
||||
int targetX = x;
|
||||
int targetY = y;
|
||||
int targetZ = z;
|
||||
|
||||
if (!world.getBlock(x, y, z).isReplaceable(world, x, y, z)) {
|
||||
ForgeDirection direction = ForgeDirection.getOrientation(side);
|
||||
targetX += direction.offsetX;
|
||||
targetY += direction.offsetY;
|
||||
targetZ += direction.offsetZ;
|
||||
}
|
||||
|
||||
placedX = targetX;
|
||||
placedY = targetY;
|
||||
placedZ = targetZ;
|
||||
|
||||
String mobType = getMobTypeFromItemStack(itemstack);
|
||||
|
||||
boolean placed = super.onItemUse(itemstack, entityplayer, world, x, y, z, side, hitX, hitY, hitZ);
|
||||
|
||||
if (placed) {
|
||||
TileEntity tileEntity = world.getTileEntity(targetX, targetY, targetZ);
|
||||
|
||||
if (tileEntity instanceof TileEntityMobSpawner spawner && mobType != null) {
|
||||
spawner.func_145881_a().setEntityName(mobType);
|
||||
|
||||
if (!world.isRemote) {
|
||||
world.markBlockForUpdate(targetX, targetY, targetZ);
|
||||
NEICPH.sendMobSpawnerID(targetX, targetY, targetZ, mobType);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getMobTypeFromItemStack(ItemStack stack) {
|
||||
int meta = getValidMetaData(stack);
|
||||
return IDtoNameMap.get(meta);
|
||||
}
|
||||
|
||||
private int getValidMetaData(ItemStack stack) {
|
||||
int meta = stack.getItemDamage();
|
||||
if (meta == 0 || !IDtoNameMap.containsKey(meta)) {
|
||||
return idPig;
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
public void addInformation(ItemStack itemstack, EntityPlayer par2EntityPlayer, List<String> list, boolean par4) {
|
||||
setDefaultTag(itemstack);
|
||||
int meta = itemstack.getItemDamage();
|
||||
if (meta == 0) {
|
||||
meta = idPig;
|
||||
public void addInformation(ItemStack itemstack, EntityPlayer player, List<String> tooltip, boolean advanced) {
|
||||
int meta = getValidMetaData(itemstack);
|
||||
EntityLiving entity = getEntity(meta);
|
||||
String mobName = IDtoNameMap.get(meta);
|
||||
|
||||
if (entity != null && mobName != null) {
|
||||
EnumChatFormatting color = (entity instanceof IMob) ? EnumChatFormatting.DARK_RED
|
||||
: EnumChatFormatting.DARK_AQUA;
|
||||
tooltip.add(color + mobName);
|
||||
}
|
||||
Entity e = getEntity(meta);
|
||||
list.add("\u00A7" + (e instanceof IMob ? "4" : "3") + IDtoNameMap.get(meta));
|
||||
}
|
||||
|
||||
public static EntityLiving getEntity(int ID) {
|
||||
EntityLiving e = entityHashMap.get(ID);
|
||||
if (e == null) {
|
||||
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) {
|
||||
if (clazz == null)
|
||||
NEIClientConfig.logger.error("Null class for entity (" + ID + ", " + IDtoNameMap.get(ID));
|
||||
else NEIClientConfig.logger.error("Error creating instance of entity: " + clazz.getName(), t);
|
||||
e = getEntity(idPig);
|
||||
public static EntityLiving getEntity(int id) {
|
||||
EntityLiving cached = entityHashMap.get(id);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
loadSpawners();
|
||||
|
||||
Class<?> entityClass = EntityList.IDtoClassMapping.get(id);
|
||||
World world = NEIClientUtils.mc() != null ? NEIClientUtils.mc().theWorld : null;
|
||||
|
||||
if (isInvalidEntityClass(entityClass)) {
|
||||
return cacheFallback(id);
|
||||
}
|
||||
|
||||
EntityLiving entity = createEntityInstance(entityClass, world, id);
|
||||
if (entity != null) {
|
||||
entityHashMap.put(id, entity);
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
private static boolean isInvalidEntityClass(Class<?> entityClass) {
|
||||
if (entityClass == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int modifiers = entityClass.getModifiers();
|
||||
if (Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers)) {
|
||||
NEIClientConfig.logger.warn("Skipping abstract/interface entity class: {}", entityClass.getName());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!EntityLiving.class.isAssignableFrom(entityClass)) {
|
||||
NEIClientConfig.logger.warn("Skipping non-EntityLiving class: {}", entityClass.getName());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static EntityLiving createEntityInstance(Class<?> entityClass, World world, int id) {
|
||||
if (entityClass == null || world == null) {
|
||||
NEIClientConfig.logger.debug("World or entity class is null, using fallback for ID: {}", id);
|
||||
return getFallbackEntity(id);
|
||||
}
|
||||
|
||||
try {
|
||||
Class<? extends EntityLiving> livingClass = (Class<? extends EntityLiving>) entityClass;
|
||||
return livingClass.getConstructor(World.class).newInstance(world);
|
||||
} catch (Throwable t) {
|
||||
logEntityCreationError(entityClass, id, t);
|
||||
return getFallbackEntity(id);
|
||||
}
|
||||
}
|
||||
|
||||
private static void logEntityCreationError(Class<?> entityClass, int id, Throwable t) {
|
||||
String entityName = IDtoNameMap.getOrDefault(id, "unknown");
|
||||
if (entityClass == null) {
|
||||
NEIClientConfig.logger
|
||||
.error("Failed to create entity instance: Class is null for ID {}, Name {}", id, entityName, t);
|
||||
} else {
|
||||
NEIClientConfig.logger.error(
|
||||
"Failed to create instance of entity: Class {}, ID {}, Name {}",
|
||||
entityClass.getName(),
|
||||
id,
|
||||
entityName,
|
||||
t);
|
||||
}
|
||||
}
|
||||
|
||||
private static EntityLiving cacheFallback(int id) {
|
||||
EntityLiving fallback = getFallbackEntity(id);
|
||||
if (fallback != null) {
|
||||
entityHashMap.put(id, fallback);
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
private static EntityLiving getFallbackEntity(int originalId) {
|
||||
EntityLiving pig = entityHashMap.get(idPig);
|
||||
if (pig == null) {
|
||||
World world = NEIClientUtils.mc() != null ? NEIClientUtils.mc().theWorld : null;
|
||||
|
||||
if (world != null) {
|
||||
try {
|
||||
pig = new EntityPig(world);
|
||||
entityHashMap.put(idPig, pig);
|
||||
NEIClientConfig.logger.debug("Created fallback pig entity for ID: {}", originalId);
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger
|
||||
.error("Failed to create fallback pig entity for original ID: {}", originalId, e);
|
||||
}
|
||||
} else {
|
||||
NEIClientConfig.logger.warn("World is null, cannot create fallback entity for ID: {}", originalId);
|
||||
}
|
||||
entityHashMap.put(ID, e);
|
||||
}
|
||||
return e;
|
||||
|
||||
return pig;
|
||||
}
|
||||
|
||||
public static void clearEntityReferences(World newWorld) {
|
||||
entityHashMap.values().removeIf(e -> e.worldObj != newWorld);
|
||||
public static void clearEntityReferences() {
|
||||
entityHashMap.clear();
|
||||
NEIClientConfig.logger.debug("Cleared all entity references from cache");
|
||||
}
|
||||
|
||||
private void setDefaultTag(ItemStack itemstack) {
|
||||
if (!IDtoNameMap.containsKey(itemstack.getItemDamage())) itemstack.setItemDamage(idPig);
|
||||
}
|
||||
public static void loadSpawners() {
|
||||
if (loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
public static void loadSpawners(World world) {
|
||||
if (loaded) return;
|
||||
loaded = true;
|
||||
Map<Class<? extends Entity>, String> classToStringMapping = EntityList.classToStringMapping;
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<Class<? extends Entity>, Integer> classToIDMapping = (Map<Class<? extends Entity>, Integer>) EntityList.classToIDMapping;
|
||||
for (Class<? extends Entity> eclass : classToStringMapping.keySet()) {
|
||||
if (!EntityLiving.class.isAssignableFrom(eclass)) continue;
|
||||
synchronized (ItemMobSpawner.class) {
|
||||
try {
|
||||
EntityLiving entityliving = (EntityLiving) eclass.getConstructor(new Class[] { World.class })
|
||||
.newInstance(world);
|
||||
entityliving.isChild();
|
||||
for (Map.Entry<Class<? extends Entity>, String> entry : EntityList.classToStringMapping.entrySet()) {
|
||||
|
||||
int id = classToIDMapping.get(eclass);
|
||||
String name = classToStringMapping.get(eclass);
|
||||
Class<? extends Entity> clazz = entry.getKey();
|
||||
String name = entry.getValue();
|
||||
|
||||
if (name.equals("EnderDragon")) continue;
|
||||
if (shouldRegisterEntity(clazz, name)) {
|
||||
Integer id = (Integer) EntityList.classToIDMapping.get(clazz);
|
||||
if (id != null) {
|
||||
IDtoNameMap.put(id, name);
|
||||
ENTITY_CLASS_TO_NAME_CACHE.put(clazz, name);
|
||||
|
||||
IDtoNameMap.put(id, name);
|
||||
if ("Pig".equals(name)) {
|
||||
idPig = id;
|
||||
NEIClientConfig.logger.debug("Set pig entity ID to: {}", id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
loaded = true;
|
||||
NEIClientConfig.logger.info("Loaded {} spawner entity mappings", IDtoNameMap.size());
|
||||
|
||||
if (name.equals("Pig")) idPig = id;
|
||||
} catch (Throwable ignored) {}
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.error("Error loading spawners from entity list", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldRegisterEntity(Class<? extends Entity> clazz, String name) {
|
||||
if (clazz == null || name == null || name.trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IDtoNameMap.entrySet()
|
||||
.removeIf(e -> getEntity(e.getKey()).getClass() == EntityPig.class && !e.getValue().equals("Pig"));
|
||||
if (!EntityLiving.class.isAssignableFrom(clazz)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ("EnderDragon".equals(name) || "Giant".equals(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getSubItems(Item item, CreativeTabs tab, List<ItemStack> list) {
|
||||
if (!NEIClientConfig.hasSMPCounterPart()) list.add(new ItemStack(item));
|
||||
else for (int i : IDtoNameMap.keySet()) list.add(new ItemStack(item, 1, i));
|
||||
if (!NEIClientConfig.hasSMPCounterPart()) {
|
||||
list.add(new ItemStack(item));
|
||||
} else {
|
||||
loadSpawners();
|
||||
for (int id : IDtoNameMap.keySet()) {
|
||||
ItemStack stack = new ItemStack(item, 1, id);
|
||||
list.add(stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getEntityNameForMeta(int meta) {
|
||||
loadSpawners();
|
||||
return IDtoNameMap.getOrDefault(meta, IDtoNameMap.getOrDefault(idPig, "Pig"));
|
||||
}
|
||||
|
||||
public static boolean isValidEntityMeta(int meta) {
|
||||
loadSpawners();
|
||||
return IDtoNameMap.containsKey(meta) || meta == 0;
|
||||
}
|
||||
|
||||
public static Map<Integer, String> getRegisteredSpawnerEntities() {
|
||||
loadSpawners();
|
||||
return Collections.unmodifiableMap(IDtoNameMap);
|
||||
}
|
||||
|
||||
public static boolean isEntityValidForSpawner(Class<? extends Entity> entityClass) {
|
||||
if (entityClass == null) return false;
|
||||
|
||||
String name = ENTITY_CLASS_TO_NAME_CACHE.get(entityClass);
|
||||
if (name == null) {
|
||||
name = EntityList.classToStringMapping.get(entityClass);
|
||||
}
|
||||
|
||||
return name != null && shouldRegisterEntity(entityClass, name);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,18 @@
|
||||
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.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.ItemsPanelGrid.ItemsPanelGridSlot;
|
||||
import codechicken.nei.util.NEIMouseUtils;
|
||||
|
||||
public class ItemPanel extends PanelWidget {
|
||||
public class ItemPanel extends PanelWidget<ItemsPanelGrid> {
|
||||
|
||||
/**
|
||||
* Backwards compat :-/
|
||||
@@ -41,285 +32,56 @@ public class ItemPanel extends PanelWidget {
|
||||
return super.getStackMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
public ItemHistoryPanel historyPanel;
|
||||
public Button toggleGroups;
|
||||
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 MaskMetadata {
|
||||
|
||||
public int groupIndex = -1;
|
||||
public String displayName = "";
|
||||
public boolean extended = false;
|
||||
|
||||
public Color bgColor = null;
|
||||
public Color color = null;
|
||||
|
||||
public boolean left = false;
|
||||
public boolean top = false;
|
||||
public boolean right = false;
|
||||
public boolean bottom = false;
|
||||
|
||||
}
|
||||
|
||||
protected static class ItemPanelGrid extends ItemsGrid {
|
||||
|
||||
public ArrayList<ItemStack> newItems;
|
||||
public ArrayList<ItemStack> rawItems;
|
||||
|
||||
protected final HashMap<Integer, List<ItemStack>> groupItems = new HashMap<>();
|
||||
protected final HashMap<Integer, MaskMetadata> maskMetadata = new HashMap<>();
|
||||
protected boolean forceExpand = false;
|
||||
|
||||
public void setItems(ArrayList<ItemStack> items) {
|
||||
newItems = items;
|
||||
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 (this.newItems != null) {
|
||||
this.groupItems.clear();
|
||||
this.forceExpand = false;
|
||||
protected static ItemPanelSlot of(ItemsPanelGridSlot slot) {
|
||||
|
||||
if (!CollapsibleItems.isEmpty() && !this.newItems.isEmpty()) {
|
||||
final Set<Integer> groups = new HashSet<>();
|
||||
boolean outsideGroup = false;
|
||||
|
||||
this.realItems = new ArrayList<>();
|
||||
this.rawItems = new ArrayList<>(this.newItems);
|
||||
|
||||
for (ItemStack stack : this.newItems) {
|
||||
final int groupIndex = CollapsibleItems.getGroupIndex(stack);
|
||||
|
||||
if (groupIndex == -1) {
|
||||
this.realItems.add(stack);
|
||||
outsideGroup = true;
|
||||
} else {
|
||||
|
||||
if (!groups.contains(groupIndex) || CollapsibleItems.isExpanded(groupIndex)) {
|
||||
this.realItems.add(stack);
|
||||
groups.add(groupIndex);
|
||||
}
|
||||
|
||||
if (!this.groupItems.containsKey(groupIndex)) {
|
||||
this.groupItems.put(groupIndex, new ArrayList<>());
|
||||
}
|
||||
|
||||
this.groupItems.get(groupIndex).add(stack);
|
||||
}
|
||||
}
|
||||
|
||||
// automatically opens if there are elements from only one group
|
||||
if (!outsideGroup && groups.size() == 1) {
|
||||
this.realItems = new ArrayList<>(this.newItems);
|
||||
this.forceExpand = true;
|
||||
}
|
||||
} else {
|
||||
this.realItems = new ArrayList<>(this.newItems);
|
||||
}
|
||||
|
||||
this.newItems = null;
|
||||
onItemsChanged();
|
||||
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 List<Integer> getMask() {
|
||||
final boolean updateBorders = this.gridMask == null;
|
||||
final List<Integer> mask = super.getMask();
|
||||
|
||||
if (updateBorders) {
|
||||
calculateGroupBorders(mask);
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
protected void calculateGroupBorders(List<Integer> mask) {
|
||||
this.maskMetadata.clear();
|
||||
|
||||
if (mask.isEmpty() || this.groupItems.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final HashMap<Integer, Integer> maskGroup = new HashMap<>();
|
||||
final Color collapsedColor = new Color(
|
||||
NEIClientConfig.getSetting("inventory.collapsibleItems.collapsedColor").getHexValue(),
|
||||
true);
|
||||
final Color expandedColor = new Color(
|
||||
NEIClientConfig.getSetting("inventory.collapsibleItems.expandedColor").getHexValue(),
|
||||
true);
|
||||
|
||||
for (int slotIndex = 0; slotIndex < mask.size(); slotIndex++) {
|
||||
if (mask.get(slotIndex) == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int idx = mask.get(slotIndex);
|
||||
maskGroup.put(idx, CollapsibleItems.getGroupIndex(getItem(idx)));
|
||||
}
|
||||
|
||||
for (int slotIndex = 0; slotIndex < mask.size(); slotIndex++) {
|
||||
if (mask.get(slotIndex) == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int idx = mask.get(slotIndex);
|
||||
int groupIndex = maskGroup.get(idx);
|
||||
|
||||
if (groupIndex == -1 || this.groupItems.get(groupIndex).size() == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int column = slotIndex % this.columns;
|
||||
int row = slotIndex / this.columns;
|
||||
int prevSlotIndex = (row - 1) * this.columns + column;
|
||||
int nextSlotIndex = (row + 1) * this.columns + column;
|
||||
MaskMetadata metadata = new MaskMetadata();
|
||||
|
||||
metadata.groupIndex = groupIndex;
|
||||
metadata.displayName = CollapsibleItems.getDisplayName(groupIndex);
|
||||
metadata.extended = this.forceExpand || CollapsibleItems.isExpanded(groupIndex);
|
||||
metadata.bgColor = metadata.extended ? expandedColor : collapsedColor;
|
||||
metadata.color = darkerColor(metadata.bgColor);
|
||||
metadata.left = column == 0 || idx == 0
|
||||
|| mask.get(slotIndex - 1) == null
|
||||
|| maskGroup.getOrDefault(idx - 1, -1) != groupIndex;
|
||||
metadata.right = column == this.columns - 1 || maskGroup.getOrDefault(idx + 1, -1) != groupIndex;
|
||||
|
||||
if (prevSlotIndex >= 0) {
|
||||
Integer previdx = mask.get(prevSlotIndex);
|
||||
metadata.top = previdx == null || maskGroup.getOrDefault(previdx, -1) != groupIndex;
|
||||
} else {
|
||||
metadata.top = true;
|
||||
}
|
||||
|
||||
if (nextSlotIndex < mask.size()) {
|
||||
Integer nextidx = mask.get(nextSlotIndex);
|
||||
metadata.bottom = nextidx == null || maskGroup.getOrDefault(nextidx, -1) != groupIndex;
|
||||
} else {
|
||||
metadata.bottom = true;
|
||||
}
|
||||
|
||||
this.maskMetadata.put(idx, metadata);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeDrawItems(int mousex, int mousey, @Nullable ItemPanelSlot focused) {
|
||||
final List<Integer> mask = getMask();
|
||||
|
||||
super.beforeDrawItems(mousex, mousey, focused);
|
||||
|
||||
for (int i = 0; i < mask.size(); i++) {
|
||||
if (mask.get(i) != null) {
|
||||
drawBorder(mask.get(i), getSlotRect(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void drawBorder(int slotIdx, Rectangle4i rect) {
|
||||
final MaskMetadata metadata = this.maskMetadata.get(slotIdx);
|
||||
|
||||
if (metadata != null) {
|
||||
final float LINE_WIDTH = 0.75f;
|
||||
|
||||
drawRect(rect.x, rect.y, rect.w, rect.h, metadata.bgColor);
|
||||
|
||||
if (metadata.left) {
|
||||
float leftBottom = metadata.bottom ? -LINE_WIDTH : 0;
|
||||
drawRect(rect.x, rect.y, LINE_WIDTH, rect.h + leftBottom, metadata.color);
|
||||
}
|
||||
|
||||
if (metadata.right) {
|
||||
float rightTop = metadata.top ? LINE_WIDTH : 0;
|
||||
drawRect(rect.x + rect.w, rect.y - rightTop, LINE_WIDTH, rect.h + rightTop, metadata.color);
|
||||
}
|
||||
|
||||
if (metadata.top) {
|
||||
drawRect(rect.x, rect.y - LINE_WIDTH, rect.w, LINE_WIDTH, metadata.color);
|
||||
}
|
||||
|
||||
if (metadata.bottom) {
|
||||
drawRect(rect.x, rect.y + rect.h - LINE_WIDTH, rect.w, LINE_WIDTH, metadata.color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Color darkerColor(Color color) {
|
||||
return new Color(
|
||||
color.getRed(),
|
||||
color.getGreen(),
|
||||
color.getBlue(),
|
||||
Math.min((int) (color.getAlpha() + (255f / 5) * 2), 255));
|
||||
}
|
||||
|
||||
private static void drawRect(double left, double top, double width, double height, Color color) {
|
||||
Tessellator tessellator = Tessellator.instance;
|
||||
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
OpenGlHelper.glBlendFunc(770, 771, 1, 0);
|
||||
GL11.glColor4f(
|
||||
color.getRed() / 255f,
|
||||
color.getGreen() / 255f,
|
||||
color.getBlue() / 255f,
|
||||
color.getAlpha() / 255f);
|
||||
tessellator.startDrawingQuads();
|
||||
tessellator.addVertex(left, top + height, 0.0D);
|
||||
tessellator.addVertex(left + width, top + height, 0.0D);
|
||||
tessellator.addVertex(left + width, top, 0.0D);
|
||||
tessellator.addVertex(left, top, 0.0D);
|
||||
tessellator.draw();
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
GL11.glDisable(GL11.GL_BLEND);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawItem(Rectangle4i rect, int slotIdx) {
|
||||
final MaskMetadata metadata = this.maskMetadata.get(slotIdx);
|
||||
|
||||
if (metadata != null && !metadata.extended) {
|
||||
final List<ItemStack> groupItems = this.groupItems.get(metadata.groupIndex);
|
||||
|
||||
GuiContainerManager.drawItems.zLevel -= 10F;
|
||||
GuiContainerManager.drawItem(rect.x + 1, rect.y - 1, groupItems.get(groupItems.size() - 1), true, "");
|
||||
GuiContainerManager.drawItems.zLevel += 10F;
|
||||
|
||||
GuiContainerManager.drawItem(rect.x - 1, rect.y + 1, getItem(slotIdx), true, "");
|
||||
} else {
|
||||
super.drawItem(rect, slotIdx);
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
final ItemsPanelGrid grid = ItemPanels.itemPanel.getGrid();
|
||||
|
||||
if (grid.rawItems.size() != newItems.size()) {
|
||||
grid.setPage(0);
|
||||
}
|
||||
|
||||
grid.setItems(newItems);
|
||||
ItemPanels.itemPanel.realItems = newItems;
|
||||
}
|
||||
|
||||
@@ -329,6 +91,11 @@ public class ItemPanel extends PanelWidget {
|
||||
|
||||
toggleGroups = new Button("G") {
|
||||
|
||||
@Override
|
||||
public String getRenderLabel() {
|
||||
return NEIClientUtils.translate("itempanel.collapsed.button");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getButtonTip() {
|
||||
return NEIClientUtils.translate("itempanel.collapsed.button.tip");
|
||||
@@ -342,36 +109,41 @@ public class ItemPanel extends PanelWidget {
|
||||
}
|
||||
};
|
||||
|
||||
historyPanel = new ItemHistoryPanel();
|
||||
}
|
||||
|
||||
@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()));
|
||||
}
|
||||
|
||||
protected String getPositioningSettingName() {
|
||||
return "world.panels.items";
|
||||
}
|
||||
@Override
|
||||
public Rectangle4i calculateBounds(GuiContainer gui) {
|
||||
final int maxWidth = (gui.width - 176) / 2 - PADDING * 2;
|
||||
final int maxHeight = gui.height - PADDING * 2;
|
||||
final int freeSpace = (gui.width - gui.xSize) / 2 - PADDING * 2;
|
||||
|
||||
public int getMarginLeft(GuiContainer gui) {
|
||||
return (gui.width + gui.xSize) / 2 + PADDING;
|
||||
}
|
||||
final int paddingLeft = (int) Math
|
||||
.ceil(maxWidth * NEIClientConfig.getSetting("world.panels.items.left").getIntValue() / 100000.0);
|
||||
final int paddingTop = (int) Math
|
||||
.ceil(maxHeight * NEIClientConfig.getSetting("world.panels.items.top").getIntValue() / 100000.0);
|
||||
final int paddingRight = (int) Math
|
||||
.ceil(maxWidth * NEIClientConfig.getSetting("world.panels.items.right").getIntValue() / 100000.0);
|
||||
final int paddingBottom = (int) Math
|
||||
.ceil(maxHeight * NEIClientConfig.getSetting("world.panels.items.bottom").getIntValue() / 100000.0);
|
||||
|
||||
public int getMarginTop(GuiContainer gui) {
|
||||
return PADDING;
|
||||
}
|
||||
final int width = Math.max(
|
||||
ItemsGrid.SLOT_SIZE,
|
||||
snapDownToMultiple(
|
||||
Math.min(freeSpace - paddingRight, maxWidth - paddingLeft - paddingRight),
|
||||
ItemsGrid.SLOT_SIZE));
|
||||
final int height = Math.max(ItemsGrid.SLOT_SIZE, maxHeight - paddingTop - paddingBottom);
|
||||
|
||||
public int getWidth(GuiContainer gui) {
|
||||
return gui.width - (gui.xSize + gui.width) / 2 - PADDING * 2;
|
||||
}
|
||||
|
||||
public int getHeight(GuiContainer gui) {
|
||||
return gui.height - getMarginTop(gui) - PADDING;
|
||||
return new Rectangle4i(gui.width - width - PADDING - paddingRight, paddingTop + PADDING, width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -387,26 +159,38 @@ public class ItemPanel extends PanelWidget {
|
||||
}
|
||||
|
||||
protected int resizeFooter(GuiContainer gui) {
|
||||
if (!NEIClientConfig.showItemQuantityWidget() && NEIClientConfig.isSearchWidgetCentered()
|
||||
&& !NEIClientConfig.showHistoryPanelWidget()) {
|
||||
int footerY = y + h;
|
||||
int footerHeight = 0;
|
||||
|
||||
if (grid.getPerPage() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.showItemQuantityWidget() || !NEIClientConfig.isSearchWidgetCentered()) {
|
||||
footerY = LayoutManager.quantity.y;
|
||||
footerHeight = LayoutManager.quantity.h + PanelWidget.PADDING;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.showHistoryPanelWidget()) {
|
||||
historyPanel.x = x;
|
||||
historyPanel.w = w;
|
||||
historyPanel.h = ItemsGrid.SLOT_SIZE * NEIClientConfig.getIntSetting("inventory.history.useRows");
|
||||
|
||||
if (NEIClientConfig.showItemQuantityWidget() || !NEIClientConfig.isSearchWidgetCentered()) {
|
||||
historyPanel.y = LayoutManager.quantity.y - historyPanel.h - PanelWidget.PADDING;
|
||||
return LayoutManager.quantity.h + historyPanel.h + PanelWidget.PADDING * 2;
|
||||
} else {
|
||||
historyPanel.y = y + h - historyPanel.h;
|
||||
return historyPanel.h + PanelWidget.PADDING;
|
||||
if (historyPanel.setPanelWidth(w) != 0) {
|
||||
footerY = historyPanel.y = footerY - historyPanel.h;
|
||||
footerHeight += historyPanel.h;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (NEIClientConfig.showCraftablesPanelWidget()) {
|
||||
craftablesPanel.x = x;
|
||||
|
||||
if (craftablesPanel.setPanelWidth(w) != 0) {
|
||||
footerY = craftablesPanel.y = footerY - craftablesPanel.h;
|
||||
footerHeight += craftablesPanel.h;
|
||||
}
|
||||
}
|
||||
|
||||
return LayoutManager.quantity.h + PanelWidget.PADDING;
|
||||
return footerHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -414,92 +198,86 @@ public class ItemPanel extends PanelWidget {
|
||||
super.setVisible();
|
||||
|
||||
if (grid.getPerPage() > 0) {
|
||||
|
||||
if (!CollapsibleItems.isEmpty() && !grid.isEmpty()) {
|
||||
LayoutManager.addWidget(toggleGroups);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.showHistoryPanelWidget() && (!grid.isEmpty() || !historyPanel.isEmpty())) {
|
||||
if (NEIClientConfig.showCraftablesPanelWidget()) {
|
||||
LayoutManager.addWidget(craftablesPanel);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.showHistoryPanelWidget()) {
|
||||
LayoutManager.addWidget(historyPanel);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(GuiContainer gui) {
|
||||
super.resize(gui);
|
||||
historyPanel.resize(gui);
|
||||
this.historyPanel.resize(gui);
|
||||
this.craftablesPanel.resize(gui);
|
||||
}
|
||||
|
||||
protected ItemStack getDraggedStackWithQuantity(int mouseDownSlot) {
|
||||
ItemStack stack = grid.getItem(mouseDownSlot);
|
||||
|
||||
if (stack != null) {
|
||||
int amount = NEIClientConfig.showItemQuantityWidget() ? NEIClientConfig.getItemQuantity() : 0;
|
||||
|
||||
if (amount == 0) {
|
||||
amount = stack.getMaxStackSize();
|
||||
}
|
||||
|
||||
return NEIServerUtils.copyStack(stack, amount);
|
||||
}
|
||||
|
||||
return null;
|
||||
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) {
|
||||
final ItemPanelGrid panelGrid = ((ItemPanelGrid) this.grid);
|
||||
public List<String> handleItemTooltip(ItemStack itemstack, int mousex, int mousey, List<String> currenttip) {
|
||||
|
||||
if (!panelGrid.forceExpand && !NEIClientConfig.isHidden() && !currenttip.isEmpty()) {
|
||||
final ItemPanelSlot hoverSlot = getSlotMouseOver(mousex, mousey);
|
||||
if (!this.grid.forceExpand && !currenttip.isEmpty()) {
|
||||
final ItemsPanelGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (hoverSlot != null) {
|
||||
final MaskMetadata metadata = panelGrid.maskMetadata.get(hoverSlot.slotIndex);
|
||||
|
||||
if (metadata != null) {
|
||||
final List<ItemStack> items = panelGrid.groupItems.get(metadata.groupIndex);
|
||||
|
||||
if (NEIClientConfig.getBooleanSetting("inventory.collapsibleItems.customName") && !metadata.extended
|
||||
&& !"".equals(metadata.displayName)) {
|
||||
currenttip.clear();
|
||||
currenttip.add(metadata.displayName + GuiDraw.TOOLTIP_LINESPACE);
|
||||
}
|
||||
|
||||
if (items != null && items.size() > 1) {
|
||||
String message = metadata.extended ? "itempanel.collapsed.hint.collapse"
|
||||
: "itempanel.collapsed.hint.expand";
|
||||
currenttip.add(
|
||||
1,
|
||||
EnumChatFormatting.GRAY + NEIClientUtils.translate(message, items.size())
|
||||
+ EnumChatFormatting.RESET);
|
||||
}
|
||||
}
|
||||
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 super.handleItemTooltip(gui, itemstack, mousex, mousey, currenttip);
|
||||
return super.handleItemTooltip(itemstack, mousex, mousey, currenttip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleClick(int mousex, int mousey, int button) {
|
||||
final ItemPanelGrid panelGrid = ((ItemPanelGrid) this.grid);
|
||||
|
||||
if (NEIClientUtils.altKey() && button == 0 && !panelGrid.forceExpand) {
|
||||
final ItemPanelSlot hoverSlot = grid.getSlotMouseOver(mousex, mousey);
|
||||
if (button == 0 && !this.grid.forceExpand && NEIClientUtils.altKey()) {
|
||||
final ItemsPanelGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
|
||||
|
||||
if (hoverSlot != null) {
|
||||
final MaskMetadata metadata = panelGrid.maskMetadata.get(hoverSlot.slotIndex);
|
||||
|
||||
if (metadata != null) {
|
||||
CollapsibleItems.setExpanded(metadata.groupIndex, !metadata.extended);
|
||||
panelGrid.setItems(panelGrid.rawItems);
|
||||
return true;
|
||||
}
|
||||
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(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 super.handleHotkeys(mousex, mousey, hotkeys);
|
||||
}
|
||||
|
||||
public boolean containsWithSubpanels(int px, int py) {
|
||||
return contains(px, py) || NEIClientConfig.showHistoryPanelWidget() && this.historyPanel.contains(px, py)
|
||||
|| NEIClientConfig.showCraftablesPanelWidget() && this.craftablesPanel.contains(px, py);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,36 +107,21 @@ public class ItemQuantityField extends TextField {
|
||||
|
||||
@Override
|
||||
public void onTextChange(String oldText) {
|
||||
NEIClientUtils.setItemQuantity(intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mousex, int mousey) {
|
||||
|
||||
if (!focused() && intValue() == 0) {
|
||||
field.setText(translate("itempanel.quantity.default"));
|
||||
field.setCursorPositionZero();
|
||||
field.setEnabled(false);
|
||||
super.draw(mousex, mousey);
|
||||
field.setEnabled(true);
|
||||
field.setText("0");
|
||||
} else {
|
||||
super.draw(mousex, mousey);
|
||||
}
|
||||
NEIClientUtils.setItemQuantity(getInteger());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMouseWheel(int i, int mx, int my) {
|
||||
if (!contains(mx, my)) return false;
|
||||
int multiplier = 1;
|
||||
|
||||
if (NEIClientUtils.shiftKey()) {
|
||||
multiplier = 10;
|
||||
} else if (NEIClientUtils.controlKey()) {
|
||||
multiplier = 64;
|
||||
}
|
||||
|
||||
int quantity = intValue() + i * multiplier;
|
||||
setText(Integer.toString(quantity));
|
||||
setText(Integer.toString(Math.max(0, getInteger() + i * multiplier)));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,12 @@ public class ItemStackAmount {
|
||||
}
|
||||
}
|
||||
|
||||
public void addAll(Iterable<ItemStack> items) {
|
||||
for (ItemStack stack : items) {
|
||||
add(stack);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(ItemStack item) {
|
||||
add(item, (long) StackInfo.getAmount(item));
|
||||
}
|
||||
@@ -30,7 +36,9 @@ public class ItemStackAmount {
|
||||
if (stack == null || stack.getItem() == null) return;
|
||||
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
|
||||
|
||||
this.itemMap.put(key, value + this.itemMap.getOrDefault(key, 0L));
|
||||
if (key != null) {
|
||||
this.itemMap.put(key, value + this.itemMap.getOrDefault(key, 0L));
|
||||
}
|
||||
}
|
||||
|
||||
public Long get(ItemStack stack) {
|
||||
@@ -44,7 +52,9 @@ public class ItemStackAmount {
|
||||
if (stack == null || stack.getItem() == null) return;
|
||||
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
|
||||
|
||||
this.itemMap.put(key, value);
|
||||
if (key != null) {
|
||||
this.itemMap.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public long getOrDefault(ItemStack stack, long defaultAmount) {
|
||||
@@ -53,6 +63,10 @@ public class ItemStackAmount {
|
||||
return e == null ? defaultAmount : e;
|
||||
}
|
||||
|
||||
public boolean contains(ItemStack stack) {
|
||||
return get(stack) != null;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.itemMap.clear();
|
||||
}
|
||||
@@ -90,6 +104,16 @@ public class ItemStackAmount {
|
||||
return this.itemMap.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (obj instanceof ItemStackAmount items) {
|
||||
return this.itemMap.equals(items.itemMap);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static ItemStackAmount of(ItemStackAmount map) {
|
||||
ItemStackAmount result = new ItemStackAmount();
|
||||
result.itemMap.putAll(map.itemMap);
|
||||
|
||||
@@ -46,8 +46,7 @@ public class ItemStackMap<T> {
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof StackMetaKey)) return false;
|
||||
StackMetaKey t = (StackMetaKey) o;
|
||||
if (!(o instanceof StackMetaKey t)) return false;
|
||||
return damage == t.damage && Objects.equal(tag, t.tag);
|
||||
}
|
||||
}
|
||||
@@ -218,8 +217,7 @@ public class ItemStackMap<T> {
|
||||
public void put(ItemStack key, T value) {
|
||||
if (key == null || key.getItem() == null) return;
|
||||
|
||||
DetailMap map = itemMap.get(key.getItem());
|
||||
if (map == null) itemMap.put(key.getItem(), map = new DetailMap());
|
||||
DetailMap map = itemMap.computeIfAbsent(key.getItem(), k -> new DetailMap());
|
||||
map.put(key, value);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,9 +40,9 @@ public class ItemZoom extends Widget implements IContainerInputHandler {
|
||||
@Override
|
||||
public void draw(int mx, int my) {
|
||||
|
||||
if (this.stack != null
|
||||
if (this.stack != null && this.availableAreaWidth >= SLOT_SIZE * 2
|
||||
&& (NEIClientConfig.getBooleanSetting("inventory.itemzoom.enabled")
|
||||
|| NEIClientConfig.isKeyHashDown("gui.itemzoom_hold"))
|
||||
|| KeyManager.isKeyDown("itemzoom.hold"))
|
||||
&& GuiContainerManager.shouldShowTooltip(NEIClientUtils.getGuiContainer())) {
|
||||
final float inverseScaleFactor = 1.0f / this.scale;
|
||||
final float screenScale = getScreenScale();
|
||||
@@ -58,7 +58,7 @@ public class ItemZoom extends Widget implements IContainerInputHandler {
|
||||
|
||||
GL11.glPopMatrix();
|
||||
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
|
||||
GuiContainerManager.enable2DRender();
|
||||
|
||||
if (NEIClientConfig.getBooleanSetting("inventory.itemzoom.showName")) {
|
||||
@@ -74,7 +74,7 @@ public class ItemZoom extends Widget implements IContainerInputHandler {
|
||||
|
||||
if (NEIClientConfig.getBooleanSetting("inventory.itemzoom.enabled")
|
||||
&& NEIClientConfig.getBooleanSetting("inventory.itemzoom.helpText")) {
|
||||
String keyName = NEIClientConfig.getKeyName("gui.itemzoom_toggle");
|
||||
String keyName = KeyManager.getKeyName("itemzoom.toggle", NEIClientUtils.SHIFT_HASH);
|
||||
|
||||
if (keyName != null) {
|
||||
String helpText = NEIClientUtils.translate("itemzoom.toggle", keyName);
|
||||
@@ -198,24 +198,24 @@ public class ItemZoom extends Widget implements IContainerInputHandler {
|
||||
@Override
|
||||
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.itemzoom_toggle")) {
|
||||
if (KeyManager.isHashDown("itemzoom.toggle", NEIClientUtils.SHIFT_HASH)) {
|
||||
NEIClientConfig.getSetting("inventory.itemzoom.enabled")
|
||||
.setBooleanValue(!NEIClientConfig.getBooleanSetting("inventory.itemzoom.enabled"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.stack != null && NEIClientConfig.isKeyHashDown("gui.itemzoom_hold")) {
|
||||
if (this.stack != null && KeyManager.isKeyDown("itemzoom.hold")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.stack != null && NEIClientConfig.isKeyHashDown("gui.itemzoom_zoom_in")) {
|
||||
if (this.stack != null && KeyManager.isKeyDown("itemzoom.zoom_in")) {
|
||||
increaseZoom(gui);
|
||||
previousKeyboardRepeatEnabled = Keyboard.areRepeatEventsEnabled();
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.stack != null && NEIClientConfig.isKeyHashDown("gui.itemzoom_zoom_out")) {
|
||||
if (this.stack != null && KeyManager.isKeyDown("itemzoom.zoom_out")) {
|
||||
decreaseZoom(gui);
|
||||
previousKeyboardRepeatEnabled = Keyboard.areRepeatEventsEnabled();
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import static codechicken.lib.gui.GuiDraw.drawRect;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
@@ -20,17 +18,17 @@ 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.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
|
||||
public class ItemsGrid {
|
||||
public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends ItemsGrid.MouseContext> {
|
||||
|
||||
private static class ScreenCapture {
|
||||
protected static class ScreenCapture {
|
||||
|
||||
private long nextCacheRefresh = 0;
|
||||
private Framebuffer framebuffer;
|
||||
private final Framebuffer framebuffer;
|
||||
|
||||
public ScreenCapture() {
|
||||
this.framebuffer = new Framebuffer(1, 1, true);
|
||||
@@ -54,7 +52,7 @@ public class ItemsGrid {
|
||||
}
|
||||
|
||||
public void captureScreen(Runnable callback, int mode) {
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
|
||||
|
||||
resetFramebuffer();
|
||||
this.framebuffer.bindFramebuffer(false);
|
||||
@@ -88,7 +86,7 @@ public class ItemsGrid {
|
||||
this.framebuffer.framebufferClear();
|
||||
}
|
||||
|
||||
// copy depth buffer from MC (fix Angelica)
|
||||
// Copy stencil values (required by mui2)
|
||||
OpenGlHelper.func_153171_g(GL30.GL_READ_FRAMEBUFFER, minecraft.getFramebuffer().framebufferObject);
|
||||
OpenGlHelper.func_153171_g(GL30.GL_DRAW_FRAMEBUFFER, this.framebuffer.framebufferObject);
|
||||
GL30.glBlitFramebuffer(
|
||||
@@ -140,7 +138,130 @@ public class ItemsGrid {
|
||||
|
||||
}
|
||||
|
||||
public static final int SLOT_SIZE = 18;
|
||||
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;
|
||||
@@ -157,20 +278,17 @@ public class ItemsGrid {
|
||||
|
||||
protected int rows;
|
||||
protected int columns;
|
||||
protected List<Integer> gridMask = null;
|
||||
|
||||
protected boolean[] invalidSlotMap;
|
||||
|
||||
protected Label messageLabel = new Label(getMessageOnEmpty(), 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() {
|
||||
@@ -222,7 +340,11 @@ public class ItemsGrid {
|
||||
}
|
||||
|
||||
public int getLastRowIndex() {
|
||||
return this.columns > 0 ? (int) Math.ceil((float) this.getMask().size() / this.columns) - 1 : 0;
|
||||
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) {
|
||||
@@ -236,9 +358,6 @@ public class ItemsGrid {
|
||||
rows = height / SLOT_SIZE;
|
||||
|
||||
paddingLeft = (width % SLOT_SIZE) / 2;
|
||||
|
||||
messageLabel.x = marginLeft + width / 2;
|
||||
messageLabel.y = marginTop + height / 2;
|
||||
}
|
||||
|
||||
public void shiftPage(int shift) {
|
||||
@@ -270,10 +389,9 @@ public class ItemsGrid {
|
||||
if (this.screenCapture != null) {
|
||||
this.screenCapture.refreshBuffer();
|
||||
}
|
||||
this.gridMask = null;
|
||||
}
|
||||
|
||||
protected void onItemsChanged() {
|
||||
public void onItemsChanged() {
|
||||
onGridChanged();
|
||||
}
|
||||
|
||||
@@ -323,20 +441,37 @@ public class ItemsGrid {
|
||||
}
|
||||
}
|
||||
|
||||
public Rectangle4i getItemRect(int idx) {
|
||||
final List<Integer> mask = getMask();
|
||||
|
||||
for (int i = 0; i < mask.size(); i++) {
|
||||
if (mask.get(i) != null && idx == mask.get(i)) {
|
||||
return getSlotRect(i);
|
||||
}
|
||||
public T getSlotMouseOver(int mousex, int mousey) {
|
||||
if (!contains(mousex, mousey)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
final int overRow = getRowIndex(mousey);
|
||||
final int overColumn = getColumnIndex(mousex);
|
||||
final int slt = columns * overRow + overColumn;
|
||||
|
||||
if (overRow >= rows || overColumn >= columns) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getSlotBySlotIndex(slt);
|
||||
}
|
||||
|
||||
public Rectangle4i getSlotRect(int i) {
|
||||
return getSlotRect(i / columns, i % columns);
|
||||
public T getSlotBySlotIndex(int slotIndex) {
|
||||
return getMask().stream().filter(item -> item.slotIndex == slotIndex).findAny().orElse(null);
|
||||
}
|
||||
|
||||
public T getSlotByItemIndex(int itemIndex) {
|
||||
return getMask().stream().filter(item -> item.itemIndex == itemIndex).findAny().orElse(null);
|
||||
}
|
||||
|
||||
public Rectangle4i getItemRect(int itemIndex) {
|
||||
final T item = getSlotByItemIndex(itemIndex);
|
||||
return item != null ? getSlotRect(item.slotIndex) : null;
|
||||
}
|
||||
|
||||
public Rectangle4i getSlotRect(int slotIndex) {
|
||||
return getSlotRect(slotIndex / columns, slotIndex % columns);
|
||||
}
|
||||
|
||||
public Rectangle4i getSlotRect(int row, int column) {
|
||||
@@ -347,67 +482,45 @@ 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() {
|
||||
public abstract List<T> getMask();
|
||||
|
||||
if (this.gridMask == null) {
|
||||
this.gridMask = new ArrayList<>();
|
||||
int idx = page * perPage;
|
||||
|
||||
for (int i = 0; i < rows * columns && idx < size(); i++) {
|
||||
this.gridMask.add(isInvalidSlot(i) ? null : idx++);
|
||||
}
|
||||
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 this.gridMask;
|
||||
}
|
||||
|
||||
protected void beforeDrawItems(int mousex, int mousey, @Nullable ItemPanelSlot focused) {
|
||||
|
||||
final List<Integer> mask = getMask();
|
||||
|
||||
for (int i = 0; i < mask.size(); i++) {
|
||||
if (mask.get(i) != null) {
|
||||
beforeDrawSlot(focused, mask.get(i), getSlotRect(i));
|
||||
}
|
||||
for (T item : getMask()) {
|
||||
item.drawBorder(getSlotRect(item.slotIndex));
|
||||
}
|
||||
}
|
||||
|
||||
protected void afterDrawItems(int mousex, int mousey, @Nullable ItemPanelSlot focused) {
|
||||
final List<Integer> mask = getMask();
|
||||
|
||||
for (int i = 0; i < mask.size(); i++) {
|
||||
if (mask.get(i) != null) {
|
||||
afterDrawSlot(focused, mask.get(i), getSlotRect(i));
|
||||
}
|
||||
protected void afterDrawItems(int mousex, int mousey, M mouseContext) {
|
||||
for (T item : getMask()) {
|
||||
item.afterDraw(getSlotRect(item.slotIndex), mouseContext);
|
||||
}
|
||||
}
|
||||
|
||||
public void update() {}
|
||||
|
||||
protected void beforeDrawSlot(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {
|
||||
if (focused != null && focused.slotIndex == slotIdx) {
|
||||
drawRect(rect.x, rect.y, rect.w, rect.h, 0xee555555); // highlight
|
||||
}
|
||||
}
|
||||
protected void drawItems() {
|
||||
|
||||
protected void afterDrawSlot(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {}
|
||||
|
||||
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));
|
||||
}
|
||||
for (T item : getMask()) {
|
||||
item.drawItem(getSlotRect(item.slotIndex));
|
||||
}
|
||||
|
||||
GuiContainerManager.disableMatrixStackLogging();
|
||||
}
|
||||
|
||||
protected int getGridRenderingCacheMode() {
|
||||
@@ -419,10 +532,10 @@ public class ItemsGrid {
|
||||
return;
|
||||
}
|
||||
|
||||
final ItemPanelSlot focused = getSlotMouseOver(mousex, mousey);
|
||||
final int gridRenderingCacheMode = getGridRenderingCacheMode();
|
||||
final M mouseContext = getMouseContext(mousex, mousey);
|
||||
|
||||
beforeDrawItems(mousex, mousey, focused);
|
||||
beforeDrawItems(mousex, mousey, mouseContext);
|
||||
|
||||
if (gridRenderingCacheMode > 0) {
|
||||
|
||||
@@ -431,49 +544,21 @@ public class ItemsGrid {
|
||||
}
|
||||
|
||||
if (this.screenCapture.needRefresh(gridRenderingCacheMode)) {
|
||||
this.screenCapture.captureScreen(this::drawItems, gridRenderingCacheMode);
|
||||
this.screenCapture.captureScreen(() -> {
|
||||
GuiContainerManager.enableMatrixStackLogging();
|
||||
drawItems();
|
||||
GuiContainerManager.disableMatrixStackLogging();
|
||||
}, gridRenderingCacheMode);
|
||||
}
|
||||
|
||||
this.screenCapture.renderCapturedScreen();
|
||||
} else {
|
||||
GuiContainerManager.enableMatrixStackLogging();
|
||||
drawItems();
|
||||
GuiContainerManager.disableMatrixStackLogging();
|
||||
}
|
||||
|
||||
afterDrawItems(mousex, mousey, focused);
|
||||
}
|
||||
|
||||
public void setVisible() {
|
||||
if (getItems().isEmpty() && getMessageOnEmpty() != null) {
|
||||
LayoutManager.addWidget(messageLabel);
|
||||
}
|
||||
}
|
||||
|
||||
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 = (mousey - marginTop) / SLOT_SIZE;
|
||||
final int overColumn = (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;
|
||||
afterDrawItems(mousex, mousey, mouseContext);
|
||||
}
|
||||
|
||||
public boolean contains(int px, int py) {
|
||||
@@ -487,13 +572,7 @@ public class ItemsGrid {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int r = (py - marginTop) / SLOT_SIZE;
|
||||
final int c = (px - marginLeft - paddingLeft) / SLOT_SIZE;
|
||||
|
||||
return !isInvalidSlot(columns * r + c);
|
||||
return !isInvalidSlot(columns * getRowIndex(py) + getColumnIndex(px));
|
||||
}
|
||||
|
||||
public String getMessageOnEmpty() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
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.gui.GuiDraw;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
|
||||
public class ItemsPanelGrid extends ItemsGrid<ItemsPanelGrid.ItemsPanelGridSlot, ItemsPanelGrid.MouseContext> {
|
||||
|
||||
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 = new ArrayList<>();
|
||||
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));
|
||||
}
|
||||
|
||||
public void draw(int mousex, int mousey) {
|
||||
if (ItemList.loadFinished) {
|
||||
super.draw(mousex, mousey);
|
||||
} else {
|
||||
GuiDraw.drawStringC(
|
||||
NEIClientUtils
|
||||
.cropText(GuiDraw.fontRenderer, NEIClientUtils.translate("itempanel.loading"), width - 10),
|
||||
marginLeft + width / 2,
|
||||
marginTop + height / 2,
|
||||
0xffffff,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,15 +3,19 @@ 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;
|
||||
@@ -19,12 +23,14 @@ 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;
|
||||
@@ -46,9 +52,8 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
|
||||
this.columns = Math.min(MAX_COLUMNS, this.length);
|
||||
this.rows = Math.min(maxRows, (int) Math.ceil((float) this.length / this.columns));
|
||||
|
||||
this.size.width = Math
|
||||
.max(this.columns * ItemsGrid.SLOT_SIZE, fontRenderer.getStringWidth(this.label) + 15);
|
||||
this.size.height = this.rows * ItemsGrid.SLOT_SIZE + fontRenderer.FONT_HEIGHT + 2 + MARGIN_TOP;
|
||||
this.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,
|
||||
@@ -58,12 +63,22 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
|
||||
|
||||
if (this.items.size() > this.count) {
|
||||
String text = "+" + (this.items.size() - this.count);
|
||||
this.count -= (int) Math.ceil((float) (fontRenderer.getStringWidth(text) - 2) / ItemsGrid.SLOT_SIZE);
|
||||
this.count -= (int) Math.ceil((float) (fontRenderer.getStringWidth(text) - 2) / SLOT_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setActiveStack(ItemStack activeStack) {
|
||||
final ItemStack realStack = items.stream().filter(stack -> NEIClientUtils.areStacksSameType(stack, activeStack))
|
||||
.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();
|
||||
}
|
||||
@@ -85,37 +100,51 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
|
||||
|
||||
fontRenderer.drawStringWithShadow(this.labelColor + this.label + ":", x, y, 0);
|
||||
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
GL11.glPushMatrix();
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
|
||||
GL11.glScaled(1, 1, 3);
|
||||
GL11.glTranslatef(x, y + fontRenderer.FONT_HEIGHT + 2, 0);
|
||||
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
|
||||
|
||||
for (int i = 0; i < this.count; i++) {
|
||||
ItemStack drawStack = this.items.get(i);
|
||||
int col = i % this.columns;
|
||||
int row = i / this.columns;
|
||||
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
|
||||
final int xTranslation = x;
|
||||
final int yTranslation = y + fontRenderer.FONT_HEIGHT + 2;
|
||||
final int zTranslation = GuiContainerManager.TOOLTIP_Z_OFFSET;
|
||||
GL11.glTranslatef(xTranslation, yTranslation, zTranslation);
|
||||
|
||||
int indexShift = 0;
|
||||
|
||||
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);
|
||||
|
||||
drawItem(col * ItemsGrid.SLOT_SIZE, row * ItemsGrid.SLOT_SIZE, 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()) {
|
||||
String text = "+" + (this.items.size() - this.count);
|
||||
|
||||
fontRenderer.drawStringWithShadow(
|
||||
text,
|
||||
MAX_COLUMNS * ItemsGrid.SLOT_SIZE - fontRenderer.getStringWidth(text) - 2,
|
||||
(this.rows - 1) * ItemsGrid.SLOT_SIZE + (ItemsGrid.SLOT_SIZE - fontRenderer.FONT_HEIGHT) / 2,
|
||||
0xee555555);
|
||||
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.glTranslatef(-xTranslation, -yTranslation, -zTranslation);
|
||||
GL11.glPopAttrib();
|
||||
}
|
||||
|
||||
@@ -124,12 +153,19 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
|
||||
}
|
||||
|
||||
private List<ItemStack> groupingItemStacks(List<ItemStack> items) {
|
||||
final List<ItemStack> result = ItemStackAmount.of(items).values();
|
||||
final List<ItemStack> result = new ArrayList<>();
|
||||
|
||||
for (ItemStack stack : result) {
|
||||
if (StackInfo.itemStackToNBT(stack).hasKey("gtFluidName")) {
|
||||
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;
|
||||
|
||||
@@ -2,10 +2,21 @@ package codechicken.nei;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.settings.KeyBinding;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
import codechicken.nei.util.NEIKeyboardUtils;
|
||||
import codechicken.nei.util.NEIMouseUtils;
|
||||
import cpw.mods.fml.client.registry.ClientRegistry;
|
||||
|
||||
/**
|
||||
* Good old down/held/up keystate tracker
|
||||
* Registers NEI key bindings as vanilla {@link KeyBinding}s and exposes their state to the rest of NEI.
|
||||
*/
|
||||
public class KeyManager {
|
||||
|
||||
@@ -14,30 +25,132 @@ public class KeyManager {
|
||||
public void tickKeyStates();
|
||||
}
|
||||
|
||||
public static class KeyState {
|
||||
public static LinkedList<IKeyStateTracker> trackers = new LinkedList<>();
|
||||
private static final Map<String, KeyBinding> keyBindings = new HashMap<>();
|
||||
private static final Map<String, String> keyAliases = new HashMap<>();
|
||||
private static volatile boolean pendingOptionsReload = false;
|
||||
|
||||
public boolean down;
|
||||
public boolean held;
|
||||
public boolean up;
|
||||
static {
|
||||
// Aliases for legacy keybinds
|
||||
keyAliases.put("gui.recipe", "recipe.recipe");
|
||||
keyAliases.put("gui.usage", "recipe.usage");
|
||||
keyAliases.put("gui.hide_bookmarks", "bookmark.hide");
|
||||
}
|
||||
|
||||
public static HashMap<String, KeyState> keyStates = new HashMap<>();
|
||||
public static LinkedList<IKeyStateTracker> trackers = new LinkedList<>();
|
||||
public static KeyBinding registerKeyBinding(String ident, int defaultKey) {
|
||||
return keyBindings.computeIfAbsent(ident, id -> {
|
||||
final KeyBinding binding = new KeyBinding(
|
||||
"nei.options.keys." + id,
|
||||
NEIKeyboardUtils.unhash(defaultKey),
|
||||
categoryFor(id));
|
||||
ClientRegistry.registerKeyBinding(binding);
|
||||
return binding;
|
||||
});
|
||||
}
|
||||
|
||||
public static KeyBinding getKeyBinding(String ident) {
|
||||
return keyBindings.get(keyAliases.getOrDefault(ident, ident));
|
||||
}
|
||||
|
||||
public static boolean isRegistered(String description) {
|
||||
for (KeyBinding binding : keyBindings.values()) {
|
||||
if (binding.getKeyDescription().equals(description)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int getKeyCode(String ident) {
|
||||
final KeyBinding binding = getKeyBinding(ident);
|
||||
return binding == null ? Keyboard.KEY_NONE : binding.getKeyCode();
|
||||
}
|
||||
|
||||
public static boolean isKeyDown(String ident) {
|
||||
final KeyBinding binding = getKeyBinding(ident);
|
||||
|
||||
if (binding != null) {
|
||||
final int keyCode = binding.getKeyCode();
|
||||
|
||||
if (keyCode < 0) {
|
||||
return Mouse.isButtonDown(keyCode + 100);
|
||||
} else if (keyCode > Keyboard.KEY_NONE && keyCode < Keyboard.KEYBOARD_SIZE) {
|
||||
return Keyboard.isKeyDown(keyCode);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isHashDown(String ident) {
|
||||
return isHashDown(ident, 0);
|
||||
}
|
||||
|
||||
public static boolean isHashDown(String ident, int modifierMask) {
|
||||
|
||||
if (!isKeyDown(ident)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NEIKeyboardUtils.isHashKey(getKeyCode(ident))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return ((modifierMask & NEIKeyboardUtils.CTRL_HASH) != 0) == NEIClientUtils.controlKey()
|
||||
&& ((modifierMask & NEIKeyboardUtils.SHIFT_HASH) != 0) == NEIClientUtils.shiftKey()
|
||||
&& ((modifierMask & NEIKeyboardUtils.ALT_HASH) != 0) == NEIClientUtils.altKey();
|
||||
}
|
||||
|
||||
public static String getKeyName(String ident) {
|
||||
return getKeyName(ident, 0);
|
||||
}
|
||||
|
||||
public static String getKeyName(String ident, int meta) {
|
||||
final int keyCode = getKeyCode(ident);
|
||||
return keyCode == Keyboard.KEY_NONE ? null : NEIKeyboardUtils.getKeyName(keyCode + meta);
|
||||
}
|
||||
|
||||
public static String getKeyName(String ident, int meta, int mouseBind) {
|
||||
final int keyCode = getKeyCode(ident);
|
||||
return keyCode == Keyboard.KEY_NONE && mouseBind == NEIMouseUtils.MOUSE_BTN_NONE ? null
|
||||
: getKeyName(keyCode + meta, mouseBind);
|
||||
}
|
||||
|
||||
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 boolean isPressed(String ident) {
|
||||
final KeyBinding binding = getKeyBinding(ident);
|
||||
return binding != null && binding.isPressed();
|
||||
}
|
||||
|
||||
private static String categoryFor(String ident) {
|
||||
final int dot = ident.indexOf('.');
|
||||
return dot < 0 ? "nei.options.keys" : "nei.options.keys." + ident.substring(0, dot);
|
||||
}
|
||||
|
||||
public static void requestOptionsReload() {
|
||||
pendingOptionsReload = true;
|
||||
}
|
||||
|
||||
public static void tickKeyStates() {
|
||||
for (Entry<String, KeyState> entry : keyStates.entrySet()) {
|
||||
final boolean down = NEIClientConfig.isKeyHashDown(entry.getKey());
|
||||
final KeyState state = entry.getValue();
|
||||
|
||||
if (down) {
|
||||
state.down = !state.held;
|
||||
state.up = false;
|
||||
} else {
|
||||
state.up = state.held;
|
||||
state.down = false;
|
||||
}
|
||||
|
||||
state.held = down;
|
||||
if (pendingOptionsReload) {
|
||||
pendingOptionsReload = false;
|
||||
Minecraft.getMinecraft().gameSettings.loadOptions();
|
||||
}
|
||||
|
||||
for (IKeyStateTracker tracker : trackers) tracker.tickKeyStates();
|
||||
|
||||
@@ -65,8 +65,10 @@ 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;
|
||||
import codechicken.nei.recipe.debug.DebugHandlerWidget;
|
||||
|
||||
public class LayoutManager implements IContainerInputHandler, IContainerTooltipHandler, IContainerDrawHandler,
|
||||
IContainerObjectHandler, IKeyStateTracker {
|
||||
@@ -101,7 +103,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
public static Button delete;
|
||||
public static ButtonCycled gamemode;
|
||||
public static Button rain;
|
||||
public static Button magnet;
|
||||
public static ButtonCycled magnet;
|
||||
public static Button[] timeButtons = new Button[4];
|
||||
public static Button heal;
|
||||
|
||||
@@ -135,10 +137,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
|
||||
@Override
|
||||
public void onPreDraw(GuiContainer gui) {
|
||||
if (!isHidden() && isEnabled() && gui instanceof InventoryEffectRenderer) // Reset the gui to the center of the
|
||||
// screen, for potion effect offsets
|
||||
// etc
|
||||
{
|
||||
// Reset the gui to the center of the screen, for potion effect offsets etc
|
||||
if (isEnabled() && gui instanceof InventoryEffectRenderer) {
|
||||
gui.guiLeft = (gui.width - gui.xSize) / 2;
|
||||
gui.guiTop = (gui.height - gui.ySize) / 2;
|
||||
|
||||
@@ -224,18 +224,17 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
@Override
|
||||
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.hide")) {
|
||||
if (KeyManager.isKeyDown("gui.hide")) {
|
||||
toggleBooleanSetting("inventory.hidden");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.hide_bookmarks")) {
|
||||
if (KeyManager.isKeyDown("bookmark.hide")) {
|
||||
toggleBooleanSetting("inventory.bookmarks.enabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.next_tooltip")) {
|
||||
GuiContainerManager.incrementTooltipPage();
|
||||
if (KeyManager.isKeyDown("gui.next_tooltip") && GuiContainerManager.incrementTooltipPage()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -293,19 +292,6 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postRenderTooltips(GuiContainer gui, int mousex, int mousey, List<String> tooltip) {
|
||||
|
||||
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
|
||||
final Widget focused = getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
if (focused != null) {
|
||||
focused.postDrawTooltips(mousex, mousey, tooltip);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
|
||||
|
||||
@@ -356,6 +342,10 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
|
||||
final Widget focused = getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
if (focused != null) {
|
||||
currenttip = focused.handleItemTooltip(itemstack, mousex, mousey, currenttip);
|
||||
}
|
||||
|
||||
if (focused instanceof IContainerTooltipHandler tip) {
|
||||
currenttip = tip.handleItemTooltip(gui, itemstack, mousex, mousey, currenttip);
|
||||
}
|
||||
@@ -370,9 +360,14 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
|
||||
final Widget focused = getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
if (focused instanceof IContainerTooltipHandler tip) {
|
||||
hotkeys = tip.handleHotkeys(gui, mousex, mousey, hotkeys);
|
||||
if (focused != null) {
|
||||
hotkeys = focused.handleHotkeys(mousex, mousey, hotkeys);
|
||||
|
||||
if (focused instanceof IContainerTooltipHandler tip) {
|
||||
hotkeys = tip.handleHotkeys(gui, mousex, mousey, hotkeys);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return hotkeys;
|
||||
@@ -602,7 +597,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
return getStateTip("rain", state);
|
||||
}
|
||||
};
|
||||
magnet = new Button() {
|
||||
magnet = new ButtonCycled(2) {
|
||||
|
||||
@Override
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
@@ -785,9 +780,10 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
addWidget(itemZoom);
|
||||
|
||||
if (visiblity.showSubsetDropdown) {
|
||||
// Bookmarks or Subset/dropdown
|
||||
addWidget(dropDown);
|
||||
}
|
||||
|
||||
addWidget(DebugHandlerWidget.instance);
|
||||
}
|
||||
|
||||
public static LayoutStyle getLayoutStyle(int id) {
|
||||
@@ -830,7 +826,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
|
||||
@Override
|
||||
public boolean shouldShowTooltip(GuiContainer gui) {
|
||||
return itemPanel.draggedStack == null && !bookmarkPanel.inEditingState();
|
||||
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. */
|
||||
@@ -858,13 +854,11 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
ItemStack item = slot.getStack();
|
||||
|
||||
if (item == null ? !getSearchExpression().equals("") : !searchField.getFilter().matches(item)) {
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
GL11.glDisable(GL11.GL_DEPTH_TEST);
|
||||
GL11.glTranslatef(0, 0, 150);
|
||||
drawRect(slot.xDisplayPosition, slot.yDisplayPosition, 16, 16, 0x80000000);
|
||||
GL11.glTranslatef(0, 0, -150);
|
||||
GL11.glEnable(GL11.GL_LIGHTING);
|
||||
GL11.glEnable(GL11.GL_DEPTH_TEST);
|
||||
NEIClientUtils.gl2DRenderContext(() -> {
|
||||
GL11.glTranslatef(0, 0, 150);
|
||||
drawRect(slot.xDisplayPosition, slot.yDisplayPosition, 16, 16, 0x80000000);
|
||||
GL11.glTranslatef(0, 0, -150);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -909,6 +903,9 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
final int ty2 = ty + 20 - h2 - te;
|
||||
final int tx2 = 200 - w2 - te;
|
||||
|
||||
final boolean is2DTexture = GL11.glGetBoolean(GL11.GL_TEXTURE_2D);
|
||||
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
changeTexture("textures/gui/widgets.png");
|
||||
drawTexturedModalRect(x, y, tx1, ty1, w1, h1); // top left
|
||||
drawTexturedModalRect(x, y2, tx1, ty2, w1, h2); // bottom left
|
||||
@@ -921,16 +918,14 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
|
||||
drawTexturedModalRect(x2, y, tx2, ty1, w2, h1); // top right
|
||||
drawTexturedModalRect(x2, y2, tx2, ty2, w2, h2); // bottom right
|
||||
|
||||
if (!is2DTexture) GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
public static void drawItemPresenceOverlay(int slotX, int slotY, boolean isPresent, boolean slotHighlight) {
|
||||
|
||||
if (slotHighlight) {
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
GL11.glDisable(GL11.GL_DEPTH_TEST);
|
||||
drawRect(slotX, slotY, 16, 16, isPresent ? 0x8000AA00 : 0x80AA0000);
|
||||
GL11.glPopAttrib();
|
||||
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);
|
||||
@@ -946,12 +941,12 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
public void tickKeyStates() {
|
||||
if (Minecraft.getMinecraft().currentScreen != null) return;
|
||||
|
||||
if (KeyManager.keyStates.get("world.dawn").down) timeButtons[0].onButtonPress(false);
|
||||
if (KeyManager.keyStates.get("world.noon").down) timeButtons[1].onButtonPress(false);
|
||||
if (KeyManager.keyStates.get("world.dusk").down) timeButtons[2].onButtonPress(false);
|
||||
if (KeyManager.keyStates.get("world.midnight").down) timeButtons[3].onButtonPress(false);
|
||||
if (KeyManager.keyStates.get("world.rain").down) rain.onButtonPress(false);
|
||||
if (KeyManager.keyStates.get("world.heal").down) heal.onButtonPress(false);
|
||||
if (KeyManager.keyStates.get("world.creative").down) gamemode.onButtonPress(false);
|
||||
if (KeyManager.isPressed("world.dawn")) timeButtons[0].onButtonPress(false);
|
||||
if (KeyManager.isPressed("world.noon")) timeButtons[1].onButtonPress(false);
|
||||
if (KeyManager.isPressed("world.dusk")) timeButtons[2].onButtonPress(false);
|
||||
if (KeyManager.isPressed("world.midnight")) timeButtons[3].onButtonPress(false);
|
||||
if (KeyManager.isPressed("world.rain")) rain.onButtonPress(false);
|
||||
if (KeyManager.isPressed("world.heal")) heal.onButtonPress(false);
|
||||
if (KeyManager.isPressed("world.creative")) gamemode.onButtonPress(false);
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,8 @@ public class LayoutStyleMinecraft extends LayoutStyle {
|
||||
LayoutManager.gamemode.icons[0] = new Image(132, 12, 12, 12);
|
||||
LayoutManager.gamemode.icons[1] = new Image(156, 12, 12, 12);
|
||||
LayoutManager.gamemode.icons[2] = new Image(168, 12, 12, 12);
|
||||
LayoutManager.magnet.icon = new Image(180, 24, 12, 12);
|
||||
LayoutManager.magnet.icons[0] = new Image(180, 24, 12, 12);
|
||||
LayoutManager.magnet.icons[1] = new Image(180, 36, 12, 12);
|
||||
LayoutManager.timeButtons[0].icon = new Image(132, 24, 12, 12);
|
||||
LayoutManager.timeButtons[1].icon = new Image(120, 24, 12, 12);
|
||||
LayoutManager.timeButtons[2].icon = new Image(144, 24, 12, 12);
|
||||
@@ -52,7 +53,7 @@ public class LayoutStyleMinecraft extends LayoutStyle {
|
||||
public void layout(GuiContainer gui, VisiblityData visiblity) {
|
||||
reset();
|
||||
|
||||
leftSize = ItemPanels.bookmarkPanel.getWidth(gui);
|
||||
leftSize = (gui.width - gui.xSize) / 2 - 4;
|
||||
numButtons = Math.max(leftSize / 20, 1);
|
||||
|
||||
LayoutManager.delete.state = 0x4;
|
||||
@@ -86,6 +87,7 @@ public class LayoutStyleMinecraft extends LayoutStyle {
|
||||
LayoutManager.options.index = NEIClientConfig.getCheatMode();
|
||||
|
||||
LayoutManager.magnet.state = 0x4 | (NEIClientConfig.getMagnetMode() ? 1 : 0);
|
||||
LayoutManager.magnet.index = (LayoutManager.magnet.state & 0x1) != 0 ? 1 : 0;
|
||||
|
||||
if (NEIClientConfig.canPerformAction("delete")) {
|
||||
layoutButton(LayoutManager.delete);
|
||||
@@ -184,7 +186,7 @@ public class LayoutStyleMinecraft extends LayoutStyle {
|
||||
final Rectangle4i area = new Rectangle4i(0, 0, 0, BUTTON_SIZE);
|
||||
|
||||
if (NEIClientConfig.isSearchWidgetCentered()) {
|
||||
area.w = gui.xSize - MARGIN * 2;
|
||||
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()) {
|
||||
@@ -242,7 +244,11 @@ public class LayoutStyleMinecraft extends LayoutStyle {
|
||||
|
||||
Image icon = b.getRenderIcon();
|
||||
if (icon == null) {
|
||||
int colour = tex == 2 ? 0xffffa0 : tex == 0 ? 0x601010 : 0xe0e0e0;
|
||||
int labelColor = b.getRenderLabelColor();
|
||||
int colour = labelColor != 0 ? labelColor
|
||||
: tex == 2 ? ColorUtils.buttonLabelHover.getColor()
|
||||
: tex == 0 ? ColorUtils.buttonLabelDisabled.getColor()
|
||||
: ColorUtils.buttonLabelNormal.getColor();
|
||||
|
||||
drawStringC(b.getRenderLabel(), b.x + b.w / 2, b.y + (b.h - 8) / 2, colour);
|
||||
} else {
|
||||
|
||||
@@ -54,6 +54,7 @@ public class NEIActions {
|
||||
addAction("magnet", true);
|
||||
addAction("enchant", true);
|
||||
addAction("potion", true);
|
||||
addAction("autocraft");
|
||||
|
||||
canDisable.add("dawn");
|
||||
canDisable.add("noon");
|
||||
|
||||
@@ -6,6 +6,7 @@ import static codechicken.nei.PacketIDs.S2C;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.inventory.GuiInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.play.INetHandlerPlayClient;
|
||||
import net.minecraft.util.ChatComponentTranslation;
|
||||
import net.minecraft.world.World;
|
||||
@@ -14,6 +15,7 @@ import codechicken.core.ClientUtils;
|
||||
import codechicken.lib.inventory.InventoryUtils;
|
||||
import codechicken.lib.packet.PacketCustom;
|
||||
import codechicken.lib.packet.PacketCustom.IClientPacketHandler;
|
||||
import codechicken.nei.commands.CommandBookmarkAdd;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
|
||||
public class NEICPH implements IClientPacketHandler {
|
||||
@@ -56,6 +58,18 @@ public class NEICPH implements IClientPacketHandler {
|
||||
case S2C.OPEN_POTION_GUI:
|
||||
ClientUtils.openSMPGui(packet.readUByte(), new GuiPotionCreator(mc.thePlayer.inventory));
|
||||
break;
|
||||
case S2C.CACHE_BOOKMARK_DATA:
|
||||
handleCacheBookmarkData(packet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCacheBookmarkData(PacketCustom packet) {
|
||||
final String payloadId = packet.readString();
|
||||
final NBTTagCompound payloadTag = packet.readNBTTagCompound();
|
||||
|
||||
if (payloadTag != null) {
|
||||
CommandBookmarkAdd.cachePayload(payloadId, payloadTag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,6 +200,12 @@ public class NEICPH implements IClientPacketHandler {
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
public static void sendChatLink(NBTTagCompound payloadTag) {
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.SEND_CHAT_ITEM_LINK);
|
||||
packet.writeNBTTagCompound(payloadTag);
|
||||
packet.sendToServer();
|
||||
}
|
||||
|
||||
public static void sendOpenEnchantmentWindow() {
|
||||
PacketCustom packet = new PacketCustom(channel, C2S.REQUEST_ENCHANTMENT_GUI);
|
||||
packet.sendToServer();
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
@@ -16,7 +17,6 @@ import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.SaveFormatComparator;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
@@ -45,7 +45,6 @@ import codechicken.nei.config.GuiHighlightTips;
|
||||
import codechicken.nei.config.GuiNEIOptionList;
|
||||
import codechicken.nei.config.GuiOptionList;
|
||||
import codechicken.nei.config.GuiPanelSettings;
|
||||
import codechicken.nei.config.OptionButton;
|
||||
import codechicken.nei.config.OptionCycled;
|
||||
import codechicken.nei.config.OptionGamemodes;
|
||||
import codechicken.nei.config.OptionIntegerField;
|
||||
@@ -59,8 +58,9 @@ import codechicken.nei.config.preset.GuiPresetList;
|
||||
import codechicken.nei.event.NEIConfigsLoadedEvent;
|
||||
import codechicken.nei.recipe.GuiRecipeTab;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
import codechicken.nei.recipe.InformationHandler;
|
||||
import codechicken.nei.recipe.RecipeCatalysts;
|
||||
import codechicken.nei.recipe.RecipeInfo;
|
||||
import codechicken.nei.util.ItemUntranslator;
|
||||
import codechicken.obfuscator.ObfuscationRun;
|
||||
|
||||
public class NEIClientConfig {
|
||||
@@ -145,6 +145,11 @@ public class NEIClientConfig {
|
||||
tag.getTag("inventory.widgetsenabled").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.widgetsenabled"));
|
||||
|
||||
tag.getTag("findFuelsParallel").getBooleanValue(true);
|
||||
tag.getTag("showRepairOnlyForDamageableItems").getBooleanValue(true);
|
||||
|
||||
tag.getTag("inventory.autocrafting").getBooleanValue(true);
|
||||
tag.getTag("inventory.dynamicFontSize").getBooleanValue(true);
|
||||
tag.getTag("inventory.hidden").getBooleanValue(false);
|
||||
tag.getTag("inventory.cheatmode").getIntValue(2);
|
||||
tag.getTag("inventory.lockmode").setComment(
|
||||
@@ -178,6 +183,7 @@ public class NEIClientConfig {
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
super.onClick(button);
|
||||
ItemPanels.bookmarkPanel.save();
|
||||
ItemPanels.bookmarkPanel.load();
|
||||
return true;
|
||||
}
|
||||
@@ -191,27 +197,43 @@ public class NEIClientConfig {
|
||||
.getIntValue(1);
|
||||
API.addOption(new OptionCycled("inventory.bookmarks.recipeTooltipsMode", 4, true));
|
||||
|
||||
tag.getTag("inventory.bookmarks.showRecipeMarker").setComment("Show Recipe Marker").getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.bookmarks.showRecipeMarker", true));
|
||||
tag.getTag("inventory.bookmarks.showRecipeMarkerMode").setComment("Show Recipe Marker").getIntValue(0);
|
||||
API.addOption(new OptionCycled("inventory.bookmarks.showRecipeMarkerMode", 3, true));
|
||||
|
||||
tag.getTag("inventory.bookmarks.craftingChainDir").getIntValue(1);
|
||||
API.addOption(new OptionCycled("inventory.bookmarks.craftingChainDir", 2, true));
|
||||
tag.getTag("inventory.bookmarks.recipeMarkerColor").setComment("Color of the icon marker")
|
||||
.getHexValue(0xADADAD);
|
||||
API.addOption(
|
||||
new OptionIntegerField(
|
||||
"inventory.bookmarks.recipeMarkerColor",
|
||||
0,
|
||||
OptionIntegerField.UNSIGNED_INT_MAX));
|
||||
|
||||
tag.getTag("inventory.bookmarks.showRecipeHandlerIcon").setComment("Show Recipe Handler Icon")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.bookmarks.showRecipeHandlerIcon", true));
|
||||
|
||||
tag.getTag("inventory.bookmarks.recipeChainDir").getIntValue(1);
|
||||
API.addOption(new OptionCycled("inventory.bookmarks.recipeChainDir", 2, true));
|
||||
|
||||
tag.getTag("inventory.bookmarks.ignorePotionOverlap").setComment("Ignore overlap with potion effect HUD")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.bookmarks.ignorePotionOverlap", true));
|
||||
|
||||
tag.getTag("inventory.bookmarks.bookmarkItemsWithRecipe").setComment("Bookmark items with recipe")
|
||||
.getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.bookmarks.bookmarkItemsWithRecipe", true));
|
||||
|
||||
tag.getTag("inventory.bookmarks.bookmarkRecipeWithCount").setComment("Bookmark recipe with count")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.bookmarks.bookmarkRecipeWithCount", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.jeiStyleTabs").setComment("Enable/disable JEI Style Tabs")
|
||||
.getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButtonBoubs("inventory.guirecipe.jeiStyleTabs", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.jeiStyleRecipeCatalyst").setComment("Enable/disable JEI Style Recipe Catalysts")
|
||||
.getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.jeiStyleRecipeCatalyst", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.jeiStyleCycledIngredients").setComment("JEI styled cycled ingredients")
|
||||
.getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.jeiStyleCycledIngredients", true));
|
||||
tag.getTag("inventory.guirecipe.jeiStyleRecipeCatalyst")
|
||||
.setComment("JEI Style Recipe Catalysts (0 - none, 1 - grid, 2 - scroll)").getIntValue(1);
|
||||
API.addOption(new OptionCycled("inventory.guirecipe.jeiStyleRecipeCatalyst", 3, true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.cycledIngredientsTooltip").setComment("Show cycled ingredients tooltip")
|
||||
.getBooleanValue(true);
|
||||
@@ -229,31 +251,56 @@ public class NEIClientConfig {
|
||||
.getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.slotHighlightPresent", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.infiniteScroll").setComment("Use Infinite Scroll for Handlers")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.infiniteScroll", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.maxHeight").setComment("Recipe GUI Max Height").getIntValue(370);
|
||||
API.addOption(new OptionIntegerField("inventory.guirecipe.maxHeight", 166, 4000));
|
||||
|
||||
tag.getTag("inventory.guirecipe.shiftOverlayRecipe")
|
||||
.setComment("Require holding shift to move items when overlaying recipe").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.shiftOverlayRecipe", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.scrollPages").setComment("Disable page scroll when overlaying recipe")
|
||||
.getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.scrollPages", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.profile").getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.profile", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.handlerInfo").setComment("ADVANCED: Handler Info Widget")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.handlerInfo", true));
|
||||
|
||||
tag.getTag("inventory.subsets.enabled").setComment("Enable/disable Subsets Dropdown").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.subsets.enabled", true));
|
||||
|
||||
tag.getTag("inventory.subsets.widgetPosition").setComment("Subsets Widget Position").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.subsets.widgetPosition", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.profile").getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.profile", true));
|
||||
|
||||
tag.getTag("inventory.history.enabled").setComment("Enable/disable History Panel").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.history.enabled", true));
|
||||
|
||||
tag.getTag("inventory.history.historyColor").setComment("Color of the history area display")
|
||||
.getHexValue(0xee555555);
|
||||
API.addOption(new OptionIntegerField("inventory.history.historyColor", 0, OptionIntegerField.UNSIGNED_INT_MAX));
|
||||
tag.getTag("inventory.history.color").setComment("Color of the history area display").getHexValue(0xee555555);
|
||||
API.addOption(new OptionIntegerField("inventory.history.color", 0, OptionIntegerField.UNSIGNED_INT_MAX));
|
||||
|
||||
tag.getTag("inventory.history.useRows").setComment("Rows used in historical areas").getIntValue(2);
|
||||
API.addOption(new OptionIntegerField("inventory.history.useRows", 1, 5));
|
||||
|
||||
tag.getTag("inventory.history.splittingMode").getIntValue(1);
|
||||
API.addOption(new OptionCycled("inventory.history.splittingMode", 2, true));
|
||||
tag.getTag("inventory.craftables.enabled").setComment("Enable/disable Craftables Panel").getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.craftables.enabled", true));
|
||||
|
||||
tag.getTag("inventory.craftables.color").setComment("Color of the craftables area display")
|
||||
.getHexValue(0xee555555);
|
||||
API.addOption(new OptionIntegerField("inventory.craftables.color", 0, OptionIntegerField.UNSIGNED_INT_MAX));
|
||||
|
||||
tag.getTag("inventory.craftables.useRows").setComment("Rows used in craftables areas").getIntValue(2);
|
||||
API.addOption(new OptionIntegerField("inventory.craftables.useRows", 1, 5));
|
||||
|
||||
tag.getTag("inventory.craftables.favoritesOnly").setComment("Show Only Favorites Recipes")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.craftables.favoritesOnly", true));
|
||||
|
||||
tag.getTag("inventory.collapsibleItems.enabled").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.collapsibleItems.enabled", true) {
|
||||
@@ -263,7 +310,7 @@ public class NEIClientConfig {
|
||||
super.onClick(button);
|
||||
CollapsibleItems.saveStates();
|
||||
CollapsibleItems.load();
|
||||
LayoutManager.markItemsDirty();
|
||||
ItemList.refreshItems.restart();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@@ -287,19 +334,6 @@ public class NEIClientConfig {
|
||||
0,
|
||||
OptionIntegerField.UNSIGNED_INT_MAX));
|
||||
|
||||
API.addOption(
|
||||
new OptionButton(
|
||||
"inventory.collapsibleItems.reloadLabel",
|
||||
"inventory.collapsibleItems.reloadButton",
|
||||
"inventory.collapsibleItems.reloadTip") {
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
LayoutManager.markItemsDirty();
|
||||
return super.onClick(button);
|
||||
}
|
||||
});
|
||||
|
||||
tag.getTag("inventory.itemzoom.enabled").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.itemzoom.enabled", true));
|
||||
|
||||
@@ -325,6 +359,8 @@ public class NEIClientConfig {
|
||||
tag.getTag("inventory.itemzoom.nameColor").getHexValue(0xFFFFFFFF);
|
||||
API.addOption(new OptionIntegerField("inventory.itemzoom.nameColor", 0, OptionIntegerField.UNSIGNED_INT_MAX));
|
||||
|
||||
setFavoriteDefaults(tag);
|
||||
|
||||
tag.getTag("inventory.itemIDs").getIntValue(1);
|
||||
API.addOption(new OptionCycled("inventory.itemIDs", 3, true));
|
||||
|
||||
@@ -347,6 +383,19 @@ public class NEIClientConfig {
|
||||
|
||||
API.addOption(new OptionOpenGui("world.presets", GuiPresetList.class));
|
||||
|
||||
tag.getTag("world.overlays.lock").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("world.overlays.lock", true));
|
||||
|
||||
tag.getTag("inventory.itempanelScale").getIntValue(100);
|
||||
ItemsPanelGrid.updateScale();
|
||||
API.addOption(new OptionIntegerField("inventory.itempanelScale", 1, 1000) {
|
||||
|
||||
@Override
|
||||
public void onTextChange(String text) {
|
||||
ItemsPanelGrid.updateScale();
|
||||
}
|
||||
});
|
||||
|
||||
tag.getTag("inventory.disableMouseScrollTransfer").getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.disableMouseScrollTransfer", true));
|
||||
|
||||
@@ -359,11 +408,24 @@ public class NEIClientConfig {
|
||||
}
|
||||
});
|
||||
|
||||
tag.getTag("inventory.gridRenderingCacheFPS").getIntValue(8);
|
||||
|
||||
tag.getTag("inventory.gridRenderingCacheMode").getIntValue(0);
|
||||
API.addOption(new OptionCycled("inventory.gridRenderingCacheMode", 3, true));
|
||||
|
||||
tag.getTag("inventory.gridRenderingCacheFPS").getIntValue(8);
|
||||
API.addOption(new OptionIntegerField("inventory.gridRenderingCacheFPS", 1, 144) {
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return OpenGlHelper.framebufferSupported && getIntSetting("inventory.gridRenderingCacheMode") == 1;
|
||||
}
|
||||
|
||||
});
|
||||
tag.getTag("inventory.hotkeysHelpText").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.hotkeysHelpText", true));
|
||||
tag.getTag("inventory.showHotkeys").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.showHotkeys", true));
|
||||
|
||||
tag.getTag("loadPluginsInParallel").getBooleanValue(true);
|
||||
tag.getTag("itemLoadingTimeout").getIntValue(500);
|
||||
|
||||
tag.getTag("command.creative").setDefaultValue("/gamemode {0} {1}");
|
||||
@@ -384,6 +446,27 @@ public class NEIClientConfig {
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.optimize_gui_overlap_computation", true));
|
||||
|
||||
tag.getTag("inventory.autocrafting").setComment("Autocrafting").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.autocrafting", true));
|
||||
|
||||
tag.getTag("inventory.itemUntranslator").setComment("Item Untranslator").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.itemUntranslator", true) {
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
super.onClick(button);
|
||||
|
||||
if (enableItemUntranslator()) {
|
||||
ItemUntranslator.getInstance().load();
|
||||
} else {
|
||||
ItemUntranslator.getInstance().unload();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
tag.getTag("tools.handler_load_from_config").setComment("ADVANCED: Load handlers from config")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("tools.handler_load_from_config", true) {
|
||||
@@ -460,12 +543,15 @@ public class NEIClientConfig {
|
||||
API.addOption(new OptionCycled("inventory.search.widgetAutofocus", 3, true));
|
||||
|
||||
tag.getTag("inventory.search.patternMode").setComment("Search Mode").getIntValue(1);
|
||||
API.addOption(new OptionCycled("inventory.search.patternMode", 3, true) {
|
||||
API.addOption(new OptionCycled("inventory.search.patternMode", 4, true) {
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
if (!super.onClick(button)) {
|
||||
return false;
|
||||
}
|
||||
SearchField.searchParser.clearCache();
|
||||
return super.onClick(button);
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
@@ -518,7 +604,7 @@ public class NEIClientConfig {
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
// SearchField.searchParser.clearCache();
|
||||
SearchField.searchParser.clearCache();
|
||||
return super.onClick(button);
|
||||
}
|
||||
|
||||
@@ -535,8 +621,11 @@ public class NEIClientConfig {
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
if (!super.onClick(button)) {
|
||||
return false;
|
||||
}
|
||||
SearchField.searchParser.clearCache();
|
||||
return super.onClick(button);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -560,8 +649,11 @@ public class NEIClientConfig {
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
if (!super.onClick(button)) {
|
||||
return false;
|
||||
}
|
||||
SearchField.searchParser.clearCache();
|
||||
return super.onClick(button);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -584,8 +676,11 @@ public class NEIClientConfig {
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
if (!super.onClick(button)) {
|
||||
return false;
|
||||
}
|
||||
SearchField.searchParser.clearCache();
|
||||
return super.onClick(button);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -608,8 +703,11 @@ public class NEIClientConfig {
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
if (!super.onClick(button)) {
|
||||
return false;
|
||||
}
|
||||
SearchField.searchParser.clearCache();
|
||||
return super.onClick(button);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -632,8 +730,11 @@ public class NEIClientConfig {
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
if (!super.onClick(button)) {
|
||||
return false;
|
||||
}
|
||||
SearchField.searchParser.clearCache();
|
||||
return super.onClick(button);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -651,6 +752,9 @@ public class NEIClientConfig {
|
||||
|
||||
});
|
||||
|
||||
tag.getTag("inventory.search.logSearchExceptions").setComment("Search exceptions for extended+")
|
||||
.getBooleanValue(false);
|
||||
|
||||
String prefixRedefinitions = tag.getTag("inventory.search.prefixRedefinitions").setComment(
|
||||
"Redefine search prefixes by providing a char-to-char map (JSON). The keys are the original prefixes, the values the new ones. Example: { \"$\": \"€\", \"#\": \"+\", \"@\": \"°\", \"%\": \"!\" }")
|
||||
.getValue("{}");
|
||||
@@ -661,47 +765,87 @@ public class NEIClientConfig {
|
||||
};
|
||||
Map<Character, Character> charMap = new Gson().fromJson(prefixRedefinitions, typeToken.getType());
|
||||
SearchField.searchParser.prefixRedefinitions.putAll(charMap);
|
||||
SearchField.searchParser.clearCache();
|
||||
} catch (JsonParseException e) {
|
||||
logger.warn("Failed to convert prefix redefinitions from JSON to CharToCharMap:", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void setFavoriteDefaults(ConfigTagParent tag) {
|
||||
|
||||
tag.getTag("inventory.favorites.enabled").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.favorites.enabled", true));
|
||||
|
||||
tag.getTag("inventory.favorites.worldSpecific").setComment("Global or world specific favorites")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.favorites.worldSpecific", true) {
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
super.onClick(button);
|
||||
FavoriteRecipes.reload();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
tag.getTag("inventory.favorites.showRecipeTooltipInPanel").setComment("Show recipe tooltips in Items Panel")
|
||||
.getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.favorites.showRecipeTooltipInPanel", true));
|
||||
|
||||
tag.getTag("inventory.favorites.showRecipeTooltipInGui").setComment("Show recipe tooltips in Recipe Gui")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.favorites.showRecipeTooltipInGui", true));
|
||||
|
||||
tag.getTag("inventory.favorites.generateSingleRecipeFavorites")
|
||||
.setComment("Automatically generate favorites for items with only one recipe").getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.favorites.generateSingleRecipeFavorites", true) {
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
super.onClick(button);
|
||||
FavoriteRecipes.loadAutoGeneratedRecipes();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
tag.getTag("inventory.favorites.depth").setComment("Bookmark creation depth").getIntValue(9);
|
||||
API.addOption(new OptionIntegerField("inventory.favorites.depth", 0, 100));
|
||||
}
|
||||
|
||||
private static void setDefaultKeyBindings() {
|
||||
API.addHashBind("gui.recipe", Keyboard.KEY_R);
|
||||
API.addHashBind("gui.usage", Keyboard.KEY_U);
|
||||
API.addKeyBind("gui.back", Keyboard.KEY_BACK);
|
||||
API.addHashBind("gui.enchant", Keyboard.KEY_X);
|
||||
API.addHashBind("gui.potion", Keyboard.KEY_P);
|
||||
API.addKeyBind("gui.enchant", Keyboard.KEY_X);
|
||||
API.addKeyBind("gui.potion", Keyboard.KEY_P);
|
||||
API.addKeyBind("gui.prev", Keyboard.KEY_PRIOR);
|
||||
API.addKeyBind("gui.next", Keyboard.KEY_NEXT);
|
||||
API.addKeyBind("gui.prev_machine", Keyboard.KEY_UP);
|
||||
API.addKeyBind("gui.next_machine", Keyboard.KEY_DOWN);
|
||||
API.addKeyBind("gui.prev_recipe", Keyboard.KEY_LEFT);
|
||||
API.addKeyBind("gui.next_recipe", Keyboard.KEY_RIGHT);
|
||||
API.addHashBind("gui.hide", Keyboard.KEY_O);
|
||||
API.addHashBind("gui.search", Keyboard.KEY_F);
|
||||
API.addHashBind("gui.bookmark", Keyboard.KEY_A);
|
||||
API.addHashBind("gui.bookmark_recipe", Keyboard.KEY_A + NEIClientUtils.SHIFT_HASH);
|
||||
API.addHashBind("gui.remove_recipe", Keyboard.KEY_A + NEIClientUtils.SHIFT_HASH);
|
||||
API.addHashBind("gui.bookmark_count", Keyboard.KEY_A + NEIClientUtils.CTRL_HASH);
|
||||
API.addHashBind(
|
||||
"gui.bookmark_recipe_count",
|
||||
Keyboard.KEY_A + NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH);
|
||||
API.addHashBind("gui.bookmark_pull_items", Keyboard.KEY_V);
|
||||
API.addHashBind("gui.bookmark_pull_items_ingredients", Keyboard.KEY_V + NEIClientUtils.SHIFT_HASH);
|
||||
API.addHashBind("gui.overlay", Keyboard.KEY_S);
|
||||
API.addHashBind("gui.overlay_use", Keyboard.KEY_S + NEIClientUtils.SHIFT_HASH);
|
||||
API.addHashBind("gui.overlay_hide", Keyboard.KEY_S + NEIClientUtils.CTRL_HASH);
|
||||
API.addHashBind("gui.hide_bookmarks", Keyboard.KEY_B);
|
||||
API.addKeyBind("gui.hide", Keyboard.KEY_O);
|
||||
API.addKeyBind("gui.search", Keyboard.KEY_F);
|
||||
API.addKeyBind("gui.overlay", Keyboard.KEY_S);
|
||||
API.addKeyBind("gui.craft_items", Keyboard.KEY_C);
|
||||
API.addKeyBind("gui.getprevioussearch", Keyboard.KEY_UP);
|
||||
API.addKeyBind("gui.getnextsearch", Keyboard.KEY_DOWN);
|
||||
API.addHashBind("gui.next_tooltip", Keyboard.KEY_Z);
|
||||
API.addKeyBind("gui.next_tooltip", Keyboard.KEY_Z);
|
||||
|
||||
API.addHashBind("gui.itemzoom_toggle", Keyboard.KEY_Z + NEIClientUtils.SHIFT_HASH);
|
||||
API.addHashBind("gui.itemzoom_hold", 0);
|
||||
API.addHashBind("gui.itemzoom_zoom_in", 0);
|
||||
API.addHashBind("gui.itemzoom_zoom_out", 0);
|
||||
API.addKeyBind("recipe.recipe", Keyboard.KEY_R);
|
||||
API.addKeyBind("recipe.usage", Keyboard.KEY_U);
|
||||
API.addKeyBind("recipe.back", Keyboard.KEY_BACK);
|
||||
API.addKeyBind("recipe.prev_machine", Keyboard.KEY_UP);
|
||||
API.addKeyBind("recipe.next_machine", Keyboard.KEY_DOWN);
|
||||
API.addKeyBind("recipe.prev_recipe", Keyboard.KEY_LEFT);
|
||||
API.addKeyBind("recipe.next_recipe", Keyboard.KEY_RIGHT);
|
||||
|
||||
API.addKeyBind("bookmark.add", Keyboard.KEY_A);
|
||||
API.addKeyBind("bookmark.favorite", Keyboard.KEY_F);
|
||||
API.addKeyBind("bookmark.favorite_item", Keyboard.KEY_F);
|
||||
API.addKeyBind("bookmark.remove_recipe", Keyboard.KEY_A);
|
||||
API.addKeyBind("bookmark.pull_items", Keyboard.KEY_V);
|
||||
API.addKeyBind("bookmark.chat_link", Keyboard.KEY_L);
|
||||
API.addKeyBind("bookmark.hide", Keyboard.KEY_B);
|
||||
|
||||
API.addKeyBind("itemzoom.toggle", Keyboard.KEY_Z);
|
||||
API.addKeyBind("itemzoom.hold", 0);
|
||||
API.addKeyBind("itemzoom.zoom_in", 0);
|
||||
API.addKeyBind("itemzoom.zoom_out", 0);
|
||||
|
||||
API.addKeyBind("world.chunkoverlay", Keyboard.KEY_F9);
|
||||
API.addKeyBind("world.moboverlay", Keyboard.KEY_F7);
|
||||
@@ -713,8 +857,10 @@ public class NEIClientConfig {
|
||||
API.addKeyBind("world.rain", 0);
|
||||
API.addKeyBind("world.heal", 0);
|
||||
API.addKeyBind("world.creative", 0);
|
||||
API.addHashBind("gui.copy_name", Keyboard.KEY_C + NEIClientUtils.CTRL_HASH);
|
||||
API.addHashBind("gui.copy_oredict", Keyboard.KEY_D + NEIClientUtils.CTRL_HASH);
|
||||
|
||||
API.addKeyBind("copy.name", Keyboard.KEY_C);
|
||||
API.addKeyBind("copy.oredict", Keyboard.KEY_D);
|
||||
API.addKeyBind("copy.identifier", Keyboard.KEY_X);
|
||||
}
|
||||
|
||||
public static OptionList getOptionList() {
|
||||
@@ -722,24 +868,27 @@ public class NEIClientConfig {
|
||||
}
|
||||
|
||||
public static void loadWorld(String worldPath) {
|
||||
final File specificDir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
|
||||
final boolean newWorld = !specificDir.exists();
|
||||
unloadWorld();
|
||||
setInternalEnabled(true);
|
||||
|
||||
if (!worldPath.equals(NEIClientConfig.worldPath)) {
|
||||
if (!worldPath.equals(NEIClientConfig.worldPath) || newWorld) {
|
||||
NEIClientConfig.worldPath = worldPath;
|
||||
|
||||
logger.debug("Loading " + (Minecraft.getMinecraft().isSingleplayer() ? "Local" : "Remote") + " World");
|
||||
|
||||
final File specificDir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
|
||||
final boolean newWorld = !specificDir.exists();
|
||||
|
||||
if (newWorld) {
|
||||
specificDir.mkdirs();
|
||||
}
|
||||
|
||||
world = new ConfigSet(new File(specificDir, "NEI.dat"), new ConfigFile(new File(specificDir, "NEI.cfg")));
|
||||
bootNEI(ClientUtils.getWorld());
|
||||
onWorldLoad(newWorld);
|
||||
|
||||
if (newWorld && Minecraft.getMinecraft().isSingleplayer()) {
|
||||
world.config.getTag("inventory.cheatmode")
|
||||
.setIntValue(NEIClientUtils.mc().playerController.isInCreativeMode() ? 2 : 0);
|
||||
}
|
||||
|
||||
bootNEI();
|
||||
onWorldLoad();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -747,7 +896,7 @@ public class NEIClientConfig {
|
||||
return NEIClientConfig.worldPath;
|
||||
}
|
||||
|
||||
private static void onWorldLoad(boolean newWorld) {
|
||||
private static void onWorldLoad() {
|
||||
world.config.setComment(
|
||||
"World based configuration of NEI.\nMost of these options can be changed ingame.\nDeleting any element will restore it to it's default value");
|
||||
|
||||
@@ -755,12 +904,6 @@ public class NEIClientConfig {
|
||||
creativeInv = new ItemStack[54];
|
||||
LayoutManager.searchField.setText(getSearchExpression());
|
||||
LayoutManager.quantity.setText(Integer.toString(getItemQuantity()));
|
||||
|
||||
if (newWorld && Minecraft.getMinecraft().isSingleplayer()) {
|
||||
world.config.getTag("inventory.cheatmode")
|
||||
.setIntValue(NEIClientUtils.mc().playerController.isInCreativeMode() ? 2 : 0);
|
||||
}
|
||||
|
||||
NEIInfo.load(ClientUtils.getWorld());
|
||||
}
|
||||
|
||||
@@ -774,62 +917,64 @@ public class NEIClientConfig {
|
||||
}
|
||||
|
||||
public static void unloadWorld() {
|
||||
if (ItemPanels.bookmarkPanel != null) {
|
||||
ItemPanels.bookmarkPanel.saveBookmarks();
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemPanels.bookmarkPanel.save();
|
||||
|
||||
SubsetWidget.saveHidden();
|
||||
FavoriteRecipes.save();
|
||||
CollapsibleItems.saveStates();
|
||||
|
||||
if (world != null) {
|
||||
world.saveNBT();
|
||||
}
|
||||
world.saveNBT();
|
||||
}
|
||||
|
||||
private static final Map<String, String> keySettings = new HashMap<>();
|
||||
|
||||
public static int getKeyBinding(String string) {
|
||||
final String key = keySettings.computeIfAbsent(string, (s) -> "keys." + s);
|
||||
return getSetting(key).getIntValue(Keyboard.KEY_NONE);
|
||||
return KeyManager.getKeyCode(string);
|
||||
}
|
||||
|
||||
public static void setDefaultKeyBinding(String string, int key) {
|
||||
getSetting("keys." + string).getIntValue(key);
|
||||
KeyManager.registerKeyBinding(string, key);
|
||||
}
|
||||
|
||||
public static boolean isKeyHashDown(String string) {
|
||||
final int hash = getKeyBinding(string);
|
||||
return hash != Keyboard.CHAR_NONE && hash == NEIClientUtils.getKeyHash();
|
||||
return KeyManager.isHashDown(string);
|
||||
}
|
||||
|
||||
public static String getKeyName(String keyBind) {
|
||||
final int hash = getKeyBinding(keyBind);
|
||||
|
||||
if (hash == Keyboard.CHAR_NONE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return NEIClientUtils.getKeyName(hash);
|
||||
return KeyManager.getKeyName(keyBind);
|
||||
}
|
||||
|
||||
public static void bootNEI(World world) {
|
||||
public static String getKeyName(String keyBind, int meta, int mouseBind) {
|
||||
return KeyManager.getKeyName(keyBind, meta, mouseBind);
|
||||
}
|
||||
|
||||
public static String getKeyName(String keyBind, int meta) {
|
||||
return KeyManager.getKeyName(keyBind, meta);
|
||||
}
|
||||
|
||||
public static void bootNEI() {
|
||||
|
||||
if (!mainNEIConfigLoaded) {
|
||||
// main NEI config loading
|
||||
ItemInfo.load(world);
|
||||
ItemInfo.load();
|
||||
GuiInfo.load();
|
||||
RecipeInfo.load();
|
||||
HeldItemHandler.load();
|
||||
LayoutManager.load();
|
||||
NEIController.load();
|
||||
BookmarkContainerInfo.load();
|
||||
InformationHandler.load();
|
||||
mainNEIConfigLoaded = true;
|
||||
|
||||
new Thread("NEI Plugin Loader") {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final Stream<Class<?>> stream = NEIClientConfig.getBooleanSetting("loadPluginsInParallel")
|
||||
? NEIClientConfig.pluginsList.parallelStream()
|
||||
: NEIClientConfig.pluginsList.stream();
|
||||
|
||||
NEIClientConfig.pluginsList.parallelStream().forEach(clazz -> {
|
||||
stream.forEach(clazz -> {
|
||||
try {
|
||||
IConfigureNEI config = (IConfigureNEI) clazz.getConstructor().newInstance();
|
||||
config.loadConfig();
|
||||
@@ -840,8 +985,9 @@ public class NEIClientConfig {
|
||||
}
|
||||
});
|
||||
|
||||
KeyManager.requestOptionsReload();
|
||||
RecipeCatalysts.loadCatalystInfo();
|
||||
ItemPanels.bookmarkPanel.load();
|
||||
SubsetWidget.loadCustomSubsets();
|
||||
SubsetWidget.loadHidden();
|
||||
CollapsibleItems.load();
|
||||
ItemSorter.loadConfig();
|
||||
@@ -853,15 +999,18 @@ public class NEIClientConfig {
|
||||
// API. I don't expect any handler to do this, but who knows what modders have come up with...
|
||||
pluginNEIConfigLoaded = true;
|
||||
MinecraftForge.EVENT_BUS.post(new NEIConfigsLoadedEvent());
|
||||
|
||||
ItemList.loadItems.restart();
|
||||
}
|
||||
}.start();
|
||||
} else {
|
||||
ItemPanels.bookmarkPanel.load();
|
||||
SubsetWidget.loadHidden();
|
||||
ItemList.loadItems.restart();
|
||||
if (ItemList.loadFinished) {
|
||||
ItemList.refreshItems.restart();
|
||||
} else {
|
||||
ItemList.loadItems.restart();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static boolean isWorldSpecific(String setting) {
|
||||
@@ -882,6 +1031,16 @@ public class NEIClientConfig {
|
||||
return !enabledOverride || getBooleanSetting("inventory.hidden");
|
||||
}
|
||||
|
||||
public static boolean autocraftingEnabled() {
|
||||
if (!getBooleanSetting("inventory.autocrafting")) return false;
|
||||
if (hasSMPCounterpart) return permissableActions.contains("autocraft");
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean favoritesEnabled() {
|
||||
return getBooleanSetting("inventory.favorites.enabled");
|
||||
}
|
||||
|
||||
public static boolean isBookmarkPanelHidden() {
|
||||
return !getBooleanSetting("inventory.bookmarks.enabled");
|
||||
}
|
||||
@@ -894,8 +1053,16 @@ public class NEIClientConfig {
|
||||
return getIntSetting("inventory.bookmarks.recipeTooltipsMode");
|
||||
}
|
||||
|
||||
public static boolean showRecipeMarker() {
|
||||
return getBooleanSetting("inventory.bookmarks.showRecipeMarker");
|
||||
public static boolean showRecipeTooltipInPanel() {
|
||||
return getBooleanSetting("inventory.favorites.showRecipeTooltipInPanel");
|
||||
}
|
||||
|
||||
public static boolean showRecipeTooltipInGui() {
|
||||
return getBooleanSetting("inventory.favorites.showRecipeTooltipInGui");
|
||||
}
|
||||
|
||||
public static int showRecipeMarkerMode() {
|
||||
return getIntSetting("inventory.bookmarks.showRecipeMarkerMode");
|
||||
}
|
||||
|
||||
public static boolean showItemQuantityWidget() {
|
||||
@@ -934,8 +1101,8 @@ public class NEIClientConfig {
|
||||
return getBooleanSetting("inventory.guirecipe.slotHighlightPresent");
|
||||
}
|
||||
|
||||
public static boolean areJEIStyleRecipeCatalystsVisible() {
|
||||
return getBooleanSetting("inventory.guirecipe.jeiStyleRecipeCatalyst");
|
||||
public static int getJEIStyleRecipeCatalysts() {
|
||||
return getIntSetting("inventory.guirecipe.jeiStyleRecipeCatalyst");
|
||||
}
|
||||
|
||||
public static boolean useCreativeTabStyle() {
|
||||
@@ -946,18 +1113,14 @@ public class NEIClientConfig {
|
||||
return getBooleanSetting("inventory.bookmarks.ignorePotionOverlap");
|
||||
}
|
||||
|
||||
public static int craftingChainDir() {
|
||||
return getIntSetting("inventory.bookmarks.craftingChainDir");
|
||||
public static int recipeChainDir() {
|
||||
return getIntSetting("inventory.bookmarks.recipeChainDir");
|
||||
}
|
||||
|
||||
public static boolean optimizeGuiOverlapComputation() {
|
||||
return getBooleanSetting("inventory.optimize_gui_overlap_computation");
|
||||
}
|
||||
|
||||
public static boolean useJEIStyledCycledIngredients() {
|
||||
return getBooleanSetting("inventory.guirecipe.jeiStyleCycledIngredients");
|
||||
}
|
||||
|
||||
public static boolean showCycledIngredientsTooltip() {
|
||||
return getBooleanSetting("inventory.guirecipe.cycledIngredientsTooltip");
|
||||
}
|
||||
@@ -1066,6 +1229,10 @@ public class NEIClientConfig {
|
||||
return getBooleanSetting("inventory.history.enabled");
|
||||
}
|
||||
|
||||
public static boolean showCraftablesPanelWidget() {
|
||||
return getBooleanSetting("inventory.craftables.enabled");
|
||||
}
|
||||
|
||||
public static int getGridRenderingCacheMode() {
|
||||
return OpenGlHelper.framebufferSupported ? getIntSetting("inventory.gridRenderingCacheMode") : 0;
|
||||
}
|
||||
@@ -1074,6 +1241,10 @@ public class NEIClientConfig {
|
||||
return getBooleanSetting("inventory.collapsibleItems.enabled");
|
||||
}
|
||||
|
||||
public static boolean enableItemUntranslator() {
|
||||
return getBooleanSetting("inventory.itemUntranslator");
|
||||
}
|
||||
|
||||
public static boolean getMagnetMode() {
|
||||
return enabledActions.contains("magnet");
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ 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;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
@@ -25,57 +25,80 @@ 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.nbt.NBTTagCompound;
|
||||
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 com.gtnewhorizon.gtnhlib.util.numberformatting.NumberFormatUtil;
|
||||
|
||||
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;
|
||||
|
||||
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<>();
|
||||
private static final Map<Integer, Integer> keyHashMap = new HashMap<>();
|
||||
private static final DecimalFormat CHANCE_FORMAT = new DecimalFormat("##0.##%");
|
||||
|
||||
public static final int ALT_HASH = 1 << 27;
|
||||
public static final int SHIFT_HASH = 1 << 26;
|
||||
public static final int CTRL_HASH = 1 << 25;
|
||||
|
||||
static {
|
||||
keyHashMap.put(Keyboard.KEY_LSHIFT, SHIFT_HASH);
|
||||
keyHashMap.put(Keyboard.KEY_RSHIFT, SHIFT_HASH);
|
||||
|
||||
keyHashMap.put(Keyboard.KEY_LCONTROL, CTRL_HASH);
|
||||
keyHashMap.put(Keyboard.KEY_LCONTROL, CTRL_HASH);
|
||||
|
||||
keyHashMap.put(Keyboard.KEY_LMETA, CTRL_HASH);
|
||||
keyHashMap.put(Keyboard.KEY_RMETA, CTRL_HASH);
|
||||
|
||||
keyHashMap.put(Keyboard.KEY_LMENU, ALT_HASH);
|
||||
keyHashMap.put(Keyboard.KEY_LMENU, ALT_HASH);
|
||||
}
|
||||
public static 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();
|
||||
@@ -103,16 +126,26 @@ public class NEIClientUtils extends NEIServerUtils {
|
||||
});
|
||||
}
|
||||
|
||||
public static String formatNumbers(BigInteger aNumber) {
|
||||
public static String formatNumber(Number aNumber) {
|
||||
|
||||
if (NEIModContainer.isGTNHLibLoaded()) {
|
||||
return NumberFormatUtil.formatNumber(aNumber);
|
||||
}
|
||||
|
||||
return getDecimalFormat().format(aNumber);
|
||||
}
|
||||
|
||||
public static String formatNumbers(long aNumber) {
|
||||
return getDecimalFormat().format(aNumber);
|
||||
public static String formatFluid(Number aNumber) {
|
||||
|
||||
if (NEIModContainer.isGTNHLibLoaded()) {
|
||||
return NumberFormatUtil.formatFluid(aNumber);
|
||||
}
|
||||
|
||||
return getDecimalFormat().format(aNumber) + " L";
|
||||
}
|
||||
|
||||
public static String formatNumbers(double aNumber) {
|
||||
return getDecimalFormat().format(aNumber);
|
||||
public static String formatChance(float chance) {
|
||||
return CHANCE_FORMAT.format(chance);
|
||||
}
|
||||
|
||||
public static void deleteHeldItem() {
|
||||
@@ -175,7 +208,7 @@ public class NEIClientUtils extends NEIServerUtils {
|
||||
public static void cheatItem(ItemStack stack, int button, int mode) {
|
||||
if (!canCheatItem(stack)) return;
|
||||
|
||||
if (mode == -1 && button == 0 && shiftKey() && NEIClientConfig.hasSMPCounterPart()) {
|
||||
if (mode == -1 && button == 0 && controlKey() && NEIClientConfig.hasSMPCounterPart()) {
|
||||
for (IInfiniteItemHandler handler : ItemInfo.infiniteHandlers) {
|
||||
if (!handler.canHandleItem(stack)) continue;
|
||||
|
||||
@@ -347,6 +380,10 @@ public class NEIClientUtils extends NEIServerUtils {
|
||||
else sendCommand(getStringSetting("command.heal"), mc().thePlayer.getCommandSenderName());
|
||||
}
|
||||
|
||||
public static void sendChatItemLink(NBTTagCompound payload) {
|
||||
if (hasSMPCounterPart()) NEICPH.sendChatLink(payload);
|
||||
}
|
||||
|
||||
public static void toggleMagnetMode() {
|
||||
if (hasSMPCounterPart()) NEICPH.sendToggleMagnetMode();
|
||||
}
|
||||
@@ -386,18 +423,11 @@ public class NEIClientUtils extends NEIServerUtils {
|
||||
if (textWidth > containerWidth) {
|
||||
int dots = fontRenderer.getStringWidth("...");
|
||||
|
||||
if (containerWidth > dots) {
|
||||
textWidth += dots;
|
||||
|
||||
while (textWidth > containerWidth) {
|
||||
textWidth -= fontRenderer.getCharWidth(text.charAt(text.length() - 1));
|
||||
text = text.substring(0, text.length() - 1);
|
||||
}
|
||||
|
||||
return text + "...";
|
||||
if (containerWidth <= dots) {
|
||||
return "...";
|
||||
}
|
||||
|
||||
return "...";
|
||||
return fontRenderer.trimStringToWidth(text, containerWidth - dots) + "...";
|
||||
}
|
||||
|
||||
return text;
|
||||
@@ -425,78 +455,8 @@ public class NEIClientUtils extends NEIServerUtils {
|
||||
return Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU);
|
||||
}
|
||||
|
||||
public static int getMetaHash() {
|
||||
if (Keyboard.getEventKeyState()) {
|
||||
int hash = 0;
|
||||
|
||||
if (altKey()) {
|
||||
hash = hash | ALT_HASH;
|
||||
}
|
||||
|
||||
if (shiftKey()) {
|
||||
hash = hash | SHIFT_HASH;
|
||||
}
|
||||
|
||||
if (controlKey()) {
|
||||
hash = hash | CTRL_HASH;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int getKeyHash() {
|
||||
|
||||
if (Keyboard.getEventKeyState()) {
|
||||
final int keycode = Keyboard.getEventKey();
|
||||
|
||||
if (!keyHashMap.containsKey(keycode)) {
|
||||
return getMetaHash() + keycode;
|
||||
}
|
||||
}
|
||||
|
||||
return Keyboard.CHAR_NONE;
|
||||
}
|
||||
|
||||
public static String getKeyHashName(int keyBind) {
|
||||
StringJoiner keyText = new StringJoiner(" + ");
|
||||
|
||||
if ((keyBind & CTRL_HASH) != 0) {
|
||||
keyText.add(translate(Minecraft.isRunningOnMac ? "key.ctrl.mac" : "key.ctrl"));
|
||||
}
|
||||
|
||||
if ((keyBind & SHIFT_HASH) != 0) {
|
||||
keyText.add(translate("key.shift"));
|
||||
}
|
||||
|
||||
if ((keyBind & ALT_HASH) != 0) {
|
||||
keyText.add(translate("key.alt"));
|
||||
}
|
||||
|
||||
return keyText.toString();
|
||||
}
|
||||
|
||||
public static String getKeyName(int keyBind) {
|
||||
keyBind = keyHashMap.getOrDefault(keyBind, keyBind);
|
||||
StringJoiner keyText = new StringJoiner(" + ");
|
||||
String hashText = getKeyHashName(keyBind);
|
||||
int keyID = unHashKey(keyBind);
|
||||
|
||||
if (!hashText.isEmpty()) {
|
||||
keyText.add(hashText);
|
||||
}
|
||||
|
||||
if (keyID != Keyboard.CHAR_NONE || hashText.isEmpty()) {
|
||||
keyText.add(Keyboard.getKeyName(keyID));
|
||||
}
|
||||
|
||||
return keyText.toString();
|
||||
}
|
||||
|
||||
public static int unHashKey(int keyBind) {
|
||||
return keyBind & ~(CTRL_HASH | SHIFT_HASH | ALT_HASH);
|
||||
public static String getKeyName(int keyBind, int mouseBind) {
|
||||
return KeyManager.getKeyName(keyBind, mouseBind);
|
||||
}
|
||||
|
||||
public static void playClickSound() {
|
||||
@@ -522,4 +482,69 @@ public class NEIClientUtils extends NEIServerUtils {
|
||||
reportErrorBuffered(e, buffer, "null");
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawRect(double left, double top, double width, double height, Color color) {
|
||||
final boolean is2DTexture = GL11.glGetBoolean(GL11.GL_TEXTURE_2D);
|
||||
final boolean isBlend = GL11.glGetBoolean(GL11.GL_BLEND);
|
||||
final Tessellator tessellator = Tessellator.instance;
|
||||
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
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.glColor4f(1, 1, 1, 1);
|
||||
if (is2DTexture) GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
if (!isBlend) GL11.glDisable(GL11.GL_BLEND);
|
||||
}
|
||||
|
||||
public static void drawNEIOverlayText(String text, Rectangle4i rect, float scale, int color, boolean shadow,
|
||||
Alignment alignment) {
|
||||
final float screenScale = mc().currentScreen.width * 1f / mc().displayWidth;
|
||||
final double smallTextScale = Math
|
||||
.max(screenScale, (Math.max(scale, 1f) * (GuiDraw.fontRenderer.getUnicodeFlag() ? 3F / 4F : 1F / 2F)));
|
||||
|
||||
NEIClientUtils.gl2DRenderContext(() -> {
|
||||
final int width = GuiDraw.fontRenderer.getStringWidth(text);
|
||||
final float partW = rect.w / 2f;
|
||||
final float partH = rect.h / 2f;
|
||||
final double offsetX = Math
|
||||
.ceil(rect.x + partW + partW * alignment.x - (width / 2f * (alignment.x + 1)) * smallTextScale);
|
||||
final double offsetY = Math.ceil(
|
||||
rect.y + partH
|
||||
+ partH * alignment.y
|
||||
- (GuiDraw.fontRenderer.FONT_HEIGHT / 2f * (alignment.y + 1)) * smallTextScale);
|
||||
|
||||
GL11.glTranslated(offsetX, offsetY, 0);
|
||||
GL11.glScaled(smallTextScale, smallTextScale, 1);
|
||||
GuiDraw.fontRenderer.drawString(text, 0, 0, color, shadow);
|
||||
GL11.glScaled(1 / smallTextScale, 1 / smallTextScale, 1);
|
||||
GL11.glTranslated(-1 * offsetX, -1 * offsetY, 0);
|
||||
});
|
||||
}
|
||||
|
||||
public static void drawNEIOverlayText(String text, int x, int y) {
|
||||
drawNEIOverlayText(text, new Rectangle4i(x, y, 16, 16), 0.5f, 0xFDD835, false, Alignment.TopLeft);
|
||||
}
|
||||
|
||||
public static void gl2DRenderContext(Runnable callback) {
|
||||
boolean isLighting = GL11.glGetBoolean(GL11.GL_LIGHTING);
|
||||
boolean isDepthTest = GL11.glGetBoolean(GL11.GL_DEPTH_TEST);
|
||||
boolean isAlphaTest = GL11.glGetBoolean(GL11.GL_ALPHA_TEST);
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
GL11.glEnable(GL11.GL_ALPHA_TEST);
|
||||
GL11.glDisable(GL11.GL_DEPTH_TEST);
|
||||
|
||||
callback.run();
|
||||
|
||||
if (isLighting) GL11.glEnable(GL11.GL_LIGHTING);
|
||||
if (isDepthTest) GL11.glEnable(GL11.GL_DEPTH_TEST);
|
||||
if (!isAlphaTest) GL11.glDisable(GL11.GL_ALPHA_TEST);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +1,35 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import static codechicken.lib.gui.GuiDraw.getMousePosition;
|
||||
import static codechicken.nei.NEIClientConfig.canCheatItem;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.client.gui.inventory.GuiContainerCreative;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.inventory.SlotCrafting;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.client.ClientCommandHandler;
|
||||
|
||||
import codechicken.core.CommonUtils;
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.nei.api.API;
|
||||
import codechicken.nei.api.GuiInfo;
|
||||
import codechicken.nei.api.IInfiniteItemHandler;
|
||||
import codechicken.nei.api.INEIGuiHandler;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.commands.CommandBookmarkAdd;
|
||||
import codechicken.nei.commands.CommandRecipeId;
|
||||
import codechicken.nei.commands.CommandUntranslator;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.guihook.IContainerInputHandler;
|
||||
import codechicken.nei.guihook.IContainerSlotClickHandler;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.util.EmptyContainer;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
public class NEIController implements IContainerSlotClickHandler, IContainerInputHandler {
|
||||
|
||||
@@ -39,6 +48,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,32 +67,48 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
|
||||
return gui.field_147007_t && gui.field_147008_s.size() > 1;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static void registerClientCommands() {
|
||||
ClientCommandHandler.instance.registerCommand(new CommandBookmarkAdd());
|
||||
ClientCommandHandler.instance.registerCommand(new CommandRecipeId());
|
||||
ClientCommandHandler.instance.registerCommand(new CommandUntranslator());
|
||||
}
|
||||
|
||||
public static void updateUnlimitedItems(InventoryPlayer inventory) {
|
||||
if (!NEIClientConfig.canPerformAction("item") || !NEIClientConfig.hasSMPCounterPart()) return;
|
||||
|
||||
LinkedList<ItemStack> beforeStacks = new LinkedList<>();
|
||||
for (int i = 0; i < inventory.getSizeInventory(); i++)
|
||||
beforeStacks.add(NEIServerUtils.copyStack(inventory.getStackInSlot(i)));
|
||||
|
||||
for (int i = 0; i < inventory.getSizeInventory(); i++) {
|
||||
int size = inventory.getSizeInventory();
|
||||
for (int i = 0; i < size; i++) {
|
||||
ItemStack stack = inventory.getStackInSlot(i);
|
||||
if (stack == null) continue;
|
||||
|
||||
for (IInfiniteItemHandler handler : ItemInfo.infiniteHandlers)
|
||||
if (handler.canHandleItem(stack) && handler.isItemInfinite(stack))
|
||||
handler.replenishInfiniteStack(inventory, i);
|
||||
}
|
||||
for (IInfiniteItemHandler handler : ItemInfo.infiniteHandlers) {
|
||||
if (!handler.canHandleItem(stack) || !handler.isItemInfinite(stack)) continue;
|
||||
|
||||
for (int i = 0; i < inventory.getSizeInventory(); i++) {
|
||||
ItemStack newstack = inventory.getStackInSlot(i);
|
||||
long beforeSize = packStackSize(stack.stackSize, stack.getItemDamage());
|
||||
handler.replenishInfiniteStack(inventory, i);
|
||||
|
||||
if (!NEIServerUtils.areStacksIdentical(beforeStacks.get(i), newstack)) {
|
||||
inventory.setInventorySlotContents(i, beforeStacks.get(i)); // restore in case of SMP fail
|
||||
NEIClientUtils.setSlotContents(i, newstack, false); // sends via SMP handler ;)
|
||||
ItemStack newstack = inventory.getStackInSlot(i);
|
||||
if (!sameStack(stack, beforeSize, newstack)) {
|
||||
NEIClientUtils.setSlotContents(i, newstack, false); // sends via SMP handler ;)
|
||||
stack.stackSize = (int) (beforeSize >> 32);
|
||||
stack.setItemDamage((int) beforeSize);
|
||||
inventory.setInventorySlotContents(i, stack); // restore in case of SMP fail
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static long packStackSize(int stackSize, int itemDamage) {
|
||||
return ((long) stackSize << 32) | (itemDamage & 0xFFFFFFFFL);
|
||||
}
|
||||
|
||||
private static boolean sameStack(ItemStack before, long beforeSize, ItemStack stack) {
|
||||
if (stack == null) return before == null;
|
||||
return before != null && Item.getIdFromItem(before.getItem()) == Item.getIdFromItem(stack.getItem())
|
||||
&& beforeSize == packStackSize(stack.stackSize, stack.getItemDamage());
|
||||
}
|
||||
|
||||
public static void processCreativeCycling(InventoryPlayer inventory) {
|
||||
if (NEIClientConfig.invCreativeMode() && NEIClientUtils.controlKey()) {
|
||||
if (selectedItem != inventory.currentItem) {
|
||||
@@ -122,7 +149,7 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
|
||||
return true;
|
||||
}
|
||||
|
||||
if (button == 1 && slot instanceof SlotCrafting) // right click
|
||||
if (button == 1 && modifier != 2 && slot instanceof SlotCrafting) // right click
|
||||
{
|
||||
for (int i1 = 0; i1 < 64; i1++) // click this slot 64 times
|
||||
manager.handleSlotClick(slot.slotNumber, button, 0);
|
||||
@@ -134,26 +161,40 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
|
||||
&& slot != null
|
||||
&& slot.getStack() != null
|
||||
&& slot.isItemValid(slot.getStack())) {
|
||||
if (!canCheatItem(slot.getStack())) return false;
|
||||
|
||||
NEIClientUtils.cheatItem(slot.getStack(), button, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GuiInfo.hasCustomSlots(gui)) return false;
|
||||
|
||||
if (slotIndex >= 0 && NEIClientUtils.shiftKey()
|
||||
&& NEIClientUtils.getHeldItem() != null
|
||||
&& !slot.getHasStack()) {
|
||||
ItemStack held = NEIClientUtils.getHeldItem();
|
||||
manager.handleSlotClick(slot.slotNumber, button, 0);
|
||||
if (slot.isItemValid(held) && !ItemInfo.fastTransferExemptions.contains(slot.getClass()))
|
||||
fastTransferManager.performMassTransfer(gui, pickedUpFromSlot, slotIndex, held);
|
||||
if (NEIClientUtils.shiftKey()) {
|
||||
// fix small mouse movement while clicking causing slotIndex to be -999
|
||||
if (slotIndex == -999) {
|
||||
final Point mouse = GuiDraw.getMousePosition();
|
||||
slot = gui.getSlotAtPosition(mouse.x, mouse.y);
|
||||
|
||||
return true;
|
||||
}
|
||||
if (slot != null) {
|
||||
slotIndex = slot.slotNumber;
|
||||
}
|
||||
}
|
||||
|
||||
if (slotIndex == -999 && NEIClientUtils.shiftKey() && button == 0) {
|
||||
fastTransferManager.throwAll(gui, pickedUpFromSlot);
|
||||
return true;
|
||||
if (slotIndex >= 0 && NEIClientUtils.getHeldItem() != null && !slot.getHasStack()) {
|
||||
final ItemStack held = NEIClientUtils.getHeldItem();
|
||||
manager.handleSlotClick(slot.slotNumber, button, 0);
|
||||
|
||||
if (slot.isItemValid(held) && !ItemInfo.fastTransferExemptions.contains(slot.getClass())) {
|
||||
fastTransferManager.performMassTransfer(gui, pickedUpFromSlot, slotIndex, held);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (slotIndex == -999 && button == 0) {
|
||||
fastTransferManager.throwAll(gui, pickedUpFromSlot);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -220,7 +261,7 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
|
||||
|
||||
// slot in GuiRecipe does not contain actual stack
|
||||
// and scroll should be handled by GuiRecipe, not here
|
||||
if (gui instanceof GuiRecipe) return false;
|
||||
if (gui.inventorySlots instanceof EmptyContainer) return false;
|
||||
|
||||
Point mousePos = getMousePosition();
|
||||
Slot mouseover = manager.window.getSlotAtPosition(mousePos.x, mousePos.y);
|
||||
|
||||
@@ -7,8 +7,7 @@ import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
@@ -18,6 +17,7 @@ import codechicken.core.launch.CodeChickenCorePlugin;
|
||||
import codechicken.nei.api.IConfigureNEI;
|
||||
import codechicken.nei.asm.NEICorePlugin;
|
||||
import codechicken.nei.config.IMCHandler;
|
||||
import codechicken.nei.guihook.HideousLinkedList;
|
||||
import codechicken.nei.recipe.GuiRecipeTab;
|
||||
import cpw.mods.fml.client.FMLFileResourcePack;
|
||||
import cpw.mods.fml.client.FMLFolderResourcePack;
|
||||
@@ -25,25 +25,30 @@ 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.event.FMLServerAboutToStartEvent;
|
||||
import cpw.mods.fml.common.versioning.ArtifactVersion;
|
||||
import cpw.mods.fml.common.versioning.VersionParser;
|
||||
import cpw.mods.fml.common.versioning.VersionRange;
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public class NEIModContainer extends DummyModContainer {
|
||||
|
||||
public static LinkedList<IConfigureNEI> plugins = new LinkedList<>();
|
||||
public static final LinkedList<IConfigureNEI> plugins = new HideousLinkedList<>(new CopyOnWriteArrayList<>());
|
||||
|
||||
private static boolean gregTech5Loaded;
|
||||
private static boolean gtnhLibLoaded;
|
||||
private static boolean cubicChunksLoaded;
|
||||
|
||||
private static ASMDataTable asmDataTable;
|
||||
|
||||
public NEIModContainer() {
|
||||
super(getModMetadata());
|
||||
loadMetadata();
|
||||
}
|
||||
|
||||
private static ModMetadata getModMetadata() {
|
||||
@@ -51,7 +56,7 @@ public class NEIModContainer extends DummyModContainer {
|
||||
modMetadata.name = "NotEnoughItems";
|
||||
modMetadata.modId = "NotEnoughItems";
|
||||
modMetadata.version = Tags.VERSION;
|
||||
modMetadata.authorList = Arrays.asList("ChickenBones", "mitchej123");
|
||||
modMetadata.authorList = Arrays.asList("ChickenBones", "mitchej123", "SLPrime");
|
||||
modMetadata.url = "https://github.com/GTNewHorizons/NotEnoughItems";
|
||||
modMetadata.description = "Recipe Viewer, Inventory Manager, Item Spawner, Cheats and more; GTNH Version includes many enhancements.";
|
||||
return modMetadata;
|
||||
@@ -65,6 +70,10 @@ public class NEIModContainer extends DummyModContainer {
|
||||
return gtnhLibLoaded;
|
||||
}
|
||||
|
||||
public static boolean isCCLoaded() {
|
||||
return cubicChunksLoaded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ArtifactVersion> getRequirements() {
|
||||
Set<ArtifactVersion> deps = new HashSet<>();
|
||||
@@ -76,36 +85,12 @@ public class NEIModContainer extends DummyModContainer {
|
||||
public List<ArtifactVersion> getDependencies() {
|
||||
List<ArtifactVersion> deps = new ArrayList<>();
|
||||
deps.add(VersionParser.parseVersionReference("CodeChickenCore@[" + codechicken.core.asm.Tags.VERSION + ",)"));
|
||||
deps.add(VersionParser.parseVersionReference("gtnhlib@[0.6.0,)"));
|
||||
deps.add(VersionParser.parseVersionReference("gtnhlib@[0.9.6,)"));
|
||||
return deps;
|
||||
}
|
||||
|
||||
private String description;
|
||||
|
||||
private void loadMetadata() {
|
||||
description = super.getMetadata().description.replace("Supporters:", EnumChatFormatting.AQUA + "Supporters:");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModMetadata getMetadata() {
|
||||
StringBuilder s_plugins = new StringBuilder();
|
||||
if (plugins.size() == 0) {
|
||||
s_plugins.append(EnumChatFormatting.RED).append("No installed plugins.");
|
||||
} else {
|
||||
s_plugins.append(EnumChatFormatting.GREEN).append("Installed plugins: ");
|
||||
for (int i = 0; i < plugins.size(); i++) {
|
||||
if (i > 0) s_plugins.append(", ");
|
||||
IConfigureNEI plugin = plugins.get(i);
|
||||
s_plugins.append(plugin.getName()).append(" ").append(plugin.getVersion());
|
||||
}
|
||||
s_plugins.append(".");
|
||||
}
|
||||
|
||||
ModMetadata meta = super.getMetadata();
|
||||
meta.description = description.replace("<plugins>", s_plugins.toString());
|
||||
return meta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerBus(EventBus bus, LoadController controller) {
|
||||
bus.register(this);
|
||||
@@ -116,13 +101,17 @@ public class NEIModContainer extends DummyModContainer {
|
||||
public void preInit(FMLPreInitializationEvent event) {
|
||||
gregTech5Loaded = Loader.isModLoaded("gregtech") && !Loader.isModLoaded("gregapi_post");
|
||||
gtnhLibLoaded = Loader.isModLoaded("gtnhlib");
|
||||
cubicChunksLoaded = Loader.isModLoaded("cubicchunks");
|
||||
if (CommonUtils.isClient()) ClientHandler.preInit();
|
||||
asmDataTable = event.getAsmData();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void init(FMLInitializationEvent event) {
|
||||
if (CommonUtils.isClient()) ClientHandler.load();
|
||||
|
||||
if (CommonUtils.isClient()) {
|
||||
ClientHandler.load();
|
||||
IMCForNEI.IMCSender();
|
||||
}
|
||||
ServerHandler.load();
|
||||
}
|
||||
|
||||
@@ -139,9 +128,15 @@ public class NEIModContainer extends DummyModContainer {
|
||||
GuiRecipeTab.loadHandlerInfo();
|
||||
ClientHandler.loadPluginsList();
|
||||
ClientHandler.loadHandlerOrdering();
|
||||
asmDataTable = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onServerAboutToStart(FMLServerAboutToStartEvent event) {
|
||||
NEIServerConfig.resetFirstLoad();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void handleIMCMessages(FMLInterModComms.IMCEvent event) {
|
||||
IMCHandler.processIMC(event.getMessages());
|
||||
@@ -161,4 +156,8 @@ public class NEIModContainer extends DummyModContainer {
|
||||
public Class<?> getCustomResourcePackClass() {
|
||||
return getSource().isDirectory() ? FMLFolderResourcePack.class : FMLFileResourcePack.class;
|
||||
}
|
||||
|
||||
public static ASMDataTable getAsmDataTable() {
|
||||
return asmDataTable;
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.inventory.InventoryBasic;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.play.INetHandlerPlayServer;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityMobSpawner;
|
||||
@@ -88,9 +89,17 @@ public class NEISPH implements IServerPacketHandler {
|
||||
case C2S.SET_DUMMY_SLOT:
|
||||
handleDummySlotSet(sender, packet);
|
||||
break;
|
||||
case C2S.SEND_CHAT_ITEM_LINK:
|
||||
handleSendChatItemLink(sender, packet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSendChatItemLink(EntityPlayerMP sender, PacketCustom packet) {
|
||||
final NBTTagCompound payloadTag = packet.readNBTTagCompound();
|
||||
NEIServerUtils.sendChatItemLink(sender, payloadTag);
|
||||
}
|
||||
|
||||
private void handleDummySlotSet(EntityPlayerMP sender, PacketCustom packet) {
|
||||
int slotNumber = packet.readShort();
|
||||
ItemStack stack = packet.readItemStack(true);
|
||||
|
||||
@@ -18,9 +18,10 @@ import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.JsonToNBT;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
import net.minecraftforge.permission.PermissionLevel;
|
||||
import net.minecraftforge.permission.PermissionManager;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
@@ -35,24 +36,38 @@ import codechicken.lib.packet.PacketCustom;
|
||||
|
||||
public class NEIServerConfig {
|
||||
|
||||
private static MinecraftServer server;
|
||||
|
||||
private static boolean firstLoad;
|
||||
public static Logger logger = LogManager.getLogger("NotEnoughItems");
|
||||
public static File saveDir;
|
||||
public static ConfigFile serverConfig;
|
||||
public static Map<Integer, NBTTagCompound> dimTags = new HashMap<>();
|
||||
public static HashMap<String, PlayerSave> playerSaves = new HashMap<>();
|
||||
public static ItemStackMap<Set<String>> bannedItems = new ItemStackMap<>();
|
||||
private static boolean doesPermAPIExist = false;
|
||||
|
||||
public static void resetFirstLoad() {
|
||||
firstLoad = true;
|
||||
}
|
||||
|
||||
public static void load(World world) {
|
||||
if (MinecraftServer.getServer() != server) {
|
||||
if (firstLoad) {
|
||||
firstLoad = false;
|
||||
logger.debug("Loading NEI Server");
|
||||
server = MinecraftServer.getServer();
|
||||
saveDir = new File(DimensionManager.getCurrentSaveRootDirectory(), "NEI");
|
||||
|
||||
dimTags.clear();
|
||||
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);
|
||||
}
|
||||
@@ -93,6 +108,7 @@ public class NEIServerConfig {
|
||||
setDefaultFeature("save-state");
|
||||
setDefaultFeature("item");
|
||||
setDefaultFeature("delete");
|
||||
setDefaultFeature("autocraft", "ALL");
|
||||
setDefaultFeature("notify-item", "CONSOLE, OP");
|
||||
}
|
||||
|
||||
@@ -121,7 +137,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) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.zip.ZipException;
|
||||
|
||||
import net.minecraft.command.ICommandSender;
|
||||
@@ -17,6 +18,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;
|
||||
@@ -27,11 +29,11 @@ import net.minecraft.nbt.NBTException;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.ChatComponentText;
|
||||
import net.minecraft.util.ChatComponentTranslation;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraft.world.WorldSettings.GameType;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
@@ -43,12 +45,29 @@ import codechicken.lib.inventory.InventoryRange;
|
||||
import codechicken.lib.inventory.InventoryUtils;
|
||||
import codechicken.lib.packet.PacketCustom;
|
||||
import codechicken.nei.PacketIDs.S2C;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.NBTHelper;
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper;
|
||||
|
||||
public class NEIServerUtils {
|
||||
|
||||
private static class GTMetaBaseItemHolder {
|
||||
|
||||
private static final Class<?> gtMetaBaseItem = loadMetaBaseItem();
|
||||
|
||||
private static Class<?> loadMetaBaseItem() {
|
||||
try {
|
||||
final ClassLoader loader = NEIServerUtils.class.getClassLoader();
|
||||
return ReflectionHelper
|
||||
.getClass(loader, "gregtech.api.items.MetaBaseItem", "gregtech.api.items.GT_MetaBase_Item");
|
||||
} catch (Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isRaining(World world) {
|
||||
return world.getWorldInfo().isRaining();
|
||||
}
|
||||
@@ -56,7 +75,7 @@ public class NEIServerUtils {
|
||||
public static void toggleRaining(World world, boolean notify) {
|
||||
boolean raining = !world.isRaining();
|
||||
if (!raining) // turn off
|
||||
((WorldServer) world).provider.resetRainAndThunder();
|
||||
world.provider.resetRainAndThunder();
|
||||
else world.getWorldInfo().setRaining(!isRaining(world));
|
||||
|
||||
if (notify)
|
||||
@@ -69,6 +88,48 @@ public class NEIServerUtils {
|
||||
player.extinguish();
|
||||
}
|
||||
|
||||
public static void sendChatItemLink(EntityPlayerMP sender, NBTTagCompound payload) {
|
||||
if (payload == null) {
|
||||
sender.addChatMessage(new ChatComponentText("Invalid bookmark payload"));
|
||||
return;
|
||||
}
|
||||
|
||||
final String linkType = payload.getString("linkType");
|
||||
final String payloadId = UUID.randomUUID().toString().substring(0, 8);
|
||||
final PacketCustom packet = new PacketCustom(NEISPH.channel, S2C.CACHE_BOOKMARK_DATA).writeString(payloadId)
|
||||
.writeNBTTagCompound((NBTTagCompound) payload.copy());
|
||||
|
||||
for (EntityPlayer player : ServerUtils.getPlayers()) {
|
||||
if (player instanceof EntityPlayerMP playerMP) {
|
||||
packet.sendToPlayer(playerMP);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
final IChatComponent clickable;
|
||||
|
||||
if (payload.hasKey("item")) {
|
||||
clickable = StackInfo.loadFromNBT(payload.getCompoundTag("item")).func_151000_E();
|
||||
} else {
|
||||
clickable = new ChatComponentText("[")
|
||||
.appendSibling(new ChatComponentTranslation("nei.chat.item_link." + linkType + ".text"))
|
||||
.appendText("]");
|
||||
}
|
||||
|
||||
if (clickable == null) {
|
||||
throw new Exception("Invalid ItemStack NBT");
|
||||
}
|
||||
|
||||
clickable.getChatStyle()
|
||||
.setChatClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/nei_bookmark " + payloadId));
|
||||
ServerUtils.sendChatToAll(
|
||||
new ChatComponentTranslation("nei.chat.item_link.text", sender.getDisplayName(), clickable));
|
||||
} catch (Exception e) {
|
||||
sender.addChatMessage(new ChatComponentText(e.toString()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static long getTime(World world) {
|
||||
return world.getWorldInfo().getWorldTime();
|
||||
}
|
||||
@@ -146,7 +207,7 @@ public class NEIServerUtils {
|
||||
|
||||
/**
|
||||
* NBT-friendly version of {@link #areStacksSameType(ItemStack, ItemStack)}
|
||||
*
|
||||
*
|
||||
* @param stack1 The {@link ItemStack} being compared.
|
||||
* @param stack2 The {@link ItemStack} to compare to.
|
||||
* @return whether the two items are the same in terms of itemID, damage and NBT.
|
||||
@@ -154,7 +215,7 @@ public class NEIServerUtils {
|
||||
public static boolean areStacksSameTypeWithNBT(ItemStack stack1, ItemStack stack2) {
|
||||
return stack1 != null && stack2 != null
|
||||
&& stack1.getItem() == stack2.getItem()
|
||||
&& (!stack2.getHasSubtypes() || stack2.getItemDamage() == stack1.getItemDamage())
|
||||
&& (stack2.isItemStackDamageable() || stack2.getItemDamage() == stack1.getItemDamage())
|
||||
&& NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound());
|
||||
}
|
||||
|
||||
@@ -177,19 +238,33 @@ 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
|
||||
*/
|
||||
public static boolean isItemTool(ItemStack stack) {
|
||||
return GTMetaBaseItemHolder.gtMetaBaseItem != null
|
||||
&& GTMetaBaseItemHolder.gtMetaBaseItem.isInstance(stack.getItem());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -377,7 +452,7 @@ public class NEIServerUtils {
|
||||
}
|
||||
|
||||
public static List<Integer> getRange(final int start, final int end) {
|
||||
return new AbstractList<Integer>() {
|
||||
return new AbstractList<>() {
|
||||
|
||||
@Override
|
||||
public Integer get(int index) {
|
||||
|
||||
@@ -23,6 +23,7 @@ public final class PacketIDs {
|
||||
public static final int SET_CREATIVE_PLUS_MODE = 23;
|
||||
public static final int REQUEST_POTION_GUI = 24;
|
||||
public static final int SET_DUMMY_SLOT = 25;
|
||||
public static final int SEND_CHAT_ITEM_LINK = 26;
|
||||
}
|
||||
|
||||
public static final class S2C {
|
||||
@@ -36,5 +37,6 @@ public final class PacketIDs {
|
||||
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;
|
||||
public static final int CACHE_BOOKMARK_DATA = 25;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,22 @@
|
||||
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.api.ShortcutInputHandler;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.guihook.IContainerTooltipHandler;
|
||||
import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.GuiUsageRecipe;
|
||||
|
||||
public abstract class PanelWidget extends Widget implements IContainerTooltipHandler {
|
||||
public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ? extends ItemsGrid.MouseContext>>
|
||||
extends Widget {
|
||||
|
||||
protected static final int PADDING = 2;
|
||||
|
||||
@@ -27,20 +27,20 @@ public abstract class PanelWidget extends Widget implements IContainerTooltipHan
|
||||
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) {
|
||||
|
||||
@@ -54,11 +54,12 @@ public abstract class PanelWidget extends Widget implements IContainerTooltipHan
|
||||
}
|
||||
|
||||
@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) {
|
||||
|
||||
@@ -72,61 +73,34 @@ public abstract class PanelWidget extends Widget implements IContainerTooltipHan
|
||||
}
|
||||
|
||||
@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 Rectangle4i calculateBounds(GuiContainer gui);
|
||||
|
||||
public abstract int getMarginLeft(GuiContainer gui);
|
||||
|
||||
public abstract int getMarginTop(GuiContainer gui);
|
||||
|
||||
public abstract int getWidth(GuiContainer gui);
|
||||
|
||||
public abstract int getHeight(GuiContainer gui);
|
||||
protected static int snapDownToMultiple(int value, int multiple) {
|
||||
return (value / multiple) * multiple;
|
||||
}
|
||||
|
||||
public void resize(GuiContainer gui) {
|
||||
final Rectangle4i margin = new Rectangle4i(
|
||||
getMarginLeft(gui),
|
||||
getMarginTop(gui),
|
||||
getWidth(gui),
|
||||
getHeight(gui));
|
||||
final Rectangle4i bounds = calculateBounds(gui);
|
||||
|
||||
final 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) {
|
||||
@@ -171,22 +145,21 @@ public abstract class PanelWidget extends Widget implements IContainerTooltipHan
|
||||
protected abstract int resizeFooter(GuiContainer gui);
|
||||
|
||||
public void setVisible() {
|
||||
if (grid.getPerPage() > 0 && !grid.isEmpty()) {
|
||||
if (this.grid.getPerPage() > 0 && !this.grid.isEmpty()) {
|
||||
LayoutManager.addWidget(pagePrev);
|
||||
LayoutManager.addWidget(pageNext);
|
||||
LayoutManager.addWidget(pageLabel);
|
||||
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
|
||||
@@ -200,37 +173,33 @@ public abstract class PanelWidget extends Widget implements IContainerTooltipHan
|
||||
|
||||
@Override
|
||||
public void mouseDragged(int mousex, int mousey, int button, long heldTime) {
|
||||
if (mouseDownSlot >= grid.realItems.size()) {
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -245,7 +214,7 @@ public abstract class PanelWidget extends Widget implements IContainerTooltipHan
|
||||
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;
|
||||
}
|
||||
@@ -311,25 +280,17 @@ public abstract class PanelWidget extends Widget implements IContainerTooltipHan
|
||||
|
||||
@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.copy();
|
||||
|
||||
if (NEIController.manager.window instanceof GuiRecipe || NEIClientUtils.shiftKey()
|
||||
|| !NEIClientConfig.canCheatItem(item)) {
|
||||
|
||||
if (button == 0) {
|
||||
GuiCraftingRecipe.openRecipeGui("item", item);
|
||||
} else if (button == 1) {
|
||||
GuiUsageRecipe.openRecipeGui("item", item);
|
||||
}
|
||||
|
||||
mouseDownSlot = -1;
|
||||
return;
|
||||
|| !NEIClientConfig.canCheatItem(hoverSlot.getItemStack())) {
|
||||
ShortcutInputHandler.handleMouseClick(hoverSlot.getItemStack());
|
||||
} else {
|
||||
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.getItemStack()), button, -1);
|
||||
}
|
||||
|
||||
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.slotIndex), button, -1);
|
||||
}
|
||||
|
||||
mouseDownSlot = -1;
|
||||
@@ -339,20 +300,22 @@ public abstract class PanelWidget extends Widget implements IContainerTooltipHan
|
||||
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);
|
||||
if (KeyManager.isKeyDown("gui.next")) {
|
||||
this.grid.shiftPage(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.prev")) {
|
||||
grid.shiftPage(-1);
|
||||
if (KeyManager.isKeyDown("gui.prev")) {
|
||||
this.grid.shiftPage(-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -361,41 +324,28 @@ public abstract class PanelWidget extends Widget implements IContainerTooltipHan
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
|
||||
return currenttip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleItemDisplayName(GuiContainer gui, ItemStack itemstack, List<String> currenttip) {
|
||||
return currenttip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
|
||||
List<String> currenttip) {
|
||||
return currenttip;
|
||||
return this.grid.contains(px, py);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,12 +24,12 @@ public class PopupInputHandler implements IContainerInputHandler {
|
||||
@Override
|
||||
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyID) {
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.enchant") && canPerformAction("enchant")) {
|
||||
if (KeyManager.isHashDown("gui.enchant") && canPerformAction("enchant")) {
|
||||
NEICPH.sendOpenEnchantmentWindow();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.potion") && canPerformAction("potion")) {
|
||||
if (KeyManager.isHashDown("gui.potion") && canPerformAction("potion")) {
|
||||
NEICPH.sendOpenPotionWindow();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package codechicken.nei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -10,22 +11,27 @@ import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
import codechicken.nei.ItemList.AllMultiItemFilter;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.recipe.Badge;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
|
||||
/**
|
||||
* Simply an {@link ItemStack} with position. Mainly used in the recipe handlers.
|
||||
*/
|
||||
public class PositionedStack {
|
||||
|
||||
/** Maximum chance value representing 100% probability (1 unit = 0.01%). */
|
||||
public static final int CHANCE_FULL = 10_000;
|
||||
|
||||
public int relx;
|
||||
public int rely;
|
||||
public ItemStack[] items;
|
||||
// compatibility dummy
|
||||
public ItemStack item;
|
||||
|
||||
protected int chance = CHANCE_FULL;
|
||||
private boolean permutated = false;
|
||||
|
||||
public PositionedStack(Object object, int x, int y, boolean genPerms) {
|
||||
@@ -81,9 +87,26 @@ public class PositionedStack {
|
||||
for (ItemStack item : items) if (item.stackSize > i) item.stackSize = i;
|
||||
}
|
||||
|
||||
public List<Badge> getBadges() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getChance() {
|
||||
return this.chance;
|
||||
}
|
||||
|
||||
public void setChance(int chance) {
|
||||
this.chance = chance;
|
||||
}
|
||||
|
||||
public PositionedStack copy() {
|
||||
PositionedStack pStack = new PositionedStack(Arrays.asList(items), relx, rely, false);
|
||||
PositionedStack pStack = new PositionedStack(
|
||||
Arrays.stream(this.items).map(ItemStack::copy).toArray(ItemStack[]::new),
|
||||
relx,
|
||||
rely,
|
||||
false);
|
||||
pStack.permutated = this.permutated;
|
||||
pStack.chance = this.chance;
|
||||
return pStack;
|
||||
}
|
||||
|
||||
@@ -92,40 +115,42 @@ public class PositionedStack {
|
||||
}
|
||||
|
||||
public List<ItemStack> getFilteredPermutations(ItemFilter additionalFilter) {
|
||||
List<ItemStack> items = Arrays.asList(this.items).stream().filter(getItemFilter(additionalFilter)::matches)
|
||||
.collect(Collectors.toList());
|
||||
List<ItemStack> items = Arrays.asList(this.items);
|
||||
|
||||
if (items.isEmpty()) {
|
||||
items.addAll(
|
||||
Arrays.asList(this.items).stream().filter(item -> !ItemInfo.isHidden(item))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
if (items.isEmpty()) {
|
||||
items.addAll(Arrays.asList(this.items));
|
||||
}
|
||||
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::containsManual).reversed());
|
||||
return items;
|
||||
}
|
||||
|
||||
private ItemFilter getItemFilter(ItemFilter additionalFilter) {
|
||||
return new AllMultiItemFilter(
|
||||
additionalFilter,
|
||||
item -> !ItemInfo.isHidden(item),
|
||||
PresetsList.getItemFilter(),
|
||||
GuiRecipe.getSearchItemFilter());
|
||||
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) {
|
||||
public int getPermutationIndex(ItemStack stack) {
|
||||
|
||||
for (int index = 0; index < this.items.length; index++) {
|
||||
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(this.items[index], ingredient)) {
|
||||
setPermutationToRender(index);
|
||||
return true;
|
||||
if (NEIServerUtils.areStacksSameType(items[index], stack)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean setPermutationToRender(ItemStack ingredient) {
|
||||
final int stackIndex = getPermutationIndex(ingredient);
|
||||
|
||||
if (stackIndex >= 0) {
|
||||
setPermutationToRender(stackIndex);
|
||||
}
|
||||
|
||||
return stackIndex >= 0;
|
||||
}
|
||||
|
||||
public void setPermutationToRender(int index) {
|
||||
@@ -138,6 +163,10 @@ public class PositionedStack {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(int mx, int my) {
|
||||
return mx >= this.relx - 1 && mx < this.relx + 17 && my >= this.rely - 1 && my < this.rely + 17;
|
||||
}
|
||||
|
||||
public boolean contains(ItemStack ingredient) {
|
||||
for (ItemStack item : items) if (NEIServerUtils.areStacksSameTypeCrafting(item, ingredient)) return true;
|
||||
|
||||
@@ -148,7 +177,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;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import codechicken.core.CommonUtils;
|
||||
import codechicken.nei.SubsetWidget.SubsetTag;
|
||||
import codechicken.nei.api.API;
|
||||
import codechicken.nei.api.IRecipeFilter;
|
||||
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
|
||||
@@ -33,6 +34,7 @@ import codechicken.nei.util.NBTJson;
|
||||
public class PresetsList {
|
||||
|
||||
public enum PresetMode {
|
||||
SUBSET,
|
||||
HIDE,
|
||||
REMOVE,
|
||||
GROUP;
|
||||
@@ -66,11 +68,11 @@ public class PresetsList {
|
||||
}
|
||||
}
|
||||
|
||||
protected static class RecipesFilter implements IRecipeFilterProvider, IRecipeFilter {
|
||||
protected static class PresetRecipeFilter implements IRecipeFilterProvider, IRecipeFilter {
|
||||
|
||||
public Set<String> cache;
|
||||
|
||||
public IRecipeFilter getFilter() {
|
||||
public IRecipeFilter getRecipeFilter() {
|
||||
|
||||
if (cache == null) {
|
||||
cache = PresetsList.presets.stream().filter(p -> p.enabled && p.mode == PresetMode.REMOVE)
|
||||
@@ -81,17 +83,20 @@ public class PresetsList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(IRecipeHandler handler, List<PositionedStack> ingredients, PositionedStack result,
|
||||
List<PositionedStack> others) {
|
||||
public boolean matches(IRecipeHandler handler, int recipeIndex) {
|
||||
|
||||
if (matchPositionedStack(ingredients, false)) {
|
||||
if (matchPositionedStack(handler.getIngredientStacks(recipeIndex), false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PositionedStack result = handler.getResultStack(recipeIndex);
|
||||
|
||||
if (result != null && matchPositionedStack(result)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final List<PositionedStack> others = handler.getOtherStacks(recipeIndex);
|
||||
|
||||
if (!others.isEmpty() && matchPositionedStack(others, true)) {
|
||||
return true;
|
||||
}
|
||||
@@ -143,7 +148,7 @@ public class PresetsList {
|
||||
}
|
||||
|
||||
public static final List<Preset> presets = new ArrayList<>();
|
||||
protected static RecipesFilter recipeFilter = new RecipesFilter();
|
||||
protected static PresetRecipeFilter recipeFilter = new PresetRecipeFilter();
|
||||
protected static ItemPanelFilter itemFilter = new ItemPanelFilter();
|
||||
|
||||
static {
|
||||
@@ -158,9 +163,7 @@ public class PresetsList {
|
||||
public static void load() {
|
||||
final File presetsFile = new File(CommonUtils.getMinecraftDir(), "saves/NEI/global/presets.ini");
|
||||
|
||||
if (presetsFile == null || !presetsFile.exists()) {
|
||||
return;
|
||||
}
|
||||
if (!presetsFile.exists()) return;
|
||||
|
||||
List<String> itemStrings;
|
||||
try (FileInputStream reader = new FileInputStream(presetsFile)) {
|
||||
@@ -216,6 +219,8 @@ public class PresetsList {
|
||||
if (!preset.items.isEmpty()) {
|
||||
presets.add(preset);
|
||||
}
|
||||
|
||||
updateSubsets();
|
||||
}
|
||||
|
||||
public static void savePresets() {
|
||||
@@ -236,14 +241,29 @@ public class PresetsList {
|
||||
try (FileOutputStream output = new FileOutputStream(presetsFile)) {
|
||||
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Filed to save presets list to file {}", presetsFile, e);
|
||||
NEIClientConfig.logger.error("Failed to save presets list to file {}", presetsFile, e);
|
||||
}
|
||||
|
||||
recipeFilter.cache = null;
|
||||
itemFilter.cache = null;
|
||||
updateSubsets();
|
||||
CollapsibleItems.saveStates();
|
||||
CollapsibleItems.load();
|
||||
LayoutManager.markItemsDirty();
|
||||
ItemList.refreshItems.restart();
|
||||
}
|
||||
|
||||
private static void updateSubsets() {
|
||||
SubsetWidget.removeTag("Presets");
|
||||
|
||||
for (Preset preset : PresetsList.presets) {
|
||||
if (preset.enabled && preset.mode == PresetMode.SUBSET) {
|
||||
SubsetWidget.addTag(
|
||||
new SubsetTag(
|
||||
"Presets." + preset.name,
|
||||
stack -> preset.items.contains(Preset.getIdentifier(stack))));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,10 +3,13 @@ package codechicken.nei;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import codechicken.nei.SearchField.GuiSearchField;
|
||||
import codechicken.nei.api.IRecipeFilter;
|
||||
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
|
||||
import codechicken.nei.util.TextHistory;
|
||||
|
||||
public abstract class RecipeSearchField extends TextField {
|
||||
public abstract class RecipeSearchField extends TextField implements ItemFilterProvider, IRecipeFilterProvider {
|
||||
|
||||
private static final TextHistory history = new TextHistory();
|
||||
|
||||
@@ -17,9 +20,12 @@ public abstract class RecipeSearchField extends TextField {
|
||||
|
||||
@Override
|
||||
protected void initInternalTextField() {
|
||||
field = new GuiSearchField();
|
||||
final GuiSearchField field = new GuiSearchField();
|
||||
field.setMaxStringLength(maxSearchLength);
|
||||
field.setCursorPositionZero();
|
||||
field.setSkipRecipeTokens(true);
|
||||
((SearchTextFormatter) field.getFormatter()).setContextToken("<>");
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
@@ -44,11 +50,11 @@ public abstract class RecipeSearchField extends TextField {
|
||||
@Override
|
||||
public void lastKeyTyped(int keyID, char keyChar) {
|
||||
|
||||
if (focused() && NEIClientConfig.isKeyHashDown("gui.getprevioussearch")) {
|
||||
if (focused() && KeyManager.isKeyDown("gui.getprevioussearch")) {
|
||||
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
|
||||
}
|
||||
|
||||
if (focused() && NEIClientConfig.isKeyHashDown("gui.getnextsearch")) {
|
||||
if (focused() && KeyManager.isKeyDown("gui.getnextsearch")) {
|
||||
handleNavigateHistory(TextHistory.Direction.NEXT);
|
||||
}
|
||||
}
|
||||
@@ -58,10 +64,16 @@ public abstract class RecipeSearchField extends TextField {
|
||||
return EnumChatFormatting.getTextWithoutFormattingCodes(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter getFilter() {
|
||||
return ((GuiSearchField) field).getFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IRecipeFilter getRecipeFilter() {
|
||||
return ((GuiSearchField) field).getRecipeFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFocus(boolean focus) {
|
||||
final boolean previousFocus = field.isFocused();
|
||||
|
||||
@@ -15,7 +15,8 @@ import net.minecraftforge.fluids.FluidStack;
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.nei.ItemList.NothingItemFilter;
|
||||
import codechicken.nei.SearchTokenParser.ISearchParserProvider;
|
||||
import codechicken.nei.SearchTokenParser.SearchMode;
|
||||
import codechicken.nei.api.IRecipeFilter;
|
||||
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
@@ -83,14 +84,15 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchMode getSearchMode() {
|
||||
return SearchMode.fromInt(NEIClientConfig.getIntSetting("inventory.search." + this.name + "SearchMode"));
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
public static class GuiSearchField extends FormattedTextField {
|
||||
public static class GuiSearchField extends FormattedTextField implements ItemFilterProvider, IRecipeFilterProvider {
|
||||
|
||||
protected final SearchTokenParser searchParser;
|
||||
protected boolean skipRecipeTokens = false;
|
||||
|
||||
public GuiSearchField() {
|
||||
this(SearchField.searchParser);
|
||||
@@ -100,14 +102,30 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
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);
|
||||
return this.searchParser.getFilter(filterText, this.skipRecipeTokens);
|
||||
}
|
||||
|
||||
public IRecipeFilter getRecipeFilter(String filterText) {
|
||||
return this.searchParser.getRecipeFilter(filterText);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -203,7 +221,6 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
public void onTextChange(String oldText) {
|
||||
final String newText = text();
|
||||
if (!newText.equals(oldText)) {
|
||||
if (newText.length() > 0) NEIClientConfig.logger.debug("Searching for " + newText);
|
||||
NEIClientConfig.setSearchExpression(newText);
|
||||
ItemList.updateFilter.restart();
|
||||
}
|
||||
@@ -212,14 +229,14 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
@Override
|
||||
public void lastKeyTyped(int keyID, char keyChar) {
|
||||
|
||||
if (isVisible() && NEIClientConfig.isKeyHashDown("gui.search")) {
|
||||
if (isVisible() && KeyManager.isHashDown("gui.search")) {
|
||||
setFocus(true);
|
||||
}
|
||||
if (focused() && NEIClientConfig.isKeyHashDown("gui.getprevioussearch")) {
|
||||
if (focused() && KeyManager.isKeyDown("gui.getprevioussearch")) {
|
||||
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
|
||||
}
|
||||
|
||||
if (focused() && NEIClientConfig.isKeyHashDown("gui.getnextsearch")) {
|
||||
if (focused() && KeyManager.isKeyDown("gui.getnextsearch")) {
|
||||
handleNavigateHistory(TextHistory.Direction.NEXT);
|
||||
}
|
||||
}
|
||||
@@ -270,7 +287,7 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// regex and extended+
|
||||
if (!search.isEmpty()) {
|
||||
try {
|
||||
return Pattern.compile(search, Pattern.MULTILINE | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
|
||||
@@ -281,7 +298,7 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
}
|
||||
|
||||
public static String getEscapedSearchText(ItemStack stack) {
|
||||
final FluidStack fluidStack = StackInfo.isFluidContainer(stack) ? null : StackInfo.getFluid(stack);
|
||||
final FluidStack fluidStack = StackInfo.getFluid(stack);
|
||||
String displayName;
|
||||
|
||||
if (fluidStack != null) {
|
||||
@@ -296,6 +313,9 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
public static String getEscapedSearchText(String text) {
|
||||
text = EnumChatFormatting.getTextWithoutFormattingCodes(text);
|
||||
|
||||
boolean addQuotes = text.contains(" ")
|
||||
&& NEIClientConfig.getBooleanSetting("inventory.search.quoteDropItemName");
|
||||
|
||||
switch (NEIClientConfig.getIntSetting("inventory.search.patternMode")) {
|
||||
case 1:
|
||||
text = text.replaceAll("[\\?|\\*]", "\\\\$0");
|
||||
@@ -303,11 +323,20 @@ public class SearchField extends TextField implements ItemFilterProvider {
|
||||
case 2:
|
||||
text = text.replaceAll("[{}()\\[\\].+*?^$\\\\|]", "\\\\$0");
|
||||
break;
|
||||
case 3:
|
||||
// In extended+ quotes require only quotes to be escaped
|
||||
if (addQuotes) {
|
||||
text = text.replaceAll("\"", "\\\\$0");
|
||||
} else {
|
||||
String prefixes = searchParser.getPrefixes();
|
||||
text = text.replaceAll("[-<>^{}|/\\\\\"" + Pattern.quote(prefixes) + "]", "\\\\$0");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (text.contains(" ") && NEIClientConfig.getBooleanSetting("inventory.search.quoteDropItemName")) {
|
||||
if (addQuotes) {
|
||||
text = "\"" + text + "\"";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,66 +1,96 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import codechicken.nei.FormattedTextField.TextFormatter;
|
||||
import codechicken.nei.SearchTokenParser.SearchToken;
|
||||
import codechicken.nei.search.SearchExpressionFormatVisitor;
|
||||
import codechicken.nei.search.SearchExpressionUtils;
|
||||
import codechicken.nei.search.SearchToken;
|
||||
|
||||
public class SearchTextFormatter implements TextFormatter {
|
||||
|
||||
protected final SearchTokenParser searchParser;
|
||||
protected String contextToken = "";
|
||||
|
||||
public SearchTextFormatter(SearchTokenParser searchParser) {
|
||||
this.searchParser = searchParser;
|
||||
}
|
||||
|
||||
public void setContextToken(String contextToken) {
|
||||
this.contextToken = contextToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(String text) {
|
||||
final String[] parts = (text + "| ").split("\\|");
|
||||
StringJoiner formattedText = new StringJoiner(EnumChatFormatting.GRAY + "|");
|
||||
final int patternMode = NEIClientConfig.getIntSetting("inventory.search.patternMode");
|
||||
if (patternMode == 3) {
|
||||
final int spaceModeEnabled = NEIClientConfig.getIntSetting("inventory.search.spaceMode");
|
||||
if (spaceModeEnabled == 1) {
|
||||
text = SearchTokenParser.SPACE_PATTERN.matcher(text).replaceAll("\\\\ ");
|
||||
}
|
||||
final SearchExpressionFormatVisitor visitor = new SearchExpressionFormatVisitor(searchParser);
|
||||
return SearchExpressionUtils.visitRecipeSearchExpression(text, visitor);
|
||||
} else {
|
||||
final StringBuilder formattedText = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < parts.length - 1; i++) {
|
||||
final String filterText = parts[i];
|
||||
final List<SearchToken> tokens = searchParser.splitSearchText(filterText);
|
||||
StringBuilder formattedPart = new StringBuilder();
|
||||
int startIndex = 0;
|
||||
for (String[] orQuery : searchParser.splitByDelimiters(text, "|", false)) {
|
||||
final String filterText = orQuery[1];
|
||||
|
||||
for (SearchToken token : tokens) {
|
||||
formattedPart.append(filterText.substring(startIndex, token.start));
|
||||
EnumChatFormatting tokenColor = EnumChatFormatting.RESET;
|
||||
formattedText.append(SearchExpressionUtils.HIGHLIGHTS.OR + orQuery[0]);
|
||||
|
||||
if (token.firstChar != null) {
|
||||
tokenColor = searchParser.getProvider(token.firstChar).getHighlightedColor();
|
||||
for (String[] contextPart : searchParser.splitByDelimiters(filterText, this.contextToken, false)) {
|
||||
|
||||
if (!contextPart[0].isEmpty()) {
|
||||
formattedText.append(
|
||||
SearchExpressionUtils.HIGHLIGHTS.RECIPE + contextPart[0].substring(0, 1)
|
||||
+ EnumChatFormatting.RESET);
|
||||
contextPart[1] = contextPart[0].substring(1) + contextPart[1];
|
||||
}
|
||||
|
||||
if (contextPart[1].isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int startIndex = 0;
|
||||
|
||||
for (SearchToken token : searchParser.splitSearchText(contextPart[1])) {
|
||||
formattedText.append(contextPart[1].substring(startIndex, token.start));
|
||||
EnumChatFormatting tokenColor = EnumChatFormatting.RESET;
|
||||
|
||||
if (token.firstChar != null) {
|
||||
tokenColor = searchParser.getProvider(token.firstChar).getHighlightedColor();
|
||||
}
|
||||
|
||||
if (token.ignore != null) {
|
||||
formattedText
|
||||
.append(SearchExpressionUtils.HIGHLIGHTS.NEGATE + String.valueOf(token.ignore));
|
||||
}
|
||||
|
||||
if (token.firstChar != null) {
|
||||
formattedText.append(tokenColor + String.valueOf(token.firstChar));
|
||||
}
|
||||
|
||||
if (token.quotes) {
|
||||
formattedText.append(SearchExpressionUtils.HIGHLIGHTS.QUOTED + "\"");
|
||||
}
|
||||
|
||||
if (!token.rawText.isEmpty()) {
|
||||
formattedText.append(tokenColor + token.rawText);
|
||||
}
|
||||
|
||||
if (token.quotes) {
|
||||
formattedText.append(SearchExpressionUtils.HIGHLIGHTS.QUOTED + "\"");
|
||||
}
|
||||
|
||||
startIndex = token.end;
|
||||
}
|
||||
|
||||
formattedText.append(contextPart[1].substring(startIndex, contextPart[1].length()));
|
||||
}
|
||||
|
||||
if (token.ignore) {
|
||||
formattedPart.append(EnumChatFormatting.BLUE + "-");
|
||||
}
|
||||
|
||||
if (token.firstChar != null) {
|
||||
formattedPart.append(tokenColor + String.valueOf(token.firstChar));
|
||||
}
|
||||
|
||||
if (token.quotes) {
|
||||
formattedPart.append(EnumChatFormatting.GOLD + "\"");
|
||||
}
|
||||
|
||||
if (!token.rawText.isEmpty()) {
|
||||
formattedPart.append(tokenColor + token.rawText);
|
||||
}
|
||||
|
||||
if (token.quotes) {
|
||||
formattedPart.append(EnumChatFormatting.GOLD + "\"");
|
||||
}
|
||||
|
||||
startIndex = token.end;
|
||||
}
|
||||
|
||||
formattedPart.append(filterText.substring(startIndex, filterText.length()));
|
||||
formattedText.add(formattedPart);
|
||||
return formattedText.toString();
|
||||
}
|
||||
|
||||
return formattedText.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.Language;
|
||||
@@ -18,9 +15,16 @@ import net.minecraft.util.EnumChatFormatting;
|
||||
import codechicken.nei.ItemList.AllMultiItemFilter;
|
||||
import codechicken.nei.ItemList.AnyMultiItemFilter;
|
||||
import codechicken.nei.ItemList.EverythingItemFilter;
|
||||
import codechicken.nei.ItemList.NegatedItemFilter;
|
||||
import codechicken.nei.ItemList.NothingItemFilter;
|
||||
import codechicken.nei.api.IRecipeFilter;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.filter.AllMultiRecipeFilter;
|
||||
import codechicken.nei.filter.AnyMultiRecipeFilter;
|
||||
import codechicken.nei.filter.RecipeFilter;
|
||||
import codechicken.nei.filter.RecipeFilter.FilterContext;
|
||||
import codechicken.nei.search.ItemFilterVisitor;
|
||||
import codechicken.nei.search.RecipeFilterVisitor;
|
||||
import codechicken.nei.search.SearchExpressionUtils;
|
||||
import codechicken.nei.search.SearchToken;
|
||||
|
||||
public class SearchTokenParser {
|
||||
|
||||
@@ -39,20 +43,6 @@ public class SearchTokenParser {
|
||||
}
|
||||
}
|
||||
|
||||
public static class SearchToken {
|
||||
|
||||
public boolean ignore = false;
|
||||
public boolean quotes = false;
|
||||
public Character firstChar = null;
|
||||
|
||||
public String[] words;
|
||||
|
||||
public String rawText = "";
|
||||
public int start = 0;
|
||||
public int end = 0;
|
||||
|
||||
}
|
||||
|
||||
public static interface ISearchParserProvider {
|
||||
|
||||
public ItemFilter getFilter(String searchText);
|
||||
@@ -69,7 +59,13 @@ public class SearchTokenParser {
|
||||
|
||||
public EnumChatFormatting getHighlightedColor();
|
||||
|
||||
public SearchMode getSearchMode();
|
||||
default SearchMode getSearchMode() {
|
||||
return SearchMode.fromInt(NEIClientConfig.getIntSetting("inventory.search." + getName() + "SearchMode"));
|
||||
}
|
||||
|
||||
default String getName() {
|
||||
return String.valueOf(getPrefix());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ProvidersCache {
|
||||
@@ -83,7 +79,7 @@ public class SearchTokenParser {
|
||||
}
|
||||
}
|
||||
|
||||
private static class IsRegisteredItemFilter implements ItemFilter {
|
||||
public static class IsRegisteredItemFilter implements ItemFilter {
|
||||
|
||||
public ItemFilter filter;
|
||||
|
||||
@@ -99,10 +95,14 @@ public class SearchTokenParser {
|
||||
}
|
||||
}
|
||||
|
||||
public static final Pattern SPACE_PATTERN = Pattern.compile(" ");
|
||||
|
||||
protected final LRUCache<String, ItemFilter> filtersCache = new LRUCache<>(20);
|
||||
protected final LRUCache<String, IRecipeFilter> recipesCache = new LRUCache<>(20);
|
||||
protected final List<ISearchParserProvider> searchProviders;
|
||||
protected final ProvidersCache providersCache = new ProvidersCache();
|
||||
protected final Map<Character, Character> prefixRedefinitions = new HashMap<>();
|
||||
protected String prefixes = null;
|
||||
|
||||
public SearchTokenParser(List<ISearchParserProvider> searchProviders) {
|
||||
this.searchProviders = searchProviders;
|
||||
@@ -114,196 +114,384 @@ public class SearchTokenParser {
|
||||
|
||||
public void addProvider(ISearchParserProvider provider) {
|
||||
this.searchProviders.add(provider);
|
||||
clearCache();
|
||||
}
|
||||
|
||||
public synchronized void clearCache() {
|
||||
this.providersCache.clear();
|
||||
this.filtersCache.clear();
|
||||
this.recipesCache.clear();
|
||||
this.prefixes = null;
|
||||
}
|
||||
|
||||
public void clearCache() {
|
||||
this.filtersCache.clear();
|
||||
}
|
||||
|
||||
protected List<ISearchParserProvider> getProviders() {
|
||||
public List<ISearchParserProvider> getProviders() {
|
||||
Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage();
|
||||
|
||||
if (!currentLanguage.getLanguageCode().equals(providersCache.languageCode)) {
|
||||
Map<Character, ISearchParserProvider> providers = new HashMap<>();
|
||||
final List<ISearchParserProvider> providersList = new ArrayList<>();
|
||||
final Map<Character, ISearchParserProvider> providers = new HashMap<>();
|
||||
|
||||
for (int index = this.searchProviders.size() - 1; index >= 0; index--) {
|
||||
ISearchParserProvider provider = this.searchProviders.get(index);
|
||||
|
||||
if (!providers.containsKey(provider.getPrefix())
|
||||
&& provider.getMatchingLanguages().contains(currentLanguage)) {
|
||||
providers.put(provider.getPrefix(), provider);
|
||||
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) {
|
||||
providersList.add(provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
providersCache.providers = new ArrayList<>(providers.values());
|
||||
providersList.addAll(providers.values());
|
||||
providersCache.languageCode = currentLanguage.getLanguageCode();
|
||||
providersCache.providers = providersList;
|
||||
}
|
||||
|
||||
return providersCache.providers;
|
||||
}
|
||||
|
||||
public boolean hasRedefinedPrefix(char ch) {
|
||||
return getPrefixes().indexOf(ch) >= 0;
|
||||
}
|
||||
|
||||
public ISearchParserProvider getProvider(char ch) {
|
||||
return getProviders().stream()
|
||||
.filter(
|
||||
provider -> provider.getSearchMode() == SearchMode.PREFIX
|
||||
&& getRedefinedPrefix(provider.getPrefix()) == ch)
|
||||
.findFirst().orElse(null);
|
||||
if (!hasRedefinedPrefix(ch)) {
|
||||
return null;
|
||||
}
|
||||
for (ISearchParserProvider provider : getProviders()) {
|
||||
if (provider.getSearchMode() == SearchMode.PREFIX && getRedefinedPrefix(provider.getPrefix()) == ch) {
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<ItemFilter> getAlwaysProvidersFilters(String searchText) {
|
||||
final List<ItemFilter> filters = new ArrayList<>();
|
||||
for (ISearchParserProvider provider : getProviders()) {
|
||||
if (provider.getSearchMode() == SearchMode.ALWAYS) {
|
||||
filters.add(provider.getFilter(searchText));
|
||||
}
|
||||
}
|
||||
|
||||
return filters;
|
||||
}
|
||||
|
||||
public synchronized ItemFilter getFilter(String filterText) {
|
||||
return getFilter(filterText, false);
|
||||
}
|
||||
|
||||
public synchronized ItemFilter getFilter(String rawText, boolean skipRecipeTokens) {
|
||||
final String filterText = EnumChatFormatting.getTextWithoutFormattingCodes(rawText).toLowerCase();
|
||||
|
||||
if (filterText.isEmpty()) {
|
||||
return new EverythingItemFilter();
|
||||
}
|
||||
|
||||
final int patternMode = NEIClientConfig.getIntSetting("inventory.search.patternMode");
|
||||
|
||||
if (patternMode != 3) {
|
||||
return this.filtersCache.computeIfAbsent(skipRecipeTokens + ":" + filterText, _t -> {
|
||||
final List<ItemFilter> searchTokens = new ArrayList<>();
|
||||
|
||||
for (String[] subQuery : splitByDelimiters(filterText, "|", false)) {
|
||||
|
||||
if (subQuery[1].isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final List<ItemFilter> tokens = new ArrayList<>();
|
||||
|
||||
for (String[] contextQuery : splitByDelimiters(subQuery[1], skipRecipeTokens ? "<>" : "", false)) {
|
||||
|
||||
if (contextQuery[1].isEmpty() || contextQuery[0].startsWith(">")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!contextQuery[0].isEmpty()) {
|
||||
contextQuery[0] = contextQuery[0].substring(1);
|
||||
}
|
||||
|
||||
for (SearchToken token : splitSearchText(contextQuery[0] + contextQuery[1])) {
|
||||
final ItemFilter result = token.getFilter(this);
|
||||
|
||||
if (result != null) {
|
||||
tokens.add(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tokens.size() == 1) {
|
||||
searchTokens.add(tokens.get(0));
|
||||
} else if (!tokens.isEmpty()) {
|
||||
searchTokens.add(new AllMultiItemFilter(tokens));
|
||||
}
|
||||
}
|
||||
|
||||
if (searchTokens.isEmpty()) {
|
||||
return new EverythingItemFilter();
|
||||
} else if (searchTokens.size() == 1) {
|
||||
return new IsRegisteredItemFilter(searchTokens.get(0));
|
||||
} else {
|
||||
return new IsRegisteredItemFilter(new AnyMultiItemFilter(searchTokens));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return this.filtersCache.computeIfAbsent(filterText, text -> {
|
||||
final int spaceMode = NEIClientConfig.getIntSetting("inventory.search.spaceMode");
|
||||
|
||||
if (spaceMode == 1) {
|
||||
text = SearchTokenParser.SPACE_PATTERN.matcher(text).replaceAll("\\\\ ");
|
||||
}
|
||||
if (skipRecipeTokens) {
|
||||
return new IsRegisteredItemFilter(
|
||||
SearchExpressionUtils.visitRecipeSearchExpression(text, new ItemFilterVisitor(this)));
|
||||
} else {
|
||||
return new IsRegisteredItemFilter(
|
||||
SearchExpressionUtils.visitSearchExpression(text, new ItemFilterVisitor(this)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public synchronized IRecipeFilter getRecipeFilter(String filterText) {
|
||||
filterText = EnumChatFormatting.getTextWithoutFormattingCodes(filterText).toLowerCase();
|
||||
|
||||
return this.filtersCache.computeIfAbsent(filterText, text -> {
|
||||
final String[] parts = text.split("\\|");
|
||||
final List<ItemFilter> searchTokens = Arrays.stream(parts).map(this::parseSearchText).filter(s -> s != null)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
if (filterText.isEmpty()) {
|
||||
return new RecipeFilter(FilterContext.ANY, true, new EverythingItemFilter());
|
||||
}
|
||||
|
||||
if (searchTokens.isEmpty()) {
|
||||
return new EverythingItemFilter();
|
||||
} else if (searchTokens.size() == 1) {
|
||||
return new IsRegisteredItemFilter(searchTokens.get(0));
|
||||
} else {
|
||||
return new IsRegisteredItemFilter(new AnyMultiItemFilter(searchTokens));
|
||||
}
|
||||
final int patternMode = NEIClientConfig.getIntSetting("inventory.search.patternMode");
|
||||
|
||||
});
|
||||
if (patternMode != 3) {
|
||||
return this.recipesCache.computeIfAbsent(filterText, input -> {
|
||||
final List<IRecipeFilter> searchTokens = new ArrayList<>();
|
||||
|
||||
for (String[] orQueryPart : splitByDelimiters(input, "|", false)) {
|
||||
|
||||
if (orQueryPart[1].isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final List<IRecipeFilter> contextList = new ArrayList<>();
|
||||
|
||||
for (String[] contextQuery : splitByDelimiters(orQueryPart[1], "<>", false)) {
|
||||
|
||||
if (contextQuery[1].isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final List<IRecipeFilter> tokens = new ArrayList<>();
|
||||
FilterContext context = FilterContext.ANY;
|
||||
|
||||
if (!contextQuery[0].isEmpty()) {
|
||||
context = FilterContext.fromChar(contextQuery[0].charAt(0));
|
||||
contextQuery[0] = contextQuery[0].substring(1);
|
||||
}
|
||||
|
||||
for (SearchToken token : splitSearchText(contextQuery[0] + contextQuery[1])) {
|
||||
final ItemFilter result = token.getFilter(this);
|
||||
if (result != null) {
|
||||
tokens.add(
|
||||
new RecipeFilter(context, token.ignore == null || token.ignore != '!', result));
|
||||
}
|
||||
}
|
||||
|
||||
if (tokens.size() == 1) {
|
||||
contextList.add(tokens.get(0));
|
||||
} else if (!tokens.isEmpty()) {
|
||||
contextList.add(new AllMultiRecipeFilter(tokens));
|
||||
}
|
||||
}
|
||||
|
||||
if (contextList.size() == 1) {
|
||||
searchTokens.add(contextList.get(0));
|
||||
} else if (!contextList.isEmpty()) {
|
||||
searchTokens.add(new AllMultiRecipeFilter(contextList));
|
||||
}
|
||||
}
|
||||
|
||||
if (searchTokens.isEmpty()) {
|
||||
return new RecipeFilter(FilterContext.ANY, true, new EverythingItemFilter());
|
||||
} else if (searchTokens.size() == 1) {
|
||||
return searchTokens.get(0);
|
||||
} else {
|
||||
return new AnyMultiRecipeFilter(searchTokens);
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
return this.recipesCache.computeIfAbsent(filterText, text -> {
|
||||
final int spaceMode = NEIClientConfig.getIntSetting("inventory.search.spaceMode");
|
||||
|
||||
if (spaceMode == 1) {
|
||||
text = SearchTokenParser.SPACE_PATTERN.matcher(text).replaceAll("\\\\ ");
|
||||
}
|
||||
|
||||
return SearchExpressionUtils.visitRecipeSearchExpression(text, new RecipeFilterVisitor(this));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public List<SearchToken> splitSearchText(String filterText) {
|
||||
|
||||
if (filterText.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final List<SearchToken> tokens = new ArrayList<>();
|
||||
final String prefixes = getPrefixes();
|
||||
final int spaceMode = NEIClientConfig.getIntSetting("inventory.search.spaceMode");
|
||||
// The regular expression first tries to match a string that starts with a space or the beginning of the string,
|
||||
// followed by a sequence of characters that do not contain special characters -"@#$%&, and ends with a space
|
||||
// and the characters -"@#$%& or the end of the string.
|
||||
final String patternPart1 = "(?<tokenA>(^|\\s+)(?:[^" + Pattern.quote(" -\"" + prefixes)
|
||||
+ "]).+?(?=\\s+["
|
||||
+ Pattern.quote("-\"" + prefixes)
|
||||
+ "]|$))";
|
||||
// If the first condition is not met, it tries to match a sequence of - characters, followed by @#$%&
|
||||
// characters, then either a quoted string or non-space characters.
|
||||
final String patternPart2 = "((?<ignore>-*)(?<firstChar>[" + Pattern.quote(prefixes)
|
||||
+ "]*)(?<tokenB>\\\".*?(?:\\\"|$)|\\S+\\s*))";
|
||||
final Pattern pattern = Pattern.compile(spaceMode == 0 ? patternPart2 : (patternPart1 + "|" + patternPart2));
|
||||
final Matcher filterMatcher = pattern.matcher(filterText);
|
||||
final String prefixes = getPrefixes();
|
||||
SearchToken lastToken = null;
|
||||
int lastEnd = 0;
|
||||
|
||||
while (filterMatcher.find()) {
|
||||
String firstChar = filterMatcher.group("firstChar");
|
||||
SearchToken token = new SearchToken();
|
||||
token.start = filterMatcher.start();
|
||||
token.end = filterMatcher.end();
|
||||
token.ignore = "-".equals(filterMatcher.group("ignore"));
|
||||
token.rawText = spaceMode == 0 ? null : filterMatcher.group("tokenA");
|
||||
for (String[] part : splitByDelimiters(filterText, "-!" + prefixes, true)) {
|
||||
final SearchToken token = createToken(lastEnd, part, prefixes);
|
||||
final int length = part[0].length() + part[1].length();
|
||||
|
||||
if (firstChar != null && !firstChar.isEmpty()) {
|
||||
token.firstChar = firstChar.charAt(0);
|
||||
if (token.isSimpleFilter() && token.rawText.isEmpty()) {
|
||||
lastEnd += length;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token.rawText == null) { // spaceMode == 0
|
||||
token.rawText = filterMatcher.group("tokenB");
|
||||
token.quotes = token.rawText.length() > 1 && token.rawText.startsWith("\"")
|
||||
&& token.rawText.endsWith("\"");
|
||||
if (spaceMode == 0) { // and
|
||||
tokens.add(lastToken = token);
|
||||
} else if (spaceMode == 1) { // space
|
||||
|
||||
if (token.quotes) {
|
||||
token.rawText = token.rawText.substring(1, token.rawText.length() - 1);
|
||||
if (lastToken != null && lastToken.isSimpleFilter() && token.isSimpleFilter()) {
|
||||
lastToken.rawText = filterText.substring(lastToken.start, token.end).trim();
|
||||
lastToken.words[0] = lastToken.rawText;
|
||||
lastToken.end = token.end;
|
||||
} else {
|
||||
tokens.add(lastToken = token);
|
||||
}
|
||||
|
||||
} else if (spaceMode == 2) { // and-x
|
||||
|
||||
if (lastToken != null && lastToken.isSimpleFilter() && token.isSimpleFilter()) {
|
||||
final String[] newWords = new String[lastToken.words.length + token.words.length];
|
||||
|
||||
System.arraycopy(lastToken.words, 0, newWords, 0, lastToken.words.length);
|
||||
System.arraycopy(token.words, 0, newWords, lastToken.words.length, token.words.length);
|
||||
|
||||
lastToken.words = newWords;
|
||||
lastToken.rawText = filterText.substring(lastToken.start, token.end).trim();
|
||||
lastToken.end = token.end;
|
||||
} else {
|
||||
tokens.add(lastToken = token);
|
||||
}
|
||||
|
||||
token.words = new String[] { token.rawText.trim() };
|
||||
} else if (spaceMode == 2) {
|
||||
token.words = token.rawText.trim().split("\\s+");
|
||||
} else {
|
||||
token.words = new String[] { token.rawText.trim() };
|
||||
}
|
||||
|
||||
tokens.add(token);
|
||||
lastEnd += length;
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private String getPrefixes() {
|
||||
StringBuilder prefixes = new StringBuilder().append('\0');
|
||||
private SearchToken createToken(int lastEnd, String[] part, String prefixes) {
|
||||
final SearchToken token = new SearchToken();
|
||||
String pref = part[0];
|
||||
String query = part[1].trim();
|
||||
|
||||
for (ISearchParserProvider provider : getProviders()) {
|
||||
if (provider.getSearchMode() == SearchMode.PREFIX) {
|
||||
prefixes.append(getRedefinedPrefix(provider.getPrefix()));
|
||||
token.start = lastEnd;
|
||||
token.end = lastEnd + pref.length() + query.length();
|
||||
|
||||
if (pref.startsWith("-")) {
|
||||
token.ignore = '-';
|
||||
pref = pref.substring(1);
|
||||
} else if (pref.startsWith("!")) {
|
||||
token.ignore = '!';
|
||||
pref = pref.substring(1);
|
||||
}
|
||||
|
||||
if (!pref.isEmpty()) {
|
||||
char firstChar = pref.charAt(0);
|
||||
|
||||
if (prefixes.indexOf(firstChar) >= 0) {
|
||||
token.firstChar = firstChar;
|
||||
pref = pref.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
return prefixes.toString();
|
||||
String text = pref + query;
|
||||
token.quotes = text.length() > 1 && text.startsWith("\"") && text.endsWith("\"");
|
||||
|
||||
if (token.quotes) {
|
||||
text = text.substring(1, text.length() - 1);
|
||||
}
|
||||
|
||||
token.rawText = text;
|
||||
token.words = new String[] { token.quotes ? text.replaceAll("\\\\\"", "\"") : text };
|
||||
return token;
|
||||
}
|
||||
|
||||
public List<String[]> splitByDelimiters(String input, String delimiters, boolean space) {
|
||||
|
||||
if (delimiters == null || delimiters.isEmpty()) {
|
||||
return Collections.singletonList(new String[] { "", input });
|
||||
}
|
||||
|
||||
final List<String[]> tokens = new ArrayList<>();
|
||||
final int length = input.length();
|
||||
boolean insideQuotes = false;
|
||||
String token = "";
|
||||
int lastEnd = 0;
|
||||
int index = 0;
|
||||
|
||||
while (index < length) {
|
||||
final char ch = input.charAt(index);
|
||||
|
||||
if (!insideQuotes && delimiters.indexOf(ch) >= 0
|
||||
&& (!space || index == 0 || input.charAt(index - 1) == ' ')) {
|
||||
|
||||
if (lastEnd == index) {
|
||||
token += String.valueOf(ch);
|
||||
} else {
|
||||
tokens.add(new String[] { token, input.substring(lastEnd, index) });
|
||||
token = String.valueOf(ch);
|
||||
}
|
||||
|
||||
lastEnd = index + 1;
|
||||
} else if (!insideQuotes && space && ch != ' ' && (index > 0 && input.charAt(index - 1) == ' ')) {
|
||||
tokens.add(new String[] { token, input.substring(lastEnd, index) });
|
||||
token = "";
|
||||
|
||||
lastEnd = index;
|
||||
}
|
||||
|
||||
if (ch == '"' && (index == 0 || input.charAt(index - 1) != '\\')) {
|
||||
insideQuotes = !insideQuotes;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
tokens.add(new String[] { token, input.substring(lastEnd) });
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
public String getPrefixes() {
|
||||
if (this.prefixes == null) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (ISearchParserProvider provider : getProviders()) {
|
||||
if (provider.getSearchMode() == SearchTokenParser.SearchMode.PREFIX) {
|
||||
builder.append(getRedefinedPrefix(provider.getPrefix()));
|
||||
}
|
||||
}
|
||||
|
||||
this.prefixes = builder.toString();
|
||||
}
|
||||
|
||||
return this.prefixes;
|
||||
}
|
||||
|
||||
public char getRedefinedPrefix(char prefix) {
|
||||
return this.prefixRedefinitions.getOrDefault(prefix, prefix);
|
||||
}
|
||||
|
||||
private ItemFilter parseSearchText(String filterText) {
|
||||
|
||||
if (filterText.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final AllMultiItemFilter searchTokens = new AllMultiItemFilter();
|
||||
final List<SearchToken> tokens = splitSearchText(filterText);
|
||||
|
||||
for (SearchToken token : tokens) {
|
||||
if (!token.rawText.isEmpty()) {
|
||||
ItemFilter result = parseToken(token);
|
||||
|
||||
if (token.ignore) {
|
||||
searchTokens.filters.add(new NegatedItemFilter(result));
|
||||
} else {
|
||||
searchTokens.filters.add(result);
|
||||
}
|
||||
} else if (!token.ignore) {
|
||||
searchTokens.filters.add(new NothingItemFilter());
|
||||
}
|
||||
}
|
||||
|
||||
return searchTokens;
|
||||
}
|
||||
|
||||
private ItemFilter parseToken(SearchToken token) {
|
||||
final ISearchParserProvider provider = token.firstChar == null ? null : this.getProvider(token.firstChar);
|
||||
|
||||
if (provider == null || provider.getSearchMode() == SearchMode.NEVER) {
|
||||
final List<ItemFilter> filters = new ArrayList<>();
|
||||
|
||||
for (ISearchParserProvider _provider : getProviders()) {
|
||||
if (_provider.getSearchMode() == SearchMode.ALWAYS) {
|
||||
AllMultiItemFilter filter = generateFilters(_provider, token.words);
|
||||
|
||||
if (!filter.filters.isEmpty()) {
|
||||
filters.add(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filters.isEmpty() ? new NothingItemFilter() : new AnyMultiItemFilter(filters);
|
||||
} else {
|
||||
return generateFilters(provider, token.words);
|
||||
}
|
||||
}
|
||||
|
||||
private AllMultiItemFilter generateFilters(ISearchParserProvider provider, String[] words) {
|
||||
final AllMultiItemFilter filters = new AllMultiItemFilter();
|
||||
|
||||
for (String work : words) {
|
||||
final ItemFilter filter = provider.getFilter(work);
|
||||
|
||||
if (filter != null) {
|
||||
filters.filters.add(filter);
|
||||
}
|
||||
}
|
||||
|
||||
return filters;
|
||||
}
|
||||
}
|
||||
@@ -21,10 +21,8 @@ import cpw.mods.fml.common.gameevent.TickEvent.Phase;
|
||||
|
||||
public class ServerHandler {
|
||||
|
||||
private static ServerHandler instance;
|
||||
|
||||
public static void load() {
|
||||
instance = new ServerHandler();
|
||||
ServerHandler instance = new ServerHandler();
|
||||
|
||||
PacketCustom.assignHandler(NEICPH.channel, new NEISPH());
|
||||
FMLCommonHandler.instance().bus().register(instance);
|
||||
@@ -48,8 +46,7 @@ public class ServerHandler {
|
||||
|
||||
@SubscribeEvent
|
||||
public void tickEvent(TickEvent.PlayerTickEvent event) {
|
||||
if (event.phase == Phase.START && event.player instanceof EntityPlayerMP) {
|
||||
EntityPlayerMP player = (EntityPlayerMP) event.player;
|
||||
if (event.phase == Phase.START && event.player instanceof EntityPlayerMP player) {
|
||||
PlayerSave save = NEIServerConfig.forPlayer(player.getCommandSenderName());
|
||||
if (save == null) return;
|
||||
updateMagneticPlayer(player, save);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,26 +1,30 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.nbt.NBTTagString;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import codechicken.core.gui.GuiScrollSlot;
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
@@ -32,17 +36,21 @@ import codechicken.nei.api.API;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.guihook.IContainerTooltipHandler;
|
||||
import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiRecipeTab;
|
||||
import codechicken.nei.recipe.ICraftingHandler;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.NBTJson;
|
||||
import codechicken.nei.util.NEIMouseUtils;
|
||||
|
||||
public class SubsetWidget extends Button implements ItemFilterProvider, IContainerTooltipHandler {
|
||||
public class SubsetWidget extends Button implements ItemFilterProvider {
|
||||
|
||||
protected static final int SLOT_HEIGHT = 18;
|
||||
protected static final int MARGIN = 2;
|
||||
protected static final char PREFIX = '%';
|
||||
|
||||
protected static ReentrantReadWriteLock hiddenItemLock = new ReentrantReadWriteLock();
|
||||
protected static Lock hiddenWriteLock = hiddenItemLock.writeLock();
|
||||
protected static Lock hiddenReadLock = hiddenItemLock.readLock();
|
||||
private static final Object hiddenLock = new Object();
|
||||
|
||||
public static class SubsetTag {
|
||||
|
||||
@@ -185,7 +193,7 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
|
||||
}
|
||||
|
||||
public String name() {
|
||||
int idx = this.fullname.indexOf('.');
|
||||
int idx = this.fullname.lastIndexOf('.');
|
||||
return idx < 0 ? this.fullname : this.fullname.substring(idx + 1);
|
||||
}
|
||||
|
||||
@@ -355,16 +363,31 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
|
||||
private static class DefaultParserProvider implements ISearchParserProvider {
|
||||
|
||||
public ItemFilter getFilter(String searchText) {
|
||||
final int patternMode = NEIClientConfig.getIntSetting("inventory.search.patternMode");
|
||||
Pattern pattern = null;
|
||||
if (patternMode != 3) {
|
||||
searchText = searchText.replaceAll("\\s+", "").toLowerCase();
|
||||
} else {
|
||||
pattern = SearchField.getPattern(searchText, patternMode);
|
||||
}
|
||||
final AnyMultiItemFilter filter = new AnyMultiItemFilter();
|
||||
final String pathPart = searchText.replaceAll("\\s+", "").toLowerCase();
|
||||
final Set<ItemStack> filteredItems = new HashSet<>();
|
||||
final List<SubsetTag> snapshot;
|
||||
|
||||
for (SubsetTag tag : tags.values()) {
|
||||
if (tag.filter != null && tag.path.contains(pathPart)) {
|
||||
filter.filters.add(tag.filter);
|
||||
synchronized (tags) {
|
||||
snapshot = new ArrayList<>(tags.values());
|
||||
}
|
||||
|
||||
for (SubsetTag tag : snapshot) {
|
||||
if (tag.filter != null && matches(tag.path, searchText, pattern)) {
|
||||
synchronized (tag.items) {
|
||||
filteredItems.addAll(tag.items);
|
||||
filter.filters.add(tag.filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filter;
|
||||
return stack -> filteredItems.contains(stack) || !ItemList.items.contains(stack) && filter.matches(stack);
|
||||
}
|
||||
|
||||
public char getPrefix() {
|
||||
@@ -376,15 +399,25 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchMode getSearchMode() {
|
||||
return SearchMode.fromInt(NEIClientConfig.getIntSetting("inventory.search.subsetsSearchMode"));
|
||||
public String getName() {
|
||||
return "subsets";
|
||||
}
|
||||
|
||||
private boolean matches(String name, String searchText, Pattern pattern) {
|
||||
if (pattern != null) {
|
||||
return pattern.matcher(name).find();
|
||||
} else {
|
||||
return name.contains(searchText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All operations on this variable should be synchronised.
|
||||
* Canonical {@link StackInfo#getItemStackGUID(ItemStack)} of every hidden item, stored by GUID so the state
|
||||
* survives world reloads. All operations should be synchronised.
|
||||
*/
|
||||
private static final ItemStackSet hiddenItems = new ItemStackSet();
|
||||
private static final Set<String> hiddenItems = new HashSet<>();
|
||||
|
||||
private static final Map<String, SubsetTag> tags = new HashMap<>();
|
||||
private static final SubsetTag root = new SubsetTag("");
|
||||
protected static boolean enableSearchBySubsets = false;
|
||||
@@ -407,24 +440,31 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
|
||||
}
|
||||
|
||||
updateHiddenItems();
|
||||
SearchField.searchParser.clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeTag(String path) {
|
||||
updateState.stop();
|
||||
|
||||
synchronized (tags) {
|
||||
tags.keySet().removeIf(
|
||||
parentpath -> parentpath.equals(path.toLowerCase())
|
||||
|| parentpath.startsWith(path.toLowerCase() + "."));
|
||||
updateHiddenItems();
|
||||
SearchField.searchParser.clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isHidden(ItemStack item) {
|
||||
try {
|
||||
if (hiddenReadLock.tryLock(5, TimeUnit.SECONDS)) {
|
||||
try {
|
||||
return hiddenItems.contains(item);
|
||||
} finally {
|
||||
hiddenReadLock.unlock();
|
||||
}
|
||||
} else {
|
||||
NEIClientConfig.logger.error("Unable to obtain read lock in 'isHidden'");
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
final String guid = StackInfo.getItemStackGUID(item);
|
||||
synchronized (hiddenLock) {
|
||||
return hiddenItems.contains(guid);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static List<String> toGUIDs(List<ItemStack> items) {
|
||||
return items.stream().map(StackInfo::getItemStackGUID).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static List<ItemStack> getItems(SubsetTag tag, List<ItemStack> items) {
|
||||
@@ -438,90 +478,50 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
|
||||
}
|
||||
|
||||
public static void showOnly(SubsetTag tag) {
|
||||
try {
|
||||
if (hiddenWriteLock.tryLock(5, TimeUnit.SECONDS)) {
|
||||
try {
|
||||
hiddenItems.clear();
|
||||
hiddenItems.addAll(getItems(root, new ArrayList<>()));
|
||||
hiddenItems.removeAll(getItems(tag, new ArrayList<>()));
|
||||
} finally {
|
||||
hiddenWriteLock.unlock();
|
||||
}
|
||||
} else {
|
||||
NEIClientConfig.logger.error("Unable to obtain write lock in 'showOnly'");
|
||||
}
|
||||
final List<String> allItems = toGUIDs(getItems(root, new ArrayList<>()));
|
||||
final List<String> tagItems = toGUIDs(getItems(tag, new ArrayList<>()));
|
||||
|
||||
calculateVisibility();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
synchronized (hiddenLock) {
|
||||
hiddenItems.clear();
|
||||
hiddenItems.addAll(allItems);
|
||||
hiddenItems.removeAll(tagItems);
|
||||
}
|
||||
|
||||
calculateVisibility();
|
||||
}
|
||||
|
||||
public static void setHidden(SubsetTag tag, boolean hidden) {
|
||||
try {
|
||||
if (hiddenWriteLock.tryLock(5, TimeUnit.SECONDS)) {
|
||||
try {
|
||||
List<ItemStack> tagItems = getItems(tag, new ArrayList<>());
|
||||
final List<String> tagItems = toGUIDs(getItems(tag, new ArrayList<>()));
|
||||
|
||||
if (hidden) {
|
||||
hiddenItems.addAll(tagItems);
|
||||
} else {
|
||||
hiddenItems.removeAll(tagItems);
|
||||
}
|
||||
|
||||
} finally {
|
||||
hiddenWriteLock.unlock();
|
||||
}
|
||||
synchronized (hiddenLock) {
|
||||
if (hidden) {
|
||||
hiddenItems.addAll(tagItems);
|
||||
} else {
|
||||
NEIClientConfig.logger.error("Unable to obtain write lock in 'setHidden'");
|
||||
hiddenItems.removeAll(tagItems);
|
||||
}
|
||||
|
||||
calculateVisibility();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
calculateVisibility();
|
||||
}
|
||||
|
||||
public static void setHidden(ItemStack item, boolean hidden) {
|
||||
try {
|
||||
if (hiddenWriteLock.tryLock(5, TimeUnit.SECONDS)) {
|
||||
try {
|
||||
final String guid = StackInfo.getItemStackGUID(item);
|
||||
|
||||
if (hidden) {
|
||||
hiddenItems.add(item);
|
||||
} else {
|
||||
hiddenItems.remove(item);
|
||||
}
|
||||
|
||||
} finally {
|
||||
hiddenWriteLock.unlock();
|
||||
}
|
||||
synchronized (hiddenLock) {
|
||||
if (hidden) {
|
||||
hiddenItems.add(guid);
|
||||
} else {
|
||||
NEIClientConfig.logger.error("Unable to obtain write lock in 'setHidden'");
|
||||
hiddenItems.remove(guid);
|
||||
}
|
||||
|
||||
calculateVisibility();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
calculateVisibility();
|
||||
}
|
||||
|
||||
public static void unhideAll() {
|
||||
try {
|
||||
if (hiddenWriteLock.tryLock(5, TimeUnit.SECONDS)) {
|
||||
try {
|
||||
hiddenItems.clear();
|
||||
} finally {
|
||||
hiddenWriteLock.unlock();
|
||||
}
|
||||
} else {
|
||||
NEIClientConfig.logger.error("Unable to obtain write lock in 'unhideAll'");
|
||||
}
|
||||
|
||||
calculateVisibility();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
synchronized (hiddenLock) {
|
||||
hiddenItems.clear();
|
||||
}
|
||||
calculateVisibility();
|
||||
}
|
||||
|
||||
public static void updateHiddenItems() {
|
||||
@@ -530,43 +530,106 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadCustomSubsets() {
|
||||
File dir = new File(NEIClientConfig.configDir, "subsets");
|
||||
|
||||
if (!dir.exists() || !dir.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Stream.of(dir.listFiles()).filter(file -> !file.isDirectory()).forEach(file -> {
|
||||
ClientHandler.loadSettingsFile(
|
||||
"subsets/" + file.getName(),
|
||||
lines -> parseFile(file.getName(), lines.collect(Collectors.toList())));
|
||||
});
|
||||
}
|
||||
|
||||
private static void parseFile(String resource, List<String> itemStrings) {
|
||||
final JsonParser parser = new JsonParser();
|
||||
final int dotIndex = resource.lastIndexOf('.');
|
||||
final String subsetNamespace = dotIndex > 0 ? resource.substring(0, dotIndex) : resource;
|
||||
SubsetTag processedTag = new SubsetTag(subsetNamespace, new ItemStackSet());
|
||||
|
||||
for (String itemStr : itemStrings) {
|
||||
try {
|
||||
if (itemStr.startsWith("; ")) {
|
||||
addTag(processedTag);
|
||||
|
||||
final String handlerName = itemStr.substring(2);
|
||||
final IRecipeHandler recipeHandler = Stream
|
||||
.concat(
|
||||
GuiCraftingRecipe.craftinghandlers.stream(),
|
||||
GuiCraftingRecipe.serialCraftingHandlers.stream())
|
||||
.filter(handler -> handlerName.equals(getHandlerName(handler))).findFirst().orElse(null);
|
||||
String recipeName = handlerName;
|
||||
|
||||
if (recipeHandler != null) {
|
||||
recipeName = recipeHandler.getRecipeName().trim();
|
||||
}
|
||||
|
||||
processedTag = new SubsetTag(
|
||||
subsetNamespace + "." + recipeName.replace(".", ""),
|
||||
new ItemStackSet());
|
||||
} else {
|
||||
final NBTBase nbt = NBTJson.toNbt(parser.parse(itemStr));
|
||||
|
||||
if (nbt instanceof NBTTagCompound tag) {
|
||||
((ItemStackSet) processedTag.filter).add(StackInfo.loadFromNBT(tag));
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Expected NBTTagCompound but got " + nbt.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.error("Failed to load custom subset items from json string:\n{}", itemStr);
|
||||
}
|
||||
}
|
||||
|
||||
addTag(processedTag);
|
||||
}
|
||||
|
||||
private static String getHandlerName(ICraftingHandler handler) {
|
||||
return GuiRecipeTab.getHandlerInfo(handler).getHandlerName();
|
||||
}
|
||||
|
||||
public static void loadHidden() {
|
||||
final List<ItemStack> itemList = new LinkedList<>();
|
||||
final Set<String> guids = new HashSet<>();
|
||||
|
||||
try {
|
||||
final NBTTagList guidList = NEIClientConfig.world.nbt.getTagList("hiddenItems", 8);
|
||||
|
||||
for (int i = 0; i < guidList.tagCount(); i++) {
|
||||
guids.add(guidList.getStringTagAt(i));
|
||||
}
|
||||
|
||||
final NBTTagList list = NEIClientConfig.world.nbt.getTagList("hiddenItems", 10);
|
||||
|
||||
for (int i = 0; i < list.tagCount(); i++) {
|
||||
itemList.add(ItemStack.loadItemStackFromNBT(list.getCompoundTagAt(i)));
|
||||
final ItemStack stack = ItemStack.loadItemStackFromNBT(list.getCompoundTagAt(i));
|
||||
|
||||
if (stack != null) {
|
||||
guids.add(StackInfo.getItemStackGUID(stack));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.error("Error loading hiddenItems", e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (hiddenWriteLock.tryLock(5, TimeUnit.SECONDS)) {
|
||||
try {
|
||||
hiddenItems.clear();
|
||||
hiddenItems.addAll(itemList);
|
||||
} finally {
|
||||
hiddenWriteLock.unlock();
|
||||
}
|
||||
} else {
|
||||
NEIClientConfig.logger.error("Unable to obtain second write lock in 'loadHidden'");
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
synchronized (hiddenLock) {
|
||||
hiddenItems.clear();
|
||||
hiddenItems.addAll(guids);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void saveHidden() {
|
||||
if (NEIClientConfig.world == null) return;
|
||||
|
||||
final NBTTagList list = new NBTTagList();
|
||||
for (ItemStack stack : hiddenItems.values()) {
|
||||
list.appendTag(stack.writeToNBT(new NBTTagCompound()));
|
||||
synchronized (hiddenLock) {
|
||||
for (String guid : hiddenItems) {
|
||||
list.appendTag(new NBTTagString(guid));
|
||||
}
|
||||
}
|
||||
|
||||
NEIClientConfig.world.nbt.setTag("hiddenItems", list);
|
||||
@@ -584,14 +647,22 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
|
||||
public void execute() {
|
||||
|
||||
try {
|
||||
List<SubsetTag> list = new ArrayList<>(tags.values());
|
||||
final List<SubsetTag> list;
|
||||
|
||||
synchronized (tags) {
|
||||
list = new ArrayList<>(tags.values());
|
||||
}
|
||||
|
||||
root.clearCache();
|
||||
|
||||
list.parallelStream().forEach(tag -> {
|
||||
tag.clearCache();
|
||||
ItemList.items.stream().filter(tag.filter::matches).map(ItemStack::copy)
|
||||
.collect(Collectors.toCollection(() -> tag.items));
|
||||
|
||||
if (!(tag.filter instanceof NothingItemFilter)) {
|
||||
ItemList.items.stream().filter(tag.filter::matches)
|
||||
.collect(Collectors.toCollection(() -> tag.items));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
for (SubsetTag tag : list) {
|
||||
@@ -627,6 +698,7 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
SearchField.searchParser.clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -638,15 +710,17 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRenderLabel() {
|
||||
public int getRenderLabelColor() {
|
||||
return NEIClientConfig.subsetWidgetOnTop() ? 0 : ColorUtils.subsetWidget.getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRenderLabel() {
|
||||
if (NEIClientConfig.subsetWidgetOnTop()) {
|
||||
return NEIClientUtils.translate("inventory.item_subsets");
|
||||
} else {
|
||||
return EnumChatFormatting.DARK_PURPLE + String.valueOf(SearchField.searchParser.getRedefinedPrefix(PREFIX))
|
||||
+ EnumChatFormatting.RESET;
|
||||
return String.valueOf(SearchField.searchParser.getRedefinedPrefix(PREFIX));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -684,7 +758,7 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
|
||||
|
||||
root.resize(screen, parent, dropRight);
|
||||
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
|
||||
GuiContainerManager.enable2DRender();
|
||||
GuiContainerManager.drawItems.zLevel += 100;
|
||||
|
||||
@@ -835,27 +909,27 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
|
||||
public Map<String, String> handleHotkeys(int mousex, int mousey, Map<String, String> hotkeys) {
|
||||
|
||||
if (SubsetWidget.hoverStack != null) {
|
||||
|
||||
if (NEIClientConfig.canCheatItem(SubsetWidget.hoverStack)) {
|
||||
hotkeys.put(
|
||||
NEIClientUtils.translate("subsets.item.cheat.key"),
|
||||
NEIClientUtils.getKeyName(NEIClientUtils.CTRL_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("subsets.item.cheat"));
|
||||
}
|
||||
|
||||
if (SubsetWidget.enableSearchBySubsets) {
|
||||
hotkeys.put(
|
||||
NEIClientUtils.translate("subsets.item.search.key"),
|
||||
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("subsets.item.search"));
|
||||
}
|
||||
|
||||
hotkeys.put(
|
||||
NEIClientUtils.translate("subsets.item.show.key"),
|
||||
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("subsets.item.show"));
|
||||
hotkeys.put(
|
||||
NEIClientUtils.translate("subsets.item.hide.key"),
|
||||
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_RMB),
|
||||
NEIClientUtils.translate("subsets.item.hide"));
|
||||
} else if (SubsetWidget.hoverTag != null) {
|
||||
hotkeys.put(
|
||||
@@ -864,12 +938,16 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
|
||||
|
||||
if (SubsetWidget.enableSearchBySubsets) {
|
||||
hotkeys.put(
|
||||
NEIClientUtils.translate("subsets.tag.search.key"),
|
||||
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("subsets.tag.search"));
|
||||
}
|
||||
|
||||
hotkeys.put(NEIClientUtils.translate("subsets.tag.show.key"), NEIClientUtils.translate("subsets.tag.show"));
|
||||
hotkeys.put(NEIClientUtils.translate("subsets.tag.hide.key"), NEIClientUtils.translate("subsets.tag.hide"));
|
||||
hotkeys.put(
|
||||
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("subsets.tag.show"));
|
||||
hotkeys.put(
|
||||
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_RMB),
|
||||
NEIClientUtils.translate("subsets.tag.hide"));
|
||||
}
|
||||
|
||||
return hotkeys;
|
||||
|
||||
@@ -89,7 +89,7 @@ public abstract class TextField extends Widget {
|
||||
onTextChange(oldText);
|
||||
}
|
||||
|
||||
return handled;
|
||||
return handled || keyID == Keyboard.KEY_SPACE;
|
||||
}
|
||||
|
||||
public abstract void onTextChange(String oldText);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
@@ -14,8 +15,6 @@ public abstract class Widget {
|
||||
|
||||
public void postDraw(int mx, int my) {}
|
||||
|
||||
public void postDrawTooltips(int mx, int my, List<String> tooltip) {}
|
||||
|
||||
public boolean handleClick(int mx, int my, int button) {
|
||||
return true;
|
||||
}
|
||||
@@ -38,6 +37,10 @@ public abstract class Widget {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Map<String, String> handleHotkeys(int mousex, int mousey, Map<String, String> hotkeys) {
|
||||
return hotkeys;
|
||||
}
|
||||
|
||||
public void update() {}
|
||||
|
||||
public Rectangle4i bounds() {
|
||||
@@ -58,6 +61,14 @@ public abstract class Widget {
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
public List<String> handleItemTooltip(ItemStack itemstack, int mousex, int mousey, List<String> tooltip) {
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
public boolean isFocused() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void loseFocus() {}
|
||||
|
||||
public void gainFocus() {}
|
||||
@@ -67,4 +78,5 @@ public abstract class Widget {
|
||||
public int z;
|
||||
public int w;
|
||||
public int h;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
|
||||
public class WidgetContainer extends Widget {
|
||||
|
||||
protected final List<Widget> widgets = new ArrayList<>();
|
||||
protected boolean isFocused = false;
|
||||
|
||||
public void addWidget(Widget widget) {
|
||||
this.widgets.add(widget);
|
||||
}
|
||||
|
||||
public void setWidgets(List<Widget> widgets) {
|
||||
final boolean isFocused = this.isFocused;
|
||||
clear();
|
||||
loseFocus();
|
||||
|
||||
for (Widget widget : widgets) {
|
||||
addWidget(widget);
|
||||
}
|
||||
|
||||
this.isFocused = isFocused;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.widgets.clear();
|
||||
this.isFocused = false;
|
||||
}
|
||||
|
||||
public List<Widget> getWidgets() {
|
||||
return Collections.unmodifiableList(this.widgets);
|
||||
}
|
||||
|
||||
public boolean removeIf(Predicate<Widget> filter) {
|
||||
return this.widgets.removeIf(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mousex, int mousey) {
|
||||
drawWidgets(mousex, mousey);
|
||||
}
|
||||
|
||||
protected void drawWidgets(int mousex, int mousey) {
|
||||
final Rectangle4i bounds = bounds();
|
||||
|
||||
for (Widget widget : this.widgets) {
|
||||
if (widget.bounds().intersects(bounds)) {
|
||||
widget.draw(mousex, mousey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
|
||||
for (Widget widget : this.widgets) {
|
||||
widget.update();
|
||||
}
|
||||
|
||||
Collections.sort(this.widgets, Comparator.comparingInt((Widget widget) -> widget.z));
|
||||
}
|
||||
|
||||
public Widget getWidgetUnderMouse(int mousex, int mousey) {
|
||||
|
||||
if (!bounds().contains(mousex, mousey)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
if (widget.contains(mousex, mousey)) {
|
||||
return widget;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMouseWheel(int scroll, int mousex, int mousey) {
|
||||
final Widget widget = getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
return widget != null && widget.onMouseWheel(scroll, mousex, mousey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleClick(int mousex, int mousey, int button) {
|
||||
|
||||
if (contains(mousex, mousey)) {
|
||||
gainFocus();
|
||||
}
|
||||
|
||||
final Widget widget = getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
return widget != null && widget.handleClick(mousex, mousey, button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleClickExt(int mousex, int mousey, int button) {
|
||||
loseFocus();
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
if (!widget.contains(mousex, mousey) && widget.handleClickExt(mousex, mousey, button)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(int mousex, int mousey, int button, long heldTime) {
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
widget.mouseDragged(mousex, mousey, button, heldTime);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseUp(int mousex, int mousey, int button) {
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
widget.mouseUp(mousex, mousey, button);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyPress(int keyCode, char keyChar) {
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
if (widget.handleKeyPress(keyCode, keyChar)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lastKeyTyped(int keyID, char keyChar) {
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
widget.lastKeyTyped(keyID, keyChar);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFocused() {
|
||||
return this.isFocused;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loseFocus() {
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
if (widget.isFocused()) {
|
||||
widget.loseFocus();
|
||||
}
|
||||
}
|
||||
|
||||
this.isFocused = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gainFocus() {
|
||||
final Point mouse = GuiDraw.getMousePosition();
|
||||
final Widget widget = getWidgetUnderMouse(mouse.x, mouse.y);
|
||||
|
||||
if (widget != null) {
|
||||
|
||||
if (!widget.isFocused()) {
|
||||
loseFocus();
|
||||
widget.gainFocus();
|
||||
}
|
||||
|
||||
} else {
|
||||
loseFocus();
|
||||
}
|
||||
|
||||
this.isFocused = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackMouseOver(int mousex, int mousey) {
|
||||
final Widget widget = getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
if (widget != null) {
|
||||
return widget.getStackMouseOver(mousex, mousey);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDraw(int mousex, int mousey) {
|
||||
|
||||
for (Widget widget : this.widgets) {
|
||||
widget.postDraw(mousex, mousey);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClick(int mousex, int mousey) {
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
widget.onGuiClick(mousex, mousey);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(int mousex, int mousey, List<String> tooltip) {
|
||||
final Widget widget = getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
if (widget != null) {
|
||||
return widget.handleTooltip(mousex, mousey, tooltip);
|
||||
}
|
||||
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> handleHotkeys(int mousex, int mousey, Map<String, String> hotkeys) {
|
||||
final Widget widget = getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
if (widget != null) {
|
||||
return widget.handleHotkeys(mousex, mousey, hotkeys);
|
||||
}
|
||||
|
||||
return hotkeys;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockSnow;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.entity.Entity;
|
||||
@@ -15,6 +21,8 @@ import net.minecraft.world.chunk.Chunk;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import com.cardinalstar.cubicchunks.world.api.IMinMaxHeight;
|
||||
|
||||
import codechicken.lib.math.MathHelper;
|
||||
import codechicken.nei.KeyManager.IKeyStateTracker;
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper;
|
||||
@@ -26,20 +34,23 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
public static int mobOverlay = 0;
|
||||
private static byte[] mobSpawnCache;
|
||||
private static long mobOverlayUpdateTime;
|
||||
private static String oregenPatternName;
|
||||
|
||||
public static void reset() {
|
||||
mobOverlay = 0;
|
||||
chunkOverlay = 0;
|
||||
oregenPatternName = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
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.isPressed("world.moboverlay")) {
|
||||
mobOverlay = (mobOverlay + 1) % 2;
|
||||
NEIClientUtils
|
||||
.printChatMessage(new ChatComponentText(NEIClientUtils.translate("chat.moboverlay." + mobOverlay)));
|
||||
}
|
||||
|
||||
if (KeyManager.isPressed("world.chunkoverlay")) {
|
||||
chunkOverlay = (chunkOverlay + 1) % (NEIModContainer.isGT5Loaded() ? 4 : 3);
|
||||
// 0-2 (or 3 with gt)
|
||||
NEIClientUtils.printChatMessage(
|
||||
@@ -49,6 +60,7 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
}
|
||||
|
||||
public static void render(float frame) {
|
||||
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_LINE_BIT);
|
||||
GL11.glPushMatrix();
|
||||
Entity entity = Minecraft.getMinecraft().renderViewEntity;
|
||||
|
||||
@@ -62,9 +74,12 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
|
||||
GL11.glTranslated(-interpPosX + intOffsetX, -interpPosY + intOffsetY, -interpPosZ + intOffsetZ);
|
||||
|
||||
GL11.glEnable(GL11.GL_DEPTH_TEST);
|
||||
GL11.glDepthFunc(GL11.GL_LEQUAL);
|
||||
renderChunkBounds(entity, intOffsetX, intOffsetY, intOffsetZ);
|
||||
renderMobSpawnOverlay(entity, intOffsetX, intOffsetY, intOffsetZ);
|
||||
GL11.glPopMatrix();
|
||||
GL11.glPopAttrib();
|
||||
}
|
||||
|
||||
private static void buildMobSpawnOverlay(Entity entity) {
|
||||
@@ -73,9 +88,11 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
}
|
||||
|
||||
World world = entity.worldObj;
|
||||
int worldHeight = world.getHeight();
|
||||
|
||||
int x1 = (int) entity.posX;
|
||||
int z1 = (int) entity.posZ;
|
||||
int y1 = (int) MathHelper.clip(entity.posY, 16, world.getHeight() - 16);
|
||||
int y1 = (int) MathHelper.clip(entity.posY, 16, worldHeight - 16);
|
||||
|
||||
for (int i = 0; i <= 32; i++) {
|
||||
int x = x1 - 16 + i;
|
||||
@@ -94,6 +111,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;
|
||||
@@ -104,6 +127,15 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
}
|
||||
}
|
||||
|
||||
private static double getOverlayYOffset(World world, int x, int y, int z) {
|
||||
Block block = world.getBlock(x, y, z);
|
||||
if (block instanceof BlockSnow) {
|
||||
int meta = world.getBlockMetadata(x, y, z) & 7;
|
||||
return (1 + meta) / 8.0 + 0.02;
|
||||
}
|
||||
return 0.02;
|
||||
}
|
||||
|
||||
private static void renderMobSpawnOverlay(Entity entity, int intOffsetX, int intOffsetY, int intOffsetZ) {
|
||||
if (mobOverlay == 0) {
|
||||
if (mobSpawnCache != null) {
|
||||
@@ -159,10 +191,12 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
curSpawnMode = spawnMode;
|
||||
}
|
||||
|
||||
tess.addVertex(x, y + 0.02, z);
|
||||
tess.addVertex(x + 1, y + 0.02, z + 1);
|
||||
tess.addVertex(x + 1, y + 0.02, z);
|
||||
tess.addVertex(x, y + 0.02, z + 1);
|
||||
double yOff = getOverlayYOffset(world, x + intOffsetX, y + intOffsetY, z + intOffsetZ);
|
||||
|
||||
tess.addVertex(x, y + yOff, z);
|
||||
tess.addVertex(x + 1, y + yOff, z + 1);
|
||||
tess.addVertex(x + 1, y + yOff, z);
|
||||
tess.addVertex(x, y + yOff, z + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -177,6 +211,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;
|
||||
@@ -199,6 +237,9 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
private static void renderChunkBounds(Entity entity, int intOffsetX, int intOffsetY, int intOffsetZ) {
|
||||
if (chunkOverlay == 0) return;
|
||||
|
||||
int worldMinY = worldMinHeight(entity.worldObj);
|
||||
int worldMaxY = worldMaxHeight(entity.worldObj);
|
||||
|
||||
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
@@ -217,14 +258,13 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
double dy = 128;
|
||||
double y1 = Math.floor(entity.posY - dy / 2);
|
||||
double y2 = y1 + dy;
|
||||
if (y1 < 0) {
|
||||
y1 = 0;
|
||||
y2 = dy;
|
||||
if (y1 < worldMinY) {
|
||||
y1 = worldMinY;
|
||||
y2 = worldMinY + dy;
|
||||
}
|
||||
|
||||
if (y1 > entity.worldObj.getHeight()) {
|
||||
y2 = entity.worldObj.getHeight();
|
||||
y1 = y2 - dy;
|
||||
if (y2 > worldMaxY) {
|
||||
y2 = worldMaxY;
|
||||
y1 = Math.max(worldMaxY - dy, worldMinY);
|
||||
}
|
||||
|
||||
y1 -= intOffsetY;
|
||||
@@ -250,19 +290,34 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
tess.addVertex(x1, y2, z1);
|
||||
}
|
||||
|
||||
if (NEIModContainer.isCCLoaded()) {
|
||||
tess.setColorRGBA_F(0, 0.5F, 0.9F, (float) dist * 0.5F);
|
||||
int cubeBase = (int) Math.floor((y1 + intOffsetY) / 16.0) * 16;
|
||||
for (int cubeY = cubeBase; cubeY <= y2 + intOffsetY; cubeY += 16) {
|
||||
double ry = cubeY - intOffsetY;
|
||||
tess.addVertex(x1, ry, z1);
|
||||
tess.addVertex(x2, ry, z1);
|
||||
tess.addVertex(x1, ry, z2);
|
||||
tess.addVertex(x2, ry, z2);
|
||||
tess.addVertex(x1, ry, z1);
|
||||
tess.addVertex(x1, ry, z2);
|
||||
tess.addVertex(x2, ry, z1);
|
||||
tess.addVertex(x2, ry, z2);
|
||||
}
|
||||
}
|
||||
|
||||
if (cx == 0 && cz == 0) {
|
||||
if (chunkOverlay == 2) {
|
||||
dy = 32;
|
||||
y1 = Math.floor(entity.posY - dy / 2);
|
||||
y2 = y1 + dy;
|
||||
if (y1 < 0) {
|
||||
y1 = 0;
|
||||
y2 = dy;
|
||||
if (y1 < worldMinY) {
|
||||
y1 = worldMinY;
|
||||
y2 = worldMinY + dy;
|
||||
}
|
||||
|
||||
if (y1 > entity.worldObj.getHeight()) {
|
||||
y2 = entity.worldObj.getHeight();
|
||||
y1 = y2 - dy;
|
||||
if (y2 > worldMaxY) {
|
||||
y2 = worldMaxY;
|
||||
y1 = Math.max(worldMaxY - dy, worldMinY);
|
||||
}
|
||||
|
||||
y1 -= intOffsetY;
|
||||
@@ -361,20 +416,55 @@ public class WorldOverlayRenderer implements IKeyStateTracker {
|
||||
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";
|
||||
}
|
||||
private static int worldMinHeight(World world) {
|
||||
if (NEIModContainer.isCCLoaded() && world instanceof IMinMaxHeight worldHeights) {
|
||||
return worldHeights.getMinHeight();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return oregenPatternName;
|
||||
private static int worldMaxHeight(World world) {
|
||||
if (NEIModContainer.isCCLoaded() && world instanceof IMinMaxHeight worldHeights) {
|
||||
return worldHeights.getMaxHeight();
|
||||
} else {
|
||||
return world.getHeight();
|
||||
}
|
||||
}
|
||||
|
||||
private static Callable<String> oregenPatternReader;
|
||||
|
||||
private static String getOregenPatternName() {
|
||||
if (oregenPatternReader == null) {
|
||||
oregenPatternReader = resolveOregenPatternReader();
|
||||
}
|
||||
try {
|
||||
return oregenPatternReader.call();
|
||||
} catch (Exception ignored) {
|
||||
return "AXISSYMMETRICAL";
|
||||
}
|
||||
}
|
||||
|
||||
private static Callable<String> resolveOregenPatternReader() {
|
||||
try {
|
||||
final Class<?> gtWorldGenerator = ReflectionHelper.getClass(
|
||||
WorldOverlayRenderer.class.getClassLoader(),
|
||||
"gregtech.common.GTWorldgenerator",
|
||||
"gregtech.common.GT_Worldgenerator");
|
||||
|
||||
try {
|
||||
// GT5-Unofficial >= 5.09.54.29 support
|
||||
final Method accessor = gtWorldGenerator.getMethod("getOregenPattern");
|
||||
return () -> ((Enum<?>) accessor.invoke(null)).name();
|
||||
} catch (NoSuchMethodException legacy) {
|
||||
// Older GT
|
||||
final Field oregenPattern = gtWorldGenerator.getDeclaredField("oregenPattern");
|
||||
oregenPattern.setAccessible(true);
|
||||
return () -> ((Enum<?>) oregenPattern.get(null)).name();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
return () -> "AXISSYMMETRICAL";
|
||||
}
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package codechicken.nei.api;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
@@ -19,7 +22,6 @@ import codechicken.nei.ItemList;
|
||||
import codechicken.nei.ItemSorter;
|
||||
import codechicken.nei.ItemStackSet;
|
||||
import codechicken.nei.KeyManager;
|
||||
import codechicken.nei.KeyManager.KeyState;
|
||||
import codechicken.nei.LayoutManager;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.OffsetPositioner;
|
||||
@@ -31,7 +33,6 @@ 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;
|
||||
@@ -164,12 +165,32 @@ public class API {
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an alias name that this item can be found by in the search field, in addition to its display name.
|
||||
*/
|
||||
public static void setAliases(ItemStack item, String... aliases) {
|
||||
final List<String> list = Arrays.asList(aliases).stream().filter(Objects::nonNull).map(String::trim)
|
||||
.filter(s -> !s.isEmpty()).collect(Collectors.toList());
|
||||
|
||||
if (list.isEmpty()) {
|
||||
ItemInfo.itemAliases.remove(item);
|
||||
} else {
|
||||
ItemInfo.itemAliases.put(item, list);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an item to the item panel. Any items added using this function will override the default search pattern.
|
||||
*
|
||||
@@ -200,20 +221,12 @@ public class API {
|
||||
* @param defaultKey The default value, commonly obtained from {@link Keyboard}
|
||||
*/
|
||||
public static void addKeyBind(String ident, int defaultKey) {
|
||||
NEIClientConfig.setDefaultKeyBinding(ident, defaultKey);
|
||||
KeyManager.keyStates.put(ident, new KeyState());
|
||||
addOption(new OptionKeyBind(ident));
|
||||
KeyManager.registerKeyBinding(ident, defaultKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}
|
||||
*/
|
||||
@Deprecated
|
||||
public static void addHashBind(String ident, int defaultKey) {
|
||||
NEIClientConfig.setDefaultKeyBinding(ident, defaultKey);
|
||||
addOption(new OptionKeyBind(ident, true));
|
||||
KeyManager.registerKeyBinding(ident, defaultKey);
|
||||
}
|
||||
|
||||
public static void addOption(Option option) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import net.minecraft.inventory.Slot;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
|
||||
@@ -23,7 +24,7 @@ public class DefaultOverlayRenderer implements IRecipeOverlayRenderer {
|
||||
|
||||
@Override
|
||||
public void renderOverlay(GuiContainerManager gui, Slot slot) {
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
GL11.glBlendFunc(770, 1);
|
||||
|
||||
@@ -38,11 +39,7 @@ public class DefaultOverlayRenderer implements IRecipeOverlayRenderer {
|
||||
}
|
||||
|
||||
private static void drawHover(int x, int y) {
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
GL11.glDisable(GL11.GL_DEPTH_TEST);
|
||||
drawRect(x, y, 16, 16, 0x66555555);
|
||||
GL11.glPopAttrib();
|
||||
NEIClientUtils.gl2DRenderContext(() -> drawRect(x, y, 16, 16, 0x66555555));
|
||||
}
|
||||
|
||||
final IStackPositioner positioner;
|
||||
|
||||
@@ -16,7 +16,6 @@ import codechicken.nei.NEIDummySlotHandler;
|
||||
import codechicken.nei.NEIPotionGuiHandler;
|
||||
import codechicken.nei.recipe.CheatItemHandler;
|
||||
import codechicken.nei.recipe.FillFluidContainerHandler;
|
||||
import codechicken.nei.recipe.GuiRecipeCatalyst;
|
||||
import codechicken.nei.recipe.SearchInputDropHandler;
|
||||
|
||||
public class GuiInfo {
|
||||
@@ -31,7 +30,6 @@ public class GuiInfo {
|
||||
API.registerNEIGuiHandler(new NEICreativeGuiHandler());
|
||||
API.registerNEIGuiHandler(new NEIChestGuiHandler());
|
||||
API.registerNEIGuiHandler(new NEIDummySlotHandler());
|
||||
API.registerNEIGuiHandler(new GuiRecipeCatalyst(null));
|
||||
API.registerNEIGuiHandler(new SearchInputDropHandler());
|
||||
API.registerNEIGuiHandler(new FillFluidContainerHandler());
|
||||
API.registerNEIGuiHandler(new CheatItemHandler());
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
package codechicken.nei.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public interface IBookmarkContainerHandler {
|
||||
|
||||
default List<ItemStack> getStorageStacks(GuiContainer guiContainer) {
|
||||
final List<Slot> slots = guiContainer.inventorySlots.inventorySlots;
|
||||
final List<ItemStack> stacks = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < slots.size() - 4 * 9; i++) {
|
||||
if (slots.get(i).getHasStack()) {
|
||||
stacks.add(slots.get(i).getStack().copy());
|
||||
}
|
||||
}
|
||||
|
||||
return stacks;
|
||||
}
|
||||
|
||||
void pullBookmarkItemsFromContainer(GuiContainer guiContainer, ArrayList<ItemStack> realItems);
|
||||
}
|
||||
@@ -8,13 +8,34 @@ import java.util.stream.Collectors;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
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 boolean requireShiftForOverlayRecipe() {
|
||||
return NEIClientConfig.requireShiftForOverlayRecipe();
|
||||
}
|
||||
|
||||
default List<ItemOverlayState> presenceOverlay(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex) {
|
||||
final List<ItemOverlayState> itemPresenceSlots = new ArrayList<>();
|
||||
@@ -25,7 +46,7 @@ public interface IOverlayHandler {
|
||||
&& s.getStack().stackSize > 0
|
||||
&& s.isItemValid(s.getStack())
|
||||
&& s.canTakeStack(firstGui.mc.thePlayer))
|
||||
.map(s -> s.getStack().copy()).collect(Collectors.toCollection(ArrayList::new));
|
||||
.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))
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
package codechicken.nei.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
|
||||
public interface IRecipeFilter {
|
||||
|
||||
public static interface IRecipeFilterProvider {
|
||||
|
||||
public IRecipeFilter getFilter();
|
||||
public IRecipeFilter getRecipeFilter();
|
||||
}
|
||||
|
||||
public boolean matches(IRecipeHandler handler, List<PositionedStack> ingredients, PositionedStack result,
|
||||
List<PositionedStack> others);
|
||||
public boolean matches(IRecipeHandler handler, int recipeIndex);
|
||||
|
||||
}
|
||||
@@ -6,9 +6,22 @@ import net.minecraftforge.fluids.FluidStack;
|
||||
|
||||
public interface IStackStringifyHandler {
|
||||
|
||||
public NBTTagCompound convertItemStackToNBT(ItemStack stack, boolean saveStackSize);
|
||||
default NBTTagCompound convertItemStackToNBT(ItemStack stack, boolean saveStackSize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ItemStack convertNBTToItemStack(NBTTagCompound nbtTag);
|
||||
default ItemStack convertNBTToItemStack(NBTTagCompound nbtTag) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default FluidStack getFluid(ItemStack stack) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default ItemStack normalizeRecipeQueryStack(ItemStack stack) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default void pauseItemDamageSound(boolean pause) {}
|
||||
|
||||
public FluidStack getFluid(ItemStack stack);
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
package codechicken.nei.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
@@ -64,6 +66,7 @@ import codechicken.nei.search.IdentifierFilter;
|
||||
import codechicken.nei.search.ModNameFilter;
|
||||
import codechicken.nei.search.OreDictionaryFilter;
|
||||
import codechicken.nei.search.TooltipFilter;
|
||||
import codechicken.nei.util.ItemUntranslator;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.ModContainer;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
@@ -74,14 +77,18 @@ import cpw.mods.fml.common.registry.GameRegistry.UniqueIdentifier;
|
||||
*/
|
||||
public class ItemInfo {
|
||||
|
||||
public static enum Layout {
|
||||
public enum Layout {
|
||||
|
||||
HEADER,
|
||||
BODY,
|
||||
FOOTER
|
||||
FOOTER;
|
||||
|
||||
public static final Layout[] VALUES = values();
|
||||
}
|
||||
|
||||
public static final ArrayListMultimap<Layout, IHighlightHandler> highlightHandlers = ArrayListMultimap.create();
|
||||
public static final ItemStackMap<String> nameOverrides = new ItemStackMap<>();
|
||||
public static final ItemStackMap<List<String>> itemAliases = new ItemStackMap<>();
|
||||
public static final ItemStackSet hiddenItems = new ItemStackSet();
|
||||
public static final AnyMultiItemFilter hiddenItemsRules = new AnyMultiItemFilter();
|
||||
public static final ItemStackSet finiteItems = new ItemStackSet();
|
||||
@@ -107,6 +114,11 @@ public class ItemInfo {
|
||||
return nameOverrides.get(stack);
|
||||
}
|
||||
|
||||
public static List<String> getAliases(ItemStack stack) {
|
||||
final List<String> aliases = itemAliases.get(stack);
|
||||
return aliases != null ? aliases : Collections.emptyList();
|
||||
}
|
||||
|
||||
public static boolean canBeInfinite(ItemStack stack) {
|
||||
return !finiteItems.contains(stack);
|
||||
}
|
||||
@@ -123,12 +135,12 @@ 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();
|
||||
@@ -136,6 +148,10 @@ public class ItemInfo {
|
||||
addSearchProviders();
|
||||
RecipeItemInputHandler.load();
|
||||
PresetsList.load();
|
||||
|
||||
if (NEIClientConfig.enableItemUntranslator()) {
|
||||
ItemUntranslator.getInstance().load();
|
||||
}
|
||||
}
|
||||
|
||||
private static void addSearchProviders() {
|
||||
@@ -268,7 +284,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 {
|
||||
@@ -280,14 +297,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());
|
||||
@@ -323,44 +338,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);
|
||||
@@ -368,41 +368,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,25 +382,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();
|
||||
@@ -451,30 +431,38 @@ public class ItemInfo {
|
||||
Block mouseoverBlock = world.getBlock(x, y, z);
|
||||
|
||||
ArrayList<ItemStack> items = new ArrayList<>();
|
||||
|
||||
ArrayList<IHighlightHandler> handlers = new ArrayList<>();
|
||||
|
||||
if (highlightIdentifiers.containsKey(null)) handlers.addAll(highlightIdentifiers.get(null));
|
||||
if (highlightIdentifiers.containsKey(mouseoverBlock)) handlers.addAll(highlightIdentifiers.get(mouseoverBlock));
|
||||
|
||||
for (IHighlightHandler ident : handlers) {
|
||||
ItemStack item = ident.identifyHighlight(world, player, hit);
|
||||
final ItemStack item = ident.identifyHighlight(world, player, hit);
|
||||
if (item != null) items.add(item);
|
||||
}
|
||||
|
||||
if (items.size() > 0) return items;
|
||||
if (!items.isEmpty()) return items;
|
||||
|
||||
ItemStack pick = mouseoverBlock.getPickBlock(hit, world, x, y, z, player);
|
||||
if (pick != null) items.add(pick);
|
||||
try {
|
||||
final ItemStack pick = mouseoverBlock.getPickBlock(hit, world, x, y, z, player);
|
||||
if (pick != null) items.add(pick);
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
if (!items.isEmpty()) return items;
|
||||
|
||||
if (mouseoverBlock instanceof IShearable shearable) {
|
||||
if (shearable.isShearable(new ItemStack(Items.shears), world, x, y, z)) {
|
||||
items.addAll(shearable.onSheared(new ItemStack(Items.shears), world, x, y, z, 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (!items.isEmpty()) return items;
|
||||
|
||||
try {
|
||||
items.addAll(mouseoverBlock.getDrops(world, x, y, z, world.getBlockMetadata(x, y, z), 0));
|
||||
} catch (Exception ignored) {}
|
||||
if (mouseoverBlock instanceof IShearable) {
|
||||
IShearable shearable = (IShearable) mouseoverBlock;
|
||||
if (shearable.isShearable(new ItemStack(Items.shears), world, x, y, z))
|
||||
items.addAll(shearable.onSheared(new ItemStack(Items.shears), world, x, y, z, 0));
|
||||
}
|
||||
|
||||
if (items.size() == 0) items.add(0, new ItemStack(mouseoverBlock, 1, world.getBlockMetadata(x, y, z)));
|
||||
if (items.isEmpty()) items.add(new ItemStack(mouseoverBlock, 1, world.getBlockMetadata(x, y, z)));
|
||||
|
||||
return items;
|
||||
}
|
||||
@@ -487,7 +475,7 @@ public class ItemInfo {
|
||||
MovingObjectPosition mop) {
|
||||
List<String> retString = new ArrayList<>();
|
||||
|
||||
for (ItemInfo.Layout layout : ItemInfo.Layout.values())
|
||||
for (ItemInfo.Layout layout : Layout.VALUES)
|
||||
for (IHighlightHandler handler : ItemInfo.highlightHandlers.get(layout))
|
||||
retString = handler.handleTextData(itemStack, world, player, mop, retString, layout);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.LinkedList;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.config.GuiOptionList;
|
||||
import codechicken.nei.config.OptionCycled;
|
||||
|
||||
public class NEIInfo {
|
||||
@@ -13,7 +14,8 @@ public class NEIInfo {
|
||||
|
||||
public static void load(World world) {
|
||||
OptionCycled modeOption = (OptionCycled) NEIClientConfig.getOptionList().getOption("inventory.cheatmode");
|
||||
modeOption.parent.synthesizeEnvironment(false);
|
||||
// kept alive so the WeakReference in Option.slotRef isn't GC'd before copyGlobals/cycle use it
|
||||
GuiOptionList env = modeOption.parent.synthesizeEnvironment(false);
|
||||
if (!modeOption.optionValid(modeOption.value())) {
|
||||
modeOption.copyGlobals();
|
||||
modeOption.cycle();
|
||||
|
||||
@@ -1,104 +1,172 @@
|
||||
package codechicken.nei.api;
|
||||
|
||||
import static codechicken.lib.gui.GuiDraw.getMousePosition;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.util.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.nei.ItemPanel.ItemPanelSlot;
|
||||
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.KeyManager;
|
||||
import codechicken.nei.LayoutManager;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.recipe.BookmarkRecipeId;
|
||||
import codechicken.nei.SearchField;
|
||||
import codechicken.nei.bookmark.BookmarkGrid;
|
||||
import codechicken.nei.bookmark.BookmarkGroup;
|
||||
import codechicken.nei.bookmark.BookmarkItem;
|
||||
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
|
||||
import codechicken.nei.bookmark.BookmarkPayload;
|
||||
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 {
|
||||
|
||||
private static class HotkeysCache {
|
||||
|
||||
public int mousex;
|
||||
public int mousey;
|
||||
public ItemStack stack;
|
||||
public int groupId;
|
||||
public Map<String, String> hotkeys = new HashMap<>();
|
||||
|
||||
public boolean matches(int mousex, int mousey, ItemStack stack, int groupId) {
|
||||
return Math.abs(this.mousex - mousex) < 16 && Math.abs(this.mousey - mousey) < 16
|
||||
&& (this.stack == null ? stack == null && this.groupId == groupId
|
||||
: stack != null && NEIClientUtils.areStacksSameTypeWithNBT(stack, this.stack));
|
||||
}
|
||||
|
||||
public void update(int mousex, int mousey, ItemStack stack, int groupId, Map<String, String> hotkeys) {
|
||||
this.mousex = mousex;
|
||||
this.mousey = mousey;
|
||||
this.stack = stack != null ? stack.copy() : null;
|
||||
this.groupId = groupId;
|
||||
this.hotkeys = hotkeys;
|
||||
}
|
||||
}
|
||||
|
||||
private static HotkeysCache hotkeysCache = new HotkeysCache();
|
||||
|
||||
public static boolean handleKeyEvent(ItemStack stackover) {
|
||||
|
||||
if (!NEIClientConfig.isLoaded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.overlay_hide")) {
|
||||
return hideOverlayRecipe();
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.bookmark_pull_items")) {
|
||||
return ItemPanels.bookmarkPanel.pullBookmarkItems(ItemPanels.bookmarkPanel.getHoveredGroupId(true), false);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.bookmark_pull_items_ingredients")) {
|
||||
return ItemPanels.bookmarkPanel.pullBookmarkItems(ItemPanels.bookmarkPanel.getHoveredGroupId(true), true);
|
||||
}
|
||||
|
||||
if (stackover == null && NEIClientConfig.isKeyHashDown("gui.remove_recipe")) {
|
||||
final int groupId = ItemPanels.bookmarkPanel.getHoveredGroupId(true);
|
||||
|
||||
if (groupId != -1) {
|
||||
ItemPanels.bookmarkPanel.removeGroup(groupId);
|
||||
return true;
|
||||
}
|
||||
if (KeyManager.isKeyDown("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 (KeyManager.isHashDown("bookmark.remove_recipe", NEIClientUtils.SHIFT_HASH)) {
|
||||
ItemPanels.bookmarkPanel.removeGroup(groupId);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (KeyManager.isKeyDown("bookmark.pull_items")) {
|
||||
return ItemPanels.bookmarkPanel.pullBookmarkItems(groupId, NEIClientUtils.shiftKey());
|
||||
}
|
||||
|
||||
if (KeyManager.isKeyDown("bookmark.chat_link") && NEIClientUtils.controlKey()) {
|
||||
NEIClientUtils.sendChatItemLink(BookmarkPayload.of(groupId).toNBT());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NEIClientConfig.autocraftingEnabled() && KeyManager.isKeyDown("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);
|
||||
if (KeyManager.isKeyDown("gui.overlay")) {
|
||||
return openOverlayRecipe(stackover);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.copy_name")) {
|
||||
if (KeyManager.isHashDown("copy.name", NEIClientUtils.CTRL_HASH)) {
|
||||
return copyItemStackName(stackover);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.copy_oredict")) {
|
||||
if (KeyManager.isHashDown("copy.identifier", NEIClientUtils.CTRL_HASH)) {
|
||||
return copyItemStackID(stackover);
|
||||
}
|
||||
|
||||
if (KeyManager.isHashDown("copy.oredict", NEIClientUtils.CTRL_HASH)) {
|
||||
return copyItemStackOreDictionary(stackover);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.overlay_use")) {
|
||||
return openOverlayRecipe(stackover, true);
|
||||
if (KeyManager.isKeyDown("bookmark.chat_link") && NEIClientUtils.controlKey()) {
|
||||
return sendRecipeInChatLink(stackover, NEIClientUtils.shiftKey());
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.recipe")) {
|
||||
if (KeyManager.isKeyDown("recipe.recipe")) {
|
||||
return GuiCraftingRecipe.openRecipeGui("item", stackover);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.usage")) {
|
||||
if (KeyManager.isKeyDown("recipe.usage")) {
|
||||
return GuiUsageRecipe.openRecipeGui("item", stackover);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.bookmark")) {
|
||||
return saveRecipeInBookmark(stackover, false, false);
|
||||
if (KeyManager.isHashDown("bookmark.favorite", NEIClientUtils.SHIFT_HASH)) {
|
||||
return saveFavoriteTree(stackover);
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.bookmark_recipe")) {
|
||||
return saveRecipeInBookmark(stackover, true, false);
|
||||
if (KeyManager.isKeyDown("bookmark.add")) {
|
||||
return saveRecipeInBookmark(stackover, NEIClientUtils.shiftKey(), NEIClientUtils.controlKey());
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.bookmark_count")) {
|
||||
return saveRecipeInBookmark(stackover, false, true);
|
||||
if (KeyManager.isKeyDown("bookmark.pull_items")) {
|
||||
return pullRecipeItems(stackover, NEIClientUtils.shiftKey());
|
||||
}
|
||||
|
||||
if (NEIClientConfig.isKeyHashDown("gui.bookmark_recipe_count")) {
|
||||
return saveRecipeInBookmark(stackover, true, true);
|
||||
if (NEIClientConfig.autocraftingEnabled() && KeyManager.isKeyDown("gui.craft_items")
|
||||
&& NEIClientUtils.shiftKey()) {
|
||||
return runAutoCrafting(stackover, !NEIClientUtils.controlKey());
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -114,28 +182,59 @@ public abstract class ShortcutInputHandler {
|
||||
final int button = Mouse.getEventButton();
|
||||
|
||||
if (button == 0) {
|
||||
return GuiCraftingRecipe.openRecipeGui("item", stackover);
|
||||
return GuiCraftingRecipe.openRecipeGui("item", stackover.copy());
|
||||
} else if (button == 1) {
|
||||
return GuiUsageRecipe.openRecipeGui("item", stackover);
|
||||
return GuiUsageRecipe.openRecipeGui("item", stackover.copy());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean hideOverlayRecipe() {
|
||||
private static boolean copyItemStackName(ItemStack stackover) {
|
||||
GuiScreen.setClipboardString(SearchField.getEscapedSearchText(stackover));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (LayoutManager.overlayRenderer != null) {
|
||||
LayoutManager.overlayRenderer = null;
|
||||
private static boolean copyItemStackID(ItemStack stackover) {
|
||||
if (stackover == null || stackover.getItem() == null) return false;
|
||||
GuiScreen.setClipboardString(
|
||||
stackover.getItem().delegate.name()
|
||||
+ (stackover.getItemDamage() != 0 ? "/" + stackover.getItemDamage() : ""));
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean sendRecipeInChatLink(ItemStack stackover, boolean saveIngredients) {
|
||||
final Point mousePos = GuiDraw.getMousePosition();
|
||||
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mousePos.x, mousePos.y);
|
||||
|
||||
if (slot != null && saveIngredients && slot.getType() == BookmarkItemType.RESULT) {
|
||||
NEIClientUtils.sendChatItemLink(BookmarkPayload.of(slot.getBookmarkItem()).toNBT());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
final Recipe recipe = getFocusedRecipe(stackover, mousePos.x, mousePos.y, saveIngredients);
|
||||
|
||||
private static boolean copyItemStackName(ItemStack stackover) {
|
||||
Toolkit.getDefaultToolkit().getSystemClipboard()
|
||||
.setContents(new StringSelection(stackover.getDisplayName()), null);
|
||||
if (recipe != null && saveIngredients) {
|
||||
NEIClientUtils.sendChatItemLink(BookmarkPayload.of(recipe).toNBT());
|
||||
return true;
|
||||
}
|
||||
|
||||
final RecipeId recipeId;
|
||||
|
||||
if (slot != null) {
|
||||
recipeId = slot.getType() == BookmarkItemType.INGREDIENT ? null : slot.getRecipeId();
|
||||
} else {
|
||||
recipeId = recipe != null ? recipe.getRecipeId() : null;
|
||||
}
|
||||
|
||||
final boolean existsRecipe = NEIClientConfig.getBooleanSetting("inventory.bookmarks.bookmarkItemsWithRecipe");
|
||||
|
||||
if (ItemPanels.itemPanel.containsWithSubpanels(mousePos.x, mousePos.y)) {
|
||||
stackover = ItemQuantityField.prepareStackWithQuantity(stackover, 0);
|
||||
}
|
||||
|
||||
NEIClientUtils.sendChatItemLink(BookmarkPayload.of(stackover, existsRecipe ? recipeId : null).toNBT());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -153,56 +252,499 @@ public abstract class ShortcutInputHandler {
|
||||
builder.deleteCharAt(builder.length() - 1);
|
||||
}
|
||||
|
||||
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(builder.toString()), null);
|
||||
GuiScreen.setClipboardString(builder.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean openOverlayRecipe(ItemStack stackover, boolean shift) {
|
||||
final GuiContainer gui = NEIClientUtils.getGuiContainer();
|
||||
|
||||
if (gui == null || gui instanceof GuiRecipe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Point mouseover = getMousePosition();
|
||||
ItemPanelSlot panelSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
|
||||
BookmarkRecipeId recipeId = null;
|
||||
|
||||
if (panelSlot != null) {
|
||||
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(panelSlot.slotIndex);
|
||||
} else {
|
||||
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(stackover);
|
||||
}
|
||||
private static boolean runAutoCrafting(ItemStack stackover, boolean ignoreInventory) {
|
||||
final RecipeId recipeId = GuiCraftingRecipe.getRecipeId(NEIClientUtils.getGuiContainer(), stackover);
|
||||
|
||||
if (recipeId != null) {
|
||||
return GuiCraftingRecipe.overlayRecipe(stackover, recipeId, shift);
|
||||
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.getType() != BookmarkItemType.INGREDIENT) {
|
||||
|
||||
if (slot.getGroup().crafting == null) {
|
||||
final Recipe recipe = Recipe.of(slot.getRecipeId());
|
||||
if (recipe != null) {
|
||||
math = RecipeChainMath.of(recipe, Math.max(1, slot.getMultiplier()));
|
||||
}
|
||||
} else {
|
||||
math = ItemPanels.bookmarkPanel.getGrid()
|
||||
.createRecipeChainMath(slot.getGroupId(), slot.getRecipeId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (math != null) {
|
||||
|
||||
if (ignoreInventory) {
|
||||
autocraftingIgnoreInventory(math);
|
||||
}
|
||||
|
||||
AutoCraftingManager.runProcessing(math);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean saveRecipeInBookmark(ItemStack stack, boolean saveIngredients, boolean saveStackSize) {
|
||||
private static boolean openOverlayRecipe(ItemStack stackover) {
|
||||
final GuiContainer gui = NEIClientUtils.getGuiContainer();
|
||||
final RecipeId recipeId = GuiCraftingRecipe.getRecipeId(gui, stackover);
|
||||
|
||||
if (stack != null) {
|
||||
final GuiContainer gui = NEIClientUtils.getGuiContainer();
|
||||
List<PositionedStack> ingredients = null;
|
||||
String handlerName = "";
|
||||
if (recipeId != null) {
|
||||
final RecipeHandlerRef handlerRef = RecipeHandlerRef.of(recipeId);
|
||||
|
||||
if (gui instanceof GuiRecipe) {
|
||||
ingredients = ((GuiRecipe<?>) gui).getFocusedRecipeIngredients();
|
||||
handlerName = ((GuiRecipe<?>) gui).getHandlerName();
|
||||
stack.stackSize = ((GuiRecipe<?>) gui).prepareFocusedRecipeResultStackSize(stack);
|
||||
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;
|
||||
}
|
||||
|
||||
ItemPanels.bookmarkPanel.addOrRemoveItem(stack, handlerName, ingredients, saveIngredients, saveStackSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, ItemStack stack) {
|
||||
return new HashMap<>();
|
||||
private static boolean saveRecipeInBookmark(ItemStack stackover, boolean saveIngredients, boolean saveStackSize) {
|
||||
final Point mousePos = GuiDraw.getMousePosition();
|
||||
|
||||
// If no slot was removed from the bookmark panel on click:
|
||||
if (!ItemPanels.bookmarkPanel.removeSlot(mousePos.x, mousePos.y, saveIngredients)) {
|
||||
final Recipe recipe = getFocusedRecipe(stackover, mousePos.x, mousePos.y, saveIngredients);
|
||||
|
||||
// --- Case 1: saving a recipe (with ingredients) ---
|
||||
if (recipe != null && saveIngredients) {
|
||||
|
||||
// If the recipe is not already bookmarked, add it
|
||||
if (!ItemPanels.bookmarkPanel.removeRecipe(recipe.getRecipeId(), BookmarkGrid.DEFAULT_GROUP_ID)) {
|
||||
final Recipe singleRecipe = Recipe.of(
|
||||
Arrays.asList(recipe.getResult(stackover)),
|
||||
recipe.getHandlerName(),
|
||||
recipe.getIngredients());
|
||||
singleRecipe.setCustomRecipeId(recipe.getRecipeId());
|
||||
|
||||
ItemPanels.bookmarkPanel.addRecipe(
|
||||
singleRecipe,
|
||||
// Determine if stack size should be saved
|
||||
saveStackSize
|
||||
|| NEIClientConfig.getBooleanSetting("inventory.bookmarks.bookmarkRecipeWithCount")
|
||||
? 1
|
||||
: 0,
|
||||
BookmarkGrid.DEFAULT_GROUP_ID);
|
||||
}
|
||||
|
||||
// --- Case 2: saving an item only ---
|
||||
} else {
|
||||
final RecipeId recipeId = recipe != null ? recipe.getRecipeId() : null;
|
||||
|
||||
// Determine if the item is associated with a recipe and should be saved with it
|
||||
final boolean existsRecipe = recipeId != null
|
||||
&& ItemPanels.bookmarkPanel.existsRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID)
|
||||
|| NEIClientConfig.getBooleanSetting("inventory.bookmarks.bookmarkItemsWithRecipe");
|
||||
|
||||
// If the item was not removed from the bookmarks, add it
|
||||
if (!ItemPanels.bookmarkPanel
|
||||
.removeItem(stackover, existsRecipe ? recipeId : null, BookmarkGrid.DEFAULT_GROUP_ID)) {
|
||||
|
||||
// Determine whether to preserve the item count
|
||||
saveStackSize = saveStackSize || saveIngredients
|
||||
|| ItemPanels.bookmarkPanel.existsRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID);
|
||||
|
||||
if (!saveStackSize) {
|
||||
stackover = StackInfo.withAmount(stackover, 0);
|
||||
} else if (ItemPanels.itemPanel.containsWithSubpanels(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(int mousex, int mousey, ItemStack stack) {
|
||||
final int groupId = ItemPanels.bookmarkPanel.getHoveredGroupId(true);
|
||||
|
||||
if (hotkeysCache.matches(mousex, mousey, stack, groupId)) {
|
||||
return hotkeysCache.hotkeys;
|
||||
}
|
||||
|
||||
final GuiContainer gui = NEIClientUtils.getGuiContainer();
|
||||
final Map<String, String> hotkeys = new HashMap<>();
|
||||
|
||||
if (groupId != -1) {
|
||||
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.remove_recipe", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("bookmark.group.remove_recipe"));
|
||||
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.chat_link", NEIClientUtils.CTRL_HASH),
|
||||
NEIClientUtils.translate("bookmark.group.chat_link"));
|
||||
|
||||
if (BookmarkContainerInfo.getBookmarkContainerHandler(gui) != null) {
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.pull_items"),
|
||||
NEIClientUtils.translate("bookmark.group.pull_items"));
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("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(
|
||||
KeyManager.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("bookmark.group.craft_all"));
|
||||
}
|
||||
|
||||
hotkeysCache.update(mousex, mousey, stack, groupId, hotkeys);
|
||||
return hotkeys;
|
||||
}
|
||||
|
||||
if (stack == null) {
|
||||
hotkeysCache.update(mousex, mousey, stack, groupId, hotkeys);
|
||||
return hotkeys;
|
||||
}
|
||||
|
||||
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(
|
||||
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("bookmark.group.remove_recipe"));
|
||||
} else if (slot.getRecipeId() == null || slot.getType() == BookmarkItemType.ITEM) {
|
||||
hotkeys.put(KeyManager.getKeyName("bookmark.add"), 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(
|
||||
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("bookmark.remove_recipe"));
|
||||
} else {
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("bookmark.remove_recipe"));
|
||||
|
||||
if (slot.getType() == BookmarkItemType.INGREDIENT) {
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.add"),
|
||||
NEIClientUtils.translate("bookmark.remove_item"));
|
||||
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("bookmark.remove_recipe"));
|
||||
} else {
|
||||
final BookmarkItem item = slot.getBookmarkItem();
|
||||
|
||||
if (ItemPanels.bookmarkPanel.getGrid().createChainItems(groupId).values().stream()
|
||||
.noneMatch(
|
||||
m -> m.type == BookmarkItemType.RESULT && !m.equals(item)
|
||||
&& item.equalsRecipe(m))) {
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.add"),
|
||||
NEIClientUtils.translate("bookmark.remove_recipe"));
|
||||
} else {
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.add"),
|
||||
NEIClientUtils.translate("bookmark.remove_item"));
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("bookmark.remove_recipe"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (BookmarkContainerInfo.getBookmarkContainerHandler(gui) != null) {
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.pull_items"),
|
||||
NEIClientUtils.translate("bookmark.group.pull_items"));
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.pull_items", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("bookmark.group.pull_items_shift"));
|
||||
}
|
||||
|
||||
} else {
|
||||
hotkeys.put(KeyManager.getKeyName("bookmark.add"), NEIClientUtils.translate("bookmark.add_item"));
|
||||
|
||||
if (StackInfo.getAmount(stack) > 0) {
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.add", NEIClientUtils.CTRL_HASH),
|
||||
NEIClientUtils.translate("bookmark.add_item_with_count"));
|
||||
}
|
||||
|
||||
if (recipeId != null) {
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
|
||||
NEIClientUtils.translate("bookmark.add_item_with_recipe_and_count"));
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.add", 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(
|
||||
KeyManager.getKeyName("bookmark.favorite", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("recipe.favorite.bookmark_recipe"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
hotkeys.put(KeyManager.getKeyName("recipe.recipe"), NEIClientUtils.translate("itempanel.open_crafting"));
|
||||
hotkeys.put(KeyManager.getKeyName("recipe.usage"), NEIClientUtils.translate("itempanel.open_usage"));
|
||||
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("copy.name", NEIClientUtils.CTRL_HASH),
|
||||
NEIClientUtils.translate("itempanel.copy_name"));
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("copy.oredict", NEIClientUtils.CTRL_HASH),
|
||||
NEIClientUtils.translate("itempanel.copy_oredict"));
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("copy.identifier", NEIClientUtils.CTRL_HASH),
|
||||
NEIClientUtils.translate("itempanel.copy_id"));
|
||||
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.chat_link", NEIClientUtils.CTRL_HASH),
|
||||
NEIClientUtils.translate("bookmark.item.chat_link"));
|
||||
|
||||
if (!(gui instanceof GuiRecipe) && NEIClientConfig.canCheatItem(stack)) {
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("itempanel.open_crafting"));
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_RMB),
|
||||
NEIClientUtils.translate("itempanel.open_usage"));
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName(NEIClientUtils.CTRL_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
|
||||
NEIClientUtils.translate("itempanel.infinite_item"));
|
||||
} 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(
|
||||
KeyManager.getKeyName("gui.overlay"),
|
||||
NEIClientUtils.translate("itempanel.overlay_recipe"));
|
||||
}
|
||||
|
||||
if (handlerRef.canFillCraftingGrid(gui)) {
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("gui.overlay", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("itempanel.fill_crafting_grid"));
|
||||
|
||||
if (handlerRef.allowedTransferAlghoritm(gui)) {
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName(
|
||||
"gui.overlay",
|
||||
NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
|
||||
NEIClientUtils.translate("itempanel.fill_crafting_grid_quantity"));
|
||||
}
|
||||
}
|
||||
|
||||
if (NEIClientConfig.autocraftingEnabled()) {
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName(
|
||||
"gui.craft_items",
|
||||
NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
|
||||
NEIClientUtils.translate("itempanel.craft_missing"));
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("itempanel.craft_all"));
|
||||
}
|
||||
}
|
||||
|
||||
hotkeys.put(
|
||||
KeyManager.getKeyName("bookmark.chat_link", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
|
||||
NEIClientUtils.translate("bookmark.recipe.chat_link"));
|
||||
}
|
||||
|
||||
hotkeysCache.update(mousex, mousey, stack, groupId, hotkeys);
|
||||
|
||||
return hotkeys;
|
||||
}
|
||||
|
||||
private static void autocraftingIgnoreInventory(RecipeChainMath math) {
|
||||
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
|
||||
final List<ItemStack> playerInventory = AutoCraftingManager.getInventoryItems(guiContainer).values();
|
||||
final RecipeId rootRecipeId = math.createMasterRoot();
|
||||
|
||||
for (int i = 0; i < math.recipeIngredients.size(); i++) {
|
||||
final BookmarkItem item = math.recipeIngredients.get(i);
|
||||
|
||||
if (item.getAmount() > 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.getAmount()) {
|
||||
math.recipeIngredients.set(
|
||||
i,
|
||||
BookmarkItem.builder(item).multiplier(1)
|
||||
.factor(amount + item.getAmount() - (amount % item.getAmount()))
|
||||
.chance(PositionedStack.CHANCE_FULL).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static RecipeId getHotkeyRecipeId(GuiContainer gui, int mousex, int mousey, ItemStack stack,
|
||||
BookmarksGridSlot slot) {
|
||||
|
||||
if (slot != null) {
|
||||
return slot.getType() == BookmarkItemType.INGREDIENT ? 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package codechicken.nei.asm;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.settings.KeyBinding;
|
||||
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper;
|
||||
|
||||
public final class KeyBindingFixHooks {
|
||||
|
||||
private static volatile boolean initialized;
|
||||
private static Field keybindArrayField;
|
||||
private static Field pressedField;
|
||||
private static Field pressTimeField;
|
||||
|
||||
private KeyBindingFixHooks() {}
|
||||
|
||||
public static void onTickAll(int keyCode) {
|
||||
|
||||
if (keyCode == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (KeyBinding binding : getBindings()) {
|
||||
if (binding.getKeyCode() == keyCode) {
|
||||
try {
|
||||
pressTimeField.setInt(binding, pressTimeField.getInt(binding) + 1);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void setKeyBindStateAll(int keyCode, boolean pressed) {
|
||||
|
||||
if (keyCode == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (KeyBinding binding : getBindings()) {
|
||||
if (binding.getKeyCode() == keyCode) {
|
||||
try {
|
||||
pressedField.setBoolean(binding, pressed);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static List<KeyBinding> getBindings() {
|
||||
init();
|
||||
|
||||
try {
|
||||
return (List<KeyBinding>) keybindArrayField.get(null);
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static synchronized void init() {
|
||||
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
keybindArrayField = ReflectionHelper.findField(KeyBinding.class, "keybindArray", "field_74516_a");
|
||||
pressedField = ReflectionHelper.findField(KeyBinding.class, "pressed", "field_74513_e");
|
||||
pressTimeField = ReflectionHelper.findField(KeyBinding.class, "pressTime", "field_151474_i");
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -56,7 +56,8 @@ public class NEITransformer implements IClassTransformer {
|
||||
|
||||
public NEITransformer() {
|
||||
if (FMLLaunchHandler.side().isClient()) {
|
||||
// Generates method to set the placed position of a mob spawner for the item callback. More portable than
|
||||
// Generates method to set the placed position of a mob spawner for the item
|
||||
// callback. More portable than
|
||||
// copying vanilla placement code
|
||||
transformer.add(
|
||||
new MethodWriter(
|
||||
@@ -82,7 +83,6 @@ public class NEITransformer implements IClassTransformer {
|
||||
asmblocks.get("commaFix"),
|
||||
true));
|
||||
|
||||
// fix workbench container losing items on shift click output without room for the full stack
|
||||
transformer.add(
|
||||
new MethodTransformer(
|
||||
new ObfMapping(
|
||||
@@ -105,6 +105,33 @@ public class NEITransformer implements IClassTransformer {
|
||||
asmblocks.get("d_glintAlphaFix"),
|
||||
asmblocks.get("glintAlphaFix")));
|
||||
|
||||
if (FMLLaunchHandler.side().isClient()) {
|
||||
transformer.add(
|
||||
new MethodWriter(
|
||||
ACC_PUBLIC | ACC_STATIC,
|
||||
new ObfMapping("net/minecraft/client/settings/KeyBinding", "func_74507_a", "(I)V"),
|
||||
asmblocks.get("m_keyBindingOnTickAll")));
|
||||
|
||||
transformer.add(
|
||||
new MethodWriter(
|
||||
ACC_PUBLIC | ACC_STATIC,
|
||||
new ObfMapping("net/minecraft/client/settings/KeyBinding", "func_74510_a", "(IZ)V"),
|
||||
asmblocks.get("m_keyBindingSetStateAll")));
|
||||
|
||||
transformer.add(
|
||||
new MethodInjector(
|
||||
new ObfMapping("net/minecraft/client/settings/GameSettings", "func_74303_b", "()V"),
|
||||
asmblocks.get("saveOptionsHook"),
|
||||
true));
|
||||
|
||||
transformer.add(
|
||||
new MethodInjector(
|
||||
new ObfMapping("net/minecraft/client/settings/GameSettings", "func_74303_b", "()V"),
|
||||
asmblocks.get("n_saveOptionsSendSettings"),
|
||||
asmblocks.get("saveOptionsRestoreHook"),
|
||||
false));
|
||||
}
|
||||
|
||||
String GuiContainer = "net/minecraft/client/gui/inventory/GuiContainer";
|
||||
// add manager field
|
||||
transformer.add(
|
||||
@@ -413,7 +440,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);
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package codechicken.nei.asm;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import codechicken.core.CommonUtils;
|
||||
import codechicken.nei.KeyManager;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
|
||||
public final class SaveOptionsFixHooks {
|
||||
|
||||
private static final String KEY_PREFIX = "key_nei.options.keys.";
|
||||
|
||||
private static List<String> pendingRestoreLines;
|
||||
|
||||
private SaveOptionsFixHooks() {}
|
||||
|
||||
public static void onBeforeSaveOptions() {
|
||||
pendingRestoreLines = null;
|
||||
|
||||
if (NEIClientConfig.isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final File optionsFile = new File(CommonUtils.getMinecraftDir(), "options.txt");
|
||||
if (!optionsFile.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<String> missing = new ArrayList<>();
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(optionsFile))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (!line.startsWith(KEY_PREFIX)) continue;
|
||||
final int colon = line.indexOf(':');
|
||||
if (colon <= 0) continue;
|
||||
|
||||
final String description = line.substring(4, colon);
|
||||
if (!KeyManager.isRegistered(description)) {
|
||||
missing.add(line);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to read key bindings before options save", e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!missing.isEmpty()) {
|
||||
pendingRestoreLines = missing;
|
||||
}
|
||||
}
|
||||
|
||||
public static void onAfterSaveOptions() {
|
||||
final List<String> restore = pendingRestoreLines;
|
||||
pendingRestoreLines = null;
|
||||
|
||||
if (restore == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final File optionsFile = new File(CommonUtils.getMinecraftDir(), "options.txt");
|
||||
|
||||
try (FileWriter writer = new FileWriter(optionsFile, true)) {
|
||||
for (String line : restore) {
|
||||
writer.write(line);
|
||||
writer.write(System.lineSeparator());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to restore NEI key bindings after options save", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,392 @@
|
||||
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.BookmarkItem.BookmarkItemType;
|
||||
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);
|
||||
final boolean isCollapsedRecipeAnchor = group.crafting != null && bookmarkItem.recipeId != null
|
||||
&& bookmarkItem.type != BookmarkItemType.INGREDIENT
|
||||
&& group.collapsedRecipes.contains(bookmarkItem.recipeId);
|
||||
|
||||
if (group.crafting != null && !isCollapsedRecipeAnchor
|
||||
&& (!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 (item.recipeId != null && !(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.type != BookmarkItemType.INGREDIENT
|
||||
&& (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.builder(bookmarkItem.groupId, bookmarkItem.itemStack)
|
||||
.multiplier(1).factor(StackInfo.getAmount(bookmarkItem.itemStack)).recipeId(bookmarkItem.recipeId)
|
||||
.type(isIngredient ? BookmarkItemType.INGREDIENT : BookmarkItemType.RESULT)
|
||||
.permutations(Collections.emptyMap()).build();
|
||||
|
||||
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) {
|
||||
final 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.type != BookmarkItemType.INGREDIENT
|
||||
|| !meta.recipeId.equals(previousMeta.recipeId)
|
||||
|| index + 1 < maxIndex && this.grid.isInvalidSlot((index + 1) % maxIndex))) {
|
||||
// In first column must be an item without recipe, a recipe result, or an ingredient
|
||||
// if the second column is occupied
|
||||
return index;
|
||||
} else
|
||||
if (!isFirstColumn && meta.type != BookmarkItemType.ITEM
|
||||
&& previousMeta.type != BookmarkItemType.ITEM
|
||||
&& meta.groupId == previousMeta.groupId
|
||||
&& 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.setRealMultiplier(item.getCalculatedMultiplier());
|
||||
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.getRealMultiplier(),
|
||||
0,
|
||||
0,
|
||||
chainItem.getItem(),
|
||||
null,
|
||||
group);
|
||||
} else {
|
||||
return new BookmarksGridSlot(
|
||||
slotIndex,
|
||||
itemIndex,
|
||||
chainItem.getRealMultiplier(),
|
||||
chainItem.getShiftAmount(),
|
||||
chainItem.getCalculatedMultiplier(),
|
||||
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,433 @@
|
||||
package codechicken.nei.bookmark;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.recipe.Recipe;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.Recipe.RecipeIngredient;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.NBTJson;
|
||||
|
||||
public class BookmarkItem {
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private static Map<ItemStack, String> fuzzyPermutations = new HashMap<>();
|
||||
|
||||
private final int groupId;
|
||||
private final ItemStack stack;
|
||||
private long factor;
|
||||
private long multiplier = -1;
|
||||
private long chance = PositionedStack.CHANCE_FULL;
|
||||
private RecipeId recipeId = null;
|
||||
private Recipe recipe = null;
|
||||
private BookmarkItemType type = BookmarkItemType.ITEM;
|
||||
private Map<String, ItemStack> permutations = null;
|
||||
|
||||
private Builder(int groupId, ItemStack stack) {
|
||||
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(stack);
|
||||
|
||||
this.groupId = groupId;
|
||||
this.stack = stack;
|
||||
this.factor = nbTag.hasKey("gtFluidName") ? Math.min(144, nbTag.getInteger("Count")) : 1;
|
||||
}
|
||||
|
||||
public Builder factor(long factor) {
|
||||
this.factor = factor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder multiplier(long multiplier) {
|
||||
this.multiplier = multiplier;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder chance(long chance) {
|
||||
this.chance = chance;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder recipe(Recipe recipe) {
|
||||
this.recipe = recipe;
|
||||
this.recipeId = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder recipeId(RecipeId recipeId) {
|
||||
this.recipeId = recipeId;
|
||||
this.recipe = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder type(BookmarkItemType type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder permutations(Map<String, ItemStack> permutations) {
|
||||
this.permutations = permutations;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BookmarkItem build() {
|
||||
final Map<String, ItemStack> perms;
|
||||
long multiplier = 0;
|
||||
|
||||
if (this.permutations != null) {
|
||||
perms = this.permutations;
|
||||
} else if (this.type == BookmarkItemType.INGREDIENT) {
|
||||
|
||||
if (this.recipe != null) {
|
||||
perms = Builder.generatePermutations(this.stack, this.recipe);
|
||||
} else if (this.recipeId != null) {
|
||||
perms = Builder.generatePermutations(this.stack, Recipe.of(this.recipeId));
|
||||
} else {
|
||||
perms = Builder.generatePermutations(this.stack);
|
||||
}
|
||||
|
||||
} else {
|
||||
perms = Builder.generatePermutations(this.stack);
|
||||
}
|
||||
|
||||
if (this.multiplier >= 0) {
|
||||
multiplier = this.multiplier;
|
||||
} else if (this.factor > 0) {
|
||||
multiplier = StackInfo.getAmount(this.stack) / this.factor;
|
||||
}
|
||||
|
||||
return new BookmarkItem(
|
||||
this.groupId,
|
||||
multiplier,
|
||||
this.factor,
|
||||
this.chance,
|
||||
this.stack,
|
||||
perms,
|
||||
this.recipeId != null ? this.recipeId : this.recipe != null ? this.recipe.getRecipeId() : null,
|
||||
this.type);
|
||||
}
|
||||
|
||||
public static Map<String, ItemStack> generatePermutations(ItemStack stack) {
|
||||
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 generatePermutations(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 : Builder.fuzzyPermutations.entrySet()) {
|
||||
if (NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack, entry.getKey())) {
|
||||
Builder.fuzzyPermutations.put(stack, entry.getValue());
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
final String stackGUID = StackInfo.getItemStackGUID(stack);
|
||||
Builder.fuzzyPermutations.put(stack, stackGUID);
|
||||
|
||||
return stackGUID;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum BookmarkItemType {
|
||||
|
||||
INGREDIENT,
|
||||
RESULT,
|
||||
ITEM;
|
||||
|
||||
public static BookmarkItemType fromInt(int type) {
|
||||
return type == 0 ? ITEM : type == 1 ? RESULT : INGREDIENT;
|
||||
}
|
||||
|
||||
public int toInt() {
|
||||
return this == ITEM ? 0 : this == RESULT ? 1 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
public int groupId;
|
||||
|
||||
public ItemStack itemStack;
|
||||
public Map<String, ItemStack> permutations;
|
||||
|
||||
public RecipeId recipeId;
|
||||
public BookmarkItemType type = BookmarkItemType.ITEM;
|
||||
|
||||
public long multiplier = 1L;
|
||||
public final long factor;
|
||||
public final int fluidCellAmount;
|
||||
public final long chance;
|
||||
|
||||
protected BookmarkItem(int groupId, long multiplier, long factor, long chance, ItemStack itemStack,
|
||||
Map<String, ItemStack> permutations, RecipeId recipeId, BookmarkItemType type) {
|
||||
final FluidStack fluidStack = StackInfo.getFluid(itemStack);
|
||||
|
||||
if (fluidStack != null) {
|
||||
this.fluidCellAmount = Math.max(1, StackInfo.isFluidContainer(itemStack) ? fluidStack.amount : 1);
|
||||
} else {
|
||||
this.fluidCellAmount = 1;
|
||||
}
|
||||
|
||||
this.groupId = groupId;
|
||||
|
||||
this.itemStack = itemStack;
|
||||
this.permutations = permutations;
|
||||
|
||||
this.recipeId = recipeId;
|
||||
this.type = type == null ? BookmarkItemType.ITEM : type;
|
||||
|
||||
this.multiplier = multiplier;
|
||||
this.factor = factor;
|
||||
this.chance = chance;
|
||||
}
|
||||
|
||||
public static Builder builder(int groupId, ItemStack stack) {
|
||||
return new Builder(groupId, stack);
|
||||
}
|
||||
|
||||
public static Builder builder(BookmarkItem item) {
|
||||
return new Builder(item.groupId, item.itemStack).factor(item.factor).multiplier(item.multiplier)
|
||||
.chance(item.chance).recipeId(item.recipeId).type(item.type).permutations(item.permutations);
|
||||
}
|
||||
|
||||
public static Builder builder(int groupId, ItemStack stack, Recipe recipe, BookmarkItemType type) {
|
||||
final List<RecipeIngredient> items = type == BookmarkItemType.RESULT ? recipe.getResults()
|
||||
: recipe.getIngredients();
|
||||
final Builder builder = builder(groupId, stack).type(type).recipe(recipe);
|
||||
long amount = 0;
|
||||
|
||||
for (RecipeIngredient res : items) {
|
||||
if (res.contains(stack)) {
|
||||
amount += 1L * res.getAmount() * res.getChance();
|
||||
}
|
||||
}
|
||||
|
||||
if ((amount % PositionedStack.CHANCE_FULL) == 0) {
|
||||
builder.factor(amount / PositionedStack.CHANCE_FULL);
|
||||
} else {
|
||||
builder.factor(1).chance(amount);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static BookmarkItem of(int groupId, ItemStack stack) {
|
||||
return builder(groupId, stack).build();
|
||||
}
|
||||
|
||||
public static BookmarkItem of(JsonObject jsonObject) {
|
||||
final NBTTagCompound itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject.get("item"));
|
||||
final ItemStack itemStack = StackInfo.loadFromNBT(itemStackNBT);
|
||||
|
||||
if (itemStack != null) {
|
||||
final int groupId = jsonObject.has("groupId") ? jsonObject.get("groupId").getAsInt()
|
||||
: BookmarkGrid.DEFAULT_GROUP_ID;
|
||||
final BookmarkItem.Builder builder = BookmarkItem.builder(groupId, itemStack);
|
||||
|
||||
if (jsonObject.has("type")) {
|
||||
builder.type(BookmarkItemType.fromInt(jsonObject.get("type").getAsInt()));
|
||||
} else if (jsonObject.has("ingredient") && jsonObject.get("ingredient").getAsBoolean()) {
|
||||
builder.type(BookmarkItemType.INGREDIENT);
|
||||
} else {
|
||||
builder.type(BookmarkItemType.RESULT);
|
||||
}
|
||||
|
||||
if (jsonObject.has("multiplier")) {
|
||||
builder.multiplier(jsonObject.get("multiplier").getAsInt());
|
||||
}
|
||||
|
||||
if (jsonObject.has("factor")) {
|
||||
builder.factor(jsonObject.get("factor").getAsInt());
|
||||
}
|
||||
|
||||
if (jsonObject.has("chance")) {
|
||||
builder.chance(jsonObject.get("chance").getAsInt());
|
||||
}
|
||||
|
||||
if (jsonObject.get("recipeId") instanceof JsonObject recipeJson) {
|
||||
builder.recipeId(RecipeId.of(recipeJson));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public BookmarkItem copyWithMultiplier(long multiplier) {
|
||||
return new BookmarkItem(
|
||||
this.groupId,
|
||||
multiplier,
|
||||
this.factor,
|
||||
this.chance,
|
||||
this.itemStack,
|
||||
this.permutations,
|
||||
this.recipeId,
|
||||
this.type);
|
||||
}
|
||||
|
||||
public BookmarkItem copyWithAmount(long amount) {
|
||||
return copyWithMultiplier(getMultiplierFromAmount(amount));
|
||||
}
|
||||
|
||||
public BookmarkItem copy() {
|
||||
return copyWithMultiplier(this.multiplier);
|
||||
}
|
||||
|
||||
public boolean containsItems(BookmarkItem item) {
|
||||
return this.permutations.keySet().stream().anyMatch(item.permutations::containsKey);
|
||||
}
|
||||
|
||||
public long getAmount() {
|
||||
return getAmount(this.multiplier);
|
||||
}
|
||||
|
||||
public long getAmount(long multiplier) {
|
||||
long amount = this.factor * multiplier;
|
||||
|
||||
if (this.fluidCellAmount > 1) {
|
||||
amount = amount * this.fluidCellAmount;
|
||||
}
|
||||
|
||||
if (this.chance != PositionedStack.CHANCE_FULL) {
|
||||
|
||||
if (this.type == BookmarkItemType.INGREDIENT) {
|
||||
// For ingredients, round up the expected amount to be conservative.
|
||||
amount = (amount * this.chance + PositionedStack.CHANCE_FULL - 1) / PositionedStack.CHANCE_FULL;
|
||||
} else {
|
||||
// For results, round down the expected amount to be conservative.
|
||||
amount = (amount * this.chance) / PositionedStack.CHANCE_FULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
public ItemStack getItemStack() {
|
||||
return getItemStack(getAmount());
|
||||
}
|
||||
|
||||
public ItemStack getItemStack(long amount) {
|
||||
return StackInfo.withAmount(this.itemStack, getStackSize(amount));
|
||||
}
|
||||
|
||||
public long getStackSize() {
|
||||
return getStackSize(getAmount());
|
||||
}
|
||||
|
||||
public long getStackSize(long amount) {
|
||||
|
||||
if (this.fluidCellAmount > 1) {
|
||||
amount = (amount + this.fluidCellAmount - 1) / this.fluidCellAmount;
|
||||
}
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
public long getMultiplierFromAmount(long amount) {
|
||||
if (this.factor <= 0 || this.chance <= 0) return 0;
|
||||
|
||||
if (this.fluidCellAmount > 1) {
|
||||
amount = (amount + this.fluidCellAmount - 1) / this.fluidCellAmount;
|
||||
}
|
||||
|
||||
if (this.chance == PositionedStack.CHANCE_FULL) {
|
||||
return (amount + this.factor - 1) / this.factor;
|
||||
}
|
||||
|
||||
return (amount * PositionedStack.CHANCE_FULL + this.factor * this.chance - 1) / (this.factor * this.chance);
|
||||
}
|
||||
|
||||
public long getMultiplier() {
|
||||
return this.multiplier;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public boolean emptyFactor() {
|
||||
return this.factor <= 0 || this.chance <= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.groupId, this.fluidCellAmount, this.type.toInt(), this.recipeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
|
||||
if (object instanceof BookmarkItem item) {
|
||||
return this.groupId == item.groupId && this.type == item.type
|
||||
&& this.fluidCellAmount == item.fluidCellAmount
|
||||
&& StackInfo.equalItemAndNBT(this.itemStack, item.itemStack, true)
|
||||
&& (this.recipeId == item.recipeId || this.recipeId != null && this.recipeId.equals(item.recipeId));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public JsonObject toJsonObject() {
|
||||
final JsonObject jsonObject = new JsonObject();
|
||||
|
||||
jsonObject.add("item", NBTJson.toJsonObject(StackInfo.itemStackToNBT(getItemStack())));
|
||||
jsonObject.add("multiplier", new JsonPrimitive(this.multiplier));
|
||||
jsonObject.add("factor", new JsonPrimitive(this.factor));
|
||||
jsonObject.add("type", new JsonPrimitive(this.type.toInt()));
|
||||
|
||||
if (this.groupId != BookmarkGrid.DEFAULT_GROUP_ID) {
|
||||
jsonObject.add("groupId", new JsonPrimitive(this.groupId));
|
||||
}
|
||||
|
||||
if (this.recipeId != null) {
|
||||
jsonObject.add("recipeId", this.recipeId.toJsonObject());
|
||||
}
|
||||
|
||||
if (this.chance != PositionedStack.CHANCE_FULL) {
|
||||
jsonObject.add("chance", new JsonPrimitive(this.chance));
|
||||
}
|
||||
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
package codechicken.nei.bookmark;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import codechicken.lib.gui.GuiDraw;
|
||||
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.ItemQuantityField;
|
||||
import codechicken.nei.ItemStackSet;
|
||||
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
|
||||
import codechicken.nei.recipe.Recipe;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.Recipe.RecipeIngredient;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.NBTJson;
|
||||
|
||||
public class BookmarkPayload {
|
||||
|
||||
private String linkType;
|
||||
private NBTTagCompound target;
|
||||
|
||||
private NBTTagCompound group;
|
||||
|
||||
private NBTTagList items = new NBTTagList();
|
||||
private NBTTagList recipes = new NBTTagList();
|
||||
|
||||
private BookmarkPayload(String linkType, ItemStack stack) {
|
||||
this.linkType = linkType;
|
||||
this.target = stack != null ? StackInfo.itemStackToNBT(stack) : null;
|
||||
}
|
||||
|
||||
public static BookmarkPayload of(NBTTagCompound nbt) {
|
||||
final BookmarkPayload payload = new BookmarkPayload(nbt.getString("linkType"), null);
|
||||
|
||||
if (nbt.hasKey("item")) {
|
||||
payload.target = nbt.getCompoundTag("item");
|
||||
}
|
||||
|
||||
if (nbt.hasKey("group")) {
|
||||
payload.group = nbt.getCompoundTag("group");
|
||||
}
|
||||
|
||||
payload.items = nbt.getTagList("items", 10);
|
||||
payload.recipes = nbt.getTagList("recipes", 10);
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
public static BookmarkPayload of(BookmarkItem item) {
|
||||
final BookmarkPayload payload = new BookmarkPayload("recipe", item.getItemStack());
|
||||
final BookmarkGrid grid = ItemPanels.bookmarkPanel.getGrid();
|
||||
final Map<RecipeId, Integer> recipesIndexes = new HashMap<>();
|
||||
final RecipeId recipeId = item.recipeId;
|
||||
final int groupId = item.groupId;
|
||||
|
||||
payload.items = new NBTTagList();
|
||||
payload.recipes = new NBTTagList();
|
||||
|
||||
if (recipeId != null) {
|
||||
|
||||
for (int itemIndex = 0; itemIndex < grid.size(); itemIndex++) {
|
||||
final BookmarkItem currentItem = grid.getBookmarkItem(itemIndex);
|
||||
|
||||
if (currentItem != null && currentItem.groupId == groupId && recipeId.equals(currentItem.recipeId)) {
|
||||
addBookmarkItemToPayload(payload, currentItem, recipesIndexes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
addBookmarkItemToPayload(payload, item, recipesIndexes);
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
public static BookmarkPayload of(Recipe recipe) {
|
||||
final BookmarkPayload payload = new BookmarkPayload("recipe", recipe.getResult());
|
||||
final Map<RecipeId, Integer> recipesIndexes = new HashMap<>();
|
||||
final ItemStackSet seenIngredients = new ItemStackSet();
|
||||
final ItemStackSet seenResults = new ItemStackSet();
|
||||
|
||||
for (RecipeIngredient result : recipe.getResults()) {
|
||||
ItemStack stack = result.getItemStack();
|
||||
if (!seenResults.contains(stack)) {
|
||||
final BookmarkItem item = BookmarkItem.builder(-1, stack, recipe, BookmarkItemType.RESULT).build();
|
||||
addBookmarkItemToPayload(payload, item, recipesIndexes);
|
||||
seenResults.add(stack);
|
||||
}
|
||||
}
|
||||
|
||||
for (RecipeIngredient ingr : recipe.getIngredients()) {
|
||||
ItemStack stack = ingr.getItemStack();
|
||||
if (!seenIngredients.contains(stack)) {
|
||||
final BookmarkItem item = BookmarkItem.builder(-1, stack, recipe, BookmarkItemType.INGREDIENT).build();
|
||||
addBookmarkItemToPayload(payload, item, recipesIndexes);
|
||||
seenIngredients.add(stack);
|
||||
}
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
public static BookmarkPayload of(int groupId) {
|
||||
final BookmarkPayload payload = new BookmarkPayload("group", null);
|
||||
final Map<RecipeId, Integer> recipesIndexes = new HashMap<>();
|
||||
final BookmarkGrid grid = ItemPanels.bookmarkPanel.getGrid();
|
||||
|
||||
for (int itemIndex = 0; itemIndex < grid.size(); itemIndex++) {
|
||||
final BookmarkItem item = grid.getBookmarkItem(itemIndex);
|
||||
|
||||
if (item != null && item.groupId == groupId) {
|
||||
addBookmarkItemToPayload(payload, item, recipesIndexes);
|
||||
}
|
||||
}
|
||||
|
||||
payload.group = generateGroup(grid.getGroup(groupId));
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
public static BookmarkPayload of(ItemStack stackover, RecipeId recipeId) {
|
||||
final BookmarkPayload payload = new BookmarkPayload("item", stackover);
|
||||
final Map<RecipeId, Integer> recipesIndexes = new HashMap<>();
|
||||
final Point mousePos = GuiDraw.getMousePosition();
|
||||
|
||||
if (ItemPanels.itemPanel.containsWithSubpanels(mousePos.x, mousePos.y)) {
|
||||
stackover = ItemQuantityField.prepareStackWithQuantity(stackover, 0);
|
||||
}
|
||||
|
||||
final BookmarkItem item = BookmarkItem.builder(-1, stackover).recipeId(recipeId).type(BookmarkItemType.ITEM)
|
||||
.build();
|
||||
|
||||
addBookmarkItemToPayload(payload, item, recipesIndexes);
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
private static NBTTagCompound generateGroup(BookmarkGroup group) {
|
||||
final NBTTagCompound groupTag = new NBTTagCompound();
|
||||
final NBTTagList collapsedRecipes = new NBTTagList();
|
||||
|
||||
groupTag.setString("viewmode", group.viewMode.toString());
|
||||
groupTag.setBoolean("crafting", group.crafting != null);
|
||||
groupTag.setBoolean("collapsed", group.collapsed);
|
||||
|
||||
for (RecipeId recipeId : group.collapsedRecipes) {
|
||||
collapsedRecipes.appendTag(NBTJson.toNbt(recipeId.toJsonObject()));
|
||||
}
|
||||
|
||||
groupTag.setTag("collapsedRecipes", collapsedRecipes);
|
||||
|
||||
return groupTag;
|
||||
}
|
||||
|
||||
private static void addBookmarkItemToPayload(BookmarkPayload payload, BookmarkItem item,
|
||||
Map<RecipeId, Integer> recipesIndexes) {
|
||||
final JsonObject itemTag = item.toJsonObject();
|
||||
itemTag.remove("groupId");
|
||||
|
||||
if (item.recipeId != null) {
|
||||
final int recipeIndex = recipesIndexes
|
||||
.computeIfAbsent(item.recipeId, recipeId -> addRecipeToPayload(payload, recipeId, recipesIndexes));
|
||||
itemTag.addProperty("recipeId", recipeIndex);
|
||||
}
|
||||
|
||||
payload.items.appendTag(NBTJson.toNbt(itemTag));
|
||||
}
|
||||
|
||||
private static int addRecipeToPayload(BookmarkPayload payload, RecipeId recipeId,
|
||||
Map<RecipeId, Integer> recipesIndexes) {
|
||||
final NBTTagCompound recipeTag = new NBTTagCompound();
|
||||
final int recipeIndex = payload.recipes.tagCount();
|
||||
|
||||
recipeTag.setTag("recipeId", NBTJson.toNbt(recipeId.toJsonObject()));
|
||||
recipeTag.setInteger("recipeIndex", recipeIndex);
|
||||
payload.recipes.appendTag(recipeTag);
|
||||
|
||||
return recipeIndex;
|
||||
}
|
||||
|
||||
public NBTTagCompound toNBT() {
|
||||
final NBTTagCompound payloadTag = new NBTTagCompound();
|
||||
payloadTag.setString("linkType", linkType);
|
||||
|
||||
if (target != null) {
|
||||
payloadTag.setTag("item", target);
|
||||
}
|
||||
|
||||
if (group != null) {
|
||||
payloadTag.setTag("group", group);
|
||||
}
|
||||
|
||||
payloadTag.setTag("items", items);
|
||||
payloadTag.setTag("recipes", recipes);
|
||||
|
||||
return payloadTag;
|
||||
}
|
||||
|
||||
public String getLinkType() {
|
||||
return this.linkType;
|
||||
}
|
||||
|
||||
public ItemStack getTargetStack() {
|
||||
return this.target != null ? StackInfo.loadFromNBT(this.target) : null;
|
||||
}
|
||||
|
||||
public BookmarkGroup getGroup() {
|
||||
if (this.group == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final boolean crafting = this.group.hasKey("crafting") && this.group.getBoolean("crafting");
|
||||
final BookmarkViewMode viewMode;
|
||||
|
||||
if (this.group.hasKey("viewmode")) {
|
||||
viewMode = BookmarkViewMode.valueOf(this.group.getString("viewmode"));
|
||||
} else {
|
||||
viewMode = BookmarkViewMode.TODO_LIST;
|
||||
}
|
||||
|
||||
final BookmarkGroup group = new BookmarkGroup(viewMode, crafting);
|
||||
|
||||
if (this.group.hasKey("collapsed")) {
|
||||
group.collapsed = this.group.getBoolean("collapsed");
|
||||
}
|
||||
|
||||
if (this.group.hasKey("collapsedRecipes")) {
|
||||
final NBTTagList collapsedRecipes = this.group.getTagList("collapsedRecipes", 10);
|
||||
|
||||
for (int i = 0; i < collapsedRecipes.tagCount(); i++) {
|
||||
final NBTTagCompound recipeTag = collapsedRecipes.getCompoundTagAt(i);
|
||||
final RecipeId recipeId = RecipeId.of((JsonObject) NBTJson.toJsonObject(recipeTag));
|
||||
group.collapsedRecipes.add(recipeId);
|
||||
}
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
public List<BookmarkItem> getBookmarkItems(int groupId) {
|
||||
final List<BookmarkItem> bookmarkItems = new ArrayList<>();
|
||||
final Map<Integer, RecipeId> recipesMap = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < recipes.tagCount(); i++) {
|
||||
final NBTTagCompound recipeTag = recipes.getCompoundTagAt(i);
|
||||
final RecipeId recipeId = RecipeId
|
||||
.of((JsonObject) NBTJson.toJsonObject(recipeTag.getCompoundTag("recipeId")));
|
||||
recipesMap.put(recipeTag.getInteger("recipeIndex"), recipeId);
|
||||
}
|
||||
|
||||
for (int i = 0; i < items.tagCount(); i++) {
|
||||
final NBTTagCompound itemTag = items.getCompoundTagAt(i);
|
||||
RecipeId recipeId = null;
|
||||
|
||||
if (itemTag.hasKey("recipeId")) {
|
||||
recipeId = recipesMap.get(itemTag.getInteger("recipeId"));
|
||||
itemTag.removeTag("recipeId");
|
||||
}
|
||||
|
||||
final BookmarkItem item = BookmarkItem.of((JsonObject) NBTJson.toJsonObject(itemTag));
|
||||
|
||||
if (item != null) {
|
||||
item.groupId = groupId;
|
||||
item.recipeId = recipeId;
|
||||
bookmarkItems.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
return bookmarkItems;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
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.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);
|
||||
boolean wasError = false;
|
||||
|
||||
if (NEIClientConfig.world.nbt.hasKey("bookmark")) {
|
||||
navigation = NEIClientConfig.world.nbt.getCompoundTag("bookmark");
|
||||
}
|
||||
|
||||
for (String itemStr : itemStrings) {
|
||||
|
||||
try {
|
||||
|
||||
if (itemStr.isEmpty()) {
|
||||
itemStr = "; {}";
|
||||
}
|
||||
|
||||
if (itemStr.startsWith("; ")) {
|
||||
|
||||
if (grid.size() > 0) {
|
||||
// do not create empty namespaces
|
||||
grid = new BookmarkGrid();
|
||||
|
||||
if (navigation.hasKey("namespacePage." + namespaces.size())) {
|
||||
grid.setPage(navigation.getInteger("namespacePage." + namespaces.size()));
|
||||
}
|
||||
|
||||
namespaces.add(grid);
|
||||
}
|
||||
|
||||
final JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
final BookmarkItem item = BookmarkItem.of(parser.parse(itemStr).getAsJsonObject());
|
||||
|
||||
if (item != null) {
|
||||
grid.addItem(item, false);
|
||||
} else {
|
||||
wasError = true;
|
||||
NEIClientConfig.logger.warn(
|
||||
"Failed to load bookmarked ItemStack from json string, the item no longer exists:\n{}",
|
||||
itemStr);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
wasError = true;
|
||||
NEIClientConfig.logger.error("Failed to load bookmarked ItemStack from json string:\n{}", itemStr);
|
||||
}
|
||||
}
|
||||
|
||||
if (wasError) {
|
||||
try {
|
||||
Files.copy(
|
||||
bookmarkFile,
|
||||
new File(bookmarkFile.getAbsolutePath() + ".backup-" + System.currentTimeMillis()));
|
||||
NEIClientConfig.logger.info("Backed up invalid bookmark file to {}", bookmarkFile);
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to backup invalid bookmark file to {}", bookmarkFile, e);
|
||||
}
|
||||
}
|
||||
|
||||
for (BookmarkGrid gr : namespaces) {
|
||||
gr.onItemsChanged();
|
||||
}
|
||||
|
||||
this.namespaces = namespaces;
|
||||
|
||||
if (navigation.hasKey("namespaceIndex")) {
|
||||
setNamespace(navigation.getInteger("namespaceIndex"));
|
||||
} else {
|
||||
setNamespace(0);
|
||||
}
|
||||
|
||||
this.bookmarkFile = bookmarkFile;
|
||||
}
|
||||
|
||||
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 {
|
||||
strings.add(NBTJson.toJson(item.toJsonObject()));
|
||||
} 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,394 @@
|
||||
package codechicken.nei.bookmark;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
|
||||
import codechicken.nei.ItemPanels;
|
||||
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.PositionedStack;
|
||||
import codechicken.nei.bookmark.BookmarkGrid.BookmarkMouseContext;
|
||||
import codechicken.nei.bookmark.BookmarkItem.BookmarkItemType;
|
||||
import codechicken.nei.bookmark.RecipeChainDetails.CalculatedType;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.recipe.GuiRecipeTab;
|
||||
import codechicken.nei.recipe.HandlerInfo;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.util.ReadableNumberConverter;
|
||||
|
||||
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 HandlerInfo handlerInfo = null;
|
||||
|
||||
protected final boolean isOutputRecipe;
|
||||
protected final boolean isFirstOutput;
|
||||
protected final int rowIndex;
|
||||
|
||||
public BookmarksGridSlot(int slotIndex, int itemIndex, long realMultiplier, long shiftAmount,
|
||||
long calculatedMultiplier, BookmarkItem bookmarkItem, CalculatedType calculatedType, BookmarkGroup group) {
|
||||
super(
|
||||
slotIndex,
|
||||
itemIndex,
|
||||
calculatedType != null ? bookmarkItem.getItemStack(bookmarkItem.getAmount(calculatedMultiplier))
|
||||
: bookmarkItem.getItemStack(bookmarkItem.getAmount(realMultiplier)));
|
||||
|
||||
this.emptyItemStack = bookmarkItem.getItemStack(0);
|
||||
this.realAmount = bookmarkItem.getAmount(realMultiplier);
|
||||
this.shiftAmount = shiftAmount;
|
||||
this.calculatedAmount = calculatedType != null ? bookmarkItem.getAmount(calculatedMultiplier) : this.realAmount;
|
||||
|
||||
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 = realMultiplier;
|
||||
this.calculatedMultiplier = calculatedMultiplier;
|
||||
|
||||
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.type == BookmarkItemType.INGREDIENT
|
||||
|| 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.type == BookmarkItemType.RESULT
|
||||
&& ((this.slotIndex % grid.getColumns()) == 0 || group.viewMode == BookmarkViewMode.DEFAULT)
|
||||
&& (prevItem == null || prevItem.type == BookmarkItemType.INGREDIENT
|
||||
|| !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 BookmarkItemType getType() {
|
||||
return this.bookmarkItem.type;
|
||||
}
|
||||
|
||||
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.slotIndex == mouseContext.slotIndex || this.group.crafting != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.bookmarkItem.type == BookmarkItemType.ITEM && this.group.viewMode == BookmarkViewMode.TODO_LIST
|
||||
&& mouseContext.rowIndex == this.rowIndex) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.bookmarkItem.type != BookmarkItemType.ITEM
|
||||
&& this.bookmarkItem.equalsRecipe(mouseContext.recipeId, mouseContext.groupId);
|
||||
}
|
||||
|
||||
protected boolean showRealItem(BookmarkMouseContext mouseContext) {
|
||||
|
||||
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.type != BookmarkItemType.ITEM
|
||||
&& 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));
|
||||
}
|
||||
|
||||
protected HandlerInfo getHandlerInfo() {
|
||||
if (this.bookmarkItem.recipeId != null && this.handlerInfo == null) {
|
||||
this.handlerInfo = GuiRecipeTab.getHandlerInfo(this.bookmarkItem.recipeId.getHandlerName(), null);
|
||||
}
|
||||
return this.handlerInfo;
|
||||
}
|
||||
|
||||
@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.type != BookmarkItemType.INGREDIENT && 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.type == BookmarkItemType.INGREDIENT || this.bookmarkItem.recipeId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isFirstOutput) {
|
||||
if (shownItemType == ShownItemType.REAL) {
|
||||
drawMarker(
|
||||
rect,
|
||||
"x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(this.realMultiplier),
|
||||
0xFFFFFF,
|
||||
Alignment.TopLeft);
|
||||
} else if (shownItemType == ShownItemType.SHIFT) {
|
||||
drawMarker(
|
||||
rect,
|
||||
"x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(getMultiplier()),
|
||||
0xFFFFFF,
|
||||
Alignment.TopLeft);
|
||||
} else if (this.isOutputRecipe || this.realMultiplier > 1) {
|
||||
drawMarker(
|
||||
rect,
|
||||
"x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(this.realMultiplier),
|
||||
NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue(),
|
||||
Alignment.TopLeft);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isFirstOutput || NEIClientConfig.showRecipeMarkerMode() == 1) {
|
||||
drawRecipeMarker(rect);
|
||||
}
|
||||
}
|
||||
|
||||
protected void drawRecipeMarker(Rectangle4i rect) {
|
||||
if (NEIClientConfig.getBooleanSetting("inventory.bookmarks.showRecipeHandlerIcon")
|
||||
&& getHandlerInfo() != null) {
|
||||
drawHandlerIcon(rect);
|
||||
} else if (NEIClientConfig.showRecipeMarkerMode() == 1) {
|
||||
drawMarker(
|
||||
rect,
|
||||
"R",
|
||||
NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue(),
|
||||
Alignment.TopRight);
|
||||
}
|
||||
}
|
||||
|
||||
protected void drawHandlerIcon(Rectangle4i rect) {
|
||||
float panelFactor = 1;
|
||||
|
||||
if (rect.w != DEFAULT_SLOT_SIZE) {
|
||||
panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
|
||||
}
|
||||
|
||||
panelFactor *= 0.4f;
|
||||
float x = rect.x + 2 + 16 - 16 * panelFactor;
|
||||
|
||||
GL11.glTranslatef(x, rect.y, 0);
|
||||
GL11.glScaled(panelFactor, panelFactor, 1.5f);
|
||||
|
||||
if (this.handlerInfo.getImage() != null) {
|
||||
this.handlerInfo.getImage().draw(0, 0);
|
||||
} else {
|
||||
GuiContainerManager.drawItem(0, 0, this.handlerInfo.getItemStack(), true, "");
|
||||
}
|
||||
|
||||
GL11.glScaled(1f / panelFactor, 1f / panelFactor, 1f / 1.5f);
|
||||
GL11.glTranslatef(-1 * x, -1 * rect.y, 0);
|
||||
}
|
||||
|
||||
protected void drawMarker(Rectangle4i rect, String text, int color, Alignment alignment) {
|
||||
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
|
||||
NEIClientUtils.drawNEIOverlayText(
|
||||
text,
|
||||
new Rectangle4i(rect.x + 1, rect.y + 1, rect.w - 2, rect.h - 2),
|
||||
panelFactor,
|
||||
color,
|
||||
true,
|
||||
alignment);
|
||||
}
|
||||
|
||||
protected void drawStackSize(Rectangle4i rect, ShownItemType shownItemType) {
|
||||
boolean drawChance = this.calculatedMultiplier > 0;
|
||||
long amount = this.calculatedAmount;
|
||||
|
||||
if (shownItemType == null || shownItemType == ShownItemType.REAL || this.calculatedType == null) {
|
||||
amount = this.realAmount;
|
||||
drawChance = this.realMultiplier > 0;
|
||||
} else if (shownItemType == ShownItemType.SHIFT) {
|
||||
amount = this.shiftAmount;
|
||||
drawChance = false;
|
||||
}
|
||||
|
||||
if (amount > 0 || this.bookmarkItem.chance != PositionedStack.CHANCE_FULL && drawChance
|
||||
|| shownItemType == ShownItemType.REAL && !this.bookmarkItem.emptyFactor()) {
|
||||
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
|
||||
final long stackSize = this.bookmarkItem.getStackSize(amount);
|
||||
int color = 0xFFFFFF;
|
||||
String amountString = "";
|
||||
|
||||
if (stackSize < 10_000) {
|
||||
amountString = String.valueOf(stackSize);
|
||||
} else {
|
||||
amountString = ReadableNumberConverter.INSTANCE.toWideReadableForm(stackSize);
|
||||
}
|
||||
|
||||
if (this.isFluidDisplay) {
|
||||
amountString += "L";
|
||||
}
|
||||
|
||||
if (this.bookmarkItem.chance != PositionedStack.CHANCE_FULL) {
|
||||
amountString = "~" + amountString;
|
||||
color = 0xFFAA00;
|
||||
}
|
||||
|
||||
NEIClientUtils.drawNEIOverlayText(
|
||||
amountString,
|
||||
new Rectangle4i(rect.x + 1, rect.y + 1, rect.w - 2, rect.h - 2),
|
||||
panelFactor,
|
||||
color,
|
||||
true,
|
||||
this.isFluidDisplay ? Alignment.BottomLeft : Alignment.BottomRight);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
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.bookmark.BookmarkItem.BookmarkItemType;
|
||||
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 && item.type != BookmarkItemType.ITEM) {
|
||||
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
|
||||
|| rItem.type != BookmarkItemType.ITEM && 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 && item.type != BookmarkItemType.ITEM) {
|
||||
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
|
||||
|| rItem.type != BookmarkItemType.ITEM && recipeRelations.contains(rItem.recipeId))) {
|
||||
return this.grid.getAbsoluteSlotIndex(rItemIndex) / this.grid.getColumns();
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rowShift + overRowIndex;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,381 @@
|
||||
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.bookmark.BookmarkItem.BookmarkItemType;
|
||||
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 realMultiplier = 0L;
|
||||
private long shiftAmount = 0L;
|
||||
private long calculatedMultiplier = 0L;
|
||||
|
||||
public CalculatedType calculatedType;
|
||||
|
||||
protected BookmarkChainItem(BookmarkItem item, long shiftItem, long calculatedMultiplier,
|
||||
CalculatedType calculatedType) {
|
||||
this.item = item.copy();
|
||||
this.shiftAmount = shiftItem;
|
||||
this.calculatedMultiplier = calculatedMultiplier;
|
||||
this.calculatedType = calculatedType;
|
||||
}
|
||||
|
||||
public static BookmarkChainItem of(BookmarkItem item, long shiftItem, long calculatedMultiplier,
|
||||
CalculatedType calculatedType) {
|
||||
return new BookmarkChainItem(item, shiftItem, calculatedMultiplier, calculatedType);
|
||||
}
|
||||
|
||||
public static BookmarkChainItem of(BookmarkItem item, long shiftItem, CalculatedType calculatedType) {
|
||||
return new BookmarkChainItem(item, shiftItem, item.getMultiplier(), calculatedType);
|
||||
}
|
||||
|
||||
public static BookmarkChainItem of(BookmarkItem item) {
|
||||
final long amount = item.getAmount();
|
||||
return new BookmarkChainItem(
|
||||
item,
|
||||
amount,
|
||||
item.getMultiplier(),
|
||||
item.type == BookmarkItemType.INGREDIENT ? CalculatedType.INGREDIENT : CalculatedType.RESULT);
|
||||
}
|
||||
|
||||
public ItemStack getItemStack(long amount) {
|
||||
return this.item.getItemStack(amount);
|
||||
}
|
||||
|
||||
public void setRealMultiplier(long multiplier) {
|
||||
this.realMultiplier = multiplier;
|
||||
}
|
||||
|
||||
public long getRealMultiplier() {
|
||||
return this.realMultiplier;
|
||||
}
|
||||
|
||||
public void setCalculatedMultiplier(long multiplier) {
|
||||
this.calculatedMultiplier = multiplier;
|
||||
}
|
||||
|
||||
public long getCalculatedMultiplier() {
|
||||
return this.calculatedMultiplier;
|
||||
}
|
||||
|
||||
public long getShiftAmount() {
|
||||
return this.shiftAmount;
|
||||
}
|
||||
|
||||
public BookmarkItem getItem() {
|
||||
return this.item;
|
||||
}
|
||||
|
||||
public void append(long amount, long calculatedAmount) {
|
||||
this.shiftAmount += amount;
|
||||
this.calculatedMultiplier += this.item.getMultiplierFromAmount(calculatedAmount);
|
||||
this.item.multiplier = this.calculatedMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
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).setRealMultiplier(Math.max(0, item.getMultiplier() - 1));
|
||||
} else {
|
||||
this.calculatedItems.get(itemIndex).setRealMultiplier(item.getMultiplier());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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().type == BookmarkItemType.INGREDIENT || !recipeId.equals(value.getItem().recipeId)) {
|
||||
itemIndex *= -1;
|
||||
}
|
||||
|
||||
if (value.getItem().type == BookmarkItemType.RESULT
|
||||
&& !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.copyWithMultiplier(recipeId.equals(item.recipeId) ? item.multiplier : 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().type == BookmarkItemType.INGREDIENT || !recipeId.equals(value.getItem().recipeId)) {
|
||||
itemIndex *= -1;
|
||||
}
|
||||
|
||||
if (this.calculatedItems.containsKey(itemIndex)) {
|
||||
this.calculatedItems.get(itemIndex)
|
||||
.setRealMultiplier(value.getItem().getMultiplierFromAmount(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.getAmount() - 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.getAmount());
|
||||
} else if (amount > 0) {
|
||||
items.computeIfAbsent(
|
||||
StackInfo.getItemStackGUID(item.itemStack),
|
||||
is -> BookmarkChainItem.of(item, 0, 0, CalculatedType.RESULT))
|
||||
.append(amount, item.getAmount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.getAmount());
|
||||
final long refAmount = prefItem != null && !topLevelRecipes.contains(prefItem.recipeId)
|
||||
? math.requiredAmount.getOrDefault(prefItem, 0L)
|
||||
: 0;
|
||||
|
||||
if (amount != 0 || item.getAmount() > 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.getAmount() - refAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<>(items.values());
|
||||
}
|
||||
|
||||
private void generateResult(RecipeChainMath math, BookmarkItem item, int itemIndex) {
|
||||
final long amount = item.getAmount() - 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.getAmount());
|
||||
|
||||
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))
|
||||
.map(entry -> entry.getKey().recipeId).collect(Collectors.toSet());
|
||||
|
||||
if (recipeIds.isEmpty()) {
|
||||
parents.add(recipeId);
|
||||
} else {
|
||||
|
||||
for (RecipeId ingrRecipeId : recipeIds) {
|
||||
if (visited.add(ingrRecipeId)) {
|
||||
if (math.outputRecipes.containsKey(ingrRecipeId)) {
|
||||
parents.add(ingrRecipeId);
|
||||
} else {
|
||||
getRecipeParents(math, ingrRecipeId, parents, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return parents;
|
||||
}
|
||||
|
||||
}
|
||||
Loaded 100 of 244 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user