Compare commits

...
42 Commits
Author SHA1 Message Date
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
92 changed files with 9209 additions and 4375 deletions

No files matched your search

+4 -2
View File
@@ -1,8 +1,10 @@
// Add your dependencies here
dependencies {
api('com.github.GTNewHorizons:CodeChickenCore:1.4.1:dev')
implementation('com.github.GTNewHorizons:GTNHLib:0.6.5:dev')
api('com.github.GTNewHorizons:CodeChickenCore:1.4.3:dev')
implementation('com.github.GTNewHorizons:GTNHLib:0.6.31:dev')
shadowImplementation('org.apache.commons:commons-csv:1.10.0')
compileOnly 'maven.modrinth:forge-essentials:7.5.1'
}
+1 -1
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.
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.31'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.38'
}
@@ -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,14 +338,16 @@ public class ClientHandler {
Minecraft mc = Minecraft.getMinecraft();
if (event.world == mc.theWorld) {
NEIClientConfig.unloadWorld();
ItemMobSpawner.clearEntityReferences();
}
}
public void loadWorld(World world, boolean fromServer) {
if (world != lastworld) {
SMPmagneticItems.clear();
WorldOverlayRenderer.reset();
if (!NEIClientConfig.getBooleanSetting("world.overlays.lock")) {
WorldOverlayRenderer.reset();
}
if (!fromServer) {
NEIClientConfig.setHasSMPCounterPart(false);
NEIClientConfig.setInternalEnabled(false);
@@ -326,8 +355,6 @@ public class ClientHandler {
if (!Minecraft.getMinecraft().isSingleplayer()) // wait for server to initiate in singleplayer
NEIClientConfig.loadWorld("remote/" + ClientUtils.getServerIP().replace(':', '~'));
}
ItemMobSpawner.clearEntityReferences(world);
lastworld = world;
}
}
@@ -150,10 +150,16 @@ public class CollapsibleItems {
}
public static void putItem(ItemStack stack) {
final GroupItem group = CollapsibleItems.groups.stream().filter(g -> g.matches(stack)).findFirst().orElse(null);
int groupIndex = -1;
if (group != null) {
CollapsibleItems.cache.put(stack, CollapsibleItems.groups.indexOf(group));
for (int i = 0; i < CollapsibleItems.groups.size() && groupIndex == -1; i++) {
if (CollapsibleItems.groups.get(i).matches(stack)) {
groupIndex = i;
}
}
if (groupIndex != -1) {
CollapsibleItems.cache.put(stack, groupIndex);
}
}
@@ -0,0 +1,228 @@
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.List;
import java.util.Map;
import java.util.Optional;
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 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);
}
} 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));
}
return recipeId;
}
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 (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,25 +1,64 @@
package codechicken.nei;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ItemPanel.ItemPanelSlot;
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();
@@ -33,40 +72,40 @@ public class ItemHistoryPanel extends Widget {
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() > Math.max(50, grid.rows * grid.columns)) {
grid.realItems.remove(grid.realItems.size() - 1);
if (this.grid.realItems.size() > Math.max(50, this.grid.rows * this.grid.columns)) {
this.grid.realItems.remove(this.grid.realItems.size() - 1);
}
grid.onItemsChanged();
this.grid.onItemsChanged();
}
}
public void resize(GuiContainer gui) {
grid.setGridSize(x, y, w, h);
grid.refresh(gui);
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);
}
@@ -107,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;
}
}
@@ -125,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;
@@ -144,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;
}
}
+8 -13
View File
@@ -7,6 +7,7 @@ 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;
@@ -47,7 +48,7 @@ public class ItemList {
private static final HashSet<Item> erroredItems = new HashSet<>();
private static final HashSet<String> stackTraces = new HashSet<>();
private static 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.
*/
@@ -213,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) {
@@ -237,12 +237,11 @@ public class ItemList {
}
private void updateOrdering(List<ItemStack> items) {
final Map<ItemStack, Integer> newOrdering = new HashMap<>();
ItemSorter.sort(items);
HashMap<ItemStack, Integer> newOrdering = new HashMap<>();
if (!CollapsibleItems.isEmpty()) {
HashMap<Integer, Integer> groups = new HashMap<>();
final HashMap<Integer, Integer> groups = new HashMap<>();
int orderIndex = 0;
for (ItemStack stack : items) {
@@ -309,7 +308,6 @@ public class ItemList {
ListMultimap<Item, ItemStack> itemMap = ArrayListMultimap.create();
ItemStackSet unique = new ItemStackSet();
timer.setLimit(NEIClientConfig.getItemLoadingTimeout());
StreamSupport.stream(((Iterable<Item>) Item.itemRegistry).spliterator(), true).forEach(item -> {
if (item == null || item.delegate.name() == null || erroredItems.contains(item)) return;
@@ -330,6 +328,7 @@ public class ItemList {
}
CollapsibleItems.putItem(stack);
TooltipFilter.getSearchTooltip(stack);
}
}
@@ -358,13 +357,10 @@ public class ItemList {
if (interrupted()) return;
updateOrdering(ItemList.items);
new Thread(
() -> ItemList.items.parallelStream().forEach(TooltipFilter::getSearchTooltip),
"NEI Tooltip Filter Loader").start();
loadFinished = true;
SubsetWidget.updateHiddenItems();
ItemPanels.bookmarkPanel.load();
updateFilter.restart();
}
};
@@ -410,8 +406,7 @@ public class ItemList {
if (interrupted()) return;
Comparator<ItemStack> comparator = Comparator.comparingInt(ItemList.ordering::get);
filtered.sort(comparator::compare);
filtered.sort(Comparator.comparingInt(ItemList.ordering::get));
if (interrupted()) return;
@@ -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
+64 -327
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,285 +31,49 @@ public class ItemPanel extends PanelWidget {
return super.getStackMouseOver(mousex, mousey);
}
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;
}
@@ -342,12 +96,12 @@ public class ItemPanel extends PanelWidget {
}
};
historyPanel = new ItemHistoryPanel();
}
@Deprecated
public void scroll(int i) {
grid.shiftPage(i);
@Override
public ItemPanelSlot getSlotMouseOver(int mousex, int mousey) {
// use ItemPanelSlot for Backwards compat
return ItemPanelSlot.of(this.grid.getSlotMouseOver(mousex, mousey));
}
public String getLabelText() {
@@ -395,7 +149,7 @@ public class ItemPanel extends PanelWidget {
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 = LayoutManager.quantity.y - historyPanel.h - PanelWidget.PADDING;
@@ -430,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);
}
}
@@ -483,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;
}
@@ -22,6 +22,12 @@ public class ItemStackAmount {
}
}
public void addAll(Iterable<ItemStack> items) {
for (ItemStack stack : items) {
add(stack);
}
}
public void add(ItemStack item) {
add(item, (long) StackInfo.getAmount(item));
}
@@ -30,7 +36,9 @@ public class ItemStackAmount {
if (stack == null || stack.getItem() == null) return;
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
this.itemMap.put(key, value + this.itemMap.getOrDefault(key, 0L));
if (key != null) {
this.itemMap.put(key, value + this.itemMap.getOrDefault(key, 0L));
}
}
public Long get(ItemStack stack) {
@@ -44,7 +52,9 @@ public class ItemStackAmount {
if (stack == null || stack.getItem() == null) return;
final NBTTagCompound key = StackInfo.itemStackToNBT(stack, false);
this.itemMap.put(key, value);
if (key != null) {
this.itemMap.put(key, value);
}
}
public long getOrDefault(ItemStack stack, long defaultAmount) {
@@ -53,6 +63,10 @@ public class ItemStackAmount {
return e == null ? defaultAmount : e;
}
public boolean contains(ItemStack stack) {
return get(stack) != null;
}
public void clear() {
this.itemMap.clear();
}
+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())) {
+191 -103
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;
@@ -20,14 +18,13 @@ 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> {
private static class ScreenCapture {
protected static class ScreenCapture {
private long nextCacheRefresh = 0;
private Framebuffer framebuffer;
@@ -140,7 +137,126 @@ public class ItemsGrid {
}
public static final int SLOT_SIZE = 18;
public static class ItemsGridSlot {
protected static final float DEFAULT_SLOT_SIZE = 18f;
protected static final float LINE_WIDTH = 0.75f;
public final ItemStack item;
public final int slotIndex;
public final int itemIndex;
public Color borderColor = Color.BLACK;
public boolean borderLeft = false;
public boolean borderTop = false;
public boolean borderRight = false;
public boolean borderBottom = false;
public ItemsGridSlot(int slotIndex, int itemIndex, ItemStack itemStack) {
this.slotIndex = slotIndex;
this.itemIndex = itemIndex;
this.item = itemStack;
}
public ItemStack getItemStack() {
return this.item;
}
public <M extends MouseContext> void beforeDraw(Rectangle4i rect, M mouseContext) {
if (mouseContext != null && mouseContext.slotIndex == this.slotIndex) {
NEIClientUtils.drawRect(rect.x, rect.y, rect.w, rect.h, HIGHLIGHT_COLOR);
}
}
public <M extends MouseContext> void afterDraw(Rectangle4i rect, M mouseContext) {}
public void drawItem(Rectangle4i rect) {
drawItem(getItemStack(), rect);
}
protected void drawItem(ItemStack stack, Rectangle4i rect) {
if (rect.w != DEFAULT_SLOT_SIZE) {
final float panelFactor = (rect.w - 2) / (DEFAULT_SLOT_SIZE - 2);
GL11.glTranslatef(rect.x + 1, rect.y + 1, 0);
GL11.glScaled(panelFactor, panelFactor, 1);
GuiContainerManager.drawItem(0, 0, stack, true, "");
GL11.glScaled(1f / panelFactor, 1f / panelFactor, 1);
GL11.glTranslatef(-1 * (rect.x + 1), -1 * (rect.y + 1), 0);
} else {
GuiContainerManager.drawItem(rect.x + 1, rect.y + 1, stack, true, "");
}
}
public void drawBorder(Rectangle4i rect) {
float halfLineWidth = LINE_WIDTH / 2f;
if (this.borderLeft) {
NEIClientUtils
.drawRect(rect.x - halfLineWidth, rect.y + halfLineWidth, LINE_WIDTH, rect.h, this.borderColor);
}
if (this.borderRight) {
NEIClientUtils.drawRect(
rect.x + rect.w - halfLineWidth,
rect.y - halfLineWidth,
LINE_WIDTH,
rect.h,
this.borderColor);
}
if (this.borderTop) {
NEIClientUtils
.drawRect(rect.x - halfLineWidth, rect.y - halfLineWidth, rect.w, LINE_WIDTH, this.borderColor);
}
if (this.borderBottom) {
NEIClientUtils.drawRect(
rect.x + halfLineWidth,
rect.y + rect.h - halfLineWidth,
rect.w,
LINE_WIDTH,
this.borderColor);
}
}
}
public static class MouseContext {
public final int slotIndex;
public final int columnIndex;
public final int rowIndex;
public MouseContext(int slotIndex, int rowIndex, int columnIndex) {
this.slotIndex = slotIndex;
this.rowIndex = rowIndex;
this.columnIndex = columnIndex;
}
@Override
public int hashCode() {
return Objects.hash(this.rowIndex, this.slotIndex, this.columnIndex);
}
public boolean equals(Object obj) {
if (obj instanceof MouseContext context) {
return this.columnIndex == context.columnIndex && this.rowIndex == context.rowIndex
&& this.slotIndex == context.slotIndex;
}
return false;
}
}
public static int SLOT_SIZE = 18;
public static final Color HIGHLIGHT_COLOR = new Color(0xee555555, true);
protected int width;
protected int height;
@@ -157,7 +273,6 @@ public class ItemsGrid {
protected int rows;
protected int columns;
protected List<Integer> gridMask = null;
protected boolean[] invalidSlotMap;
@@ -169,8 +284,8 @@ public class ItemsGrid {
return realItems;
}
public ItemStack getItem(int idx) {
return realItems.get(idx);
public ItemStack getItem(int itemIndex) {
return realItems.get(itemIndex);
}
public int size() {
@@ -222,7 +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) {
@@ -270,10 +389,9 @@ public class ItemsGrid {
if (this.screenCapture != null) {
this.screenCapture.refreshBuffer();
}
this.gridMask = null;
}
protected void onItemsChanged() {
public void onItemsChanged() {
onGridChanged();
}
@@ -323,20 +441,37 @@ public class ItemsGrid {
}
}
public Rectangle4i getItemRect(int idx) {
final List<Integer> mask = getMask();
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) != null && idx == mask.get(i)) {
return getSlotRect(i);
}
public T getSlotMouseOver(int mousex, int mousey) {
if (!contains(mousex, mousey)) {
return null;
}
return null;
final int overRow = getRowIndex(mousey);
final int overColumn = getColumnIndex(mousex);
final int slt = columns * overRow + overColumn;
if (overRow >= rows || overColumn >= columns) {
return null;
}
return getSlotBySlotIndex(slt);
}
public Rectangle4i getSlotRect(int i) {
return getSlotRect(i / columns, i % columns);
public T getSlotBySlotIndex(int slotIndex) {
return getMask().stream().filter(item -> item.slotIndex == slotIndex).findAny().orElse(null);
}
public T getSlotByItemIndex(int itemIndex) {
return getMask().stream().filter(item -> item.itemIndex == itemIndex).findAny().orElse(null);
}
public Rectangle4i getItemRect(int itemIndex) {
final T item = getSlotByItemIndex(itemIndex);
return item != null ? getSlotRect(item.slotIndex) : null;
}
public Rectangle4i getSlotRect(int slotIndex) {
return getSlotRect(slotIndex / columns, slotIndex % columns);
}
public Rectangle4i getSlotRect(int row, int column) {
@@ -347,67 +482,45 @@ public class ItemsGrid {
SLOT_SIZE);
}
public int getRowIndex(int mousey) {
return (mousey - this.marginTop) / SLOT_SIZE;
}
public int getColumnIndex(int mousex) {
return (mousex - this.marginLeft - this.paddingLeft) / SLOT_SIZE;
}
public boolean isInvalidSlot(int index) {
return invalidSlotMap[index];
}
protected List<Integer> getMask() {
public abstract List<T> getMask();
if (this.gridMask == null) {
this.gridMask = new ArrayList<>();
int idx = page * perPage;
for (int i = 0; i < rows * columns && idx < size(); i++) {
this.gridMask.add(isInvalidSlot(i) ? null : idx++);
}
protected abstract M getMouseContext(int mousex, int mousey);
protected void beforeDrawItems(int mousex, int mousey, M mouseContext) {
for (T item : getMask()) {
item.beforeDraw(getSlotRect(item.slotIndex), mouseContext);
}
return this.gridMask;
}
protected void beforeDrawItems(int mousex, int mousey, @Nullable ItemPanelSlot focused) {
final List<Integer> mask = getMask();
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) != null) {
beforeDrawSlot(focused, mask.get(i), getSlotRect(i));
}
for (T item : getMask()) {
item.drawBorder(getSlotRect(item.slotIndex));
}
}
protected void afterDrawItems(int mousex, int mousey, @Nullable ItemPanelSlot focused) {
final List<Integer> mask = getMask();
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) != null) {
afterDrawSlot(focused, mask.get(i), getSlotRect(i));
}
protected void afterDrawItems(int mousex, int mousey, M mouseContext) {
for (T item : getMask()) {
item.afterDraw(getSlotRect(item.slotIndex), mouseContext);
}
}
public void update() {}
protected void beforeDrawSlot(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {
if (focused != null && focused.slotIndex == slotIdx) {
drawRect(rect.x, rect.y, rect.w, rect.h, 0xee555555); // highlight
}
}
protected void drawItems() {
protected void afterDrawSlot(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {}
private void drawItems() {
GuiContainerManager.enableMatrixStackLogging();
final List<Integer> mask = getMask();
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) != null) {
drawItem(getSlotRect(i), mask.get(i));
}
for (T item : getMask()) {
item.drawItem(getSlotRect(item.slotIndex));
}
GuiContainerManager.disableMatrixStackLogging();
}
protected int getGridRenderingCacheMode() {
@@ -419,10 +532,10 @@ public class ItemsGrid {
return;
}
final ItemPanelSlot focused = getSlotMouseOver(mousex, mousey);
final int gridRenderingCacheMode = getGridRenderingCacheMode();
final M mouseContext = getMouseContext(mousex, mousey);
beforeDrawItems(mousex, mousey, focused);
beforeDrawItems(mousex, mousey, mouseContext);
if (gridRenderingCacheMode > 0) {
@@ -431,15 +544,21 @@ public class ItemsGrid {
}
if (this.screenCapture.needRefresh(gridRenderingCacheMode)) {
this.screenCapture.captureScreen(this::drawItems, gridRenderingCacheMode);
this.screenCapture.captureScreen(() -> {
GuiContainerManager.enableMatrixStackLogging();
drawItems();
GuiContainerManager.disableMatrixStackLogging();
}, gridRenderingCacheMode);
}
this.screenCapture.renderCapturedScreen();
} else {
GuiContainerManager.enableMatrixStackLogging();
drawItems();
GuiContainerManager.disableMatrixStackLogging();
}
afterDrawItems(mousex, mousey, focused);
afterDrawItems(mousex, mousey, mouseContext);
}
public void setVisible() {
@@ -448,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 = (mousey - marginTop) / SLOT_SIZE;
final int overColumn = (mousex - marginLeft - paddingLeft) / SLOT_SIZE;
final int slt = columns * overRow + overColumn;
if (overRow >= rows || overColumn >= columns) {
return null;
}
final List<Integer> mask = getMask();
if (mask.size() > slt && mask.get(slt) != null) {
final int idx = mask.get(slt);
return new ItemPanelSlot(idx, getItem(idx));
}
return null;
}
public boolean contains(int px, int py) {
final Rectangle4i rect = new Rectangle4i(
marginLeft + paddingLeft,
@@ -487,10 +578,7 @@ public class ItemsGrid {
return false;
}
final int r = (py - marginTop) / SLOT_SIZE;
final int c = (px - marginLeft - paddingLeft) / SLOT_SIZE;
return !isInvalidSlot(columns * r + c);
return !isInvalidSlot(columns * getRowIndex(py) + getColumnIndex(px));
}
public String getMessageOnEmpty() {
@@ -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");
}
}
@@ -3,15 +3,19 @@ package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.fontRenderer;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.gui.GuiDraw.ITooltipLineHandler;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.StackInfo;
@@ -19,12 +23,14 @@ import codechicken.nei.util.ReadableNumberConverter;
public class ItemsTooltipLineHandler implements ITooltipLineHandler {
protected static final int SLOT_SIZE = 18;
protected static final int MAX_COLUMNS = 11;
protected static final int MARGIN_TOP = 2;
protected String label;
protected EnumChatFormatting labelColor = EnumChatFormatting.GRAY;
protected List<ItemStack> items;
protected int activeStackIndex = -1;
protected Dimension size = new Dimension();
protected boolean saveStackSize = false;
protected int columns = 0;
@@ -46,9 +52,8 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
this.columns = Math.min(MAX_COLUMNS, this.length);
this.rows = Math.min(maxRows, (int) Math.ceil((float) this.length / this.columns));
this.size.width = Math
.max(this.columns * ItemsGrid.SLOT_SIZE, fontRenderer.getStringWidth(this.label) + 15);
this.size.height = this.rows * ItemsGrid.SLOT_SIZE + fontRenderer.FONT_HEIGHT + 2 + MARGIN_TOP;
this.size.width = Math.max(this.columns * SLOT_SIZE, fontRenderer.getStringWidth(this.label) + 15);
this.size.height = this.rows * SLOT_SIZE + fontRenderer.FONT_HEIGHT + 2 + MARGIN_TOP;
this.count = Math.min(
this.length,
@@ -58,12 +63,22 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
if (this.items.size() > this.count) {
String text = "+" + (this.items.size() - this.count);
this.count -= (int) Math.ceil((float) (fontRenderer.getStringWidth(text) - 2) / ItemsGrid.SLOT_SIZE);
this.count -= (int) Math.ceil((float) (fontRenderer.getStringWidth(text) - 2) / SLOT_SIZE);
}
}
}
public void setActiveStack(ItemStack activeStack) {
final ItemStack realStack = items.stream().filter(stack -> 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();
}
@@ -93,26 +108,38 @@ 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);
drawItem(col * ItemsGrid.SLOT_SIZE, row * ItemsGrid.SLOT_SIZE, drawStack, stackSize);
if (this.activeStackIndex == index + indexShift) {
NEIClientUtils.gl2DRenderContext(
() -> GuiDraw.drawRect(col * SLOT_SIZE - 1, row * SLOT_SIZE - 1, 18, 18, 0x66555555));
}
drawItem(col * SLOT_SIZE, row * SLOT_SIZE, drawStack, stackSize);
}
if (this.count < this.items.size()) {
String text = "+" + (this.items.size() - this.count);
fontRenderer.drawStringWithShadow(
text,
MAX_COLUMNS * ItemsGrid.SLOT_SIZE - fontRenderer.getStringWidth(text) - 2,
(this.rows - 1) * ItemsGrid.SLOT_SIZE + (ItemsGrid.SLOT_SIZE - fontRenderer.FONT_HEIGHT) / 2,
0xee555555);
final String text = "+" + (this.items.size() - this.count);
NEIClientUtils.gl2DRenderContext(() -> {
fontRenderer.drawStringWithShadow(
text,
MAX_COLUMNS * SLOT_SIZE - fontRenderer.getStringWidth(text) - 2,
(this.rows - 1) * SLOT_SIZE + (SLOT_SIZE - fontRenderer.FONT_HEIGHT) / 2,
0xee555555);
});
}
GL11.glPopMatrix();
@@ -124,12 +151,19 @@ public class ItemsTooltipLineHandler implements ITooltipLineHandler {
}
private List<ItemStack> groupingItemStacks(List<ItemStack> items) {
final List<ItemStack> result = ItemStackAmount.of(items).values();
final List<ItemStack> result = new ArrayList<>();
for (ItemStack stack : result) {
if (StackInfo.itemStackToNBT(stack).hasKey("gtFluidName")) {
for (Map.Entry<NBTTagCompound, Long> entry : ItemStackAmount.of(items).entrySet()) {
final ItemStack stack = StackInfo.loadFromNBT(entry.getKey(), Math.max(0, entry.getValue()));
if (entry.getKey().hasKey("gtFluidName")) {
stack.stackSize = 0;
}
result.add(stack);
}
if (result.isEmpty()) {
result.addAll(items);
}
return result;
@@ -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;
@@ -234,8 +235,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;
}
@@ -830,7 +830,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
@Override
public boolean shouldShowTooltip(GuiContainer gui) {
return itemPanel.draggedStack == null && !bookmarkPanel.inEditingState();
return itemPanel.draggedStack == null && !bookmarkPanel.inEditingState() && !AutoCraftingManager.processing();
}
/** Note: this method isn't actually used by this mod, but NEI add-ons might need it. */
@@ -858,13 +858,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);
});
}
}
@@ -926,11 +924,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);
@@ -184,7 +184,7 @@ public class LayoutStyleMinecraft extends LayoutStyle {
final Rectangle4i area = new Rectangle4i(0, 0, 0, BUTTON_SIZE);
if (NEIClientConfig.isSearchWidgetCentered()) {
area.w = gui.xSize - MARGIN * 2;
area.w = Math.min(gui.xSize, 176) - MARGIN * 2;
area.x = (gui.width - area.w) / 2;
area.y = gui.height - BUTTON_SIZE - MARGIN;
} else if (NEIClientConfig.showItemQuantityWidget()) {
@@ -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));
@@ -233,15 +248,15 @@ public class NEIClientConfig {
.setComment("Require holding shift to move items when overlaying recipe").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.guirecipe.shiftOverlayRecipe", true));
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.guirecipe.profile").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.guirecipe.profile", true));
tag.getTag("inventory.history.enabled").setComment("Enable/disable History Panel").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.history.enabled", true));
@@ -287,19 +302,6 @@ public class NEIClientConfig {
0,
OptionIntegerField.UNSIGNED_INT_MAX));
API.addOption(
new OptionButton(
"inventory.collapsibleItems.reloadLabel",
"inventory.collapsibleItems.reloadButton",
"inventory.collapsibleItems.reloadTip") {
@Override
public boolean onClick(int button) {
LayoutManager.markItemsDirty();
return super.onClick(button);
}
});
tag.getTag("inventory.itemzoom.enabled").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.itemzoom.enabled", true));
@@ -325,6 +327,8 @@ public class NEIClientConfig {
tag.getTag("inventory.itemzoom.nameColor").getHexValue(0xFFFFFFFF);
API.addOption(new OptionIntegerField("inventory.itemzoom.nameColor", 0, OptionIntegerField.UNSIGNED_INT_MAX));
setFavoriteDefaults(tag);
tag.getTag("inventory.itemIDs").getIntValue(1);
API.addOption(new OptionCycled("inventory.itemIDs", 3, true));
@@ -347,6 +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));
@@ -359,11 +376,22 @@ public class NEIClientConfig {
}
});
tag.getTag("inventory.gridRenderingCacheFPS").getIntValue(8);
tag.getTag("inventory.gridRenderingCacheMode").getIntValue(0);
API.addOption(new OptionCycled("inventory.gridRenderingCacheMode", 3, true));
tag.getTag("inventory.gridRenderingCacheFPS").getIntValue(8);
API.addOption(new OptionIntegerField("inventory.gridRenderingCacheFPS", 1, 144) {
@Override
public boolean isEnabled() {
return OpenGlHelper.framebufferSupported && getIntSetting("inventory.gridRenderingCacheMode") == 1;
}
});
tag.getTag("inventory.hotkeysHelpText").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.hotkeysHelpText", true));
tag.getTag("loadPluginsInParallel").getBooleanValue(true);
tag.getTag("itemLoadingTimeout").getIntValue(500);
tag.getTag("command.creative").setDefaultValue("/gamemode {0} {1}");
@@ -384,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) {
@@ -667,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);
@@ -681,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.addHashBind("gui.craft", Keyboard.KEY_C + NEIClientUtils.SHIFT_HASH);
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);
@@ -738,7 +792,7 @@ public class NEIClientConfig {
}
world = new ConfigSet(new File(specificDir, "NEI.dat"), new ConfigFile(new File(specificDir, "NEI.cfg")));
bootNEI(ClientUtils.getWorld());
bootNEI();
onWorldLoad(newWorld);
}
}
@@ -775,10 +829,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) {
@@ -789,7 +844,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);
}
@@ -799,23 +854,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();
@@ -828,8 +904,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();
@@ -841,10 +920,10 @@ public class NEIClientConfig {
});
RecipeCatalysts.loadCatalystInfo();
ItemPanels.bookmarkPanel.load();
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
@@ -858,10 +937,10 @@ public class NEIClientConfig {
}
}.start();
} else {
ItemPanels.bookmarkPanel.load();
SubsetWidget.loadHidden();
ItemList.loadItems.restart();
}
}
public static boolean isWorldSpecific(String setting) {
@@ -882,6 +961,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");
}
@@ -894,8 +981,16 @@ public class NEIClientConfig {
return getIntSetting("inventory.bookmarks.recipeTooltipsMode");
}
public static boolean showRecipeMarker() {
return getBooleanSetting("inventory.bookmarks.showRecipeMarker");
public static boolean showRecipeTooltipInPanel() {
return getBooleanSetting("inventory.favorites.showRecipeTooltipInPanel");
}
public static boolean showRecipeTooltipInGui() {
return getBooleanSetting("inventory.favorites.showRecipeTooltipInGui");
}
public static int showRecipeMarkerMode() {
return getIntSetting("inventory.bookmarks.showRecipeMarkerMode");
}
public static boolean showItemQuantityWidget() {
@@ -946,8 +1041,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() {
+111 -49
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();
@@ -452,7 +475,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 +483,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 +522,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);
}
}
@@ -25,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;
@@ -41,6 +42,8 @@ public class NEIModContainer extends DummyModContainer {
private static boolean gregTech5Loaded;
private static boolean gtnhLibLoaded;
private static ASMDataTable asmDataTable;
public NEIModContainer() {
super(getModMetadata());
loadMetadata();
@@ -117,6 +120,7 @@ public class NEIModContainer extends DummyModContainer {
gregTech5Loaded = Loader.isModLoaded("gregtech") && !Loader.isModLoaded("gregapi_post");
gtnhLibLoaded = Loader.isModLoaded("gtnhlib");
if (CommonUtils.isClient()) ClientHandler.preInit();
asmDataTable = event.getAsmData();
}
@Subscribe
@@ -139,6 +143,7 @@ public class NEIModContainer extends DummyModContainer {
GuiRecipeTab.loadHandlerInfo();
ClientHandler.loadPluginsList();
ClientHandler.loadHandlerOrdering();
asmDataTable = null;
}
}
@@ -161,4 +166,8 @@ public class NEIModContainer extends DummyModContainer {
public Class<?> getCustomResourcePackClass() {
return getSource().isDirectory() ? FMLFolderResourcePack.class : FMLFileResourcePack.class;
}
public static ASMDataTable getAsmDataTable() {
return asmDataTable;
}
}
@@ -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) {
+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 && !grid.isEmpty()) {
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);
}
}
@@ -2,6 +2,7 @@ package codechicken.nei;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
@@ -10,7 +11,6 @@ import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary;
import codechicken.nei.ItemList.AllMultiItemFilter;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.recipe.GuiRecipe;
@@ -82,7 +82,11 @@ public class PositionedStack {
}
public PositionedStack copy() {
PositionedStack pStack = new PositionedStack(Arrays.asList(items), relx, rely, false);
PositionedStack pStack = new PositionedStack(
Arrays.stream(this.items).map(ItemStack::copy).toArray(ItemStack[]::new),
relx,
rely,
false);
pStack.permutated = this.permutated;
return pStack;
}
@@ -92,28 +96,21 @@ public class PositionedStack {
}
public List<ItemStack> getFilteredPermutations(ItemFilter additionalFilter) {
List<ItemStack> items = Arrays.asList(this.items).stream().filter(getItemFilter(additionalFilter)::matches)
.collect(Collectors.toList());
List<ItemStack> items = Arrays.asList(this.items);
if (items.isEmpty()) {
items.addAll(
Arrays.asList(this.items).stream().filter(item -> !ItemInfo.isHidden(item))
.collect(Collectors.toList()));
}
if (items.isEmpty()) {
items.addAll(Arrays.asList(this.items));
}
items = filteringPermutations(items, item -> !ItemInfo.isHidden(item));
items = filteringPermutations(items, PresetsList.getItemFilter());
items = filteringPermutations(items, GuiRecipe.getSearchItemFilter());
items = filteringPermutations(items, additionalFilter);
items.sort(Comparator.comparing(FavoriteRecipes::contains).reversed());
return items;
}
private ItemFilter getItemFilter(ItemFilter additionalFilter) {
return new AllMultiItemFilter(
additionalFilter,
item -> !ItemInfo.isHidden(item),
PresetsList.getItemFilter(),
GuiRecipe.getSearchItemFilter());
private List<ItemStack> filteringPermutations(List<ItemStack> items, ItemFilter filter) {
if (filter == null) return items;
final List<ItemStack> filteredItems = items.stream().filter(filter::matches).collect(Collectors.toList());
return filteredItems.isEmpty() ? items : filteredItems;
}
public boolean setPermutationToRender(ItemStack ingredient) {
@@ -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() {
@@ -281,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) {
@@ -126,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;
@@ -158,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();
@@ -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);
+20 -11
View File
@@ -4,9 +4,11 @@ import java.awt.Point;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -33,6 +35,7 @@ import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.util.NEIMouseUtils;
public class SubsetWidget extends Button implements ItemFilterProvider, IContainerTooltipHandler {
@@ -355,16 +358,18 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
private static class DefaultParserProvider implements ISearchParserProvider {
public ItemFilter getFilter(String searchText) {
final AnyMultiItemFilter filter = new AnyMultiItemFilter();
final String pathPart = searchText.replaceAll("\\s+", "").toLowerCase();
final AnyMultiItemFilter filter = new AnyMultiItemFilter();
final Set<ItemStack> filteredItems = new HashSet<>();
for (SubsetTag tag : tags.values()) {
if (tag.filter != null && tag.path.contains(pathPart)) {
filteredItems.addAll(tag.items);
filter.filters.add(tag.filter);
}
}
return filter;
return stack -> filteredItems.contains(stack) || !ItemList.items.contains(stack) && filter.matches(stack);
}
public char getPrefix() {
@@ -584,13 +589,13 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
public void execute() {
try {
List<SubsetTag> list = new ArrayList<>(tags.values());
final List<SubsetTag> list = new ArrayList<>(tags.values());
root.clearCache();
list.parallelStream().forEach(tag -> {
tag.clearCache();
ItemList.items.stream().filter(tag.filter::matches).map(ItemStack::copy)
ItemList.items.stream().filter(tag.filter::matches)
.collect(Collectors.toCollection(() -> tag.items));
});
@@ -841,21 +846,21 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
if (NEIClientConfig.canCheatItem(SubsetWidget.hoverStack)) {
hotkeys.put(
NEIClientUtils.translate("subsets.item.cheat.key"),
NEIClientUtils.getKeyName(NEIClientUtils.CTRL_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("subsets.item.cheat"));
}
if (SubsetWidget.enableSearchBySubsets) {
hotkeys.put(
NEIClientUtils.translate("subsets.item.search.key"),
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("subsets.item.search"));
}
hotkeys.put(
NEIClientUtils.translate("subsets.item.show.key"),
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("subsets.item.show"));
hotkeys.put(
NEIClientUtils.translate("subsets.item.hide.key"),
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_RMB),
NEIClientUtils.translate("subsets.item.hide"));
} else if (SubsetWidget.hoverTag != null) {
hotkeys.put(
@@ -864,12 +869,16 @@ public class SubsetWidget extends Button implements ItemFilterProvider, IContain
if (SubsetWidget.enableSearchBySubsets) {
hotkeys.put(
NEIClientUtils.translate("subsets.tag.search.key"),
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("subsets.tag.search"));
}
hotkeys.put(NEIClientUtils.translate("subsets.tag.show.key"), NEIClientUtils.translate("subsets.tag.show"));
hotkeys.put(NEIClientUtils.translate("subsets.tag.hide.key"), NEIClientUtils.translate("subsets.tag.hide"));
hotkeys.put(
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("subsets.tag.show"));
hotkeys.put(
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_RMB),
NEIClientUtils.translate("subsets.tag.hide"));
}
return hotkeys;
+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,6 +9,7 @@ import net.minecraft.inventory.Slot;
import org.lwjgl.opengl.GL11;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.guihook.GuiContainerManager;
@@ -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))
+42 -77
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;
@@ -123,12 +124,12 @@ public class ItemInfo {
addMobSpawnerItem();
}
public static void load(World world) {
public static void load() {
addVanillaBlockProperties();
addDefaultDropDowns();
searchItems();
parseModItems();
ItemMobSpawner.loadSpawners(world);
ItemMobSpawner.loadSpawners();
addSpawnEggs();
addInfiniteHandlers();
addInputHandlers();
@@ -268,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 {
@@ -280,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());
@@ -323,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);
@@ -368,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);
}
}
@@ -410,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,30 +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 {
@@ -34,35 +45,42 @@ 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() && ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)
&& NEIClientConfig.isKeyHashDown("gui.craft")) {
AutoCraftingManager
.runProcessing(ItemPanels.bookmarkPanel.getGrid().createRecipeChainMath(groupId));
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")) {
@@ -73,10 +91,6 @@ public abstract class ShortcutInputHandler {
return copyItemStackOreDictionary(stackover);
}
if (NEIClientConfig.isKeyHashDown("gui.overlay_use")) {
return openOverlayRecipe(stackover, true);
}
if (NEIClientConfig.isKeyHashDown("gui.recipe")) {
return GuiCraftingRecipe.openRecipeGui("item", stackover);
}
@@ -86,19 +100,15 @@ 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")) {
return runAutoCrafting(stackover);
}
return false;
@@ -123,19 +133,8 @@ 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) {
Toolkit.getDefaultToolkit().getSystemClipboard()
.setContents(new StringSelection(stackover.getDisplayName()), null);
GuiScreen.setClipboardString(SearchField.getEscapedSearchText(stackover));
return true;
}
@@ -153,56 +152,311 @@ public abstract class ShortcutInputHandler {
builder.deleteCharAt(builder.length() - 1);
}
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(builder.toString()), null);
GuiScreen.setClipboardString(builder.toString());
return true;
}
private static boolean openOverlayRecipe(ItemStack stackover, boolean shift) {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
if (gui == null || gui instanceof GuiRecipe) {
return false;
}
final Point mouseover = getMousePosition();
ItemPanelSlot panelSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
BookmarkRecipeId recipeId = null;
if (panelSlot != null) {
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(panelSlot.slotIndex);
} else {
recipeId = ItemPanels.bookmarkPanel.getBookmarkRecipeId(stackover);
}
private static boolean runAutoCrafting(ItemStack stackover) {
final RecipeId recipeId = GuiCraftingRecipe.getRecipeId(NEIClientUtils.getGuiContainer(), stackover);
if (recipeId != null) {
return GuiCraftingRecipe.overlayRecipe(stackover, recipeId, shift);
final Point mouseover = GuiDraw.getMousePosition();
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
RecipeChainMath math = null;
if (slot == null) {
final Recipe recipe = Recipe.of(recipeId);
if (recipe != null) {
math = RecipeChainMath.of(recipe, 1);
}
} else if (slot.getRecipeId() != null && !slot.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) {
AutoCraftingManager.runProcessing(math);
return true;
}
}
return false;
}
private static boolean saveRecipeInBookmark(ItemStack stack, boolean saveIngredients, boolean saveStackSize) {
private static boolean openOverlayRecipe(ItemStack stackover) {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
final RecipeId recipeId = GuiCraftingRecipe.getRecipeId(gui, stackover);
if (stack != null) {
final GuiContainer gui = NEIClientUtils.getGuiContainer();
List<PositionedStack> ingredients = null;
String handlerName = "";
if (recipeId != null) {
final RecipeHandlerRef handlerRef = RecipeHandlerRef.of(recipeId);
if (gui instanceof GuiRecipe) {
ingredients = ((GuiRecipe<?>) gui).getFocusedRecipeIngredients();
handlerName = ((GuiRecipe<?>) gui).getHandlerName();
stack.stackSize = ((GuiRecipe<?>) gui).prepareFocusedRecipeResultStackSize(stack);
if (handlerRef != null) {
if (NEIClientUtils.shiftKey() && handlerRef.canFillCraftingGrid(gui)) {
int multiplier = 0;
if (NEIClientUtils.controlKey()) {
final Point mouseover = GuiDraw.getMousePosition();
final BookmarksGridSlot slot = ItemPanels.bookmarkPanel
.getSlotMouseOver(mouseover.x, mouseover.y);
multiplier = slot != null ? (int) Math.min(64, slot.getMultiplier()) : 1;
}
handlerRef.fillCraftingGrid(gui, multiplier);
} else if (!NEIClientUtils.shiftKey() && handlerRef.canUseOverlayRenderer(gui)) {
handlerRef.useOverlayRenderer(gui);
}
}
ItemPanels.bookmarkPanel.addOrRemoveItem(stack, handlerName, ingredients, saveIngredients, saveStackSize);
return true;
}
return false;
}
private static boolean saveRecipeInBookmark(ItemStack stackover, boolean saveIngredients, boolean saveStackSize) {
final Point mousePos = GuiDraw.getMousePosition();
if (!ItemPanels.bookmarkPanel.removeSlot(mousePos.x, mousePos.y, saveIngredients)) {
final Recipe recipe = getFocusedRecipe(stackover, mousePos.x, mousePos.y, saveIngredients);
if (recipe != null && saveIngredients) {
if (!ItemPanels.bookmarkPanel.removeRecipe(recipe.getRecipeId(), BookmarkGrid.DEFAULT_GROUP_ID)) {
final Recipe singleRecipe = Recipe.of(
Arrays.asList(recipe.getResult(stackover)),
recipe.getHandlerName(),
recipe.getIngredients());
singleRecipe.setCustomRecipeId(recipe.getRecipeId());
ItemPanels.bookmarkPanel.addRecipe(singleRecipe, 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.getFavorite(permutations.get(index)) != null) {
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 {
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) {
return new HashMap<>();
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"), NEIClientUtils.translate("bookmark.group.craft"));
}
}
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"));
if (!(gui instanceof GuiRecipe) && NEIClientConfig.canCheatItem(stack)) {
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("itempanel.open_crafting"));
hotkeys.put(
NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_RMB),
NEIClientUtils.translate("itempanel.open_usage"));
} else {
hotkeys.put(
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB),
NEIClientUtils.translate("itempanel.open_crafting"));
hotkeys.put(
NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_RMB),
NEIClientUtils.translate("itempanel.open_usage"));
}
if (recipeId != null) {
final RecipeHandlerRef handlerRef = RecipeHandlerRef.of(recipeId);
if (handlerRef != null) {
if (handlerRef.canUseOverlayRenderer(gui)) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.overlay"),
NEIClientUtils.translate("itempanel.overlay_recipe"));
}
if (handlerRef.canFillCraftingGrid(gui)) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.overlay", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("itempanel.fill_crafting_grid"));
if (handlerRef.allowedTransferAlghoritm(gui)) {
hotkeys.put(
NEIClientConfig.getKeyName(
"gui.overlay",
NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("itempanel.fill_crafting_grid_quantity"));
}
}
if (NEIClientConfig.autocraftingEnabled()) {
hotkeys.put(NEIClientConfig.getKeyName("gui.craft"), NEIClientUtils.translate("itempanel.craft"));
}
}
}
return hotkeys;
}
private static RecipeId getHotkeyRecipeId(GuiContainer gui, int mousex, int mousey, ItemStack stack,
BookmarksGridSlot slot) {
if (slot != null) {
return slot.getRecipeId();
} else if (ItemPanels.itemPanel.contains(mousex, mousey)
|| ItemPanels.itemPanel.historyPanel.contains(mousex, mousey)) {
return FavoriteRecipes.getFavorite(stack);
} else
if (gui instanceof GuiRecipe guiRecipe) {
final Recipe focusedRecipe = guiRecipe.getFocusedRecipe();
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,191 @@
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.recipe.Recipe;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.Recipe.RecipeIngredient;
import codechicken.nei.recipe.StackInfo;
public class BookmarkItem {
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 String getItemGUID(ItemStack stack) {
final FluidStack fluidStack = StackInfo.getFluid(stack);
if (fluidStack != null) {
return fluidStack.getFluid().getName() + ":" + fluidStack.tag;
} else {
return StackInfo.getItemStackGUID(stack);
}
}
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);
}
}
@@ -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";
@@ -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
@@ -8,7 +8,7 @@ import codechicken.nei.TextField;
public class OptionTextField extends Option {
protected final TextField textField = new TextField("test") {
protected final TextField textField = new TextField("option-text-field") {
{
this.h = 20;
@@ -19,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());
}
}
@@ -27,12 +28,20 @@ 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);
}
public void onTextChange(String text) {}
@Override
public void update() {
textField.update();
@@ -47,6 +56,10 @@ public class OptionTextField extends Option {
return slot.slotWidth();
}
public boolean isEnabled() {
return true;
}
@Override
public void draw(int mousex, int mousey, float frame) {
GuiDraw.drawString(getPrefix(), 10, 6, -1);
@@ -59,12 +72,14 @@ public class OptionTextField extends Option {
@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
@@ -74,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);
}
@@ -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,7 +10,6 @@ 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;
@@ -181,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;
@@ -213,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"));
}
}
@@ -233,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"));
}
/**
@@ -294,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,
@@ -306,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 {
@@ -350,30 +362,32 @@ 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;
}
@@ -384,11 +398,19 @@ public class GuiContainerManager {
}
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() {
@@ -554,7 +576,8 @@ public class GuiContainerManager {
}
ItemStack stack = getStackMouseOver(window);
if (tooltip.isEmpty() && shouldShowTooltip(window)) { // mouseover tip, not holding an item
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);
@@ -569,7 +592,7 @@ public class GuiContainerManager {
if (!tooltip.isEmpty()) tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE); // add space after 'title'
if (shouldShowTooltip(window)) {
if (showTooltip) {
List<String> hotkeystips = collectHotkeyTips(mousex, mousey);
if (!hotkeystips.isEmpty()) {
@@ -615,23 +638,19 @@ public class GuiContainerManager {
}
private List<String> collectHotkeyTips(int mousex, int mousey) {
Map<String, String> hotkeys = new HashMap<>();
synchronized (instanceTooltipHandlers) {
for (IContainerTooltipHandler handler : instanceTooltipHandlers) {
hotkeys = handler.handleHotkeys(window, mousex, mousey, hotkeys);
if (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<>();
if (!hotkeys.isEmpty()) {
List<String> hotkeystips = new ArrayList<>();
if (!NEIClientUtils.altKey()) {
hotkeystips.add(
EnumChatFormatting.GRAY + translate(
"showHotkeys",
EnumChatFormatting.GOLD + translate("key.alt") + EnumChatFormatting.GRAY));
} else {
Map<String, List<String>> messages = new HashMap<>();
hotkeys.remove(null);
hotkeys.remove("");
@@ -664,9 +683,28 @@ public class GuiContainerManager {
hotkeystips.set(
hotkeystips.size() - 1,
hotkeystips.get(hotkeystips.size() - 1) + GuiDraw.TOOLTIP_LINESPACE);
return hotkeystips;
}
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();
@@ -675,39 +713,53 @@ public class GuiContainerManager {
private String getHotkeyTip(List<String> keys, String message) {
return EnumChatFormatting.GOLD
+ String.join(EnumChatFormatting.DARK_GRAY + " / " + EnumChatFormatting.GOLD, keys)
+ EnumChatFormatting.GRAY
+ 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,
tooltips.get(tooltipPage),
currentTooltip,
RenderTooltipEventHelper.getBackgroundStart(),
RenderTooltipEventHelper.getBackgroundEnd(),
RenderTooltipEventHelper.getBorderStart(),
RenderTooltipEventHelper.getBorderEnd());
return;
} else {
drawMultilineTip(font, x, y, currentTooltip);
}
drawMultilineTip(font, x, y, tooltips.get(tooltipPage));
}
public static List<List<String>> splitTooltipByPage(List<String> list) {
@@ -719,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));
@@ -752,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) {
@@ -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,150 @@
package codechicken.nei.recipe;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import 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") {
private static final ItemStack ROOT_ITEM = new ItemStack(Blocks.fire);
private static final RecipeId ROOT_RECIPE_ID = RecipeId
.of(ROOT_ITEM, "recipe-autocrafting", Collections.emptyList());
@Override
public void execute() {
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
final InventoryPlayer playerInventory = guiContainer.mc.thePlayer.inventory;
final ItemStackAmount inventory = ItemStackAmount.of(Arrays.asList(playerInventory.mainInventory));
final RecipeChainMath math = createMasterRoot(AutoCraftingManager.math);
final List<BookmarkItem> initialItems = prepareInitialItems(math, inventory);
boolean processed = false;
boolean changed = false;
do {
changed = false;
RecipeChainIterator iterator = new RecipeChainIterator(math, initialItems);
iterator.updateInventory(playerInventory.mainInventory);
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(playerInventory.mainInventory);
}
}
} while (changed && !interrupted(guiContainer));
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 RecipeChainMath createMasterRoot(RecipeChainMath math) {
final List<BookmarkItem> rootIngredients = new ArrayList<>();
for (BookmarkItem item : math.recipeResults) {
if (math.outputRecipes.containsKey(item.recipeId)) {
long amount = item.factor * math.outputRecipes.get(item.recipeId);
rootIngredients.add(
BookmarkItem.of(
-1,
item.getItemStack(amount),
item.getStackSize(amount),
ROOT_RECIPE_ID,
true,
BookmarkItem.generatePermutations(item.itemStack, null)));
}
}
math.outputRecipes.clear();
math.outputRecipes.put(ROOT_RECIPE_ID, 1L);
math.recipeResults.add(BookmarkItem.of(-1, ROOT_ITEM, 1, ROOT_RECIPE_ID, false));
math.recipeIngredients.addAll(rootIngredients);
return math;
}
private List<BookmarkItem> prepareInitialItems(RecipeChainMath math, ItemStackAmount inventory) {
final List<BookmarkItem> initialItems = new ArrayList<>();
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) {
task.restart();
}
}
public static boolean processing() {
return AutoCraftingManager.math != null && !task.interrupted();
}
}
@@ -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;
@@ -36,11 +36,10 @@ public class CheatItemHandler extends INEIGuiAdapter {
draggedStack.stackSize -= total - contents;
}
return true;
} else {
draggedStack.stackSize = 0;
}
return true;
}
return false;
@@ -7,15 +7,20 @@ 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.InventoryPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.inventory.SlotCrafting;
import net.minecraft.item.ItemStack;
import codechicken.lib.inventory.InventoryUtils;
import codechicken.nei.FastTransferManager;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIServerUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.api.IOverlayHandler;
import codechicken.nei.util.NBTHelper;
import cpw.mods.fml.relauncher.ReflectionHelper;
public class DefaultOverlayHandler implements IOverlayHandler {
@@ -70,44 +75,92 @@ 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);
if (multiplier != 0) {
moveIngredients(gui, assignedIngredients, (int) multiplier);
}
return 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;
@Override
public boolean canFillCraftingGrid(GuiContainer firstGui, IRecipeHandler handler, int recipeIndex) {
return presenceOverlay(firstGui, handler, recipeIndex).stream().allMatch(state -> state.isPresent());
}
FastTransferManager.clickSlot(gui, slot.slotNumber, 0, 1);
if (slot.getHasStack()) return false;
@Override
public boolean canCraft(GuiContainer firstGui, IRecipeHandler handler, int recipeIndex) {
return canFillCraftingGrid(firstGui, handler, recipeIndex);
}
@Override
public boolean craft(GuiContainer firstGui, IRecipeHandler recipe, int recipeIndex, int multiplier) {
final EntityClientPlayerMP thePlayer = NEIClientUtils.mc().thePlayer;
boolean craft = false;
while (multiplier > 0) {
final int transfer = transferRecipe(firstGui, recipe, recipeIndex, multiplier);
if (transfer <= 0) {
break;
}
multiplier -= transfer;
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;
}
}
}
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 true;
}
private void moveIngredients(GuiContainer gui, List<IngredientDistribution> assignedIngredients, int quantity) {
private void moveIngredients(GuiContainer gui, List<IngredientDistribution> assignedIngredients, int multiplier) {
for (IngredientDistribution distrib : assignedIngredients) {
if (distrib.slots.length == 0) continue;
ItemStack pstack = distrib.permutation;
int transferCap = quantity * pstack.stackSize;
int transferCap = multiplier * pstack.stackSize;
int transferred = 0;
int destSlotIndex = 0;
@@ -119,7 +172,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
if (!slot.getHasStack() || !canMoveFrom(slot, gui)) continue;
ItemStack stack = slot.getStack();
if (!canStack(stack, pstack)) continue;
if (!canStack(pstack, stack)) continue;
int amount = Math.min(transferCap - transferred, stack.stackSize);
FastTransferManager.clickSlot(gui, slot.slotNumber);
@@ -145,6 +198,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
private int calculateRecipeQuantity(List<IngredientDistribution> assignedIngredients) {
int quantity = Integer.MAX_VALUE;
for (IngredientDistribution distrib : assignedIngredients) {
DistributedIngred istack = distrib.distrib;
if (istack.numSlots == 0) return 0;
@@ -160,6 +214,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
}
quantity = Math.min(quantity, newQuantity);
}
if (quantity == Integer.MAX_VALUE) {
// Only possible if all ingredients were non-stackable
quantity = 1;
@@ -292,14 +347,14 @@ 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;
if (NEIServerUtils.areStacksSameTypeCrafting(stack2, stack1)) {
if (NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound())) 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
@@ -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);
}
}
@@ -4,7 +4,6 @@ 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.UnaryOperator;
import java.util.stream.Collectors;
@@ -14,11 +13,12 @@ import net.minecraft.client.gui.GuiScreen;
import net.minecraft.item.ItemStack;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ItemPanel.ItemPanelSlot;
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> {
@@ -33,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++) {
@@ -41,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);
}
@@ -62,28 +62,6 @@ 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;
@@ -91,9 +69,9 @@ public class GuiCraftingRecipe extends GuiRecipe<ICraftingHandler> {
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);
@@ -127,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 = GuiDraw.getMousePosition();
ItemPanelSlot panelSlot = ItemPanels.bookmarkPanel.getSlotMouseOver(mouseover.x, mouseover.y);
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 = canFillCraftingGrid() ? 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);
}
}
@@ -19,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;
@@ -28,8 +27,6 @@ import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.Button;
import codechicken.nei.GuiNEIButton;
import codechicken.nei.ItemsTooltipLineHandler;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEICPH;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
@@ -40,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;
@@ -52,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 {
@@ -67,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)
@@ -96,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;
@@ -106,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;
@@ -116,41 +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 List<ItemStack> items = pStack.getFilteredPermutations();
if (items.size() > 1) {
return new PermutationTooltipLineHandler(pStack, items);
}
return null;
}
@Override
protected void drawItem(int x, int y, ItemStack drawStack, String stackSize) {
if (StackInfo.equalItemAndNBT(drawStack, this.pStack.item, true)) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glDisable(GL11.GL_DEPTH_TEST);
GuiDraw.drawRect(x - 1, y - 1, 18, 18, 0x66555555);
GL11.glPopAttrib();
}
super.drawItem(x, y, drawStack, stackSize);
}
}
public static class ItemRecipeFilter implements IRecipeFilter {
public ItemFilter filter;
@@ -248,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();
@@ -323,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();
}
}
@@ -435,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) {
@@ -459,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) {
@@ -477,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;
@@ -488,22 +454,32 @@ 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 (int refIndex = 0; refIndex < indices.size(); refIndex++) {
final int recipeIndex = indices.get(refIndex);
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();
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;
@@ -517,42 +493,46 @@ 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));
GuiRecipeButton button = new GuiOverlayButton(
firstGui,
RecipeHandlerRef.of(handler.original, recipeIndex),
xOffset - GuiRecipeButton.BUTTON_WIDTH,
yOffset + height * (refIndex + 1));
buttons.add(button);
if (showFavorites) {
buttons.add(
new GuiFavoriteButton(
RecipeHandlerRef.of(handler.original, recipeIndex),
button.xPosition,
button.yPosition - button.height - 1));
}
}
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);
}
/** 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() {
@@ -604,11 +584,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;
@@ -619,13 +606,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)));
}
@@ -639,49 +626,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;
}
@@ -696,6 +655,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();
}
@@ -708,7 +676,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));
@@ -752,7 +720,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);
}
@@ -814,9 +782,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;
}
}
}
@@ -845,8 +823,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
@@ -857,7 +844,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);
}
@@ -892,36 +879,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;
@@ -931,13 +923,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;
}
@@ -962,26 +962,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();
@@ -997,7 +977,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);
@@ -1011,18 +990,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();
}
@@ -1032,7 +1012,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.
@@ -1042,18 +1022,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);
@@ -1108,21 +1091,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();
}
}
@@ -1134,11 +1108,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;
}
}
@@ -1158,16 +1135,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();
@@ -1240,15 +1217,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);
}
@@ -1257,7 +1225,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) {
@@ -1266,10 +1234,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)
@@ -1311,16 +1283,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);
@@ -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,185 @@
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<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) {
try {
return !overlayHandler.getClass()
.getDeclaredMethod(
"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;
}
}
}
@@ -1,17 +1,28 @@
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, IContainerTooltipHandler {
protected RecipeTooltipLineHandler recipeTooltipLineHandler = null;
public static void load() {
RecipeItemInputHandler recipeHandler = new RecipeItemInputHandler();
GuiContainerManager.addInputHandler(recipeHandler);
@@ -26,7 +37,8 @@ public class RecipeItemInputHandler implements IContainerInputHandler, IContaine
@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;
return ShortcutInputHandler.handleMouseClick(GuiContainerManager.getStackMouseOver(gui));
@@ -46,6 +58,63 @@ public class RecipeItemInputHandler implements IContainerInputHandler, IContaine
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
public void onKeyTyped(GuiContainer gui, char keyChar, int keyID) {}
@@ -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();
}
}
@@ -86,11 +86,11 @@ public class StackInfo {
}
public static boolean equalItemAndNBT(ItemStack stackA, ItemStack stackB, boolean useNBT) {
if (stackA == null || stackB == null || !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);
@@ -31,6 +31,7 @@ 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.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
@@ -193,7 +194,7 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
for (PositionedStack pStack : stacks) {
if (pStack.items.length <= 1) continue;
final List<ItemStack> items = pStack.getFilteredPermutations();
final List<ItemStack> items = pStack.getFilteredPermutations(FavoriteRecipes::contains);
pStack.setPermutationToRender(items.get((int) (cycle % items.size())));
}
}
@@ -204,7 +205,7 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
: Math.abs(new Random(cycle + offset).nextInt());
if (stack.items.length <= 1) return;
final List<ItemStack> items = stack.getFilteredPermutations();
final List<ItemStack> items = stack.getFilteredPermutations(FavoriteRecipes::contains);
stack.setPermutationToRender(items.get((int) (cycle % items.size())));
}
@@ -706,15 +707,7 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
if (overStack != null && overStack.items.length > 1) {
final List<ItemStack> items = overStack.getFilteredPermutations();
int stackIndex = 0;
for (int index = 0; index < items.size(); index++) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(items.get(index), overStack.item)) {
stackIndex = index;
break;
}
}
final int stackIndex = getPermutationIndex(overStack.item, items);
final ItemStack stack = items.get((items.size() - scroll + stackIndex) % items.size());
if (NEIClientConfig.useJEIStyledCycledIngredients()) {
@@ -733,6 +726,17 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
return false;
}
private int getPermutationIndex(ItemStack stack, List<ItemStack> items) {
for (int index = 0; index < items.size(); index++) {
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(items.get(index), stack)) {
return index;
}
}
return -1;
}
private PositionedStack getIngredientMouseOver(int mousex, int mousey, int recipe) {
for (PositionedStack pStack : getIngredientStacks(recipe)) {
@@ -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)));
}
}
}
}
@@ -0,0 +1,296 @@
package codechicken.nei.recipe.chain;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minecraft.item.ItemStack;
import codechicken.nei.ItemStackAmount;
import codechicken.nei.bookmark.BookmarkItem;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.Recipe.RecipeIngredient;
import codechicken.nei.recipe.StackInfo;
public class RecipeChainMath {
public final Map<RecipeId, Long> outputRecipes = new HashMap<>();
public final List<BookmarkItem> initialItems = new ArrayList<>();
public final List<BookmarkItem> recipeIngredients = new ArrayList<>();
public final List<BookmarkItem> recipeResults = new ArrayList<>();
public final Map<BookmarkItem, BookmarkItem> preferredItems = new HashMap<>();
public final Map<BookmarkItem, Long> requiredAmount = new HashMap<>();
private RecipeChainMath(List<BookmarkItem> recipeItems, Set<RecipeId> collapsedRecipes) {
final Map<RecipeId, Integer> recipeState = new HashMap<>();
final Map<RecipeId, Long> multipliers = new HashMap<>();
for (BookmarkItem item : recipeItems) {
if (item.recipeId != null) {
recipeState
.put(item.recipeId, recipeState.getOrDefault(item.recipeId, 0) | (item.isIngredient ? 1 : 2));
}
}
for (BookmarkItem item : recipeItems) {
if (recipeState.getOrDefault(item.recipeId, 0) != 3) {
this.initialItems.add(item.copy());
} else if (item.isIngredient) {
this.recipeIngredients.add(item.copyWithAmount(0));
} else {
this.recipeResults.add(item.copyWithAmount(0));
multipliers.put(
item.recipeId,
Math.max(multipliers.getOrDefault(item.recipeId, 0L), item.getMultiplier()));
}
}
for (Map.Entry<RecipeId, Long> entry : multipliers.entrySet()) {
if (entry.getValue() > 1 || collapsedRecipes.contains(entry.getKey())) {
collectPreferredItems(entry.getKey(), this.preferredItems, new HashSet<>());
this.outputRecipes.put(entry.getKey(), entry.getValue());
}
}
while (true) {
Map<BookmarkItem, BookmarkItem> maxReference = Collections.emptyMap();
RecipeId maxRecipeId = null;
long maxMultiplier = 0;
int maxDepth = 0;
for (Map.Entry<RecipeId, Long> entry : multipliers.entrySet()) {
final RecipeId recipeId = entry.getKey();
if (!this.outputRecipes.containsKey(recipeId) && this.preferredItems.values().stream()
.noneMatch(resItem -> resItem.recipeId.equals(recipeId))) {
final Map<BookmarkItem, BookmarkItem> references = new HashMap<>(this.preferredItems);
final int depth = collectPreferredItems(recipeId, references, new HashSet<>());
if (maxDepth < depth || maxDepth == depth && entry.getValue() > maxMultiplier) {
maxMultiplier = entry.getValue();
maxReference = references;
maxRecipeId = recipeId;
maxDepth = depth;
}
}
}
if (maxReference.isEmpty()) {
break;
}
this.preferredItems.putAll(maxReference);
this.outputRecipes.put(maxRecipeId, multipliers.get(maxRecipeId));
}
for (Map.Entry<RecipeId, Long> entry : multipliers.entrySet()) {
if (!this.outputRecipes.containsKey(entry.getKey()) && this.preferredItems.values().stream()
.noneMatch(resItem -> resItem.recipeId.equals(entry.getKey()))) {
this.outputRecipes.put(entry.getKey(), entry.getValue());
}
}
for (Map.Entry<RecipeId, Long> entry : this.outputRecipes.entrySet()) {
if (entry.getValue() == 0 && this.preferredItems.values().stream()
.noneMatch(prefItem -> prefItem.recipeId.equals(entry.getKey()))) {
entry.setValue(1L);
}
}
}
private int collectPreferredItems(RecipeId recipeId, Map<BookmarkItem, BookmarkItem> preferredItems,
Set<RecipeId> visited) {
int maxDepth = 0;
visited.add(recipeId);
for (BookmarkItem ingrItem : this.recipeIngredients) {
if (ingrItem.factor > 0 && recipeId.equals(ingrItem.recipeId) && !preferredItems.containsKey(ingrItem)) {
BookmarkItem prefItem = null;
for (BookmarkItem item : this.recipeResults) {
if (item.factor > (prefItem == null ? 0 : prefItem.factor) && item.containsItems(ingrItem)
&& !visited.contains(item.recipeId)) {
prefItem = item;
}
}
if (prefItem != null) {
preferredItems.put(ingrItem, prefItem);
maxDepth = Math
.max(maxDepth, collectPreferredItems(prefItem.recipeId, preferredItems, visited) + 1);
}
}
}
visited.remove(recipeId);
return maxDepth;
}
public static RecipeChainMath of(List<BookmarkItem> chainItems, Set<RecipeId> collapsedRecipes) {
return new RecipeChainMath(chainItems, collapsedRecipes);
}
public static RecipeChainMath of(Recipe recipe, long multiplier) {
final List<BookmarkItem> chainItems = new ArrayList<>();
final RecipeId recipeId = recipe.getRecipeId();
final ItemStack result = recipe.getResult();
chainItems.add(BookmarkItem.of(-1, result, StackInfo.getAmount(result), recipeId, false));
for (RecipeIngredient ingr : recipe.getIngredients()) {
chainItems.add(
BookmarkItem.of(
-1,
ingr.getItemStack(),
ingr.getAmount(),
recipeId,
true,
BookmarkItem.generatePermutations(ingr.getItemStack(), recipe)));
}
for (BookmarkItem item : chainItems) {
item.amount *= multiplier;
}
return new RecipeChainMath(chainItems, Collections.emptySet());
}
public ItemStackAmount getMissedItems() {
final ItemStackAmount missedItems = new ItemStackAmount();
for (BookmarkItem item : this.recipeResults) {
long amount = item.amount - this.requiredAmount.getOrDefault(item, 0L);
if (amount > 0) {
missedItems.add(item.getItemStack(amount));
}
}
for (BookmarkItem item : this.recipeIngredients) {
long amount = this.requiredAmount.containsKey(this.preferredItems.get(item)) ? 0
: this.requiredAmount.getOrDefault(item, item.amount);
if (amount > 0) {
missedItems.add(item.getItemStack(amount));
}
}
for (BookmarkItem item : this.initialItems) {
if (this.requiredAmount.getOrDefault(item, -1L) == 0) {
missedItems.add(item.getItemStack());
}
}
return missedItems;
}
private void resetCalculation() {
for (BookmarkItem item : this.recipeIngredients) {
item.amount = 0;
}
for (BookmarkItem item : this.recipeResults) {
item.amount = 0;
}
this.preferredItems.clear();
this.requiredAmount.clear();
for (RecipeId recipeId : this.outputRecipes.keySet()) {
collectPreferredItems(recipeId, this.preferredItems, new HashSet<>());
}
}
public RecipeChainMath refresh() {
resetCalculation();
for (BookmarkItem prefItem : this.recipeResults) {
if (prefItem.factor > 0 && this.outputRecipes.containsKey(prefItem.recipeId)) {
final long prefAmount = prefItem.factor * this.outputRecipes.get(prefItem.recipeId);
this.preferredItems.put(prefItem, prefItem);
calculateSuitableRecipe(prefItem, prepareAmount(prefItem, prefAmount), new ArrayList<>());
this.preferredItems.remove(prefItem);
}
}
for (BookmarkItem prefItem : this.recipeResults) {
if (prefItem.factor > 0 && this.outputRecipes.containsKey(prefItem.recipeId)
&& this.requiredAmount.containsKey(prefItem)) {
final long prefAmount = prefItem.factor * this.outputRecipes.get(prefItem.recipeId);
this.requiredAmount.put(prefItem, this.requiredAmount.get(prefItem) - prefAmount);
}
}
return this;
}
private void prepareIngredients(RecipeId recipeId, long stepShift, List<RecipeId> visited) {
for (BookmarkItem item : this.recipeIngredients) {
if (item.factor > 0 && recipeId.equals(item.recipeId)) {
calculateSuitableRecipe(item, prepareAmount(item, item.factor * stepShift), visited);
}
}
}
private void calculateSuitableRecipe(BookmarkItem ingrItem, long ingrAmount, List<RecipeId> visited) {
final BookmarkItem prefItem = this.preferredItems.get(ingrItem);
if (prefItem == null) {
this.requiredAmount.put(ingrItem, this.requiredAmount.getOrDefault(ingrItem, 0L) + ingrAmount);
} else if (visited.contains(prefItem.recipeId)) {
this.requiredAmount.put(prefItem, this.requiredAmount.getOrDefault(prefItem, 0L) + ingrAmount);
} else {
this.requiredAmount.put(prefItem, this.requiredAmount.getOrDefault(prefItem, 0L) + ingrAmount);
final long shift = (long) Math
.ceil((this.requiredAmount.get(prefItem) - prefItem.amount) / (double) prefItem.factor);
if (shift > 0) {
addShift(prefItem.recipeId, shift);
visited.add(prefItem.recipeId);
prepareIngredients(prefItem.recipeId, shift, visited);
visited.remove(prefItem.recipeId);
}
}
}
private long prepareAmount(BookmarkItem ingrItem, long ingrAmount) {
if (ingrAmount == 0) return 0;
for (BookmarkItem item : this.initialItems) {
if (item.containsItems(ingrItem)) {
long initAmount = Math.min(ingrAmount, item.amount - this.requiredAmount.getOrDefault(item, 0L));
if (initAmount > 0) {
this.requiredAmount.put(item, this.requiredAmount.getOrDefault(item, 0L) + initAmount);
ingrAmount -= initAmount;
if (ingrAmount == 0) break;
}
}
}
return ingrAmount;
}
private void addShift(RecipeId recipeId, long shift) {
for (BookmarkItem item : this.recipeIngredients) {
if (recipeId.equals(item.recipeId)) {
item.amount += item.factor * shift;
}
}
for (BookmarkItem item : this.recipeResults) {
if (recipeId.equals(item.recipeId)) {
item.amount += item.factor * shift;
}
}
}
}
@@ -0,0 +1,253 @@
package codechicken.nei.recipe.chain;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.gui.GuiDraw.ITooltipLineHandler;
import codechicken.nei.ItemSorter;
import codechicken.nei.ItemStackAmount;
import codechicken.nei.ItemsTooltipLineHandler;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.bookmark.BookmarkItem;
import codechicken.nei.recipe.StackInfo;
public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
public final int groupId;
public final boolean crafting;
protected final RecipeChainMath math;
protected final List<BookmarkItem> initialItems;
protected ItemsTooltipLineHandler available;
protected ItemsTooltipLineHandler inputs;
protected ItemsTooltipLineHandler outputs;
protected ItemsTooltipLineHandler remainder;
protected boolean lastShiftKey = false;
protected Dimension size = new Dimension();
public RecipeChainTooltipLineHandler(int groupId, boolean crafting, RecipeChainMath math) {
this.groupId = groupId;
this.crafting = crafting;
this.math = math;
this.initialItems = new ArrayList<>(this.math.initialItems);
}
private void onUpdate() {
final List<ItemStack> available = new ArrayList<>();
final List<ItemStack> inputs = new ArrayList<>();
final List<ItemStack> outputs = new ArrayList<>();
final List<ItemStack> remainder = new ArrayList<>();
final ItemStackAmount inventory = new ItemStackAmount();
if (lastShiftKey) {
inventory.addAll(Arrays.asList(NEIClientUtils.mc().thePlayer.inventory.mainInventory));
}
if (!this.math.outputRecipes.isEmpty()) {
this.math.initialItems.clear();
if (lastShiftKey) {
for (ItemStack stack : inventory.values()) {
final long invStackSize = inventory.get(stack);
if (invStackSize > 0) {
this.math.initialItems.add(BookmarkItem.of(-1, stack.copy()));
}
}
} else {
this.math.initialItems.addAll(initialItems);
}
this.math.refresh();
for (BookmarkItem item : math.initialItems) {
final long amount = math.requiredAmount.getOrDefault(item, 0L);
if (amount > 0) {
if (lastShiftKey) {
available.add(item.getItemStack(amount));
} else {
inputs.add(item.getItemStack(amount));
}
}
}
for (BookmarkItem item : math.recipeIngredients) {
final long amount = math.requiredAmount.containsKey(math.preferredItems.get(item)) ? 0
: math.requiredAmount.getOrDefault(item, item.amount);
if (amount > 0) {
inputs.add(item.getItemStack(amount));
}
}
for (BookmarkItem item : math.recipeResults) {
final long amount = item.amount - math.requiredAmount.getOrDefault(item, 0L);
if (amount > 0) {
if (math.outputRecipes.containsKey(item.recipeId)) {
outputs.add(item.getItemStack(amount));
} else if (lastShiftKey) {
remainder.add(item.getItemStack(amount));
}
}
}
} else if (lastShiftKey) {
for (BookmarkItem item : this.math.initialItems) {
if (inventory.contains(item.itemStack)) {
final long invAmount = inventory.get(item.itemStack) * item.fluidCellAmount;
if ((item.amount - invAmount) > 0) {
inputs.add(item.getItemStack(item.amount - invAmount));
}
if (Math.min(item.amount, invAmount) > 0) {
available.add(item.getItemStack(Math.min(item.amount, invAmount)));
}
} else {
inputs.add(item.getItemStack());
}
}
}
inputs.sort(
Comparator.comparing((ItemStack stack) -> StackInfo.getFluid(stack) != null)
.thenComparing(ItemSorter.instance));
outputs.sort(
Comparator.comparing((ItemStack stack) -> StackInfo.getFluid(stack) != null)
.thenComparing(ItemSorter.instance));
remainder.sort(
Comparator.comparing((ItemStack stack) -> StackInfo.getFluid(stack) != null)
.thenComparing(ItemSorter.instance));
this.inputs = new ItemsTooltipLineHandler(
lastShiftKey ? NEIClientUtils.translate("bookmark.crafting_chain.missing")
: NEIClientUtils.translate("bookmark.crafting_chain.input"),
inputs,
true,
Integer.MAX_VALUE);
this.available = new ItemsTooltipLineHandler(
NEIClientUtils.translate("bookmark.crafting_chain.available"),
available,
true,
Integer.MAX_VALUE);
this.outputs = new ItemsTooltipLineHandler(
NEIClientUtils.translate("bookmark.crafting_chain.output"),
outputs,
true,
Integer.MAX_VALUE);
this.remainder = new ItemsTooltipLineHandler(
NEIClientUtils.translate("bookmark.crafting_chain.remainder"),
remainder,
true,
Integer.MAX_VALUE);
if (lastShiftKey) {
this.inputs.setLabelColor(EnumChatFormatting.RED);
this.available.setLabelColor(EnumChatFormatting.GREEN);
}
if (!this.inputs.isEmpty() || !this.outputs.isEmpty()
|| !this.remainder.isEmpty()
|| !this.available.isEmpty()) {
if (!this.math.outputRecipes.isEmpty()) {
this.size.height = 2 + GuiDraw.fontRenderer.FONT_HEIGHT;
}
this.size.width = Math.max(
this.inputs.getSize().width,
Math.max(
this.outputs.getSize().width,
Math.max(this.remainder.getSize().width, this.available.getSize().width)));
this.size.height += this.inputs.getSize().height + this.outputs.getSize().height
+ this.remainder.getSize().height
+ this.available.getSize().height;
} else {
this.size.height = this.size.width = 0;
}
}
@Override
public Dimension getSize() {
if (this.lastShiftKey != (this.lastShiftKey = NEIClientUtils.shiftKey()) || this.outputs == null) {
onUpdate();
}
return this.size;
}
@Override
public void draw(int x, int y) {
if (this.size.height == 0) return;
if (!this.math.outputRecipes.isEmpty()) {
GuiDraw.fontRenderer.drawStringWithShadow(
EnumChatFormatting.AQUA + NEIClientUtils.translate("bookmark.crafting_chain"),
x,
y + 2,
0xee555555);
y += 2 + GuiDraw.fontRenderer.FONT_HEIGHT;
}
if (NEIClientConfig.recipeChainDir() == 0) {
if (!this.inputs.isEmpty()) {
this.inputs.draw(x, y);
y += this.inputs.getSize().height;
}
if (!this.available.isEmpty()) {
this.available.draw(x, y);
y += this.available.getSize().height;
}
if (!this.outputs.isEmpty()) {
this.outputs.draw(x, y);
y += this.outputs.getSize().height;
}
} else {
if (!this.outputs.isEmpty()) {
this.outputs.draw(x, y);
y += this.outputs.getSize().height;
}
if (!this.inputs.isEmpty()) {
this.inputs.draw(x, y);
y += this.inputs.getSize().height;
}
if (!this.available.isEmpty()) {
this.available.draw(x, y);
y += this.available.getSize().height;
}
}
if (!this.remainder.isEmpty()) {
this.remainder.draw(x, y);
}
}
}
@@ -24,7 +24,7 @@ public class DefaultStackStringifyHandler implements IStackStringifyHandler {
nbTag.setInteger("Count", saveStackSize ? stack.stackSize : 1);
nbTag.setShort("Damage", (short) stack.getItemDamage());
if (stack.hasTagCompound()) {
if (stack.hasTagCompound() && !stack.getTagCompound().hasNoTags()) {
nbTag.setTag("tag", stack.getTagCompound());
}
@@ -0,0 +1,80 @@
package codechicken.nei.util;
import java.util.HashMap;
import java.util.Map;
import java.util.StringJoiner;
import net.minecraft.client.Minecraft;
import org.lwjgl.input.Keyboard;
import codechicken.nei.NEIClientUtils;
public class NEIKeyboardUtils {
public static final int ALT_HASH = 1 << 27;
public static final int SHIFT_HASH = 1 << 26;
public static final int CTRL_HASH = 1 << 25;
private static final Map<Integer, Integer> keyHashMap = new HashMap<>();
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);
}
private NEIKeyboardUtils() {}
public static boolean isHashKey(int keycode) {
return keyHashMap.containsKey(keycode);
}
public static String getHashName(int keyBind) {
StringJoiner keyText = new StringJoiner(" + ");
if ((keyBind & CTRL_HASH) != 0) {
keyText.add(NEIClientUtils.translate(Minecraft.isRunningOnMac ? "key.ctrl.mac" : "key.ctrl"));
}
if ((keyBind & SHIFT_HASH) != 0) {
keyText.add(NEIClientUtils.translate("key.shift"));
}
if ((keyBind & ALT_HASH) != 0) {
keyText.add(NEIClientUtils.translate("key.alt"));
}
return keyText.toString();
}
public static String getKeyName(int keyBind) {
keyBind = keyHashMap.getOrDefault(keyBind, keyBind);
StringJoiner keyText = new StringJoiner(" + ");
String hashText = getHashName(keyBind);
int keyID = unhash(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 unhash(int keyBind) {
return keyBind & ~(CTRL_HASH | SHIFT_HASH | ALT_HASH);
}
}
@@ -0,0 +1,67 @@
package codechicken.nei.util;
import java.util.StringJoiner;
import codechicken.nei.NEIClientUtils;
public class NEIMouseUtils {
public static final int MOUSE_BTN_NONE = Integer.MIN_VALUE;
public static final int MOUSE_BTN_LMB = 0;
public static final int MOUSE_BTN_RMB = 1;
public static final int MOUSE_BTN_MMB = 2;
public static final int MOUSE_SCROLL = 1 << 27;
public static final int MOUSE_DRAG = 1 << 26;
private NEIMouseUtils() {}
public static String getHashName(int mouseBind) {
StringJoiner mouseText = new StringJoiner(" + ");
if ((mouseBind & MOUSE_SCROLL) != 0) {
mouseText.add(NEIClientUtils.translate("mouse.scroll"));
}
if ((mouseBind & MOUSE_DRAG) != 0) {
mouseText.add(NEIClientUtils.translate("mouse.drag"));
}
return mouseText.toString();
}
public static String getKeyName(int mouseBind) {
StringJoiner mouseText = new StringJoiner(" + ");
String hashText = getHashName(mouseBind < 0 ? mouseBind - MOUSE_BTN_NONE : mouseBind);
if (mouseBind >= 0) {
int button = unhash(mouseBind);
switch (button) {
case MOUSE_BTN_LMB:
mouseText.add(NEIClientUtils.translate("mouse.left"));
break;
case MOUSE_BTN_RMB:
mouseText.add(NEIClientUtils.translate("mouse.right"));
break;
case MOUSE_BTN_MMB:
mouseText.add(NEIClientUtils.translate("mouse.middle"));
break;
default:
mouseText.add(NEIClientUtils.translate("mouse.other", button));
break;
}
}
if (!hashText.isEmpty()) {
mouseText.add(hashText);
}
return mouseText.toString();
}
public static int unhash(int mouseBind) {
return mouseBind & ~(MOUSE_SCROLL | MOUSE_DRAG);
}
}
@@ -24,7 +24,7 @@ public enum ReadableNumberConverter {
/**
* String representation of the sorted postfixes
*/
private static final char[] ENCODED_POSTFIXES = "KMGTPE".toCharArray();
private static final char[] ENCODED_POSTFIXES = "kMGTPE".toCharArray();
private final Format format;
@@ -16,8 +16,9 @@
#
minecraft:portal
minecraft:end_portal
minecraft:fire
minecraft:lava
r/minecraft:fire$/
r/minecraft:water$/
r/minecraft:lava$/
minecraft:mob_spawner
minecraft:anvil !0
minecraft:flowing_water
@@ -12,6 +12,8 @@ appeng.integration.modules.NEIHelpers.NEIFacadeRecipeHandler,Applied Energistics
appeng.integration.modules.NEIHelpers.NEIGrinderRecipeHandler,Applied Energistics 2,appliedenergistics2:tile.BlockGrinder,,appliedenergistics2,TRUE,,,,,,,,,,,
appeng.integration.modules.NEIHelpers.NEIInscriberRecipeHandler,Applied Energistics 2,appliedenergistics2:tile.BlockInscriber,,appliedenergistics2,TRUE,,,70,,5,,,,,,
appeng.integration.modules.NEIHelpers.NEIWorldCraftingHandler,Applied Energistics 2,appliedenergistics2:item.ItemMultiMaterial:9,,appliedenergistics2,TRUE,,,85,,5,,,,,,There's only some explanatory text for fluix crystals and QEDs
appeng.integration.modules.NEIHelpers.NEICellViewHandler,Applied Energistics 2,appliedenergistics2:item.ItemBasicStorageCell.64k,,appliedenergistics2,TRUE,,,180,,1,,,,,,,
com.glodblock.github.nei.NEICellViewHandler,AE2 Fluid Crafting,ae2fc:multi_fluid_storage64,,ae2fc,TRUE,,,,,1,,,,,,,
aroma1997.core.recipes.nei.ShapedAromicRecipeHandler,AromaBackup,minecraft:crafting_table,,AromaBackup,TRUE,,,65,,5,,,,,,
aroma1997.core.recipes.nei.ShapelessAromicRecipeHandler,AromaBackup,minecraft:crafting_table,,AromaBackup,TRUE,,,,,,,,,,,
fox.spiteful.avaritia.compat.nei.CompressionHandler,Avaritia,Avaritia:Neutronium_Compressor,,Avaritia,TRUE,,,50,,6,,,,,,
1 handler modName itemName nbtInfo modId modRequired excludedModId yShift handlerHeight handlerWidth maxRecipesPerPage imageResource imageX imageY imageWidth imageHeight itemNotes
12 appeng.integration.modules.NEIHelpers.NEIGrinderRecipeHandler Applied Energistics 2 appliedenergistics2:tile.BlockGrinder appliedenergistics2 TRUE
13 appeng.integration.modules.NEIHelpers.NEIInscriberRecipeHandler Applied Energistics 2 appliedenergistics2:tile.BlockInscriber appliedenergistics2 TRUE 70 5
14 appeng.integration.modules.NEIHelpers.NEIWorldCraftingHandler Applied Energistics 2 appliedenergistics2:item.ItemMultiMaterial:9 appliedenergistics2 TRUE 85 5 There's only some explanatory text for fluix crystals and QEDs
15 appeng.integration.modules.NEIHelpers.NEICellViewHandler Applied Energistics 2 appliedenergistics2:item.ItemBasicStorageCell.64k appliedenergistics2 TRUE 180 1
16 com.glodblock.github.nei.NEICellViewHandler AE2 Fluid Crafting ae2fc:multi_fluid_storage64 ae2fc TRUE 1
17 aroma1997.core.recipes.nei.ShapedAromicRecipeHandler AromaBackup minecraft:crafting_table AromaBackup TRUE 65 5
18 aroma1997.core.recipes.nei.ShapelessAromicRecipeHandler AromaBackup minecraft:crafting_table AromaBackup TRUE
19 fox.spiteful.avaritia.compat.nei.CompressionHandler Avaritia Avaritia:Neutronium_Compressor Avaritia TRUE 50 6
+86 -36
View File
@@ -5,6 +5,12 @@ nei.save=Save
nei.key.ctrl=CTRL
nei.key.shift=SHIFT
nei.key.alt=ALT
nei.mouse.left=LMB
nei.mouse.right=RMB
nei.mouse.middle=MMB
nei.mouse.other=Button %d
nei.mouse.scroll=Scroll
nei.mouse.drag=Drag
# Mac Command Key
nei.key.ctrl.mac=CMD
nei.showHotkeys=Hold %s for hotkeys
@@ -15,29 +21,46 @@ nei.bookmark.pullBookmarkedItems.tip=Pull all bookmarked items from storage to i
nei.bookmark.group=Bookmarks Group
nei.bookmark.group.include_group=Create/Include Group
nei.bookmark.group.include_group.key=LMB + Drag
nei.bookmark.group.exclude_group=Remove/Exclude Group
nei.bookmark.group.exclude_group.key=RMB + Drag
nei.bookmark.group.toggle_mode=Toggle Group Mode
nei.bookmark.group.toggle_mode.key=Left Click
nei.bookmark.group.toggle_collapse=Toggle Collapse/Expand
nei.bookmark.group.toggle_crafting_chain=Toggle Crafting Chain
nei.bookmark.group.toggle_crafting_chain.key=Right Click
nei.bookmark.group.sorting=Sorting
nei.bookmark.group.sorting.key=SHIFT + LMB + Drag
nei.bookmark.group.overlay_use=Fill Crafting Grid
nei.bookmark.group.sorting=Move Position
nei.bookmark.group.remove_recipe=Remove Group
nei.bookmark.group.pull_items=Pull all Items
nei.bookmark.group.pull_items_ingredients=Pull all Ingredients
nei.bookmark.group.pull_items_shift=Pull missing Items
nei.bookmark.group.craft=Craft Group
nei.bookmark.item.sorting=Move Position
nei.bookmark.remove_recipe=Remove Recipe
nei.bookmark.remove_item=Remove Item
nei.bookmark.add_item=Add Bookmark
nei.bookmark.add_item_with_recipe=Add Bookmark with Recipe
nei.bookmark.add_item_with_count=Add Bookmark with Count
nei.bookmark.change_quantity=Change Quantity
nei.bookmark.change_quantity_step=Change Quantity with Multiplier
nei.bookmark.recipe.toggle_collapse=Toggle Collapse/Expand
nei.bookmark.crafting_chain=Crafting Chain
nei.bookmark.crafting_chain.input=Ingredients
nei.bookmark.crafting_chain.missing=Missing Items
nei.bookmark.crafting_chain.output=Results
nei.bookmark.crafting_chain.remainder=Remainders
nei.bookmark.crafting_chain.available=Available Items
nei.inventory.search.placeholder=Search...
nei.itempanel.quantity.default=One stack
nei.itempanel.loading=Loading Item List...
nei.itempanel.deleteItem=Delete Item
nei.itempanel.collapsed.button.tip=Collapse/Expand All Collapsible Items
nei.itempanel.collapsed.hint.expand=Alt-Click to expand (%d items)
nei.itempanel.collapsed.hint.collapse=Alt-Click to collapse (%d items)
nei.itempanel.collapsed.hint.expand=Expand Group (%d items)
nei.itempanel.collapsed.hint.collapse=Collapse Group (%d items)
nei.itempanel.overlay_recipe=Overlay Recipe
nei.itempanel.craft=Craft Recipe
nei.itempanel.fill_crafting_grid=Fill Crafting Grid
nei.itempanel.fill_crafting_grid_quantity=Fill Crafting Grid With Quantity
nei.itempanel.open_crafting=Recipe to make this item
nei.itempanel.open_usage=Recipes that use this item
nei.itempanel.copy_name=Copy Item Name
nei.itempanel.copy_oredict=Copy Item OreDictionary
nei.enchant=Enchant
nei.enchant.level=Level
@@ -87,6 +110,8 @@ nei.inventory.current.gamemode.1=Current gamemode: creative
nei.inventory.current.gamemode.2=Current gamemode: creative+
nei.inventory.current.gamemode.3=Current gamemode: adventure
nei.inventory.tooltip.page=Page: %s / %s [Press %s to see next page]
nei.inventory.tooltip.count.item=Count: %s
nei.inventory.tooltip.count.fluid=Amount: %s
nei.inventory.gamemode.0=Click: Set gamemode to survival
nei.inventory.gamemode.1=Click: Set gamemode to creative
@@ -139,16 +164,13 @@ nei.options.keys.gui.remove_recipe=Remove Group from Bookmarks
nei.options.keys.gui.bookmark_recipe=Add Bookmark with Recipe
nei.options.keys.gui.bookmark_count=Add Bookmark with Count
nei.options.keys.gui.bookmark_pull_items=Pull all Bookmarked Items
nei.options.keys.gui.bookmark_pull_items_ingredients=Pull all Bookmarked Ingredients
nei.options.keys.gui.bookmark_recipe_count=Add Bookmark with Recipe & Count
nei.options.keys.gui.hide_bookmarks=Toggle Bookmark Panel Visibility
nei.options.keys.gui.overlay=Overlay Recipe
nei.options.keys.gui.overlay_hide=Hide Overlay Recipe
nei.options.keys.gui.overlay_use=Use Overlay Recipe
nei.options.keys.gui.overlay=Fill/Overlay Crafting Grid
nei.options.keys.gui.getprevioussearch=Previous Search
nei.options.keys.gui.getnextsearch=Next Search
nei.options.keys.gui.next_tooltip=Next Tooltip
nei.options.keys.gui.copy_name=Copy Item Name
nei.options.keys.gui.craft=Craft Recipe
nei.options.keys.gui.copy_oredict=Copy Item OreDictionary
nei.options.keys.gui.itemzoom_toggle=Toggle Item Zoom
nei.options.keys.gui.itemzoom_hold=Hold to Display Item Zoom
@@ -175,23 +197,45 @@ nei.options.inventory.bookmarks.enabled.false=Hidden
nei.options.inventory.bookmarks.animation=REI Style Animation in Bookmarks
nei.options.inventory.bookmarks.animation.true=Yes
nei.options.inventory.bookmarks.animation.false=No
nei.options.inventory.bookmarks.craftingChainDir=Crafting Chain Info Direction
nei.options.inventory.bookmarks.craftingChainDir.0=Input First
nei.options.inventory.bookmarks.craftingChainDir.1=Output First
nei.options.inventory.bookmarks.recipeTooltipsMode=Show recipe tooltips in Bookmarks
nei.options.inventory.bookmarks.recipeChainDir=Crafting Chain Info Direction
nei.options.inventory.bookmarks.recipeChainDir.0=Input First
nei.options.inventory.bookmarks.recipeChainDir.1=Output First
nei.options.inventory.bookmarks.recipeTooltipsMode=Show Recipe Tooltips in Bookmarks
nei.options.inventory.bookmarks.recipeTooltipsMode.0=None
nei.options.inventory.bookmarks.recipeTooltipsMode.1=In Horizontal View
nei.options.inventory.bookmarks.recipeTooltipsMode.2=In Vertical View
nei.options.inventory.bookmarks.recipeTooltipsMode.3=Always
nei.options.inventory.bookmarks.showRecipeMarker=Show Recipe Marker
nei.options.inventory.bookmarks.showRecipeMarker.true=Yes
nei.options.inventory.bookmarks.showRecipeMarker.false=No
nei.options.inventory.bookmarks.showRecipeMarkerMode=Show Recipe Marker
nei.options.inventory.bookmarks.showRecipeMarkerMode.0=None
nei.options.inventory.bookmarks.showRecipeMarkerMode.1=Icon
nei.options.inventory.bookmarks.showRecipeMarkerMode.2=Background
nei.options.inventory.bookmarks.recipeMarkerColor=Recipe Marker Color
nei.options.inventory.bookmarks.ignorePotionOverlap=Ignore overlap with potion effect HUD
nei.options.inventory.bookmarks.ignorePotionOverlap.true=Yes
nei.options.inventory.bookmarks.ignorePotionOverlap.false=No
nei.options.inventory.bookmarks.worldSpecific=World Specific Bookmarks
nei.options.inventory.bookmarks.worldSpecific=World Specific
nei.options.inventory.bookmarks.worldSpecific.true=Yes
nei.options.inventory.bookmarks.worldSpecific.false=No
nei.options.inventory.bookmarks.bookmarkItemsWithRecipe=Bookmark items with recipe
nei.options.inventory.bookmarks.bookmarkItemsWithRecipe.true=Yes
nei.options.inventory.bookmarks.bookmarkItemsWithRecipe.false=No
nei.options.inventory.favorites=Favorites
nei.options.inventory.favorites.enabled=Visibility
nei.options.inventory.favorites.enabled.true=Visible
nei.options.inventory.favorites.enabled.false=Hidden
nei.options.inventory.favorites.worldSpecific=World Specific
nei.options.inventory.favorites.worldSpecific.true=Yes
nei.options.inventory.favorites.worldSpecific.false=No
nei.options.inventory.favorites.showRecipeTooltipInPanel=Show Recipe Tooltips in Right Panel
nei.options.inventory.favorites.showRecipeTooltipInPanel.true=Yes
nei.options.inventory.favorites.showRecipeTooltipInPanel.false=No
nei.options.inventory.favorites.showRecipeTooltipInGui=Show Recipe Tooltips in Recipe Gui
nei.options.inventory.favorites.showRecipeTooltipInGui.true=Yes
nei.options.inventory.favorites.showRecipeTooltipInGui.false=No
nei.options.inventory.favorites.depth=Depth
nei.options.inventory.hotkeysHelpText=Show Hotkeys Help Text
nei.options.inventory.hotkeysHelpText.true=Yes
nei.options.inventory.hotkeysHelpText.false=No
nei.options.inventory.guirecipe=Recipes GUI
nei.options.inventory.guirecipe.jeiStyleTabs=JEI Style Tabs
nei.options.inventory.guirecipe.jeiStyleTabs.true=Yes
@@ -266,6 +310,9 @@ nei.options.inventory.guirecipe.creativeTabStyle.false=JEI
nei.options.inventory.optimize_gui_overlap_computation=Optimize computation for GUI overlap
nei.options.inventory.optimize_gui_overlap_computation.true=Yes
nei.options.inventory.optimize_gui_overlap_computation.false=No
nei.options.inventory.autocrafting=Autocrafting
nei.options.inventory.autocrafting.true=Enabled
nei.options.inventory.autocrafting.false=Disabled
nei.options.inventory.guirecipe.jeiStyleCycledIngredients=JEI styled cycled ingredients
nei.options.inventory.guirecipe.jeiStyleCycledIngredients.true=Yes
nei.options.inventory.guirecipe.jeiStyleCycledIngredients.false=No
@@ -301,6 +348,7 @@ nei.options.inventory.gamemodes.tip=Select the gamemodes to cycle through
nei.options.inventory.gamemodes.creative=Creative
nei.options.inventory.gamemodes.creative+=Creative+
nei.options.inventory.gamemodes.adventure=Adventure
nei.options.inventory.itempanelScale=Item Panel Scale (in percent)
nei.options.inventory.disableMouseScrollTransfer=Disable Mouse Wheel Transfer
nei.options.inventory.disableMouseScrollTransfer.true=True
nei.options.inventory.disableMouseScrollTransfer.false=False
@@ -311,6 +359,7 @@ nei.options.inventory.gridRenderingCacheMode=Grid Rendering Cache Mode
nei.options.inventory.gridRenderingCacheMode.0=Off
nei.options.inventory.gridRenderingCacheMode.1=Low FPS
nei.options.inventory.gridRenderingCacheMode.2=Freeze
nei.options.inventory.gridRenderingCacheFPS=Grid Rendering Cache FPS
nei.options.inventory.collapsibleItems=Collapsible Items
nei.options.inventory.collapsibleItems.enabled=Collapsible Items
nei.options.inventory.collapsibleItems.enabled.true=Enabled
@@ -320,8 +369,6 @@ nei.options.inventory.collapsibleItems.customName.true=Yes
nei.options.inventory.collapsibleItems.customName.false=No
nei.options.inventory.collapsibleItems.expandedColor=Expanded Color
nei.options.inventory.collapsibleItems.collapsedColor=Collapsed Color
nei.options.inventory.collapsibleItems.reloadLabel=Reload
nei.options.inventory.collapsibleItems.reloadButton=Run
nei.options.inventory.history=History Panel
nei.options.inventory.history.enabled=History Panel Visibility
nei.options.inventory.history.enabled.true=Enabled
@@ -380,6 +427,11 @@ nei.options.world.highlight_tips.sample=Sample
nei.options.world.panels=Panels Settings
nei.options.world.presets=Presets List
nei.options.world.overlays=Overlays Settings
nei.options.world.overlays.lock=Lock overlays between dimensions
nei.options.world.overlays.lock.true=Enabled
nei.options.world.overlays.lock.false=Disabled
nei.options.tools=Tools
nei.options.tools.handler_load_from_config=Load handlers from Config
nei.options.tools.handler_load_from_config.true=Config
@@ -387,6 +439,9 @@ nei.options.tools.handler_load_from_config.false=JAR
nei.options.tools.catalyst_load_from_config=Load catalysts from Config
nei.options.tools.catalyst_load_from_config.true=Config
nei.options.tools.catalyst_load_from_config.false=JAR
nei.options.tools.handler_info=Handler Info Widget
nei.options.tools.handler_info.true=Enabled
nei.options.tools.handler_info.false=Disabled
nei.options.tools.dump=Data Dumps
nei.options.tools.dump.dump=Dump
nei.options.tools.dump.dumped=%s IDs dumped to %s
@@ -439,16 +494,18 @@ nei.recipe.profiler.usage=Usage Profiling
nei.recipe.concurrent.usage=Concurrent Usage - Total
nei.recipe.concurrent.crafting=Concurrent Crafting - Total
nei.recipe.accepts=Accepts following
nei.recipe.accepts.scroll=Change Item
nei.recipe.overlay=Recipe Overlay
nei.recipe.overlay.missing=Missing following
nei.recipe.overlay.mismatch=Mismatch Crafting Grid
nei.recipe.overlay.overlayRecipe=Overlay Recipe
nei.recipe.overlay.fillCraftingGrid=Fill Crafting Grid
nei.recipe.overlay.fillCraftingGrid.key=SHIFT + Click
nei.recipe.overlay.bookmark=Save to Bookmark
nei.recipe.overlay.bookmarkRecipe=Save with Recipe
nei.recipe.overlay.bookmarkAmount=Save with Amount
nei.recipe.overlay.bookmarkRecipeAndAmount=Save with Recipe & Amount
nei.recipe.favorite=Favorite
nei.recipe.favorite.bookmark_recipe=Save Recipe Tree
nei.recipe.favorite.change_result_index=Change Output
nei.itemsort.minecraft=Minecraft
nei.itemsort.minecraft.tip=Sorts items from vanilla minecraft first
@@ -461,21 +518,14 @@ nei.itemsort.damage=Item Damage
nei.itemsort.name=Display Name
nei.subsets.item.cheat=Give out an Item
nei.subsets.item.cheat.key=Ctrl + LMB
nei.subsets.item.search=Search by Item
nei.subsets.item.search.key=Shift + LMB
nei.subsets.item.show=Show Item
nei.subsets.item.show.key=LMB
nei.subsets.item.hide=Hide Item
nei.subsets.item.hide.key=RMB
nei.subsets.tag.search=Search by Subset
nei.subsets.tag.search.key=Shift + LMB
nei.subsets.tag.onlythis=Show only this Subset
nei.subsets.tag.onlythis.key=Double LMB
nei.subsets.tag.show=Show Subset
nei.subsets.tag.show.key=LMB
nei.subsets.tag.hide=Hide Subset
nei.subsets.tag.hide.key=RMB
nei.subsets.Blocks=Blocks
nei.subsets.Blocks.MobSpawners=Mob Spawners
@@ -134,6 +134,11 @@ nei.options.world.highlight_tips=Mettez en surbrillance les info-bulles
nei.options.world.highlight_tips.hide=Caché
nei.options.world.highlight_tips.show=Montré
nei.options.world.overlays=Paramètres des overlays
nei.options.world.overlays.lock.true=Activé
nei.options.world.overlays.lock.false=Désactivé
nei.options.world.overlays.lock=Conserver les overlays entre les dimensions
nei.options.tools=Outils
nei.options.tools.dump=Data Dumps
nei.options.tools.dump.dump=Jeter
+11 -25
View File
@@ -13,18 +13,13 @@ nei.bookmark.pullBookmarkedItems.tip=Переместить все отмече
nei.bookmark.group=Группа закладок
nei.bookmark.group.include_group=Создать/Включить группу
nei.bookmark.group.include_group.key=ЛКМ + Перетаскивание
nei.bookmark.group.exclude_group=Удалить/Исключить группу
nei.bookmark.group.exclude_group.key=ПКМ + Перетаскивание
nei.bookmark.group.toggle_mode=Переключить режим группы
nei.bookmark.group.toggle_mode.key=Левый клик
nei.bookmark.group.toggle_crafting_chain=Переключить цепочку крафта
nei.bookmark.group.toggle_crafting_chain.key=Правый клик
nei.bookmark.group.sorting=Сортировка
nei.bookmark.group.sorting.key=SHIFT + ЛКМ + Перетаскивание
nei.bookmark.group.remove_recipe=Удалить группу
nei.bookmark.group.pull_items=Переместить все предметы
nei.bookmark.group.pull_items_ingredients=Переместить все ингредиенты
nei.bookmark.group.pull_items_shift=Переместить недостающие предметы
nei.bookmark.crafting_chain=Цепочка крафта
nei.bookmark.crafting_chain.input=Ингредиенты
nei.bookmark.crafting_chain.output=Результаты
@@ -34,8 +29,8 @@ nei.itempanel.quantity.default=Одна стопка
nei.itempanel.loading=Загрузка списка предметов...
nei.itempanel.deleteItem=Удалить предмет
nei.itempanel.collapsed.button.tip=Свернуть/Развернуть все группы предметов
nei.itempanel.collapsed.hint.expand=Alt-Клик для разворачивания (%d предметов)
nei.itempanel.collapsed.hint.collapse=Alt-Клик для сворачивания (%d предметов)
nei.itempanel.collapsed.hint.expand=Развернуть группу (%d предметов)
nei.itempanel.collapsed.hint.collapse=Свернуть группу (%d предметов)
nei.enchant=Зачаровать
nei.enchant.level=Уровень
@@ -137,12 +132,8 @@ nei.options.keys.gui.remove_recipe=Удалить группу из заклад
nei.options.keys.gui.bookmark_recipe=Добавить закладку с рецептом
nei.options.keys.gui.bookmark_count=Добавить закладку с учётом количества
nei.options.keys.gui.bookmark_pull_items=Переместить все отмеченные предметы
nei.options.keys.gui.bookmark_pull_items_ingredients=Переместить все отмеченные ингредиенты
nei.options.keys.gui.bookmark_recipe_count=Добавить закладку с рецептом, учитывающую количество
nei.options.keys.gui.hide_bookmarks=Переключить видимость панели закладок
nei.options.keys.gui.overlay=Отображение рецепта
nei.options.keys.gui.overlay_hide=Скрыть отображение рецепта
nei.options.keys.gui.overlay_use=Использовать отображение рецепта
nei.options.keys.gui.overlay=Заполнить сетку крафта
nei.options.keys.gui.getprevioussearch=Предыдущий поиск
nei.options.keys.gui.getnextsearch=Следующий поиск
nei.options.keys.gui.next_tooltip=Следующая подсказка
@@ -173,17 +164,18 @@ nei.options.inventory.bookmarks.enabled.false=Скрытая
nei.options.inventory.bookmarks.animation=Анимация в стиле REI в закладках
nei.options.inventory.bookmarks.animation.true=Да
nei.options.inventory.bookmarks.animation.false=Нет
nei.options.inventory.bookmarks.craftingChainDir=Направление информации о цепочке крафта
nei.options.inventory.bookmarks.craftingChainDir.0=Сначала ингредиенты
nei.options.inventory.bookmarks.craftingChainDir.1=Сначала результат
nei.options.inventory.bookmarks.recipeChainDir=Направление информации о цепочке крафта
nei.options.inventory.bookmarks.recipeChainDir.0=Сначала ингредиенты
nei.options.inventory.bookmarks.recipeChainDir.1=Сначала результат
nei.options.inventory.bookmarks.recipeTooltipsMode=Показывать подсказки рецептов в закладках
nei.options.inventory.bookmarks.recipeTooltipsMode.0=Нет
nei.options.inventory.bookmarks.recipeTooltipsMode.1=В горизонтальном виде
nei.options.inventory.bookmarks.recipeTooltipsMode.2=В вертикальном виде
nei.options.inventory.bookmarks.recipeTooltipsMode.3=Всегда
nei.options.inventory.bookmarks.showRecipeMarker=Показывать маркер рецепта
nei.options.inventory.bookmarks.showRecipeMarker.true=Да
nei.options.inventory.bookmarks.showRecipeMarker.false=Нет
nei.options.inventory.bookmarks.showRecipeMarkerMode=Показывать маркер рецепта
nei.options.inventory.bookmarks.showRecipeMarkerMode.0=Нет
nei.options.inventory.bookmarks.showRecipeMarkerMode.1=Иконка
nei.options.inventory.bookmarks.showRecipeMarkerMode.2=Фон
nei.options.inventory.bookmarks.ignorePotionOverlap=Игнорировать перекрытие с HUD эффектов зелий
nei.options.inventory.bookmarks.ignorePotionOverlap.true=Да
nei.options.inventory.bookmarks.ignorePotionOverlap.false=Нет
@@ -301,8 +293,6 @@ nei.options.inventory.collapsibleItems.customName.true=Да
nei.options.inventory.collapsibleItems.customName.false=Нет
nei.options.inventory.collapsibleItems.expandedColor=Цвет развернутого
nei.options.inventory.collapsibleItems.collapsedColor=Цвет свернутого
nei.options.inventory.collapsibleItems.reloadLabel=Перезагрузить
nei.options.inventory.collapsibleItems.reloadButton=Запустить
nei.options.inventory.history=Панель истории
nei.options.inventory.history.enabled=Видимость панели истории
nei.options.inventory.history.enabled.true=Включено
@@ -418,11 +408,7 @@ nei.recipe.overlay=отображение рецепта
nei.recipe.overlay.missing=Отсутствует следующее
nei.recipe.overlay.mismatch=Несоответствие сетки крафта
nei.recipe.overlay.fillCraftingGrid=Заполнить сетку крафта
nei.recipe.overlay.fillCraftingGrid.key=SHIFT + Клик
nei.recipe.overlay.bookmark=Сохранить в закладки
nei.recipe.overlay.bookmarkRecipe=Сохранить с рецептом
nei.recipe.overlay.bookmarkAmount=Сохранить с учётом количества
nei.recipe.overlay.bookmarkRecipeAndAmount=Сохранить с рецептом и количеством
nei.itemsort.minecraft=Minecraft
nei.itemsort.minecraft.tip=Сортирует предметы из ванильного Minecraft первыми
@@ -105,11 +105,8 @@ nei.options.keys.gui.search=跳转到搜索框
nei.options.keys.gui.bookmark=添加书签
nei.options.keys.gui.bookmark_recipe=添加带有合成表的书签
nei.options.keys.gui.bookmark_count=添加带有数量的书签
nei.options.keys.gui.bookmark_recipe_count=添加带有合成表和数量的书签
nei.options.keys.gui.hide_bookmarks=显示/隐藏书签页
nei.options.keys.gui.overlay=提取合成表至合成栏/工作台
nei.options.keys.gui.overlay_hide=隐藏覆盖合成表
nei.options.keys.gui.overlay_use=使用覆盖合成表
nei.options.keys.gui.overlay=使用覆盖合成表
nei.options.keys.gui.getprevioussearch=上一个搜索
nei.options.keys.gui.getnextsearch=下一个搜索
nei.options.keys.gui.copy_name=复制物品名称
@@ -144,8 +141,7 @@ nei.options.inventory.bookmarks.animation=REI风格书签动画
nei.options.inventory.bookmarks.animation.true=是
nei.options.inventory.bookmarks.animation.false=否
nei.options.inventory.bookmarks.showRecipeMarker=在书签栏显示合成产物标记
nei.options.inventory.bookmarks.showRecipeMarker.true=是
nei.options.inventory.bookmarks.showRecipeMarker.false=否
nei.options.inventory.bookmarks.showRecipeMarker.0=否
nei.options.inventory.showItemQuantityWidget=显示物品数量栏(右下角)
nei.options.inventory.showItemQuantityWidget.true=是
nei.options.inventory.showItemQuantityWidget.false=否
Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 32 KiB