mirror of
https://github.com/GTNewHorizons/NotEnoughItems.git
synced 2026-11-15 01:34:42 +00:00
Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11d5d8ecf7 | ||
|
|
80e382a5b1 | ||
|
|
1c9c89a6a5 | ||
|
|
1b82963160 | ||
|
|
9e7b279e37 | ||
|
|
f6cd66be3b | ||
|
|
f532b87880 | ||
|
|
71cca7a0bb | ||
|
|
68fcc34d18 | ||
|
|
3ff3bb5c11 | ||
|
|
903271b279 | ||
|
|
204c37fa36 |
No files matched your search
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
dependencies {
|
||||
api('com.github.GTNewHorizons:CodeChickenCore:1.4.1:dev')
|
||||
implementation('com.github.GTNewHorizons:GTNHLib:0.6.16:dev')
|
||||
implementation('com.github.GTNewHorizons:GTNHLib:0.6.18:dev')
|
||||
|
||||
shadowImplementation('org.apache.commons:commons-csv:1.10.0')
|
||||
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.37'
|
||||
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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,10 @@ package codechicken.nei;
|
||||
|
||||
import static codechicken.nei.NEIClientUtils.translate;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
|
||||
public class ItemQuantityField extends TextField {
|
||||
|
||||
public ItemQuantityField(String ident) {
|
||||
@@ -22,6 +26,22 @@ public class ItemQuantityField extends TextField {
|
||||
}
|
||||
}
|
||||
|
||||
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")) {
|
||||
|
||||
@@ -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,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;
|
||||
|
||||
@@ -829,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. */
|
||||
@@ -857,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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -925,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);
|
||||
|
||||
@@ -146,6 +146,7 @@ public class NEIClientConfig {
|
||||
tag.getTag("inventory.widgetsenabled").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.widgetsenabled"));
|
||||
|
||||
tag.getTag("inventory.autocrafting").getBooleanValue(false);
|
||||
tag.getTag("inventory.hidden").getBooleanValue(false);
|
||||
tag.getTag("inventory.cheatmode").getIntValue(2);
|
||||
tag.getTag("inventory.lockmode").setComment(
|
||||
@@ -179,6 +180,7 @@ public class NEIClientConfig {
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
super.onClick(button);
|
||||
ItemPanels.bookmarkPanel.save();
|
||||
ItemPanels.bookmarkPanel.load();
|
||||
return true;
|
||||
}
|
||||
@@ -192,11 +194,19 @@ 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);
|
||||
@@ -234,15 +244,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));
|
||||
|
||||
@@ -313,6 +323,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));
|
||||
|
||||
@@ -338,6 +350,16 @@ public class NEIClientConfig {
|
||||
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));
|
||||
|
||||
@@ -350,8 +372,6 @@ public class NEIClientConfig {
|
||||
}
|
||||
});
|
||||
|
||||
tag.getTag("inventory.gridRenderingCacheFPS").getIntValue(8);
|
||||
|
||||
tag.getTag("inventory.gridRenderingCacheMode").getIntValue(0);
|
||||
API.addOption(new OptionCycled("inventory.gridRenderingCacheMode", 3, true));
|
||||
|
||||
@@ -671,6 +691,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);
|
||||
@@ -685,22 +735,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);
|
||||
@@ -779,10 +822,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) {
|
||||
@@ -837,6 +881,7 @@ public class NEIClientConfig {
|
||||
}
|
||||
|
||||
public static void bootNEI(World world) {
|
||||
|
||||
if (!mainNEIConfigLoaded) {
|
||||
// main NEI config loading
|
||||
ItemInfo.load(world);
|
||||
@@ -868,10 +913,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
|
||||
@@ -885,10 +930,10 @@ public class NEIClientConfig {
|
||||
}
|
||||
}.start();
|
||||
} else {
|
||||
ItemPanels.bookmarkPanel.load();
|
||||
SubsetWidget.loadHidden();
|
||||
ItemList.loadItems.restart();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static boolean isWorldSpecific(String setting) {
|
||||
@@ -909,6 +954,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");
|
||||
}
|
||||
@@ -921,8 +974,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() {
|
||||
@@ -973,8 +1034,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() {
|
||||
|
||||
@@ -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,12 +44,15 @@ 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;
|
||||
@@ -55,6 +61,36 @@ 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. */
|
||||
@@ -486,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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -96,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) {
|
||||
|
||||
@@ -281,7 +281,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) {
|
||||
|
||||
@@ -158,7 +158,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,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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
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() ? "itempanel.remove_item" : "itempanel.remove_recipe"));
|
||||
|
||||
if (slot.isIngredient()) {
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("itempanel.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("itempanel.add_item"));
|
||||
|
||||
if (StackInfo.getAmount(stack) > 0) {
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.CTRL_HASH),
|
||||
NEIClientUtils.translate("itempanel.add_item_with_count"));
|
||||
}
|
||||
|
||||
if (recipeId != null) {
|
||||
hotkeys.put(
|
||||
NEIClientConfig.getKeyName("gui.bookmark", NEIClientUtils.SHIFT_HASH),
|
||||
NEIClientUtils.translate("itempanel.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;
|
||||
}
|
||||
|
||||
}
|
||||
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";
|
||||
|
||||
@@ -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;
|
||||
@@ -213,7 +212,7 @@ 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 {
|
||||
@@ -294,7 +293,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,
|
||||
@@ -350,30 +349,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 +385,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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,90 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 +170,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 +196,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 +212,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 +345,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,36 @@ 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++) {
|
||||
for (int refIndex = 0; refIndex < indices.size() && hovered == null; refIndex++) {
|
||||
final int recipeIndex = indices.get(refIndex);
|
||||
final List<PositionedStack> stacks = handler.original.getIngredientStacks(recipeIndex);
|
||||
|
||||
if (itemstack != null && focused == null) {
|
||||
final List<PositionedStack> stacks = handler.original.getIngredientStacks(recipeIndex);
|
||||
|
||||
for (PositionedStack pStack : stacks) {
|
||||
if (isMouseOver(pStack, refIndex)) {
|
||||
focused = pStack;
|
||||
break;
|
||||
}
|
||||
for (PositionedStack pStack : stacks) {
|
||||
if (isMouseOver(pStack, refIndex)) {
|
||||
hovered = pStack;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 +918,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 +957,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 +972,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 +985,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 +1007,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 +1017,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 +1086,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 +1103,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 +1130,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 +1212,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 +1220,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 +1229,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 +1278,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();
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,7 @@ public class StackInfo {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,,,,,,
|
||||
|
||||
|
@@ -21,29 +21,50 @@ 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.overlay_use=Fill Crafting Grid
|
||||
nei.bookmark.group.sorting=Sorting
|
||||
nei.bookmark.group.sorting.key=SHIFT + LMB + Drag
|
||||
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.group.change_quantity=Change Quantity
|
||||
nei.bookmark.group.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.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.remove_recipe=Remove Recipe
|
||||
nei.itempanel.remove_item=Remove Item
|
||||
nei.itempanel.add_item=Add Bookmark
|
||||
nei.itempanel.add_item_with_recipe=Add Bookmark with Recipe
|
||||
nei.itempanel.add_item_with_count=Add Bookmark with Count
|
||||
nei.itempanel.change_quantity=Change Quantity
|
||||
nei.itempanel.change_quantity_step=Change Quantity with Multiplier
|
||||
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.sort_item=Sorting
|
||||
nei.itempanel.sort_recipe=Sorting
|
||||
nei.itempanel.copy_name=Copy Item Name
|
||||
nei.itempanel.copy_oredict=Copy Item OreDictionary
|
||||
|
||||
nei.enchant=Enchant
|
||||
nei.enchant.level=Level
|
||||
@@ -145,16 +166,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
|
||||
@@ -181,23 +199,39 @@ 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.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
|
||||
@@ -310,6 +344,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
|
||||
@@ -452,16 +487,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
|
||||
|
||||
@@ -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=Нет
|
||||
@@ -416,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 |
Reference in new issue
Block a user