Compare commits

...
77 Commits
Author SHA1 Message Date
Dream Master b49d066231 update 2025-08-08 19:05:06 +07:00
slprime 594fbe6f79 Allowed fill crafting grid without all ingredients (#693) 2025-08-06 13:40:52 -04:00
koolkrafter5andEthryan 3edb85b317 Allow handlers to hide the favorite and overlay buttons via IMC (#678)
Co-authored-by: Ethryan <[email protected]>
2025-07-29 20:37:37 +07:00
TotallyNotOndre 5fd0a74363 Add ability to bookmark linked items (#674) 2025-07-26 07:42:34 +07:00
Dream Master 2ae94e94a0 update 2025-07-17 22:31:09 +07:00
TotallyNotOndre fa3adde3e6 Add ability to link Item in chat (#673) 2025-07-17 10:09:43 +07:00
slprime 56941cc45d Correctly used tools in favorites (#670) 2025-07-12 07:44:34 +02:00
slprimeandCaedis cd7d014704 Bookmarks Chains: Use active Item as preferred if exists (#664)
Co-authored-by: Caedis <[email protected]>
2025-07-11 14:36:10 +00:00
slprime 0634466851 Bookmarks Chains: Optimize GTTools (#667) 2025-07-11 14:33:14 +00:00
slprimeandCaedis b87e389132 Bookmarks Hotkeys: optimization thaumcraft recipes (#663)
Co-authored-by: Caedis <[email protected]>
2025-07-11 14:25:15 +00:00
slprimeandCaedis c788a07cf5 Bookmarks Chains Math: fix infinity loop (#662)
Co-authored-by: Caedis <[email protected]>
2025-07-11 16:21:32 +02:00
Martin Robertz 7d4ed91e86 update 2025-07-09 14:43:40 +02:00
slprime ca79cdd3c9 Disable play sound when crafting with gt tools (#659) 2025-07-08 15:41:42 +02:00
slprime 3a0722adc2 Update Bookmark Chain Tooltip Cache (#657) 2025-07-01 05:52:46 -05:00
slprime 77fa3bafd6 Autocrafting Improvement (#655) 2025-06-27 08:32:54 -05:00
Martin Robertz e23e542aac update 2025-06-22 18:27:06 +02:00
slprime 7ec2ad132e Tools in autocrafting (#653) 2025-06-22 17:49:20 +02:00
slprime 7b43826d05 Clear Crafting Grid after autocrafting (#652) 2025-06-20 09:25:02 -05:00
slprime c7a18dd288 Fix Item Tooltip (#651) 2025-06-19 16:22:12 +00:00
slprime 4fb1d7b1d8 Add Autocrafting Option (#649) 2025-06-16 23:30:10 +02:00
AlexdoruandMartin Robertz 081071562f Fix WorldClient leak in ItemModSpawner and ClientHandler (#637)
Co-authored-by: Martin Robertz <[email protected]>
2025-06-15 12:09:55 +02:00
Martin Robertz 81e05dc030 update 2025-06-14 00:08:03 +02:00
slprime efc54fb662 Add Translation to Item Count Details (#647) 2025-06-13 23:46:32 +02:00
slprime 6e75124ea2 Set Minimum Zoom Size (#648) 2025-06-13 23:46:22 +02:00
slprime 2c9f17983a Fix Paged Tooltip with Line Handler (#645) 2025-06-13 23:46:05 +02:00
slprime e0b6d62143 Add Bookmark items with recipe Option (#644) 2025-06-13 23:45:50 +02:00
Martin Robertz 3d5e9aecf0 update 2025-06-08 11:59:07 +02:00
FalsePattern 07cec30f3e allow setOverrideName to remove name overrides (#643) 2025-06-06 14:11:33 +00:00
koolkrafter5 f3add01e74 Too Many (Hidden) Items (#641) 2025-06-03 08:26:44 +02:00
Maya d469fdc90d update 2025-06-01 18:05:04 -06:00
abel1502 763d9b8cd4 Fix Incorrect handleDragNDrop Implementation (#639) 2025-06-01 18:04:55 -06:00
Jason Mitchell 55ccb70c8b Update JarJar detection so it works when jarjar is loaded but rfb is not setup properly. (#636) 2025-05-26 16:49:52 -04:00
2e1c7764b7 Ignore prefix when SearchMode is ALWAYS (#635)
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: Maya <[email protected]>
2025-05-26 15:55:37 +00:00
Martin Robertz 9daa9cabb2 update 2025-05-26 08:46:40 +02:00
Jason Mitchell 74dc7c34d9 Don't exclude locals/frames when transforming. (#632) 2025-05-18 17:50:06 -05:00
slprimeandslprime e5f85e32ec Add Settings: Dynamic Font Size (#631)
Co-authored-by: slprime <[email protected]>
2025-05-18 11:18:12 -05:00
Maya 5383e0891a update 2025-05-13 19:14:13 -05:00
slprimeandslprime 6142d4cc6d Subset: Memory Optimization (#626)
Co-authored-by: slprime <[email protected]>
2025-05-13 19:13:17 -05:00
Maya 6aa6b2e6d2 update 2025-05-12 09:46:11 -05:00
koolkrafter5andMaya 29ade6f327 Make the "Accepts following:" tooltip work for otherStacks (#625)
Co-authored-by: Maya <[email protected]>
2025-05-12 14:45:57 +00:00
slprimeandslprime 5ad6095c43 Filtering the input in the ItemQuantityField (#623)
Co-authored-by: slprime <[email protected]>
2025-05-12 09:40:42 -05:00
Martin Robertz 8ae3304861 update 2025-04-25 13:38:04 +02:00
0dc7bc1228 Create Favorites Widget; More hotkeys; More Tooltips; (#617)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Maya <[email protected]>
2025-04-24 17:48:40 +02:00
Maya 19d8b42993 update 2025-04-08 23:53:43 -05:00
Kogepan229 3b7eae67af Add AE2 Cell View handlers (#621) 2025-04-08 23:51:52 -05:00
Glease 64a747e4bd prevent empty pages from being produced (#615) 2025-03-25 15:06:45 +01:00
Martin Robertz 4f60928b61 update 2025-03-24 16:05:00 +01:00
8dba2ff4c1 Add option to adjust FPS rendering of items (#612)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
2025-03-24 15:01:41 +00:00
eb40e3b112 Add Hotkeys Widget Settings (#613)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
2025-03-24 15:48:11 +01:00
Martin Robertz 98c8981f05 update 2025-03-19 16:45:47 +01:00
Spacebuilder2020 1ed35c8357 Implement Forge Essentials Permission Checking (#611) 2025-03-18 08:15:30 -07:00
Martin Robertz 6249bab886 update 2025-03-14 19:04:03 +01:00
azodandThéo Jacquelin b525760dd3 feature: Overlays Settings GUI (Keep overlays through dimensions) (#610)
Signed-off-by: AzodFR <[email protected]>
Co-authored-by: Théo Jacquelin <[email protected]>
2025-03-13 17:48:25 +00:00
Jason Mitchell 83b4855f5e Use the updated ASMDataTable (with interfaces) when JarJar is present (#608) 2025-03-13 07:04:41 -07:00
Maya 75352caf11 update 2025-02-08 12:14:10 -06:00
475f5811f6 Add loadPluginsInParallel Option (#604)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Maya <[email protected]>
2025-02-08 18:11:17 +00:00
slprimeandslprime 7503e1dfcb Fix NC marker in recipe after fluid pattern terminal (#603)
Co-authored-by: slprime <[email protected]>
2025-02-08 12:08:36 -06:00
Martin Robertz 9d1f475941 update 2025-01-27 08:06:08 +01:00
slprimeandslprime ac50d1b27e Added hotkey utils methods (#599)
Co-authored-by: slprime <[email protected]>
2025-01-26 12:59:16 -06:00
Maya 48934d621f update 2025-01-25 13:17:03 -06:00
slprimeandslprime 0bbb889f39 Change Permutation Filter (#598)
Co-authored-by: slprime <[email protected]>
2025-01-25 13:16:28 -06:00
Martin Robertz af55a6b191 update
(cherry picked from commit bd7e8d05fa)
2025-01-21 17:55:50 +01:00
slprimeandslprime b3e1f23683 Restore Issue 583 (#593)
Co-authored-by: slprime <[email protected]>
2025-01-21 10:50:16 -06:00
slprimeandslprime 39578a4419 Update Render Cache after window resize (#592)
Co-authored-by: slprime <[email protected]>
2025-01-19 11:33:26 -06:00
e3574800c0 Subset Widget Improvement (#577)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: Caedis <[email protected]>
Co-authored-by: Maya <[email protected]>
2025-01-16 21:12:26 +01:00
Martin Robertz 5cd7556e6a update 2025-01-16 12:44:42 +01:00
80c2cba778 Created Grid Rendering Cache Mode (#573)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: Caedis <[email protected]>
2025-01-15 23:23:16 -06:00
Glease 31173a1fbd fix memory leak fixes not working for MP (#590)
#258 addresses the memory leak in ItemMobSpawner. Unfortunately the clean up handler is not consistently called on every world unloaded. This PR fixes this issue by moving the call out of that if block
2025-01-10 17:11:52 +08:00
Caedis fd08a93554 Fix NPE in ItemsTooltipLineHandler (#589) 2025-01-10 10:42:23 +02:00
Martin Robertz 4dace1f6e5 update 2025-01-09 21:05:10 +01:00
0c0cf37eb0 Add 'Hide Item List Until Searching' option (#572)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: Maya <[email protected]>
2025-01-09 07:53:27 +00:00
Chris Stone 3ec4f8dd68 Add mod handlers for mods in Per Fabrica Ad Astra modpack (#587) 2025-01-08 12:30:34 -06:00
lailani-fandlailani-f e0dd6847cb Item List Sort: Ensure access to shared private field is atomic (#584)
Co-authored-by: lailani-f <>
2025-01-04 14:03:53 +00:00
slprimeandslprime 6374c162ba Fixed NEI reload when changing dimension (#583)
Co-authored-by: slprime <[email protected]>
2024-12-31 19:33:21 +01:00
8dd36f1c4a Add RenderTooltipEvent Compat (#574)
Co-authored-by: Martin Robertz <[email protected]>
Co-authored-by: Maya <[email protected]>
2024-12-28 23:00:02 -06:00
4613ade468 Change OptionIntegerField Width (#575)
Co-authored-by: slprime <[email protected]>
Co-authored-by: Maya <[email protected]>
2024-12-29 02:36:53 +00:00
ca7030df72 Add Space Mode Settings to Search (#571)
Co-authored-by: slprime <[email protected]>
Co-authored-by: boubou19 <[email protected]>
2024-12-23 10:21:28 +00:00
119 changed files with 11900 additions and 5436 deletions

No files matched your search

+5 -1
View File
@@ -1,6 +1,10 @@
// Add your dependencies here
dependencies {
api('com.github.GTNewHorizons:CodeChickenCore:1.4.0:dev')
api('com.github.GTNewHorizons:CodeChickenCore:1.4.5:dev')
implementation('com.github.GTNewHorizons:GTNHLib:0.6.38:dev')
shadowImplementation('org.apache.commons:commons-csv:1.10.0')
compileOnly 'maven.modrinth:forge-essentials:7.5.1'
}
+2 -2
View File
@@ -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.
@@ -151,7 +151,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.
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+2 -3
View File
@@ -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
@@ -206,7 +205,7 @@ 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.
+4
View File
@@ -1,4 +1,8 @@
// Add any additional repositiroes for your dependencies here
repositories {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ pluginManagement {
}
plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.30'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.41'
}
@@ -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
@@ -19,13 +19,14 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiErrorScreen;
import net.minecraft.client.gui.GuiMainMenu;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiSelectWorld;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.launchwrapper.Launch;
import net.minecraft.world.World;
import net.minecraftforge.client.event.GuiOpenEvent;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.WorldEvent;
@@ -46,6 +47,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 +61,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;
@@ -254,11 +257,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 +307,19 @@ public class ClientHandler {
if (mc.currentScreen == null) NEIController.processCreativeCycling(mc.thePlayer.inventory);
updateMagnetMode(mc.theWorld, mc.thePlayer);
} else {
lastworld = null;
}
}
GuiScreen gui = mc.currentScreen;
if (gui != lastGui) {
if (gui instanceof GuiMainMenu) lastworld = null;
else if (gui instanceof GuiSelectWorld) NEIClientConfig.reloadSaves();
else if (gui == null) {
/* prevent WorldClient reference being held in the Gui */
NEIController.manager = null;
}
@SubscribeEvent
public void onGuiScreen(GuiOpenEvent event) {
if (event.gui instanceof GuiSelectWorld) {
NEIClientConfig.reloadSaves();
} else if (event.gui == null) {
/* prevent WorldClient reference being held in the Gui */
NEIController.manager = null;
}
lastGui = gui;
}
@SubscribeEvent
@@ -311,24 +338,23 @@ 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);
if (!Minecraft.getMinecraft().isSingleplayer()) // wait for server to initiate in singleplayer
NEIClientConfig.loadWorld("remote/" + ClientUtils.getServerIP().replace(':', '~'));
ItemMobSpawner.clearEntityReferences(world);
}
lastworld = world;
}
}
@@ -145,24 +145,22 @@ public class CollapsibleItems {
return filter;
}
public static void updateCache(final List<ItemStack> items) {
public static void clearCache() {
CollapsibleItems.cache.clear();
}
try {
public static void putItem(ItemStack stack) {
int groupIndex = -1;
ItemList.forkJoinPool.submit(() -> items.parallelStream().forEach(stack -> {
GroupItem group = CollapsibleItems.groups.stream().filter(g -> g.matches(stack)).findFirst()
.orElse(null);
if (group != null) {
CollapsibleItems.cache.put(stack, CollapsibleItems.groups.indexOf(group));
}
})).get();
} catch (Exception e) {
NEIClientConfig.logger.error("Error create collapsible items groups", e);
for (int i = 0; i < CollapsibleItems.groups.size() && groupIndex == -1; i++) {
if (CollapsibleItems.groups.get(i).matches(stack)) {
groupIndex = i;
}
}
if (groupIndex != -1) {
CollapsibleItems.cache.put(stack, groupIndex);
}
}
public static int getGroupIndex(ItemStack stack) {
@@ -0,0 +1,251 @@
package codechicken.nei;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import org.apache.commons.io.IOUtils;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import codechicken.core.CommonUtils;
import codechicken.nei.api.API;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
public class FavoriteRecipes {
private static final Set<NBTTagCompound> tools = new HashSet<>();
private static final Map<NBTTagCompound, RecipeId> items = new HashMap<>();
private static final Map<String, RecipeId> fluids = new HashMap<>();
private static File favoriteFile;
static {
API.addSubset("Favorites", FavoriteRecipes::contains);
}
private FavoriteRecipes() {}
public static void load() {
String worldPath = "global";
if (NEIClientConfig.getBooleanSetting("inventory.favorites.worldSpecific")) {
worldPath = NEIClientConfig.getWorldPath();
}
final File dir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
if (!dir.exists()) {
dir.mkdirs();
}
favoriteFile = new File(dir, "favorites.ini");
if (!favoriteFile.exists()) {
final File globalFavorites = new File(CommonUtils.getMinecraftDir(), "saves/NEI/global/favorites.ini");
final File configFavorites = new File(NEIClientConfig.configDir, "favorites.ini");
final File defaultFavorites = configFavorites.exists() ? configFavorites : globalFavorites;
if (defaultFavorites.exists()) {
try {
if (favoriteFile.createNewFile()) {
InputStream src = new FileInputStream(defaultFavorites);
OutputStream dst = new FileOutputStream(favoriteFile);
IOUtils.copy(src, dst);
src.close();
dst.close();
}
} catch (IOException e) {}
}
}
loadData();
}
private static void loadData() {
if (favoriteFile == null || !favoriteFile.exists()) {
return;
}
List<String> itemStrings;
try (FileInputStream reader = new FileInputStream(favoriteFile)) {
NEIClientConfig.logger.info("Loading favorites from file {}", favoriteFile);
itemStrings = IOUtils.readLines(reader, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load favorites from file {}", favoriteFile, e);
return;
}
final JsonParser parser = new JsonParser();
items.clear();
for (String itemStr : itemStrings) {
if (itemStr.isEmpty() || itemStr.startsWith("#")) {
continue;
}
try {
JsonObject jsonObject = parser.parse(itemStr).getAsJsonObject();
if (jsonObject.get("item") != null && jsonObject.get("recipeId") != null) {
final NBTTagCompound itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject.get("item"));
final RecipeId recipeId = RecipeId.of(jsonObject.getAsJsonObject("recipeId"));
final ItemStack stack = StackInfo.loadFromNBT(itemStackNBT);
if (stack != null) {
final String fluidKey = getFluidKey(stack);
if (fluidKey != null) {
fluids.put(fluidKey, recipeId);
}
}
items.put(itemStackNBT, recipeId);
if (NEIServerUtils.isItemTool(stack)) {
tools.add(itemStackNBT);
}
}
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
NEIClientConfig.logger.error("Failed to load favorite from json string:\n{}", itemStr);
}
}
SubsetWidget.updateHiddenItems();
}
public static RecipeId getFavorite(ItemStack stack) {
if (NEIClientConfig.favoritesEnabled() && stack != null) {
RecipeId recipeId = items.get(StackInfo.itemStackToNBT(stack, false));
if (recipeId == null) {
recipeId = fluids.get(getFluidKey(stack));
}
if (recipeId != null) {
return recipeId;
}
if (NEIServerUtils.isItemTool(stack)
&& (stack.stackTagCompound == null || !stack.stackTagCompound.hasKey("GT.ToolStats"))) {
for (NBTTagCompound nbt : tools) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(stack, StackInfo.loadFromNBT(nbt))) {
return items.get(nbt);
}
}
}
}
return null;
}
public static ItemStack getFavorite(RecipeId recipeId) {
if (NEIClientConfig.favoritesEnabled()) {
final Optional<Map.Entry<NBTTagCompound, RecipeId>> result = items.entrySet().stream()
.filter(entry -> entry.getValue().equals(recipeId)).findAny();
if (result.isPresent()) {
return StackInfo.loadFromNBT(result.get().getKey());
}
}
return null;
}
public static boolean contains(ItemStack stack) {
return getFavorite(stack) != null;
}
public static void setFavorite(ItemStack stack, RecipeId recipeId) {
final NBTTagCompound itemStackNBT = StackInfo.itemStackToNBT(stack, false);
final String fluidKey = getFluidKey(stack);
items.entrySet().removeIf(entry -> entry.getKey().equals(itemStackNBT) || entry.getValue().equals(recipeId));
fluids.entrySet().removeIf(entry -> entry.getKey().equals(fluidKey) || entry.getValue().equals(recipeId));
if (recipeId != null) {
items.put(itemStackNBT, recipeId);
if (NEIServerUtils.isItemTool(stack)) {
tools.add(itemStackNBT);
}
if (fluidKey != null) {
fluids.put(fluidKey, recipeId);
}
}
SubsetWidget.updateHiddenItems();
ItemList.updateFilter.restart();
}
private static String getFluidKey(ItemStack stack) {
final FluidStack fluid = StackInfo.getFluid(stack);
if (fluid != null) {
return FluidRegistry.getFluidName(fluid);
}
return null;
}
public static void save() {
if (favoriteFile == null) {
return;
}
final List<String> strings = new ArrayList<>();
for (Map.Entry<NBTTagCompound, RecipeId> entry : items.entrySet()) {
try {
final JsonObject line = new JsonObject();
line.add("item", NBTJson.toJsonObject(entry.getKey()));
line.add("recipeId", entry.getValue().toJsonObject());
strings.add(NBTJson.toJson(line));
} catch (JsonSyntaxException e) {
NEIClientConfig.logger.error("Failed to stringify favorites ItemStack to json string");
}
}
try (FileOutputStream output = new FileOutputStream(favoriteFile)) {
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Filed 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,10 @@ public class FormattedTextField extends GuiTextField {
this.formatter = formatter;
}
public void setPlaceholder(String placeholder) {
this.placeholder = placeholder;
}
@Override
public void updateCursorCounter() {
super.updateCursorCounter();
@@ -102,89 +108,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);
}
}
@@ -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,7 +25,8 @@ public class HeldItemHandler implements IContainerInputHandler, IContainerToolti
}
protected boolean contains(int mousex, int mousey) {
return NEIClientUtils.getHeldItem() != null
return NEIClientUtils.getHeldItem() != null && !ItemPanels.bookmarkPanel.inEditingState()
&& !AutoCraftingManager.processing()
&& (ItemPanels.bookmarkPanel.contains(mousex, mousey) || ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey));
}
@@ -94,17 +95,6 @@ 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) {
@@ -1,69 +1,111 @@
package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.drawRect;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.ItemsGrid.MouseContext;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.GuiUsageRecipe;
import codechicken.nei.recipe.StackInfo;
public class ItemHistoryPanel extends Widget {
public class ItemHistoryPanel extends Widget implements IContainerTooltipHandler {
protected int mouseDownSlot = -1;
protected ItemsGrid grid;
protected int mouseDownItemIndex = -1;
public ItemHistoryPanel() {
grid = new ItemsGrid();
protected ItemsGrid<ItemsGridSlot, MouseContext> grid = new ItemsGrid<>() {
protected List<ItemsGridSlot> gridMask;
@Override
protected void onGridChanged() {
this.gridMask = null;
super.onGridChanged();
}
@Override
public List<ItemsGridSlot> getMask() {
if (this.gridMask == null) {
this.gridMask = new ArrayList<>();
for (int slotIndex = 0; slotIndex < Math.min(size(), this.rows * this.columns); slotIndex++) {
this.gridMask.add(new ItemsGridSlot(slotIndex, slotIndex, getItem(slotIndex)));
}
}
return this.gridMask;
}
@Override
protected MouseContext getMouseContext(int mousex, int mousey) {
final ItemsGridSlot hovered = getSlotMouseOver(mousex, mousey);
if (hovered != null) {
return new MouseContext(
hovered.slotIndex,
hovered.slotIndex / this.columns,
hovered.slotIndex % this.columns);
}
return null;
}
};
public boolean isEmpty() {
return grid.isEmpty();
}
public void draw(int mousex, int mousey) {
if (NEIClientConfig.getIntSetting("inventory.history.splittingMode") == 0) {
drawRect(x, y, w, h, NEIClientConfig.getSetting("inventory.history.historyColor").getHexValue());
GuiDraw.drawRect(x, y, w, h, NEIClientConfig.getSetting("inventory.history.historyColor").getHexValue());
} else {
drawSplittingArea(x, y, w, h, NEIClientConfig.getSetting("inventory.history.historyColor").getHexValue());
}
grid.draw(mousex, mousey);
this.grid.draw(mousex, mousey);
}
public void update() {
grid.update();
this.grid.update();
}
public void addItem(ItemStack stack) {
if (stack != null) {
ItemStack is = StackInfo.loadFromNBT(StackInfo.itemStackToNBT(stack), 0);
grid.realItems.removeIf(historyStack -> StackInfo.equalItemAndNBT(historyStack, stack, true));
grid.realItems.add(0, is);
this.grid.realItems.removeIf(historyStack -> StackInfo.equalItemAndNBT(historyStack, stack, true));
this.grid.realItems.add(0, is);
if (grid.realItems.size() > (grid.rows * grid.columns)) {
grid.realItems.remove(grid.rows * grid.columns);
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);
this.grid.setGridSize(x, y + 4, w, h - 8);
this.grid.refresh(gui);
}
@Override
public ItemStack getStackMouseOver(int mousex, int mousey) {
ItemPanelSlot slot = getSlotMouseOver(mousex, mousey);
return slot == null ? null : slot.item;
final ItemsGridSlot slot = getSlotMouseOver(mousex, mousey);
return slot == null ? null : slot.getItemStack();
}
public ItemPanelSlot getSlotMouseOver(int mousex, int mousey) {
public ItemsGridSlot getSlotMouseOver(int mousex, int mousey) {
return grid.getSlotMouseOver(mousex, mousey);
}
@@ -104,15 +146,16 @@ public class ItemHistoryPanel extends Widget {
@Override
public void mouseDragged(int mousex, int mousey, int button, long heldTime) {
if (mouseDownSlot >= 0 && ItemPanels.itemPanel.draggedStack == null
if (this.mouseDownItemIndex >= 0 && ItemPanels.itemPanel.draggedStack == null
&& NEIClientUtils.getHeldItem() == null
&& NEIClientConfig.hasSMPCounterPart()) {
ItemPanelSlot mouseOverSlot = getSlotMouseOver(mousex, mousey);
final ItemsGridSlot mouseOverSlot = getSlotMouseOver(mousex, mousey);
if (mouseOverSlot == null || mouseOverSlot.slotIndex != mouseDownSlot || heldTime > 500) {
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(mouseDownSlot);
mouseDownSlot = -1;
if (mouseOverSlot == null || mouseOverSlot.itemIndex != this.mouseDownItemIndex || heldTime > 500) {
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(
this.grid.getItem(this.mouseDownItemIndex));
this.mouseDownItemIndex = -1;
}
}
@@ -122,17 +165,13 @@ public class ItemHistoryPanel extends Widget {
public boolean handleClick(int mousex, int mousey, int button) {
if (handleClickExt(mousex, mousey, button)) return true;
ItemPanelSlot hoverSlot = getSlotMouseOver(mousex, mousey);
final ItemsGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
if (hoverSlot != null) {
if (button == 2) {
if (hoverSlot.item != null) {
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(hoverSlot.slotIndex);
}
ItemPanels.itemPanel.draggedStack = getDraggedStackWithQuantity(hoverSlot.getItemStack());
} else {
mouseDownSlot = hoverSlot.slotIndex;
mouseDownItemIndex = hoverSlot.itemIndex;
}
return true;
@@ -141,46 +180,38 @@ public class ItemHistoryPanel extends Widget {
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(ItemStack itemStack) {
return ItemQuantityField.prepareStackWithQuantity(itemStack, 0);
}
protected ItemStack getDraggedStackWithQuantity(int mouseDownSlot) {
ItemStack stack = grid.getItem(mouseDownSlot);
public ItemStack getStackMouseOverWithQuantity(int mousex, int mousey) {
final ItemStack hoverSlot = getStackMouseOver(mousex, mousey);
return hoverSlot != null ? getDraggedStackWithQuantity(hoverSlot) : null;
}
if (stack != null) {
int amount = NEIClientConfig.showItemQuantityWidget() ? NEIClientConfig.getItemQuantity() : 0;
@Override
public void mouseUp(int mousex, int mousey, int button) {
final ItemsGridSlot hoverSlot = getSlotMouseOver(mousex, mousey);
if (amount == 0) {
amount = stack.getMaxStackSize();
if (hoverSlot != null && hoverSlot.itemIndex == this.mouseDownItemIndex
&& ItemPanels.itemPanel.draggedStack == null) {
if (NEIController.manager.window instanceof GuiRecipe || NEIClientUtils.shiftKey()
|| !NEIClientConfig.canCheatItem(hoverSlot.getItemStack())) {
if (button == 0) {
GuiCraftingRecipe.openRecipeGui("item", hoverSlot.getItemStack().copy());
} else if (button == 1) {
GuiUsageRecipe.openRecipeGui("item", hoverSlot.getItemStack().copy());
}
} else {
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.getItemStack()), button, -1);
}
return NEIServerUtils.copyStack(stack, amount);
}
return null;
this.mouseDownItemIndex = -1;
}
}
+82 -42
View File
@@ -2,15 +2,18 @@ package codechicken.nei;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import net.minecraft.client.Minecraft;
import net.minecraft.item.Item;
@@ -25,6 +28,7 @@ import codechicken.nei.ThreadOperationTimer.TimeoutException;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.search.TooltipFilter;
public class ItemList {
@@ -44,7 +48,7 @@ public class ItemList {
private static final HashSet<Item> erroredItems = new HashSet<>();
private static final HashSet<String> stackTraces = new HashSet<>();
private static final HashMap<ItemStack, Integer> ordering = new HashMap<>();
private static Map<ItemStack, Integer> ordering = new HashMap<>();
/**
* Unlike {@link LayoutManager#itemsLoaded}, this indicates whether item loading is actually finished or not.
*/
@@ -210,8 +214,7 @@ public class ItemList {
IIcon icon = item.getIconIndex(itemstack);
String name = getTooltip(itemstack);
String s = name + "@" + (icon == null ? 0 : icon.hashCode());
if (!damageIconSet.contains(s)) {
damageIconSet.add(s);
if (damageIconSet.add(s)) {
permutations.add(itemstack);
}
} catch (TimeoutException t) {
@@ -234,81 +237,116 @@ public class ItemList {
}
private void updateOrdering(List<ItemStack> items) {
ItemList.ordering.clear();
final Map<ItemStack, Integer> newOrdering = new HashMap<>();
ItemSorter.sort(items);
if (!CollapsibleItems.isEmpty()) {
HashMap<Integer, Integer> groups = new HashMap<>();
final HashMap<Integer, Integer> groups = new HashMap<>();
int orderIndex = 0;
for (ItemStack stack : items) {
final int groupIndex = CollapsibleItems.getGroupIndex(stack);
if (groupIndex == -1) {
ItemList.ordering.put(stack, orderIndex++);
newOrdering.put(stack, orderIndex++);
} else {
if (!groups.containsKey(groupIndex)) {
groups.put(groupIndex, orderIndex++);
}
ItemList.ordering.put(stack, groups.get(groupIndex));
newOrdering.put(stack, groups.get(groupIndex));
}
}
} else {
int orderIndex = 0;
for (ItemStack stack : items) {
ItemList.ordering.put(stack, orderIndex++);
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;
List<ItemStack> items = new LinkedList<>();
List<ItemStack> permutations = new LinkedList<>();
SearchField.searchParser.clearCache();
ItemSorter.instance.ordering.clear();
CollapsibleItems.clearCache();
TooltipFilter.clearCache();
List<ItemStack> items = new ArrayList<>();
ListMultimap<Item, ItemStack> itemMap = ArrayListMultimap.create();
ItemStackSet unique = new ItemStackSet();
timer.setLimit(NEIClientConfig.getItemLoadingTimeout());
for (Item item : (Iterable<Item>) Item.itemRegistry) {
if (interrupted()) return;
if (item == null || erroredItems.contains(item)) continue;
StreamSupport.stream(((Iterable<Item>) Item.itemRegistry).spliterator(), true).forEach(item -> {
if (item == null || item.delegate.name() == null || erroredItems.contains(item)) return;
try {
timer.reset(item);
permutations.clear();
permutations.addAll(ItemInfo.itemOverrides.get(item));
if (permutations.isEmpty()) {
item.getSubItems(item, null, permutations);
}
if (permutations.isEmpty()) {
damageSearch(item, permutations);
}
permutations.addAll(ItemInfo.itemVariants.get(item));
List<ItemStack> permutations = getPermutations(item);
timer.reset();
permutations = permutations.stream().filter(stack -> !ItemInfo.isHidden(stack))
.collect(Collectors.toCollection(ArrayList::new));
for (ItemStack stack : permutations) {
if (!unique.contains(stack)) {
items.addAll(permutations);
itemMap.putAll(item, permutations);
synchronized (unique) {
unique.add(stack);
}
synchronized (items) {
items.add(stack);
}
CollapsibleItems.putItem(stack);
TooltipFilter.getSearchTooltip(stack);
}
}
synchronized (itemMap) {
itemMap.putAll(item, permutations);
}
} catch (Throwable t) {
NEIServerConfig.logger.error("Removing item: " + item + " from list.", t);
NEIServerConfig.logger.error("Removing item: {} from list.", item, t);
erroredItems.add(item);
}
});
int index = 0;
for (Item item : (Iterable<Item>) Item.itemRegistry) {
for (ItemStack stack : itemMap.get(item)) {
ItemSorter.instance.ordering.put(stack, index++);
}
}
if (interrupted()) return;
@@ -317,10 +355,12 @@ public class ItemList {
for (ItemsLoadedCallback callback : loadCallbacks) callback.itemsLoaded();
if (interrupted()) return;
CollapsibleItems.updateCache(items);
updateOrdering(items);
updateOrdering(ItemList.items);
loadFinished = true;
SubsetWidget.updateHiddenItems();
ItemPanels.bookmarkPanel.load();
updateFilter.restart();
}
};
@@ -346,12 +386,9 @@ public class ItemList {
public static final RestartableTask updateFilter = new RestartableTask("NEI Item Filtering") {
private int compare(ItemStack o1, ItemStack o2) {
return Integer.compare(ItemList.ordering.get(o1), ItemList.ordering.get(o2));
}
@Override
public void execute() {
if (!loadFinished) return;
ItemFilter filter = getItemListFilter();
ArrayList<ItemStack> filtered;
@@ -368,8 +405,11 @@ public class ItemList {
}
if (interrupted()) return;
filtered.sort(this::compare);
filtered.sort(Comparator.comparingInt(ItemList.ordering::get));
if (interrupted()) return;
ItemPanel.updateItemList(filtered);
}
};
@@ -16,10 +16,14 @@ import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntityMobSpawner;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IIcon;
import net.minecraft.world.World;
import net.minecraftforge.client.MinecraftForgeClient;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class ItemMobSpawner extends ItemBlock {
private static final Map<Integer, EntityLiving> entityHashMap = new HashMap<>();
@@ -29,7 +33,6 @@ public class ItemMobSpawner extends ItemBlock {
public ItemMobSpawner() {
super(Blocks.mob_spawner);
hasSubtypes = true;
MinecraftForgeClient.registerItemRenderer(this, new SpawnerRenderer());
}
@@ -38,7 +41,6 @@ public class ItemMobSpawner extends ItemBlock {
* These are ASM translated from BlockMobSpawner
*/
public static int placedX;
public static int placedY;
public static int placedZ;
@@ -65,6 +67,7 @@ public class ItemMobSpawner extends ItemBlock {
return false;
}
@SideOnly(Side.CLIENT)
@Override
public void addInformation(ItemStack itemstack, EntityPlayer par2EntityPlayer, List<String> list, boolean par4) {
setDefaultTag(itemstack);
@@ -73,15 +76,17 @@ public class ItemMobSpawner extends ItemBlock {
meta = idPig;
}
Entity e = getEntity(meta);
list.add("\u00A7" + (e instanceof IMob ? "4" : "3") + IDtoNameMap.get(meta));
list.add(
(e instanceof IMob ? EnumChatFormatting.DARK_RED : EnumChatFormatting.DARK_AQUA)
+ IDtoNameMap.get(meta));
}
public static EntityLiving getEntity(int ID) {
EntityLiving e = entityHashMap.get(ID);
if (e == null) {
loadSpawners();
Class<?> clazz = EntityList.IDtoClassMapping.get(ID);
World world = NEIClientUtils.mc().theWorld;
loadSpawners(world);
Class<?> clazz = (Class<?>) EntityList.IDtoClassMapping.get(ID);
try {
e = (EntityLiving) clazz.getConstructor(new Class[] { World.class }).newInstance(world);
} catch (Throwable t) {
@@ -95,40 +100,31 @@ public class ItemMobSpawner extends ItemBlock {
return e;
}
public static void clearEntityReferences(World newWorld) {
entityHashMap.values().removeIf(e -> e.worldObj != newWorld);
public static void clearEntityReferences() {
entityHashMap.clear();
}
private void setDefaultTag(ItemStack itemstack) {
if (!IDtoNameMap.containsKey(itemstack.getItemDamage())) itemstack.setItemDamage(idPig);
}
public static void loadSpawners(World world) {
public static void loadSpawners() {
if (loaded) return;
loaded = true;
Map<Class<? extends Entity>, String> classToStringMapping = EntityList.classToStringMapping;
@SuppressWarnings("unchecked")
Map<Class<? extends Entity>, Integer> classToIDMapping = (Map<Class<? extends Entity>, Integer>) EntityList.classToIDMapping;
for (Class<? extends Entity> eclass : classToStringMapping.keySet()) {
if (!EntityLiving.class.isAssignableFrom(eclass)) continue;
try {
EntityLiving entityliving = (EntityLiving) eclass.getConstructor(new Class[] { World.class })
.newInstance(world);
entityliving.isChild();
int id = classToIDMapping.get(eclass);
String name = classToStringMapping.get(eclass);
for (Map.Entry<Class<? extends Entity>, String> entry : EntityList.classToStringMapping.entrySet()) {
final Class<? extends Entity> clazz = entry.getKey();
if (EntityLiving.class.isAssignableFrom(clazz)) {
Integer id = (Integer) EntityList.classToIDMapping.get(clazz);
if (id == null) continue;
String name = entry.getValue();
if (name == null) continue;
if (name.equals("EnderDragon")) continue;
IDtoNameMap.put(id, name);
if (name.equals("Pig")) idPig = id;
} catch (Throwable ignored) {}
if (clazz != EntityPig.class || name.equals("Pig")) {
IDtoNameMap.put(id, name);
}
}
}
IDtoNameMap.entrySet()
.removeIf(e -> getEntity(e.getKey()).getClass() == EntityPig.class && !e.getValue().equals("Pig"));
}
@Override
+69 -400
View File
@@ -1,27 +1,17 @@
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,288 +31,49 @@ public class ItemPanel extends PanelWidget {
return super.getStackMouseOver(mousex, mousey);
}
public Button more;
public Button less;
public ItemQuantityField quantity;
public ItemHistoryPanel historyPanel;
public ItemHistoryPanel historyPanel = new ItemHistoryPanel();
public Button toggleGroups;
public static class ItemPanelSlot {
@Deprecated
public static class ItemPanelSlot extends ItemsPanelGridSlot {
public ItemStack item;
public int slotIndex;
public ItemPanelSlot(int idx, ItemStack stack) {
slotIndex = idx;
item = stack;
@Deprecated
public ItemPanelSlot(int idx, ItemStack item) {
this(idx, 0, item);
}
@Deprecated
public ItemPanelSlot(int idx) {
this(idx, ItemPanels.itemPanel.getGrid().getItem(idx));
}
}
protected static class 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);
ItemPanels.itemPanel.getGrid().setItems(newItems);
ItemPanels.itemPanel.realItems = newItems;
}
@@ -345,48 +96,12 @@ public class ItemPanel extends PanelWidget {
}
};
more = new Button("+") {
@Override
public boolean onButtonPress(boolean rightclick) {
if (rightclick) return false;
int modifier = NEIClientUtils.controlKey() ? 64 : NEIClientUtils.shiftKey() ? 10 : 1;
int quantity = NEIClientConfig.getItemQuantity() + modifier;
if (quantity < 0) {
quantity = 0;
}
ItemPanels.itemPanel.quantity.setText(Integer.toString(quantity));
return true;
}
};
less = new Button("-") {
@Override
public boolean onButtonPress(boolean rightclick) {
if (rightclick) return false;
int modifier = NEIClientUtils.controlKey() ? -64 : NEIClientUtils.shiftKey() ? -10 : -1;
int quantity = NEIClientConfig.getItemQuantity() + modifier;
if (quantity < 0) {
quantity = 0;
}
ItemPanels.itemPanel.quantity.setText(Integer.toString(quantity));
return true;
}
};
quantity = new ItemQuantityField("quantity");
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() {
@@ -431,44 +146,21 @@ public class ItemPanel extends PanelWidget {
return 0;
}
final int BUTTON_SIZE = 20;
more.w = less.w = BUTTON_SIZE;
quantity.h = BUTTON_SIZE;
if (NEIClientConfig.isSearchWidgetCentered()) {
more.h = less.h = BUTTON_SIZE;
more.x = x + w - BUTTON_SIZE;
more.y = less.y = quantity.y = y + h - BUTTON_SIZE;
less.x = x;
quantity.x = x + BUTTON_SIZE + 2;
quantity.w = more.x - quantity.x - 2;
} else {
quantity.x = (int) (x + (w * 0.7)) + 3;
quantity.y = y + h - BUTTON_SIZE;
quantity.w = (int) ((w * 0.3) - BUTTON_SIZE - 1);
more.h = less.h = BUTTON_SIZE / 2;
more.y = y + h - (more.h * 2);
less.x = more.x = quantity.x + quantity.w;
less.y = more.y + more.h;
}
if (NEIClientConfig.showHistoryPanelWidget()) {
historyPanel.x = x;
historyPanel.w = w;
historyPanel.h = ItemsGrid.SLOT_SIZE * NEIClientConfig.getIntSetting("inventory.history.useRows");
historyPanel.h = 8 + ItemsGrid.SLOT_SIZE * NEIClientConfig.getIntSetting("inventory.history.useRows");
if (NEIClientConfig.showItemQuantityWidget() || !NEIClientConfig.isSearchWidgetCentered()) {
historyPanel.y = quantity.y - historyPanel.h - PanelWidget.PADDING;
return quantity.h + historyPanel.h + PanelWidget.PADDING * 2;
historyPanel.y = LayoutManager.quantity.y - historyPanel.h - PanelWidget.PADDING;
return LayoutManager.quantity.h + historyPanel.h + PanelWidget.PADDING * 2;
} else {
historyPanel.y = y + h - historyPanel.h;
return historyPanel.h + PanelWidget.PADDING;
}
}
return quantity.h + PanelWidget.PADDING;
return LayoutManager.quantity.h + PanelWidget.PADDING;
}
@Override
@@ -476,17 +168,11 @@ public class ItemPanel extends PanelWidget {
super.setVisible();
if (grid.getPerPage() > 0) {
if (NEIClientConfig.showItemQuantityWidget()) {
LayoutManager.addWidget(more);
LayoutManager.addWidget(less);
LayoutManager.addWidget(quantity);
}
if (!CollapsibleItems.isEmpty()) {
if (!CollapsibleItems.isEmpty() && !grid.isEmpty()) {
LayoutManager.addWidget(toggleGroups);
}
if (NEIClientConfig.showHistoryPanelWidget()) {
if (NEIClientConfig.showHistoryPanelWidget() && (!grid.isEmpty() || !historyPanel.isEmpty())) {
LayoutManager.addWidget(historyPanel);
}
}
@@ -498,51 +184,23 @@ public class ItemPanel extends PanelWidget {
historyPanel.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);
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);
}
}
@@ -551,23 +209,34 @@ public class ItemPanel extends PanelWidget {
@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(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
final ItemsPanelGridSlot hoverSlot = this.grid.getSlotMouseOver(mousex, mousey);
if (!this.grid.forceExpand && hoverSlot != null && hoverSlot.groupIndex >= 0 && hoverSlot.groupSize > 1) {
final String message = hoverSlot.extended ? "itempanel.collapsed.hint.collapse"
: "itempanel.collapsed.hint.expand";
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.ALT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate(message, hoverSlot.groupSize));
}
return hotkeys;
}
}
@@ -1,6 +1,11 @@
package codechicken.nei;
import static codechicken.nei.NEIClientUtils.translate;
import net.minecraft.client.Minecraft;
import net.minecraft.item.ItemStack;
import org.lwjgl.input.Keyboard;
import codechicken.nei.recipe.StackInfo;
public class ItemQuantityField extends TextField {
@@ -10,18 +15,84 @@ public class ItemQuantityField extends TextField {
field.setDisabledTextColour(0xFF303030);
}
public int intValue() {
return intValue(text());
@Override
protected void initInternalTextField() {
field = new FormattedTextField(Minecraft.getMinecraft().fontRenderer, 0, 0, 0, 0) {
{
setPlaceholder(NEIClientUtils.translate("itempanel.quantity.default"));
}
@Override
public String getText() {
String text = super.getText();
return !isFocused() && "0".equals(text) ? "" : text;
}
@Override
protected boolean beforeWrite(String text) {
if (text == null || text.isEmpty()) return true;
try {
return Integer.parseInt(text) >= 0;
} catch (NumberFormatException e) {
return false;
}
}
@Override
public boolean textboxKeyTyped(char keyChar, int keyID) {
if (!isFocused()) return false;
if (super.textboxKeyTyped(keyChar, keyID)) {
return true;
} else if (keyID == Keyboard.KEY_DOWN) {
setText(Integer.toString(Math.max(0, getInteger() - 1)));
return true;
} else if (keyID == Keyboard.KEY_UP) {
setText(Integer.toString(getInteger() + 1));
return true;
}
return false;
}
private int getInteger() {
try {
return Math.max(0, Integer.parseInt(text()));
} catch (NumberFormatException nfe) {
return 0;
}
}
};
field.setMaxStringLength(maxSearchLength);
field.setCursorPositionZero();
}
public int intValue(String s) {
private int getInteger() {
try {
return Math.max(0, Integer.parseInt(s));
return Math.max(0, Integer.parseInt(text()));
} catch (NumberFormatException nfe) {
return 0;
}
}
public static ItemStack prepareStackWithQuantity(ItemStack stack, long amount) {
if (stack == null) {
return null;
}
if (amount == 0) {
amount = NEIClientConfig.showItemQuantityWidget() ? NEIClientConfig.getItemQuantity() : 0;
if (amount == 0) {
amount = StackInfo.itemStackToNBT(stack).hasKey("gtFluidName") ? 144 : stack.getMaxStackSize();
}
}
return StackInfo.withAmount(stack, amount);
}
@Override
public void gainFocus() {
if (text().equals("0")) {
@@ -36,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;
}
+3 -14
View File
@@ -4,19 +4,19 @@ import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.StatCollector;
import codechicken.lib.config.ConfigTagParent;
import codechicken.nei.ItemList.ItemsLoadedCallback;
import codechicken.nei.api.API;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.config.GuiItemSorter;
import codechicken.nei.config.OptionOpenGui;
public class ItemSorter implements Comparator<ItemStack>, ItemsLoadedCallback {
public class ItemSorter implements Comparator<ItemStack> {
public static class SortEntry {
@@ -44,12 +44,10 @@ public class ItemSorter implements Comparator<ItemStack>, ItemsLoadedCallback {
public static final ItemSorter instance = new ItemSorter();
// optimisations
public HashMap<ItemStack, Integer> ordering = null;
public Map<ItemStack, Integer> ordering = new HashMap<>();
public static void sort(List<ItemStack> items) {
try {
// items = (ArrayList<ItemStack>)
// items.parallelStream().sorted(instance).collect(Collectors.toList());
items.sort(instance);
} catch (Exception e) {
NEIClientConfig.logger.error("Exception sorting item list", e);
@@ -65,14 +63,6 @@ public class ItemSorter implements Comparator<ItemStack>, ItemsLoadedCallback {
return 0;
}
@Override
public void itemsLoaded() {
HashMap<ItemStack, Integer> newMap = new HashMap<>();
int i = 0;
for (ItemStack stack : ItemList.items) newMap.put(stack, i++);
ordering = newMap;
}
public static SortEntry find(String name) {
for (SortEntry e : entries) if (e.name.equals(name)) return e;
@@ -136,7 +126,6 @@ public class ItemSorter implements Comparator<ItemStack>, ItemsLoadedCallback {
list = fromSaveString(activeTag().getValue());
}
});
ItemList.loadCallbacks.add(instance);
}
public static String getSaveString(List<SortEntry> list) {
@@ -0,0 +1,133 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import codechicken.nei.recipe.StackInfo;
public class ItemStackAmount {
private final Map<NBTTagCompound, Long> itemMap = new LinkedHashMap<>();
public void putAll(ItemStackAmount amounts) {
for (Map.Entry<NBTTagCompound, Long> entry : amounts.itemMap.entrySet()) {
this.itemMap.put(entry.getKey(), entry.getValue() + this.itemMap.getOrDefault(entry.getKey(), 0L));
}
}
public void addAll(Iterable<ItemStack> items) {
for (ItemStack stack : items) {
add(stack);
}
}
public void add(ItemStack item) {
add(item, (long) StackInfo.getAmount(item));
}
public void add(ItemStack stack, Long value) {
if (stack == null || stack.getItem() == null) return;
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
if (key != null) {
this.itemMap.put(key, value + this.itemMap.getOrDefault(key, 0L));
}
}
public Long get(ItemStack stack) {
if (stack == null || stack.getItem() == null) return null;
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
return this.itemMap.get(key);
}
public void put(ItemStack stack, long value) {
if (stack == null || stack.getItem() == null) return;
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
if (key != null) {
this.itemMap.put(key, value);
}
}
public long getOrDefault(ItemStack stack, long defaultAmount) {
final Long e = get(stack);
return e == null ? defaultAmount : e;
}
public boolean contains(ItemStack stack) {
return get(stack) != null;
}
public void clear() {
this.itemMap.clear();
}
public Long remove(ItemStack stack) {
if (stack == null || stack.getItem() == null) return null;
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
return this.itemMap.remove(key);
}
public boolean removeIf(Predicate<Map.Entry<NBTTagCompound, Long>> predicate) {
return this.itemMap.entrySet().removeIf(predicate);
}
public Set<Map.Entry<NBTTagCompound, Long>> entrySet() {
return this.itemMap.entrySet();
}
public List<ItemStack> values() {
List<ItemStack> list = new ArrayList<>();
for (Map.Entry<NBTTagCompound, Long> entry : this.itemMap.entrySet()) {
list.add(StackInfo.loadFromNBT(entry.getKey(), Math.max(0, entry.getValue())));
}
return list;
}
public int size() {
return this.itemMap.size();
}
public boolean isEmpty() {
return this.itemMap.isEmpty();
}
public static ItemStackAmount of(ItemStackAmount map) {
ItemStackAmount result = new ItemStackAmount();
result.itemMap.putAll(map.itemMap);
return result;
}
public static ItemStackAmount of(ItemStackMap<Long> map) {
ItemStackAmount result = new ItemStackAmount();
for (ItemStackMap.Entry<Long> entry : map.entries()) {
result.put(entry.key, entry.value);
}
return result;
}
public static ItemStackAmount of(Iterable<ItemStack> items) {
ItemStackAmount result = new ItemStackAmount();
for (ItemStack stack : items) {
result.add(stack);
}
return result;
}
}
@@ -5,9 +5,11 @@ import static codechicken.lib.inventory.InventoryUtils.newItemStack;
import static net.minecraftforge.oredict.OreDictionary.WILDCARD_VALUE;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@@ -24,8 +26,13 @@ public class ItemStackMap<T> {
public final int damage;
public final NBTTagCompound tag;
private final int hashCode;
public StackMetaKey(int damage, NBTTagCompound tag) {
if (tag != null && tag.hasNoTags()) {
tag = null;
}
this.hashCode = Objects.hashCode(damage, tag);
this.damage = damage;
this.tag = tag;
}
@@ -35,7 +42,7 @@ public class ItemStackMap<T> {
}
public int hashCode() {
return Objects.hashCode(damage, tag);
return this.hashCode;
}
public boolean equals(Object o) {
@@ -191,7 +198,7 @@ public class ItemStackMap<T> {
WILDCARD_TAG.setBoolean("*", true);
}
private final HashMap<Item, DetailMap> itemMap = new HashMap<>();
private final Map<Item, DetailMap> itemMap = new LinkedHashMap<>();
private int size;
public T get(ItemStack key) {
@@ -216,8 +223,22 @@ public class ItemStackMap<T> {
map.put(key, value);
}
public T computeIfAbsent(ItemStack key, Function<ItemStack, ? extends T> mappingFunction) {
T value;
if ((value = get(key)) == null) {
T newValue;
if ((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
}
return value;
}
public void clear() {
itemMap.clear();
size = 0;
}
public T remove(ItemStack key) {
@@ -32,6 +32,11 @@ public class ItemStackSet extends ItemStackMap<ItemStack> implements ItemFilter
return this;
}
public ItemStackSet removeAll(Iterable<ItemStack> items) {
for (ItemStack item : items) remove(item);
return this;
}
public boolean contains(ItemStack item) {
return get(item) != null;
}
+1 -1
View File
@@ -40,7 +40,7 @@ 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"))
&& GuiContainerManager.shouldShowTooltip(NEIClientUtils.getGuiContainer())) {
+322 -159
View File
@@ -1,12 +1,10 @@
package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.drawRect;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nullable;
import java.util.Objects;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.ScaledResolution;
@@ -17,16 +15,248 @@ import net.minecraft.client.shader.Framebuffer;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL30;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.StackInfo;
public class ItemsGrid {
public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends ItemsGrid.MouseContext> {
public static final int SLOT_SIZE = 18;
protected static class ScreenCapture {
private long nextCacheRefresh = 0;
private Framebuffer framebuffer;
public ScreenCapture() {
this.framebuffer = new Framebuffer(1, 1, true);
this.framebuffer.setFramebufferColor(0.0F, 0.0F, 0.0F, 0.0F);
Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
}
protected int getGridRenderingCacheFPS(int mode) {
return mode == 1 ? NEIClientConfig.getIntSetting("inventory.gridRenderingCacheFPS") : 0;
}
public boolean needRefresh(int mode) {
final Minecraft minecraft = Minecraft.getMinecraft();
return this.nextCacheRefresh == 0 || this.framebuffer.framebufferWidth != minecraft.displayWidth
|| framebuffer.framebufferHeight != minecraft.displayHeight
|| getGridRenderingCacheFPS(mode) > 0 && this.nextCacheRefresh < System.currentTimeMillis();
}
public void refreshBuffer() {
this.nextCacheRefresh = 0;
}
public void captureScreen(Runnable callback, int mode) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
resetFramebuffer();
this.framebuffer.bindFramebuffer(false);
/* Set up some rendering state needed for items to work correctly */
GL11.glDisable(GL11.GL_BLEND);
GL11.glDepthMask(true);
OpenGlHelper.glBlendFunc(
GL11.GL_SRC_ALPHA,
GL11.GL_ONE_MINUS_SRC_ALPHA,
GL11.GL_SRC_ALPHA,
GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
callback.run();
GL11.glPopAttrib();
Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
this.nextCacheRefresh = System.currentTimeMillis() + (1000 / Math.max(1, getGridRenderingCacheFPS(mode)));
}
private void resetFramebuffer() {
final Minecraft minecraft = Minecraft.getMinecraft();
if (this.framebuffer.framebufferWidth != minecraft.displayWidth
|| framebuffer.framebufferHeight != minecraft.displayHeight) {
this.framebuffer.createBindFramebuffer(minecraft.displayWidth, minecraft.displayHeight);
this.framebuffer.setFramebufferFilter(GL11.GL_NEAREST);
} else {
this.framebuffer.framebufferClear();
}
// copy depth buffer from MC (fix Angelica)
OpenGlHelper.func_153171_g(GL30.GL_READ_FRAMEBUFFER, minecraft.getFramebuffer().framebufferObject);
OpenGlHelper.func_153171_g(GL30.GL_DRAW_FRAMEBUFFER, this.framebuffer.framebufferObject);
GL30.glBlitFramebuffer(
0,
0,
minecraft.displayWidth,
minecraft.displayHeight,
0,
0,
minecraft.displayWidth,
minecraft.displayHeight,
GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT,
GL11.GL_NEAREST);
}
public void renderCapturedScreen() {
this.framebuffer.bindFramebufferTexture();
final Tessellator tessellator = Tessellator.instance;
final Minecraft minecraft = Minecraft.getMinecraft();
final ScaledResolution scaledresolution = new ScaledResolution(
minecraft,
minecraft.displayWidth,
minecraft.displayHeight);
/* Set up some rendering state needed for items to work correctly */
GL11.glEnable(GL11.GL_BLEND);
OpenGlHelper
.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
GL11.glEnable(GL11.GL_TEXTURE_2D);
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(0, scaledresolution.getScaledHeight_double(), 0.0, 0, 0);
tessellator.addVertexWithUV(
scaledresolution.getScaledWidth_double(),
scaledresolution.getScaledHeight_double(),
0.0,
1,
0);
tessellator.addVertexWithUV(scaledresolution.getScaledWidth_double(), 0, 0.0, 1, 1);
tessellator.addVertexWithUV(0, 0, 0, 0, 1);
tessellator.draw();
this.framebuffer.unbindFramebufferTexture();
}
}
public static class ItemsGridSlot {
protected static final float DEFAULT_SLOT_SIZE = 18f;
protected static final float LINE_WIDTH = 0.75f;
public final ItemStack item;
public final int slotIndex;
public final int itemIndex;
public Color borderColor = Color.BLACK;
public boolean borderLeft = false;
public boolean borderTop = false;
public boolean borderRight = false;
public boolean borderBottom = false;
public ItemsGridSlot(int slotIndex, int itemIndex, ItemStack itemStack) {
this.slotIndex = slotIndex;
this.itemIndex = itemIndex;
this.item = itemStack;
}
public ItemStack getItemStack() {
return this.item;
}
public <M extends MouseContext> void beforeDraw(Rectangle4i rect, M mouseContext) {
if (mouseContext != null && mouseContext.slotIndex == this.slotIndex) {
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, HIGHLIGHT_COLOR);
}
}
public <M extends MouseContext> void afterDraw(Rectangle4i rect, M mouseContext) {}
public void drawItem(Rectangle4i rect) {
drawItem(getItemStack(), rect);
}
protected void drawItem(ItemStack stack, Rectangle4i rect) {
if (rect.w != DEFAULT_SLOT_SIZE) {
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
GL11.glTranslatef(rect.x + 1, rect.y + 1, 0);
GL11.glScaled(panelFactor, panelFactor, 1);
GuiContainerManager.drawItem(0, 0, stack, true, "");
GL11.glScaled(1f / panelFactor, 1f / panelFactor, 1);
GL11.glTranslatef(-1 * (rect.x + 1), -1 * (rect.y + 1), 0);
} else {
GuiContainerManager.drawItem(rect.x + 1, rect.y + 1, stack, true, "");
}
}
public void drawBorder(Rectangle4i rect) {
float halfLineWidth = LINE_WIDTH / 2f;
if (this.borderLeft) {
NEIClientUtils
.drawRect(rect.x - halfLineWidth, rect.y + halfLineWidth, LINE_WIDTH, rect.h, this.borderColor);
}
if (this.borderRight) {
NEIClientUtils.drawRect(
rect.x + rect.w - halfLineWidth,
rect.y - halfLineWidth,
LINE_WIDTH,
rect.h,
this.borderColor);
}
if (this.borderTop) {
NEIClientUtils
.drawRect(rect.x - halfLineWidth, rect.y - halfLineWidth, rect.w, LINE_WIDTH, this.borderColor);
}
if (this.borderBottom) {
NEIClientUtils.drawRect(
rect.x + halfLineWidth,
rect.y + rect.h - halfLineWidth,
rect.w,
LINE_WIDTH,
this.borderColor);
}
}
}
public static class MouseContext {
public final int slotIndex;
public final int columnIndex;
public final int rowIndex;
public MouseContext(int slotIndex, int rowIndex, int columnIndex) {
this.slotIndex = slotIndex;
this.rowIndex = rowIndex;
this.columnIndex = columnIndex;
}
@Override
public int hashCode() {
return Objects.hash(this.rowIndex, this.slotIndex, this.columnIndex);
}
public boolean equals(Object obj) {
if (obj instanceof MouseContext context) {
return this.columnIndex == context.columnIndex && this.rowIndex == context.rowIndex
&& this.slotIndex == context.slotIndex;
}
return false;
}
}
public static int SLOT_SIZE = 18;
public static final Color HIGHLIGHT_COLOR = new Color(0xee555555, true);
protected int width;
protected int height;
@@ -43,29 +273,29 @@ public class ItemsGrid {
protected int rows;
protected int columns;
protected List<Integer> gridMask = null;
protected boolean[] invalidSlotMap;
protected Label messageLabel = new Label(getMessageOnEmpty(), true);
@Nullable
private Framebuffer framebuffer = null;
protected boolean refreshBuffer = true;
protected ScreenCapture screenCapture = null;
public ArrayList<ItemStack> getItems() {
return realItems;
}
public ItemStack getItem(int idx) {
return realItems.get(idx);
public ItemStack getItem(int itemIndex) {
return realItems.get(itemIndex);
}
public int size() {
return realItems.size();
}
public boolean isEmpty() {
return realItems.isEmpty();
}
public int indexOf(ItemStack stackA, boolean useNBT) {
for (int idx = 0; idx < realItems.size(); idx++) {
@@ -107,7 +337,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) {
@@ -152,11 +386,12 @@ public class ItemsGrid {
}
protected void onGridChanged() {
refreshBuffer = true;
this.gridMask = null;
if (this.screenCapture != null) {
this.screenCapture.refreshBuffer();
}
}
protected void onItemsChanged() {
public void onItemsChanged() {
onGridChanged();
}
@@ -206,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) {
@@ -230,99 +482,49 @@ public class ItemsGrid {
SLOT_SIZE);
}
public int getRowIndex(int mousey) {
return (mousey - this.marginTop) / SLOT_SIZE;
}
public int getColumnIndex(int mousex) {
return (mousex - this.marginLeft - this.paddingLeft) / SLOT_SIZE;
}
public boolean isInvalidSlot(int index) {
return invalidSlotMap[index];
}
protected List<Integer> getMask() {
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 blitExistingBuffer() {
Minecraft minecraft = Minecraft.getMinecraft();
GL11.glEnable(GL11.GL_BLEND);
OpenGlHelper.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
getFrameBuffer().bindFramebufferTexture();
GL11.glEnable(GL11.GL_TEXTURE_2D);
ScaledResolution res = new ScaledResolution(minecraft, minecraft.displayWidth, minecraft.displayHeight);
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(0, res.getScaledHeight_double(), 0.0, 0, 0);
tessellator.addVertexWithUV(res.getScaledWidth_double(), res.getScaledHeight_double(), 0.0, 1, 0);
tessellator.addVertexWithUV(res.getScaledWidth_double(), 0, 0.0, 1, 1);
tessellator.addVertexWithUV(0, 0, 0, 0, 1);
tessellator.draw();
OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
}
private Framebuffer getFrameBuffer() {
if (framebuffer == null) {
framebuffer = new Framebuffer(1, 1, true);
framebuffer.setFramebufferColor(0.0F, 0.0F, 0.0F, 0.0F);
for (T item : getMask()) {
item.drawItem(getSlotRect(item.slotIndex));
}
return framebuffer;
}
private void drawItems() {
GuiContainerManager.enableMatrixStackLogging();
final List<Integer> mask = getMask();
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) != null) {
drawItem(getSlotRect(i), mask.get(i));
}
}
GuiContainerManager.disableMatrixStackLogging();
}
protected boolean shouldCacheItemRendering() {
return NEIClientConfig.shouldCacheItemRendering();
protected int getGridRenderingCacheMode() {
return NEIClientConfig.getGridRenderingCacheMode();
}
public void draw(int mousex, int mousey) {
@@ -330,41 +532,33 @@ public class ItemsGrid {
return;
}
final ItemPanelSlot focused = getSlotMouseOver(mousex, mousey);
final int gridRenderingCacheMode = getGridRenderingCacheMode();
final M mouseContext = getMouseContext(mousex, mousey);
if (shouldCacheItemRendering()) {
beforeDrawItems(mousex, mousey, mouseContext);
if (refreshBuffer) {
Minecraft minecraft = Minecraft.getMinecraft();
Framebuffer framebuffer = getFrameBuffer();
framebuffer.createBindFramebuffer(minecraft.displayWidth, minecraft.displayHeight);
framebuffer.framebufferClear();
framebuffer.bindFramebuffer(false);
if (gridRenderingCacheMode > 0) {
/* Set up some rendering state needed for items to work correctly */
GL11.glDisable(GL11.GL_BLEND);
GL11.glDepthMask(true);
OpenGlHelper.glBlendFunc(
GL11.GL_SRC_ALPHA,
GL11.GL_ONE_MINUS_SRC_ALPHA,
GL11.GL_SRC_ALPHA,
GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
drawItems();
Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
refreshBuffer = false;
if (this.screenCapture == null) {
this.screenCapture = new ScreenCapture();
}
beforeDrawItems(mousex, mousey, focused);
blitExistingBuffer();
if (this.screenCapture.needRefresh(gridRenderingCacheMode)) {
this.screenCapture.captureScreen(() -> {
GuiContainerManager.enableMatrixStackLogging();
drawItems();
GuiContainerManager.disableMatrixStackLogging();
}, gridRenderingCacheMode);
}
this.screenCapture.renderCapturedScreen();
} else {
beforeDrawItems(mousex, mousey, focused);
GuiContainerManager.enableMatrixStackLogging();
drawItems();
GuiContainerManager.disableMatrixStackLogging();
}
afterDrawItems(mousex, mousey, focused);
afterDrawItems(mousex, mousey, mouseContext);
}
public void setVisible() {
@@ -373,34 +567,6 @@ public class ItemsGrid {
}
}
protected void drawItem(Rectangle4i rect, int idx) {
GuiContainerManager.drawItem(rect.x + 1, rect.y + 1, getItem(idx));
}
public ItemPanelSlot getSlotMouseOver(int mousex, int mousey) {
if (!contains(mousex, mousey)) {
return null;
}
final int overRow = (int) ((mousey - marginTop) / SLOT_SIZE);
final int overColumn = (int) ((mousex - marginLeft - paddingLeft) / SLOT_SIZE);
final int slt = columns * overRow + overColumn;
if (overRow >= rows || overColumn >= columns) {
return null;
}
final List<Integer> mask = getMask();
if (mask.size() > slt && mask.get(slt) != null) {
final int idx = mask.get(slt);
return new ItemPanelSlot(idx, getItem(idx));
}
return null;
}
public boolean contains(int px, int py) {
final Rectangle4i rect = new Rectangle4i(
marginLeft + paddingLeft,
@@ -412,10 +578,7 @@ public class ItemsGrid {
return false;
}
final int r = (int) ((py - marginTop) / SLOT_SIZE);
final int c = (int) ((px - marginLeft - paddingLeft) / SLOT_SIZE);
return !isInvalidSlot(columns * r + c);
return !isInvalidSlot(columns * getRowIndex(py) + getColumnIndex(px));
}
public String getMessageOnEmpty() {
@@ -0,0 +1,239 @@
package codechicken.nei;
import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.guihook.GuiContainerManager;
public class ItemsPanelGrid extends ItemsGrid<ItemsPanelGrid.ItemsPanelGridSlot, ItemsPanelGrid.MouseContext> {
public static class ItemsPanelGridSlot extends ItemsGridSlot {
protected static final float LINE_WIDTH = 0.75f;
public int groupIndex = -1;
public String displayName = "";
public ItemStack bgItemStack;
public int groupSize = 1;
public boolean extended = false;
public Color bgColor = null;
public ItemsPanelGridSlot(int slotIndex, int itemIndex, ItemStack itemStack) {
super(slotIndex, itemIndex, itemStack);
}
public ItemStack getBGItem() {
return this.bgItemStack;
}
@Override
public void beforeDraw(Rectangle4i rect, MouseContext mouseContext) {
super.beforeDraw(rect, mouseContext);
if (this.bgColor != null) {
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, this.bgColor);
}
}
@Override
public void drawItem(Rectangle4i rect) {
if (!this.extended && getBGItem() != null) {
GuiContainerManager.drawItems.zLevel -= 10F;
super.drawItem(getBGItem(), rect.offset(1, -1));
GuiContainerManager.drawItems.zLevel += 10F;
super.drawItem(getItemStack(), rect.offset(-2, 2));
} else {
super.drawItem(rect);
}
}
}
public ArrayList<ItemStack> newItems;
public ArrayList<ItemStack> rawItems;
protected List<ItemsPanelGridSlot> gridMask;
protected final Map<Integer, Integer> itemToGroup = new HashMap<>();
protected final Map<Integer, List<ItemStack>> groupItems = new HashMap<>();
protected boolean forceExpand = false;
public void setItems(ArrayList<ItemStack> items) {
newItems = items;
}
public static void updateScale() {
SLOT_SIZE = 2 + (int) Math.ceil(8f * NEIClientConfig.getIntSetting("inventory.itempanelScale") / 100) * 2;
}
@Override
public void refresh(GuiContainer gui) {
if (this.newItems != null) {
this.groupItems.clear();
this.itemToGroup.clear();
this.forceExpand = false;
if (!CollapsibleItems.isEmpty() && !this.newItems.isEmpty()) {
final Set<Integer> groups = new HashSet<>();
boolean outsideGroup = false;
this.realItems = new ArrayList<>();
this.rawItems = new ArrayList<>(this.newItems);
for (ItemStack stack : this.newItems) {
final int groupIndex = CollapsibleItems.getGroupIndex(stack);
if (groupIndex == -1) {
this.realItems.add(stack);
outsideGroup = true;
} else {
if (!groups.contains(groupIndex) || CollapsibleItems.isExpanded(groupIndex)) {
this.itemToGroup.put(this.realItems.size(), groupIndex);
this.realItems.add(stack);
groups.add(groupIndex);
}
this.groupItems.computeIfAbsent(groupIndex, gi -> new ArrayList<>()).add(stack);
}
}
// automatically opens if there are elements from only one group
if (!outsideGroup && groups.size() == 1) {
final int groupIndex = groups.iterator().next();
this.realItems = new ArrayList<>(this.newItems);
this.itemToGroup.clear();
this.forceExpand = true;
for (int itemIndex = 0; itemIndex < this.realItems.size(); itemIndex++) {
this.itemToGroup.put(itemIndex, groupIndex);
}
}
} else {
this.realItems = new ArrayList<>(this.newItems);
}
this.newItems = null;
onItemsChanged();
}
super.refresh(gui);
}
@Override
protected void onGridChanged() {
this.gridMask = null;
super.onGridChanged();
}
@Override
public List<ItemsPanelGridSlot> getMask() {
if (this.gridMask == null) {
this.gridMask = new ArrayList<>();
int itemIndex = page * perPage;
for (int slotIndex = 0; slotIndex < rows * columns && itemIndex < size(); slotIndex++) {
if (!isInvalidSlot(slotIndex)) {
this.gridMask.add(new ItemsPanelGridSlot(slotIndex, itemIndex, getItem(itemIndex)));
itemIndex++;
}
}
calculateGroupBorders(this.gridMask);
}
return this.gridMask;
}
@Override
protected MouseContext getMouseContext(int mousex, int mousey) {
final ItemsPanelGridSlot hovered = getSlotMouseOver(mousex, mousey);
if (hovered != null) {
return new MouseContext(
hovered.slotIndex,
hovered.slotIndex / this.columns,
hovered.slotIndex % this.columns);
}
return null;
}
protected void calculateGroupBorders(List<ItemsPanelGridSlot> gridMask) {
if (gridMask.isEmpty() || this.groupItems.isEmpty()) {
return;
}
final Color collapsedBGColor = new Color(
NEIClientConfig.getSetting("inventory.collapsibleItems.collapsedColor").getHexValue(),
true);
final Color expandedBGColor = new Color(
NEIClientConfig.getSetting("inventory.collapsibleItems.expandedColor").getHexValue(),
true);
final Color collapsedBorderColor = darkerColor(collapsedBGColor);
final Color expandedBorderColor = darkerColor(expandedBGColor);
final Map<Integer, Integer> borderGrid = new HashMap<>();
for (ItemsPanelGridSlot item : gridMask) {
borderGrid.put(item.slotIndex, this.itemToGroup.getOrDefault(item.itemIndex, -1));
}
for (ItemsPanelGridSlot item : gridMask) {
final int groupIndex = borderGrid.get(item.slotIndex);
final List<ItemStack> groupItems = this.groupItems.get(groupIndex);
if (groupItems == null || groupItems.size() == 1) {
continue;
}
int column = item.slotIndex % this.columns;
int row = item.slotIndex / this.columns;
int prevSlotIndex = (row - 1) * this.columns + column;
int nextSlotIndex = (row + 1) * this.columns + column;
item.groupIndex = groupIndex;
item.groupSize = groupItems.size();
item.bgItemStack = groupItems.get(groupItems.size() - 1);
item.displayName = CollapsibleItems.getDisplayName(groupIndex);
item.extended = this.forceExpand || CollapsibleItems.isExpanded(groupIndex);
item.bgColor = item.extended ? expandedBGColor : collapsedBGColor;
item.borderColor = item.extended ? expandedBorderColor : collapsedBorderColor;
item.borderLeft = column == 0 || borderGrid.getOrDefault(item.slotIndex - 1, -1) != groupIndex;
item.borderRight = column + 1 == this.columns
|| borderGrid.getOrDefault(item.slotIndex + 1, -1) != groupIndex;
item.borderTop = borderGrid.getOrDefault(prevSlotIndex, -1) != groupIndex;
item.borderBottom = borderGrid.getOrDefault(nextSlotIndex, -1) != groupIndex;
}
}
private static Color darkerColor(Color color) {
return new Color(
color.getRed(),
color.getGreen(),
color.getBlue(),
Math.min((int) (color.getAlpha() + (255f / 5) * 2), 255));
}
@Override
public String getMessageOnEmpty() {
return ItemList.loadFinished ? null : NEIClientUtils.translate("itempanel.loading");
}
}
@@ -4,8 +4,6 @@ import static codechicken.lib.gui.GuiDraw.fontRenderer;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -17,6 +15,7 @@ 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;
@@ -24,12 +23,14 @@ import codechicken.nei.util.ReadableNumberConverter;
public class ItemsTooltipLineHandler implements ITooltipLineHandler {
protected static int MAX_COLUMNS = 11;
protected static int MARGIN_TOP = 2;
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;
@@ -37,7 +38,7 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
protected int rows = 0;
protected int length = 0;
public ItemsTooltipLineHandler(String label, List<ItemStack> items, boolean saveStackSize) {
public ItemsTooltipLineHandler(String label, List<ItemStack> items) {
this(label, items, true, 5);
}
@@ -51,19 +52,33 @@ 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,
Math.min(
this.columns * this.rows,
this.length > MAX_COLUMNS * maxRows ? (MAX_COLUMNS * maxRows - 1) : Integer.MAX_VALUE));
this.length > MAX_COLUMNS * maxRows ? (MAX_COLUMNS * maxRows) : Integer.MAX_VALUE));
if (this.items.size() > this.count) {
String text = "+" + (this.items.size() - this.count);
this.count -= (int) Math.ceil((float) (fontRenderer.getStringWidth(text) - 2) / SLOT_SIZE);
}
}
}
public void setActiveStack(ItemStack activeStack) {
final ItemStack realStack = items.stream().filter(stack -> StackInfo.equalItemAndNBT(stack, activeStack, true))
.findFirst().orElse(null);
this.activeStackIndex = items.indexOf(realStack);
}
public ItemStack getActiveStack() {
return this.activeStackIndex == -1 ? null : this.items.get(this.activeStackIndex);
}
public boolean isEmpty() {
return this.items.isEmpty();
}
@@ -85,6 +100,7 @@ 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();
@@ -92,57 +108,64 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
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;
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);
GuiContainerManager
.drawItem(col * ItemsGrid.SLOT_SIZE, row * ItemsGrid.SLOT_SIZE, drawStack, true, 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()) {
fontRenderer.drawStringWithShadow(
"+" + (this.items.size() - this.count),
(this.columns - 1) * ItemsGrid.SLOT_SIZE,
(this.rows - 1) * ItemsGrid.SLOT_SIZE + (ItemsGrid.SLOT_SIZE - fontRenderer.FONT_HEIGHT) / 2 - 1,
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.glDisable(GL12.GL_RESCALE_NORMAL);
GL11.glPopMatrix();
GL11.glPopAttrib();
}
protected void drawItem(int x, int y, ItemStack drawStack, String stackSize) {
GuiContainerManager.drawItem(x, y, drawStack, true, stackSize);
}
private List<ItemStack> groupingItemStacks(List<ItemStack> items) {
final Map<String, Integer> count = new HashMap<>();
final Map<String, NBTTagCompound> unique = new LinkedHashMap<>();
final List<ItemStack> result = new ArrayList<>();
for (ItemStack stack : items) {
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(stack, true);
final String GUID = StackInfo.getItemStackGUID(stack);
for (Map.Entry<NBTTagCompound, Long> entry : ItemStackAmount.of(items).entrySet()) {
final ItemStack stack = StackInfo.loadFromNBT(entry.getKey(), Math.max(0, entry.getValue()));
if (!unique.containsKey(GUID)) {
count.put(GUID, nbTag.getInteger("Count"));
unique.put(GUID, nbTag);
} else {
count.put(GUID, count.get(GUID) + nbTag.getInteger("Count"));
}
}
for (String GUID : unique.keySet()) {
ItemStack stack = StackInfo.loadFromNBT(unique.get(GUID), count.get(GUID));
if (unique.get(GUID).hasKey("gtFluidName")) {
if (entry.getKey().hasKey("gtFluidName")) {
stack.stackSize = 0;
}
result.add(stack);
}
if (result.isEmpty()) {
result.addAll(items);
}
return result;
}
@@ -0,0 +1,21 @@
package codechicken.nei;
import java.util.LinkedHashMap;
import java.util.Map;
// Simple LRUCache
public class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int capacity;
public LRUCache(int capacity) {
super(capacity, 0.75f, true);
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > capacity;
}
}
+134 -72
View File
@@ -12,7 +12,6 @@ import static codechicken.nei.NEIClientConfig.invCreativeMode;
import static codechicken.nei.NEIClientConfig.isBookmarkPanelHidden;
import static codechicken.nei.NEIClientConfig.isEnabled;
import static codechicken.nei.NEIClientConfig.isHidden;
import static codechicken.nei.NEIClientConfig.isLoaded;
import static codechicken.nei.NEIClientConfig.showIDs;
import static codechicken.nei.NEIClientConfig.toggleBooleanSetting;
import static codechicken.nei.NEIClientUtils.cycleGamemode;
@@ -32,10 +31,11 @@ import static codechicken.nei.NEIClientUtils.toggleMagnetMode;
import static codechicken.nei.NEIClientUtils.toggleRaining;
import static codechicken.nei.NEIClientUtils.translate;
import java.awt.Point;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import net.minecraft.client.Minecraft;
@@ -65,6 +65,7 @@ import codechicken.nei.guihook.IContainerDrawHandler;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.guihook.IContainerObjectHandler;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.recipe.AutoCraftingManager;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.RecipeCatalysts;
@@ -79,13 +80,11 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
/**
* Sorted bottom first
*/
private static TreeSet<Widget> drawWidgets = new TreeSet<>(new WidgetZOrder(false));
private static Set<Widget> drawWidgets = new TreeSet<>(new WidgetZOrder(false));
/**
* Sorted top first
*/
private static TreeSet<Widget> controlWidgets = new TreeSet<>(new WidgetZOrder(true));
private static List<IContainerTooltipHandler> tooltipWidgets = new LinkedList<>();
private static Set<Widget> controlWidgets = new TreeSet<>(new WidgetZOrder(true));
public static ItemPanel itemPanel;
public static BookmarkPanel bookmarkPanel;
@@ -96,13 +95,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public static ButtonCycled options;
public static ButtonCycled bookmarksButton;
@Deprecated
public static Button more;
@Deprecated
public static Button less;
@Deprecated
public static ItemQuantityField quantity;
public static Button delete;
@@ -142,16 +136,14 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public void onPreDraw(GuiContainer gui) {
if (!isHidden() && isEnabled() && gui instanceof InventoryEffectRenderer) // Reset the gui to the center of the
// screen, for potion effect offsets
// etc
{
// Reset the gui to the center of the screen, for potion effect offsets etc
if (isEnabled() && gui instanceof InventoryEffectRenderer) {
gui.guiLeft = (gui.width - gui.xSize) / 2;
gui.guiTop = (gui.height - gui.ySize) / 2;
if (gui instanceof GuiContainerCreative && gui.buttonList.size() >= 2) {
GuiButton button1 = (GuiButton) gui.buttonList.get(0);
GuiButton button2 = (GuiButton) gui.buttonList.get(1);
GuiButton button1 = gui.buttonList.get(0);
GuiButton button2 = gui.buttonList.get(1);
button1.xPosition = gui.guiLeft;
button2.xPosition = gui.guiLeft + gui.xSize - 20;
}
@@ -172,14 +164,18 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
if (isHidden()) return;
for (Widget widget : controlWidgets) widget.onGuiClick(mousex, mousey);
for (Widget widget : controlWidgets) {
widget.onGuiClick(mousex, mousey);
}
}
@Override
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
if (isHidden()) return false;
if (!isEnabled()) return options.contains(mousex, mousey) && options.handleClick(mousex, mousey, button);
if (!isEnabled()) {
return options.contains(mousex, mousey) && options.handleClick(mousex, mousey, button);
}
for (Widget widget : controlWidgets) {
widget.onGuiClick(mousex, mousey);
@@ -193,10 +189,22 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public boolean objectUnderMouse(GuiContainer gui, int mousex, int mousey) {
if (!isHidden() && isEnabled())
for (Widget widget : drawWidgets) if (widget.contains(mousex, mousey)) return true;
return getWidgetUnderMouse(mousex, mousey) != null;
}
return false;
public Widget getWidgetUnderMouse(int mousex, int mousey) {
if (isHidden() || !isEnabled()) {
return null;
}
for (Widget widget : controlWidgets) {
if (widget.contains(mousex, mousey)) {
return widget;
}
}
return null;
}
public boolean keyTyped(GuiContainer gui, char keyChar, int keyID) {
@@ -225,8 +233,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
return true;
}
if (NEIClientConfig.isKeyHashDown("gui.next_tooltip")) {
GuiContainerManager.incrementTooltipPage();
if (NEIClientConfig.isKeyHashDown("gui.next_tooltip") && GuiContainerManager.incrementTooltipPage()) {
return true;
}
@@ -252,12 +259,12 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public ItemStack getStackUnderMouse(GuiContainer gui, int mousex, int mousey) {
if (!isHidden() && isEnabled()) {
for (Widget widget : drawWidgets) {
ItemStack stack = widget.getStackMouseOver(mousex, mousey);
if (stack != null) return stack;
}
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused != null) {
return focused.getStackMouseOver(mousex, mousey);
}
return null;
}
@@ -286,18 +293,32 @@ 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)) {
for (Widget widget : drawWidgets) widget.postDrawTooltips(mousex, mousey, tooltip);
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused != null) {
focused.postDrawTooltips(mousex, mousey, tooltip);
}
}
}
@Override
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
for (Widget widget : drawWidgets) currenttip = widget.handleTooltip(mousex, mousey, currenttip);
for (IContainerTooltipHandler tip : tooltipWidgets)
currenttip = tip.handleTooltip(gui, mousex, mousey, currenttip);
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused != null) {
currenttip = focused.handleTooltip(mousex, mousey, currenttip);
if (focused instanceof IContainerTooltipHandler tip) {
currenttip = tip.handleTooltip(gui, mousex, mousey, currenttip);
}
}
}
return currenttip;
}
@@ -315,8 +336,12 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
}
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
for (IContainerTooltipHandler tip : tooltipWidgets)
final Point mouse = GuiDraw.getMousePosition();
final Widget focused = getWidgetUnderMouse(mouse.x, mouse.y);
if (focused instanceof IContainerTooltipHandler tip) {
currenttip = tip.handleItemDisplayName(gui, stack, currenttip);
}
}
return currenttip;
@@ -327,8 +352,11 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
List<String> currenttip) {
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
for (IContainerTooltipHandler tip : tooltipWidgets)
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused instanceof IContainerTooltipHandler tip) {
currenttip = tip.handleItemTooltip(gui, itemstack, mousex, mousey, currenttip);
}
}
return currenttip;
@@ -338,8 +366,11 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
if (!isHidden() && isEnabled() && GuiContainerManager.shouldShowTooltip(gui)) {
for (IContainerTooltipHandler tip : tooltipWidgets)
final Widget focused = getWidgetUnderMouse(mousex, mousey);
if (focused instanceof IContainerTooltipHandler tip) {
hotkeys = tip.handleHotkeys(gui, mousex, mousey, hotkeys);
}
}
return hotkeys;
@@ -347,17 +378,12 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public static void layout(GuiContainer gui) {
VisiblityData visiblity = new VisiblityData();
if (isHidden()) visiblity.showNEI = false;
if (isBookmarkPanelHidden()) visiblity.showBookmarkPanel = false;
if (gui.height - gui.ySize <= 40 && NEIClientConfig.isSearchWidgetCentered())
visiblity.showSearchSection = false;
if (visiblity.showBookmarkPanel || gui.guiTop <= 20) visiblity.showSubsetDropdown = false;
if (gui.guiLeft - 4 < 76) visiblity.showWidgets = false;
visiblity.showNEI = !isHidden();
visiblity.showBookmarkPanel = !isBookmarkPanelHidden();
visiblity.showSearchSection = !(gui.height - gui.ySize <= 40 && NEIClientConfig.isSearchWidgetCentered());
visiblity.showSubsetDropdown = NEIClientConfig.showSubsetWidget()
&& (gui.guiTop > 20 || visiblity.showSearchSection && !NEIClientConfig.subsetWidgetOnTop());
visiblity.showWidgets = gui.guiLeft - 4 > 76;
try {
GuiInfo.readLock.lock();
@@ -467,9 +493,43 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
}
};
more = ItemPanels.itemPanel.more;
less = ItemPanels.itemPanel.less;
quantity = ItemPanels.itemPanel.quantity;
more = new Button("+") {
@Override
public boolean onButtonPress(boolean rightclick) {
if (rightclick) return false;
int modifier = NEIClientUtils.controlKey() ? 64 : NEIClientUtils.shiftKey() ? 10 : 1;
int quantity = NEIClientConfig.getItemQuantity() + modifier;
if (quantity < 0) {
quantity = 0;
}
LayoutManager.quantity.setText(Integer.toString(quantity));
return true;
}
};
less = new Button("-") {
@Override
public boolean onButtonPress(boolean rightclick) {
if (rightclick) return false;
int modifier = NEIClientUtils.controlKey() ? -64 : NEIClientUtils.shiftKey() ? -10 : -1;
int quantity = NEIClientConfig.getItemQuantity() + modifier;
if (quantity < 0) {
quantity = 0;
}
LayoutManager.quantity.setText(Integer.toString(quantity));
return true;
}
};
quantity = new ItemQuantityField("quantity");
delete = new Button() {
@Override
@@ -643,7 +703,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
if (isEnabled()) {
setInputFocused(null);
if (!itemsLoaded && isLoaded()) {
if (!itemsLoaded) {
ItemList.loadItems.restart();
}
@@ -677,12 +737,18 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public static void updateWidgetVisiblities(GuiContainer gui, VisiblityData visiblity) {
drawWidgets = new TreeSet<>(new WidgetZOrder(false));
controlWidgets = new TreeSet<>(new WidgetZOrder(true));
tooltipWidgets.clear();
if (!visiblity.showNEI) return;
addWidget(options);
addWidget(bookmarksButton);
if (visiblity.showItemPanel && NEIClientConfig.showItemQuantityWidget()) {
addWidget(quantity);
addWidget(more);
addWidget(less);
}
if (visiblity.showItemPanel) {
addWidget(itemPanel);
itemPanel.setVisible();
@@ -693,9 +759,13 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
bookmarkPanel.setVisible();
}
searchField.setVisible(visiblity.showSearchSection);
if (visiblity.showSearchSection) {
if (visiblity.showSearchSection && NEIClientConfig.isSearchWidgetCentered()
|| visiblity.showItemPanel && !NEIClientConfig.isSearchWidgetCentered()) {
searchField.setVisible(true);
addWidget(searchField);
} else {
searchField.setVisible(false);
searchField.setFocus(false);
}
if (visiblity.showUtilityButtons) {
@@ -731,10 +801,6 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public static void addWidget(Widget widget) {
drawWidgets.add(widget);
controlWidgets.add(widget);
if (widget instanceof IContainerTooltipHandler) {
tooltipWidgets.add((IContainerTooltipHandler) widget);
}
}
@Override
@@ -750,7 +816,9 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
if (isHidden() || !isEnabled()) return false;
for (Widget widget : drawWidgets) if (widget.onMouseWheel(scrolled, mousex, mousey)) return true;
for (Widget widget : controlWidgets) {
if (widget.onMouseWheel(scrolled, mousex, mousey)) return true;
}
return false;
}
@@ -760,7 +828,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. */
@@ -788,13 +856,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);
});
}
}
@@ -856,11 +922,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
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);
@@ -1,34 +1,20 @@
package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.drawStringC;
import static codechicken.nei.LayoutManager.bookmarkPanel;
import static codechicken.nei.LayoutManager.bookmarksButton;
import static codechicken.nei.LayoutManager.delete;
import static codechicken.nei.LayoutManager.dropDown;
import static codechicken.nei.LayoutManager.gamemode;
import static codechicken.nei.LayoutManager.heal;
import static codechicken.nei.LayoutManager.itemPanel;
import static codechicken.nei.LayoutManager.itemPresenceOverlays;
import static codechicken.nei.LayoutManager.itemZoom;
import static codechicken.nei.LayoutManager.magnet;
import static codechicken.nei.LayoutManager.options;
import static codechicken.nei.LayoutManager.rain;
import static codechicken.nei.LayoutManager.searchField;
import static codechicken.nei.LayoutManager.timeButtons;
import static codechicken.nei.NEIClientConfig.canPerformAction;
import static codechicken.nei.NEIClientConfig.disabledActions;
import static codechicken.nei.NEIClientConfig.getMagnetMode;
import static codechicken.nei.NEIClientConfig.isEnabled;
import net.minecraft.client.gui.inventory.GuiContainer;
import org.lwjgl.opengl.GL11;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.api.LayoutStyle;
import codechicken.nei.drawable.DrawableBuilder;
public class LayoutStyleMinecraft extends LayoutStyle {
protected static final int BUTTON_SIZE = 20;
protected static final int MARGIN = 2;
public int buttonCount;
public int leftSize;
public int numButtons;
@@ -40,19 +26,21 @@ public class LayoutStyleMinecraft extends LayoutStyle {
@Override
public void init() {
delete.icon = new Image(144, 12, 12, 12);
rain.icon = new Image(120, 12, 12, 12);
gamemode.icons[0] = new Image(132, 12, 12, 12);
gamemode.icons[1] = new Image(156, 12, 12, 12);
gamemode.icons[2] = new Image(168, 12, 12, 12);
magnet.icon = new Image(180, 24, 12, 12);
timeButtons[0].icon = new Image(132, 24, 12, 12);
timeButtons[1].icon = new Image(120, 24, 12, 12);
timeButtons[2].icon = new Image(144, 24, 12, 12);
timeButtons[3].icon = new Image(156, 24, 12, 12);
heal.icon = new Image(168, 24, 12, 12);
itemPresenceOverlays[0] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 0, 40, 8, 8).build();
itemPresenceOverlays[1] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 8, 40, 8, 8).build();
LayoutManager.delete.icon = new Image(144, 12, 12, 12);
LayoutManager.rain.icon = new Image(120, 12, 12, 12);
LayoutManager.gamemode.icons[0] = new Image(132, 12, 12, 12);
LayoutManager.gamemode.icons[1] = new Image(156, 12, 12, 12);
LayoutManager.gamemode.icons[2] = new Image(168, 12, 12, 12);
LayoutManager.magnet.icon = new Image(180, 24, 12, 12);
LayoutManager.timeButtons[0].icon = new Image(132, 24, 12, 12);
LayoutManager.timeButtons[1].icon = new Image(120, 24, 12, 12);
LayoutManager.timeButtons[2].icon = new Image(144, 24, 12, 12);
LayoutManager.timeButtons[3].icon = new Image(156, 24, 12, 12);
LayoutManager.heal.icon = new Image(168, 24, 12, 12);
LayoutManager.itemPresenceOverlays[0] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 0, 40, 8, 8)
.build();
LayoutManager.itemPresenceOverlays[1] = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 8, 40, 8, 8)
.build();
}
@Override
@@ -65,85 +53,177 @@ public class LayoutStyleMinecraft extends LayoutStyle {
reset();
leftSize = ItemPanels.bookmarkPanel.getWidth(gui);
numButtons = Math.max(leftSize / 18, 1);
numButtons = Math.max(leftSize / 20, 1);
delete.state = 0x4;
if (NEIController.getDeleteMode()) delete.state |= 1;
else if (!visiblity.enableDeleteMode) delete.state |= 2;
rain.state = 0x4;
if (disabledActions.contains("rain")) rain.state |= 2;
else if (NEIClientUtils.isRaining()) rain.state |= 1;
gamemode.state = 0x4;
if (NEIClientUtils.getGamemode() != 0) {
gamemode.state |= 0x1;
gamemode.index = NEIClientUtils.getGamemode() - 1;
} else {
if (NEIClientUtils.isValidGamemode("creative")) gamemode.index = 0;
else if (NEIClientUtils.isValidGamemode("creative+")) gamemode.index = 1;
else if (NEIClientUtils.isValidGamemode("adventure")) gamemode.index = 2;
LayoutManager.delete.state = 0x4;
if (NEIController.getDeleteMode()) {
LayoutManager.delete.state |= 1;
} else if (!visiblity.enableDeleteMode) {
LayoutManager.delete.state |= 2;
}
bookmarksButton.index = NEIClientConfig.isBookmarkPanelHidden() ? 0 : 1;
options.index = NEIClientConfig.getCheatMode();
magnet.state = 0x4 | (getMagnetMode() ? 1 : 0);
LayoutManager.rain.state = 0x4;
if (NEIClientConfig.disabledActions.contains("rain")) {
LayoutManager.rain.state |= 2;
} else if (NEIClientUtils.isRaining()) {
LayoutManager.rain.state |= 1;
}
if (canPerformAction("delete")) layoutButton(delete);
if (canPerformAction("rain")) layoutButton(rain);
if (NEIClientUtils.isValidGamemode("creative") || NEIClientUtils.isValidGamemode("creative+")
|| NEIClientUtils.isValidGamemode("adventure"))
layoutButton(gamemode);
if (canPerformAction("magnet")) layoutButton(magnet);
if (canPerformAction("time")) {
for (int i = 0; i < 4; i++) {
timeButtons[i].state = disabledActions.contains(NEIActions.timeZones[i]) ? 2 : 0;
layoutButton(timeButtons[i]);
LayoutManager.gamemode.state = 0x4;
if (NEIClientUtils.getGamemode() != 0) {
LayoutManager.gamemode.state |= 0x1;
LayoutManager.gamemode.index = NEIClientUtils.getGamemode() - 1;
} else {
if (NEIClientUtils.isValidGamemode("creative")) {
LayoutManager.gamemode.index = 0;
} else if (NEIClientUtils.isValidGamemode("creative+")) {
LayoutManager.gamemode.index = 1;
} else if (NEIClientUtils.isValidGamemode("adventure")) {
LayoutManager.gamemode.index = 2;
}
}
if (canPerformAction("heal")) layoutButton(heal);
LayoutManager.bookmarksButton.index = NEIClientConfig.isBookmarkPanelHidden() ? 0 : 1;
LayoutManager.options.index = NEIClientConfig.getCheatMode();
itemPanel.resize(gui);
bookmarkPanel.resize(gui);
itemZoom.resize(gui);
LayoutManager.magnet.state = 0x4 | (NEIClientConfig.getMagnetMode() ? 1 : 0);
options.x = isEnabled() ? 0 : 6;
options.y = isEnabled() ? gui.height - 22 : gui.height - 28;
options.w = 22;
options.h = 22;
if (NEIClientConfig.canPerformAction("delete")) {
layoutButton(LayoutManager.delete);
}
bookmarksButton.x = 24 + (isEnabled() ? 0 : 6);
bookmarksButton.y = isEnabled() ? gui.height - 22 : gui.height - 28;
bookmarksButton.w = 22;
bookmarksButton.h = 22;
if (NEIClientConfig.canPerformAction("rain")) {
layoutButton(LayoutManager.rain);
}
dropDown.h = 18;
dropDown.w = 150;
dropDown.y = 0;
dropDown.x = (gui.width - gui.xSize) / 2 + gui.xSize - dropDown.w;
if (NEIClientUtils.isValidGamemode("creative") || NEIClientUtils.isValidGamemode("creative+")
|| NEIClientUtils.isValidGamemode("adventure")) {
layoutButton(LayoutManager.gamemode);
}
searchField.h = 20;
if (NEIClientConfig.isSearchWidgetCentered()) {
searchField.w = 150;
searchField.x = (gui.width - searchField.w) / 2;
if (NEIClientConfig.canPerformAction("magnet")) {
layoutButton(LayoutManager.magnet);
}
if (NEIClientConfig.canPerformAction("time")) {
for (int i = 0; i < 4; i++) {
LayoutManager.timeButtons[i].state = NEIClientConfig.disabledActions.contains(NEIActions.timeZones[i])
? 2
: 0;
layoutButton(LayoutManager.timeButtons[i]);
}
}
if (NEIClientConfig.canPerformAction("heal")) {
layoutButton(LayoutManager.heal);
}
layoutFooter(gui, visiblity);
LayoutManager.itemPanel.resize(gui);
LayoutManager.bookmarkPanel.resize(gui);
LayoutManager.itemZoom.resize(gui);
}
protected void layoutFooter(GuiContainer gui, VisiblityData visiblity) {
LayoutManager.options.x = MARGIN;
LayoutManager.options.y = gui.height - BUTTON_SIZE - MARGIN;
LayoutManager.options.w = LayoutManager.options.h = BUTTON_SIZE;
LayoutManager.bookmarksButton.x = LayoutManager.options.x + LayoutManager.options.w + MARGIN;
LayoutManager.bookmarksButton.y = gui.height - BUTTON_SIZE - MARGIN;
LayoutManager.bookmarksButton.w = LayoutManager.bookmarksButton.h = BUTTON_SIZE;
final Rectangle4i searchArea = getSearchFieldArea(gui);
final Rectangle4i quantityArea = getQuantityFieldArea(visiblity);
LayoutManager.searchField.x = searchArea.x;
LayoutManager.searchField.y = searchArea.y;
LayoutManager.searchField.w = searchArea.w;
LayoutManager.searchField.h = searchArea.h;
if (!NEIClientConfig.subsetWidgetOnTop() && visiblity.showSubsetDropdown) {
LayoutManager.dropDown.x = searchArea.x;
LayoutManager.dropDown.y = searchArea.y;
LayoutManager.dropDown.h = LayoutManager.dropDown.w = BUTTON_SIZE;
LayoutManager.searchField.x += BUTTON_SIZE;
LayoutManager.searchField.w -= BUTTON_SIZE;
} else {
searchField.w = (int) (itemPanel.w * (NEIClientConfig.showItemQuantityWidget() ? 0.7 : 1));
searchField.x = itemPanel.x;
LayoutManager.dropDown.h = 16;
LayoutManager.dropDown.w = 150;
LayoutManager.dropDown.y = MARGIN;
LayoutManager.dropDown.x = (gui.width - LayoutManager.dropDown.w) / 2;
}
searchField.y = gui.height - searchField.h - 2;
if (!visiblity.showItemSection) {
searchField.setFocus(false);
if (quantityArea.w == ItemPanels.itemPanel.w) {
LayoutManager.more.w = LayoutManager.less.w = BUTTON_SIZE;
LayoutManager.more.h = LayoutManager.less.h = LayoutManager.quantity.h = quantityArea.h;
LayoutManager.more.y = LayoutManager.less.y = LayoutManager.quantity.y = quantityArea.y;
LayoutManager.less.x = quantityArea.x;
LayoutManager.more.x = quantityArea.x2() - BUTTON_SIZE;
LayoutManager.quantity.x = LayoutManager.less.x + LayoutManager.less.w + 1;
LayoutManager.quantity.w = LayoutManager.more.x - LayoutManager.quantity.x - 1;
} else {
LayoutManager.quantity.x = quantityArea.x;
LayoutManager.quantity.w = quantityArea.w - 18;
LayoutManager.quantity.y = LayoutManager.more.y = quantityArea.y;
LayoutManager.quantity.h = quantityArea.h;
LayoutManager.more.w = LayoutManager.less.w = 18;
LayoutManager.more.x = LayoutManager.less.x = LayoutManager.quantity.x + LayoutManager.quantity.w;
LayoutManager.more.h = LayoutManager.less.h = LayoutManager.quantity.h / 2;
LayoutManager.less.y = LayoutManager.more.y + LayoutManager.more.h;
}
}
private Rectangle4i getSearchFieldArea(GuiContainer gui) {
final Rectangle4i area = new Rectangle4i(0, 0, 0, BUTTON_SIZE);
if (NEIClientConfig.isSearchWidgetCentered()) {
area.w = Math.min(gui.xSize, 176) - MARGIN * 2;
area.x = (gui.width - area.w) / 2;
area.y = gui.height - BUTTON_SIZE - MARGIN;
} else if (NEIClientConfig.showItemQuantityWidget()) {
area.w = ItemPanels.itemPanel.w - (int) Math.max(BUTTON_SIZE * 2.5f, ItemPanels.itemPanel.w * 0.3f) - 1;
area.x = ItemPanels.itemPanel.x;
area.y = ItemPanels.itemPanel.y + ItemPanels.itemPanel.h - BUTTON_SIZE;
} else {
area.w = ItemPanels.itemPanel.w;
area.x = ItemPanels.itemPanel.x;
area.y = ItemPanels.itemPanel.y + ItemPanels.itemPanel.h - BUTTON_SIZE;
}
return area;
}
private Rectangle4i getQuantityFieldArea(VisiblityData visiblity) {
final Rectangle4i area = new Rectangle4i(0, 0, 0, BUTTON_SIZE);
if (!visiblity.showSearchSection || NEIClientConfig.isSearchWidgetCentered()) {
area.w = ItemPanels.itemPanel.w;
area.x = ItemPanels.itemPanel.x;
} else {
area.w = (int) Math.max(BUTTON_SIZE * 2.5f, ItemPanels.itemPanel.w * 0.3f);
area.x = ItemPanels.itemPanel.x + ItemPanels.itemPanel.w - area.w;
}
area.y = ItemPanels.itemPanel.y + ItemPanels.itemPanel.h - BUTTON_SIZE;
return area;
}
public void layoutButton(Button button) {
button.x = 2 + (buttonCount % numButtons) * 19;
button.y = 2 + (buttonCount / numButtons) * 18;
button.h = 17;
button.w = button.contentWidth() + 6;
button.x = MARGIN + (buttonCount % numButtons) * (button.w + MARGIN);
button.y = MARGIN + (buttonCount / numButtons) * (button.h + MARGIN);
buttonCount++;
}
@@ -177,9 +257,16 @@ public class LayoutStyleMinecraft extends LayoutStyle {
@Override
public void drawSubsetTag(String text, int x, int y, int w, int h, int state, boolean mouseover) {
if (state == 1) GL11.glColor4f(0.65F, 0.65F, 0.65F, 1.0F);
else GL11.glColor4f(1, 1, 1, 1);
if (state == 1) {
GL11.glColor4f(0.65F, 0.65F, 0.65F, 1.0F);
} else {
GL11.glColor4f(1, 1, 1, 1);
}
LayoutManager.drawButtonBackground(x, y, w, h, false, state == 0 ? 0 : 1);
if (text != null) drawStringC(text, x, y, w, h, state == 2 ? 0xFFE0E0E0 : 0xFFA0A0A0);
if (text != null) {
drawStringC(text, x, y, w, h, mouseover ? 0xFFFFFFA0 : (state == 2 ? 0xFFE0E0E0 : 0xFFA0A0A0));
}
}
}
@@ -186,6 +186,12 @@ public class NEICPH implements IClientPacketHandler {
packet.sendToServer();
}
public static void sendChatLink(ItemStack stackover) {
PacketCustom packet = new PacketCustom(channel, C2S.SEND_CHAT_ITEM_LINK);
packet.writeItemStack(stackover);
packet.sendToServer();
}
public static void sendOpenEnchantmentWindow() {
PacketCustom packet = new PacketCustom(channel, C2S.REQUEST_ENCHANTMENT_GUI);
packet.sendToServer();
@@ -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;
@@ -61,6 +60,7 @@ import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.IRecipeHandler;
import codechicken.nei.recipe.RecipeCatalysts;
import codechicken.nei.recipe.RecipeInfo;
import codechicken.nei.util.NEIKeyboardUtils;
import codechicken.obfuscator.ObfuscationRun;
public class NEIClientConfig {
@@ -145,6 +145,8 @@ public class NEIClientConfig {
tag.getTag("inventory.widgetsenabled").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.widgetsenabled"));
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 +180,7 @@ public class NEIClientConfig {
@Override
public boolean onClick(int button) {
super.onClick(button);
ItemPanels.bookmarkPanel.save();
ItemPanels.bookmarkPanel.load();
return true;
}
@@ -191,16 +194,28 @@ 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.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.guirecipe.jeiStyleTabs").setComment("Enable/disable JEI Style Tabs")
.getBooleanValue(true);
API.addOption(new OptionToggleButtonBoubs("inventory.guirecipe.jeiStyleTabs", true));
@@ -236,12 +251,18 @@ public class NEIClientConfig {
tag.getTag("inventory.guirecipe.profile").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.guirecipe.profile", 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.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"));
API.addOption(new OptionIntegerField("inventory.history.historyColor", 0, OptionIntegerField.UNSIGNED_INT_MAX));
tag.getTag("inventory.history.useRows").setComment("Rows used in historical areas").getIntValue(2);
API.addOption(new OptionIntegerField("inventory.history.useRows", 1, 5));
@@ -267,24 +288,19 @@ public class NEIClientConfig {
tag.getTag("inventory.collapsibleItems.expandedColor")
.setComment("Color of the collapsible item expanded state").getHexValue(0x335555EE);
API.addOption(new OptionIntegerField("inventory.collapsibleItems.expandedColor"));
API.addOption(
new OptionIntegerField(
"inventory.collapsibleItems.expandedColor",
0,
OptionIntegerField.UNSIGNED_INT_MAX));
tag.getTag("inventory.collapsibleItems.collapsedColor")
.setComment("Color of the collapsible item collapsed state").getHexValue(0x335555EE);
API.addOption(new OptionIntegerField("inventory.collapsibleItems.collapsedColor"));
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);
}
});
new OptionIntegerField(
"inventory.collapsibleItems.collapsedColor",
0,
OptionIntegerField.UNSIGNED_INT_MAX));
tag.getTag("inventory.itemzoom.enabled").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.itemzoom.enabled", true));
@@ -309,7 +325,9 @@ public class NEIClientConfig {
API.addOption(new OptionToggleButton("inventory.itemzoom.showName", true));
tag.getTag("inventory.itemzoom.nameColor").getHexValue(0xFFFFFFFF);
API.addOption(new OptionIntegerField("inventory.itemzoom.nameColor"));
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));
@@ -333,6 +351,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));
@@ -345,9 +376,22 @@ public class NEIClientConfig {
}
});
tag.getTag("inventory.cacheItemRendering").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.cacheItemRendering", true));
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("loadPluginsInParallel").getBooleanValue(true);
tag.getTag("itemLoadingTimeout").getIntValue(500);
tag.getTag("command.creative").setDefaultValue("/gamemode {0} {1}");
@@ -368,6 +412,9 @@ 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("tools.handler_load_from_config").setComment("ADVANCED: Load handlers from config")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("tools.handler_load_from_config", true) {
@@ -425,6 +472,18 @@ public class NEIClientConfig {
tag.getTag("inventory.search.widgetPosition").setComment("Widget Position").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.search.widgetPosition", true));
tag.getTag("inventory.search.hideUntilSearching").setComment("Hide Items Until Searching")
.getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.search.hideUntilSearching", true) {
@Override
public boolean onClick(int button) {
super.onClick(button);
ItemList.updateFilter.restart();
return true;
}
});
tag.getTag("inventory.search.widgetAutofocus")
.setComment(
"Focus Search Widget on Open, blurs/unfocuses on mouse move unless typing has started first")
@@ -457,6 +516,7 @@ public class NEIClientConfig {
}
if (state()) {
NEIClientConfig.setIntSetting("inventory.search.spaceMode", 1);
NEIClientConfig.setIntSetting("inventory.search.modNameSearchMode", 0);
NEIClientConfig.setIntSetting("inventory.search.tooltipSearchMode", 0);
NEIClientConfig.setIntSetting("inventory.search.identifierSearchMode", 0);
@@ -468,6 +528,7 @@ public class NEIClientConfig {
SearchField.searchParser.prefixRedefinitions.put('@', '%');
SearchField.searchParser.clearCache();
} else {
NEIClientConfig.setIntSetting("inventory.search.spaceMode", 0);
NEIClientConfig.setIntSetting("inventory.search.modNameSearchMode", 1);
NEIClientConfig.setIntSetting("inventory.search.tooltipSearchMode", 0);
NEIClientConfig.setIntSetting("inventory.search.identifierSearchMode", 0);
@@ -483,6 +544,22 @@ public class NEIClientConfig {
});
tag.getTag("inventory.search.spaceMode").setComment("Search Space Rules").getIntValue(0);
API.addOption(new OptionCycled("inventory.search.spaceMode", 3, true) {
@Override
public boolean onClick(int button) {
// SearchField.searchParser.clearCache();
return super.onClick(button);
}
@Override
public boolean isEnabled() {
return !tag.getTag("inventory.search.format").getBooleanValue();
}
});
tag.getTag("inventory.search.modNameSearchMode").setComment("Search mode for Mod Names (prefix: @)")
.getIntValue(1);
API.addOption(new OptionCycled("inventory.search.modNameSearchMode", 3, true) {
@@ -621,6 +698,36 @@ public class NEIClientConfig {
}
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.save();
FavoriteRecipes.load();
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.depth").setComment("Bookmark creation depth").getIntValue(3);
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);
@@ -635,22 +742,15 @@ public class NEIClientConfig {
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.addKeyBind("gui.bookmark", Keyboard.KEY_A);
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.addKeyBind("gui.bookmark_pull_items", Keyboard.KEY_V);
API.addKeyBind("gui.overlay", Keyboard.KEY_S);
API.addKeyBind("gui.craft_items", Keyboard.KEY_C);
API.addHashBind("gui.hide_bookmarks", Keyboard.KEY_B);
API.addKeyBind("gui.getprevioussearch", Keyboard.KEY_UP);
API.addKeyBind("gui.getnextsearch", Keyboard.KEY_DOWN);
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);
@@ -669,6 +769,7 @@ public class NEIClientConfig {
API.addKeyBind("world.creative", 0);
API.addHashBind("gui.copy_name", Keyboard.KEY_C + NEIClientUtils.CTRL_HASH);
API.addHashBind("gui.copy_oredict", Keyboard.KEY_D + NEIClientUtils.CTRL_HASH);
API.addHashBind("gui.chat_link_item", Keyboard.KEY_L + NEIClientUtils.CTRL_HASH);
}
public static OptionList getOptionList() {
@@ -677,23 +778,24 @@ public class NEIClientConfig {
public static void loadWorld(String worldPath) {
unloadWorld();
NEIClientConfig.worldPath = worldPath;
setInternalEnabled(true);
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 (!worldPath.equals(NEIClientConfig.worldPath)) {
NEIClientConfig.worldPath = worldPath;
if (newWorld) {
specificDir.mkdirs();
logger.debug("Loading " + (Minecraft.getMinecraft().isSingleplayer() ? "Local" : "Remote") + " World");
final File specificDir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
final boolean newWorld = !specificDir.exists();
if (newWorld) {
specificDir.mkdirs();
}
world = new ConfigSet(new File(specificDir, "NEI.dat"), new ConfigFile(new File(specificDir, "NEI.cfg")));
bootNEI();
onWorldLoad(newWorld);
}
world = new ConfigSet(new File(specificDir, "NEI.dat"), new ConfigFile(new File(specificDir, "NEI.cfg")));
bootNEI(ClientUtils.getWorld());
CollapsibleItems.load();
ItemPanels.bookmarkPanel.load();
onWorldLoad(newWorld);
}
public static String getWorldPath() {
@@ -707,11 +809,12 @@ public class NEIClientConfig {
setWorldDefaults();
creativeInv = new ItemStack[54];
LayoutManager.searchField.setText(getSearchExpression());
ItemPanels.itemPanel.quantity.setText(Integer.toString(getItemQuantity()));
SubsetWidget.loadHidden();
LayoutManager.quantity.setText(Integer.toString(getItemQuantity()));
if (newWorld && Minecraft.getMinecraft().isSingleplayer()) world.config.getTag("inventory.cheatmode")
.setIntValue(NEIClientUtils.mc().playerController.isInCreativeMode() ? 2 : 0);
if (newWorld && Minecraft.getMinecraft().isSingleplayer()) {
world.config.getTag("inventory.cheatmode")
.setIntValue(NEIClientUtils.mc().playerController.isInCreativeMode() ? 2 : 0);
}
NEIInfo.load(ClientUtils.getWorld());
}
@@ -727,9 +830,11 @@ public class NEIClientConfig {
public static void unloadWorld() {
if (ItemPanels.bookmarkPanel != null) {
ItemPanels.bookmarkPanel.saveBookmarks();
ItemPanels.bookmarkPanel.save();
}
SubsetWidget.saveHidden();
FavoriteRecipes.save();
CollapsibleItems.saveStates();
if (world != null) {
@@ -740,7 +845,7 @@ public class NEIClientConfig {
private static final Map<String, String> keySettings = new HashMap<>();
public static int getKeyBinding(String string) {
final String key = keySettings.computeIfAbsent(string, (s) -> "keys." + s);
final String key = keySettings.computeIfAbsent(string, s -> "keys." + s);
return getSetting(key).getIntValue(Keyboard.KEY_NONE);
}
@@ -750,23 +855,44 @@ public class NEIClientConfig {
public static boolean isKeyHashDown(String string) {
final int hash = getKeyBinding(string);
return hash != Keyboard.CHAR_NONE && hash == NEIClientUtils.getKeyHash();
if (hash != Keyboard.CHAR_NONE && Keyboard.getEventKeyState()) {
return KeyManager.keyStates.containsKey(string) ? hash == Keyboard.getEventKey()
: hash == NEIClientUtils.getKeyHash();
}
return false;
}
public static String getKeyName(String keyBind) {
return getKeyName(keyBind, 0);
}
public static String getKeyName(String keyBind, int meta, int mouseBind) {
final int hash = getKeyBinding(keyBind);
if (hash == Keyboard.CHAR_NONE) {
return null;
}
return NEIClientUtils.getKeyName(hash);
return NEIClientUtils.getKeyName(hash + meta, mouseBind);
}
public static void bootNEI(World world) {
public static String getKeyName(String keyBind, int meta) {
final int hash = getKeyBinding(keyBind);
if (hash == Keyboard.CHAR_NONE) {
return null;
}
return NEIKeyboardUtils.getKeyName(hash + meta);
}
public static void bootNEI() {
if (!mainNEIConfigLoaded) {
// main NEI config loading
ItemInfo.load(world);
ItemInfo.load();
GuiInfo.load();
RecipeInfo.load();
HeldItemHandler.load();
@@ -779,8 +905,11 @@ public class NEIClientConfig {
@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();
@@ -792,7 +921,10 @@ public class NEIClientConfig {
});
RecipeCatalysts.loadCatalystInfo();
SubsetWidget.loadHidden();
CollapsibleItems.load();
ItemSorter.loadConfig();
FavoriteRecipes.load();
// Set pluginNEIConfigLoaded here before posting the NEIConfigsLoadedEvent. This used to be the
// other way around, but apparently if your modpack includes 800 mods the event poster might not
@@ -806,8 +938,10 @@ public class NEIClientConfig {
}
}.start();
} else {
SubsetWidget.loadHidden();
ItemList.loadItems.restart();
}
}
public static boolean isWorldSpecific(String setting) {
@@ -828,6 +962,14 @@ public class NEIClientConfig {
return !enabledOverride || getBooleanSetting("inventory.hidden");
}
public static boolean autocraftingEnabled() {
return getBooleanSetting("inventory.autocrafting");
}
public static boolean favoritesEnabled() {
return getBooleanSetting("inventory.favorites.enabled");
}
public static boolean isBookmarkPanelHidden() {
return !getBooleanSetting("inventory.bookmarks.enabled");
}
@@ -840,18 +982,38 @@ 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() {
return getBooleanSetting("inventory.showItemQuantityWidget");
}
public static boolean hideItemsUntilSearching() {
return getBooleanSetting("inventory.search.hideUntilSearching");
}
public static boolean isSearchWidgetCentered() {
return getBooleanSetting("inventory.search.widgetPosition");
}
public static boolean showSubsetWidget() {
return getBooleanSetting("inventory.subsets.enabled");
}
public static boolean subsetWidgetOnTop() {
return getBooleanSetting("inventory.subsets.widgetPosition");
}
public static int searchWidgetAutofocus() {
return getIntSetting("inventory.search.widgetAutofocus");
}
@@ -880,8 +1042,8 @@ 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() {
@@ -1000,8 +1162,8 @@ public class NEIClientConfig {
return getBooleanSetting("inventory.history.enabled");
}
public static boolean shouldCacheItemRendering() {
return getBooleanSetting("inventory.cacheItemRendering") && OpenGlHelper.framebufferSupported;
public static int getGridRenderingCacheMode() {
return OpenGlHelper.framebufferSupported ? getIntSetting("inventory.gridRenderingCacheMode") : 0;
}
public static boolean enableCollapsibleItems() {
+116 -50
View File
@@ -8,6 +8,7 @@ import static codechicken.nei.NEIClientConfig.hasSMPCounterPart;
import static codechicken.nei.NEIClientConfig.invCreativeMode;
import static codechicken.nei.NEIClientConfig.world;
import java.awt.Color;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigInteger;
@@ -32,6 +33,8 @@ 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;
@@ -41,41 +44,61 @@ import net.minecraft.util.IChatComponent;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import com.google.common.collect.Iterables;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.inventory.InventoryRange;
import codechicken.lib.inventory.InventoryUtils;
import codechicken.lib.util.LangProxy;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.IInfiniteItemHandler;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.util.NEIKeyboardUtils;
import codechicken.nei.util.NEIMouseUtils;
public class NEIClientUtils extends NEIServerUtils {
public static class Alignment {
public final int x, y;
public static final Alignment TopLeft = new Alignment(-1, -1);
public static final Alignment TopCenter = new Alignment(0, -1);
public static final Alignment TopRight = new Alignment(1, -1);
public static final Alignment CenterLeft = new Alignment(-1, 0);
public static final Alignment Center = new Alignment(0, 0);
public static final Alignment CenterRight = new Alignment(1, 0);
public static final Alignment BottomLeft = new Alignment(-1, 1);
public static final Alignment BottomCenter = new Alignment(0, 1);
public static final Alignment BottomRight = new Alignment(1, 1);
public Alignment(int x, int y) {
this.x = x;
this.y = y;
}
public float getX(float parentWidth, float childWidth) {
final float x = (this.x + 1) / 2f;
return parentWidth * x - childWidth * x;
}
public float getY(float parentHeight, float childHeight) {
final float y = (this.y + 1) / 2f;
return parentHeight * y - childHeight * y;
}
}
public static LangProxy lang = new LangProxy("nei");
/** Formats a number with group separator and at most 2 fraction digits. */
private static final Map<Locale, DecimalFormat> decimalFormatters = new HashMap<>();
private static final Map<Integer, Integer> keyHashMap = new HashMap<>();
public static final int ALT_HASH = 1 << 27;
public static final int SHIFT_HASH = 1 << 26;
public static final int CTRL_HASH = 1 << 25;
static {
keyHashMap.put(Keyboard.KEY_LSHIFT, SHIFT_HASH);
keyHashMap.put(Keyboard.KEY_RSHIFT, SHIFT_HASH);
keyHashMap.put(Keyboard.KEY_LCONTROL, CTRL_HASH);
keyHashMap.put(Keyboard.KEY_LCONTROL, CTRL_HASH);
keyHashMap.put(Keyboard.KEY_LMETA, CTRL_HASH);
keyHashMap.put(Keyboard.KEY_RMETA, CTRL_HASH);
keyHashMap.put(Keyboard.KEY_LMENU, ALT_HASH);
keyHashMap.put(Keyboard.KEY_LMENU, ALT_HASH);
}
public static 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();
@@ -322,7 +345,7 @@ public class NEIClientUtils extends NEIServerUtils {
}
public static void sendCommand(String command, Object... args) {
if (command.length() == 0) return;
if (command.isEmpty()) return;
NumberFormat numberformat = NumberFormat.getIntegerInstance();
numberformat.setGroupingUsed(false);
@@ -347,6 +370,10 @@ public class NEIClientUtils extends NEIServerUtils {
else sendCommand(getStringSetting("command.heal"), mc().thePlayer.getCommandSenderName());
}
public static void sendChatItemLink(ItemStack stackover) {
if (hasSMPCounterPart()) NEICPH.sendChatLink(stackover);
}
public static void toggleMagnetMode() {
if (hasSMPCounterPart()) NEICPH.sendToggleMagnetMode();
}
@@ -452,7 +479,7 @@ public class NEIClientUtils extends NEIServerUtils {
if (Keyboard.getEventKeyState()) {
final int keycode = Keyboard.getEventKey();
if (!keyHashMap.containsKey(keycode)) {
if (!NEIKeyboardUtils.isHashKey(keycode)) {
return getMetaHash() + keycode;
}
}
@@ -460,45 +487,22 @@ public class NEIClientUtils extends NEIServerUtils {
return Keyboard.CHAR_NONE;
}
public static String getKeyHashName(int keyBind) {
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 ((keyBind & CTRL_HASH) != 0) {
keyText.add(translate(Minecraft.isRunningOnMac ? "key.ctrl.mac" : "key.ctrl"));
if (!keyHash.isEmpty()) {
keyText.add(keyHash);
}
if ((keyBind & SHIFT_HASH) != 0) {
keyText.add(translate("key.shift"));
}
if ((keyBind & ALT_HASH) != 0) {
keyText.add(translate("key.alt"));
if (!mouseHash.isEmpty()) {
keyText.add(mouseHash);
}
return keyText.toString();
}
public static String getKeyName(int keyBind) {
keyBind = keyHashMap.getOrDefault(keyBind, keyBind);
StringJoiner keyText = new StringJoiner(" + ");
String hashText = getKeyHashName(keyBind);
int keyID = unHashKey(keyBind);
if (!hashText.isEmpty()) {
keyText.add(hashText);
}
if (keyID != Keyboard.CHAR_NONE || hashText.isEmpty()) {
keyText.add(Keyboard.getKeyName(keyID));
}
return keyText.toString();
}
public static int unHashKey(int keyBind) {
return keyBind & ~(CTRL_HASH | SHIFT_HASH | ALT_HASH);
}
public static void playClickSound() {
mc().getSoundHandler()
.playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F));
@@ -522,4 +526,66 @@ public class NEIClientUtils extends NEIServerUtils {
reportErrorBuffered(e, buffer, "null");
}
}
public static void drawRect(double left, double top, double width, double height, Color color) {
Tessellator tessellator = Tessellator.instance;
GL11.glEnable(GL11.GL_BLEND);
GL11.glDisable(GL11.GL_TEXTURE_2D);
OpenGlHelper.glBlendFunc(770, 771, 1, 0);
GL11.glColor4f(color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
tessellator.startDrawingQuads();
tessellator.addVertex(left, top + height, 0.0D);
tessellator.addVertex(left + width, top + height, 0.0D);
tessellator.addVertex(left + width, top, 0.0D);
tessellator.addVertex(left, top, 0.0D);
tessellator.draw();
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_BLEND);
}
public static void drawNEIOverlayText(String text, Rectangle4i rect, float scale, int color, boolean shadow,
Alignment alignment) {
final float screenScale = mc().currentScreen.width * 1f / mc().displayWidth;
final double smallTextScale = Math
.max(screenScale, (Math.max(scale, 1f) * (GuiDraw.fontRenderer.getUnicodeFlag() ? 3F / 4F : 1F / 2F)));
NEIClientUtils.gl2DRenderContext(() -> {
final int width = GuiDraw.fontRenderer.getStringWidth(text);
final float partW = rect.w / 2f;
final float partH = rect.h / 2f;
final double offsetX = Math
.ceil(rect.x + partW + partW * alignment.x - (width / 2f * (alignment.x + 1)) * smallTextScale);
final double offsetY = Math.ceil(
rect.y + partH
+ partH * alignment.y
- (GuiDraw.fontRenderer.FONT_HEIGHT / 2f * (alignment.y + 1)) * smallTextScale);
GL11.glTranslated(offsetX, offsetY, 0);
GL11.glScaled(smallTextScale, smallTextScale, 1);
GuiDraw.fontRenderer.drawString(text, 0, 0, color, shadow);
GL11.glScaled(1 / smallTextScale, 1 / smallTextScale, 1);
GL11.glTranslated(-1 * offsetX, -1 * offsetY, 0);
});
}
public static void drawNEIOverlayText(String text, int x, int y) {
drawNEIOverlayText(text, new Rectangle4i(x, y, 16, 16), 0.5f, 0xFDD835, false, Alignment.TopLeft);
}
public static void gl2DRenderContext(Runnable callback) {
boolean isLighting = GL11.glGetBoolean(GL11.GL_LIGHTING);
boolean isDepthTest = GL11.glGetBoolean(GL11.GL_DEPTH_TEST);
boolean isAlphaTest = GL11.glGetBoolean(GL11.GL_ALPHA_TEST);
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_ALPHA_TEST);
GL11.glDisable(GL11.GL_DEPTH_TEST);
callback.run();
if (isLighting) GL11.glEnable(GL11.GL_LIGHTING);
if (isDepthTest) GL11.glEnable(GL11.GL_DEPTH_TEST);
if (!isAlphaTest) GL11.glDisable(GL11.GL_ALPHA_TEST);
}
}
@@ -11,16 +11,21 @@ import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.inventory.SlotCrafting;
import net.minecraft.item.ItemStack;
import net.minecraftforge.client.ClientCommandHandler;
import codechicken.core.CommonUtils;
import codechicken.nei.api.API;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.IInfiniteItemHandler;
import codechicken.nei.api.INEIGuiHandler;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.commands.CommandBookmarkAdd;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.guihook.IContainerSlotClickHandler;
import codechicken.nei.recipe.GuiRecipe;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class NEIController implements IContainerSlotClickHandler, IContainerInputHandler {
@@ -39,6 +44,8 @@ public class NEIController implements IContainerSlotClickHandler, IContainerInpu
public static void load() {
GuiContainerManager.addSlotClickHandler(instance);
GuiContainerManager.addInputHandler(instance);
if (CommonUtils.isClient()) registerClientCommands();
}
public static void load(GuiContainer gui) {
@@ -56,6 +63,11 @@ 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());
}
public static void updateUnlimitedItems(InventoryPlayer inventory) {
if (!NEIClientConfig.canPerformAction("item") || !NEIClientConfig.hasSMPCounterPart()) return;
@@ -1,6 +1,7 @@
package codechicken.nei;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
@@ -24,6 +25,7 @@ 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;
@@ -38,6 +40,9 @@ public class NEIModContainer extends DummyModContainer {
public static LinkedList<IConfigureNEI> plugins = new LinkedList<>();
private static boolean gregTech5Loaded;
private static boolean gtnhLibLoaded;
private static ASMDataTable asmDataTable;
public NEIModContainer() {
super(getModMetadata());
@@ -59,16 +64,23 @@ public class NEIModContainer extends DummyModContainer {
return gregTech5Loaded;
}
public static boolean isGTNHLibLoaded() {
return gtnhLibLoaded;
}
@Override
public Set<ArtifactVersion> getRequirements() {
Set<ArtifactVersion> deps = new HashSet<>();
deps.add(VersionParser.parseVersionReference("CodeChickenCore@[" + CodeChickenCorePlugin.version + ",)"));
deps.add(VersionParser.parseVersionReference("CodeChickenCore@[" + codechicken.core.asm.Tags.VERSION + ",)"));
return deps;
}
@Override
public List<ArtifactVersion> getDependencies() {
return new LinkedList<>(getRequirements());
List<ArtifactVersion> deps = new ArrayList<>();
deps.add(VersionParser.parseVersionReference("CodeChickenCore@[" + codechicken.core.asm.Tags.VERSION + ",)"));
deps.add(VersionParser.parseVersionReference("gtnhlib@[0.6.0,)"));
return deps;
}
private String description;
@@ -106,7 +118,9 @@ public class NEIModContainer extends DummyModContainer {
@Subscribe
public void preInit(FMLPreInitializationEvent event) {
gregTech5Loaded = Loader.isModLoaded("gregtech") && !Loader.isModLoaded("gregapi_post");
gtnhLibLoaded = Loader.isModLoaded("gtnhlib");
if (CommonUtils.isClient()) ClientHandler.preInit();
asmDataTable = event.getAsmData();
}
@Subscribe
@@ -129,6 +143,7 @@ public class NEIModContainer extends DummyModContainer {
GuiRecipeTab.loadHandlerInfo();
ClientHandler.loadPluginsList();
ClientHandler.loadHandlerOrdering();
asmDataTable = null;
}
}
@@ -151,4 +166,8 @@ public class NEIModContainer extends DummyModContainer {
public Class<?> getCustomResourcePackClass() {
return getSource().isDirectory() ? FMLFolderResourcePack.class : FMLFileResourcePack.class;
}
public static ASMDataTable getAsmDataTable() {
return asmDataTable;
}
}
@@ -88,9 +88,16 @@ public class NEISPH implements IServerPacketHandler {
case C2S.SET_DUMMY_SLOT:
handleDummySlotSet(sender, packet);
break;
case C2S.SEND_CHAT_ITEM_LINK:
handleSendChatItemLink(sender, packet);
break;
}
}
private void handleSendChatItemLink(EntityPlayerMP sender, PacketCustom packet) {
NEIServerUtils.sendChatItemLink(sender, packet.readItemStack());
}
private void handleDummySlotSet(EntityPlayerMP sender, PacketCustom packet) {
int slotNumber = packet.readShort();
ItemStack stack = packet.readItemStack(true);
@@ -21,6 +21,8 @@ import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.permission.PermissionLevel;
import net.minecraftforge.permission.PermissionManager;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
@@ -44,6 +46,8 @@ public class NEIServerConfig {
public static HashMap<String, PlayerSave> playerSaves = new HashMap<>();
public static ItemStackMap<Set<String>> bannedItems = new ItemStackMap<>();
private static boolean doesPermAPIExist = false;
public static void load(World world) {
if (MinecraftServer.getServer() != server) {
logger.debug("Loading NEI Server");
@@ -53,6 +57,16 @@ public class NEIServerConfig {
dimTags.clear();
loadConfig();
loadBannedItems();
try {
Class.forName("net.minecraftforge.permission.PermissionManager");
doesPermAPIExist = true;
NEIActions.baseActions().forEach(
action -> {
PermissionManager.registerPermission("nei.permissions." + action, PermissionLevel.OP);
});
} catch (ClassNotFoundException ignored) {}
}
loadWorld(world);
}
@@ -121,7 +135,12 @@ public class NEIServerConfig {
}
public static boolean canPlayerPerformAction(String playername, String name) {
return isPlayerInList(playername, getPlayerList("permissions." + NEIActions.base(name)), true);
String node = "permissions." + NEIActions.base(name);
boolean hasPerm = doesPermAPIExist
? PermissionManager.checkPermission(ServerUtils.getPlayer(playername), "nei." + node)
: false;
return hasPerm || isPlayerInList(playername, getPlayerList(node), true);
}
public static boolean isPlayerInList(String playername, Set<String> list, boolean allowCards) {
@@ -197,7 +216,7 @@ public class NEIServerConfig {
FileReader r = new FileReader(file);
int line = 0;
for (String s : IOUtils.readLines(r)) {
if (s.charAt(0) == '#' || s.trim().length() == 0) continue;
if (s.charAt(0) == '#' || s.trim().isEmpty()) continue;
int delim = s.lastIndexOf('=');
if (delim < 0) {
logger.error("line " + line + ": Missing =");
@@ -17,6 +17,7 @@ import net.minecraft.enchantment.Enchantment;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.event.ClickEvent;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@@ -46,9 +47,22 @@ import codechicken.nei.PacketIDs.S2C;
import codechicken.nei.util.NBTHelper;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.relauncher.ReflectionHelper;
public class NEIServerUtils {
private static Class<?> gtMetaBaseItem;
static {
try {
final ClassLoader loader = NEIServerUtils.class.getClassLoader();
NEIServerUtils.gtMetaBaseItem = ReflectionHelper
.getClass(loader, "gregtech.api.items.MetaBaseItem", "gregtech.api.items.GT_MetaBase_Item");
} catch (Exception ignored) {
/* Do nothing */
}
}
public static boolean isRaining(World world) {
return world.getWorldInfo().isRaining();
}
@@ -69,6 +83,18 @@ public class NEIServerUtils {
player.extinguish();
}
public static void sendChatItemLink(EntityPlayerMP sender, ItemStack stackover) {
ServerUtils.sendChatToAll(
new ChatComponentTranslation(
"nei.chat.item_link.text",
sender.getDisplayName(),
stackover.func_151000_E().setChatStyle(
stackover.func_151000_E().getChatStyle().setChatClickEvent(
new ClickEvent(
ClickEvent.Action.RUN_COMMAND,
"/nei_bookmark " + stackover.writeToNBT(new NBTTagCompound()))))));
}
public static long getTime(World world) {
return world.getWorldInfo().getWorldTime();
}
@@ -146,7 +172,7 @@ public class NEIServerUtils {
/**
* NBT-friendly version of {@link #areStacksSameType(ItemStack, ItemStack)}
*
*
* @param stack1 The {@link ItemStack} being compared.
* @param stack2 The {@link ItemStack} to compare to.
* @return whether the two items are the same in terms of itemID, damage and NBT.
@@ -177,19 +203,35 @@ public class NEIServerUtils {
/**
* NBT-friendly version of {@link #areStacksSameTypeCrafting(ItemStack, ItemStack)}
*
*
* @param stack1 The {@link ItemStack} being compared.
* @param stack2 The {@link ItemStack} to compare to.
* @return whether the two items are the same from the perspective of a crafting inventory.
*/
public static boolean areStacksSameTypeCraftingWithNBT(ItemStack stack1, ItemStack stack2) {
return stack1 != null && stack2 != null
&& stack1.getItem() == stack2.getItem()
&& (stack1.getItemDamage() == stack2.getItemDamage()
|| stack1.getItemDamage() == OreDictionary.WILDCARD_VALUE
|| stack2.getItemDamage() == OreDictionary.WILDCARD_VALUE
|| stack1.getItem().isDamageable())
&& NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound());
if (NEIServerUtils.areStacksSameTypeCrafting(stack2, stack1)) {
if (NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound())) return true;
if (isItemTool(stack1)
&& (stack1.stackTagCompound == null || stack1.stackTagCompound.hasKey("GT.ToolStats"))
&& (stack2.stackTagCompound == null || stack2.stackTagCompound.hasKey("GT.ToolStats")))
return true;
return stack1.getMaxStackSize() == 1 && stack2.getMaxStackSize() == 1
&& (stack1.stackTagCompound == null ^ stack2.stackTagCompound == null);
}
return false;
}
/**
* GT Items don't have any NBT set for the recipe, so if either of the stacks has a NULL nbt, and the other doesn't,
* pretend they stack
*
* @param ItemStack stack
* @return
*/
public static boolean isItemTool(ItemStack stack) {
return NEIServerUtils.gtMetaBaseItem != null && NEIServerUtils.gtMetaBaseItem.isInstance(stack.getItem());
}
/**
@@ -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 {
+56 -72
View File
@@ -1,13 +1,14 @@
package codechicken.nei;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.api.GuiInfo;
import codechicken.nei.api.INEIGuiHandler;
import codechicken.nei.guihook.GuiContainerManager;
@@ -16,7 +17,8 @@ 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 implements IContainerTooltipHandler {
protected static final int PADDING = 2;
@@ -27,20 +29,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 +56,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,8 +75,9 @@ 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);
}
};
}
@@ -97,9 +101,6 @@ public abstract class PanelWidget extends Widget implements IContainerTooltipHan
getWidth(gui),
getHeight(gui));
final int minWidth = 5 * ItemsGrid.SLOT_SIZE;
final int minHeight = 9 * ItemsGrid.SLOT_SIZE;
final String settingName = getPositioningSettingName();
int paddingLeft = (int) Math
.ceil(margin.w * NEIClientConfig.getSetting(settingName + ".left").getIntValue() / 100000.0);
@@ -110,12 +111,12 @@ public abstract class PanelWidget extends Widget implements IContainerTooltipHan
int paddingBottom = (int) Math
.ceil(margin.h * NEIClientConfig.getSetting(settingName + ".bottom").getIntValue() / 100000.0);
int deltaHeight = Math.min(0, margin.h - paddingTop - paddingBottom - minHeight) / 2;
int deltaHeight = Math.min(0, margin.h - paddingTop - paddingBottom - ItemsGrid.SLOT_SIZE) / 2;
paddingLeft = Math.min(paddingLeft, Math.max(0, margin.w - paddingRight - minWidth));
paddingRight = Math.min(paddingRight, Math.max(0, margin.w - paddingLeft - minWidth));
paddingTop = Math.min(margin.h - minHeight, Math.max(0, paddingTop + deltaHeight));
paddingBottom = Math.min(margin.h - paddingTop - minHeight, Math.max(0, paddingBottom - deltaHeight));
paddingLeft = Math.min(paddingLeft, Math.max(0, margin.w - paddingRight - ItemsGrid.SLOT_SIZE));
paddingRight = Math.min(paddingRight, Math.max(0, margin.w - paddingLeft - ItemsGrid.SLOT_SIZE));
paddingTop = Math.min(margin.h - ItemsGrid.SLOT_SIZE, Math.max(0, paddingTop + deltaHeight));
paddingBottom = Math.min(margin.h - paddingTop - ItemsGrid.SLOT_SIZE, Math.max(0, paddingBottom - deltaHeight));
x = margin.x + paddingLeft;
y = margin.y + paddingTop;
@@ -125,8 +126,8 @@ public abstract class PanelWidget extends Widget implements IContainerTooltipHan
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 +172,22 @@ public abstract class PanelWidget extends Widget implements IContainerTooltipHan
protected abstract int resizeFooter(GuiContainer gui);
public void setVisible() {
if (grid.getPerPage() > 0) {
if (this.grid.getPerPage() > 0 && !this.grid.isEmpty()) {
LayoutManager.addWidget(pagePrev);
LayoutManager.addWidget(pageNext);
LayoutManager.addWidget(pageLabel);
grid.setVisible();
this.grid.setVisible();
}
}
@Override
public void update() {
grid.update();
this.grid.update();
}
@Override
public void draw(int mousex, int mousey) {
grid.draw(mousex, mousey);
this.grid.draw(mousex, mousey);
}
@Override
@@ -200,37 +201,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 +242,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 +308,23 @@ 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)) {
|| !NEIClientConfig.canCheatItem(hoverSlot.getItemStack())) {
if (button == 0) {
GuiCraftingRecipe.openRecipeGui("item", item);
GuiCraftingRecipe.openRecipeGui("item", hoverSlot.getItemStack().copy());
} else if (button == 1) {
GuiUsageRecipe.openRecipeGui("item", item);
GuiUsageRecipe.openRecipeGui("item", hoverSlot.getItemStack().copy());
}
mouseDownSlot = -1;
return;
} else {
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.getItemStack()), button, -1);
}
NEIClientUtils.cheatItem(getDraggedStackWithQuantity(hoverSlot.slotIndex), button, -1);
}
mouseDownSlot = -1;
@@ -339,20 +334,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);
this.grid.shiftPage(1);
return true;
}
if (NEIClientConfig.isKeyHashDown("gui.prev")) {
grid.shiftPage(-1);
this.grid.shiftPage(-1);
return true;
}
@@ -361,41 +358,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);
}
}
@@ -1,13 +1,21 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.StackInfo;
/**
* Simply an {@link ItemStack} with position. Mainly used in the recipe handlers.
*/
@@ -40,7 +48,7 @@ public class PositionedStack {
public void generatePermutations() {
if (permutated) return;
ArrayList<ItemStack> stacks = new ArrayList<>();
List<ItemStack> stacks = new ArrayList<>();
for (ItemStack item : items) {
if (item == null || item.getItem() == null) continue;
@@ -75,18 +83,57 @@ public class PositionedStack {
}
public PositionedStack copy() {
return new PositionedStack(items, relx, rely);
PositionedStack pStack = new PositionedStack(
Arrays.stream(this.items).map(ItemStack::copy).toArray(ItemStack[]::new),
relx,
rely,
false);
pStack.permutated = this.permutated;
return pStack;
}
public List<ItemStack> getFilteredPermutations() {
return getFilteredPermutations(null);
}
public List<ItemStack> getFilteredPermutations(ItemFilter additionalFilter) {
List<ItemStack> items = Arrays.asList(this.items);
items = filteringPermutations(items, item -> !ItemInfo.isHidden(item));
items = filteringPermutations(items, PresetsList.getItemFilter());
items = filteringPermutations(items, GuiRecipe.getSearchItemFilter());
items = filteringPermutations(items, additionalFilter);
items.sort(Comparator.comparing(FavoriteRecipes::contains).reversed());
return items;
}
private List<ItemStack> filteringPermutations(List<ItemStack> items, ItemFilter filter) {
if (filter == null) return items;
final List<ItemStack> filteredItems = items.stream().filter(filter::matches).collect(Collectors.toList());
return filteredItems.isEmpty() ? items : filteredItems;
}
public boolean setPermutationToRender(ItemStack ingredient) {
for (int index = 0; index < this.items.length; index++) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(this.items[index], ingredient)) {
setPermutationToRender(index);
return true;
}
}
return false;
}
public void setPermutationToRender(int index) {
item = items[index].copy();
this.item = this.items[index].copy();
if (item.getItem() == null) {
item = new ItemStack(Blocks.fire);
} else if (item.getItemDamage() == OreDictionary.WILDCARD_VALUE && item.getItem() != null
&& item.getItem().isRepairable()) {
item.setItemDamage(0);
}
if (this.item.getItem() == null) {
this.item = new ItemStack(Blocks.fire);
} else if (this.item.getItemDamage() == OreDictionary.WILDCARD_VALUE && this.item.getItem().isRepairable()) {
this.item.setItemDamage(0);
}
}
public boolean contains(ItemStack ingredient) {
@@ -99,7 +146,7 @@ public class PositionedStack {
* NBT-friendly version of {@link #contains(ItemStack)}
*/
public boolean containsWithNBT(ItemStack ingredient) {
for (ItemStack item : items) if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(item, ingredient)) return true;
for (ItemStack item : items) if (StackInfo.equalItemAndNBT(item, ingredient, true)) return true;
return false;
}
+10 -2
View File
@@ -100,6 +100,8 @@ 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 ItemFilter getFilter() {
@@ -144,7 +146,8 @@ public class SearchField extends TextField implements ItemFilterProvider {
@Override
public int getTextColour() {
if (ItemPanels.itemPanel.getItems().isEmpty()) {
if (ItemPanels.itemPanel.getItems().isEmpty()
&& (!this.field.getText().isEmpty() || !NEIClientConfig.hideItemsUntilSearching())) {
return focused() ? 0xFFcc3300 : 0xFF993300;
} else {
return focused() ? 0xFFE0E0E0 : 0xFF909090;
@@ -280,7 +283,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) {
@@ -315,6 +318,11 @@ public class SearchField extends TextField implements ItemFilterProvider {
@Override
public ItemFilter getFilter() {
if (field.getText().isEmpty() && NEIClientConfig.hideItemsUntilSearching()) {
return new NothingItemFilter();
}
return ((GuiSearchField) field).getFilter();
}
@@ -1,12 +1,12 @@
package codechicken.nei;
import java.util.List;
import java.util.StringJoiner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.minecraft.util.EnumChatFormatting;
import codechicken.nei.FormattedTextField.TextFormatter;
import codechicken.nei.SearchTokenParser.SearchToken;
public class SearchTextFormatter implements TextFormatter {
@@ -17,63 +17,50 @@ public class SearchTextFormatter implements TextFormatter {
}
public String format(String text) {
final String[] parts = text.split("\\|");
final Pattern splitPattern = searchParser.getSplitPattern();
final String[] parts = (text + "| ").split("\\|");
StringJoiner formattedText = new StringJoiner(EnumChatFormatting.GRAY + "|");
for (String filterText : parts) {
Matcher filterMatcher = splitPattern.matcher(filterText);
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;
while (filterMatcher.find()) {
boolean ignore = "-".equals(filterMatcher.group(2));
String firstChar = filterMatcher.group(3);
String token = filterMatcher.group(4);
boolean quotes = token.length() > 1 && token.startsWith("\"") && token.endsWith("\"");
if (quotes) {
token = token.substring(1, token.length() - 1);
}
formattedPart.append(filterText.substring(startIndex, filterMatcher.start()));
for (SearchToken token : tokens) {
formattedPart.append(filterText.substring(startIndex, token.start));
EnumChatFormatting tokenColor = EnumChatFormatting.RESET;
if (!firstChar.isEmpty()) {
tokenColor = searchParser.getProvider(firstChar.charAt(0)).getHighlightedColor();
if (token.firstChar != null) {
tokenColor = searchParser.getProvider(token.firstChar).getHighlightedColor();
}
if (ignore) {
if (token.ignore) {
formattedPart.append(EnumChatFormatting.BLUE + "-");
}
if (!firstChar.isEmpty()) {
formattedPart.append(tokenColor + firstChar);
if (token.firstChar != null) {
formattedPart.append(tokenColor + String.valueOf(token.firstChar));
}
if (quotes) {
if (token.quotes) {
formattedPart.append(EnumChatFormatting.GOLD + "\"");
}
if (!token.isEmpty()) {
formattedPart.append(tokenColor + token);
if (!token.rawText.isEmpty()) {
formattedPart.append(tokenColor + token.rawText);
}
if (quotes) {
if (token.quotes) {
formattedPart.append(EnumChatFormatting.GOLD + "\"");
}
startIndex = filterMatcher.end();
startIndex = token.end;
}
formattedPart.append(filterText.substring(startIndex, filterText.length()));
formattedText.add(formattedPart);
}
if (text.endsWith("|")) {
formattedText.add("");
}
return formattedText.toString();
}
}
@@ -2,8 +2,8 @@ package codechicken.nei;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
@@ -21,8 +21,6 @@ import codechicken.nei.ItemList.EverythingItemFilter;
import codechicken.nei.ItemList.NegatedItemFilter;
import codechicken.nei.ItemList.NothingItemFilter;
import codechicken.nei.api.ItemFilter;
import gnu.trove.map.TCharCharMap;
import gnu.trove.map.hash.TCharCharHashMap;
public class SearchTokenParser {
@@ -41,6 +39,20 @@ 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);
@@ -87,19 +99,10 @@ public class SearchTokenParser {
}
}
private final LinkedHashMap<String, ItemFilter> filtersCache = new LinkedHashMap<>() {
private static final long serialVersionUID = 1042213947848622164L;
@Override
protected boolean removeEldestEntry(Map.Entry<String, ItemFilter> eldest) {
return size() > 20;
}
};
protected final LRUCache<String, ItemFilter> filtersCache = new LRUCache<>(20);
protected final List<ISearchParserProvider> searchProviders;
protected final ProvidersCache providersCache = new ProvidersCache();
protected final TCharCharMap prefixRedefinitions = new TCharCharHashMap();
protected final Map<Character, Character> prefixRedefinitions = new HashMap<>();
public SearchTokenParser(List<ISearchParserProvider> searchProviders) {
this.searchProviders = searchProviders;
@@ -123,19 +126,24 @@ public class SearchTokenParser {
Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage();
if (!currentLanguage.getLanguageCode().equals(providersCache.languageCode)) {
providersCache.providers = new ArrayList<>();
providersCache.languageCode = currentLanguage.getLanguageCode();
Map<Character, ISearchParserProvider> providers = new HashMap<>();
for (int index = this.searchProviders.size() - 1; index >= 0; index--) {
ISearchParserProvider provider = this.searchProviders.get(index);
if (!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) {
providersCache.providers.add(provider);
}
}
}
providersCache.providers = new ArrayList<>(providers.values());
providersCache.languageCode = currentLanguage.getLanguageCode();
providersCache.providers.addAll(providers.values());
}
return providersCache.providers;
@@ -155,7 +163,7 @@ public class SearchTokenParser {
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));
.collect(Collectors.toList());
if (searchTokens.isEmpty()) {
return new EverythingItemFilter();
@@ -169,7 +177,64 @@ public class SearchTokenParser {
}
public Pattern getSplitPattern() {
public List<SearchToken> splitSearchText(String filterText) {
if (filterText.isEmpty()) {
return Collections.emptyList();
}
final List<SearchToken> tokens = new ArrayList<>();
final String prefixes = getPrefixes();
final int spaceMode = NEIClientConfig.getIntSetting("inventory.search.spaceMode");
// The regular expression first tries to match a string that starts with a space or the beginning of the string,
// followed by a sequence of characters that do not contain special characters -"@#$%&, and ends with a space
// and the characters -"@#$%& or the end of the string.
final String patternPart1 = "(?<tokenA>(^|\\s+)(?:[^" + Pattern.quote(" -\"" + prefixes)
+ "]).+?(?=\\s+["
+ Pattern.quote("-\"" + prefixes)
+ "]|$))";
// If the first condition is not met, it tries to match a sequence of - characters, followed by @#$%&
// characters, then either a quoted string or non-space characters.
final String patternPart2 = "((?<ignore>-*)(?<firstChar>[" + Pattern.quote(prefixes)
+ "]*)(?<tokenB>\\\".*?(?:\\\"|$)|\\S+\\s*))";
final Pattern pattern = Pattern.compile(spaceMode == 0 ? patternPart2 : (patternPart1 + "|" + patternPart2));
final Matcher filterMatcher = pattern.matcher(filterText);
while (filterMatcher.find()) {
String firstChar = filterMatcher.group("firstChar");
SearchToken token = new SearchToken();
token.start = filterMatcher.start();
token.end = filterMatcher.end();
token.ignore = "-".equals(filterMatcher.group("ignore"));
token.rawText = spaceMode == 0 ? null : filterMatcher.group("tokenA");
if (firstChar != null && !firstChar.isEmpty()) {
token.firstChar = firstChar.charAt(0);
}
if (token.rawText == null) { // spaceMode == 0
token.rawText = filterMatcher.group("tokenB");
token.quotes = token.rawText.length() > 1 && token.rawText.startsWith("\"")
&& token.rawText.endsWith("\"");
if (token.quotes) {
token.rawText = token.rawText.substring(1, token.rawText.length() - 1);
}
token.words = new String[] { token.rawText.trim() };
} else if (spaceMode == 2) {
token.words = token.rawText.trim().split("\\s+");
} else {
token.words = new String[] { token.rawText.trim() };
}
tokens.add(token);
}
return tokens;
}
private String getPrefixes() {
StringBuilder prefixes = new StringBuilder().append('\0');
for (ISearchParserProvider provider : getProviders()) {
@@ -178,14 +243,11 @@ public class SearchTokenParser {
}
}
return Pattern.compile("((-*)([" + Pattern.quote(prefixes.toString()) + "]*)(\\\".*?(?:\\\"|$)|\\S+))");
return prefixes.toString();
}
public char getRedefinedPrefix(char prefix) {
if (this.prefixRedefinitions.containsKey(prefix)) {
return this.prefixRedefinitions.get(prefix);
}
return prefix;
return this.prefixRedefinitions.getOrDefault(prefix, prefix);
}
private ItemFilter parseSearchText(String filterText) {
@@ -194,28 +256,19 @@ public class SearchTokenParser {
return null;
}
final Matcher filterMatcher = getSplitPattern().matcher(filterText);
final AllMultiItemFilter searchTokens = new AllMultiItemFilter();
final List<SearchToken> tokens = splitSearchText(filterText);
while (filterMatcher.find()) {
boolean ignore = "-".equals(filterMatcher.group(2));
String firstChar = filterMatcher.group(3);
String token = filterMatcher.group(4);
boolean quotes = token.length() > 1 && token.startsWith("\"") && token.endsWith("\"");
for (SearchToken token : tokens) {
if (!token.rawText.isEmpty()) {
ItemFilter result = parseToken(token);
if (quotes) {
token = token.substring(1, token.length() - 1);
}
if (!token.isEmpty()) {
ItemFilter result = parseToken(firstChar, token);
if (ignore) {
if (token.ignore) {
searchTokens.filters.add(new NegatedItemFilter(result));
} else {
searchTokens.filters.add(result);
}
} else if (!ignore) {
} else if (!token.ignore) {
searchTokens.filters.add(new NothingItemFilter());
}
}
@@ -223,17 +276,17 @@ public class SearchTokenParser {
return searchTokens;
}
private ItemFilter parseToken(String firstChar, String token) {
final ISearchParserProvider provider = firstChar.isEmpty() ? null : this.getProvider(firstChar.charAt(0));
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) {
ItemFilter filter = _provider.getFilter(token);
AllMultiItemFilter filter = generateFilters(_provider, token.words);
if (filter != null) {
if (!filter.filters.isEmpty()) {
filters.add(filter);
}
}
@@ -241,7 +294,21 @@ public class SearchTokenParser {
return filters.isEmpty() ? new NothingItemFilter() : new AnyMultiItemFilter(filters);
} else {
return provider.getFilter(token);
return generateFilters(provider, token.words);
}
}
private AllMultiItemFilter generateFilters(ISearchParserProvider provider, String[] words) {
final AllMultiItemFilter filters = new AllMultiItemFilter();
for (String work : words) {
final ItemFilter filter = provider.getFilter(work);
if (filter != null) {
filters.filters.add(filter);
}
}
return filters;
}
}
@@ -9,7 +9,6 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.boss.BossStatus;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.client.IItemRenderer;
import org.lwjgl.opengl.GL11;
@@ -27,21 +26,16 @@ public class SpawnerRenderer implements IItemRenderer {
public void renderInventoryItem(RenderBlocks render, ItemStack item) {
int meta = item.getItemDamage();
if (meta == 0) meta = ItemMobSpawner.idPig;
String bossName = BossStatus.bossName;
int bossTimeout = BossStatus.statusBarTime;
boolean bossHasColorModifier = BossStatus.hasColorModifier;
Entity entity = ItemMobSpawner.getEntity(meta);
try {
World world = NEIClientUtils.mc().theWorld;
ItemMobSpawner.loadSpawners(world);
CCRenderState.changeTexture(TextureMap.locationBlocksTexture);
render.renderBlockAsItem(Blocks.mob_spawner, 0, 1F);
entity.setWorld(render.minecraftRB.theWorld);
GL11.glPushMatrix();
Entity entity = ItemMobSpawner.getEntity(meta);
entity.setWorld(world);
float f1 = 0.4375F;
if (entity.getShadowSize() > 1.5) f1 = 0.1F;
GL11.glRotatef((float) (ClientUtils.getRenderTime() * 10), 0.0F, 1.0F, 0.0F);
@@ -51,7 +45,6 @@ public class SpawnerRenderer implements IItemRenderer {
entity.setLocationAndAngles(0, 0, 0, 0.0F, 0.0F);
RenderManager.instance.renderEntityWithPosYaw(entity, 0.0D, 0.0D, 0.0D, 0.0F, 0);
GL11.glPopMatrix();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit);
GL11.glDisable(GL11.GL_TEXTURE_2D);
File diff suppressed because it is too large. Load diff
@@ -11,6 +11,6 @@ public class WidgetZOrder implements Comparator<Widget> {
}
public int compare(Widget w1, Widget w2) {
return w1.z != w2.z ? ((topfirst ? w1.z > w2.z : w1.z < w2.z) ? 1 : -1) : 1;
return w1.z != w2.z ? ((topfirst ? w1.z < w2.z : w1.z > w2.z) ? 1 : -1) : 1;
}
}
+8 -2
View File
@@ -3,6 +3,7 @@ package codechicken.nei.api;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import net.minecraft.block.Block;
import net.minecraft.client.gui.inventory.GuiContainer;
@@ -164,8 +165,13 @@ 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();
}
}
@@ -9,13 +9,14 @@ import net.minecraft.inventory.Slot;
import org.lwjgl.opengl.GL11;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.guihook.GuiContainerManager;
public class DefaultOverlayRenderer implements IRecipeOverlayRenderer {
public DefaultOverlayRenderer(List<PositionedStack> ai, IStackPositioner positioner) {
positioner = this.positioner = positioner;
this.positioner = positioner;
ingreds = new ArrayList<>();
for (PositionedStack stack : ai) ingreds.add(stack.copy());
ingreds = positioner.positionStacks(ingreds);
@@ -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;
@@ -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());
}
}
return stacks;
}
void pullBookmarkItemsFromContainer(GuiContainer guiContainer, ArrayList<ItemStack> realItems);
}
@@ -14,7 +14,23 @@ import codechicken.nei.recipe.IRecipeHandler;
public interface IOverlayHandler {
void overlayRecipe(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, boolean shift);
void overlayRecipe(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, boolean maxTransfer);
default int transferRecipe(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, int multiplier) {
return 0;
}
default boolean canFillCraftingGrid(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex) {
return true;
}
default boolean craft(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, int multiplier) {
return false;
}
default boolean canCraft(GuiContainer firstGui, IRecipeHandler handler, int recipeIndex) {
return false;
}
default List<ItemOverlayState> presenceOverlay(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex) {
final List<ItemOverlayState> itemPresenceSlots = new ArrayList<>();
@@ -25,7 +41,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))
@@ -6,9 +6,18 @@ import net.minecraftforge.fluids.FluidStack;
public interface IStackStringifyHandler {
public NBTTagCompound convertItemStackToNBT(ItemStack stack, boolean saveStackSize);
default NBTTagCompound convertItemStackToNBT(ItemStack stack, boolean saveStackSize) {
return null;
}
public ItemStack convertNBTToItemStack(NBTTagCompound nbtTag);
default ItemStack convertNBTToItemStack(NBTTagCompound nbtTag) {
return null;
}
default FluidStack getFluid(ItemStack stack) {
return null;
}
default void pauseItemDamageSound(boolean pause) {}
public FluidStack getFluid(ItemStack stack);
}
+43 -80
View File
@@ -5,6 +5,7 @@ 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;
@@ -43,7 +44,6 @@ import com.google.common.collect.ArrayListMultimap;
import codechicken.core.featurehack.GameDataManipulator;
import codechicken.nei.InfiniteStackSizeHandler;
import codechicken.nei.InfiniteToolHandler;
import codechicken.nei.ItemList;
import codechicken.nei.ItemList.AnyMultiItemFilter;
import codechicken.nei.ItemList.PatternItemFilter;
import codechicken.nei.ItemMobSpawner;
@@ -124,19 +124,19 @@ public class ItemInfo {
addMobSpawnerItem();
}
public static void load(World world) {
public static void load() {
addVanillaBlockProperties();
addDefaultDropDowns();
searchItems();
parseModItems();
ItemMobSpawner.loadSpawners(world);
ItemMobSpawner.loadSpawners();
addSpawnEggs();
addInfiniteHandlers();
addInputHandlers();
addIDDumps();
addSearchProviders();
RecipeItemInputHandler.load();
PresetsList.load();
ItemList.loadCallbacks.add(TooltipFilter::populateSearchMap);
}
private static void addSearchProviders() {
@@ -269,7 +269,8 @@ public class ItemInfo {
@SuppressWarnings("unchecked")
private static void parseModItems() {
HashMap<String, ItemStackSet> modSubsets = new HashMap<>();
final Map<String, ItemStackSet> modSubsets = new HashMap<>();
for (Item item : (Iterable<Item>) Item.itemRegistry) {
UniqueIdentifier ident = null;
try {
@@ -281,14 +282,12 @@ public class ItemInfo {
continue;
}
String modId = ident.modId;
itemOwners.put(item, modId);
ItemStackSet itemset = modSubsets.get(modId);
if (itemset == null) modSubsets.put(modId, itemset = new ItemStackSet());
itemset.with(item);
itemOwners.put(item, ident.modId);
modSubsets.computeIfAbsent(ident.modId, i -> new ItemStackSet()).with(item);
}
API.addSubset("Mod.Minecraft", modSubsets.remove("minecraft"));
for (Entry<String, ItemStackSet> entry : modSubsets.entrySet()) {
ModContainer mc = FMLCommonHandler.instance().findContainerFor(entry.getKey());
if (mc == null) NEIClientConfig.logger.error("Missing container for " + entry.getKey());
@@ -297,7 +296,6 @@ public class ItemInfo {
}
private static void addInputHandlers() {
GuiContainerManager.addInputHandler(new RecipeItemInputHandler());
GuiContainerManager.addInputHandler(new PopupInputHandler());
}
@@ -325,44 +323,29 @@ public class ItemInfo {
}
private static void addDefaultDropDowns() {
final Item mob_spawner = Item.getItemFromBlock(Blocks.mob_spawner);
API.addSubset("Items", item -> Block.getBlockFromItem(item.getItem()) == Blocks.air);
API.addSubset("Blocks", item -> Block.getBlockFromItem(item.getItem()) != Blocks.air);
API.addSubset("Blocks.MobSpawners", ItemStackSet.of(Blocks.mob_spawner));
API.addSubset("Blocks.MobSpawners", item -> item.getItem() == mob_spawner);
}
@SuppressWarnings("unchecked")
private static void searchItems() {
ItemStackSet tools = new ItemStackSet();
ItemStackSet picks = new ItemStackSet();
ItemStackSet shovels = new ItemStackSet();
ItemStackSet axes = new ItemStackSet();
ItemStackSet hoes = new ItemStackSet();
ItemStackSet swords = new ItemStackSet();
ItemStackSet chest = new ItemStackSet();
ItemStackSet helmets = new ItemStackSet();
ItemStackSet legs = new ItemStackSet();
ItemStackSet boots = new ItemStackSet();
ItemStackSet other = new ItemStackSet();
ItemStackSet ranged = new ItemStackSet();
ItemStackSet food = new ItemStackSet();
ItemStackSet potioningredients = new ItemStackSet();
ArrayList<ItemStackSet> creativeTabRanges = new ArrayList<>(CreativeTabs.creativeTabArray.length);
List<ItemStack> stackList = new LinkedList<>();
final Map<Integer, ItemStackSet> creativeTabRanges = new HashMap<>();
final List<ItemStack> stackList = new LinkedList<>();
for (Item item : (Iterable<Item>) Item.itemRegistry) {
if (item == null) continue;
for (CreativeTabs itemTab : item.getCreativeTabs()) {
if (itemTab != null) {
while (itemTab.getTabIndex() >= creativeTabRanges.size()) creativeTabRanges.add(null);
ItemStackSet set = creativeTabRanges.get(itemTab.getTabIndex());
if (set == null) creativeTabRanges.set(itemTab.getTabIndex(), set = new ItemStackSet());
final ItemStackSet itemset = creativeTabRanges
.computeIfAbsent(itemTab.getTabIndex(), i -> new ItemStackSet());
try {
stackList.clear();
item.getSubItems(item, itemTab, stackList);
for (ItemStack stack : stackList) set.add(stack);
itemset.addAll(stackList);
} catch (Exception e) {
NEIClientConfig.logger
.error("Error loading sub-items for: " + item + ". Tab: " + itemTab.getTabLabel(), e);
@@ -370,41 +353,13 @@ public class ItemInfo {
}
}
if (item.isDamageable()) {
tools.with(item);
if (item instanceof ItemPickaxe) picks.with(item);
else if (item instanceof ItemSpade) shovels.with(item);
else if (item instanceof ItemAxe) axes.with(item);
else if (item instanceof ItemHoe) hoes.with(item);
else if (item instanceof ItemSword) swords.with(item);
else if (item instanceof ItemArmor) switch (((ItemArmor) item).armorType) {
case 0:
helmets.with(item);
break;
case 1:
chest.with(item);
break;
case 2:
legs.with(item);
break;
case 3:
boots.with(item);
break;
}
else if (item == Items.arrow || item == Items.bow) ranged.with(item);
else if (item == Items.fishing_rod || item == Items.flint_and_steel || item == Items.shears)
other.with(item);
}
if (item instanceof ItemFood) food.with(item);
try {
LinkedList<ItemStack> subItems = new LinkedList<>();
final List<ItemStack> subItems = new LinkedList<>();
item.getSubItems(item, null, subItems);
for (ItemStack stack : subItems) {
if (item.isPotionIngredient(stack) && item.getPotionEffect(stack) != null) {
BrewingRecipeHandler.ingredients.add(stack);
potioningredients.add(stack);
}
}
@@ -412,25 +367,33 @@ public class ItemInfo {
NEIClientConfig.logger.error("Error loading brewing ingredients for: " + item, e);
}
}
API.addSubset("Items.Tools.Pickaxes", picks);
API.addSubset("Items.Tools.Shovels", shovels);
API.addSubset("Items.Tools.Axes", axes);
API.addSubset("Items.Tools.Hoes", hoes);
API.addSubset("Items.Tools.Other", other);
API.addSubset("Items.Weapons.Swords", swords);
API.addSubset("Items.Weapons.Ranged", ranged);
API.addSubset("Items.Armor.Chestplates", chest);
API.addSubset("Items.Armor.Leggings", legs);
API.addSubset("Items.Armor.Helmets", helmets);
API.addSubset("Items.Armor.Boots", boots);
API.addSubset("Items.Food", food);
API.addSubset("Items.Potions.Ingredients", potioningredients);
API.addSubset("Items.Tools.Pickaxes", item -> item.getItem() instanceof ItemPickaxe);
API.addSubset("Items.Tools.Shovels", item -> item.getItem() instanceof ItemSpade);
API.addSubset("Items.Tools.Axes", item -> item.getItem() instanceof ItemAxe);
API.addSubset("Items.Tools.Hoes", item -> item.getItem() instanceof ItemHoe);
API.addSubset(
"Items.Tools.Other",
item -> item.getItem() == Items.fishing_rod || item.getItem() == Items.flint_and_steel
|| item.getItem() == Items.shears);
API.addSubset("Items.Weapons.Swords", item -> item.getItem() instanceof ItemSword);
API.addSubset("Items.Weapons.Ranged", item -> item.getItem() == Items.arrow || item.getItem() == Items.bow);
API.addSubset("Items.Armor.Helmets", item -> item.getItem() instanceof ItemArmor armor && armor.armorType == 0);
API.addSubset(
"Items.Armor.Chestplates",
item -> item.getItem() instanceof ItemArmor armor && armor.armorType == 1);
API.addSubset(
"Items.Armor.Leggings",
item -> item.getItem() instanceof ItemArmor armor && armor.armorType == 2);
API.addSubset("Items.Armor.Boots", item -> item.getItem() instanceof ItemArmor armor && armor.armorType == 3);
API.addSubset("Items.Food", item -> item.getItem() instanceof ItemFood);
API.addSubset("Items.Potions.Ingredients", BrewingRecipeHandler.ingredients);
for (CreativeTabs tab : CreativeTabs.creativeTabArray) {
if (tab.getTabIndex() >= creativeTabRanges.size()) continue;
ItemStackSet set = creativeTabRanges.get(tab.getTabIndex());
if (set != null && !set.isEmpty())
API.addSubset("CreativeTabs." + I18n.format(tab.getTranslatedTabLabel()), set);
final ItemStackSet itemset = creativeTabRanges.get(tab.getTabIndex());
if (itemset != null && !itemset.isEmpty()) {
API.addSubset("CreativeTabs." + I18n.format(tab.getTranslatedTabLabel()), itemset);
}
}
BrewingRecipeHandler.searchPotions();
@@ -1,28 +1,41 @@
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.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.BookmarkItem;
import codechicken.nei.bookmark.BookmarksGridSlot;
import codechicken.nei.recipe.AutoCraftingManager;
import codechicken.nei.recipe.GuiCraftingRecipe;
import codechicken.nei.recipe.GuiRecipe;
import codechicken.nei.recipe.GuiUsageRecipe;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.RecipeHandlerRef;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.recipe.chain.RecipeChainMath;
import codechicken.nei.util.NEIMouseUtils;
public abstract class ShortcutInputHandler {
@@ -32,35 +45,51 @@ public abstract class ShortcutInputHandler {
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 (NEIClientConfig.isKeyHashDown("gui.overlay") && stackover == null
&& LayoutManager.overlayRenderer != null) {
LayoutManager.overlayRenderer = null;
return true;
}
if (stackover == null) {
final int groupId = ItemPanels.bookmarkPanel.getHoveredGroupId(true);
if (groupId != -1) {
if (NEIClientConfig.isKeyHashDown("gui.remove_recipe")) {
ItemPanels.bookmarkPanel.removeGroup(groupId);
return true;
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark_pull_items")) {
return ItemPanels.bookmarkPanel.pullBookmarkItems(groupId, NEIClientUtils.shiftKey());
}
if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft_items")
&& NEIClientUtils.shiftKey()
&& ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)) {
final RecipeChainMath math = ItemPanels.bookmarkPanel.getGrid().createRecipeChainMath(groupId);
if (math != null) {
if (!NEIClientUtils.controlKey()) {
autocraftingIgnoreInventory(math);
}
AutoCraftingManager.runProcessing(math);
return true;
}
}
}
return false;
}
stackover = stackover.copy();
if (NEIClientConfig.isKeyHashDown("gui.overlay")) {
return openOverlayRecipe(stackover, false);
return openOverlayRecipe(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.copy_name")) {
@@ -71,8 +100,8 @@ public abstract class ShortcutInputHandler {
return copyItemStackOreDictionary(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.overlay_use")) {
return openOverlayRecipe(stackover, true);
if (NEIClientConfig.isKeyHashDown("gui.chat_link_item")) {
return sendItemStackChatLink(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.recipe")) {
@@ -84,19 +113,16 @@ public abstract class ShortcutInputHandler {
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark")) {
return saveRecipeInBookmark(stackover, false, false);
return saveRecipeInBookmark(stackover, NEIClientUtils.shiftKey(), NEIClientUtils.controlKey());
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark_recipe")) {
return saveRecipeInBookmark(stackover, true, false);
if (NEIClientConfig.isKeyHashDown("gui.bookmark_pull_items")) {
return pullRecipeItems(stackover, NEIClientUtils.shiftKey());
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark_count")) {
return saveRecipeInBookmark(stackover, false, true);
}
if (NEIClientConfig.isKeyHashDown("gui.bookmark_recipe_count")) {
return saveRecipeInBookmark(stackover, true, true);
if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft_items")
&& NEIClientUtils.shiftKey()) {
return runAutoCrafting(stackover, !NEIClientUtils.controlKey());
}
return false;
@@ -121,19 +147,15 @@ public abstract class ShortcutInputHandler {
return false;
}
private static boolean hideOverlayRecipe() {
if (LayoutManager.overlayRenderer != null) {
LayoutManager.overlayRenderer = null;
return true;
}
return false;
private static boolean copyItemStackName(ItemStack stackover) {
GuiScreen.setClipboardString(SearchField.getEscapedSearchText(stackover));
return true;
}
private static boolean copyItemStackName(ItemStack stackover) {
Toolkit.getDefaultToolkit().getSystemClipboard()
.setContents(new StringSelection(stackover.getDisplayName()), null);
private static boolean sendItemStackChatLink(ItemStack stackover) {
if (stackover == null) return false;
NEIClientUtils.sendChatItemLink(stackover); // I wish clients could just send formatted messages
return true;
}
@@ -151,52 +173,354 @@ 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();
private static boolean runAutoCrafting(ItemStack stackover, boolean ignoreInventory) {
final RecipeId recipeId = GuiCraftingRecipe.getRecipeId(NEIClientUtils.getGuiContainer(), stackover);
if (gui == null || gui instanceof GuiRecipe) {
return false;
if (recipeId != null) {
final Point mouseover = GuiDraw.getMousePosition();
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
RecipeChainMath math = null;
if (slot == null) {
final Recipe recipe = Recipe.of(recipeId);
if (recipe != null) {
math = RecipeChainMath.of(recipe, 1);
}
} else if (slot.getRecipeId() != null && !slot.isIngredient()) {
if (slot.getGroup().crafting == null) {
final Recipe recipe = Recipe.of(slot.getRecipeId());
if (recipe != null) {
math = RecipeChainMath.of(recipe, slot != null ? slot.getMultiplier() : 1);
}
} else {
math = ItemPanels.bookmarkPanel.getGrid()
.createRecipeChainMath(slot.getGroupId(), slot.getRecipeId());
}
}
if (math != null) {
if (ignoreInventory) {
autocraftingIgnoreInventory(math);
}
AutoCraftingManager.runProcessing(math);
return true;
}
}
final Point mouseover = getMousePosition();
ItemPanelSlot panelSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
BookmarkRecipeId recipeId = null;
return false;
}
if (panelSlot != null) {
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(panelSlot.slotIndex);
private static boolean openOverlayRecipe(ItemStack stackover) {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
final RecipeId recipeId = GuiCraftingRecipe.getRecipeId(gui, stackover);
if (recipeId != null) {
final RecipeHandlerRef handlerRef = RecipeHandlerRef.of(recipeId);
if (handlerRef != null) {
if (NEIClientUtils.shiftKey() && handlerRef.canFillCraftingGrid(gui)) {
int multiplier = 0;
if (NEIClientUtils.controlKey()) {
final Point mouseover = GuiDraw.getMousePosition();
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel
.getSlotMouseOver(mouseover.x, mouseover.y);
multiplier = slot != null ? (int) Math.min(64, slot.getMultiplier()) : 1;
}
handlerRef.fillCraftingGrid(gui, multiplier);
} else if (!NEIClientUtils.shiftKey() && handlerRef.canUseOverlayRenderer(gui)) {
handlerRef.useOverlayRenderer(gui);
}
}
}
return false;
}
private static boolean saveRecipeInBookmark(ItemStack stackover, boolean saveIngredients, boolean saveStackSize) {
final Point mousePos = GuiDraw.getMousePosition();
if (!ItemPanels.bookmarkPanel.removeSlot(mousePos.x, mousePos.y, saveIngredients)) {
final Recipe recipe = getFocusedRecipe(stackover, mousePos.x, mousePos.y, saveIngredients);
if (recipe != null && saveIngredients) {
if (!ItemPanels.bookmarkPanel.removeRecipe(recipe.getRecipeId(), BookmarkGrid.DEFAULT_GROUP_ID)) {
final Recipe singleRecipe = Recipe.of(
Arrays.asList(recipe.getResult(stackover)),
recipe.getHandlerName(),
recipe.getIngredients());
singleRecipe.setCustomRecipeId(recipe.getRecipeId());
ItemPanels.bookmarkPanel.addRecipe(singleRecipe, BookmarkGrid.DEFAULT_GROUP_ID);
}
} else {
final RecipeId recipeId = recipe != null ? recipe.getRecipeId() : null;
final boolean existsRecipe = recipeId != null
&& ItemPanels.bookmarkPanel.existsRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID)
|| NEIClientConfig.getBooleanSetting("inventory.bookmarks.bookmarkItemsWithRecipe");
if (!ItemPanels.bookmarkPanel
.removeItem(stackover, existsRecipe ? recipeId : null, BookmarkGrid.DEFAULT_GROUP_ID)) {
saveStackSize = saveStackSize || saveIngredients
|| ItemPanels.bookmarkPanel.existsRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID);
if (!saveStackSize) {
stackover = StackInfo.withAmount(stackover, 0);
} else if (ItemPanels.itemPanel.contains(mousePos.x, mousePos.y)
|| ItemPanels.itemPanel.historyPanel.contains(mousePos.x, mousePos.y)) {
stackover = ItemQuantityField.prepareStackWithQuantity(stackover, 0);
}
ItemPanels.bookmarkPanel
.addItem(stackover, existsRecipe ? recipeId : null, BookmarkGrid.DEFAULT_GROUP_ID);
}
}
}
return true;
}
private static Recipe getFocusedRecipe(ItemStack stackover, int mousex, int mousey, boolean useFavorites) {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
Recipe recipe = null;
if (useFavorites && (ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey))) {
recipe = Recipe.of(FavoriteRecipes.getFavorite(stackover));
if (recipe != null) {
recipe.getIngredients().stream().forEach(ingr -> {
final List<ItemStack> permutations = ingr.getPermutations();
for (int index = 0; index < permutations.size(); index++) {
if (FavoriteRecipes.contains(permutations.get(index))) {
ingr.setActiveIndex(index);
break;
}
}
});
}
} else if (gui instanceof GuiRecipe guiRecipe) {
recipe = guiRecipe.getFocusedRecipe();
}
return recipe;
}
private static boolean pullRecipeItems(ItemStack stackover, boolean shift) {
final Point mousePos = GuiDraw.getMousePosition();
if (ItemPanels.bookmarkPanel.contains(mousePos.x, mousePos.y)) {
stackover = ItemPanels.bookmarkPanel.getStackMouseOverWithQuantity(mousePos.x, mousePos.y);
} else if (ItemPanels.itemPanel.contains(mousePos.x, mousePos.y)) {
stackover = ItemPanels.itemPanel.getStackMouseOverWithQuantity(mousePos.x, mousePos.y);
} else if (ItemPanels.itemPanel.historyPanel.contains(mousePos.x, mousePos.y)) {
stackover = ItemPanels.itemPanel.historyPanel.getStackMouseOverWithQuantity(mousePos.x, mousePos.y);
} else {
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(stackover);
stackover = ItemQuantityField.prepareStackWithQuantity(stackover, 0);
}
final RecipeChainMath math = RecipeChainMath
.of(Arrays.asList(BookmarkItem.of(-3, stackover)), Collections.emptySet());
return ItemPanels.bookmarkPanel.pullBookmarkItems(math, shift);
}
public static Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, ItemStack stack) {
final int groupId = ItemPanels.bookmarkPanel.getHoveredGroupId(true);
final Map<String, String> hotkeys = new HashMap<>();
if (groupId != -1) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.remove_recipe"),
NEIClientUtils.translate("bookmark.group.remove_recipe"));
if (BookmarkContainerInfo.getBookmarkContainerHandler(gui) != null) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark_pull_items"),
NEIClientUtils.translate("bookmark.group.pull_items"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark_pull_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.pull_items_shift"));
}
if (NEIClientConfig.autocraftingEnabled() && ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)) {
hotkeys.put(
NEIClientConfig
.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("bookmark.group.craft_missing"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.craft_all"));
}
}
if (stack == null) {
return hotkeys;
}
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mousex, mousey);
final RecipeId recipeId = getHotkeyRecipeId(gui, mousex, mousey, stack, slot);
if (slot != null) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark"),
NEIClientUtils.translate(slot.isIngredient() ? "bookmark.remove_item" : "bookmark.remove_recipe"));
if (slot.isIngredient()) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.remove_recipe"));
}
if (BookmarkContainerInfo.getBookmarkContainerHandler(gui) != null) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark_pull_items"),
NEIClientUtils.translate("bookmark.group.pull_items"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark_pull_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.pull_items_shift"));
}
} else {
hotkeys.put(NEIClientConfig.getKeyName("gui.bookmark"), NEIClientUtils.translate("bookmark.add_item"));
if (StackInfo.getAmount(stack) > 0) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("bookmark.add_item_with_count"));
}
if (recipeId != null) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.add_item_with_recipe"));
}
}
hotkeys.put(NEIClientConfig.getKeyName("gui.recipe"), NEIClientUtils.translate("itempanel.open_crafting"));
hotkeys.put(NEIClientConfig.getKeyName("gui.usage"), NEIClientUtils.translate("itempanel.open_usage"));
hotkeys.put(NEIClientConfig.getKeyName("gui.copy_name"), NEIClientUtils.translate("itempanel.copy_name"));
hotkeys.put(NEIClientConfig.getKeyName("gui.copy_oredict"), NEIClientUtils.translate("itempanel.copy_oredict"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.chat_link_item"),
NEIClientUtils.translate("itempanel.chat_link_item"));
if (!(gui instanceof GuiRecipe) && NEIClientConfig.canCheatItem(stack)) {
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("itempanel.open_crafting"));
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_RMB),
NEIClientUtils.translate("itempanel.open_usage"));
} else {
hotkeys.put(
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("itempanel.open_crafting"));
hotkeys.put(
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_RMB),
NEIClientUtils.translate("itempanel.open_usage"));
}
if (recipeId != null) {
return GuiCraftingRecipe.overlayRecipe(stackover, recipeId, shift);
}
final RecipeHandlerRef handlerRef = RecipeHandlerRef.of(recipeId);
return false;
}
if (handlerRef != null) {
private static boolean saveRecipeInBookmark(ItemStack stack, boolean saveIngredients, boolean saveStackSize) {
if (handlerRef.canUseOverlayRenderer(gui)) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.overlay"),
NEIClientUtils.translate("itempanel.overlay_recipe"));
}
if (stack != null) {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
List<PositionedStack> ingredients = null;
String handlerName = "";
if (handlerRef.canFillCraftingGrid(gui)) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.overlay", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("itempanel.fill_crafting_grid"));
if (gui instanceof GuiRecipe) {
ingredients = ((GuiRecipe<?>) gui).getFocusedRecipeIngredients();
handlerName = ((GuiRecipe<?>) gui).getHandlerName();
stack.stackSize = ((GuiRecipe<?>) gui).prepareFocusedRecipeResultStackSize(stack);
if (handlerRef.allowedTransferAlghoritm(gui)) {
hotkeys.put(
NEIClientConfig.getKeyName(
"gui.overlay",
NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("itempanel.fill_crafting_grid_quantity"));
}
}
if (NEIClientConfig.autocraftingEnabled()) {
hotkeys.put(
NEIClientConfig.getKeyName(
"gui.craft_items",
NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("itempanel.craft_missing"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("itempanel.craft_all"));
}
}
ItemPanels.bookmarkPanel.addOrRemoveItem(stack, handlerName, ingredients, saveIngredients, saveStackSize);
return true;
}
return false;
return hotkeys;
}
private static void autocraftingIgnoreInventory(RecipeChainMath math) {
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
final List<ItemStack> playerInventory = AutoCraftingManager.getInventoryItems(guiContainer).values();
final RecipeId rootRecipeId = math.createMasterRoot();
for (BookmarkItem item : math.recipeIngredients) {
if (item.amount > 0 && rootRecipeId.equals(item.recipeId)) {
long amount = 0;
for (ItemStack stack : playerInventory) {
if (NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack, item.itemStack)) {
amount += StackInfo.getAmount(stack);
}
}
if (amount >= item.amount) {
item.factor = item.amount = amount + item.amount - (amount % item.amount);
}
}
}
}
private static RecipeId getHotkeyRecipeId(GuiContainer gui, int mousex, int mousey, ItemStack stack,
BookmarksGridSlot slot) {
if (slot != null) {
return slot.isIngredient() ? null : slot.getRecipeId();
} else if (ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey)) {
return FavoriteRecipes.getFavorite(stack);
} else
if (gui instanceof GuiRecipe guiRecipe) {
final Recipe focusedRecipe = guiRecipe.getFocusedRecipe();
if (focusedRecipe != null) {
return focusedRecipe.getRecipeId();
}
}
return null;
}
}
@@ -413,7 +413,7 @@ public class NEITransformer implements IClassTransformer {
if (name.equals("net.minecraftforge.oredict.OreDictionary")) {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cr.accept(new OreDictionaryVisitor(ASM5, cw), ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
cr.accept(new OreDictionaryVisitor(ASM5, cw), 0);
bytes = cw.toByteArray();
}
bytes = transformSubclasses(name, bytes);
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,384 @@
package codechicken.nei.bookmark;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.ItemSorter;
import codechicken.nei.bookmark.RecipeChainDetails.BookmarkChainItem;
import codechicken.nei.bookmark.RecipeChainDetails.CalculatedType;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
public class BookmarkGridGenerator {
protected final BookmarkGrid grid;
public List<BookmarksGridSlot> gridMask = null;
public final Map<Integer, Integer> rowToGroupId = new HashMap<>();
public final Map<Integer, RecipeId> itemToRecipe = new HashMap<>();
public final Map<Integer, Integer> slotToItem = new LinkedHashMap<>();
public final Map<Integer, Integer> itemToSlot = new LinkedHashMap<>();
public final Map<Integer, BookmarkChainItem> caclulatedItems = new HashMap<>();
public int pageCount = 0;
public int maxAbsoluteSlotIndex = 0;
public BookmarkGridGenerator(BookmarkGrid grid) {
this.grid = grid;
}
public int getRowGroupId(int rowIndex) {
final int absoluteRowIndex = rowIndex + (this.grid.getPage() - 1) * this.grid.getRows();
return rowToGroupId.getOrDefault(absoluteRowIndex, BookmarkGrid.DEFAULT_GROUP_ID);
}
public void generate() {
BookmarkItem prevBookmarkItem = null;
Map<Integer, String> borderGrid = new HashMap<>();
int gridColumns = this.grid.getColumns();
int size = this.grid.size();
int absoluteSlotIndex = -2;
int itemIndex = 0;
this.pageCount = 0;
this.maxAbsoluteSlotIndex = 0;
this.gridMask = new ArrayList<>();
this.itemToRecipe.clear();
this.caclulatedItems.clear();
this.slotToItem.clear();
this.itemToSlot.clear();
this.rowToGroupId.clear();
if (this.grid.isEmpty() || this.grid.getPerPage() == 0) {
return;
}
while (itemIndex < size && absoluteSlotIndex != -1) {
final BookmarkItem bookmarkItem = this.grid.getBookmarkItem(itemIndex);
final BookmarkGroup group = this.grid.getGroup(bookmarkItem.groupId);
if (group.crafting != null && (!group.crafting.calculatedItems.containsKey(itemIndex)
|| bookmarkItem.recipeId != null && !bookmarkItem.recipeId
.equals(group.crafting.itemToRecipe.getOrDefault(itemIndex, bookmarkItem.recipeId)))) {
itemIndex++;
} else if (group.collapsed) {
final List<Integer> results = getGroupResults(bookmarkItem.groupId, itemIndex, size);
final String groupKey = "group:" + bookmarkItem.groupId;
for (int index = 0; index < results.size(); index++) {
final int collapsedItemIndex = results.get(index);
final BookmarkItem item = this.grid.getBookmarkItem(collapsedItemIndex);
final int nextSlotIndex = nextSlotIndex(
absoluteSlotIndex + 1,
prevBookmarkItem,
item,
BookmarkViewMode.DEFAULT);
if (nextSlotIndex == -1 || index > 0 && (nextSlotIndex % gridColumns) == 0) {
break;
}
prevBookmarkItem = item;
absoluteSlotIndex = nextSlotIndex;
this.slotToItem.put(absoluteSlotIndex, collapsedItemIndex);
this.itemToSlot.put(collapsedItemIndex, absoluteSlotIndex);
this.caclulatedItems.put(collapsedItemIndex, getItem(group, collapsedItemIndex));
borderGrid.put(absoluteSlotIndex, groupKey);
}
while (itemIndex < size && this.grid.getBookmarkItem(itemIndex).groupId == bookmarkItem.groupId) {
itemIndex++;
}
} else if (group.crafting != null && group.viewMode == BookmarkViewMode.DEFAULT) {
final List<Integer> results = getGroupResults(bookmarkItem.groupId, itemIndex, size);
List<Integer> shadows;
for (int index = 0; index < results.size() && absoluteSlotIndex != -1; index++) {
final int collapsedItemIndex = results.get(index);
final BookmarkItem item = this.grid.getBookmarkItem(collapsedItemIndex);
if ((absoluteSlotIndex = nextSlotIndex(
absoluteSlotIndex + 1,
prevBookmarkItem,
item,
BookmarkViewMode.DEFAULT)) != -1) {
prevBookmarkItem = item;
this.slotToItem.put(absoluteSlotIndex, collapsedItemIndex);
this.itemToSlot.put(collapsedItemIndex, absoluteSlotIndex);
this.caclulatedItems.put(collapsedItemIndex, getItem(group, collapsedItemIndex));
if (!(shadows = getShadows(group, item.recipeId)).isEmpty()) {
borderGrid.put(absoluteSlotIndex, "recipe:" + shadows.get(0));
}
}
}
while (itemIndex < size && this.grid.getBookmarkItem(itemIndex).groupId == bookmarkItem.groupId) {
itemIndex++;
}
} else if (group.crafting != null && group.crafting.itemToRecipe.values().contains(bookmarkItem.recipeId)) {
absoluteSlotIndex = generateCollapsedRecipe(prevBookmarkItem, itemIndex, absoluteSlotIndex, borderGrid);
prevBookmarkItem = bookmarkItem;
while (itemIndex < size && bookmarkItem.equalsRecipe(this.grid.getBookmarkItem(itemIndex))) {
itemIndex++;
}
} else if ((absoluteSlotIndex = nextSlotIndex(
absoluteSlotIndex + 1,
prevBookmarkItem,
bookmarkItem,
group.viewMode)) != -1) {
prevBookmarkItem = bookmarkItem;
this.slotToItem.put(absoluteSlotIndex, itemIndex);
this.itemToSlot.put(itemIndex, absoluteSlotIndex);
this.caclulatedItems.put(itemIndex, getItem(group, itemIndex));
itemIndex++;
}
}
this.maxAbsoluteSlotIndex = this.slotToItem.keySet().stream().mapToInt(index -> index).max().orElse(-1) + 1;
generateGroups();
splitGridMask();
calculateGroupBorders(borderGrid);
}
private List<Integer> getGroupResults(int groupId, int itemIndex, int size) {
final BookmarkGroup group = this.grid.getGroup(groupId);
final List<Integer> results = new ArrayList<>();
while (itemIndex < size) {
final BookmarkItem bookmarkItem = this.grid.getBookmarkItem(itemIndex);
if (bookmarkItem == null || bookmarkItem.groupId != groupId) {
break;
}
if (!bookmarkItem.isIngredient
&& (group.crafting == null || group.crafting.calculatedItems.containsKey(itemIndex))) {
results.add(itemIndex);
}
itemIndex++;
}
return results;
}
private int generateCollapsedRecipe(BookmarkItem prevBookmarkItem, int itemIndex, int absoluteSlotIndex,
Map<Integer, String> borderGrid) {
final BookmarkItem bookmarkItem = this.grid.getBookmarkItem(itemIndex);
final BookmarkGroup group = this.grid.getGroup(bookmarkItem.groupId);
final List<Integer> shadows = getShadows(group, bookmarkItem.recipeId);
final String borderId = "recipe:" + shadows.get(0);
shadows.sort(generateSortingComparator(group.crafting.calculatedItems));
for (int shadowIndex : shadows) {
final boolean isIngredient = shadows.get(0) != shadowIndex
|| group.crafting.calculatedItems.get(shadowIndex).calculatedType == CalculatedType.INGREDIENT;
final BookmarkItem shadowBookmarkItem = BookmarkItem.of(
bookmarkItem.groupId,
bookmarkItem.itemStack,
1,
bookmarkItem.recipeId,
isIngredient,
Collections.emptyMap());
if ((absoluteSlotIndex = nextSlotIndex(
absoluteSlotIndex + 1,
prevBookmarkItem,
shadowBookmarkItem,
group.viewMode)) != -1) {
this.slotToItem.put(absoluteSlotIndex, shadowIndex);
this.itemToSlot.put(shadowIndex, absoluteSlotIndex);
this.caclulatedItems.put(shadowIndex, getItem(group, shadowIndex));
this.itemToRecipe.put(shadowIndex, bookmarkItem.recipeId);
borderGrid.put(absoluteSlotIndex, borderId);
prevBookmarkItem = shadowBookmarkItem;
}
}
return absoluteSlotIndex;
}
private List<Integer> getShadows(BookmarkGroup group, RecipeId recipeId) {
return group.crafting.itemToRecipe.entrySet().stream().filter(entry -> recipeId.equals(entry.getValue()))
.map(entry -> entry.getKey()).collect(Collectors.toList());
}
private int nextSlotIndex(int index, BookmarkItem previousMeta, BookmarkItem meta, BookmarkViewMode viewMode) {
int gridColumns = this.grid.getColumns();
int maxIndex = this.grid.getRows() * gridColumns;
int j = 0;
index = Math.max(0, index);
while (j++ < maxIndex) {
boolean isFirstColumn = (index % gridColumns) == 0;
if (this.grid.isInvalidSlot(index % maxIndex)) {
index++;
} else if (!isFirstColumn && (previousMeta == null || previousMeta.groupId != meta.groupId)) {
// new group must start on a new line
index++;
} else if (viewMode == BookmarkViewMode.DEFAULT) {
return index;
} else if (isFirstColumn && (meta.recipeId == null || previousMeta == null
|| previousMeta.groupId != meta.groupId
|| !meta.recipeId.equals(previousMeta.recipeId)
|| index + 1 < maxIndex && this.grid.isInvalidSlot((index + 1) % maxIndex))) {
// In first column must be an item without recipe, a recipe result, or an ingredient
// if the second column is occupied
return index;
} else
if (!isFirstColumn && meta.recipeId != null && meta.recipeId.equals(previousMeta.recipeId)) {
return index;
} else {
index++;
}
}
return -1;
}
private void generateGroups() {
int gridColumns = this.grid.getColumns();
int previousGroupId = BookmarkGrid.DEFAULT_GROUP_ID;
for (int absoluteSlotIndex = 0; absoluteSlotIndex < this.maxAbsoluteSlotIndex; absoluteSlotIndex++) {
int absoluteRowIndex = absoluteSlotIndex / gridColumns;
if (this.rowToGroupId.getOrDefault(absoluteRowIndex, BookmarkGrid.DEFAULT_GROUP_ID)
== BookmarkGrid.DEFAULT_GROUP_ID) {
int groupId = BookmarkGrid.DEFAULT_GROUP_ID;
if (this.slotToItem.containsKey(absoluteSlotIndex)) {
groupId = this.caclulatedItems.get(this.slotToItem.get(absoluteSlotIndex)).getItem().groupId;
}
this.rowToGroupId.put(absoluteRowIndex, groupId);
if (groupId != BookmarkGrid.DEFAULT_GROUP_ID && previousGroupId == (previousGroupId = groupId)) {
while ((--absoluteRowIndex) >= 0
&& this.rowToGroupId.get(absoluteRowIndex) == BookmarkGrid.DEFAULT_GROUP_ID) {
this.rowToGroupId.put(absoluteRowIndex, groupId);
}
}
}
}
}
private Comparator<Integer> generateSortingComparator(Map<Integer, BookmarkChainItem> calculatedItems) {
return Comparator.comparingInt((Integer index) -> calculatedItems.get(index).calculatedType.toInt())
.thenComparing(index -> StackInfo.getFluid(calculatedItems.get(index).getItem().itemStack) != null)
.thenComparing(
(i1, i2) -> ItemSorter.instance.compare(
calculatedItems.get(i1).getItem().itemStack,
calculatedItems.get(i2).getItem().itemStack));
}
private void splitGridMask() {
int gridColumns = this.grid.getColumns();
int rows = this.grid.getRows();
int perPage = rows * gridColumns;
this.pageCount = (int) Math.ceil(this.maxAbsoluteSlotIndex / (float) perPage);
int page = Math.max(0, Math.min(this.grid.getPage(), this.pageCount) - 1);
for (int absoluteSlotIndex = page * perPage; absoluteSlotIndex
< Math.min(this.maxAbsoluteSlotIndex, (page + 1) * perPage); absoluteSlotIndex++) {
if (this.slotToItem.get(absoluteSlotIndex) != null) {
this.gridMask
.add(getBookmarkGridSlot(absoluteSlotIndex % perPage, this.slotToItem.get(absoluteSlotIndex)));
}
}
}
private BookmarkChainItem getItem(BookmarkGroup group, int itemIndex) {
if (group.crafting != null) {
return group.crafting.calculatedItems.get(itemIndex);
} else {
BookmarkChainItem item = BookmarkChainItem.of(this.grid.getBookmarkItem(itemIndex));
item.setRealAmount(item.getShiftAmount());
return item;
}
}
private BookmarksGridSlot getBookmarkGridSlot(int slotIndex, int itemIndex) {
final BookmarkChainItem chainItem = this.caclulatedItems.get(itemIndex);
final BookmarkGroup group = this.grid.getGroup(chainItem.getItem().groupId);
if (group.crafting == null) {
return new BookmarksGridSlot(
slotIndex,
itemIndex,
chainItem.getRealAmount(),
0,
0,
chainItem.getItem(),
null,
group);
} else {
return new BookmarksGridSlot(
slotIndex,
itemIndex,
chainItem.getRealAmount(),
chainItem.getShiftAmount(),
chainItem.getCalculatedAmount(),
chainItem.getItem(),
chainItem.calculatedType,
group);
}
}
protected void calculateGroupBorders(Map<Integer, String> borderGrid) {
int gridColumns = this.grid.getColumns();
int page = Math.max(1, Math.min(this.grid.getPage(), this.pageCount)) - 1;
int shiftIndex = page * this.grid.getRows() * gridColumns;
for (BookmarksGridSlot slot : this.gridMask) {
if (borderGrid.get(shiftIndex + slot.slotIndex) == null) {
continue;
}
String groupIndex = borderGrid.get(shiftIndex + slot.slotIndex);
int column = slot.slotIndex % gridColumns;
int row = slot.slotIndex / gridColumns;
int prevSlotIndex = shiftIndex + (row - 1) * gridColumns + column;
int nextSlotIndex = shiftIndex + (row + 1) * gridColumns + column;
BookmarkGroup group = slot.getGroup();
if (group.crafting == null) {
slot.borderColor = BookmarkGrid.GROUP_NONE_COLOR;
} else if (group.collapsed) {
slot.borderColor = BookmarkGrid.GROUP_CHAIN_COLOR;
} else {
slot.borderColor = BookmarkGrid.RECIPE_COLOR;
}
slot.borderLeft = column == 0 || !groupIndex.equals(borderGrid.get(shiftIndex + slot.slotIndex - 1));
slot.borderRight = column + 1 == gridColumns
|| !groupIndex.equals(borderGrid.get(shiftIndex + slot.slotIndex + 1));
slot.borderTop = !groupIndex.equals(borderGrid.get(prevSlotIndex));
slot.borderBottom = !groupIndex.equals(borderGrid.get(nextSlotIndex));
}
}
}
@@ -0,0 +1,58 @@
package codechicken.nei.bookmark;
import java.util.HashSet;
import java.util.Set;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.recipe.Recipe.RecipeId;
public class BookmarkGroup {
public RecipeChainDetails crafting = null;
public BookmarkViewMode viewMode;
public boolean collapsed = false;
public Set<RecipeId> collapsedRecipes = new HashSet<>();
public BookmarkGroup(BookmarkViewMode viewMode) {
this.viewMode = viewMode;
}
public BookmarkGroup(BookmarkViewMode viewMode, boolean crafting) {
this.viewMode = viewMode;
setCraftingMode(crafting);
}
public void toggleViewMode() {
if (this.viewMode == BookmarkViewMode.DEFAULT) {
this.viewMode = BookmarkViewMode.TODO_LIST;
} else {
this.viewMode = BookmarkViewMode.DEFAULT;
}
}
public void setCraftingMode(boolean crafting) {
if ((this.crafting != null) != crafting) {
this.crafting = crafting ? new RecipeChainDetails() : null;
}
}
public void toggleCraftingMode() {
setCraftingMode(this.crafting == null);
}
public void toggleCollapsedState() {
this.collapsed = !this.collapsed;
}
public void toggleCollapsedRecipe(RecipeId recipeId) {
if (this.collapsedRecipes.contains(recipeId)) {
this.collapsedRecipes.remove(recipeId);
} else {
this.collapsedRecipes.add(recipeId);
}
}
public BookmarkGroup copy() {
return new BookmarkGroup(this.viewMode);
}
}
@@ -0,0 +1,205 @@
package codechicken.nei.bookmark;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fluids.FluidStack;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.Recipe.RecipeIngredient;
import codechicken.nei.recipe.StackInfo;
public class BookmarkItem {
private static Map<ItemStack, String> fuzzyPermutations = new HashMap<>();
public int groupId;
public long amount = 0L;
public final int fluidCellAmount;
public ItemStack itemStack;
public Map<String, ItemStack> permutations;
public long factor;
public RecipeId recipeId;
public boolean isIngredient = false;
protected BookmarkItem(int groupId, long amount, int fluidCellAmount, ItemStack itemStack,
Map<String, ItemStack> permutations, long factor, RecipeId recipeId, boolean isIngredient) {
this.groupId = groupId;
this.amount = amount;
this.fluidCellAmount = fluidCellAmount;
this.itemStack = itemStack;
this.permutations = permutations;
this.factor = factor;
this.recipeId = recipeId;
this.isIngredient = isIngredient;
}
public static BookmarkItem of(int groupId, ItemStack stack, long factor, RecipeId recipeId, boolean isIngredient,
Map<String, ItemStack> permutations) {
final FluidStack fluidStack = StackInfo.getFluid(stack);
int fluidCellAmount = 1;
long amount;
if (fluidStack != null) {
amount = fluidStack.amount * (long) Math.max(0, stack.stackSize);
fluidCellAmount = Math.max(1, StackInfo.isFluidContainer(stack) ? fluidStack.amount : 1);
} else {
amount = StackInfo.getAmount(stack);
}
return new BookmarkItem(
groupId,
amount,
fluidCellAmount,
stack,
permutations,
factor * fluidCellAmount,
recipeId,
isIngredient);
}
public static BookmarkItem of(int groupId, ItemStack stack, long factor, RecipeId recipeId, boolean isIngredient) {
return of(groupId, stack, factor, recipeId, isIngredient, generatePermutations(stack, recipeId, isIngredient));
}
public static BookmarkItem of(int groupId, ItemStack stack) {
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(stack);
final long factor = nbTag.hasKey("gtFluidName") ? Math.min(144, nbTag.getInteger("Count")) : 1;
return BookmarkItem
.of(groupId, stack, factor, null, false, Collections.singletonMap(getItemGUID(stack), stack));
}
public BookmarkItem copyWithAmount(long amount) {
return new BookmarkItem(
this.groupId,
amount,
this.fluidCellAmount,
this.itemStack,
this.permutations,
this.factor,
this.recipeId,
this.isIngredient);
}
public BookmarkItem copy() {
return copyWithAmount(this.amount);
}
public static Map<String, ItemStack> generatePermutations(ItemStack stack, RecipeId recipeId,
boolean isIngredient) {
if (isIngredient && recipeId != null) {
return generatePermutations(stack, Recipe.of(recipeId));
}
return Collections.singletonMap(getItemGUID(stack), stack);
}
public static Map<String, ItemStack> generatePermutations(ItemStack stack, Recipe recipe) {
if (recipe != null) {
final RecipeIngredient ingr = recipe.getIngredients().stream()
.filter(ingredient -> ingredient.contains(stack)).findAny().orElse(null);
if (ingr != null) {
final Map<String, ItemStack> permutations = new HashMap<>();
for (ItemStack ingrStack : ingr.getPermutations()) {
permutations.put(getItemGUID(ingrStack), ingrStack);
}
return permutations;
}
}
return Collections.singletonMap(getItemGUID(stack), stack);
}
private static synchronized String getItemGUID(ItemStack stack) {
final FluidStack fluidStack = StackInfo.getFluid(stack);
if (fluidStack != null) {
return fluidStack.getFluid().getName() + ":" + fluidStack.tag;
} else {
for (Map.Entry<ItemStack, String> entry : BookmarkItem.fuzzyPermutations.entrySet()) {
if (NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack, entry.getKey())) {
BookmarkItem.fuzzyPermutations.put(stack, entry.getValue());
return entry.getValue();
}
}
final String stackGUID = StackInfo.getItemStackGUID(stack);
BookmarkItem.fuzzyPermutations.put(stack, stackGUID);
return stackGUID;
}
}
public boolean containsItems(BookmarkItem item) {
return this.permutations.keySet().stream().anyMatch(item.permutations::containsKey);
}
public ItemStack getItemStack() {
return getItemStack(this.amount);
}
public ItemStack getItemStack(long amount) {
return StackInfo.withAmount(this.itemStack, getStackSize(amount));
}
public long getStackSize() {
return getStackSize(this.amount);
}
public long getStackSize(long amount) {
return (long) (this.factor > 0 ? Math.ceil(amount / (double) this.fluidCellAmount) : 0);
}
public long getMultiplier() {
return getMultiplier(this.amount);
}
public long getMultiplier(long amount) {
return (long) (this.factor > 0 ? Math.ceil(amount / (double) this.factor) : 0);
}
public long getFactor() {
return this.factor / this.fluidCellAmount;
}
public boolean equalsRecipe(BookmarkItem meta) {
return equalsRecipe(meta.recipeId, meta.groupId);
}
public boolean equalsRecipe(RecipeId recipeId, int groupId) {
return groupId == this.groupId && recipeId != null && recipeId.equals(this.recipeId);
}
@Override
public int hashCode() {
return Objects.hash(this.groupId, this.fluidCellAmount, this.isIngredient, this.recipeId);
}
@Override
public boolean equals(Object object) {
if (object instanceof BookmarkItem item) {
return this.groupId == item.groupId && this.isIngredient == item.isIngredient
&& this.fluidCellAmount == item.fluidCellAmount
&& StackInfo.equalItemAndNBT(this.itemStack, item.itemStack, true)
&& (this.recipeId == item.recipeId || this.recipeId != null && this.recipeId.equals(item.recipeId));
}
return false;
}
}
@@ -0,0 +1,366 @@
package codechicken.nei.bookmark;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import org.apache.commons.io.IOUtils;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
public class BookmarkStorage {
protected List<BookmarkGrid> namespaces = new ArrayList<>();
protected int activeNamespaceIndex = 0;
protected File bookmarkFile = null;
public BookmarkStorage() {
this.namespaces.add(new BookmarkGrid());
}
public boolean prevNamespace() {
getNamespaceSize();
removeEmptyNamespaces();
if (this.activeNamespaceIndex == 0) {
setNamespace(getNamespaceSize() - 1);
} else {
setNamespace(this.activeNamespaceIndex - 1);
}
return true;
}
public boolean nextNamespace() {
if (removeEmptyNamespaces()) {
return true;
}
if (this.activeNamespaceIndex == getNamespaceSize() - 1) {
setNamespace(0);
} else {
setNamespace(this.activeNamespaceIndex + 1);
}
return true;
}
private void setNamespace(int namespaceIndex) {
this.activeNamespaceIndex = Math.min(namespaceIndex, this.namespaces.size() - 1);
BookmarkGrid grid = this.namespaces.get(this.activeNamespaceIndex);
if (grid.size() == 0 && this.activeNamespaceIndex > 0) {
grid.setViewMode(
BookmarkGrid.DEFAULT_GROUP_ID,
this.namespaces.get(this.activeNamespaceIndex - 1).getViewMode(BookmarkGrid.DEFAULT_GROUP_ID));
}
}
public int getNamespaceSize() {
if (this.namespaces.get(this.namespaces.size() - 1).size() > 0) {
this.namespaces.add(new BookmarkGrid());
} else if (this.activeNamespaceIndex == this.namespaces.size() - 2 && getActiveGrid().size() == 0) {
this.namespaces.remove(this.namespaces.size() - 1);
}
return this.namespaces.size();
}
public boolean isEmpty() {
return this.namespaces.size() <= 1 && getActiveGrid().isEmpty();
}
public int getActiveIndex() {
return this.activeNamespaceIndex;
}
public BookmarkGrid getActiveGrid() {
return this.namespaces.get(this.activeNamespaceIndex);
}
private boolean removeEmptyNamespaces() {
if (this.activeNamespaceIndex != this.namespaces.size() - 1 && getActiveGrid().size() == 0) {
this.namespaces.remove(this.activeNamespaceIndex);
setNamespace(this.activeNamespaceIndex);
return true;
}
return false;
}
public void load(File bookmarkFile) {
if (bookmarkFile.equals(this.bookmarkFile)) {
return;
}
List<String> itemStrings = Collections.emptyList();
if (bookmarkFile.exists()) {
try (FileInputStream reader = new FileInputStream(bookmarkFile)) {
NEIClientConfig.logger.info("Loading bookmarks from file {}", bookmarkFile);
itemStrings = IOUtils.readLines(reader, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load bookmarks from file {}", bookmarkFile, e);
return;
}
}
final JsonParser parser = new JsonParser();
final List<BookmarkGrid> namespaces = new ArrayList<>();
NBTTagCompound navigation = new NBTTagCompound();
namespaces.add(new BookmarkGrid());
BookmarkGrid grid = namespaces.get(0);
if (NEIClientConfig.world.nbt.hasKey("bookmark")) {
navigation = NEIClientConfig.world.nbt.getCompoundTag("bookmark");
}
for (String itemStr : itemStrings) {
try {
if (itemStr.isEmpty()) {
itemStr = "; {}";
}
if (itemStr.startsWith("; ")) {
JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
if (grid.size() > 0) {
// do not create empty namespaces
grid = new BookmarkGrid();
namespaces.add(grid);
}
if (navigation.hasKey("namespacePage." + (namespaces.size() - 1))) {
grid.setPage(navigation.getInteger("namespacePage." + (namespaces.size() - 1)));;
}
if (settings.get("viewmode") != null) {
grid.groups.get(BookmarkGrid.DEFAULT_GROUP_ID).viewMode = BookmarkViewMode
.valueOf(settings.get("viewmode").getAsString());
} else if (settings.get("groups") instanceof JsonObject jsonObject) {
BookmarkGroup group;
for (Map.Entry<String, JsonElement> jsonEntry : jsonObject.entrySet()) {
if (jsonEntry.getValue() instanceof JsonObject value) {
group = new BookmarkGroup(
value.has("viewmode")
? BookmarkViewMode.valueOf(value.get("viewmode").getAsString())
: BookmarkViewMode.DEFAULT,
value.has("crafting") && value.get("crafting").getAsBoolean());
group.collapsed = value.has("collapsed") && value.get("collapsed").getAsBoolean();
if (value.has("collapsedRecipes")) {
for (JsonElement recipeId : value.get("collapsedRecipes").getAsJsonArray()) {
if (recipeId instanceof JsonObject item) {
group.collapsedRecipes.add(RecipeId.of(item));
}
}
}
grid.groups.put(Integer.valueOf(jsonEntry.getKey()), group);
}
}
}
continue;
}
if (!addItemToGrid(grid, parser.parse(itemStr).getAsJsonObject())) {
NEIClientConfig.logger.warn(
"Failed to load bookmarked ItemStack from json string, the item no longer exists:\n{}",
itemStr);
}
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
NEIClientConfig.logger.error("Failed to load bookmarked ItemStack from json string:\n{}", itemStr);
}
}
prepareOldRecipeFormat(namespaces);
for (BookmarkGrid gr : namespaces) {
gr.onItemsChanged();
}
this.namespaces = namespaces;
if (navigation.hasKey("namespaceIndex")) {
setNamespace(navigation.getInteger("namespaceIndex"));
} else {
setNamespace(0);
}
this.bookmarkFile = bookmarkFile;
}
private boolean addItemToGrid(BookmarkGrid grid, JsonObject jsonObject) {
NBTTagCompound itemStackNBT;
if (jsonObject.get("item") != null) {
itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject.get("item"));
} else { // old format
itemStackNBT = (NBTTagCompound) NBTJson.toNbt(jsonObject);
}
ItemStack itemStack = StackInfo.loadFromNBT(itemStackNBT);
if (itemStack != null) {
RecipeId recipeId = null;
boolean isFluid = itemStackNBT.hasKey("gtFluidName");
int groupId = jsonObject.has("groupId") ? jsonObject.get("groupId").getAsInt()
: BookmarkGrid.DEFAULT_GROUP_ID;
int factor = jsonObject.has("factor") ? Math.abs(jsonObject.get("factor").getAsInt()) : (isFluid ? 144 : 1);
boolean isIngredient = jsonObject.has("ingredient") && jsonObject.get("ingredient").getAsBoolean();
if (jsonObject.get("recipeId") instanceof JsonObject recipeJson) {
recipeId = RecipeId.of(recipeJson);
}
if (!grid.groups.containsKey(groupId)) {
groupId = BookmarkGrid.DEFAULT_GROUP_ID;
}
grid.addItem(BookmarkItem.of(groupId, itemStack, factor, recipeId, isIngredient), false);
}
return itemStack != null;
}
private void prepareOldRecipeFormat(List<BookmarkGrid> namespaces) {
for (BookmarkGrid grid : namespaces) {
if (grid.bookmarkItems.stream()
.noneMatch(item -> item.recipeId != null && item.recipeId.getResult() == null)) {
continue;
}
final Map<String, RecipeId> recipes = new HashMap<>();
for (BookmarkItem item : grid.bookmarkItems) {
if (item.recipeId != null && !item.isIngredient && item.recipeId.getResult() == null) {
final JsonObject recipeJson = item.recipeId.toJsonObject();
final String recipeGUID = item.groupId + ":" + NBTJson.toJson(recipeJson);
if (!recipes.containsKey(recipeGUID)) {
recipeJson.add("result", NBTJson.toJsonObject(StackInfo.itemStackToNBT(item.itemStack)));
recipes.put(recipeGUID, item.recipeId = RecipeId.of(recipeJson));
}
}
}
for (BookmarkItem item : grid.bookmarkItems) {
if (item.recipeId != null && item.recipeId.getResult() == null) {
final JsonObject recipeJson = item.recipeId.toJsonObject();
final String recipeGUID = item.groupId + ":" + NBTJson.toJson(recipeJson);
if (recipes.containsKey(recipeGUID)) {
item.recipeId = recipes.get(recipeGUID).copy();
item.permutations = BookmarkItem
.generatePermutations(item.itemStack, item.recipeId, item.isIngredient);
} else {
item.recipeId = null;
}
}
}
}
}
public void save() {
if (this.bookmarkFile == null) {
return;
}
List<String> strings = new ArrayList<>();
NBTTagCompound navigation = new NBTTagCompound();
navigation.setInteger("namespaceIndex", this.activeNamespaceIndex);
for (int grpIdx = 0; grpIdx < namespaces.size(); grpIdx++) {
BookmarkGrid grid = namespaces.get(grpIdx);
JsonObject settings = new JsonObject();
JsonObject groups = new JsonObject();
for (int groupId : grid.groups.keySet()) {
BookmarkGroup group = grid.groups.get(groupId);
JsonObject groupJson = new JsonObject();
groupJson.add("viewmode", new JsonPrimitive(group.viewMode.toString()));
groupJson.add("crafting", new JsonPrimitive(group.crafting != null));
groupJson.add("collapsed", new JsonPrimitive(group.collapsed));
if (!group.collapsedRecipes.isEmpty()) {
JsonArray collapsedRecipes = new JsonArray();
for (RecipeId recipeId : group.collapsedRecipes) {
collapsedRecipes.add(recipeId.toJsonObject());
}
groupJson.add("collapsedRecipes", collapsedRecipes);
}
groups.add(String.valueOf(groupId), groupJson);
}
settings.add("groups", groups);
strings.add("; " + NBTJson.toJson(settings));
navigation.setInteger("namespacePage." + grpIdx, grid.getPage() - 1);
for (BookmarkItem item : grid.bookmarkItems) {
try {
JsonObject row = new JsonObject();
row.add("item", NBTJson.toJsonObject(StackInfo.itemStackToNBT(item.getItemStack())));
row.add("factor", new JsonPrimitive(item.getFactor()));
row.add("ingredient", new JsonPrimitive(item.isIngredient));
if (item.groupId != BookmarkGrid.DEFAULT_GROUP_ID) {
row.add("groupId", new JsonPrimitive(item.groupId));
}
if (item.recipeId != null) {
row.add("recipeId", item.recipeId.toJsonObject());
}
strings.add(NBTJson.toJson(row));
} catch (JsonSyntaxException e) {
NEIClientConfig.logger.error("Failed to stringify bookmarked ItemStack to json string");
}
}
}
try (FileOutputStream output = new FileOutputStream(bookmarkFile)) {
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
NEIClientConfig.world.nbt.setTag("bookmark", navigation);
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save bookmarks list to file {}", bookmarkFile, e);
}
}
}
@@ -0,0 +1,322 @@
package codechicken.nei.bookmark;
import java.awt.Color;
import net.minecraft.item.ItemStack;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.ItemPanels;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.ItemsGrid.MouseContext;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIClientUtils.Alignment;
import codechicken.nei.bookmark.BookmarkGrid.BookmarkMouseContext;
import codechicken.nei.bookmark.RecipeChainDetails.CalculatedType;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.ReadableNumberConverter;
public class BookmarksGridSlot extends ItemsGridSlot {
protected enum ShownItemType {
REAL,
SHIFT,
CALCULATED
}
protected static final float LINE_WIDTH = 0.75f;
protected static final Color INGREDIENTS_COLOR = new Color(0x6645DA75, true);
protected static final Color RESULTS_COLOR = new Color(0x9966CCFF, true);
protected static final Color RESULTS_BG_COLOR = new Color(0x3366CCFF, true);
protected static final Color RESULTS_BG_FLUID_COLOR = new Color(0x5566CCFF, true);
protected static final Color REMAINDER_COLOR = new Color(0x55A033A0, true);
protected static final Color REMAINDER_BG_COLOR = new Color(0x33A033A0, true);
protected static final Color REMAINDER_BG_FLUID_COLOR = new Color(0x44A033A0, true);
protected final ItemStack emptyItemStack;
protected final long realAmount;
protected final long shiftAmount;
protected final long calculatedAmount;
protected final long realMultiplier;
protected final long calculatedMultiplier;
protected final BookmarkGroup group;
protected final boolean isFluidDisplay;
protected final CalculatedType calculatedType;
protected final CalculatedType realType;
protected final BookmarkItem bookmarkItem;
protected final boolean isOutputRecipe;
protected final boolean isFirstOutput;
protected final int rowIndex;
public BookmarksGridSlot(int slotIndex, int itemIndex, long realAmount, long shiftAmount, long calculatedAmount,
BookmarkItem bookmarkItem, CalculatedType calculatedType, BookmarkGroup group) {
super(
slotIndex,
itemIndex,
calculatedType != null ? bookmarkItem.getItemStack(calculatedAmount)
: bookmarkItem.getItemStack(realAmount));
this.emptyItemStack = bookmarkItem.getItemStack(0);
this.realAmount = realAmount;
this.shiftAmount = shiftAmount;
this.calculatedAmount = calculatedAmount;
this.group = group;
this.calculatedType = calculatedType;
this.bookmarkItem = bookmarkItem;
this.isOutputRecipe = group.crafting != null && group.crafting.outputRecipes.contains(bookmarkItem.recipeId);
this.isFluidDisplay = StackInfo.itemStackToNBT(bookmarkItem.itemStack).hasKey("gtFluidName");
this.realMultiplier = bookmarkItem.getMultiplier(realAmount);
this.calculatedMultiplier = bookmarkItem.getMultiplier(calculatedAmount);
if (this.group.crafting != null && this.group.crafting.calculatedItems.containsKey(this.itemIndex)) {
this.realType = this.group.crafting.calculatedItems.get(this.itemIndex).calculatedType
== CalculatedType.INGREDIENT ? CalculatedType.INGREDIENT : CalculatedType.RESULT;
} else {
this.realType = this.bookmarkItem.isIngredient
|| this.group.crafting != null && this.bookmarkItem.recipeId == null ? CalculatedType.INGREDIENT
: CalculatedType.RESULT;
}
final BookmarkGrid grid = ItemPanels.bookmarkPanel.getGrid();
final BookmarkItem prevItem = grid.getCalculatedItem(
grid.gridGenerator.slotToItem.getOrDefault(grid.gridGenerator.itemToSlot.get(this.itemIndex) - 1, -1));
this.isFirstOutput = this.itemIndex >= 0 && !this.bookmarkItem.isIngredient
&& ((this.slotIndex % grid.getColumns()) == 0 || group.viewMode == BookmarkViewMode.DEFAULT)
&& (prevItem == null || prevItem.isIngredient || !this.bookmarkItem.equalsRecipe(prevItem));
this.rowIndex = this.slotIndex / grid.getColumns();
}
public long getMultiplier() {
return this.calculatedType != null ? this.calculatedMultiplier : this.realMultiplier;
}
public BookmarkItem getBookmarkItem() {
return this.bookmarkItem;
}
public RecipeId getRecipeId() {
return this.bookmarkItem.recipeId;
}
public boolean isIngredient() {
return this.bookmarkItem.isIngredient;
}
public BookmarkGroup getGroup() {
return this.group;
}
public int getGroupId() {
return this.bookmarkItem.groupId;
}
protected ShownItemType getShownItemType(BookmarkMouseContext mouseContext) {
if (mouseContext != null) {
if (this.showShiftItem(mouseContext)) {
return ShownItemType.SHIFT;
} else if (this.showRealItem(mouseContext)) {
return ShownItemType.REAL;
}
}
if (this.calculatedType != null) {
return ShownItemType.CALCULATED;
}
return null;
}
protected boolean showShiftItem(BookmarkMouseContext mouseContext) {
if (!mouseContext.shiftKey || this.bookmarkItem.groupId != mouseContext.groupId) {
return false;
}
if (this.group.crafting != null) {
return true;
}
return this.bookmarkItem.equalsRecipe(mouseContext.recipeId, mouseContext.groupId);
}
protected boolean showRealItem(BookmarkMouseContext mouseContext) {
if (!mouseContext.controlKey || this.bookmarkItem.groupId != mouseContext.groupId) {
return false;
}
if (this.slotIndex == mouseContext.slotIndex || this.group.collapsed) {
return true;
}
if (mouseContext.recipeId == null && this.group.viewMode == BookmarkViewMode.TODO_LIST
&& mouseContext.rowIndex == this.rowIndex) {
return true;
}
if (this.bookmarkItem.equalsRecipe(mouseContext.recipeId, mouseContext.groupId)) {
return true;
}
return this.group.crafting != null && mouseContext.recipeId != null
&& mouseContext.recipeId.equals(this.group.crafting.itemToRecipe.get(this.itemIndex));
}
@Override
public void drawItem(Rectangle4i rect) {
super.drawItem(this.emptyItemStack, rect);
}
@Override
public <M extends MouseContext> void beforeDraw(Rectangle4i rect, M mouseContext) {
final ShownItemType shownItemType = getShownItemType((BookmarkMouseContext) mouseContext);
boolean showMarker = NEIClientConfig.showRecipeMarkerMode() == 2;
CalculatedType calculatedType = null;
if (shownItemType == ShownItemType.REAL) {
calculatedType = this.realType;
} else if (shownItemType == ShownItemType.SHIFT) {
if (this.calculatedType != null) {
calculatedType = this.shiftAmount > 0 ? this.calculatedType : null;
showMarker = false;
} else if (group.crafting == null) {
calculatedType = this.realType;
}
}
if (!this.bookmarkItem.isIngredient && this.bookmarkItem.recipeId != null
&& calculatedType == null
&& showMarker
&& (mouseContext == null || mouseContext.slotIndex != this.slotIndex)) {
drawMerkerBackground(rect);
}
if (calculatedType == null || !drawBackground(rect, calculatedType)) {
super.beforeDraw(rect, mouseContext);
}
}
protected boolean drawBackground(Rectangle4i rect, CalculatedType calculatedType) {
switch (calculatedType) {
case INGREDIENT:
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, INGREDIENTS_COLOR);
break;
case RESULT:
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, RESULTS_COLOR);
break;
case REMAINDER:
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, REMAINDER_COLOR);
break;
default:
return false;
}
return true;
}
protected void drawMerkerBackground(Rectangle4i rect) {
Color color = this.isFluidDisplay ? RESULTS_BG_FLUID_COLOR : RESULTS_BG_COLOR;
if (this.shiftAmount > 0 && this.calculatedType == CalculatedType.REMAINDER) {
color = this.isFluidDisplay ? REMAINDER_BG_FLUID_COLOR : REMAINDER_BG_COLOR;
}
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, color);
}
@Override
public <M extends MouseContext> void afterDraw(Rectangle4i rect, M mouseContext) {
final ShownItemType shownItemType = getShownItemType((BookmarkMouseContext) mouseContext);
drawStackSize(rect, shownItemType);
if (this.bookmarkItem.isIngredient || this.bookmarkItem.recipeId == null) {
return;
}
if (this.isFirstOutput) {
if (shownItemType == ShownItemType.REAL) {
drawMarker(
rect,
"x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(this.realMultiplier),
0xFFFFFF);
} else if (shownItemType == ShownItemType.SHIFT) {
drawMarker(rect, "x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(getMultiplier()), 0xFFFFFF);
} else if (this.isOutputRecipe || this.realMultiplier > 1) {
drawMarker(
rect,
"x" + ReadableNumberConverter.INSTANCE.toWideReadableForm(this.realMultiplier),
NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue());
} else if (NEIClientConfig.showRecipeMarkerMode() == 1) {
drawMarker(
rect,
"R",
NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue());
}
} else if (NEIClientConfig.showRecipeMarkerMode() == 1) {
drawMarker(rect, "R", NEIClientConfig.getSetting("inventory.bookmarks.recipeMarkerColor").getHexValue());
}
}
protected void drawMarker(Rectangle4i rect, String text, int color) {
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
NEIClientUtils.drawNEIOverlayText(
text,
new Rectangle4i(rect.x + 1, rect.y + 1, rect.w - 2, rect.h - 2),
panelFactor,
color,
true,
Alignment.TopLeft);
}
protected void drawStackSize(Rectangle4i rect, ShownItemType shownItemType) {
long amount = this.calculatedAmount;
if (shownItemType == null || shownItemType == ShownItemType.REAL || this.calculatedType == null) {
amount = this.realAmount;
} else if (shownItemType == ShownItemType.SHIFT) {
amount = this.shiftAmount;
}
if (amount > 0 || shownItemType == ShownItemType.REAL && this.bookmarkItem.factor > 0) {
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
final long stackSize = this.bookmarkItem.getStackSize(amount);
String amountString = "";
if (stackSize < 10_000) {
amountString = String.valueOf(stackSize);
} else {
amountString = ReadableNumberConverter.INSTANCE.toWideReadableForm(stackSize);
}
if (this.isFluidDisplay) {
amountString += "L";
}
NEIClientUtils.drawNEIOverlayText(
amountString,
new Rectangle4i(rect.x + 1, rect.y + 1, rect.w - 2, rect.h - 2),
panelFactor,
0xFFFFFF,
true,
this.isFluidDisplay ? Alignment.BottomLeft : Alignment.BottomRight);
}
}
}
@@ -0,0 +1,190 @@
package codechicken.nei.bookmark;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.recipe.Recipe.RecipeId;
public class GroupingItem {
public static class PointEntry {
public int cursorRowIndex;
public int topRowIndex;
public int bottomRowIndex;
public PointEntry(int clickSlotIndex, int topSlotIndex, int bottomSlotIndex) {
this.cursorRowIndex = clickSlotIndex;
this.topRowIndex = topSlotIndex;
this.bottomRowIndex = bottomSlotIndex;
}
}
public BookmarkGrid grid;
public int groupId = -1;
public PointEntry startPoint;
public PointEntry endPoint;
public GroupingItem(BookmarkGrid grid, int groupId, int overRowIndex) {
this.groupId = groupId;
this.grid = grid;
setStartPoint(overRowIndex);
}
public void setStartPoint(int overRowIndex) {
if (this.grid.getRowItemIndex(overRowIndex, true) != Integer.MIN_VALUE) {
this.startPoint = new PointEntry(
overRowIndex + getRowShift(),
getTopRowIndex(overRowIndex),
getBottomRowIndex(overRowIndex));
} else {
this.startPoint = new PointEntry(overRowIndex + getRowShift(), -1, -1);
}
}
public void setEndPoint(int overRowIndex) {
if (this.grid.getRowItemIndex(overRowIndex, true) != Integer.MIN_VALUE) {
this.endPoint = new PointEntry(
overRowIndex + getRowShift(),
getTopRowIndex(overRowIndex),
getBottomRowIndex(overRowIndex));
}
}
public int getStartSlotIndex() {
return this.startPoint.cursorRowIndex - getRowShift();
}
public int getEndSlotIndex() {
return this.endPoint != null ? this.endPoint.cursorRowIndex - getRowShift() : 0;
}
public boolean hasEndRow() {
return this.endPoint != null;
}
private int getRowShift() {
return (this.grid.getPage() - 1) * this.grid.getRows();
}
public Map<Integer, Integer> prepareGroups(Map<Integer, Integer> groups) {
final int topRowIndex = Math.min(this.startPoint.topRowIndex, this.endPoint.topRowIndex);
final int bottomRowIndex = Math.max(this.startPoint.bottomRowIndex, this.endPoint.bottomRowIndex);
groups = new HashMap<>(groups);
if (this.groupId != BookmarkGrid.DEFAULT_GROUP_ID) {
if (this.startPoint.cursorRowIndex > this.endPoint.cursorRowIndex) {
int rowIndex = this.endPoint.topRowIndex - 1;
while (groups.containsKey(rowIndex) && groups.get(rowIndex) == this.groupId) {
groups.put(rowIndex--, BookmarkGrid.DEFAULT_GROUP_ID);
}
} else if (this.startPoint.cursorRowIndex < this.endPoint.cursorRowIndex) {
int rowIndex = this.endPoint.bottomRowIndex + 1;
while (groups.containsKey(rowIndex) && groups.get(rowIndex) == this.groupId) {
groups.put(rowIndex++, BookmarkGrid.DEFAULT_GROUP_ID);
}
}
} else if (groups.containsKey(topRowIndex - 1)
&& groups.get(topRowIndex - 1).equals(groups.get(bottomRowIndex + 1))) {
int groupId = groups.get(bottomRowIndex);
int rowIndex = bottomRowIndex + 1;
while (groups.containsKey(rowIndex) && groups.get(rowIndex) == groupId) {
groups.put(rowIndex, -1 * groups.get(rowIndex));
rowIndex++;
}
}
for (int rowIndex = topRowIndex; rowIndex <= bottomRowIndex && groups.containsKey(rowIndex); rowIndex++) {
groups.put(rowIndex, this.groupId);
}
return groups;
}
protected int getTopRowIndex(int overRowIndex) {
final int rowShift = getRowShift();
int itemIndex = this.grid.getRowItemIndex(overRowIndex, true);
if (itemIndex == Integer.MIN_VALUE) {
return -1;
}
final BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
if (item.recipeId != null) {
final List<Integer> sortedItems = this.grid.getSortedItems();
final BookmarkGroup group = this.grid.getGroup(item.groupId);
final boolean isCollapsedGroup = group.collapsed
|| group.crafting != null && group.viewMode == BookmarkViewMode.DEFAULT;
final RecipeId recipeId = group.crafting != null
? group.crafting.itemToRecipe.getOrDefault(itemIndex, item.recipeId)
: item.recipeId;
final Set<RecipeId> recipeRelations = group.crafting != null
? group.crafting.recipeRelations.getOrDefault(recipeId, Collections.singleton(recipeId))
: Collections.singleton(recipeId);
for (Integer rItemIndex : sortedItems) {
final BookmarkItem rItem = this.grid.getCalculatedItem(rItemIndex);
if (rItem.groupId == item.groupId && (isCollapsedGroup || recipeRelations.contains(rItem.recipeId))) {
return this.grid.getAbsoluteSlotIndex(rItemIndex) / this.grid.getColumns();
}
}
return -1;
}
return rowShift + overRowIndex;
}
protected int getBottomRowIndex(int overRowIndex) {
final int rowShift = getRowShift();
final int itemIndex = this.grid.getRowItemIndex(overRowIndex, false);
if (itemIndex == Integer.MIN_VALUE) {
return -1;
}
final BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
if (item.recipeId != null) {
final List<Integer> sortedItems = this.grid.getSortedItems();
final BookmarkGroup group = this.grid.getGroup(item.groupId);
final boolean isCollapsedGroup = group.collapsed
|| group.crafting != null && group.viewMode == BookmarkViewMode.DEFAULT;
final RecipeId recipeId = group.crafting != null
? group.crafting.itemToRecipe.getOrDefault(itemIndex, item.recipeId)
: item.recipeId;
final Set<RecipeId> recipeRelations = group.crafting != null
? group.crafting.recipeRelations.getOrDefault(recipeId, Collections.singleton(recipeId))
: Collections.singleton(recipeId);
for (int index = sortedItems.size() - 1; index >= 0; index--) {
final int rItemIndex = sortedItems.get(index);
final BookmarkItem rItem = this.grid.getCalculatedItem(rItemIndex);
if (rItem.groupId == item.groupId && (isCollapsedGroup || recipeRelations.contains(rItem.recipeId))) {
return this.grid.getAbsoluteSlotIndex(rItemIndex) / this.grid.getColumns();
}
}
return -1;
}
return rowShift + overRowIndex;
}
}
@@ -0,0 +1,374 @@
package codechicken.nei.bookmark;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import net.minecraft.item.ItemStack;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.recipe.chain.RecipeChainMath;
public class RecipeChainDetails {
public enum CalculatedType {
INGREDIENT,
RESULT,
REMAINDER;
public int toInt() {
switch (this) {
case RESULT:
return 0;
case REMAINDER:
return 1;
case INGREDIENT:
return 2;
}
return -1;
}
}
public static class BookmarkChainItem {
private final BookmarkItem item;
private long realAmount = 0L;
private long shiftAmount = 0L;
private long calculatedAmount = 0L;
public CalculatedType calculatedType;
protected BookmarkChainItem(BookmarkItem item, long shiftItem, long calculatedItem,
CalculatedType calculatedType) {
this.item = item.copy();
this.shiftAmount = shiftItem;
this.calculatedAmount = calculatedItem;
this.calculatedType = calculatedType;
}
public static BookmarkChainItem of(BookmarkItem item, long shiftItem, long calculatedAmount,
CalculatedType calculatedType) {
return new BookmarkChainItem(item, shiftItem, calculatedAmount, calculatedType);
}
public static BookmarkChainItem of(BookmarkItem item, long shiftItem, CalculatedType calculatedType) {
return new BookmarkChainItem(item, shiftItem, item.amount, calculatedType);
}
public static BookmarkChainItem of(BookmarkItem item) {
return new BookmarkChainItem(
item,
item.amount,
item.amount,
item.isIngredient ? CalculatedType.INGREDIENT : CalculatedType.RESULT);
}
public ItemStack getItemStack(long amount) {
return this.item.getItemStack(amount);
}
public void setRealAmount(long amount) {
this.realAmount = amount;
}
public long getRealAmount() {
return this.realAmount;
}
public long getShiftAmount() {
return this.shiftAmount;
}
public long getCalculatedAmount() {
return this.calculatedAmount;
}
public BookmarkItem getItem() {
return this.item;
}
public void append(long amount, long calculatedAmount) {
this.shiftAmount += amount;
this.calculatedAmount += calculatedAmount;
this.item.amount = this.calculatedAmount;
}
}
public final Map<Integer, BookmarkChainItem> calculatedItems = new HashMap<>();
public final Map<Integer, RecipeId> itemToRecipe = new HashMap<>();
public final Set<RecipeId> outputRecipes = new HashSet<>();
public final Set<RecipeId> recipeInMiddle = new HashSet<>();
public final Map<RecipeId, Set<RecipeId>> recipeRelations = new HashMap<>();
public void refresh(Map<Integer, BookmarkItem> chainItems, Set<RecipeId> collapsedRecipes) {
final Map<BookmarkItem, Integer> sortingChainItems = new HashMap<>();
for (Map.Entry<Integer, BookmarkItem> entry : chainItems.entrySet()) {
sortingChainItems.put(entry.getValue(), entry.getKey());
}
this.itemToRecipe.clear();
this.outputRecipes.clear();
this.recipeInMiddle.clear();
this.calculatedItems.clear();
this.recipeRelations.clear();
final RecipeChainMath math = RecipeChainMath.of(new ArrayList<>(chainItems.values()), collapsedRecipes)
.refresh();
this.outputRecipes.addAll(math.outputRecipes.keySet());
for (BookmarkItem item : math.preferredItems.values()) {
if (item != null && item.recipeId != null) {
this.recipeInMiddle.add(item.recipeId);
}
}
for (BookmarkItem item : math.initialItems) {
this.calculatedItems.put(
sortingChainItems.get(item),
BookmarkChainItem.of(item, math.requiredAmount.getOrDefault(item, 0L), CalculatedType.INGREDIENT));
}
if (collapsedRecipes.isEmpty()) {
for (BookmarkItem item : math.recipeResults) {
generateResult(math, item, sortingChainItems.get(item));
}
for (BookmarkItem item : math.recipeIngredients) {
generateIngredient(math, item, sortingChainItems.get(item));
}
} else {
final Set<RecipeId> topLevelRecipes = findTopLevelRecipes(math, collapsedRecipes);
for (RecipeId recipeId : collapsedRecipes) {
this.recipeRelations.put(
recipeId,
getRecipeRelations(math, recipeId, topLevelRecipes, new HashSet<>(Arrays.asList(recipeId))));
generateCollapsedRecipe(math, recipeId, topLevelRecipes, sortingChainItems);
generateShadowItems(recipeId, chainItems.values(), sortingChainItems);
}
for (BookmarkItem item : math.recipeResults) {
if (!collapsedRecipes.contains(item.recipeId) && topLevelRecipes.contains(item.recipeId)) {
generateResult(math, item, sortingChainItems.get(item));
}
}
for (BookmarkItem item : math.recipeIngredients) {
if (!collapsedRecipes.contains(item.recipeId) && topLevelRecipes.contains(item.recipeId)) {
generateIngredient(math, item, sortingChainItems.get(item));
}
}
}
for (Map.Entry<Integer, BookmarkItem> entry : chainItems.entrySet()) {
final int itemIndex = entry.getKey();
if (itemIndex >= 0 && this.calculatedItems.containsKey(itemIndex)) {
final BookmarkItem item = entry.getValue();
if (this.recipeInMiddle.contains(item.recipeId)) {
this.calculatedItems.get(itemIndex).setRealAmount(item.amount);
} else {
this.calculatedItems.get(itemIndex).setRealAmount(Math.max(item.factor, item.amount));
}
}
}
}
private Set<RecipeId> getRecipeRelations(RecipeChainMath math, RecipeId recipeId, Set<RecipeId> topLevelRecipes,
Set<RecipeId> recipes) {
for (BookmarkItem item : math.recipeIngredients) {
if (item.recipeId.equals(recipeId)) {
final BookmarkItem prefItem = math.preferredItems.get(item);
if (prefItem != null && !topLevelRecipes.contains(prefItem.recipeId)
&& recipes.add(prefItem.recipeId)) {
getRecipeRelations(math, prefItem.recipeId, topLevelRecipes, recipes);
}
}
}
return recipes;
}
private void generateCollapsedRecipe(RecipeChainMath math, RecipeId recipeId, Set<RecipeId> topLevelRecipes,
Map<BookmarkItem, Integer> sortingChainItems) {
final List<BookmarkChainItem> items = collectItems(
math,
recipeId,
this.recipeRelations.get(recipeId),
topLevelRecipes);
for (BookmarkChainItem value : items) {
int itemIndex = sortingChainItems.get(value.getItem());
if (value.getItem().isIngredient || !recipeId.equals(value.getItem().recipeId)) {
itemIndex *= -1;
}
if (!value.getItem().isIngredient && !math.outputRecipes.containsKey(value.getItem().recipeId)) {
value.calculatedType = CalculatedType.REMAINDER;
}
this.itemToRecipe.put(itemIndex, recipeId);
this.calculatedItems.put(itemIndex, value);
}
}
private void generateShadowItems(RecipeId recipeId, Iterable<BookmarkItem> chainItems,
Map<BookmarkItem, Integer> sortingChainItems) {
final Set<RecipeId> recipeRelations = this.recipeRelations.get(recipeId);
final List<BookmarkItem> subChainItems = new ArrayList<>();
for (BookmarkItem item : chainItems) {
if (recipeRelations.contains(item.recipeId)) {
subChainItems.add(item.copyWithAmount(recipeId.equals(item.recipeId) ? item.amount : 0));
}
}
final RecipeChainMath math = RecipeChainMath.of(subChainItems, Collections.emptySet()).refresh();
final List<BookmarkChainItem> items = collectItems(
math,
recipeId,
this.recipeRelations.get(recipeId),
Collections.emptySet());
for (BookmarkChainItem value : items) {
int itemIndex = sortingChainItems.get(value.getItem());
if (value.getItem().isIngredient || !recipeId.equals(value.getItem().recipeId)) {
itemIndex *= -1;
}
if (this.calculatedItems.containsKey(itemIndex)) {
this.calculatedItems.get(itemIndex).setRealAmount(value.getShiftAmount());
}
}
}
private List<BookmarkChainItem> collectItems(RecipeChainMath math, RecipeId recipeId, Set<RecipeId> recipeRelations,
Set<RecipeId> topLevelRecipes) {
final Map<String, BookmarkChainItem> items = new HashMap<>();
final Map<RecipeId, Long> multiplier = new HashMap<>();
for (RecipeId relRecipeId : recipeRelations) {
for (BookmarkItem item : math.recipeResults) {
if (item.recipeId.equals(relRecipeId)) {
final long amount = item.amount - math.requiredAmount.getOrDefault(item, 0L);
if (item.recipeId.equals(recipeId)) {
multiplier.put(item.recipeId, item.getMultiplier());
items.computeIfAbsent(
StackInfo.getItemStackGUID(item.itemStack),
is -> BookmarkChainItem.of(item, 0, 0, CalculatedType.RESULT))
.append(amount, item.amount);
} else if (amount > 0) {
items.computeIfAbsent(
StackInfo.getItemStackGUID(item.itemStack),
is -> BookmarkChainItem.of(item, 0, 0, CalculatedType.RESULT)).append(amount, amount);
}
}
}
for (BookmarkItem item : math.recipeIngredients) {
if (item.recipeId.equals(relRecipeId)) {
final BookmarkItem prefItem = math.preferredItems.get(item);
final long amount = math.requiredAmount.containsKey(prefItem) ? 0
: math.requiredAmount.getOrDefault(item, item.amount);
final long refAmount = prefItem != null && !topLevelRecipes.contains(prefItem.recipeId)
? math.requiredAmount.getOrDefault(prefItem, 0L)
: 0;
if (amount != 0 || item.amount > refAmount && math.requiredAmount.containsKey(prefItem)
|| recipeId.equals(item.recipeId) && multiplier.get(recipeId) == 0) {
items.computeIfAbsent(
StackInfo.getItemStackGUID(item.itemStack),
is -> BookmarkChainItem.of(item, 0, 0, CalculatedType.INGREDIENT))
.append(amount, item.amount - refAmount);
}
}
}
}
return new ArrayList<>(items.values());
}
private void generateResult(RecipeChainMath math, BookmarkItem item, int itemIndex) {
final long amount = item.amount - math.requiredAmount.getOrDefault(item, 0L);
final CalculatedType calculatedType = math.outputRecipes.containsKey(item.recipeId) ? CalculatedType.RESULT
: CalculatedType.REMAINDER;
this.calculatedItems.put(itemIndex, BookmarkChainItem.of(item, amount, calculatedType));
}
private void generateIngredient(RecipeChainMath math, BookmarkItem item, int itemIndex) {
final BookmarkItem prefItem = math.preferredItems.get(item);
final long amount = math.requiredAmount.containsKey(prefItem) ? 0
: math.requiredAmount.getOrDefault(item, item.amount);
this.calculatedItems.put(itemIndex, BookmarkChainItem.of(item, amount, CalculatedType.INGREDIENT));
}
private Set<RecipeId> findTopLevelRecipes(RecipeChainMath math, Set<RecipeId> collapsedRecipes) {
final Set<RecipeId> result = new HashSet<>(math.outputRecipes.keySet());
for (BookmarkItem item : math.recipeResults) {
if (!result.contains(item.recipeId)) {
final Set<RecipeId> parents = getRecipeParents(
math,
item.recipeId,
new HashSet<>(),
new HashSet<>(Arrays.asList(item.recipeId)));
if (parents.size() != 1 || parents.stream().noneMatch(collapsedRecipes::contains)) {
result.add(item.recipeId);
}
}
}
return result;
}
private Set<RecipeId> getRecipeParents(RecipeChainMath math, RecipeId recipeId, Set<RecipeId> parents,
Set<RecipeId> visited) {
final Set<RecipeId> recipeIds = math.preferredItems.entrySet().stream()
.filter(
entry -> entry.getValue() != null && recipeId.equals(entry.getValue().recipeId)
&& !visited.contains(entry.getKey().recipeId))
.map(entry -> entry.getKey().recipeId).collect(Collectors.toSet());
visited.addAll(recipeIds);
if (recipeIds.isEmpty()) {
parents.add(recipeId);
} else {
for (RecipeId ingrRecipeId : recipeIds) {
if (math.outputRecipes.containsKey(ingrRecipeId)) {
parents.add(ingrRecipeId);
} else {
getRecipeParents(math, ingrRecipeId, parents, visited);
}
}
}
return parents;
}
}
@@ -0,0 +1,83 @@
package codechicken.nei.bookmark;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import org.lwjgl.opengl.GL11;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.guihook.GuiContainerManager;
public class SortableGroup {
public int groupId;
public BookmarkGrid grid;
public int shiftX = 0;
public int shiftY = 0;
public SortableGroup(BookmarkGrid grid, int groupId) {
this.grid = grid;
this.groupId = groupId;
}
public void postDraw(int mousex, int mousey) {
Point startRect = null;
GuiContainerManager.drawItems.zLevel += 100;
for (BookmarksGridSlot slot : this.grid.getMask()) {
if (slot.getGroupId() == this.groupId) {
final Rectangle4i rect = this.grid.getSlotRect(slot.slotIndex);
if (startRect == null) {
startRect = new Point(rect.x - this.shiftX, rect.y - this.shiftY);
}
GuiContainerManager.drawItem(
mousex + rect.x - startRect.x + 1,
mousey + rect.y - startRect.y + 1,
slot.getItemStack(),
true,
"");
}
}
if (startRect != null) {
int startRowIndex = -1;
int endRowIndex = 0;
for (int rowIndex = 0; rowIndex < this.grid.getRows(); rowIndex++) {
if (this.grid.getRowGroupId(rowIndex) == this.groupId) {
if (startRowIndex == -1) {
startRowIndex = rowIndex;
}
endRowIndex = rowIndex;
}
}
GL11.glPushMatrix();
GL11.glTranslated(mousex - startRect.x, mousey - startRect.y, 0);
this.grid.drawGroup(this.groupId, startRowIndex, endRowIndex);
GL11.glPopMatrix();
}
GuiContainerManager.drawItems.zLevel -= 100;
}
public List<BookmarkItem> getBookmarkItems() {
final List<BookmarkItem> items = new ArrayList<>();
for (BookmarkItem item : this.grid.bookmarkItems) {
if (item.groupId == this.groupId) {
items.add(item);
}
}
return items;
}
}
@@ -0,0 +1,250 @@
package codechicken.nei.bookmark;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.ItemsGrid;
import codechicken.nei.bookmark.RecipeChainDetails.BookmarkChainItem;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.Recipe.RecipeId;
public class SortableItem {
public final BookmarkGrid grid;
public final BookmarkItem bookmarkItem;
public final boolean moveRecipe;
public final boolean crossGroup;
public final boolean isCollapsedRecipe;
public List<Integer> items = new ArrayList<>();
public int shiftX = -8;
public int shiftY = -8;
public SortableItem(BookmarkGrid grid, BookmarkItem bookmarkItem) {
final BookmarkGroup group = grid.getGroup(bookmarkItem.groupId);
this.grid = grid;
this.bookmarkItem = bookmarkItem.copy();
this.moveRecipe = bookmarkItem.recipeId != null && !bookmarkItem.isIngredient
&& (group.viewMode == BookmarkViewMode.TODO_LIST || group.crafting != null);
this.crossGroup = !group.collapsed && group.viewMode == BookmarkViewMode.TODO_LIST
&& !this.bookmarkItem.isIngredient;
this.isCollapsedRecipe = group.crafting != null && group.crafting.itemToRecipe.values().stream()
.anyMatch(recipeId -> this.bookmarkItem.equalsRecipe(recipeId, this.bookmarkItem.groupId));
this.update();
}
public void postDraw(int mousex, int mousey) {
Point startRect = null;
GuiContainerManager.drawItems.zLevel += 100;
for (Integer itemIndex : this.grid.getSortedItems()) {
if (this.items.contains(itemIndex)) {
final BookmarkItem item = this.grid.getCalculatedItem(itemIndex);
final int slotIndex = this.grid.gridGenerator.itemToSlot.get(itemIndex);
final Rectangle4i rect = this.grid
.getSlotRect(slotIndex % (this.grid.getRows() * this.grid.getColumns()));
if (startRect == null) {
startRect = new Point(rect.x - this.shiftX, rect.y - this.shiftY);
}
GuiContainerManager.drawItem(
mousex + rect.x - startRect.x + 1,
mousey + rect.y - startRect.y + 1,
item.getItemStack(),
true,
"");
}
}
GuiContainerManager.drawItems.zLevel -= 100;
}
public void update() {
final BookmarkGroup group = this.grid.getGroup(this.bookmarkItem.groupId);
this.items.clear();
if (group.collapsed) {
return;
}
for (Map.Entry<Integer, BookmarkChainItem> entry : this.grid.gridGenerator.caclulatedItems.entrySet()) {
if (containsItem(entry.getValue().getItem())) {
this.items.add(entry.getKey());
}
}
if (this.isCollapsedRecipe && group.crafting != null) {
for (Map.Entry<Integer, RecipeId> entry : group.crafting.itemToRecipe.entrySet()) {
if (this.bookmarkItem.equalsRecipe(entry.getValue(), this.bookmarkItem.groupId)) {
this.items.add(entry.getKey());
}
}
}
}
public boolean isEmpty() {
return this.items.isEmpty();
}
public int getItemIndex() {
return this.items.isEmpty() ? -1 : this.items.get(0);
}
private boolean canInsert(BookmarkGroup group) {
return group.viewMode == BookmarkViewMode.TODO_LIST && !group.collapsed;
}
public void mouseDragged(int mousex, int mousey) {
final BookmarkViewMode sortViewMode = this.grid.getViewMode(this.bookmarkItem.groupId);
BookmarksGridSlot mouseOverSlot = this.grid.getSlotMouseOver(mousex, mousey);
if (this.crossGroup) {
final Rectangle4i topLeftSlot = this.grid.getSlotRect(0);
mouseOverSlot = this.grid.getSlotMouseOver(topLeftSlot.x, mousey);
if (mouseOverSlot != null) {
float ySlot = (float) (mousey - topLeftSlot.y) / ItemsGrid.SLOT_SIZE;
int overRowIndex = (int) ySlot;
int beforeGroupId = this.grid.getRowGroupId(overRowIndex - 1);
int afterGroupId = this.grid.getRowGroupId(overRowIndex + 1);
int overGroupId = mouseOverSlot.getGroupId();
ySlot -= overRowIndex;
if (overGroupId == this.bookmarkItem.groupId && !this.items.contains(mouseOverSlot.itemIndex)) {
this.grid.moveItem(this, mouseOverSlot.itemIndex);
} else if (ySlot <= 0.25) {
final BookmarkGroup group = this.grid.getGroup(beforeGroupId);
if (beforeGroupId != overGroupId && canInsert(group)
&& !existsRecipe(this.bookmarkItem.recipeId, beforeGroupId)) {
this.grid.moveItem(this, overRowIndex, beforeGroupId, false);
}
} else if (ySlot > 0.25 && ySlot <= 0.5) {
if (beforeGroupId == overGroupId) {
return;
}
if (overGroupId != BookmarkGrid.DEFAULT_GROUP_ID
&& beforeGroupId != BookmarkGrid.DEFAULT_GROUP_ID) {
beforeGroupId = BookmarkGrid.DEFAULT_GROUP_ID;
}
if (overGroupId == BookmarkGrid.DEFAULT_GROUP_ID && beforeGroupId != BookmarkGrid.DEFAULT_GROUP_ID
&& afterGroupId != BookmarkGrid.DEFAULT_GROUP_ID) {
return;
}
if (canInsert(this.grid.getGroup(beforeGroupId))
&& !existsRecipe(this.bookmarkItem.recipeId, beforeGroupId)) {
this.grid.moveItem(this, overRowIndex, beforeGroupId, false);
}
} else if (ySlot > 0.5 && ySlot < 0.75) {
if (afterGroupId == overGroupId) {
return;
}
if (overGroupId != BookmarkGrid.DEFAULT_GROUP_ID && afterGroupId != BookmarkGrid.DEFAULT_GROUP_ID) {
afterGroupId = BookmarkGrid.DEFAULT_GROUP_ID;
}
if (overGroupId == BookmarkGrid.DEFAULT_GROUP_ID && beforeGroupId != BookmarkGrid.DEFAULT_GROUP_ID
&& afterGroupId != BookmarkGrid.DEFAULT_GROUP_ID) {
return;
}
if (canInsert(this.grid.getGroup(afterGroupId))
&& !existsRecipe(this.bookmarkItem.recipeId, afterGroupId)) {
this.grid.moveItem(this, overRowIndex, afterGroupId, true);
}
} else if (ySlot >= 0.75) {
final BookmarkGroup group = this.grid.getGroup(afterGroupId);
if (afterGroupId != overGroupId && canInsert(group)
&& !existsRecipe(this.bookmarkItem.recipeId, afterGroupId)) {
this.grid.moveItem(this, overRowIndex, afterGroupId, true);
}
}
} else {
final int overRowIndex = this.grid.getHoveredRowIndex(false);
final int overGroupId = this.grid.getRowGroupId(overRowIndex);
if (overRowIndex != -1 && overGroupId == this.bookmarkItem.groupId) {
final int absoluteSlotIndex = ((this.grid.getPage() - 1) * this.grid.getRows() + overRowIndex)
* this.grid.getColumns();
if (absoluteSlotIndex < this.grid.gridGenerator.itemToSlot.getOrDefault(getItemIndex(), -1)) {
this.grid.moveItem(this, overRowIndex, overGroupId, true);
} else {
this.grid.moveItem(this, overRowIndex, overGroupId, false);
}
}
}
} else if (mouseOverSlot != null && !this.items.contains(mouseOverSlot.itemIndex)
&& mouseOverSlot.getGroupId() == this.bookmarkItem.groupId
&& (sortViewMode == BookmarkViewMode.DEFAULT || sortViewMode == BookmarkViewMode.TODO_LIST
&& mouseOverSlot.getBookmarkItem().equalsRecipe(this.bookmarkItem))) {
this.grid.moveItem(this, mouseOverSlot.itemIndex);
}
}
private boolean existsRecipe(RecipeId recipeId, int groupId) {
if (recipeId == null) return false;
for (int itemIndex = 0; itemIndex < this.grid.bookmarkItems.size(); itemIndex++) {
if (!this.items.contains(itemIndex)
&& this.grid.bookmarkItems.get(itemIndex).equalsRecipe(recipeId, groupId)) {
return true;
}
}
return false;
}
public List<BookmarkItem> getBookmarkItems() {
final BookmarkGroup group = this.grid.getGroup(this.bookmarkItem.groupId);
final List<BookmarkItem> items = new ArrayList<>();
final List<RecipeId> recipeRelations = new ArrayList<>();
if (this.isCollapsedRecipe && group.crafting != null) {
recipeRelations.addAll(
group.crafting.recipeRelations.getOrDefault(this.bookmarkItem.recipeId, Collections.emptySet()));
}
for (BookmarkItem item : this.grid.bookmarkItems) {
if (containsItem(item)
|| item.groupId == this.bookmarkItem.groupId && recipeRelations.contains(item.recipeId)) {
items.add(item);
}
}
return items;
}
public boolean containsItem(BookmarkItem slotItem) {
return this.moveRecipe ? this.bookmarkItem.equalsRecipe(slotItem) : this.bookmarkItem.equals(slotItem);
}
}
@@ -0,0 +1,49 @@
package codechicken.nei.commands;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommand;
import net.minecraft.command.ICommandSender;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTException;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.ChatComponentTranslation;
import codechicken.nei.ItemPanels;
public class CommandBookmarkAdd extends CommandBase implements ICommand {
@Override
public String getCommandName() {
return "nei_bookmark";
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "/nei_bookmark <nbt>";
}
@Override
public int getRequiredPermissionLevel() {
return 0;
}
@Override
public void processCommand(ICommandSender sender, String[] args) {
if (args.length < 1 || args[0].length() < 3) {
sender.addChatMessage(new ChatComponentText("§c/nei_bookmark <nbt>"));
return;
}
try {
ItemPanels.bookmarkPanel.addItem(
ItemStack.loadItemStackFromNBT((NBTTagCompound) JsonToNBT.func_150315_a(String.join(" ", args))));
sender.addChatMessage(new ChatComponentTranslation("nei.chat.bookmark_added.text"));
} catch (NBTException e) {
sender.addChatMessage(new ChatComponentText(e.toString()));
}
}
}
@@ -1,9 +1,7 @@
package codechicken.nei.config;
import static codechicken.lib.gui.GuiDraw.getMousePosition;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderHelper;
@@ -14,6 +12,7 @@ import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.core.gui.GuiScreenWidget;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.render.CCRenderState;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemPanels;
@@ -114,8 +113,8 @@ public class GuiPanelSettings extends GuiScreenWidget {
}
protected int[] getPaddings() {
final int minWidth = 5 * ItemsGrid.SLOT_SIZE;
final int minHeight = 9 * ItemsGrid.SLOT_SIZE;
final int minWidth = ItemsGrid.SLOT_SIZE;
final int minHeight = ItemsGrid.SLOT_SIZE;
int paddingLeft = (int) Math.ceil(margin.w * opt.renderTag(name + ".left").getIntValue() / 100000.0);
int paddingTop = (int) Math.ceil(margin.h * opt.renderTag(name + ".top").getIntValue() / 100000.0);
@@ -123,7 +122,7 @@ public class GuiPanelSettings extends GuiScreenWidget {
int paddingBottom = (int) Math.ceil(margin.h * opt.renderTag(name + ".bottom").getIntValue() / 100000.0);
if (dragDir != null) {
final Point mouse = getMousePosition();
final Point mouse = GuiDraw.getMousePosition();
Point drag = new Point(mouse.x - dragDown.x, mouse.y - dragDown.y);
if (dragDir == "left") {
@@ -164,13 +163,12 @@ public class GuiPanelSettings extends GuiScreenWidget {
final int columns = w / ItemsGrid.SLOT_SIZE;
final int rows = (h - (PANEL_SIZE + 2) * 2) / ItemsGrid.SLOT_SIZE;
final int paddingLeft = (w % ItemsGrid.SLOT_SIZE) / 2;
final ArrayList<ItemStack> items = ItemPanels.itemPanel.getItems();
final List<ItemStack> items = ItemPanels.itemPanel.getItems();
if (items.isEmpty()) return;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
GuiContainerManager.drawItem(
drawItem(
x + paddingLeft + ItemsGrid.SLOT_SIZE * c + 1,
y + PANEL_SIZE + 2 + ItemsGrid.SLOT_SIZE * r + 1,
items.get((r * columns + c) % items.size()));
@@ -178,6 +176,21 @@ public class GuiPanelSettings extends GuiScreenWidget {
}
}
protected void drawItem(int x, int y, ItemStack stack) {
final float scale = ItemsGrid.SLOT_SIZE / 18f;
final float inverseScaleFactor = 1.0f / scale;
final float shiftX = x * inverseScaleFactor;
final float shiftY = y * inverseScaleFactor;
GL11.glScaled(scale, scale, 1);
GL11.glTranslated(shiftX, shiftY, 0);
GuiContainerManager.drawItem(0, 0, stack, true, "");
GL11.glTranslated(-1 * shiftX, -1 * shiftY, 0);
GL11.glScaled(inverseScaleFactor, inverseScaleFactor, 1);
}
public boolean contains(int pointX, int pointY) {
return (new Rectangle4i(x, y, w, h)).contains(pointX, pointY);
}
@@ -185,7 +198,7 @@ public class GuiPanelSettings extends GuiScreenWidget {
protected void mouseClicked(int x, int y, int button) {
if (contains(x, y)) {
dragDown = getMousePosition();
dragDown = GuiDraw.getMousePosition();
if (leftButton.contains(x, y)) {
dragDir = "left";
@@ -64,7 +64,7 @@ public class IMCHandler {
final boolean requiresMod = tag.getBoolean("modRequired");
final String excludedModId = tag.hasKey("excludedModId") ? tag.getString("excludedModId") : null;
if (handler.equals("") || modName.equals("") || modId.equals("")) {
if (handler.isEmpty() || modName.isEmpty() || modId.isEmpty()) {
NEIClientConfig.logger.warn("Missing relevant information to registerHandlerInfo!");
return;
}
@@ -74,7 +74,7 @@ public class IMCHandler {
HandlerInfo info = new HandlerInfo(handler, modName, modId, requiresMod, excludedModId);
final String imageResource = tag.hasKey("imageResource") ? tag.getString("imageResource") : null;
if (imageResource != null && !imageResource.equals("")) {
if (imageResource != null && !imageResource.isEmpty()) {
info.setImage(
imageResource,
tag.getInteger("imageX"),
@@ -84,7 +84,7 @@ public class IMCHandler {
}
if (!info.hasImageOrItem()) {
final String itemName = tag.getString("itemName");
if (itemName != null && !itemName.equals("")) {
if (itemName != null && !itemName.isEmpty()) {
info.setItem(itemName, tag.hasKey("nbtInfo") ? tag.getString("nbtInfo") : null);
}
}
@@ -103,6 +103,10 @@ public class IMCHandler {
NEIClientConfig.logger.info("Error setting handler dimensions for " + handler);
}
// true if not set to false
info.setShowFavoritesButton(!tag.hasKey("showFavoritesButton") || tag.getBoolean("showFavoritesButton"));
info.setShowOverlayButton(!tag.hasKey("showOverlayButton") || tag.getBoolean("showOverlayButton"));
GuiRecipeTab.handlerAdderFromIMC.remove(handler);
GuiRecipeTab.handlerAdderFromIMC.put(handler, info);
}
@@ -75,26 +75,25 @@ public abstract class OptionButton extends Option {
}
public String getTooltip() {
String tip = null;
if (tooltip != null) {
String s = translateN(tooltip);
if (!s.equals(namespaced(tooltip))) {
tip = s;
return s;
}
}
if (tip == null && getPrefix() != null) {
if (getPrefix() != null) {
final int width = getStringWidth(getPrefix());
final Rectangle b = buttonSize();
if (width >= b.x) {
tip = translateN(name);
return translateN(name);
}
}
return tip;
return null;
}
public void drawPrefix() {
@@ -29,6 +29,18 @@ public class OptionCycled extends OptionButton {
return prefixed ? translateN(name) : null;
}
@Override
public String getTooltip() {
String tooltip = name + "." + value() + ".tip";
String s = translateN(tooltip);
if (!s.equals(namespaced(tooltip))) {
return s;
}
return super.getTooltip();
}
@Override
public boolean onClick(int button) {
return cycle();
@@ -1,11 +1,15 @@
package codechicken.nei.config;
import codechicken.lib.gui.GuiDraw;
public class OptionIntegerField extends OptionTextField {
public final int min;
public final int max;
public static final long UNSIGNED_INT_MAX = 0xFFFFFFFFL;
public OptionIntegerField(String name, int min, int max) {
public final long min;
public final long max;
public OptionIntegerField(String name, long min, long max) {
super(name);
this.min = min;
this.max = max;
@@ -15,13 +19,23 @@ public class OptionIntegerField extends OptionTextField {
this(name, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
@Override
protected int getMaxInputWidth() {
if (renderTag().getValue().startsWith("0x")) {
return GuiDraw.getStringWidth("0x" + Long.toHexString(this.max).toUpperCase()) + 32;
}
return GuiDraw.getStringWidth(String.valueOf(this.max)) + 32;
}
@Override
public boolean isValidInput(String s) {
if (s.length() == 0) return true;
if (s.isEmpty()) return true;
try {
if (s.startsWith("0x")) {
Long.parseLong(s.substring(2), 16);
Long.parseUnsignedLong(s.substring(2), 16);
} else {
Integer.parseInt(s);
}
@@ -33,15 +47,15 @@ public class OptionIntegerField extends OptionTextField {
@Override
public boolean isValidValue(String s) {
if (s.length() == 0 || !isValidInput(s)) return false;
int i = 0;
if (s.isEmpty() || !isValidInput(s)) return false;
long i = 0;
if (s.startsWith("0x")) {
i = (int) Long.parseLong(s.substring(2), 16);
i = Long.parseUnsignedLong(s.substring(2), 16);
} else {
i = Integer.parseInt(s);
}
return i >= min && i <= max;
return i >= this.min && i <= this.max;
}
}
@@ -8,6 +8,7 @@ import java.awt.Rectangle;
import org.lwjgl.input.Keyboard;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.util.NEIKeyboardUtils;
public class OptionKeyBind extends OptionButton {
@@ -123,10 +124,10 @@ public class OptionKeyBind extends OptionButton {
public String getButtonText() {
if (editing) {
return NEIClientUtils.getKeyHashName(NEIClientUtils.getMetaHash());
return NEIKeyboardUtils.getHashName(NEIClientUtils.getMetaHash());
}
return NEIClientUtils.getKeyName(Math.max(getValue(), 0));
return NEIKeyboardUtils.getKeyName(Math.max(getValue(), 0));
}
@Override
@@ -1,17 +1,14 @@
package codechicken.nei.config;
import static codechicken.lib.gui.GuiDraw.drawString;
import static codechicken.lib.gui.GuiDraw.getStringWidth;
import java.util.List;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.TextField;
import codechicken.nei.config.GuiOptionList.OptionScrollSlot;
public class OptionTextField extends Option {
protected final TextField textField = new TextField("test") {
protected final TextField textField = new TextField("option-text-field") {
{
this.h = 20;
@@ -22,6 +19,7 @@ public class OptionTextField extends Option {
// don't override global if text hasn't changed
if (focused() && isValidValue(text()) && (!defaulting() || !text().equals(getTag().getValue()))) {
getTag().setValue(text());
OptionTextField.this.onTextChange(text());
}
}
@@ -30,16 +28,19 @@ public class OptionTextField extends Option {
if (!focus && !isValidValue(text())) setText(renderTag().getValue());
super.setFocus(focus);
}
@Override
public void draw(int mousex, int mousey) {
this.field.setEnabled(isEnabled());
super.draw(mousex, mousey);
}
};
public OptionTextField(String name) {
super(name);
}
@Override
public void onAdded(OptionScrollSlot slot) {
super.onAdded(slot);
}
public void onTextChange(String text) {}
@Override
public void update() {
@@ -51,23 +52,34 @@ public class OptionTextField extends Option {
return translateN(name);
}
protected int getMaxInputWidth() {
return slot.slotWidth();
}
public boolean isEnabled() {
return true;
}
@Override
public void draw(int mousex, int mousey, float frame) {
drawString(getPrefix(), 10, 6, -1);
GuiDraw.drawString(getPrefix(), 10, 6, -1);
textField.w = slot.slotWidth() - getStringWidth(getPrefix()) - 16;
textField.w = Math
.max(60, Math.min(getMaxInputWidth(), slot.slotWidth() - GuiDraw.getStringWidth(getPrefix())) - 16);
textField.x = slot.slotWidth() - textField.w;
textField.draw(mousex, mousey);
}
@Override
public void keyTyped(char c, int keycode) {
textField.handleKeyPress(keycode, c);
if (isEnabled()) {
textField.handleKeyPress(keycode, c);
}
}
@Override
public void mouseClicked(int mousex, int mousey, int button) {
if (textField.contains(mousex, mousey)) textField.handleClick(mousex, mousey, button);
if (isEnabled() && textField.contains(mousex, mousey)) textField.handleClick(mousex, mousey, button);
}
@Override
@@ -77,7 +89,7 @@ public class OptionTextField extends Option {
@Override
public List<String> handleTooltip(int mousex, int mousey, List<String> currenttip) {
if (new Rectangle4i(10, 0, textField.x - 10, 20).contains(mousex, mousey)) {
if (isEnabled() && new Rectangle4i(10, 0, textField.x - 10, 20).contains(mousex, mousey)) {
String tip = translateN(name + ".tip");
if (!tip.equals(namespaced(name + ".tip"))) currenttip.add(tip);
}
@@ -17,6 +17,7 @@ public class OptionToggleButton extends OptionButton {
return renderTag().getBooleanValue();
}
@Override
public String getButtonText() {
return translateN(name + (state() ? ".true" : ".false"));
}
@@ -13,8 +13,8 @@ import org.lwjgl.opengl.GL12;
import codechicken.core.gui.GuiWidget;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.ItemsGrid;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.Label;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList.Preset;
@@ -49,7 +49,7 @@ public class LeftPanel extends GuiWidget {
@Override
protected ItemFilter getFilter() {
Set<String> identifiers = preset.items;
final Set<String> identifiers = preset.items;
return item -> identifiers.contains(Preset.getIdentifier(item));
}
@@ -57,6 +57,20 @@ public class LeftPanel extends GuiWidget {
protected boolean isSelected(ItemStack stack) {
return mouseSelection != null && mouseSelection.items.contains(stack);
}
@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;
}
};
protected Label nameLabel = new Label(NEIClientUtils.translate("presets.name"), false);
@@ -169,10 +183,10 @@ public class LeftPanel extends GuiWidget {
}
if (mouseSelection == null && button == 0) {
ItemPanelSlot slot = grid.getSlotMouseOver(x, y);
final ItemsGridSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null) {
mouseSelection = new MouseSelection(slot.slotIndex, grid.getItemRect(slot.slotIndex));
mouseSelection = new MouseSelection(slot.itemIndex, grid.getItemRect(slot.itemIndex));
}
}
@@ -185,10 +199,10 @@ public class LeftPanel extends GuiWidget {
nameField.mouseUp(x, y, button);
if (mouseSelection != null && button == 0) {
ItemPanelSlot hoverSlot = grid.getSlotMouseOver(x, y);
final ItemsGridSlot hoverSlot = grid.getSlotMouseOver(x, y);
if (hoverSlot != null && hoverSlot.slotIndex == mouseSelection.startIndex) {
preset.items.remove(Preset.getIdentifier(hoverSlot.item));
if (hoverSlot != null && hoverSlot.itemIndex == mouseSelection.startIndex) {
preset.items.remove(Preset.getIdentifier(hoverSlot.getItemStack()));
} else if (!mouseSelection.items.isEmpty()) {
for (ItemStack stack : mouseSelection.items) {
@@ -206,13 +220,13 @@ public class LeftPanel extends GuiWidget {
nameField.mouseDragged(x, y, button, time);
if (mouseSelection != null && button == 0) {
final ItemPanelSlot slot = grid.getSlotMouseOver(x, y);
final ItemsGridSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null && slot.slotIndex != mouseSelection.endIndex) {
mouseSelection.endIndex = slot.slotIndex;
if (slot != null && slot.itemIndex != mouseSelection.endIndex) {
mouseSelection.endIndex = slot.itemIndex;
mouseSelection.items.clear();
final Rectangle4i rec = grid.getItemRect(slot.slotIndex);
final Rectangle4i rec = grid.getItemRect(slot.itemIndex);
final Rectangle4i sel = new Rectangle4i(
Math.min(rec.x, mouseSelection.startX),
Math.min(rec.y, mouseSelection.startY),
@@ -221,10 +235,10 @@ public class LeftPanel extends GuiWidget {
for (int ix = sel.x; ix <= sel.x + sel.w; ix += ItemsGrid.SLOT_SIZE) {
for (int iy = sel.y; iy <= sel.y + sel.h; iy += ItemsGrid.SLOT_SIZE) {
ItemPanelSlot over = grid.getSlotMouseOver(ix, iy);
final ItemsGridSlot over = grid.getSlotMouseOver(ix, iy);
if (over != null) {
mouseSelection.items.add(over.item);
mouseSelection.items.add(over.getItemStack());
}
}
}
@@ -295,14 +309,14 @@ public class LeftPanel extends GuiWidget {
}
public List<String> handleTooltip(int mousex, int mousey, List<String> tooltip) {
ItemPanelSlot over = grid.getSlotMouseOver(mousex, mousey);
final ItemsGridSlot over = grid.getSlotMouseOver(mousex, mousey);
if (over != null) {
tooltip = GuiContainerManager.itemDisplayNameMultiline(over.item, null, true);
tooltip = GuiContainerManager.itemDisplayNameMultiline(over.getItemStack(), null, true);
synchronized (GuiContainerManager.tooltipHandlers) {
for (IContainerTooltipHandler handler : GuiContainerManager.tooltipHandlers) {
tooltip = handler.handleItemTooltip(null, over.item, mousex, mousey, tooltip);
tooltip = handler.handleItemTooltip(null, over.getItemStack(), mousex, mousey, tooltip);
}
}
@@ -5,31 +5,45 @@ import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.Button;
import codechicken.nei.ItemList;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.ItemSorter;
import codechicken.nei.ItemsGrid;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.Label;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.RestartableTask;
import codechicken.nei.api.ItemFilter;
public abstract class PresetItemsGrid extends ItemsGrid {
public abstract class PresetItemsGrid extends ItemsGrid<PresetItemsGrid.PresetsGridSlot, ItemsGrid.MouseContext> {
protected static final int BUTTON_SIZE = 16;
public class PresetsGridSlot extends ItemsGridSlot {
public PresetsGridSlot(int slotIndex, int itemIndex, ItemStack itemStack) {
super(slotIndex, itemIndex, itemStack);
}
@Override
public void beforeDraw(Rectangle4i rect, MouseContext mouseContext) {
if (mouseContext != null && mouseContext.slotIndex == this.slotIndex || isSelected(getItemStack())) {
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, HIGHLIGHT_COLOR);
}
}
}
public Button pagePrev;
public Label pageLabel;
public Button pageNext;
protected ArrayList<ItemStack> newItems;
protected List<PresetsGridSlot> gridMask;
protected final RestartableTask updateFilter = new RestartableTask("NEI Presets Item Filtering") {
@@ -139,6 +153,28 @@ public abstract class PresetItemsGrid extends ItemsGrid {
this.newItems = new ArrayList<>(newItems);
}
@Override
protected void onGridChanged() {
this.gridMask = null;
super.onGridChanged();
}
@Override
public List<PresetsGridSlot> getMask() {
if (this.gridMask == null) {
this.gridMask = new ArrayList<>();
int itemIndex = page * perPage;
for (int slotIndex = 0; slotIndex < rows * columns && itemIndex < size(); slotIndex++) {
this.gridMask.add(new PresetsGridSlot(slotIndex, itemIndex, getItem(itemIndex)));
itemIndex++;
}
}
return this.gridMask;
}
@Override
public void refresh(GuiContainer gui) {
@@ -151,15 +187,6 @@ public abstract class PresetItemsGrid extends ItemsGrid {
super.refresh(gui);
}
@Override
protected void beforeDrawSlot(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {
if (isSelected(getItem(slotIdx))) {
GuiDraw.drawRect(rect.x, rect.y, rect.w, rect.h, 0xee555555);
} else {
super.beforeDrawSlot(focused, slotIdx, rect);
}
}
protected abstract boolean isSelected(ItemStack stack);
protected abstract ItemFilter getFilter();
@@ -19,8 +19,8 @@ import codechicken.nei.CollapsibleItems;
import codechicken.nei.ItemList.AllMultiItemFilter;
import codechicken.nei.ItemList.AnyMultiItemFilter;
import codechicken.nei.ItemList.NegatedItemFilter;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.ItemsGrid;
import codechicken.nei.ItemsGrid.ItemsGridSlot;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList;
@@ -133,12 +133,12 @@ public class RightPanel extends GuiWidget {
@Override
protected ItemFilter getFilter() {
AllMultiItemFilter filter = new AllMultiItemFilter(searchField.getFilter());
final AllMultiItemFilter filter = new AllMultiItemFilter(searchField.getFilter());
if (enabledPresets.isChecked()) {
AllMultiItemFilter andFilter = new AllMultiItemFilter();
AnyMultiItemFilter orFilter = new AnyMultiItemFilter();
Set<String> identifiers = PresetsList.presets.stream().flatMap(p -> p.items.stream())
final AllMultiItemFilter andFilter = new AllMultiItemFilter();
final AnyMultiItemFilter orFilter = new AnyMultiItemFilter();
final Set<String> identifiers = PresetsList.presets.stream().flatMap(p -> p.items.stream())
.collect(Collectors.toSet());
andFilter.filters.add(item -> !identifiers.contains(Preset.getIdentifier(item)));
@@ -164,6 +164,20 @@ public class RightPanel extends GuiWidget {
return preset.items.contains(Preset.getIdentifier(stack));
}
@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;
}
};
protected CheckboxButton enabledPresets;
@@ -218,10 +232,10 @@ public class RightPanel extends GuiWidget {
}
if (mouseSelection == null && (button == 0 || button == 1)) {
ItemPanelSlot slot = grid.getSlotMouseOver(x, y);
final ItemsGridSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null) {
mouseSelection = new MouseSelection(slot.slotIndex, grid.getItemRect(slot.slotIndex), button == 0);
mouseSelection = new MouseSelection(slot.itemIndex, grid.getItemRect(slot.itemIndex), button == 0);
}
}
@@ -234,10 +248,10 @@ public class RightPanel extends GuiWidget {
searchField.mouseUp(x, y, button);
if (mouseSelection != null && (button == 0 || button == 1)) {
ItemPanelSlot hoverSlot = grid.getSlotMouseOver(x, y);
final ItemsGridSlot hoverSlot = grid.getSlotMouseOver(x, y);
if (hoverSlot != null && hoverSlot.slotIndex == mouseSelection.startIndex) {
setHidden(hoverSlot.item, button == 0);
if (hoverSlot != null && hoverSlot.itemIndex == mouseSelection.startIndex) {
setHidden(hoverSlot.getItemStack(), button == 0);
} else if (!mouseSelection.items.isEmpty()) {
for (ItemStack stack : mouseSelection.items) {
@@ -304,13 +318,13 @@ public class RightPanel extends GuiWidget {
searchField.mouseDragged(x, y, button, time);
if (mouseSelection != null && (button == 0 || button == 1)) {
final ItemPanelSlot slot = grid.getSlotMouseOver(x, y);
final ItemsGridSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null && slot.slotIndex != mouseSelection.endIndex) {
mouseSelection.endIndex = slot.slotIndex;
if (slot != null && slot.itemIndex != mouseSelection.endIndex) {
mouseSelection.endIndex = slot.itemIndex;
mouseSelection.items.clear();
final Rectangle4i rec = grid.getItemRect(slot.slotIndex);
final Rectangle4i rec = grid.getItemRect(slot.itemIndex);
final Rectangle4i sel = new Rectangle4i(
Math.min(rec.x, mouseSelection.startX),
Math.min(rec.y, mouseSelection.startY),
@@ -319,10 +333,10 @@ public class RightPanel extends GuiWidget {
for (int ix = sel.x; ix <= sel.x + sel.w; ix += ItemsGrid.SLOT_SIZE) {
for (int iy = sel.y; iy <= sel.y + sel.h; iy += ItemsGrid.SLOT_SIZE) {
ItemPanelSlot over = grid.getSlotMouseOver(ix, iy);
final ItemsGridSlot over = grid.getSlotMouseOver(ix, iy);
if (over != null) {
mouseSelection.items.add(over.item);
mouseSelection.items.add(over.getItemStack());
}
}
}
@@ -363,14 +377,14 @@ public class RightPanel extends GuiWidget {
}
public List<String> handleTooltip(int mousex, int mousey, List<String> tooltip) {
ItemPanelSlot over = grid.getSlotMouseOver(mousex, mousey);
final ItemsGridSlot over = grid.getSlotMouseOver(mousex, mousey);
if (over != null) {
tooltip = GuiContainerManager.itemDisplayNameMultiline(over.item, null, true);
tooltip = GuiContainerManager.itemDisplayNameMultiline(over.getItemStack(), null, true);
synchronized (GuiContainerManager.tooltipHandlers) {
for (IContainerTooltipHandler handler : GuiContainerManager.tooltipHandlers) {
tooltip = handler.handleItemTooltip(null, over.item, mousex, mousey, tooltip);
tooltip = handler.handleItemTooltip(null, over.getItemStack(), mousex, mousey, tooltip);
}
}
@@ -10,13 +10,14 @@ import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
@@ -24,6 +25,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.RenderItem;
import net.minecraft.client.resources.IResourceManager;
@@ -38,15 +40,17 @@ import net.minecraftforge.fluids.FluidStack;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ItemList;
import codechicken.nei.ItemStackSet;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.SearchField;
import codechicken.nei.NEIModContainer;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.search.TooltipFilter;
import codechicken.nei.util.ReadableNumberConverter;
import codechicken.nei.util.RenderTooltipEventHelper;
public class GuiContainerManager {
@@ -55,8 +59,7 @@ public class GuiContainerManager {
@Override
public void onResourceManagerReload(IResourceManager p_110549_1_) {
renderingErrorItems.clear();
TooltipFilter.populateSearchMap();
SearchField.searchParser.clearCache();
ItemList.loadItems.restart();
}
}
@@ -177,7 +180,11 @@ public class GuiContainerManager {
namelist.set(0, stack.getRarity().rarityColor.toString() + namelist.get(0));
for (int i = 1; i < namelist.size(); i++) {
namelist.set(i, EnumChatFormatting.GRAY + namelist.get(i) + EnumChatFormatting.RESET);
if (namelist.get(i) == null) {
namelist.set(i, "");
} else if (!namelist.get(i).startsWith(GuiDraw.TOOLTIP_HANDLER)) {
namelist.set(i, EnumChatFormatting.GRAY + namelist.get(i) + EnumChatFormatting.RESET);
}
}
return namelist;
@@ -209,15 +216,15 @@ public class GuiContainerManager {
@Nullable
public static String itemCountDetails(ItemStack stack) {
FluidStack fluid = StackInfo.getFluid(stack);
final FluidStack fluid = StackInfo.getFluid(stack);
if (fluid != null) {
return fluidAmountDetails(fluid.amount * Math.max(1, stack.stackSize));
} else {
return countDetails(
stack.stackSize,
stack.getMaxStackSize(),
"Count: %s = %s * %s + %s",
"Count: %s = %s * %s");
translate("inventory.tooltip.count.item", "%s = %s * %s + %s"),
translate("inventory.tooltip.count.item", "%s = %s * %s"));
}
}
@@ -229,7 +236,11 @@ public class GuiContainerManager {
@Nullable
public static String fluidAmountDetails(int amount) {
return countDetails(amount, 144, "Amount: %s L = %s * %s L + %s L", "Amount: %s L = %s * %s L");
return countDetails(
amount,
144,
translate("inventory.tooltip.count.fluid", "%s L = %s * %s L + %s L"),
translate("inventory.tooltip.count.fluid", "%s L = %s * %s L"));
}
/**
@@ -290,7 +301,7 @@ public class GuiContainerManager {
}
private static int modelviewDepth = -1;
private static final HashSet<String> stackTraces = new HashSet<>();
private static boolean contextEnabled = false;
private static final ItemStackSet renderingErrorItems = new ItemStackSet();
public static void drawItem(int offsetX, int offsetY, ItemStack itemstack, FontRenderer fontRenderer,
@@ -302,14 +313,19 @@ public class GuiContainerManager {
if (stackSize == null) {
if (itemstack.stackSize > 1) {
stackSize = ReadableNumberConverter.INSTANCE.toWideReadableForm(itemstack.stackSize);
if (stackSize.length() == 3) {
scale = 0.8f;
} else if (stackSize.length() == 4) {
scale = 0.6f;
} else if (stackSize.length() > 4) {
scale = 0.5f;
if (NEIClientConfig.getBooleanSetting("inventory.dynamicFontSize")) {
stackSize = ReadableNumberConverter.INSTANCE.toWideReadableForm(itemstack.stackSize);
if (stackSize.length() == 3) {
scale = 0.8f;
} else if (stackSize.length() == 4) {
scale = 0.6f;
} else if (stackSize.length() > 4) {
scale = 0.5f;
}
} else {
stackSize = String.valueOf(itemstack.stackSize);
}
} else {
@@ -346,47 +362,55 @@ public class GuiContainerManager {
private static void safeItemRenderContext(ItemStack stack, int x, int y, FontRenderer fontRenderer,
Runnable callback) {
float zLevel = drawItems.zLevel += 100F;
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
enableMatrixStackLogging();
enable3DRender();
if (!renderingErrorItems.contains(stack)) {
try {
callback.run();
if (!checkMatrixStack()) throw new IllegalStateException("Modelview matrix stack too deep");
if (Tessellator.instance.isDrawing) throw new IllegalStateException("Still drawing");
} catch (Exception e) {
NEIClientUtils.reportErrorBuffered(e, stackTraces, stack);
restoreMatrixStack();
if (Tessellator.instance.isDrawing) Tessellator.instance.draw();
drawItems.zLevel = zLevel;
try {
if (renderingErrorItems.contains(stack)) {
drawItems.renderItemIntoGUI(fontRenderer, renderEngine, new ItemStack(Blocks.fire), x, y);
renderingErrorItems.add(stack);
} else {
callback.run();
}
} else {
if (!checkMatrixStack()) throw new IllegalStateException("Modelview matrix stack too deep");
if (Tessellator.instance.isDrawing) throw new IllegalStateException("Still drawing");
} catch (Exception e) {
System.err.println("Error while rendering: " + stack + " (" + e.getMessage() + ")");
e.printStackTrace();
restoreMatrixStack();
if (Tessellator.instance.isDrawing) Tessellator.instance.draw();
drawItems.zLevel = zLevel;
drawItems.renderItemIntoGUI(fontRenderer, renderEngine, new ItemStack(Blocks.fire), x, y);
renderingErrorItems.add(stack);
}
GL11.glPopAttrib();
enable2DRender();
disableMatrixStackLogging();
drawItems.zLevel = zLevel - 100;
}
public static void registerReloadResourceListener() {
if (Minecraft.getMinecraft().getResourceManager() instanceof SimpleReloadableResourceManager) {
SimpleReloadableResourceManager manager = (SimpleReloadableResourceManager) Minecraft.getMinecraft()
.getResourceManager();
if (Minecraft.getMinecraft().getResourceManager() instanceof SimpleReloadableResourceManager manager) {
manager.registerReloadListener(new ResourcePackReloaded());
}
}
public static void enableMatrixStackLogging() {
modelviewDepth = GL11.glGetInteger(GL11.GL_MODELVIEW_STACK_DEPTH);
if (!contextEnabled) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
modelviewDepth = GL11.glGetInteger(GL11.GL_MODELVIEW_STACK_DEPTH);
contextEnabled = true;
}
}
public static void disableMatrixStackLogging() {
modelviewDepth = -1;
if (contextEnabled) {
contextEnabled = false;
modelviewDepth = -1;
GL11.glPopAttrib();
}
}
public static boolean checkMatrixStack() {
@@ -417,9 +441,9 @@ public class GuiContainerManager {
public GuiContainerManager(GuiContainer screen) {
window = screen;
if (screen instanceof IContainerTooltipHandler) {
if (screen instanceof IContainerTooltipHandler tooltipHandler) {
instanceTooltipHandlers = Collections.synchronizedList(new LinkedList<>());
instanceTooltipHandlers.add((IContainerTooltipHandler) screen);
instanceTooltipHandlers.add(tooltipHandler);
instanceTooltipHandlers.addAll(tooltipHandlers);
} else instanceTooltipHandlers = tooltipHandlers;
}
@@ -544,7 +568,6 @@ public class GuiContainerManager {
public void renderToolTips(int mousex, int mousey) {
List<String> tooltip = new LinkedList<>();
Map<String, String> hotkeys = new HashMap<>();
FontRenderer font = GuiDraw.fontRenderer;
synchronized (instanceTooltipHandlers) {
@@ -552,8 +575,9 @@ public class GuiContainerManager {
tooltip = handler.handleTooltip(window, mousex, mousey, tooltip);
}
if (tooltip.isEmpty() && shouldShowTooltip(window)) { // mouseover tip, not holding an item
ItemStack stack = getStackMouseOver(window);
ItemStack stack = getStackMouseOver(window);
boolean showTooltip = shouldShowTooltip(window);
if (tooltip.isEmpty() && showTooltip) { // mouseover tip, not holding an item
font = getFontRenderer(stack);
if (stack != null) {
tooltip = itemDisplayNameMultiline(stack, window, true);
@@ -568,64 +592,174 @@ public class GuiContainerManager {
if (!tooltip.isEmpty()) tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE); // add space after 'title'
synchronized (instanceTooltipHandlers) {
for (IContainerTooltipHandler handler : instanceTooltipHandlers) {
hotkeys = handler.handleHotkeys(window, mousex, mousey, hotkeys);
}
}
if (showTooltip) {
List<String> hotkeystips = collectHotkeyTips(mousex, mousey);
if (!hotkeys.isEmpty()) {
List<String> hotkeystips = new ArrayList<>();
if (!hotkeystips.isEmpty()) {
if (!NEIClientUtils.altKey()) {
hotkeystips.add(
EnumChatFormatting.GRAY
+ translate("showHotkeys", EnumChatFormatting.GOLD + "ALT" + EnumChatFormatting.GRAY));
} else {
for (Map.Entry<String, String> entry : hotkeys.entrySet()) {
hotkeystips.add(getHotkeyTip(entry.getKey(), entry.getValue()));
if (tooltip.isEmpty()) {
tooltip.addAll(hotkeystips);
} else {
tooltip.addAll(1, hotkeystips);
}
hotkeystips.sort((a, b) -> Integer.compare(a.indexOf(" - "), b.indexOf(" - ")));
hotkeystips.set(
hotkeystips.size() - 1,
hotkeystips.get(hotkeystips.size() - 1) + GuiDraw.TOOLTIP_LINESPACE);
}
if (tooltip.isEmpty()) {
tooltip.addAll(hotkeystips);
} else {
tooltip.addAll(1, hotkeystips);
}
}
drawPagedTooltip(font, mousex + 12, mousey - 12, tooltip);
if (NEIModContainer.isGTNHLibLoaded() && !tooltip.isEmpty()) {
if (RenderTooltipEventHelper.post(stack, this.window, mousex, mousey, font)) {
return;
}
Consumer<List<String>> alternativeRenderer = RenderTooltipEventHelper.getAlternativeRenderer();
if (alternativeRenderer == null) {
drawPagedTooltip(
RenderTooltipEventHelper.getFont(),
RenderTooltipEventHelper.getX() + 12,
RenderTooltipEventHelper.getY() - 12,
tooltip);
} else {
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
RenderHelper.disableStandardItemLighting();
GL11.glDisable(GL11.GL_DEPTH_TEST);
GuiDraw.gui.incZLevel(300.0f);
alternativeRenderer.accept(tooltip);
GuiDraw.gui.incZLevel(-300.0f);
GL11.glEnable(GL11.GL_DEPTH_TEST);
RenderHelper.enableStandardItemLighting();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
}
RenderTooltipEventHelper.flush();
} else {
drawPagedTooltip(font, mousex + 12, mousey - 12, tooltip);
}
for (IContainerDrawHandler drawHandler : drawHandlers) {
drawHandler.postRenderTooltips(window, mousex, mousey, tooltip);
}
}
private String getHotkeyTip(String key, String message) {
return EnumChatFormatting.GOLD + key + EnumChatFormatting.GRAY + " - " + message + EnumChatFormatting.RESET;
private List<String> collectHotkeyTips(int mousex, int mousey) {
if (NEIClientUtils.altKey()) {
Map<String, String> hotkeys = new HashMap<>();
synchronized (instanceTooltipHandlers) {
for (IContainerTooltipHandler handler : instanceTooltipHandlers) {
hotkeys = handler.handleHotkeys(window, mousex, mousey, hotkeys);
}
}
if (!hotkeys.isEmpty()) {
List<String> hotkeystips = new ArrayList<>();
Map<String, List<String>> messages = new HashMap<>();
hotkeys.remove(null);
hotkeys.remove("");
for (Map.Entry<String, String> entry : hotkeys.entrySet()) {
messages.computeIfAbsent(entry.getValue(), m -> new ArrayList<>()).add(entry.getKey());
}
for (List<String> keys : messages.values()) {
Collections.sort(keys, (a, b) -> {
if (a.length() != b.length()) {
return Integer.compare(a.length(), b.length());
}
return a.compareTo(b);
});
}
messages.entrySet().stream().sorted((a, b) -> {
String sa = String.join("/", a.getValue());
String sb = String.join("/", b.getValue());
if (sa.length() != sb.length()) {
return Integer.compare(sa.length(), sb.length());
}
return sa.compareTo(sb);
}).map(entry -> getHotkeyTip(entry.getValue(), entry.getKey()))
.collect(Collectors.toCollection(() -> hotkeystips));
hotkeystips.set(
hotkeystips.size() - 1,
hotkeystips.get(hotkeystips.size() - 1) + GuiDraw.TOOLTIP_LINESPACE);
return hotkeystips;
}
} else if (NEIClientConfig.getBooleanSetting("inventory.hotkeysHelpText")) {
boolean existsHotkeys = false;
synchronized (instanceTooltipHandlers) {
for (IContainerTooltipHandler handler : instanceTooltipHandlers) {
if (!handler.handleHotkeys(window, mousex, mousey, new HashMap<>()).isEmpty()) {
existsHotkeys = true;
break;
}
}
}
if (existsHotkeys) {
return Collections.singletonList(
EnumChatFormatting.GRAY + translate(
"showHotkeys",
EnumChatFormatting.GOLD + translate("key.alt") + EnumChatFormatting.GRAY));
}
}
return Collections.emptyList();
}
private String getHotkeyTip(List<String> keys, String message) {
return EnumChatFormatting.GOLD
+ String.join(EnumChatFormatting.DARK_GRAY + " / " + EnumChatFormatting.GOLD, keys)
+ EnumChatFormatting.DARK_GRAY
+ " - "
+ EnumChatFormatting.GRAY
+ message
+ EnumChatFormatting.RESET;
}
private static int tooltipPage;
private static int maxTooltipPage;
public static void drawPagedTooltip(FontRenderer font, int x, int y, List<String> list) {
if (list.isEmpty()) return;
List<List<String>> tooltips = splitTooltipByPage(list);
tooltipPage = tooltipPage < tooltips.size() ? tooltipPage : 0;
if (tooltips.size() > 1) {
tooltips.get(tooltipPage).add(
EnumChatFormatting.ITALIC + NEIClientUtils.translate(
"inventory.tooltip.page",
tooltipPage + 1,
tooltips.size(),
NEIClientConfig.getKeyName("gui.next_tooltip")));
maxTooltipPage = tooltips.size();
tooltipPage = tooltipPage < maxTooltipPage ? tooltipPage : 0;
final List<String> currentTooltip = tooltips.get(tooltipPage);
if (maxTooltipPage > 1) {
final String lastLine = currentTooltip.remove(currentTooltip.size() - 1);
final String pageTooltip = EnumChatFormatting.ITALIC + NEIClientUtils.translate(
"inventory.tooltip.page",
tooltipPage + 1,
maxTooltipPage,
NEIClientConfig.getKeyName("gui.next_tooltip"));
if (lastLine.startsWith(GuiDraw.TOOLTIP_HANDLER)) {
currentTooltip.add(lastLine);
} else {
currentTooltip.add(lastLine + GuiDraw.TOOLTIP_LINESPACE);
}
currentTooltip.add(pageTooltip);
}
if (NEIModContainer.isGTNHLibLoaded()) {
drawMultilineTip(
font,
x,
y,
currentTooltip,
RenderTooltipEventHelper.getBackgroundStart(),
RenderTooltipEventHelper.getBackgroundEnd(),
RenderTooltipEventHelper.getBorderStart(),
RenderTooltipEventHelper.getBorderEnd());
} else {
drawMultilineTip(font, x, y, currentTooltip);
}
drawMultilineTip(font, x, y, tooltips.get(tooltipPage));
}
public static List<List<String>> splitTooltipByPage(List<String> list) {
@@ -637,8 +771,9 @@ public class GuiContainerManager {
GuiDraw.ITooltipLineHandler line = GuiDraw.getTipLine(text);
int lineHeight = line != null ? line.getSize().height
: text.endsWith(GuiDraw.TOOLTIP_LINESPACE) && i + 1 < list.size() ? 12 : 10;
if (height + lineHeight <= GuiDraw.displaySize().height - 8 * 2 - 10) {
if (height + lineHeight <= GuiDraw.displaySize().height - 8 * 2 - 10 || tmp.isEmpty()) {
// top & bottom 8px + last line for showing page
// and at least include one line per page
height += lineHeight;
} else {
ret.add(new ArrayList<>(tmp));
@@ -670,8 +805,8 @@ public class GuiContainerManager {
}
}
public static void incrementTooltipPage() {
tooltipPage++;
public static boolean incrementTooltipPage() {
return tooltipPage != Math.min(tooltipPage++, maxTooltipPage);
}
public void renderSlotUnderlay(Slot slot) {
@@ -713,7 +848,7 @@ public class GuiContainerManager {
if (Keyboard.getEventKeyState() || (k == 0 && Character.isDefined(c))) {
try {
keyTyped(c, k);
} catch (java.lang.IndexOutOfBoundsException e) {
} catch (IndexOutOfBoundsException e) {
System.err.println("Caught out of bounds exception pressing " + c + " " + k);
e.printStackTrace();
}
@@ -0,0 +1,50 @@
package codechicken.nei.recipe;
import java.util.Comparator;
import java.util.List;
import net.minecraft.item.ItemStack;
import codechicken.nei.FavoriteRecipes;
import codechicken.nei.ItemsTooltipLineHandler;
import codechicken.nei.NEIClientUtils;
public class AcceptsFollowingTooltipLineHandler extends ItemsTooltipLineHandler {
protected static final int DEFAULT_MAX_ROWS = 5;
public Object tooltipGUID;
public AcceptsFollowingTooltipLineHandler(Object tooltipGUID, List<ItemStack> items, ItemStack activeStack,
int maxRows) {
super(NEIClientUtils.translate("recipe.accepts"), items, false, maxRows);
this.tooltipGUID = tooltipGUID;
setActiveStack(activeStack);
}
public static AcceptsFollowingTooltipLineHandler of(Object tooltipGUID, List<ItemStack> items,
ItemStack activeStack) {
return of(tooltipGUID, items, activeStack, DEFAULT_MAX_ROWS);
}
public static AcceptsFollowingTooltipLineHandler of(Object tooltipGUID, List<ItemStack> items,
ItemStack activeStack, int maxRows) {
if (items.size() > 1) {
items.sort(Comparator.comparing(FavoriteRecipes::contains).reversed());
return new AcceptsFollowingTooltipLineHandler(tooltipGUID, items, activeStack, maxRows);
}
return null;
}
@Override
protected void drawItem(int x, int y, ItemStack drawStack, String stackSize) {
super.drawItem(x, y, drawStack, stackSize);
if (FavoriteRecipes.contains(drawStack)) {
NEIClientUtils.drawNEIOverlayText("F", x, y);
}
}
}
@@ -0,0 +1,134 @@
package codechicken.nei.recipe;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.inventory.Slot;
import net.minecraft.inventory.SlotCrafting;
import codechicken.nei.ItemPanels;
import codechicken.nei.ItemStackAmount;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.RestartableTask;
import codechicken.nei.bookmark.BookmarkItem;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.chain.RecipeChainIterator;
import codechicken.nei.recipe.chain.RecipeChainMath;
public class AutoCraftingManager {
private static RecipeChainMath math;
private static final RestartableTask task = new RestartableTask("NEI Bookmark AutoCraft Processing") {
@Override
public void execute() {
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
final List<BookmarkItem> initialItems = prepareInitialItems(math, getInventoryItems(guiContainer));
boolean processed = false;
boolean changed = false;
StackInfo.pauseItemDamageSound(true);
do {
changed = false;
RecipeChainIterator iterator = new RecipeChainIterator(math, initialItems);
iterator.updateInventory(getInventoryItems(guiContainer));
while (iterator.hasNext() && !interrupted(guiContainer)) {
final Map<RecipeId, Long> recipes = iterator.next();
boolean craft = false;
for (Map.Entry<RecipeId, Long> entry : recipes.entrySet()) {
final RecipeHandlerRef handler = RecipeHandlerRef.of(entry.getKey());
if (handler != null && handler.canCraft(guiContainer)) {
long multiplier = entry.getValue();
while (multiplier > 0 && !interrupted(guiContainer)
&& handler.craft(guiContainer, (int) Math.min(64, multiplier))) {
multiplier -= 64;
}
craft = multiplier != entry.getValue();
}
if (interrupted(guiContainer)) break;
}
if (craft) {
changed = true;
processed = true;
iterator.updateInventory(getInventoryItems(guiContainer));
}
}
} while (changed && !interrupted(guiContainer));
StackInfo.pauseItemDamageSound(false);
if (processed && !changed && !interrupted(guiContainer)) {
NEIClientUtils.playClickSound();
}
}
@Override
public void clearTasks() {
super.clearTasks();
AutoCraftingManager.math = null;
}
private boolean interrupted(GuiContainer guiContainer) {
return interrupted() || guiContainer != NEIClientUtils.getGuiContainer();
}
private List<BookmarkItem> prepareInitialItems(RecipeChainMath math, ItemStackAmount inventory) {
final List<BookmarkItem> initialItems = new ArrayList<>();
for (BookmarkItem item : math.initialItems) {
final long invStackSize = inventory.getOrDefault(item.itemStack, 0L);
final long amount = Math.max(0, item.amount - invStackSize * item.fluidCellAmount);
if (amount > 0) {
initialItems.add(item.copyWithAmount(amount));
}
}
return initialItems;
}
};
private AutoCraftingManager() {}
public static void runProcessing(RecipeChainMath math) {
task.stop();
AutoCraftingManager.math = math;
if (AutoCraftingManager.math != null) {
ItemPanels.bookmarkPanel.clearTooltips();
math.createMasterRoot();
task.restart();
}
}
public static boolean processing() {
return AutoCraftingManager.math != null && !task.interrupted();
}
public static ItemStackAmount getInventoryItems(GuiContainer guiContainer) {
final ItemStackAmount inventory = new ItemStackAmount();
for (Slot slot : guiContainer.inventorySlots.inventorySlots) {
if (slot.getHasStack() && !(slot instanceof SlotCrafting) && slot.canTakeStack(guiContainer.mc.thePlayer)) {
inventory.add(slot.getStack());
}
}
return inventory;
}
}
@@ -14,6 +14,7 @@ import com.google.gson.JsonPrimitive;
import codechicken.nei.PositionedStack;
import codechicken.nei.util.NBTJson;
@Deprecated
public class BookmarkRecipeId {
public String handlerName = null;
@@ -25,16 +26,16 @@ public class BookmarkRecipeId {
for (Object pos : stacks) {
if (pos instanceof PositionedStack) {
pos = StackInfo.getItemStackWithMinimumDamage(((PositionedStack) pos).items);
if (pos instanceof PositionedStack item) {
pos = StackInfo.getItemStackWithMinimumDamage(item.items);
}
if (pos instanceof ItemStack) {
pos = StackInfo.itemStackToNBT((ItemStack) pos);
if (pos instanceof ItemStack item) {
pos = StackInfo.itemStackToNBT(item);
}
if (pos instanceof NBTTagCompound) {
ingredients.add((NBTTagCompound) pos);
if (pos instanceof NBTTagCompound item) {
ingredients.add(item);
}
}
}
@@ -36,11 +36,10 @@ public class CheatItemHandler extends INEIGuiAdapter {
draggedStack.stackSize -= total - contents;
}
return true;
} else {
draggedStack.stackSize = 0;
}
return true;
}
return false;
@@ -7,31 +7,23 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import net.minecraft.client.entity.EntityClientPlayerMP;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.inventory.SlotCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import codechicken.lib.inventory.InventoryUtils;
import codechicken.nei.FastTransferManager;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.api.IOverlayHandler;
import cpw.mods.fml.relauncher.ReflectionHelper;
public class DefaultOverlayHandler implements IOverlayHandler {
private static Class<?> gtItem;
static {
try {
final ClassLoader loader = DefaultOverlayHandler.class.getClassLoader();
gtItem = ReflectionHelper
.getClass(loader, "gregtech.api.items.MetaBaseItem", "gregtech.api.items.GT_MetaBase_Item");
} catch (Exception ignored) {
/* Do nothing */
}
}
public static class DistributedIngred {
public DistributedIngred(ItemStack item) {
@@ -43,6 +35,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
public int distributed;
public int numSlots;
public int recipeAmount;
public boolean isContainerItem = false;
}
public static class IngredientDistribution {
@@ -70,96 +63,182 @@ public class DefaultOverlayHandler implements IOverlayHandler {
public int offsety;
@Override
public void overlayRecipe(GuiContainer gui, IRecipeHandler recipe, int recipeIndex, boolean shift) {
List<PositionedStack> ingredients = recipe.getIngredientStacks(recipeIndex);
List<DistributedIngred> ingredStacks = getPermutationIngredients(ingredients);
public void overlayRecipe(GuiContainer gui, IRecipeHandler handler, int recipeIndex, boolean maxTransfer) {
transferRecipe(gui, handler, recipeIndex, maxTransfer ? Integer.MAX_VALUE : 1);
}
if (!clearIngredients(gui, ingredients)) return;
@Override
public int transferRecipe(GuiContainer gui, IRecipeHandler handler, int recipeIndex, int multiplier) {
final List<PositionedStack> ingredients = handler.getIngredientStacks(recipeIndex);
final List<DistributedIngred> ingredStacks = getPermutationIngredients(ingredients);
if (!clearIngredients(gui)) return 0;
findInventoryQuantities(gui, ingredStacks);
List<IngredientDistribution> assignedIngredients = assignIngredients(ingredients, ingredStacks);
if (assignedIngredients == null) return;
final List<IngredientDistribution> assignedIngredients = assignIngredients(ingredients, ingredStacks);
if (assignedIngredients == null) return 0;
assignIngredSlots(gui, ingredients, assignedIngredients);
int quantity = calculateRecipeQuantity(assignedIngredients);
multiplier = Math.min(multiplier == 0 ? 64 : multiplier, calculateRecipeQuantity(assignedIngredients));
if (quantity != 0) moveIngredients(gui, assignedIngredients, quantity);
moveIngredients(gui, assignedIngredients, Math.max(1, multiplier));
return assignedIngredients.stream().anyMatch(distrib -> distrib.distrib.distributed == 0) ? 0 : multiplier;
}
private boolean clearIngredients(GuiContainer gui, List<PositionedStack> ingreds) {
for (PositionedStack pstack : ingreds) {
for (Slot slot : gui.inventorySlots.inventorySlots) {
if (slot.xDisplayPosition == pstack.relx + offsetx && slot.yDisplayPosition == pstack.rely + offsety) {
if (!slot.getHasStack()) continue;
FastTransferManager.clickSlot(gui, slot.slotNumber, 0, 1);
if (slot.getHasStack()) return false;
}
}
}
@Override
public boolean canFillCraftingGrid(GuiContainer firstGui, IRecipeHandler handler, int recipeIndex) {
return true;
}
private void moveIngredients(GuiContainer gui, List<IngredientDistribution> assignedIngredients, int quantity) {
for (IngredientDistribution distrib : assignedIngredients) {
if (distrib.slots.length == 0) continue;
@Override
public boolean canCraft(GuiContainer firstGui, IRecipeHandler handler, int recipeIndex) {
return canFillCraftingGrid(firstGui, handler, recipeIndex)
&& presenceOverlay(firstGui, handler, recipeIndex).stream().allMatch(state -> state.isPresent());
}
ItemStack pstack = distrib.permutation;
int transferCap = quantity * pstack.stackSize;
int transferred = 0;
@Override
public boolean craft(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, int multiplier) {
final EntityClientPlayerMP thePlayer = NEIClientUtils.mc().thePlayer;
boolean craft = false;
int destSlotIndex = 0;
Slot dest = distrib.slots[0];
int slotTransferred = 0;
int slotTransferCap = pstack.getMaxStackSize();
while (multiplier > 0) {
final int transfer = transferRecipe(firstGui, recipe, recipeIndex, multiplier);
for (Slot slot : gui.inventorySlots.inventorySlots) {
if (!slot.getHasStack() || !canMoveFrom(slot, gui)) continue;
if (transfer <= 0) {
break;
}
ItemStack stack = slot.getStack();
if (!canStack(stack, pstack)) continue;
multiplier -= transfer;
int amount = Math.min(transferCap - transferred, stack.stackSize);
FastTransferManager.clickSlot(gui, slot.slotNumber);
for (int c = 0; c < amount; c++) {
FastTransferManager.clickSlot(gui, dest.slotNumber, 1);
transferred++;
slotTransferred++;
if (slotTransferred >= slotTransferCap) {
destSlotIndex++;
if (destSlotIndex == distrib.slots.length) {
dest = null;
break;
}
dest = distrib.slots[destSlotIndex];
slotTransferred = 0;
}
for (Slot slot : firstGui.inventorySlots.inventorySlots) {
if (slot.getHasStack() && slot instanceof SlotCrafting && slot.canTakeStack(thePlayer)) {
FastTransferManager.clickSlot(firstGui, slot.slotNumber, 0, 1);
craft = true;
break;
}
FastTransferManager.clickSlot(gui, slot.slotNumber);
if (transferred >= transferCap || dest == null) break;
}
}
clearIngredients(firstGui);
return craft;
}
private boolean clearIngredients(GuiContainer gui) {
final EntityClientPlayerMP thePlayer = NEIClientUtils.mc().thePlayer;
for (Slot slot : gui.inventorySlots.inventorySlots) {
if (slot.getHasStack() && !canMoveFrom(slot, gui)
&& !(slot instanceof SlotCrafting)
&& slot.canTakeStack(thePlayer)) {
FastTransferManager.clickSlot(gui, slot.slotNumber, 0, 1);
if (slot.getHasStack()) return false;
}
}
return dropOffMouseStack(thePlayer, gui);
}
private void moveIngredients(GuiContainer gui, List<IngredientDistribution> assignedIngredients, int multiplier) {
final EntityClientPlayerMP thePlayer = NEIClientUtils.mc().thePlayer;
for (Slot slot : gui.inventorySlots.inventorySlots) {
if (slot instanceof SlotCrafting || !slot.getHasStack()
|| !canMoveFrom(slot, gui)
|| !slot.canTakeStack(thePlayer))
continue;
ItemStack stack = slot.getStack();
int slotTransferCap = stack.getMaxStackSize();
for (IngredientDistribution distrib : assignedIngredients) {
if (distrib.slots.length == 0 || !slot.getHasStack() || !canStack(distrib.permutation, stack)) continue;
int transferCap = Math.min(slotTransferCap, multiplier * distrib.permutation.stackSize);
int stackSize = slot.getStack().stackSize;
boolean pickup = false;
for (Slot dest : distrib.slots) {
int amount = Math
.min(transferCap - (dest.getHasStack() ? dest.getStack().stackSize : 0), stackSize);
if (stackSize <= amount) {
if (!pickup) {
FastTransferManager.clickSlot(gui, slot.slotNumber);
}
FastTransferManager.clickSlot(gui, dest.slotNumber);
break;
} else {
for (int c = 0; c < amount; c++) {
if (pickup != (pickup = true)) {
FastTransferManager.clickSlot(gui, slot.slotNumber);
}
FastTransferManager.clickSlot(gui, dest.slotNumber, 1);
stackSize--;
}
}
}
if (thePlayer.inventory.getItemStack() != null) {
FastTransferManager.clickSlot(gui, slot.slotNumber);
}
}
}
}
protected boolean dropOffMouseStack(EntityPlayer entityPlayer, GuiContainer gui) {
if (entityPlayer.inventory.getItemStack() == null) {
return true;
}
for (int i = 0; i < gui.inventorySlots.inventorySlots.size(); i++) {
Slot slot = gui.inventorySlots.inventorySlots.get(i);
if (slot.inventory == entityPlayer.inventory) {
ItemStack mouseItem = entityPlayer.inventory.getItemStack();
ItemStack slotStack = slot.getStack();
if (slotStack == null || NEIClientUtils.areStacksSameType(mouseItem, slotStack)) {
FastTransferManager.clickSlot(gui, i, 0, 0);
}
if (entityPlayer.inventory.getItemStack() == null) {
return true;
}
}
}
return entityPlayer.inventory.getItemStack() == null;
}
private int calculateRecipeQuantity(List<IngredientDistribution> assignedIngredients) {
int quantity = Integer.MAX_VALUE;
for (IngredientDistribution distrib : assignedIngredients) {
DistributedIngred istack = distrib.distrib;
final DistributedIngred istack = distrib.distrib;
if (istack.distributed == 0) continue;
if (istack.numSlots == 0) return 0;
final int maxStackSize = istack.stack.getMaxStackSize();
int allSlots = istack.invAmount;
if (allSlots / istack.numSlots > maxStackSize) allSlots = istack.numSlots * maxStackSize;
final int newQuantity = allSlots / istack.distributed;
if (maxStackSize == 1) {
if (maxStackSize == 1 && istack.isContainerItem) {
// If non-stackable, fill up as much as possible of the other ingredients
continue;
}
quantity = Math.min(quantity, newQuantity);
final int allSlots = Math.min(istack.invAmount, istack.numSlots * maxStackSize);
quantity = Math.min(quantity, allSlots / istack.distributed);
}
if (quantity == Integer.MAX_VALUE) {
// Only possible if all ingredients were non-stackable
quantity = 1;
@@ -239,8 +318,10 @@ public class DefaultOverlayHandler implements IOverlayHandler {
}
}
if (biggestIngred == null) // not enough ingreds
return null;
if (biggestIngred == null) {
biggestIngred = new DistributedIngred(posstack.item);
permutation = InventoryUtils.copyStack(posstack.item, 0);
}
biggestIngred.distributed += permutation.stackSize;
assignedIngredients.add(new IngredientDistribution(biggestIngred, permutation));
@@ -252,9 +333,31 @@ public class DefaultOverlayHandler implements IOverlayHandler {
private void findInventoryQuantities(GuiContainer gui, List<DistributedIngred> ingredStacks) {
for (Slot slot : gui.inventorySlots.inventorySlots) /* work out how much we have to go round */ {
if (slot.getHasStack() && canMoveFrom(slot, gui)) {
ItemStack pstack = slot.getStack();
DistributedIngred istack = findIngred(ingredStacks, pstack);
if (istack != null) istack.invAmount += pstack.stackSize;
final ItemStack pstack = slot.getStack();
final DistributedIngred istack = findIngred(ingredStacks, pstack);
if (istack != null) {
istack.invAmount += pstack.stackSize;
if (!istack.isContainerItem && pstack.getMaxStackSize() == 1
&& pstack.getItem().hasContainerItem(pstack)) {
final NBTTagCompound tagCompound = pstack.getTagCompound();
if (tagCompound != null && tagCompound.hasKey("GT.ToolStats")) {
istack.isContainerItem = true;
} else {
final boolean isPausedItemDamageSound = StackInfo.isPausedItemDamageSound();
StackInfo.pauseItemDamageSound(true);
final ItemStack containerItem = pstack.getItem().getContainerItem(pstack);
if (containerItem != null) {
istack.isContainerItem = pstack.getItem() == containerItem.getItem();
}
StackInfo.pauseItemDamageSound(isPausedItemDamageSound);
}
}
}
}
}
}
@@ -292,22 +395,12 @@ public class DefaultOverlayHandler implements IOverlayHandler {
}
public DistributedIngred findIngred(List<DistributedIngred> ingredStacks, ItemStack pstack) {
for (DistributedIngred istack : ingredStacks) if (canStack(pstack, istack.stack)) return istack;
for (DistributedIngred istack : ingredStacks) if (canStack(istack.stack, pstack)) return istack;
return null;
}
protected boolean canStack(ItemStack stack1, ItemStack stack2) {
if (stack1 == null || stack2 == null) return true;
if (stack1.getItem() == stack2.getItem() && stack1.getItemDamage() == stack2.getItemDamage()) {
if (ItemStack.areItemStackTagsEqual(stack2, stack1)) return true;
// 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
if (((gtItem != null && gtItem.isInstance(stack1.getItem()))
|| (stack1.getMaxStackSize() == 1 && stack2.getMaxStackSize() == 1))
&& (stack1.stackTagCompound == null ^ stack2.stackTagCompound == null))
return true;
}
return false;
return NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack1, stack2);
}
}
@@ -6,7 +6,6 @@ import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.IFluidContainerItem;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.ItemPanels;
import codechicken.nei.api.INEIGuiAdapter;
@@ -19,18 +18,18 @@ public class FillFluidContainerHandler extends INEIGuiAdapter {
return false;
}
if (draggedStack.getItem() instanceof IFluidContainerItem || FluidContainerRegistry.isContainer(draggedStack)) {
ItemPanelSlot mouseOverSlot = ItemPanels.itemPanel.getSlotMouseOver(mouseX, mouseY);
if (StackInfo.isFluidContainer(draggedStack)) {
ItemStack overItemStack = ItemPanels.itemPanel.getStackMouseOver(mouseX, mouseY);
if (mouseOverSlot == null) {
mouseOverSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseX, mouseY);
if (overItemStack == null) {
overItemStack = ItemPanels.bookmarkPanel.getStackMouseOver(mouseX, mouseY);
}
if (mouseOverSlot != null) {
FluidStack fluidStack = StackInfo.getFluid(mouseOverSlot.item);
if (overItemStack != null) {
final FluidStack fluidStack = StackInfo.getFluid(overItemStack);
if (fluidStack != null) {
ItemStack container = fillContainer(draggedStack, fluidStack);
final ItemStack container = fillContainer(draggedStack, fluidStack);
if (container != null) {
container.stackSize = draggedStack.stackSize;
@@ -43,7 +42,7 @@ public class FillFluidContainerHandler extends INEIGuiAdapter {
}
if (button == 1 && StackInfo.getFluid(container != null ? container : draggedStack) != null) {
ItemPanels.bookmarkPanel.addOrRemoveItem((container != null ? container : draggedStack).copy());
ItemPanels.bookmarkPanel.addItem(container != null ? container : draggedStack);
}
}
@@ -70,8 +69,7 @@ public class FillFluidContainerHandler extends INEIGuiAdapter {
}
return FluidContainerRegistry.fillFluidContainer(fluidStack, draggedStack);
} else if (draggedStack.getItem() instanceof IFluidContainerItem) {
IFluidContainerItem item = (IFluidContainerItem) draggedStack.getItem();
} else if (draggedStack.getItem() instanceof IFluidContainerItem item) {
if (item.getCapacity(draggedStack) > 0) {
item.drain(draggedStack, item.getCapacity(draggedStack), true);
@@ -1,25 +1,24 @@
package codechicken.nei.recipe;
import static codechicken.lib.gui.GuiDraw.getMousePosition;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.item.ItemStack;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.FavoriteRecipes;
import codechicken.nei.ItemPanels;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.bookmark.BookmarksGridSlot;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.stackinfo.GTFluidStackStringifyHandler;
public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
@@ -34,7 +33,7 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
public static GuiRecipe<?> createRecipeGui(String outputId, boolean open, Object... results) {
final Minecraft mc = NEIClientUtils.mc();
final BookmarkRecipeId recipeId;
final RecipeId recipeId;
if ("item".equals(outputId)) {
for (int i = 0; i < results.length; i++) {
@@ -42,7 +41,7 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
}
recipeId = getRecipeId(mc.currentScreen, (ItemStack) results[0]);
} else if ("recipeId".equals(outputId)) {
recipeId = (BookmarkRecipeId) results[1];
recipeId = (RecipeId) results[1];
} else {
recipeId = getCurrentRecipeId(mc.currentScreen);
}
@@ -63,38 +62,16 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
return null;
}
public static boolean overlayRecipe(ItemStack stack, BookmarkRecipeId recipeId, final Boolean shift) {
if (stack == null || recipeId == null) {
return false;
}
final ArrayList<ICraftingHandler> handlers = getCraftingHandlers("recipeId", stack, recipeId);
if (!handlers.isEmpty()) {
final GuiCraftingRecipe gui = new GuiCraftingRecipe(handlers, true);
final int recipe = gui.openTargetRecipe(recipeId);
if (recipe != -1) {
gui.overlayRecipe(recipe, shift);
return true;
}
}
return false;
}
public static ArrayList<ICraftingHandler> getCraftingHandlers(String outputId, Object... results) {
ArrayList<ICraftingHandler> craftinghandlers = GuiCraftingRecipe.craftinghandlers;
ArrayList<ICraftingHandler> serialCraftingHandlers = GuiCraftingRecipe.serialCraftingHandlers;
Function<ICraftingHandler, ICraftingHandler> recipeHandlerFunction;
UnaryOperator<ICraftingHandler> recipeHandlerFunction;
if ("recipeId".equals(outputId)) {
ItemStack stack = (ItemStack) results[0];
BookmarkRecipeId recipeId = (BookmarkRecipeId) results[1];
craftinghandlers = filterByHandlerName(craftinghandlers, recipeId.handlerName);
serialCraftingHandlers = filterByHandlerName(serialCraftingHandlers, recipeId.handlerName);
RecipeId recipeId = (RecipeId) results[1];
craftinghandlers = filterByHandlerName(craftinghandlers, recipeId.getHandleName());
serialCraftingHandlers = filterByHandlerName(serialCraftingHandlers, recipeId.getHandleName());
recipeHandlerFunction = h -> h.getRecipeHandler("item", stack);
} else {
recipeHandlerFunction = h -> h.getRecipeHandler(outputId, results);
@@ -128,25 +105,29 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
return stack;
}
protected static BookmarkRecipeId getRecipeId(GuiScreen gui, ItemStack stackover) {
public static RecipeId getRecipeId(GuiScreen gui, ItemStack stackover) {
if (gui instanceof GuiRecipe) {
final List<PositionedStack> ingredients = ((GuiRecipe<?>) gui).getFocusedRecipeIngredients();
final String handlerName = ((GuiRecipe<?>) gui).getHandlerName();
if (gui instanceof GuiRecipe guiRecipe) {
final Recipe focusedRecipe = guiRecipe.getFocusedRecipe();
if (ingredients != null && !ingredients.isEmpty()) {
return new BookmarkRecipeId(handlerName, ingredients);
if (focusedRecipe != null) {
return focusedRecipe.getRecipeId();
}
}
final Point mouseover = getMousePosition();
ItemPanelSlot panelSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
final Point mouseover = GuiDraw.getMousePosition();
final BookmarksGridSlot panelSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
RecipeId recipeId = null;
if (panelSlot != null) {
return ItemPanels.bookmarkPanel.getBookmarkRecipeId(panelSlot.slotIndex);
if (panelSlot != null && !panelSlot.isIngredient()) {
recipeId = panelSlot.getRecipeId();
}
return ItemPanels.bookmarkPanel.getBookmarkRecipeId(stackover);
if (recipeId == null) {
recipeId = FavoriteRecipes.getFavorite(stackover);
}
return recipeId;
}
private GuiCraftingRecipe(ArrayList<ICraftingHandler> handlers, boolean limitToOneRecipe) {
@@ -0,0 +1,249 @@
package codechicken.nei.recipe;
import static codechicken.nei.NEIClientUtils.translate;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.FavoriteRecipes;
import codechicken.nei.Image;
import codechicken.nei.ItemPanels;
import codechicken.nei.ItemStackSet;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.drawable.DrawableBuilder;
import codechicken.nei.drawable.DrawableResource;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.Recipe.RecipeIngredient;
import codechicken.nei.util.NEIMouseUtils;
public class GuiFavoriteButton extends GuiRecipeButton {
private static final int BUTTON_ID_START = 14;
protected static final DrawableResource ICON_STATE_OFF = new DrawableBuilder(
"nei:textures/nei_sprites.png",
10,
76,
9,
10).build();
protected static final DrawableResource ICON_STATE_ON = new DrawableBuilder(
"nei:textures/nei_sprites.png",
19,
76,
9,
10).build();
protected final Recipe recipe;
protected boolean favorite = false;
protected RecipeIngredient favoriteResult = null;
protected RecipeIngredient selectedResult = null;
public GuiFavoriteButton(RecipeHandlerRef handlerRef, int x, int y) {
super(handlerRef, x, y, BUTTON_ID_START + handlerRef.recipeIndex, "❤");
this.recipe = Recipe.of(this.handlerRef);
ItemStack stack = FavoriteRecipes.getFavorite(this.recipe.getRecipeId());
this.favorite = stack != null;
if (stack == null) {
stack = this.recipe.getResult();
}
for (RecipeIngredient result : this.recipe.getResults()) {
if (StackInfo.equalItemAndNBT(result.getItemStack(), stack, true)) {
this.favoriteResult = result;
break;
}
}
this.visible = this.favoriteResult != null;
}
public boolean isFavorite() {
return favorite;
}
public void toggleFavorite() {
this.favorite = !this.favorite;
if (this.selectedResult != null) {
this.favoriteResult = this.selectedResult;
}
FavoriteRecipes
.setFavorite(this.favoriteResult.getItemStack(), this.favorite ? this.recipe.getRecipeId() : null);
}
@Override
protected void drawContent(Minecraft minecraft, int y, int x, boolean mouseOver) {
final DrawableResource icon = isFavorite() ? ICON_STATE_ON : ICON_STATE_OFF;
final int iconX = this.xPosition + (this.width - icon.width - 1) / 2;
final int iconY = this.yPosition + (this.height - icon.height) / 2;
GL11.glColor4f(1, 1, 1, this.enabled ? 1 : 0.5f);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
icon.draw(iconX, iconY);
GL11.glDisable(GL11.GL_BLEND);
GL11.glColor4f(1, 1, 1, 1);
if (!mouseOver) {
this.selectedResult = null;
} else if (this.selectedResult == null) {
this.selectedResult = this.favoriteResult;
}
}
@Override
public void mouseReleased(int mouseX, int mouseY) {
toggleFavorite();
}
public Recipe getRecipe() {
return Recipe.of(this.handlerRef);
}
public void lastKeyTyped(GuiRecipe<?> gui, char keyChar, int keyID) {
if (NEIClientConfig.isKeyHashDown("gui.bookmark") && NEIClientUtils.shiftKey()) {
ItemPanels.bookmarkPanel.addGroup(getRecipesTree(getRecipe()), BookmarkViewMode.TODO_LIST, true);
}
}
@Override
public Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
translate("recipe.favorite.bookmark_recipe"));
if (this.recipe.getResults().size() > 1) {
hotkeys.put(
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_NONE + NEIMouseUtils.MOUSE_SCROLL),
translate("recipe.favorite.change_result_index"));
}
return hotkeys;
}
@Override
public List<String> handleTooltip(GuiRecipe<?> gui, List<String> currenttip) {
currenttip.add(translate("recipe.favorite"));
return currenttip;
}
@Override
public void drawItemOverlay() {
if (this.selectedResult == null) return;
NEIClientUtils.gl2DRenderContext(
() -> GuiDraw.drawRect(this.selectedResult.relx, this.selectedResult.rely, 16, 16, 0x66333333));
final Image icon = isFavorite() ? ICON_STATE_ON : ICON_STATE_OFF;
final int iconX = this.selectedResult.relx + (16 - icon.width) / 2;
final int iconY = this.selectedResult.rely + (18 - icon.height) / 2;
LayoutManager.drawIcon(iconX, iconY, icon);
}
@Override
public boolean mouseScrolled(GuiRecipe<?> gui, int scroll) {
if (this.selectedResult == null) return true;
final List<RecipeIngredient> results = new ArrayList<>(this.recipe.getResults());
if (results.size() <= 1) return true;
final Set<String> uniqueResults = new HashSet<>();
results.removeIf(ingr -> !uniqueResults.add(StackInfo.getItemStackGUID(ingr.getItemStack())));
final int nextIndex = (results.size() - scroll + results.indexOf(this.selectedResult)) % results.size();
this.selectedResult = results.get(nextIndex);
this.favorite = StackInfo.equalItemAndNBT(
results.get(nextIndex).getItemStack(),
FavoriteRecipes.getFavorite(this.recipe.getRecipeId()),
true);
return true;
}
private List<Recipe> getRecipesTree(Recipe mainRecipe) {
int depth = NEIClientConfig.getIntSetting("inventory.favorites.depth");
final ItemStackSet items = new ItemStackSet();
final List<Recipe> result = new ArrayList<>();
List<Recipe> loop = new ArrayList<>();
loop.add(mainRecipe);
result.add(mainRecipe);
while (!loop.isEmpty() && depth-- >= 0) {
List<Recipe> localLoop = new ArrayList<>();
for (Recipe localRecipe : loop) {
for (RecipeIngredient ingr : localRecipe.getIngredients()) {
List<ItemStack> permutations = ingr.getPermutations();
ItemStack stack = permutations.stream().filter(items::contains).findFirst().orElse(null);
if (stack == null) {
stack = ingr.getItemStack();
RecipeId recipeId = FavoriteRecipes.getFavorite(stack);
if (recipeId == null) {
for (ItemStack permStack : permutations) {
if ((recipeId = FavoriteRecipes.getFavorite(permStack)) != null) {
stack = permStack;
break;
}
}
}
Recipe recipe = Recipe.of(recipeId);
if (recipe == null) {
stack = null;
} else {
items.add(stack);
if (depth >= 0) {
result.add(recipe);
localLoop.add(recipe);
}
}
}
if (stack != null) {
ingr.setActiveIndex(getIngrActiveIndex(permutations, stack));
}
}
}
loop = localLoop;
}
return result;
}
private int getIngrActiveIndex(List<ItemStack> permutations, ItemStack stack) {
for (int i = 0; i < permutations.size(); i++) {
if (StackInfo.equalItemAndNBT(stack, permutations.get(i), true)) {
return i;
}
}
return 0;
}
}
@@ -1,66 +1,31 @@
package codechicken.nei.recipe;
import static codechicken.nei.NEIClientUtils.translate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import net.minecraftforge.client.event.GuiScreenEvent;
import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.BookmarkPanel.BookmarkRecipe;
import codechicken.nei.GuiNEIButton;
import codechicken.nei.ItemPanels;
import codechicken.nei.ItemsTooltipLineHandler;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.api.IOverlayHandler;
import cpw.mods.fml.common.eventhandler.Cancelable;
import codechicken.nei.bookmark.BookmarkGrid;
import codechicken.nei.drawable.DrawableBuilder;
import codechicken.nei.drawable.DrawableResource;
import codechicken.nei.util.NEIMouseUtils;
public class GuiOverlayButton extends GuiNEIButton {
public static class UpdateOverlayButtonsEvent extends GuiScreenEvent {
public List<GuiOverlayButton> buttonList;
public UpdateOverlayButtonsEvent(GuiRecipe<?> gui, List<GuiOverlayButton> buttonList) {
super(gui);
this.buttonList = new ArrayList<>(buttonList);
}
@Cancelable
public static class Pre extends UpdateOverlayButtonsEvent {
public int xOffset;
public int yOffset;
public int height;
public HandlerInfo handlerInfo;
public Pre(GuiRecipe<?> gui, int xOffset, int yOffset, int height, HandlerInfo handlerInfo) {
super(gui, new ArrayList<>());
this.xOffset = xOffset;
this.yOffset = yOffset;
this.height = height;
this.handlerInfo = handlerInfo;
}
}
public static class Post extends UpdateOverlayButtonsEvent {
public Post(GuiRecipe<?> gui, List<GuiOverlayButton> buttonList) {
super(gui, buttonList);
}
}
}
public class GuiOverlayButton extends GuiRecipeButton {
public enum ItemOverlayFormat {
@@ -99,44 +64,59 @@ public class GuiOverlayButton extends GuiNEIButton {
}
}
private static final int OVERLAY_BUTTON_ID_START = 4;
protected static final DrawableResource ICON_FILL = new DrawableBuilder(
"nei:textures/nei_sprites.png",
28,
76,
9,
10).build();
protected static final DrawableResource ICON_FILL_ERROR = new DrawableBuilder(
"nei:textures/nei_sprites.png",
37,
76,
9,
10).build();
protected static final DrawableResource ICON_OVERLAY = new DrawableBuilder(
"nei:textures/nei_sprites.png",
46,
76,
9,
10).build();
protected static final int BUTTON_ID_SHIFT = 4;
public final GuiContainer firstGui;
public final IRecipeHandler handler;
public final int recipeIndex;
protected ItemsTooltipLineHandler missedMaterialsTooltipLineHandler;
protected final IOverlayHandler overlayHandler;
protected final List<ItemOverlayState> itemPresenceCache = new ArrayList<>();
protected ItemsTooltipLineHandler missedMaterialsTooltipLineHandler;
protected boolean requireShiftForOverlayRecipe = true;
protected boolean useOverlayRenderer = false;
protected boolean canUseOverlayRenderer = false;
protected boolean canFillCraftingGrid = false;
protected boolean hasOverlay = false;
public GuiOverlayButton(GuiContainer firstGui, IRecipeHandler handler, int recipeIndex, int x, int y, int width,
int height) {
super(OVERLAY_BUTTON_ID_START + recipeIndex, x, y, width, height, "+");
public GuiOverlayButton(GuiContainer firstGui, RecipeHandlerRef handlerRef, int x, int y) {
super(handlerRef, x, y, handlerRef.recipeIndex + BUTTON_ID_SHIFT, "+");
this.firstGui = firstGui != null && firstGui.inventorySlots != null ? firstGui : null;
this.handler = handler;
this.recipeIndex = recipeIndex;
this.hasOverlay = this.firstGui != null
&& handler.hasOverlay(this.firstGui, this.firstGui.inventorySlots, recipeIndex);
this.useOverlayRenderer = this.hasOverlay && handler.getOverlayRenderer(firstGui, recipeIndex) != null;
this.overlayHandler = this.hasOverlay ? handler.getOverlayHandler(firstGui, recipeIndex) : null;
this.canUseOverlayRenderer = this.firstGui != null && handlerRef.getRecipeOverlayRenderer(firstGui) != null;
this.canFillCraftingGrid = this.firstGui != null && handlerRef.getOverlayHandler(firstGui) != null;
this.hasOverlay = this.canUseOverlayRenderer || this.canFillCraftingGrid;
setRequireShiftForOverlayRecipe(NEIClientConfig.requireShiftForOverlayRecipe());
ingredientsOverlay();
}
@Override
public List<String> handleTooltip(GuiRecipe<?> gui, List<String> currenttip) {
currenttip.add(translate("recipe.overlay"));
currenttip.add(NEIClientUtils.translate("recipe.overlay"));
if (!this.enabled && this.requireShiftForOverlayRecipe && this.overlayHandler == null) {
if (!this.enabled && this.requireShiftForOverlayRecipe && this.canFillCraftingGrid) {
currenttip.set(currenttip.size() - 1, currenttip.get(currenttip.size() - 1) + GuiDraw.TOOLTIP_LINESPACE);
currenttip.add(EnumChatFormatting.RED + translate("recipe.overlay.mismatch") + EnumChatFormatting.RESET);
currenttip.add(
EnumChatFormatting.RED + NEIClientUtils.translate("recipe.overlay.mismatch")
+ EnumChatFormatting.RESET);
} else if (this.missedMaterialsTooltipLineHandler != null) {
if ((!this.requireShiftForOverlayRecipe || NEIClientUtils.shiftKey()) && this.overlayHandler != null) {
if ((!this.requireShiftForOverlayRecipe || NEIClientUtils.shiftKey()) && this.canFillCraftingGrid) {
this.missedMaterialsTooltipLineHandler.setLabelColor(EnumChatFormatting.RED);
} else {
this.missedMaterialsTooltipLineHandler.setLabelColor(EnumChatFormatting.GRAY);
@@ -148,31 +128,32 @@ public class GuiOverlayButton extends GuiNEIButton {
return currenttip;
}
@Override
public Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
if (this.requireShiftForOverlayRecipe && this.useOverlayRenderer) {
hotkeys.put(translate("recipe.overlay.fillCraftingGrid.key"), translate("recipe.overlay.fillCraftingGrid"));
if (requireShiftForOverlayRecipe()) {
if (useOverlayRenderer()) {
hotkeys.put(
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("recipe.overlay.overlayRecipe"));
}
if (canFillCraftingGrid()) {
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("recipe.overlay.fillCraftingGrid"));
}
} else if (canFillCraftingGrid()) {
hotkeys.put(
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("recipe.overlay.fillCraftingGrid"));
}
String keyName = NEIClientConfig.getKeyName("gui.bookmark");
if (keyName != null) {
hotkeys.put(keyName, translate("recipe.overlay.bookmark"));
}
keyName = NEIClientConfig.getKeyName("gui.bookmark_recipe");
if (keyName != null) {
hotkeys.put(keyName, translate("recipe.overlay.bookmarkRecipe"));
}
keyName = NEIClientConfig.getKeyName("gui.bookmark_count");
if (keyName != null) {
hotkeys.put(keyName, translate("recipe.overlay.bookmarkAmount"));
}
keyName = NEIClientConfig.getKeyName("gui.bookmark_recipe_count");
if (keyName != null) {
hotkeys.put(keyName, translate("recipe.overlay.bookmarkRecipeAndAmount"));
}
hotkeys.put(
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("recipe.overlay.bookmarkRecipe"));
return hotkeys;
}
@@ -185,37 +166,59 @@ public class GuiOverlayButton extends GuiNEIButton {
}
}
public void drawItemPresenceOverlay() {
final int presenceOverlay = NEIClientConfig.itemPresenceOverlay();
final boolean highlightPresentItem = NEIClientConfig.isSlotHighlightPresent();
final ItemOverlayFormat format = ItemOverlayFormat.from(presenceOverlay);
@Override
protected void drawContent(Minecraft minecraft, int y, int x, boolean mouseOver) {
DrawableResource icon = ICON_OVERLAY;
for (ItemOverlayState overlay : ingredientsOverlay()) {
if (highlightPresentItem || !overlay.isPresent()) {
overlay.draw(format);
if (this.hasOverlay && (!this.requireShiftForOverlayRecipe || NEIClientUtils.shiftKey())) {
icon = this.missedMaterialsTooltipLineHandler == null ? ICON_FILL : ICON_FILL_ERROR;
}
final int iconX = this.xPosition + (this.width - icon.width - 1) / 2;
final int iconY = this.yPosition + (this.height - icon.height) / 2;
GL11.glColor4f(1, 1, 1, this.enabled ? 1 : 0.5f);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
icon.draw(iconX, iconY);
GL11.glDisable(GL11.GL_BLEND);
GL11.glColor4f(1, 1, 1, 1);
}
@Override
public void drawItemOverlay() {
final int presenceOverlay = NEIClientConfig.itemPresenceOverlay();
if (presenceOverlay > 0) {
final boolean highlightPresentItem = NEIClientConfig.isSlotHighlightPresent();
final ItemOverlayFormat format = ItemOverlayFormat.from(presenceOverlay);
for (ItemOverlayState overlay : ingredientsOverlay()) {
if (highlightPresentItem || !overlay.isPresent()) {
overlay.draw(format);
}
}
}
}
protected List<ItemOverlayState> ingredientsOverlay() {
List<PositionedStack> ingredients = this.handler.getIngredientStacks(recipeIndex);
List<PositionedStack> ingredients = this.handlerRef.handler.getIngredientStacks(this.handlerRef.recipeIndex);
if (this.itemPresenceCache.size() != ingredients.size()) {
this.itemPresenceCache.clear();
if (this.overlayHandler != null) {
this.itemPresenceCache
.addAll(this.overlayHandler.presenceOverlay(this.firstGui, this.handler, this.recipeIndex));
if (this.canFillCraftingGrid) {
this.itemPresenceCache.addAll(this.handlerRef.getPresenceOverlay(this.firstGui));
} else if (this.firstGui != null) {
this.itemPresenceCache.addAll(presenceOverlay(ingredients));
}
List<ItemStack> items = this.itemPresenceCache.stream().filter(state -> !state.isPresent())
.map(state -> state.getSlot().item).collect(Collectors.toCollection(ArrayList::new));
.map(state -> state.getSlot().item).collect(Collectors.toList());
if (!items.isEmpty()) {
this.missedMaterialsTooltipLineHandler = new ItemsTooltipLineHandler(
translate("recipe.overlay.missing"),
NEIClientUtils.translate("recipe.overlay.missing"),
items,
true,
Integer.MAX_VALUE);
@@ -229,25 +232,33 @@ public class GuiOverlayButton extends GuiNEIButton {
public void setRequireShiftForOverlayRecipe(boolean require) {
this.requireShiftForOverlayRecipe = require;
this.enabled = this.hasOverlay && (this.requireShiftForOverlayRecipe || this.overlayHandler != null);
this.enabled = this.hasOverlay && (this.requireShiftForOverlayRecipe || this.canFillCraftingGrid);
}
public void setUseOverlayRenderer(boolean use) {
this.useOverlayRenderer = use;
public void setCanUseOverlayRenderer(boolean use) {
this.canUseOverlayRenderer = use;
}
public boolean useOverlayRenderer() {
return this.useOverlayRenderer;
return this.canUseOverlayRenderer;
}
public boolean requireShiftForOverlayRecipe() {
return this.requireShiftForOverlayRecipe;
}
public boolean canFillCraftingGrid() {
return this.missedMaterialsTooltipLineHandler == null;
return this.missedMaterialsTooltipLineHandler == null || this.handlerRef.canFillCraftingGrid(this.firstGui);
}
public boolean hasOverlay() {
return this.hasOverlay;
}
public Recipe getRecipe() {
return Recipe.of(this.handlerRef);
}
private List<ItemOverlayState> presenceOverlay(List<PositionedStack> ingredients) {
final List<ItemOverlayState> itemPresenceSlots = new ArrayList<>();
final List<ItemStack> invStacks = this.firstGui.inventorySlots.inventorySlots.stream()
@@ -276,82 +287,30 @@ public class GuiOverlayButton extends GuiNEIButton {
public void overlayRecipe(boolean shift) {
if (!this.hasOverlay) return;
if (!this.useOverlayRenderer || !this.requireShiftForOverlayRecipe || shift) {
if (this.overlayHandler != null) {
this.overlayHandler.overlayRecipe(
this.firstGui,
this.handler,
this.recipeIndex,
!this.requireShiftForOverlayRecipe || shift);
if (!this.requireShiftForOverlayRecipe || shift) {
if (canFillCraftingGrid()) {
this.handlerRef.fillCraftingGrid(this.firstGui, 0);
}
} else {
LayoutManager.overlayRenderer = this.handler.getOverlayRenderer(this.firstGui, this.recipeIndex);
} else if (useOverlayRenderer()) {
this.handlerRef.useOverlayRenderer(this.firstGui);
}
}
@Override
public void lastKeyTyped(GuiRecipe<?> gui, char keyChar, int keyID) {
if (NEIClientConfig.isKeyHashDown("gui.bookmark")) {
saveRecipeInBookmark(false, false);
} else if (NEIClientConfig.isKeyHashDown("gui.bookmark_recipe")) {
saveRecipeInBookmark(true, false);
} else if (NEIClientConfig.isKeyHashDown("gui.bookmark_count")) {
saveRecipeInBookmark(false, true);
} else if (NEIClientConfig.isKeyHashDown("gui.bookmark_recipe_count")) {
saveRecipeInBookmark(true, true);
}
}
public void saveRecipeInBookmark(boolean saveIngredients, boolean saveStackSize) {
final HandlerInfo handlerInfo = GuiRecipeTab.getHandlerInfo(this.handler);
final List<PositionedStack> ingredients = this.handler.getIngredientStacks(this.recipeIndex);
final BookmarkRecipeId recipeId = new BookmarkRecipeId(handlerInfo.getHandlerName(), ingredients);
if (!ItemPanels.bookmarkPanel.removeBookmarkRecipeId(recipeId)) {
BookmarkRecipe recipe = new BookmarkRecipe();
recipe.handlerName = recipeId.handlerName;
recipe.recipeId = recipeId;
if (saveIngredients) {
for (PositionedStack stack : ingredients) {
recipe.ingredients.add(stack.item);
}
}
PositionedStack result = this.handler.getResultStack(this.recipeIndex);
if (result != null) {
recipe.result.add(result.item);
} else {
for (PositionedStack stack : this.handler.getOtherStacks(this.recipeIndex)) {
recipe.result.add(stack.item);
}
}
ItemPanels.bookmarkPanel.addRecipe(recipe, saveStackSize);
if (NEIClientConfig.isKeyHashDown("gui.bookmark") && NEIClientUtils.shiftKey()) {
saveRecipeInBookmark();
}
}
public int getResultStackSize(ItemStack stackover) {
final List<PositionedStack> stacks = this.handler.getOtherStacks(this.recipeIndex);
int stackSize = stackover.stackSize;
public void saveRecipeInBookmark() {
final Recipe recipe = getRecipe();
for (PositionedStack pStack : stacks) {
if (StackInfo.equalItemAndNBT(pStack.item, stackover, true)) {
stackSize += pStack.item.stackSize;
}
if (!ItemPanels.bookmarkPanel.removeRecipe(recipe.getRecipeId(), BookmarkGrid.DEFAULT_GROUP_ID)) {
ItemPanels.bookmarkPanel.addRecipe(recipe, BookmarkGrid.DEFAULT_GROUP_ID);
}
return stackSize;
}
public Rectangle4i bounds() {
return new Rectangle4i(this.xPosition, this.yPosition, this.width, this.height);
}
public boolean contains(int mx, int my) {
return bounds().contains(mx, my);
}
}
@@ -10,7 +10,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.stream.Collectors;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
@@ -20,7 +19,6 @@ import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import net.minecraftforge.common.MinecraftForge;
import org.lwjgl.input.Keyboard;
@@ -29,9 +27,6 @@ import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.Button;
import codechicken.nei.GuiNEIButton;
import codechicken.nei.ItemStackSet;
import codechicken.nei.ItemsTooltipLineHandler;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEICPH;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
@@ -42,10 +37,8 @@ import codechicken.nei.SearchField;
import codechicken.nei.VisiblityData;
import codechicken.nei.api.IGuiContainerOverlay;
import codechicken.nei.api.INEIGuiHandler;
import codechicken.nei.api.IOverlayHandler;
import codechicken.nei.api.IRecipeFilter;
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
import codechicken.nei.api.IRecipeOverlayRenderer;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.TaggedInventoryArea;
import codechicken.nei.drawable.DrawableBuilder;
@@ -54,7 +47,9 @@ import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.guihook.IGuiClientSide;
import codechicken.nei.guihook.IGuiHandleMouseWheel;
import codechicken.nei.recipe.GuiOverlayButton.UpdateOverlayButtonsEvent;
import codechicken.nei.recipe.GuiRecipeButton.UpdateRecipeButtonsEvent;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.util.NEIMouseUtils;
public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer implements IGuiContainerOverlay,
IGuiClientSide, IGuiHandleMouseWheel, IContainerTooltipHandler, INEIGuiHandler {
@@ -69,14 +64,14 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
private static final int BG_BOTTOM_Y = BG_MIDDLE_Y + BG_MIDDLE_HEIGHT;
// Button sizes
private static final int borderPadding = 6;
private static final int buttonWidth = 13;
private static final int buttonHeight = 12;
private static final int BORDER_PADDING = 6;
private static final int BUTTON_WIDTH = 13;
private static final int BUTTON_HEIGHT = 12;
public static final List<IRecipeFilterProvider> recipeFilterers = new LinkedList<>();
protected boolean limitToOneRecipe = false;
protected PermutationTooltipLineHandler permutationTooltipLineHandler;
protected AcceptsFollowingTooltipLineHandler acceptsFollowingTooltipLineHandler;
// Background image
final DrawableResource bgTop = new DrawableBuilder("nei:textures/gui/recipebg.png", 0, BG_TOP_Y, 176, BG_TOP_HEIGHT)
@@ -98,7 +93,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
public int page;
public int recipetype;
public BookmarkRecipeId recipeId;
private RecipeId recipeId;
public ContainerRecipe slotcontainer;
public GuiContainer firstGui;
public GuiScreen firstGuiGeneral;
@@ -108,8 +103,13 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
private GuiButton nexttype;
private GuiButton prevtype;
// some mods reflect this property
@Deprecated
private GuiOverlayButton[] overlayButtons = new GuiOverlayButton[0];
private final List<GuiRecipeButton> recipeButtons = new ArrayList<>();
private String recipePageCacheKey = "";
private final Rectangle area = new Rectangle();
private final GuiRecipeTabs recipeTabs;
private final GuiRecipeCatalyst guiRecipeCatalyst;
@@ -118,35 +118,6 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
private int yShift = 0;
protected static class PermutationTooltipLineHandler extends ItemsTooltipLineHandler {
protected PositionedStack pStack = null;
public PermutationTooltipLineHandler(PositionedStack pStack, List<ItemStack> items) {
super(NEIClientUtils.translate("recipe.accepts"), items, false, 5);
this.pStack = pStack;
}
public static PermutationTooltipLineHandler getInstance(PositionedStack pStack) {
final ItemFilter filter = TemplateRecipeHandler.getItemFilter();
List<ItemStack> items = Arrays.asList(pStack.items).stream().filter(filter::matches)
.collect(Collectors.toCollection(ArrayList::new));
if (items.isEmpty()) {
items = Arrays.asList(pStack.items);
}
items = new ItemStackSet().addAll(items).keys();
if (items.size() > 1) {
return new PermutationTooltipLineHandler(pStack, items);
}
return null;
}
}
public static class ItemRecipeFilter implements IRecipeFilter {
public ItemFilter filter;
@@ -244,7 +215,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
guiRecipe.changePage(0);
} else {
final IRecipeFilter filter = new ItemRecipeFilter(GuiRecipe.searchField.getFilter());
List<Integer> filtered = searchHandler.getSearchResult(filter);
final List<Integer> filtered = searchHandler.getSearchResult(filter);
if (filtered == null) {
stop();
@@ -319,9 +290,9 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
this.firstGui = (GuiContainer) prevgui;
}
if (prevgui instanceof IGuiContainerOverlay) {
this.firstGui = ((IGuiContainerOverlay) prevgui).getFirstScreen();
this.firstGuiGeneral = ((IGuiContainerOverlay) prevgui).getFirstScreenGeneral();
if (prevgui instanceof IGuiContainerOverlay gui) {
this.firstGui = gui.getFirstScreen();
this.firstGuiGeneral = gui.getFirstScreenGeneral();
}
}
@@ -431,23 +402,21 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
if (handler == null) {
setRecipePage(recipetype);
} else {
updateOverlayButtons();
}
checkYShift();
final int rightButtonX = guiLeft + xSize - borderPadding - buttonWidth;
final int leftButtonX = guiLeft + borderPadding;
final int rightButtonX = guiLeft + xSize - BORDER_PADDING - BUTTON_WIDTH;
final int leftButtonX = guiLeft + BORDER_PADDING;
nexttype = new GuiNEIButton(0, leftButtonX, guiTop + 3, buttonWidth, buttonHeight, "<") {
nexttype = new GuiNEIButton(0, leftButtonX, guiTop + 3, BUTTON_WIDTH, BUTTON_HEIGHT, "<") {
@Override
public void mouseReleased(int mouseX, int mouseY) {
prevType();
}
};
prevtype = new GuiNEIButton(1, rightButtonX, guiTop + 3, buttonWidth, buttonHeight, ">") {
prevtype = new GuiNEIButton(1, rightButtonX, guiTop + 3, BUTTON_WIDTH, BUTTON_HEIGHT, ">") {
@Override
public void mouseReleased(int mouseX, int mouseY) {
@@ -455,14 +424,14 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
};
nextpage = new GuiNEIButton(2, leftButtonX, guiTop + 17, buttonWidth, buttonHeight, "<") {
nextpage = new GuiNEIButton(2, leftButtonX, guiTop + 17, BUTTON_WIDTH, BUTTON_HEIGHT, "<") {
@Override
public void mouseReleased(int mouseX, int mouseY) {
prevPage();
}
};
prevpage = new GuiNEIButton(3, rightButtonX, guiTop + 17, buttonWidth, buttonHeight, ">") {
prevpage = new GuiNEIButton(3, rightButtonX, guiTop + 17, BUTTON_WIDTH, BUTTON_HEIGHT, ">") {
@Override
public void mouseReleased(int mouseX, int mouseY) {
@@ -473,7 +442,8 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
toggleSearch.icon = new DrawableBuilder("nei:textures/nei_sprites.png", 0, 76, 10, 10).build();
this.buttonList.addAll(Arrays.asList(nexttype, prevtype, nextpage, prevpage));
this.overlayButtons = new GuiOverlayButton[0];
this.recipeButtons.clear();
this.recipePageCacheKey = "";
if (currenthandlers.size() == 1) {
nexttype.visible = false;
@@ -484,27 +454,36 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
refreshPage();
}
private void updateOverlayButtons() {
private void updateRecipePage() {
final List<Integer> indices = getRecipeIndices();
final String cacheKey = indices.isEmpty() ? ""
: handlerInfo.getHandlerName() + ":" + indices.get(0) + ":" + indices.get(indices.size() - 1);
if (isDirtyOverlayButtons(indices)) {
this.buttonList.removeIf(Arrays.asList(this.overlayButtons)::contains);
if (!cacheKey.equals(this.recipePageCacheKey)) {
this.recipePageCacheKey = cacheKey;
final int xOffset = (limitToOneRecipe ? 0 : guiLeft) + xSize - borderPadding;
final int yOffset = (limitToOneRecipe ? -buttonHeight : guiTop - 18) + getRecipePosition(0).y;
for (final int recipeIndex : indices) {
for (PositionedStack pStack : handler.original.getIngredientStacks(recipeIndex)) {
pStack.setPermutationToRender(pStack.getFilteredPermutations().get(0));
}
}
final int xOffset = (limitToOneRecipe ? 0 : guiLeft) + xSize - BORDER_PADDING;
final int yOffset = (limitToOneRecipe ? -BUTTON_HEIGHT : guiTop - 18) + getRefIndexPosition(0).y;
final int height = handlerInfo.getHeight() - yShift;
final UpdateOverlayButtonsEvent.Pre preEvent = new UpdateOverlayButtonsEvent.Pre(
final boolean showFavorites = NEIClientConfig.favoritesEnabled() && handlerInfo.getShowFavoritesButton();
final boolean showOverlay = handlerInfo.getShowOverlayButton();
final UpdateRecipeButtonsEvent.Pre preEvent = new UpdateRecipeButtonsEvent.Pre(
this,
xOffset,
yOffset,
height,
handlerInfo);
List<GuiOverlayButton> buttons = new ArrayList<>();
List<GuiRecipeButton> buttons = new ArrayList<>();
if (MinecraftForge.EVENT_BUS.post(preEvent)) {
buttons = preEvent.buttonList;
} else {
for (int refIndex = 0; refIndex < indices.size(); refIndex++) {
final int recipeIndex = indices.get(refIndex);
@@ -513,42 +492,49 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
continue;
}
buttons.add(
new GuiOverlayButton(
firstGui,
handler.original,
recipeIndex,
xOffset - buttonWidth,
yOffset + height * (refIndex + 1),
buttonWidth,
buttonHeight));
int x = xOffset - GuiRecipeButton.BUTTON_WIDTH;
int y = yOffset + height * (refIndex + 1);
if (showOverlay) {
buttons.add(
new GuiOverlayButton(
firstGui,
RecipeHandlerRef.of(handler.original, recipeIndex),
x,
y));
y -= GuiRecipeButton.BUTTON_HEIGHT + 1;
}
if (showFavorites) {
buttons.add(new GuiFavoriteButton(RecipeHandlerRef.of(handler.original, recipeIndex), x, y));
}
}
if (this.equals(this.mc.currentScreen)) {
UpdateOverlayButtonsEvent.Post postEvent = new UpdateOverlayButtonsEvent.Post(this, buttons);
UpdateRecipeButtonsEvent.Post postEvent = new UpdateRecipeButtonsEvent.Post(this, buttons);
MinecraftForge.EVENT_BUS.post(postEvent);
buttons = postEvent.buttonList;
}
}
this.overlayButtons = buttons.toArray(new GuiOverlayButton[buttons.size()]);
if (!showFavorites) {
buttons.removeIf(GuiFavoriteButton.class::isInstance);
}
if (!showOverlay) {
buttons.removeIf(GuiOverlayButton.class::isInstance);
}
/** compatibility with old format */
this.overlayButtons = buttons.stream().filter(GuiOverlayButton.class::isInstance)
.toArray(GuiOverlayButton[]::new);
this.buttonList.removeIf(this.recipeButtons::contains);
this.recipeButtons.clear();
this.recipeButtons.addAll(buttons);
this.buttonList.addAll(buttons);
}
}
private boolean isDirtyOverlayButtons(List<Integer> indices) {
if (this.overlayButtons.length == 0) {
return true;
}
for (GuiOverlayButton button : this.overlayButtons) {
if (button.handler != handler.original || !indices.contains(button.recipeIndex)) {
return true;
}
}
return false;
}
public static IRecipeFilter getRecipeListFilter() {
@@ -570,6 +556,10 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
return recipeFilter.filters.size() == 1 ? recipeFilter.filters.get(0) : recipeFilter;
}
public static ItemFilter getSearchItemFilter() {
return searchField.getFilter();
}
private void checkYShift() {
yShift = handlerInfo == null ? 0 : handlerInfo.getYShift();
}
@@ -596,11 +586,18 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
checkYShift();
}
public List<GuiButton> getOverlayButtons() {
return Collections.unmodifiableList(Arrays.asList(this.overlayButtons));
public List<GuiRecipeButton> getRecipeButtons() {
return Collections.unmodifiableList(this.recipeButtons);
}
public int openTargetRecipe(BookmarkRecipeId recipeId) {
public List<GuiButton> getOverlayButtons() {
return Collections.unmodifiableList(
Arrays.asList(
this.recipeButtons.stream().filter(GuiOverlayButton.class::isInstance)
.toArray(GuiButton[]::new)));
}
public int openTargetRecipe(RecipeId recipeId) {
int refIndex = -1;
int recipetype = 0;
@@ -611,13 +608,13 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
H localHandler = currenthandlers.get(j);
HandlerInfo localHandlerInfo = GuiRecipeTab.getHandlerInfo(localHandler);
if (localHandlerInfo.getHandlerName().equals(this.recipeId.handlerName)) {
if (localHandlerInfo.getHandlerName().equals(this.recipeId.getHandleName())) {
recipetype = j;
if (!this.recipeId.ingredients.isEmpty()) {
if (!this.recipeId.getIngredients().isEmpty()) {
refIndex = SearchRecipeHandler.findFirst(
localHandler,
(recipeIndex) -> this.recipeId
recipeIndex -> this.recipeId
.equalsIngredients(localHandler.getIngredientStacks(recipeIndex)));
}
@@ -631,49 +628,21 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
return refIndex;
}
public List<PositionedStack> getFocusedRecipeIngredients() {
List<Integer> indices = getRecipeIndices();
public Recipe getFocusedRecipe() {
final List<Integer> indices = getRecipeIndices();
for (int refIndex = 0; refIndex < indices.size(); refIndex++) {
final int recipeIndex = indices.get(refIndex);
if (recipeInFocus(refIndex, recipeIndex)) {
return handler.original.getIngredientStacks(recipeIndex);
return Recipe.of(handler.original, recipeIndex);
}
}
return null;
}
public int prepareFocusedRecipeResultStackSize(ItemStack stackover) {
List<Integer> indices = getRecipeIndices();
for (int refIndex = 0; refIndex < indices.size(); refIndex++) {
final int recipeIndex = indices.get(refIndex);
if (recipeInFocus(refIndex, recipeIndex)) {
final PositionedStack result = handler.original.getResultStack(recipeIndex);
int stackSize = 0;
if (result != null && StackInfo.equalItemAndNBT(result.item, stackover, true)) {
stackSize += result.item.stackSize;
}
final List<PositionedStack> stacks = handler.original.getOtherStacks(recipeIndex);
for (PositionedStack pStack : stacks) {
if (StackInfo.equalItemAndNBT(pStack.item, stackover, true)) {
stackSize += pStack.item.stackSize;
}
}
return stackSize;
}
}
return stackover.stackSize;
}
protected boolean recipeInFocus(int refIndex, int recipeIndex) {
final PositionedStack result = handler.original.getResultStack(recipeIndex);
if (result != null && isMouseOver(result, refIndex)) {
return true;
}
@@ -688,6 +657,15 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
return false;
}
public boolean isMouseOver(PositionedStack stack, int refIndex) {
Point p = getRefIndexPosition(refIndex);
Point mousepos = GuiDraw.getMousePosition();
Slot stackSlot = slotcontainer.getSlotWithStack(stack, p.x, p.y);
Slot mouseoverSlot = getSlotAtPosition(mousepos.x, mousepos.y);
return stackSlot == mouseoverSlot;
}
public String getHandlerName() {
return handlerInfo.getHandlerName();
}
@@ -700,7 +678,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
final int recipesPerPage = getRecipesPerPage();
final int minIndex = page * recipesPerPage;
final int maxIndex = Math.min(this.numRecipes(), (page + 1) * recipesPerPage);
final ArrayList<Integer> range = new ArrayList<>();
final List<Integer> range = new ArrayList<>();
for (int index = minIndex; index < maxIndex; index++) {
range.add(handler.ref(index));
@@ -744,7 +722,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
Point mouse = GuiDraw.getMousePosition();
for (GuiOverlayButton button : this.overlayButtons) {
for (GuiRecipeButton button : this.recipeButtons) {
if (button.contains(mouse.x, mouse.y)) {
button.lastKeyTyped(this, c, i);
}
@@ -806,9 +784,19 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
// handler-specific scroll behavior.
if (recipeTabs.mouseScrolled(scroll)) return;
for (int recipeIndex : getRecipeIndices()) {
if (handler.original.mouseScrolled(this, scroll, recipeIndex)) {
return;
try (CompatibilityHacks compatibilityHacks = new CompatibilityHacks()) {
Point mouse = GuiDraw.getMousePosition();
for (GuiRecipeButton button : this.recipeButtons) {
if (button.contains(mouse.x, mouse.y) && button.mouseScrolled(this, scroll)) {
return;
}
}
for (int recipeIndex : getRecipeIndices()) {
if (handler.original.mouseScrolled(this, scroll, recipeIndex)) {
return;
}
}
}
@@ -837,8 +825,17 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
@Override
public void updateScreen() {
super.updateScreen();
onUpdate();
}
public void onUpdate() {
handler.original.onUpdate();
refreshPage();
if (limitToOneRecipe) {
refreshSlots();
} else {
refreshPage();
}
}
@Override
@@ -849,7 +846,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
currenttip = handler.original.handleTooltip(this, currenttip, recipeIndex);
}
for (GuiOverlayButton button : this.overlayButtons) {
for (GuiRecipeButton button : this.recipeButtons) {
if (button.contains(mousex, mousey)) {
currenttip = button.handleTooltip(this, currenttip);
}
@@ -884,36 +881,41 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
}
}
if (NEIClientConfig.showCycledIngredientsTooltip()) {
PositionedStack focused = null;
if (NEIClientConfig.showCycledIngredientsTooltip() && itemstack != null) {
PositionedStack hovered = null;
for (int refIndex = 0; refIndex < indices.size(); refIndex++) {
outer: for (int refIndex = 0; refIndex < indices.size(); refIndex++) {
final int recipeIndex = indices.get(refIndex);
if (itemstack != null && focused == null) {
final List<PositionedStack> stacks = handler.original.getIngredientStacks(recipeIndex);
List<List<PositionedStack>> stackGroups = Arrays.asList(
handler.original.getIngredientStacks(recipeIndex),
handler.original.getOtherStacks(recipeIndex));
for (PositionedStack pStack : stacks) {
for (List<PositionedStack> group : stackGroups) {
for (PositionedStack pStack : group) {
if (isMouseOver(pStack, refIndex)) {
focused = pStack;
break;
hovered = pStack;
break outer;
}
}
}
}
if (focused == null || focused.items.length <= 1) {
this.permutationTooltipLineHandler = null;
} else if (this.permutationTooltipLineHandler == null
|| this.permutationTooltipLineHandler.pStack != focused) {
this.permutationTooltipLineHandler = PermutationTooltipLineHandler.getInstance(focused);
if (hovered == null || hovered.items.length <= 1) {
this.acceptsFollowingTooltipLineHandler = null;
} else if (this.acceptsFollowingTooltipLineHandler == null
|| this.acceptsFollowingTooltipLineHandler.tooltipGUID != hovered) {
this.acceptsFollowingTooltipLineHandler = AcceptsFollowingTooltipLineHandler
.of(hovered, hovered.getFilteredPermutations(), hovered.item);
}
} else if (this.permutationTooltipLineHandler != null) {
this.permutationTooltipLineHandler = null;
} else if (this.acceptsFollowingTooltipLineHandler != null) {
this.acceptsFollowingTooltipLineHandler = null;
}
if (this.permutationTooltipLineHandler != null) {
currenttip.add(GuiDraw.TOOLTIP_HANDLER + GuiDraw.getTipLineId(this.permutationTooltipLineHandler));
if (this.acceptsFollowingTooltipLineHandler != null) {
this.acceptsFollowingTooltipLineHandler
.setActiveStack(((PositionedStack) this.acceptsFollowingTooltipLineHandler.tooltipGUID).item);
currenttip.add(GuiDraw.TOOLTIP_HANDLER + GuiDraw.getTipLineId(this.acceptsFollowingTooltipLineHandler));
}
return currenttip;
@@ -923,13 +925,21 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
public Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
try (CompatibilityHacks compatibilityHacks = new CompatibilityHacks()) {
for (GuiOverlayButton button : this.overlayButtons) {
for (GuiRecipeButton button : this.recipeButtons) {
if (button.contains(mousex, mousey)) {
hotkeys = button.handleHotkeys(gui, mousex, mousey, hotkeys);
}
}
}
if (this.acceptsFollowingTooltipLineHandler != null) {
hotkeys.put(
NEIClientUtils.getKeyName(
NEIClientUtils.SHIFT_HASH,
NEIMouseUtils.MOUSE_BTN_NONE + NEIMouseUtils.MOUSE_SCROLL),
NEIClientUtils.translate("recipe.accepts.scroll"));
}
return hotkeys;
}
@@ -954,26 +964,6 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
setRecipePage(--recipetype);
}
protected void overlayRecipe(int recipeIndex, boolean shift) {
if (handler == null || !handler.original.hasOverlay(firstGui, firstGui.inventorySlots, recipeIndex)) {
return;
}
final boolean requireShiftForOverlayRecipe = NEIClientConfig.requireShiftForOverlayRecipe();
final IOverlayHandler overlayHandler = handler.original.getOverlayHandler(firstGui, recipeIndex);
final IRecipeOverlayRenderer renderer = handler.original.getOverlayRenderer(firstGui, recipeIndex);
if (renderer == null || !requireShiftForOverlayRecipe || shift) {
if (overlayHandler != null) {
overlayHandler
.overlayRecipe(firstGui, handler.original, recipeIndex, !requireShiftForOverlayRecipe || shift);
}
} else {
LayoutManager.overlayRenderer = renderer;
}
}
protected void changePage(int shift) {
final int recipesPerPage = getRecipesPerPage();
final int numRecipes = this.numRecipes();
@@ -989,7 +979,6 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
public void refreshPage() {
changePage(0);
refreshSlots();
final int recipesPerPage = getRecipesPerPage();
final boolean multiplepages = this.numRecipes() > recipesPerPage;
final int numRecipes = Math.min(this.numRecipes() - (page * recipesPerPage), recipesPerPage);
@@ -1003,18 +992,19 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
if (!limitToOneRecipe) {
RecipeCatalysts.updatePosition(ySize - BG_TOP_HEIGHT - (GuiRecipeCatalyst.fullBorder * 2));
toggleSearch.w = toggleSearch.h = 12;
toggleSearch.x = borderPadding + buttonWidth;
toggleSearch.x = BORDER_PADDING + BUTTON_WIDTH;
toggleSearch.y = 17;
searchField.y = 16;
searchField.x = borderPadding + buttonWidth + toggleSearch.w - 1;
searchField.w = xSize - (borderPadding + buttonWidth) * 2 + 1 - toggleSearch.w - 45;
searchField.x = BORDER_PADDING + BUTTON_WIDTH + toggleSearch.w - 1;
searchField.w = xSize - (BORDER_PADDING + BUTTON_WIDTH) * 2 + 1 - toggleSearch.w - 45;
searchField.h = 14;
}
nextpage.enabled = prevpage.enabled = multiplepages;
updateOverlayButtons();
updateRecipePage();
refreshSlots();
recipeTabs.refreshPage();
}
@@ -1024,7 +1014,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
for (int refIndex = 0; refIndex < indices.size(); refIndex++) {
int recipeIndex = indices.get(refIndex);
Point p = getRecipePosition(refIndex);
Point p = getRefIndexPosition(refIndex);
// Legacy recipe handlers only expect a single paging widget at the top of the recipe screen, in contrast,
// GTNH NEI moves the recipe paging widget from the bottom to the top, which means said legacy handlers will
// position item slots 16px too high in the screen.
@@ -1034,18 +1024,21 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
TemplateRecipeHandler.disableCycledIngredients = false;
List<PositionedStack> stacks = handler.original.getIngredientStacks(recipeIndex);
for (PositionedStack stack : stacks) slotcontainer.addSlot(stack, p.x, p.y);
for (PositionedStack stack : handler.original.getIngredientStacks(recipeIndex)) {
slotcontainer.addSlot(stack, p.x, p.y);
}
stacks = handler.original.getOtherStacks(recipeIndex);
for (PositionedStack stack : stacks) slotcontainer.addSlot(stack, p.x, p.y);
for (PositionedStack stack : handler.original.getOtherStacks(recipeIndex)) {
slotcontainer.addSlot(stack, p.x, p.y);
}
PositionedStack result = handler.original.getResultStack(recipeIndex);
if (result != null) slotcontainer.addSlot(result, p.x, p.y);
if (result != null) {
slotcontainer.addSlot(result, p.x, p.y);
}
if (!limitToOneRecipe) {
List<PositionedStack> catalysts = RecipeCatalysts.getRecipeCatalysts(handler.original);
for (PositionedStack catalyst : catalysts) {
for (PositionedStack catalyst : RecipeCatalysts.getRecipeCatalysts(handler.original)) {
int xOffset = -GuiRecipeCatalyst.ingredientSize + 1;
int yOffset = BG_TOP_Y + GuiRecipeCatalyst.fullBorder;
slotcontainer.addSlot(catalyst, xOffset, yOffset);
@@ -1100,21 +1093,12 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
handler.original.drawForeground(recipeIndex);
if (limitToOneRecipe) {
GuiOverlayButton overlayButton = Arrays.asList(this.overlayButtons).stream()
.filter(b -> b.recipeIndex == recipeIndex).findAny().orElse(null);
GuiOverlayButton overlayButton = (GuiOverlayButton) this.recipeButtons.stream()
.filter(b -> b instanceof GuiOverlayButton && b.handlerRef.recipeIndex == recipeIndex)
.findAny().orElse(null);
if (overlayButton != null && overlayButton.enabled) {
final String overlayKeyName = NEIClientConfig.getKeyName("gui.overlay_use");
if (overlayKeyName != null) {
fontRendererObj.drawStringWithShadow(
EnumChatFormatting.ITALIC + overlayKeyName,
xSize - borderPadding - fontRendererObj.getStringWidth(overlayKeyName) - 10,
handlerInfo.getHeight() - fontRendererObj.FONT_HEIGHT,
0xffffff);
}
overlayButton.drawItemPresenceOverlay();
overlayButton.drawItemOverlay();
}
}
@@ -1126,11 +1110,14 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
GL11.glPushMatrix();
GL11.glTranslatef(5, ySkip + yShift, 0);
if (!limitToOneRecipe && NEIClientConfig.itemPresenceOverlay() > 0) {
for (GuiOverlayButton button : this.overlayButtons) {
if (!limitToOneRecipe) {
for (GuiRecipeButton button : this.recipeButtons) {
if (button.contains(mouseX, mouseY)) {
GL11.glTranslatef(0, handlerInfo.getHeight() * indices.indexOf(button.recipeIndex), 0);
button.drawItemPresenceOverlay();
GL11.glTranslatef(
0,
handlerInfo.getHeight() * indices.indexOf(button.handlerRef.recipeIndex),
0);
button.drawItemOverlay();
break;
}
}
@@ -1150,16 +1137,16 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
if (NEIClientConfig.areJEIStyleTabsVisible() && !limitToOneRecipe) {
drawRect(
guiLeft + borderPadding + buttonWidth - 1,
guiLeft + BORDER_PADDING + BUTTON_WIDTH - 1,
nexttype.yPosition,
guiLeft + xSize - borderPadding - buttonWidth,
nexttype.yPosition + buttonHeight,
guiLeft + xSize - BORDER_PADDING - BUTTON_WIDTH,
nexttype.yPosition + BUTTON_HEIGHT,
0x30000000);
drawRect(
guiLeft + borderPadding + buttonWidth - 1,
guiLeft + BORDER_PADDING + BUTTON_WIDTH - 1,
nextpage.yPosition,
guiLeft + xSize - borderPadding - buttonWidth,
nextpage.yPosition + buttonHeight,
guiLeft + xSize - BORDER_PADDING - BUTTON_WIDTH,
nextpage.yPosition + BUTTON_HEIGHT,
0x30000000);
RenderHelper.enableGUIStandardItemLighting();
@@ -1232,15 +1219,6 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
return firstGuiGeneral;
}
public boolean isMouseOver(PositionedStack stack, int refIndex) {
Point p = getRecipePosition(refIndex);
Point mousepos = GuiDraw.getMousePosition();
Slot stackSlot = slotcontainer.getSlotWithStack(stack, p.x, p.y);
Slot mouseoverSlot = getSlotAtPosition(mousepos.x, mousepos.y);
return stackSlot == mouseoverSlot;
}
private int getRecipesPerPage() {
return limitToOneRecipe ? 1 : getRecipesPerPage(handlerInfo);
}
@@ -1249,7 +1227,7 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
if (handlerInfo != null) {
return Math.max(
Math.min(
((ySize - (buttonHeight * 3)) / handlerInfo.getHeight()),
((ySize - (BUTTON_HEIGHT * 3)) / handlerInfo.getHeight()),
handlerInfo.getMaxRecipesPerPage()),
1);
} else if (handler != null) {
@@ -1258,10 +1236,14 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
return 1;
}
public Point getRecipePosition(int refIndex) {
// Legacy recipe handlers using the height hack might use getRecipePosition in combination with guiTop/height to
// position certain elements like tooltips. Since guiTop is moved down by 16px during height hacking, we need to
// reduce the vertical shift here to 16px instead of 32px.
public Point getRecipePosition(int recipe) {
return getRefIndexPosition(getRecipeIndices().indexOf(recipe));
}
protected Point getRefIndexPosition(int refIndex) {
// Legacy recipe handlers using the height hack might use getRefIndexPosition in combination with guiTop/height
// to position certain elements like tooltips. Since guiTop is moved down by 16px during height hacking, we need
// to reduce the vertical shift here to 16px instead of 32px.
return new Point(
5,
(isHeightHackApplied ? 16 : 32) - (limitToOneRecipe ? 25 : 0)
@@ -1303,16 +1285,14 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
return area.intersects(x, y, w, h);
}
protected static BookmarkRecipeId getCurrentRecipeId(GuiScreen gui) {
protected static RecipeId getCurrentRecipeId(GuiScreen gui) {
if (gui instanceof GuiRecipe && ((GuiRecipe<?>) gui).handler.numRecipes() > 0) {
final GuiRecipe<?> gRecipe = (GuiRecipe<?>) gui;
if ((gui instanceof GuiRecipe<?>gRecipe) && gRecipe.handler.numRecipes() > 0) {
final List<Integer> indices = gRecipe.getRecipeIndices();
final int curRecipe = indices.isEmpty() ? 0 : indices.get(0);
final Recipe recipe = Recipe.of(gRecipe.handler.original, curRecipe);
return new BookmarkRecipeId(
gRecipe.handlerInfo.getHandlerName(),
gRecipe.handler.original.getIngredientStacks(curRecipe));
return recipe != null ? recipe.getRecipeId() : null;
}
return null;
@@ -0,0 +1,80 @@
package codechicken.nei.recipe;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraftforge.client.event.GuiScreenEvent;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.GuiNEIButton;
import cpw.mods.fml.common.eventhandler.Cancelable;
public abstract class GuiRecipeButton extends GuiNEIButton {
public static class UpdateRecipeButtonsEvent extends GuiScreenEvent {
public List<GuiRecipeButton> buttonList;
public UpdateRecipeButtonsEvent(GuiRecipe<?> gui, List<GuiRecipeButton> buttonList) {
super(gui);
this.buttonList = new ArrayList<>(buttonList);
}
@Cancelable
public static class Pre extends UpdateRecipeButtonsEvent {
public int xOffset;
public int yOffset;
public int height;
public HandlerInfo handlerInfo;
public Pre(GuiRecipe<?> gui, int xOffset, int yOffset, int height, HandlerInfo handlerInfo) {
super(gui, new ArrayList<>());
this.xOffset = xOffset;
this.yOffset = yOffset;
this.height = height;
this.handlerInfo = handlerInfo;
}
}
public static class Post extends UpdateRecipeButtonsEvent {
public Post(GuiRecipe<?> gui, List<GuiRecipeButton> buttonList) {
super(gui, buttonList);
}
}
}
public static final int BUTTON_WIDTH = 12;
public static final int BUTTON_HEIGHT = 12;
public final RecipeHandlerRef handlerRef;
protected GuiRecipeButton(RecipeHandlerRef point, int x, int y, int buttonId, String label) {
super(buttonId, x, y, BUTTON_WIDTH, BUTTON_HEIGHT, label);
this.handlerRef = point;
}
abstract List<String> handleTooltip(GuiRecipe<?> gui, List<String> currenttip);
abstract Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys);
abstract void lastKeyTyped(GuiRecipe<?> gui, char keyChar, int keyID);
abstract void drawItemOverlay();
public boolean mouseScrolled(GuiRecipe<?> gui, int scroll) {
return false;
}
public Rectangle4i bounds() {
return new Rectangle4i(this.xPosition, this.yPosition, this.width, this.height);
}
public boolean contains(int mx, int my) {
return bounds().contains(mx, my);
}
}
@@ -10,6 +10,7 @@ import net.minecraft.item.ItemStack;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.stackinfo.GTFluidStackStringifyHandler;
public class GuiUsageRecipe extends GuiRecipe<IUsageHandler> {
@@ -30,7 +31,7 @@ public class GuiUsageRecipe extends GuiRecipe<IUsageHandler> {
if (!handlers.isEmpty()) {
final Minecraft mc = NEIClientUtils.mc();
final BookmarkRecipeId recipeId = getCurrentRecipeId(mc.currentScreen);
final RecipeId recipeId = getCurrentRecipeId(mc.currentScreen);
final GuiUsageRecipe gui = new GuiUsageRecipe(handlers);
mc.displayGuiScreen(gui);
@@ -28,6 +28,8 @@ public class HandlerInfo {
private int height = DEFAULT_HEIGHT;
private int width = DEFAULT_WIDTH;
private int maxRecipesPerPage = DEFAULT_MAX_PER_PAGE;
private boolean showFavoritesButton = true;
private boolean showOverlayButton = true;
private ItemStack itemStack = null;
private DrawableResource image = null;
@@ -112,6 +114,22 @@ public class HandlerInfo {
this.yShift = yShift;
}
public boolean getShowFavoritesButton() {
return this.showFavoritesButton;
}
public void setShowFavoritesButton(boolean showFavoritesButton) {
this.showFavoritesButton = showFavoritesButton;
}
public boolean getShowOverlayButton() {
return this.showOverlayButton;
}
public void setShowOverlayButton(boolean showOverlayButton) {
this.showOverlayButton = showOverlayButton;
}
public static class Builder {
private final HandlerInfo info;
@@ -17,8 +17,9 @@ class ItemsHistoryHandler implements ICraftingHandler, IUsageHandler {
@Override
public ICraftingHandler getRecipeHandler(String outputId, Object... results) {
if (NEIClientConfig.showHistoryPanelWidget() && "item".equals(outputId) && results[0] instanceof ItemStack) {
ItemPanels.itemPanel.historyPanel.addItem((ItemStack) results[0]);
if (NEIClientConfig.showHistoryPanelWidget() && "item".equals(outputId)
&& results[0] instanceof ItemStack stack) {
ItemPanels.itemPanel.historyPanel.addItem(stack);
}
return null;
@@ -27,8 +28,9 @@ class ItemsHistoryHandler implements ICraftingHandler, IUsageHandler {
@Override
public IUsageHandler getUsageHandler(String inputId, Object... ingredients) {
if (NEIClientConfig.showHistoryPanelWidget() && "item".equals(inputId) && ingredients[0] instanceof ItemStack) {
ItemPanels.itemPanel.historyPanel.addItem((ItemStack) ingredients[0]);
if (NEIClientConfig.showHistoryPanelWidget() && "item".equals(inputId)
&& ingredients[0] instanceof ItemStack stack) {
ItemPanels.itemPanel.historyPanel.addItem(stack);
}
return null;
@@ -0,0 +1,456 @@
package codechicken.nei.recipe;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fluids.FluidContainerRegistry;
import com.google.common.base.Objects;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import codechicken.nei.NEIServerUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.util.NBTJson;
public class Recipe {
public static class RecipeId {
private static final String KEY_HANDLER_NAME = "handlerName";
private static final String KEY_INGREDIENTS = "ingredients";
private static final String KEY_RESULT = "result";
private final String handlerName;
private final List<ItemStack> ingredients;
private final ItemStack result;
protected RecipeId(ItemStack result, String handlerName, List<ItemStack> ingredients) {
this.result = result != null ? StackInfo.withAmount(result, 0) : null;
this.handlerName = handlerName;
this.ingredients = ingredients;
}
public static RecipeId of(Object result, String handlerName, Iterable<?> ingredients) {
return new RecipeId(extractItem(result), handlerName, extractItems(ingredients));
}
public static RecipeId of(JsonObject json) {
String handlerName = null;
List<ItemStack> ingredients = new ArrayList<>();
ItemStack result = null;
if (json.get(KEY_HANDLER_NAME) != null) {
handlerName = json.get(KEY_HANDLER_NAME).getAsString();
}
if (json.get(KEY_INGREDIENTS) != null) {
ingredients = convertJsonArrayToItems(json.getAsJsonArray(KEY_INGREDIENTS));
}
if (json.get(KEY_RESULT) != null) {
result = StackInfo.loadFromNBT((NBTTagCompound) NBTJson.toNbt(json.getAsJsonObject(KEY_RESULT)));
}
return new RecipeId(result, handlerName, ingredients);
}
public String getHandleName() {
return this.handlerName;
}
public ItemStack getResult() {
return this.result;
}
public List<ItemStack> getIngredients() {
return new ArrayList<>(this.ingredients);
}
protected static List<ItemStack> extractItems(Iterable<?> items) {
final List<ItemStack> list = new ArrayList<>();
for (Object item : items) {
ItemStack stack = extractItem(item);
if (stack != null) {
list.add(stack.copy());
}
}
return list;
}
protected static ItemStack extractItem(Object item) {
if (item instanceof PositionedStack positionedStack) {
item = StackInfo.getItemStackWithMinimumDamage(positionedStack.items);
}
if (item instanceof RecipeIngredient ingr) {
item = StackInfo.getItemStackWithMinimumDamage(ingr.getPermutations().toArray(new ItemStack[0]));
}
if (item instanceof NBTTagCompound nbTag) {
return StackInfo.loadFromNBT(nbTag);
}
if (item instanceof ItemStack stack) {
return stack;
}
return null;
}
public boolean equalsIngredients(List<PositionedStack> stacks) {
if (ingredients.size() != stacks.size()) {
return false;
}
for (int index = 0; index < stacks.size(); index++) {
if (!stacks.get(index).containsWithNBT(ingredients.get(index))) {
return false;
}
}
return true;
}
public JsonObject toJsonObject() {
final JsonObject json = new JsonObject();
if (this.handlerName != null && !"".equals(this.handlerName)) {
json.add(KEY_HANDLER_NAME, new JsonPrimitive(this.handlerName));
json.add(KEY_INGREDIENTS, convertItemsToJsonArray(this.ingredients));
if (this.result != null) { // old format without result
json.add(KEY_RESULT, NBTJson.toJsonObject(StackInfo.itemStackToNBT(this.result)));
}
}
return json;
}
protected JsonArray convertItemsToJsonArray(List<ItemStack> items) {
final JsonArray arr = new JsonArray();
for (ItemStack nbTag : items) {
arr.add(NBTJson.toJsonObject(StackInfo.itemStackToNBT(nbTag)));
}
return arr;
}
protected static List<ItemStack> convertJsonArrayToItems(JsonArray arr) {
final List<ItemStack> items = new ArrayList<>();
for (JsonElement elem : arr) {
final ItemStack nbt = StackInfo.loadFromNBT((NBTTagCompound) NBTJson.toNbt(elem));
if (nbt == null) {
return new ArrayList<>();
}
items.add(nbt);
}
return items;
}
@Override
public int hashCode() {
return Objects.hashCode(this.handlerName, this.ingredients.size());
}
@Override
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof RecipeId anRecipeId) {
if (!this.handlerName.equals(anRecipeId.handlerName)) {
return false;
}
if (this.ingredients.size() != anRecipeId.ingredients.size()) {
return false;
}
if (this.result != null && anRecipeId.result != null
&& !StackInfo.equalItemAndNBT(this.result, anRecipeId.result, true)) {
return false;
}
for (int idx = 0; idx < this.ingredients.size(); idx++) {
if (!StackInfo.equalItemAndNBT(this.ingredients.get(idx), anRecipeId.ingredients.get(idx), true)) {
return false;
}
}
return true;
}
return false;
}
public RecipeId copy() {
return new RecipeId(this.result, this.handlerName, this.ingredients);
}
}
public static class RecipeIngredient {
protected final ItemStack[] items;
protected int activeIndex = 0;
protected int amount = 0;
protected int relx;
protected int rely;
public RecipeIngredient(int relx, int rely, List<ItemStack> items, int activeIndex) {
this.items = items.stream().map(ItemStack::copy).toArray(size -> new ItemStack[size]);
this.amount = StackInfo.getAmount(this.items[activeIndex]);
this.activeIndex = activeIndex;
this.relx = relx;
this.rely = rely;
}
public static RecipeIngredient of(PositionedStack positionedStack) {
final List<ItemStack> stacks = Arrays.asList(positionedStack.items).stream()
.filter(item -> !ItemInfo.isHidden(item)).collect(Collectors.toList());
int activeIndex = 0;
if (stacks.isEmpty()) {
stacks.addAll(Arrays.asList(positionedStack.items));
}
for (int i = 0; i < stacks.size(); i++) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(positionedStack.item, stacks.get(i))) {
activeIndex = i;
break;
}
}
return of(positionedStack.relx, positionedStack.rely, stacks, activeIndex);
}
public static RecipeIngredient of(int relx, int rely, List<ItemStack> stacks, int activeIndex) {
return new RecipeIngredient(relx, rely, stacks, activeIndex);
}
public int getAmount() {
return this.amount;
}
public ItemStack getItemStack() {
return this.items[this.activeIndex];
}
public void setActiveIndex(int activeIndex) {
this.activeIndex = Math.max(0, Math.min(activeIndex, this.items.length - 1));
}
public boolean contains(ItemStack stackA) {
return getPermutations().stream().anyMatch(stackB -> StackInfo.equalItemAndNBT(stackA, stackB, true));
}
public List<ItemStack> getPermutations() {
return Arrays.asList(this.items);
}
public RecipeIngredient setAmount(int amount) {
for (int index = 0; index < this.items.length; index++) {
this.items[index] = StackInfo.withAmount(this.items[index], amount);
}
return this;
}
public RecipeIngredient copy() {
return new RecipeIngredient(
this.relx,
this.rely,
getPermutations().stream().map(ItemStack::copy).collect(Collectors.toList()),
this.activeIndex);
}
}
private final String handlerName;
private final RecipeIngredient[] results;
private final RecipeIngredient[] ingredients;
private RecipeId recipeId = null;
private Recipe(String handlerName, List<RecipeIngredient> ingredients, List<RecipeIngredient> results) {
this.handlerName = handlerName;
this.ingredients = ingredients.toArray(new RecipeIngredient[ingredients.size()]);
this.results = results.toArray(new RecipeIngredient[results.size()]);
}
public static Recipe of(IRecipeHandler handler, int recipeIndex) {
final String handlerName = GuiRecipeTab.getHandlerInfo(handler).getHandlerName();
final List<RecipeIngredient> ingredients = new ArrayList<>();
final List<RecipeIngredient> results = new ArrayList<>();
for (PositionedStack positionedStack : handler.getIngredientStacks(recipeIndex)) {
ingredients.add(RecipeIngredient.of(positionedStack));
}
if (handler.getResultStack(recipeIndex) != null) {
results.add(RecipeIngredient.of(handler.getResultStack(recipeIndex)));
} else {
for (PositionedStack positionedStack : handler.getOtherStacks(recipeIndex)) {
results.add(RecipeIngredient.of(positionedStack));
}
}
return new Recipe(handlerName, ingredients, results);
}
public static Recipe of(List<?> results, String handlerName, List<?> ingredients) {
return new Recipe(handlerName, extractItems(ingredients), extractItems(results));
}
public static Recipe of(RecipeHandlerRef handlerRef) {
return Recipe.of(handlerRef.handler, handlerRef.recipeIndex);
}
public static Recipe of(RecipeId recipeId) {
if (recipeId == null) {
return null;
}
final RecipeHandlerRef handlerRef = RecipeHandlerRef.of(recipeId);
if (handlerRef != null) {
return Recipe.of(handlerRef);
}
return null;
}
protected static List<RecipeIngredient> extractItems(List<?> items) {
final List<RecipeIngredient> list = new ArrayList<>();
for (Object item : items) {
RecipeIngredient ingr = extractItem(item);
if (ingr != null) {
list.add(ingr);
}
}
return list;
}
protected static RecipeIngredient extractItem(Object item) {
if (item instanceof PositionedStack positionedStack) {
return RecipeIngredient.of(positionedStack);
}
if (item instanceof NBTTagCompound nbTag) {
item = StackInfo.loadFromNBT(nbTag);
}
if (item instanceof ItemStack stack) {
return RecipeIngredient.of(0, 0, Arrays.asList(stack), 0);
}
if (item instanceof RecipeIngredient ingr) {
return ingr.copy();
}
return null;
}
public String getHandlerName() {
return this.handlerName;
}
public List<RecipeIngredient> getResults() {
return Arrays.asList(this.results);
}
public List<RecipeIngredient> getIngredients() {
return Arrays.asList(this.ingredients);
}
public ItemStack getResult() {
return getResult(null);
}
public ItemStack getResult(ItemStack stack) {
if (this.results.length == 0) {
return null;
}
if (stack == null && this.results.length > 1) {
for (RecipeIngredient ingr : this.results) {
if (!FluidContainerRegistry.isContainer(ingr.getItemStack())
|| StackInfo.getFluid(ingr.getItemStack()) != null) {
stack = ingr.getItemStack();
break;
}
}
}
if (stack == null) {
stack = this.results[0].getItemStack();
}
int stackSize = 0;
for (RecipeIngredient result : this.results) {
if (result.contains(stack)) {
stackSize += result.getAmount();
}
}
return StackInfo.withAmount(stack, stackSize);
}
public RecipeId getRecipeId() {
if (this.recipeId == null) {
this.recipeId = RecipeId.of(getResult(), this.handlerName, getIngredients());
}
return this.recipeId;
}
public void setCustomRecipeId(RecipeId recipeId) {
this.recipeId = recipeId;
}
public Recipe copy() {
final List<RecipeIngredient> ingredients = new ArrayList<>();
final List<RecipeIngredient> results = new ArrayList<>();
for (RecipeIngredient ingr : this.ingredients) {
ingredients.add(ingr.copy());
}
for (RecipeIngredient res : this.results) {
results.add(res.copy());
}
Recipe recipe = new Recipe(this.handlerName, ingredients, results);
recipe.recipeId = this.recipeId;
return recipe;
}
}
@@ -0,0 +1,202 @@
package codechicken.nei.recipe;
import java.util.Collections;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import codechicken.nei.LRUCache;
import codechicken.nei.LayoutManager;
import codechicken.nei.api.IOverlayHandler;
import codechicken.nei.api.IRecipeOverlayRenderer;
import codechicken.nei.recipe.GuiOverlayButton.ItemOverlayState;
import codechicken.nei.recipe.Recipe.RecipeId;
public class RecipeHandlerRef {
private static final LRUCache<Class<?>, Boolean> transferAlghoritmCache = new LRUCache<>(200);
private static final LRUCache<RecipeId, RecipeHandlerRef> recipeRefCache = new LRUCache<>(200);
public final IRecipeHandler handler;
public final int recipeIndex;
private RecipeHandlerRef(IRecipeHandler handler, int recipeIndex) {
this.handler = handler;
this.recipeIndex = recipeIndex;
}
public static RecipeHandlerRef of(IRecipeHandler handler, int recipeIndex) {
return new RecipeHandlerRef(handler, recipeIndex);
}
public static RecipeHandlerRef of(RecipeId recipeId) {
if (recipeId.getResult() != null && !recipeId.getIngredients().isEmpty()) {
return recipeRefCache.computeIfAbsent(recipeId, ri -> {
final List<ICraftingHandler> handlers = GuiCraftingRecipe
.getCraftingHandlers("recipeId", recipeId.getResult(), recipeId);
for (ICraftingHandler handler : handlers) {
int refIndex = SearchRecipeHandler.findFirst(
handler,
recipeIndex -> recipeId.equalsIngredients(handler.getIngredientStacks(recipeIndex)));
if (refIndex >= 0) {
return new RecipeHandlerRef(handler, refIndex);
}
}
return null;
});
}
return null;
}
private GuiContainer prepareGui(GuiContainer firstGui) {
if (firstGui instanceof GuiRecipe gui) {
firstGui = gui.firstGui;
}
return firstGui != null && firstGui.inventorySlots != null ? firstGui : null;
}
public IOverlayHandler getOverlayHandler(GuiContainer gui) {
final GuiContainer firstGui = prepareGui(gui);
if (firstGui != null && this.handler.hasOverlay(firstGui, firstGui.inventorySlots, this.recipeIndex)) {
return this.handler.getOverlayHandler(firstGui, this.recipeIndex);
}
return null;
}
public boolean canFillCraftingGrid(GuiContainer gui) {
final IOverlayHandler overlayHandler = getOverlayHandler(gui);
if (overlayHandler != null) {
return overlayHandler.canFillCraftingGrid(prepareGui(gui), this.handler, this.recipeIndex);
}
return false;
}
public boolean canCraft(GuiContainer gui) {
final IOverlayHandler overlayHandler = getOverlayHandler(gui);
if (overlayHandler != null && allowedTransferAlghoritm(gui)) {
return overlayHandler.canCraft(prepareGui(gui), this.handler, this.recipeIndex);
}
return false;
}
public List<ItemOverlayState> getPresenceOverlay(GuiContainer gui) {
final IOverlayHandler overlayHandler = getOverlayHandler(gui);
if (overlayHandler != null) {
return overlayHandler.presenceOverlay(prepareGui(gui), this.handler, this.recipeIndex);
}
return Collections.emptyList();
}
public void fillCraftingGrid(GuiContainer gui, int multiplier) {
final IOverlayHandler overlayHandler = getOverlayHandler(gui);
if (overlayHandler != null) {
final GuiContainer firstGui = prepareGui(gui);
if (!firstGui.equals(firstGui.mc.currentScreen)) {
firstGui.mc.displayGuiScreen(firstGui);
}
if (!allowedTransferAlghoritm(gui)) {
overlayHandler.overlayRecipe(firstGui, this.handler, this.recipeIndex, multiplier != 1);
} else {
overlayHandler.transferRecipe(firstGui, this.handler, this.recipeIndex, multiplier);
}
}
}
public boolean craft(GuiContainer gui, int multiplier) {
final GuiContainer firstGui = prepareGui(gui);
final IOverlayHandler overlayHandler = getOverlayHandler(firstGui);
if (overlayHandler != null && overlayHandler.canCraft(firstGui, this.handler, this.recipeIndex)) {
if (!firstGui.equals(firstGui.mc.currentScreen)) {
firstGui.mc.displayGuiScreen(firstGui);
}
return overlayHandler.craft(firstGui, this.handler, this.recipeIndex, multiplier);
}
return false;
}
public boolean allowedTransferAlghoritm(GuiContainer gui) {
final IOverlayHandler overlayHandler = getOverlayHandler(gui);
if (overlayHandler == null) {
return false;
}
return transferAlghoritmCache.computeIfAbsent(overlayHandler.getClass(), clazz -> {
try {
if (overlayHandler instanceof DefaultOverlayHandler) {
final Class<?> overlayRecipeClazz = overlayHandler.getClass()
.getMethod(
"overlayRecipe",
GuiContainer.class,
IRecipeHandler.class,
int.class,
boolean.class)
.getDeclaringClass();
if (overlayRecipeClazz.equals(DefaultOverlayHandler.class)) {
return true;
}
}
return !overlayHandler.getClass()
.getMethod("transferRecipe", GuiContainer.class, IRecipeHandler.class, int.class, int.class)
.isDefault();
} catch (NoSuchMethodException e) {}
return false;
});
}
public IRecipeOverlayRenderer getRecipeOverlayRenderer(GuiContainer gui) {
final GuiContainer firstGui = prepareGui(gui);
if (firstGui != null && this.handler.hasOverlay(firstGui, firstGui.inventorySlots, this.recipeIndex)) {
return this.handler.getOverlayRenderer(firstGui, this.recipeIndex);
}
return null;
}
public boolean canUseOverlayRenderer(GuiContainer gui) {
return getRecipeOverlayRenderer(gui) != null;
}
public void useOverlayRenderer(GuiContainer gui) {
final IRecipeOverlayRenderer renderer = getRecipeOverlayRenderer(gui);
if (renderer != null) {
final GuiContainer firstGui = prepareGui(gui);
if (!firstGui.equals(firstGui.mc.currentScreen)) {
firstGui.mc.displayGuiScreen(firstGui);
}
LayoutManager.overlayRenderer = renderer;
}
}
}
@@ -29,9 +29,10 @@ public class RecipeInfo {
@Override
public boolean equals(Object obj) {
if (!(obj instanceof OverlayKey)) return false;
OverlayKey key = (OverlayKey) obj;
return Objects.equal(ident, key.ident) && guiClass == key.guiClass;
if (obj instanceof OverlayKey item) {
return Objects.equal(ident, item.ident) && guiClass == item.guiClass;
}
return false;
}
@Override
@@ -1,14 +1,33 @@
package codechicken.nei.recipe;
import java.util.List;
import java.util.Map;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
import codechicken.nei.FavoriteRecipes;
import codechicken.nei.ItemPanels;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.api.ShortcutInputHandler;
import codechicken.nei.bookmark.BookmarksGridSlot;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.recipe.Recipe.RecipeId;
public class RecipeItemInputHandler implements IContainerInputHandler {
public class RecipeItemInputHandler implements IContainerInputHandler, IContainerTooltipHandler {
protected RecipeTooltipLineHandler recipeTooltipLineHandler = null;
public static void load() {
RecipeItemInputHandler recipeHandler = new RecipeItemInputHandler();
GuiContainerManager.addInputHandler(recipeHandler);
GuiContainerManager.addTooltipHandler(recipeHandler);
}
@Override
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyCode) {
@@ -18,12 +37,82 @@ public class RecipeItemInputHandler implements IContainerInputHandler {
@Override
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
if (!(gui instanceof GuiRecipe) || ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.bookmarkPanel.contains(mousex, mousey))
|| ItemPanels.bookmarkPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey))
return false;
ItemStack stackover = GuiContainerManager.getStackMouseOver(gui);
return ShortcutInputHandler.handleMouseClick(GuiContainerManager.getStackMouseOver(gui));
}
return ShortcutInputHandler.handleMouseClick(stackover);
@Override
public Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
if ((gui instanceof GuiRecipe) || ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.bookmarkPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey)) {
hotkeys.putAll(
ShortcutInputHandler
.handleHotkeys(gui, mousex, mousey, GuiContainerManager.getStackMouseOver(gui)));
}
return hotkeys;
}
@Override
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
List<String> currenttip) {
if (itemstack != null) {
final RecipeId recipeId = getHoveredRecipeId(gui, itemstack, mousex, mousey);
if (recipeId == null) {
recipeTooltipLineHandler = null;
} else if (recipeTooltipLineHandler == null || !recipeTooltipLineHandler.getRecipeId().equals(recipeId)) {
recipeTooltipLineHandler = new RecipeTooltipLineHandler(recipeId);
}
if (recipeTooltipLineHandler != null) {
currenttip.add(GuiDraw.TOOLTIP_HANDLER + GuiDraw.getTipLineId(recipeTooltipLineHandler));
}
} else {
recipeTooltipLineHandler = null;
}
return currenttip;
}
private RecipeId getHoveredRecipeId(GuiContainer gui, ItemStack itemstack, int mousex, int mousey) {
if (ItemPanels.bookmarkPanel.contains(mousex, mousey)) {
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mousex, mousey);
if (slot != null && slot.getRecipeId() != null
&& !slot.isIngredient()
&& NEIClientConfig.getRecipeTooltipsMode() != 0) {
final int tooltipMode = NEIClientConfig.getRecipeTooltipsMode();
final BookmarkViewMode viewMode = slot.getGroup().viewMode;
if (tooltipMode == 3 || viewMode == BookmarkViewMode.DEFAULT && tooltipMode == 1
|| viewMode == BookmarkViewMode.TODO_LIST && tooltipMode == 2) {
return slot.getRecipeId();
}
}
return null;
}
if (ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey)) {
return NEIClientConfig.showRecipeTooltipInPanel() ? FavoriteRecipes.getFavorite(itemstack) : null;
}
if (gui instanceof GuiRecipe<?>guiRecipe
&& new Rectangle4i(gui.guiLeft, gui.guiTop, gui.xSize, gui.ySize).contains(mousex, mousey)
&& NEIClientConfig.showRecipeTooltipInGui()
&& guiRecipe.getFocusedRecipe() == null) {
return FavoriteRecipes.getFavorite(itemstack);
}
return null;
}
@Override
@@ -0,0 +1,96 @@
package codechicken.nei.recipe;
import java.awt.Dimension;
import java.util.List;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.lib.gui.GuiDraw.ITooltipLineHandler;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.Recipe.RecipeId;
public class RecipeTooltipLineHandler implements ITooltipLineHandler {
protected long lastUpdate = System.currentTimeMillis();
protected GuiRecipe<?> gui = null;
protected RecipeId recipeId = null;
protected boolean createdGui = false;
public RecipeTooltipLineHandler(RecipeId recipeId) {
this.recipeId = recipeId;
}
public ItemStack getItemStack() {
return this.recipeId.getResult();
}
public RecipeId getRecipeId() {
return this.recipeId;
}
@Override
public Dimension getSize() {
if (this.gui == null && !this.createdGui) {
this.gui = GuiCraftingRecipe.createRecipeGui("recipeId", false, this.recipeId.getResult(), this.recipeId);
this.createdGui = true;
if (this.gui != null) {
this.gui.initGui();
this.gui.guiTop = 0;
this.gui.guiLeft = 0;
}
}
if (this.gui != null) {
return this.gui.getWidgetSize();
}
return new Dimension(0, 0);
}
@Override
public void draw(int x, int y) {
if (this.gui == null) return;
if ((System.currentTimeMillis() - lastUpdate) > 50) {
lastUpdate = System.currentTimeMillis();
this.gui.onUpdate();
}
GL11.glPushMatrix();
GL11.glScaled(1, 1, 3);
GL11.glTranslatef(x, y, 0);
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
RenderHelper.disableStandardItemLighting();
this.gui.drawGuiContainerBackgroundLayer(0.0f, -100, -100);
GL11.glPopAttrib();
if (this.gui.slotcontainer != null) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
RenderHelper.enableGUIStandardItemLighting();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
GL11.glDisable(GL11.GL_DEPTH_TEST);
List<Slot> slots = this.gui.slotcontainer.inventorySlots;
for (Slot slot : slots) {
if (slot != null && slot.getStack() != null) {
GuiContainerManager.drawItem(slot.xDisplayPosition, slot.yDisplayPosition, slot.getStack());
}
}
GL11.glPopAttrib();
}
this.gui.drawGuiContainerForegroundLayer(-100, -100);
GL11.glPopMatrix();
}
}
@@ -2,7 +2,7 @@ package codechicken.nei.recipe;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.item.ItemStack;
@@ -10,29 +10,27 @@ import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.IFluidContainerItem;
import codechicken.nei.ClientHandler;
import codechicken.nei.ItemStackMap;
import codechicken.nei.LRUCache;
import codechicken.nei.api.IStackStringifyHandler;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.recipe.stackinfo.DefaultStackStringifyHandler;
import codechicken.nei.recipe.stackinfo.GTFluidStackStringifyHandler;
import codechicken.nei.util.ItemStackKey;
public class StackInfo {
public static final ArrayList<IStackStringifyHandler> stackStringifyHandlers = new ArrayList<>();
private static final HashMap<String, HashMap<String, String[]>> guidfilters = new HashMap<>();
private static final FluidStack NULL_FLUID = new FluidStack(FluidRegistry.WATER, 0);
public static final List<IStackStringifyHandler> stackStringifyHandlers = new ArrayList<>();
private static final Map<String, HashMap<String, String[]>> guidfilters = new HashMap<>();
private static final ItemStackMap<String> guidcache = new ItemStackMap<>();
private static final LinkedHashMap<ItemStack, FluidStack> fluidcache = new LinkedHashMap<>() {
private static final long serialVersionUID = 1042213947848622164L;
@Override
protected boolean removeEldestEntry(Map.Entry<ItemStack, FluidStack> eldest) {
return size() > 20;
}
};
private static final LRUCache<ItemStackKey, FluidStack> fluidcache = new LRUCache<>(200);
private static boolean isPausedItemDamageSound = false;
static {
stackStringifyHandlers.add(new DefaultStackStringifyHandler());
@@ -76,12 +74,36 @@ public class StackInfo {
return stack;
}
public static void pauseItemDamageSound(boolean pause) {
if (isPausedItemDamageSound != (isPausedItemDamageSound = pause)) {
for (IStackStringifyHandler handler : stackStringifyHandlers) {
handler.pauseItemDamageSound(pause);
}
}
}
public static boolean isPausedItemDamageSound() {
return isPausedItemDamageSound;
}
public static ItemStack withAmount(ItemStack stack, long customCount) {
if (stack == null) return null;
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(stack);
return nbTag != null ? loadFromNBT(nbTag, customCount) : null;
}
public static int getAmount(ItemStack stack) {
if (stack == null) return 0;
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(stack);
return nbTag != null ? nbTag.getInteger("Count") : 0;
}
public static boolean equalItemAndNBT(ItemStack stackA, ItemStack stackB, boolean useNBT) {
if (!stackA.isItemEqual(stackB)) {
if (stackA == null || stackB == null || stackA.getItem() != stackB.getItem()) {
return false;
}
if (useNBT) {
if (useNBT && stackA != stackB) {
NBTTagCompound tagCompoundA = itemStackToNBT(stackA, false);
NBTTagCompound tagCompoundB = itemStackToNBT(stackB, false);
@@ -92,19 +114,20 @@ public class StackInfo {
return true;
}
public static FluidStack getFluid(ItemStack stack) {
FluidStack fluid = fluidcache.get(stack);
public static synchronized FluidStack getFluid(ItemStack stack) {
ItemStackKey key = new ItemStackKey(stack);
FluidStack fluid = fluidcache.get(key);
if (fluid == null && !fluidcache.containsKey(stack)) {
if (fluid == null) {
for (int i = stackStringifyHandlers.size() - 1; i >= 0 && fluid == null; i--) {
fluid = stackStringifyHandlers.get(i).getFluid(stack);
}
fluidcache.put(stack, fluid);
fluidcache.put(key, fluid == null ? NULL_FLUID : fluid);
}
return fluid;
return fluid == NULL_FLUID ? null : fluid;
}
public static boolean isFluidContainer(ItemStack stack) {
@@ -147,10 +170,10 @@ public class StackInfo {
try {
if (local instanceof NBTTagCompound) {
local = ((NBTTagCompound) local).getTag(rule[i]);
} else if (local instanceof NBTTagList) {
local = ((NBTTagList) local).tagList.get(Integer.parseInt(rule[i]));
if (local instanceof NBTTagCompound item) {
local = item.getTag(rule[i]);
} else if (local instanceof NBTTagList item) {
local = item.tagList.get(Integer.parseInt(rule[i]));
} else {
break;
}
@@ -160,8 +183,8 @@ public class StackInfo {
}
}
if (local instanceof NBTBase) {
keys.add(((NBTBase) local).toString());
if (local instanceof NBTBase item) {
keys.add(item.toString());
} else if (local != null) {
keys.add(String.valueOf(local));
}
@@ -200,7 +223,7 @@ public class StackInfo {
if (stacks.length > 1) {
for (ItemStack stack : stacks) {
if (stack.getItem() != null && stack.getItemDamage() < damage) {
if (stack.getItem() != null && !ItemInfo.isHidden(stack) && stack.getItemDamage() < damage) {
damage = stack.getItemDamage();
result = stack;
}
@@ -1,9 +1,5 @@
package codechicken.nei.recipe;
import static codechicken.lib.gui.GuiDraw.changeTexture;
import static codechicken.lib.gui.GuiDraw.drawTexturedModalRect;
import static codechicken.lib.gui.GuiDraw.getMousePosition;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
@@ -33,20 +29,18 @@ import org.lwjgl.opengl.GL11;
import com.google.common.base.Stopwatch;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.FavoriteRecipes;
import codechicken.nei.ItemList;
import codechicken.nei.ItemList.AllMultiItemFilter;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIServerUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.PresetsList;
import codechicken.nei.api.DefaultOverlayRenderer;
import codechicken.nei.api.IOverlayHandler;
import codechicken.nei.api.IRecipeOverlayRenderer;
import codechicken.nei.api.IStackPositioner;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerInputHandler;
import codechicken.nei.guihook.IContainerTooltipHandler;
@@ -188,50 +182,31 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
public List<PositionedStack> getCycledIngredients(int cycle, List<PositionedStack> ingredients) {
if (!NEIClientUtils.shiftKey() && !disableCycledIngredients) {
if (NEIClientConfig.useJEIStyledCycledIngredients()) {
jeiStyledRenderPermutation(ingredients, cycle);
} else {
randomRenderPermutation(ingredients, cycle);
}
randomRenderPermutation(ingredients, cycle);
}
return ingredients;
}
public void randomRenderPermutation(List<PositionedStack> stacks, long cycle) {
final ItemFilter filter = getItemFilter();
final int randCycle = Math.abs(new Random(cycle + offset).nextInt());
cycle = NEIClientConfig.useJEIStyledCycledIngredients() ? cycle
: Math.abs(new Random(cycle + offset).nextInt());
for (PositionedStack stack : stacks) {
if (stack.items.length <= 1) continue;
ArrayList<Integer> filtered = getFilteredIngredientAlternatives(stack, filter);
if (filtered.isEmpty()) {
stack.setPermutationToRender((int) (randCycle % stack.items.length));
} else {
stack.setPermutationToRender(filtered.get((int) (randCycle % filtered.size())));
}
}
}
protected void jeiStyledRenderPermutation(List<PositionedStack> stacks, long cycle) {
final ItemFilter filter = getItemFilter();
for (PositionedStack stack : stacks) {
if (stack.items.length <= 1) continue;
ArrayList<Integer> filtered = getFilteredIngredientAlternatives(stack, filter);
if (filtered.isEmpty()) {
stack.setPermutationToRender((int) (cycle % stack.items.length));
} else {
stack.setPermutationToRender(filtered.get((int) (cycle % filtered.size())));
}
for (PositionedStack pStack : stacks) {
if (pStack.items.length <= 1) continue;
final List<ItemStack> items = pStack.getFilteredPermutations(FavoriteRecipes::contains);
pStack.setPermutationToRender(items.get((int) (cycle % items.size())));
}
}
@Deprecated
public void randomRenderPermutation(PositionedStack stack, long cycle) {
Random rand = new Random(cycle + offset);
stack.setPermutationToRender((int) (Math.abs(rand.nextInt()) % stack.items.length));
cycle = NEIClientConfig.useJEIStyledCycledIngredients() ? cycle
: Math.abs(new Random(cycle + offset).nextInt());
if (stack.items.length <= 1) return;
final List<ItemStack> items = stack.getFilteredPermutations(FavoriteRecipes::contains);
stack.setPermutationToRender(items.get((int) (cycle % items.size())));
}
public void setIngredientPermutation(Collection<PositionedStack> ingredients, ItemStack ingredient) {
@@ -431,25 +406,6 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
RecipeTransferRectHandler.registerRectsToGuis(getRecipeTransferRectGuis(), transferRects);
}
public static ItemFilter getItemFilter() {
return new AllMultiItemFilter(
item -> !ItemInfo.isHidden(item),
PresetsList.getItemFilter(),
GuiRecipe.searchField != null ? GuiRecipe.searchField.getFilter() : null);
}
protected static ArrayList<Integer> getFilteredIngredientAlternatives(PositionedStack stack, ItemFilter filter) {
final ArrayList<Integer> filtered = new ArrayList<>();
for (int i = 0; i < stack.items.length; i++) {
if (filter.matches(stack.items[i])) {
filtered.add(i);
}
}
return filtered;
}
/**
* Add all RecipeTransferRects to the transferRects list during this call. Afterward they may be added to the input
* handler for the corresponding guis from getRecipeTransferRectGuis
@@ -553,16 +509,16 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
switch (direction) {
case 0: // right
drawTexturedModalRect(x, y, tx, ty, var, h);
GuiDraw.drawTexturedModalRect(x, y, tx, ty, var, h);
break;
case 1: // down
drawTexturedModalRect(x, y, tx, ty, w, var);
GuiDraw.drawTexturedModalRect(x, y, tx, ty, w, var);
break;
case 2: // left
drawTexturedModalRect(x + w - var, y, tx + w - var, ty, var, h);
GuiDraw.drawTexturedModalRect(x + w - var, y, tx + w - var, ty, var, h);
break;
case 3: // up
drawTexturedModalRect(x, y + h - var, tx, ty + h - var, w, var);
GuiDraw.drawTexturedModalRect(x, y + h - var, tx, ty + h - var, w, var);
break;
}
}
@@ -650,14 +606,14 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
public void drawBackground(int recipe) {
GL11.glColor4f(1, 1, 1, 1);
changeTexture(getGuiTexture());
drawTexturedModalRect(0, 0, 5, 11, 166, 65);
GuiDraw.changeTexture(getGuiTexture());
GuiDraw.drawTexturedModalRect(0, 0, 5, 11, 166, 65);
}
public void drawForeground(int recipe) {
GL11.glColor4f(1, 1, 1, 1);
GL11.glDisable(GL11.GL_LIGHTING);
changeTexture(getGuiTexture());
GuiDraw.changeTexture(getGuiTexture());
drawExtras(recipe);
}
@@ -704,7 +660,7 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
@Override
public List<String> handleTooltip(GuiRecipe<?> gui, List<String> currenttip, int recipe) {
if (GuiContainerManager.shouldShowTooltip(gui) && currenttip.size() == 0) {
if (GuiContainerManager.shouldShowTooltip(gui) && currenttip.isEmpty()) {
Point offset = gui.getRecipePosition(recipe);
currenttip = transferRectTooltip(gui, transferRects, offset.x, offset.y, currenttip);
}
@@ -744,21 +700,24 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
public boolean mouseScrolled(GuiRecipe<?> gui, int scroll, int recipe) {
if (!NEIClientUtils.shiftKey()) return false;
final Point pos = getMousePosition();
final Point pos = GuiDraw.getMousePosition();
final Point offset = gui.getRecipePosition(recipe);
final Point relMouse = new Point(pos.x - gui.guiLeft - offset.x, pos.y - gui.guiTop - offset.y);
final PositionedStack overStack = getIngredientMouseOver(relMouse.x, relMouse.y, recipe);
if (overStack != null && overStack.items.length > 1) {
final ItemFilter filter = getItemFilter();
final List<ItemStack> items = overStack.getFilteredPermutations();
final int stackIndex = getPermutationIndex(overStack.item, items);
final ItemStack stack = items.get((items.size() - scroll + stackIndex) % items.size());
if (NEIClientConfig.useJEIStyledCycledIngredients()) {
ItemStack stack = overStack.item;
for (PositionedStack pStack : getIngredientStacks(recipe)) {
shiftPermutationToRender(pStack, stack, scroll, filter);
if (pStack.containsWithNBT(stack)) {
pStack.setPermutationToRender(stack);
}
}
} else {
shiftPermutationToRender(overStack, overStack.item, scroll, filter);
overStack.setPermutationToRender(stack);
}
return true;
@@ -767,33 +726,15 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
return false;
}
private void shiftPermutationToRender(PositionedStack pStack, ItemStack stack, int scroll, ItemFilter filter) {
if (!pStack.containsWithNBT(stack)) return;
private int getPermutationIndex(ItemStack stack, List<ItemStack> items) {
final List<Integer> filtered = getFilteredIngredientAlternatives(pStack, filter);
int index = 0;
if (filtered.isEmpty()) {
for (int i = 0; i < pStack.items.length; i++) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(pStack.items[i], stack)) {
index = i;
break;
}
for (int index = 0; index < items.size(); index++) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(items.get(index), stack)) {
return index;
}
pStack.setPermutationToRender((int) ((pStack.items.length - scroll + index) % pStack.items.length));
} else {
for (int i = 0; i < filtered.size(); i++) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(pStack.items[filtered.get(i)], stack)) {
index = i;
break;
}
}
pStack.setPermutationToRender(filtered.get((int) ((filtered.size() - scroll + index) % filtered.size())));
}
return -1;
}
private PositionedStack getIngredientMouseOver(int mousex, int mousey, int recipe) {
@@ -814,7 +755,7 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
private static boolean transferRect(GuiContainer gui, Collection<RecipeTransferRect> transferRects, int offsetx,
int offsety, boolean usage) {
Point pos = getMousePosition();
Point pos = GuiDraw.getMousePosition();
Point relMouse = new Point(pos.x - gui.guiLeft - offsetx, pos.y - gui.guiTop - offsety);
for (RecipeTransferRect rect : transferRects) {
if (rect.rect.contains(relMouse) && (usage ? GuiUsageRecipe.openRecipeGui(rect.outputId, rect.results)
@@ -827,7 +768,7 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
private static List<String> transferRectTooltip(GuiContainer gui, Collection<RecipeTransferRect> transferRects,
int offsetx, int offsety, List<String> currenttip) {
Point pos = getMousePosition();
Point pos = GuiDraw.getMousePosition();
Point relMouse = new Point(pos.x - gui.guiLeft - offsetx, pos.y - gui.guiTop - offsety);
for (RecipeTransferRect rect : transferRects) {
if (rect.rect.contains(relMouse)) {
@@ -0,0 +1,103 @@
package codechicken.nei.recipe.chain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minecraft.item.ItemStack;
import codechicken.nei.ItemStackAmount;
import codechicken.nei.bookmark.BookmarkItem;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
public class RecipeChainIterator implements Iterator<Map<RecipeId, Long>> {
public final ItemStackAmount inventory = new ItemStackAmount();
private final Set<RecipeId> precessedRecipes = new HashSet<>();
private RecipeChainMath math;
private Set<RecipeId> topRecipes;
private Set<RecipeId> processedRecipes;
private List<BookmarkItem> initialItems;
public RecipeChainIterator(RecipeChainMath math, List<BookmarkItem> initialItems) {
this.math = math;
this.topRecipes = this.math.outputRecipes.keySet();
this.initialItems = new ArrayList<>(initialItems);
this.processedRecipes = new HashSet<>(this.topRecipes);
}
public void updateInventory(ItemStack[] mainInventory) {
updateInventory(ItemStackAmount.of(Arrays.asList(mainInventory)));
}
public void updateInventory(ItemStackAmount mainInventory) {
this.inventory.clear();
this.inventory.putAll(mainInventory);
}
@Override
public Map<RecipeId, Long> next() {
refreshInitialItems(this.math, this.initialItems);
this.math.refresh();
final Set<RecipeId> skipRecipes = new HashSet<>();
final Map<RecipeId, Long> rootRecipes = new HashMap<>();
final HashMap<BookmarkItem, BookmarkItem> preferredItems = new HashMap<>(this.math.preferredItems);
preferredItems.values()
.removeIf(item -> item == null || item.amount == 0 || this.precessedRecipes.contains(item.recipeId));
preferredItems.keySet().removeIf(item -> item.amount == 0);
for (Map.Entry<BookmarkItem, BookmarkItem> entry : preferredItems.entrySet()) {
final BookmarkItem keyItem = entry.getKey();
if (this.topRecipes.contains(keyItem.recipeId) && !skipRecipes.contains(keyItem.recipeId)) {
final BookmarkItem item = entry.getValue();
if (preferredItems.entrySet().stream().anyMatch(
pref -> !this.processedRecipes.contains(pref.getKey().recipeId)
&& item.equals(pref.getValue()))) {
skipRecipes.add(item.recipeId);
} else {
rootRecipes.put(
item.recipeId,
Math.max(rootRecipes.getOrDefault(item.recipeId, 0L), item.getMultiplier()));
}
}
}
for (RecipeId recipeId : skipRecipes) {
rootRecipes.remove(recipeId);
}
this.processedRecipes.addAll(rootRecipes.keySet());
rootRecipes.values().removeIf(amount -> amount == 0);
this.topRecipes = rootRecipes.keySet();
this.precessedRecipes.addAll(this.topRecipes);
return rootRecipes;
}
@Override
public boolean hasNext() {
return !this.topRecipes.isEmpty();
}
private void refreshInitialItems(RecipeChainMath math, List<BookmarkItem> initialItems) {
math.initialItems.clear();
math.initialItems.addAll(initialItems);
for (ItemStack stack : this.inventory.values()) {
final long invStackSize = this.inventory.getOrDefault(stack, 0L);
if (invStackSize > 0) {
math.initialItems.add(BookmarkItem.of(-1, StackInfo.withAmount(stack, invStackSize)));
}
}
}
}
Loaded 100 of 119 files, more files were not shown because too many files have changed in this diff. Show more