mirror of
https://github.com/GTNewHorizons/NotEnoughItems.git
synced 2026-11-14 09:15:03 +00:00
Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e6b31de18 | ||
|
|
1a27b02412 | ||
|
|
0185cd64b1 | ||
|
|
fbbeafcd79 | ||
|
|
9839d1d08f | ||
|
|
84d42de15f | ||
|
|
d04e1c8e83 | ||
|
|
514af5669c | ||
|
|
41c2b96c88 | ||
|
|
8e1541eab1 | ||
|
|
9411541fd8 | ||
|
|
ae0d6c6108 | ||
|
|
aea4c2866a | ||
|
|
c1a525594c | ||
|
|
afc8a2380b | ||
|
|
a0b2430458 | ||
|
|
4dc6be839b |
No files matched your search
@@ -75,7 +75,7 @@ All items that match `filter` will show your information page. See `config/NEI/c
|
||||
|
||||
#### Item Information Config File
|
||||
|
||||
If you're a modpack creator and want to make custom item information pages, they can easily be added in `config/NEI/informationpages.cfg`, which has a few more examples.
|
||||
If you're a modpack creator and want to make custom item information pages, they can easily be added in `config/NEI/informationpages.cfg`, which has a few more examples. The file is not created automatically: use the Export button in the NEI options under Tools > Default Config Files to copy the defaults to `config/NEI`.
|
||||
|
||||
## Other items of note:
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.lwjgl.opengl.GL11;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
import codechicken.nei.api.GuiInfo;
|
||||
import codechicken.nei.api.INEIGuiHandler;
|
||||
import codechicken.nei.api.ShortcutInputHandler;
|
||||
import codechicken.nei.drawable.DrawableBuilder;
|
||||
import codechicken.nei.drawable.DrawableResource;
|
||||
@@ -55,12 +56,14 @@ public abstract class AbstractSubpanel<T extends ItemsGrid<? extends ItemsGridSl
|
||||
}
|
||||
|
||||
protected void updateLinePadding() {
|
||||
GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
|
||||
final GuiContainer guiContainer = NEIClientUtils.getGuiContainer();
|
||||
final INEIGuiHandler[] handlers = GuiInfo.getGuiHandlersSnapshot();
|
||||
final Rectangle4i rect = new Rectangle4i(this.x, this.y - 1, 10, 2);
|
||||
this.linePaddingStart = 0;
|
||||
|
||||
while (GuiInfo
|
||||
.hideItemPanelSlot(guiContainer, new Rectangle4i(this.x + this.linePaddingStart, this.y - 1, 10, 2))) {
|
||||
while (this.linePaddingStart < this.w && GuiInfo.hideItemPanelSlot(guiContainer, rect, handlers)) {
|
||||
this.linePaddingStart += 10;
|
||||
rect.x += 10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ package codechicken.nei;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
@@ -12,7 +10,8 @@ import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -37,8 +36,10 @@ import net.minecraftforge.client.event.RenderWorldLastEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import codechicken.core.ClassDiscoverer;
|
||||
@@ -50,8 +51,13 @@ import codechicken.nei.api.IConfigureNEI;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.bookmark.tree.GuiCraftingTree;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.recipe.GuiRecipeTab;
|
||||
import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiUsageRecipe;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
import codechicken.nei.recipe.RecipeHandlerRef;
|
||||
import codechicken.nei.recipe.RecipeItemInputHandler;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
import codechicken.nei.recipe.debug.DebugHandlerWidget;
|
||||
import cpw.mods.fml.client.CustomModLoadingErrorDisplayException;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
@@ -67,6 +73,22 @@ public class ClientHandler {
|
||||
|
||||
private static ClientHandler instance;
|
||||
private final ArrayList<EntityItem> SMPmagneticItems = new ArrayList<>();
|
||||
private static final String HANDLER_ORDERING = "handlerordering.csv";
|
||||
public static final List<String> DEFAULT_CONFIGS = ImmutableList.of(
|
||||
"serialhandlers.cfg",
|
||||
"heighthackhandlers.cfg",
|
||||
"hiddenhandlers.cfg",
|
||||
"enableautofocus.cfg",
|
||||
"guicraftablesblacklist.cfg",
|
||||
"defaultbookmarkcontainers.cfg",
|
||||
"hiddenitems.cfg",
|
||||
"guidfilters.cfg",
|
||||
"informationpages.cfg",
|
||||
"collapsibleitems.cfg",
|
||||
"recipeidblacklist.cfg",
|
||||
"handlers.csv",
|
||||
"catalysts.csv",
|
||||
HANDLER_ORDERING);
|
||||
private World lastworld;
|
||||
|
||||
public void addSMPMagneticItem(int i, World world) {
|
||||
@@ -160,17 +182,30 @@ public class ClientHandler {
|
||||
StackInfo.loadGuidFilters();
|
||||
}
|
||||
|
||||
public static void loadSettingsFile(String resource, Consumer<Stream<String>> callback) {
|
||||
loadSettingsFile(resource, (file, writer) -> {
|
||||
String folder = resource.substring(resource.lastIndexOf(".") + 1);
|
||||
URL defaultResource = ClientHandler.class.getResource("/assets/nei/" + folder + "/" + resource);
|
||||
private static URL getDefaultResource(String resource) {
|
||||
final String folder = resource.substring(resource.lastIndexOf(".") + 1);
|
||||
return ClientHandler.class.getResource("/assets/nei/" + folder + "/" + resource);
|
||||
}
|
||||
|
||||
if (defaultResource != null) {
|
||||
try {
|
||||
IOUtils.copy(defaultResource.openStream(), writer);
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
}, callback);
|
||||
public static boolean exportDefaultConfig(String resource) {
|
||||
final File file = new File(NEIClientConfig.configDir, resource);
|
||||
if (file.exists() && !NEIClientUtils.backupFile(file)) return false;
|
||||
|
||||
if (HANDLER_ORDERING.equals(resource)) {
|
||||
return writeDefaultHandlerOrdering();
|
||||
}
|
||||
|
||||
final URL url = getDefaultResource(resource);
|
||||
if (url == null) return false;
|
||||
|
||||
try {
|
||||
FileUtils.copyURLToFile(url, file);
|
||||
NEIClientConfig.logger.info("Exported default '{}' to {}", resource, file);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to export default '{}' to file {}", resource, file, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean loadSettingsResource(String resource, Consumer<Stream<String>> callback) {
|
||||
@@ -196,30 +231,24 @@ public class ClientHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean loadSettingsFile(String resource, BiConsumer<File, FileWriter> createDefault,
|
||||
Consumer<Stream<String>> callback) {
|
||||
File file = new File(NEIClientConfig.configDir, resource);
|
||||
public static boolean loadSettingsFile(String resource, Consumer<Stream<String>> callback) {
|
||||
final File file = new File(NEIClientConfig.configDir, resource);
|
||||
final boolean fromJar = !file.exists();
|
||||
|
||||
if (!file.exists() && createDefault != null) {
|
||||
try (FileWriter writer = new FileWriter(file)) {
|
||||
NEIClientConfig.logger.info("Creating default '{}' {}", resource, file);
|
||||
createDefault.accept(file, writer);
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to save default '{}' to file {}", resource, file, e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
final URL url = fromJar ? getDefaultResource(resource) : file.toURI().toURL();
|
||||
if (url == null) return false;
|
||||
|
||||
if (file.exists()) {
|
||||
try (FileReader reader = new FileReader(file)) {
|
||||
NEIClientConfig.logger.info("Loading '{}' file {}", resource, file);
|
||||
try (InputStreamReader reader = new InputStreamReader(url.openStream(), StandardCharsets.UTF_8)) {
|
||||
NEIClientConfig.logger.info("Loading '{}' from {}", resource, fromJar ? "JAR" : file);
|
||||
callback.accept(
|
||||
IOUtils.readLines(reader).stream()
|
||||
.map(line -> line.contains("#") ? line.substring(0, line.indexOf('#')) : line)
|
||||
.map(String::trim).filter(line -> !line.isEmpty()));
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to load '{}' file {}", resource, file, e);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to load '{}' file {}", resource, file, e);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -292,26 +321,46 @@ public class ClientHandler {
|
||||
}
|
||||
|
||||
public static void loadHandlerOrdering() {
|
||||
final String COMMA_DELIMITER = ",";
|
||||
final String[] defaultHandlerOrdering = {
|
||||
loadSettingsFile(
|
||||
HANDLER_ORDERING,
|
||||
lines -> lines.map(line -> line.split(",")).filter(parts -> parts.length == 2).forEach(parts -> {
|
||||
String handlerId = parts[0];
|
||||
int ordering = Integer.parseInt(parts[1]);
|
||||
NEIClientConfig.handlerOrdering.put(handlerId, ordering);
|
||||
}));
|
||||
}
|
||||
|
||||
private static boolean writeDefaultHandlerOrdering() {
|
||||
final File file = new File(NEIClientConfig.configDir, HANDLER_ORDERING);
|
||||
final List<String> lines = Lists.newArrayList(
|
||||
"# Each line in this file should either be a comment (starts with '#') or an ordering.",
|
||||
"# Ordering lines are <handler ID>,<ordering number>.",
|
||||
"# Handlers will be sorted in order of number ascending, so smaller numbers first.",
|
||||
"# Any handlers that are missing from this file will be assigned to 0.", "# Negative numbers are fine.",
|
||||
"# If you delete this file, it will be regenerated with all registered handler IDs.", };
|
||||
"# Any handlers that are missing from this file keep their own order, 0 for most of them.",
|
||||
"# Negative numbers are fine.");
|
||||
final Map<String, Integer> orders = new TreeMap<>();
|
||||
final List<IRecipeHandler> handlers = new ArrayList<>();
|
||||
handlers.addAll(GuiCraftingRecipe.craftinghandlers);
|
||||
handlers.addAll(GuiCraftingRecipe.serialCraftingHandlers);
|
||||
handlers.addAll(GuiUsageRecipe.usagehandlers);
|
||||
handlers.addAll(GuiUsageRecipe.serialUsageHandlers);
|
||||
|
||||
loadSettingsFile("handlerordering.csv", (file, writer) -> {
|
||||
List<String> toWrite = Lists.newArrayList(defaultHandlerOrdering);
|
||||
GuiRecipeTab.handlerMap.keySet().stream().sorted()
|
||||
.forEach(handlerId -> toWrite.add(String.format("%s" + COMMA_DELIMITER + "0", handlerId)));
|
||||
try {
|
||||
IOUtils.writeLines(toWrite, "\n", writer);
|
||||
} catch (IOException e) {}
|
||||
}, lines -> lines.map(line -> line.split(COMMA_DELIMITER)).filter(parts -> parts.length == 2).forEach(parts -> {
|
||||
String handlerId = parts[0];
|
||||
int ordering = Integer.parseInt(parts[1]);
|
||||
NEIClientConfig.handlerOrdering.put(handlerId, ordering);
|
||||
}));
|
||||
for (IRecipeHandler handler : handlers) {
|
||||
orders.putIfAbsent(
|
||||
NEIClientConfig.HANDLER_ID_FUNCTION.apply(handler),
|
||||
NEIClientConfig.getHandlerOrder(handler));
|
||||
}
|
||||
|
||||
orders.forEach((handlerId, order) -> lines.add(handlerId + "," + order));
|
||||
|
||||
try {
|
||||
NEIClientConfig.logger.info("Creating default '{}' {}", HANDLER_ORDERING, file);
|
||||
FileUtils.writeLines(file, StandardCharsets.UTF_8.name(), lines, "\n");
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to save default '{}' to file {}", HANDLER_ORDERING, file, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadPluginsList() {
|
||||
@@ -398,6 +447,11 @@ public class ClientHandler {
|
||||
if (event.world == mc.theWorld) {
|
||||
NEIClientConfig.unloadWorld();
|
||||
ItemMobSpawner.clearEntityReferences();
|
||||
RecipeItemInputHandler.instance.clearTooltipCache();
|
||||
RecipeHandlerRef.clearCache();
|
||||
ItemPanels.itemPanel.craftablesPanel.clearGuiReferences();
|
||||
DebugHandlerWidget.instance.clearGuiReferences();
|
||||
NEIController.manager = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,11 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTBase.NBTPrimitive;
|
||||
@@ -35,6 +38,7 @@ public class CollapsibleItems {
|
||||
public ItemFilter filter;
|
||||
public boolean expanded = false;
|
||||
public String displayName = "";
|
||||
public String unlocalizedName;
|
||||
|
||||
public void setFilter(String filter) {
|
||||
this.filter = ItemStackFilterParser.parse(filter.trim());
|
||||
@@ -46,15 +50,38 @@ public class CollapsibleItems {
|
||||
this.guid = guid;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
if (this.unlocalizedName != null && !this.unlocalizedName.isEmpty()) {
|
||||
final String translated = StatCollector.translateToLocal(this.unlocalizedName);
|
||||
|
||||
if (!translated.equals(this.unlocalizedName)) {
|
||||
return translated;
|
||||
}
|
||||
}
|
||||
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
public boolean matches(ItemStack stack) {
|
||||
return this.filter.matches(stack);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ApiGroup {
|
||||
|
||||
private String unlocalizedName;
|
||||
|
||||
public ApiGroup setName(String unlocalizedName) {
|
||||
this.unlocalizedName = unlocalizedName;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String STATE_KEY = "collapsibleitems";
|
||||
|
||||
protected static File statesFile;
|
||||
protected static final List<GroupItem> groups = new ArrayList<>();
|
||||
protected static final List<Supplier<GroupItem>> apiGroups = new CopyOnWriteArrayList<>();
|
||||
protected static final Map<ItemStack, Integer> cache = new ConcurrentHashMap<>();
|
||||
|
||||
private CollapsibleItems() {}
|
||||
@@ -77,11 +104,57 @@ public class CollapsibleItems {
|
||||
ClientHandler.loadSettingsFile(
|
||||
"collapsibleitems.cfg",
|
||||
lines -> parseFile(lines.collect(Collectors.toCollection(ArrayList::new))));
|
||||
|
||||
for (Supplier<GroupItem> apiGroup : CollapsibleItems.apiGroups) {
|
||||
try {
|
||||
addGroup(apiGroup.get());
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.error("Failed to add API group", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadStates();
|
||||
}
|
||||
|
||||
public static ApiGroup registerGroup(String filter) {
|
||||
final ApiGroup apiGroup = new ApiGroup();
|
||||
|
||||
CollapsibleItems.apiGroups.add(() -> {
|
||||
GroupItem group = new GroupItem();
|
||||
group.setFilter(filter);
|
||||
group.unlocalizedName = apiGroup.unlocalizedName;
|
||||
return group;
|
||||
});
|
||||
|
||||
return apiGroup;
|
||||
}
|
||||
|
||||
public static ApiGroup registerGroup(Iterable<ItemStack> items) {
|
||||
final ApiGroup apiGroup = new ApiGroup();
|
||||
final ItemStackSet filter = new ItemStackSet();
|
||||
|
||||
for (ItemStack stack : items) {
|
||||
if (stack != null) filter.add(stack.copy());
|
||||
}
|
||||
|
||||
if (filter.isEmpty()) return apiGroup;
|
||||
|
||||
final String key = filter.keys().stream()
|
||||
.map(stack -> Item.itemRegistry.getNameForObject(stack.getItem()) + ":" + stack.getItemDamage())
|
||||
.sorted().collect(Collectors.joining(","));
|
||||
final String guid = UUID.nameUUIDFromBytes(key.getBytes()).toString();
|
||||
|
||||
CollapsibleItems.apiGroups.add(() -> {
|
||||
GroupItem group = new GroupItem();
|
||||
group.setFilter(filter, guid);
|
||||
group.unlocalizedName = apiGroup.unlocalizedName;
|
||||
return group;
|
||||
});
|
||||
|
||||
return apiGroup;
|
||||
}
|
||||
|
||||
private static void parseFile(List<String> itemStrings) {
|
||||
final JsonParser parser = new JsonParser();
|
||||
GroupItem group = new GroupItem();
|
||||
@@ -92,17 +165,8 @@ public class CollapsibleItems {
|
||||
if (itemStr.startsWith("; ")) {
|
||||
JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
|
||||
|
||||
if (settings.get("displayName") != null) {
|
||||
group.displayName = settings.get("displayName").getAsString();
|
||||
}
|
||||
|
||||
if (settings.get("unlocalizedName") != null) {
|
||||
String unlocalizedName = settings.get("unlocalizedName").getAsString();
|
||||
String displayName = StatCollector.translateToLocal(unlocalizedName);
|
||||
|
||||
if (!displayName.equals(unlocalizedName)) {
|
||||
group.displayName = displayName;
|
||||
}
|
||||
group.unlocalizedName = settings.get("unlocalizedName").getAsString();
|
||||
}
|
||||
|
||||
if (settings.get("expanded") != null) {
|
||||
@@ -176,7 +240,7 @@ public class CollapsibleItems {
|
||||
public static String getDisplayName(int groupIndex) {
|
||||
|
||||
if (groupIndex < CollapsibleItems.groups.size()) {
|
||||
return CollapsibleItems.groups.get(groupIndex).displayName;
|
||||
return CollapsibleItems.groups.get(groupIndex).getDisplayName();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -9,7 +9,6 @@ import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -24,7 +23,6 @@ import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
@@ -34,7 +32,6 @@ import codechicken.nei.api.API;
|
||||
import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiRecipeTab;
|
||||
import codechicken.nei.recipe.ICraftingHandler;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.RecipeHandlerRef;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
@@ -95,7 +92,7 @@ public class FavoriteRecipes {
|
||||
for (int i = 0; i < handler.numRecipes(); i++) {
|
||||
RecipeHandlerRef ref = null;
|
||||
|
||||
for (PositionedStack result : getOutputs(handler, i)) {
|
||||
for (PositionedStack result : handler.getResultStacks(i)) {
|
||||
ItemStack stack = StackInfo.getItemStackWithMinimumDamage(result.items);
|
||||
final FastKey key = new FastKey(stack);
|
||||
|
||||
@@ -130,11 +127,6 @@ public class FavoriteRecipes {
|
||||
updateSubsetVisibility();
|
||||
}
|
||||
|
||||
protected List<PositionedStack> getOutputs(IRecipeHandler handler, int recipeIndex) {
|
||||
final PositionedStack pStackResult = handler.getResultStack(recipeIndex);
|
||||
return pStackResult != null ? Collections.singletonList(pStackResult) : handler.getOtherStacks(recipeIndex);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public static final String FAVORITE_ITEM = "FavoriteItem";
|
||||
@@ -244,14 +236,7 @@ public class FavoriteRecipes {
|
||||
|
||||
if (hasErrors) {
|
||||
|
||||
try {
|
||||
Files.copy(
|
||||
favoriteFile,
|
||||
new File(favoriteFile.getAbsolutePath() + ".backup-" + System.currentTimeMillis()));
|
||||
NEIClientConfig.logger.info("Backed up invalid favorite file to {}", favoriteFile);
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to backup invalid favorite file to {}", favoriteFile, e);
|
||||
}
|
||||
NEIClientUtils.backupFile(favoriteFile);
|
||||
|
||||
save();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
package codechicken.nei;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
|
||||
final class GridOverlapScanner {
|
||||
|
||||
private static boolean scanRequested = true;
|
||||
private static boolean scanFrame = true;
|
||||
private static boolean wasShowTooltip = true;
|
||||
private static WeakReference<GuiContainer> lastGui = new WeakReference<>(null);
|
||||
|
||||
private boolean invalidated = true;
|
||||
|
||||
private final Rectangle4i rect = new Rectangle4i();
|
||||
private boolean[] checked = new boolean[0];
|
||||
private int[] queue = new int[0];
|
||||
private int tail;
|
||||
|
||||
private Predicate<Rectangle4i> isHidden;
|
||||
private boolean[] hidden;
|
||||
private int hiddenCount;
|
||||
private int left;
|
||||
private int top;
|
||||
private int slotSize;
|
||||
private int columns;
|
||||
|
||||
public static void requestScan() {
|
||||
scanRequested = true;
|
||||
}
|
||||
|
||||
public static void beginFrame(GuiContainer gui, boolean shouldShowTooltip) {
|
||||
|
||||
if (wasShowTooltip != shouldShowTooltip) {
|
||||
scanRequested = true;
|
||||
}
|
||||
|
||||
wasShowTooltip = shouldShowTooltip;
|
||||
|
||||
if (lastGui.get() != gui) {
|
||||
lastGui = new WeakReference<>(gui);
|
||||
scanRequested = true;
|
||||
}
|
||||
|
||||
scanFrame = scanRequested;
|
||||
scanRequested = false;
|
||||
}
|
||||
|
||||
public static boolean isScanFrame() {
|
||||
return scanFrame;
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
this.invalidated = true;
|
||||
}
|
||||
|
||||
public boolean shouldRefresh() {
|
||||
final boolean refresh = this.invalidated || scanFrame;
|
||||
this.invalidated = false;
|
||||
return refresh;
|
||||
}
|
||||
|
||||
public int scan(Predicate<Rectangle4i> isHidden, int left, int top, int slotSize, int rows, int columns,
|
||||
boolean seedLeft, boolean seedRight, boolean[] hidden) {
|
||||
final int size = rows * columns;
|
||||
|
||||
if (this.checked.length < size) {
|
||||
this.checked = new boolean[size];
|
||||
this.queue = new int[size];
|
||||
} else {
|
||||
Arrays.fill(this.checked, 0, size, false);
|
||||
}
|
||||
|
||||
this.isHidden = isHidden;
|
||||
this.hidden = hidden;
|
||||
this.hiddenCount = 0;
|
||||
this.tail = 0;
|
||||
this.left = left;
|
||||
this.top = top;
|
||||
this.slotSize = slotSize;
|
||||
this.columns = columns;
|
||||
|
||||
for (int r = 0; r < rows; r++) {
|
||||
if (seedLeft) {
|
||||
probe(r, 0);
|
||||
}
|
||||
if (seedRight) {
|
||||
probe(r, columns - 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (int head = 0; head < this.tail; head++) {
|
||||
final int row = this.queue[head] / columns;
|
||||
final int column = this.queue[head] % columns;
|
||||
|
||||
for (int r = Math.max(0, row - 1); r <= Math.min(rows - 1, row + 1); r++) {
|
||||
for (int c = Math.max(0, column - 1); c <= Math.min(columns - 1, column + 1); c++) {
|
||||
probe(r, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int r = 0; r < rows; r++) {
|
||||
for (int c = 0; c < columns; c++) {
|
||||
if (this.checked[r * columns + c]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int c1 = c;
|
||||
while (c1 + 1 < columns && !this.checked[r * columns + c1 + 1]) {
|
||||
c1++;
|
||||
}
|
||||
|
||||
int r1 = r;
|
||||
while (r1 + 1 < rows && isUnchecked(r1 + 1, c, c1)) {
|
||||
r1++;
|
||||
}
|
||||
|
||||
scanArea(r, r1, c, c1);
|
||||
c = c1;
|
||||
}
|
||||
}
|
||||
|
||||
this.isHidden = null;
|
||||
this.hidden = null;
|
||||
|
||||
return this.hiddenCount;
|
||||
}
|
||||
|
||||
private void probe(int row, int column) {
|
||||
final int idx = row * this.columns + column;
|
||||
|
||||
if (!this.checked[idx]) {
|
||||
this.checked[idx] = true;
|
||||
|
||||
if (test(row, row, column, column)) {
|
||||
this.hidden[idx] = true;
|
||||
this.queue[this.tail++] = idx;
|
||||
this.hiddenCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void scanArea(int r0, int r1, int c0, int c1) {
|
||||
|
||||
if (!test(r0, r1, c0, c1)) {
|
||||
for (int r = r0; r <= r1; r++) {
|
||||
Arrays.fill(this.checked, r * this.columns + c0, r * this.columns + c1 + 1, true);
|
||||
}
|
||||
} else if (r0 == r1 && c0 == c1) {
|
||||
this.checked[r0 * this.columns + c0] = true;
|
||||
this.hidden[r0 * this.columns + c0] = true;
|
||||
this.hiddenCount++;
|
||||
} else if (r1 - r0 >= c1 - c0) {
|
||||
final int mid = (r0 + r1) / 2;
|
||||
scanArea(r0, mid, c0, c1);
|
||||
scanArea(mid + 1, r1, c0, c1);
|
||||
} else {
|
||||
final int mid = (c0 + c1) / 2;
|
||||
scanArea(r0, r1, c0, mid);
|
||||
scanArea(r0, r1, mid + 1, c1);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUnchecked(int row, int c0, int c1) {
|
||||
for (int c = c0; c <= c1; c++) {
|
||||
if (this.checked[row * this.columns + c]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean test(int r0, int r1, int c0, int c1) {
|
||||
this.rect.set(
|
||||
this.left + c0 * this.slotSize,
|
||||
this.top + r0 * this.slotSize,
|
||||
(c1 - c0 + 1) * this.slotSize,
|
||||
(r1 - r0 + 1) * this.slotSize);
|
||||
return this.isHidden.test(this.rect);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import java.util.stream.IntStream;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.fluids.FluidContainerRegistry;
|
||||
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.ItemsGrid.ItemsGridSlot;
|
||||
@@ -24,6 +23,7 @@ import codechicken.nei.recipe.GuiCraftingRecipe;
|
||||
import codechicken.nei.recipe.GuiRecipe;
|
||||
import codechicken.nei.recipe.ICraftingHandler;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
import codechicken.nei.recipe.Recipe;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.recipe.RecipeInfo;
|
||||
import codechicken.nei.recipe.StackInfo;
|
||||
@@ -137,7 +137,11 @@ public class ItemCraftablesPanel
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
pendingResult.set(generateCraftables(ItemCraftablesPanel.this.pendingSnapshot));
|
||||
final CraftablesSnapshot snapshot = ItemCraftablesPanel.this.pendingSnapshot;
|
||||
|
||||
if (snapshot != null) {
|
||||
pendingResult.set(generateCraftables(snapshot));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -298,6 +302,11 @@ public class ItemCraftablesPanel
|
||||
}
|
||||
}
|
||||
|
||||
public void clearGuiReferences() {
|
||||
this.lastGuiContainer = null;
|
||||
this.pendingSnapshot = null;
|
||||
}
|
||||
|
||||
private GuiContainer getGuiContainer() {
|
||||
final GuiContainer firstGui = NEIClientUtils.getGuiContainer();
|
||||
return (firstGui instanceof GuiRecipe<?>gui) ? gui.firstGui : firstGui;
|
||||
@@ -378,48 +387,19 @@ public class ItemCraftablesPanel
|
||||
}
|
||||
|
||||
private static ItemStack getCheapResultItem(IRecipeHandler handler, int recipeIndex) {
|
||||
final PositionedStack resultStack = handler.getResultStack(recipeIndex);
|
||||
|
||||
if (resultStack != null) {
|
||||
return resultStack.item;
|
||||
}
|
||||
|
||||
final List<PositionedStack> otherStacks = handler.getOtherStacks(recipeIndex);
|
||||
|
||||
for (PositionedStack otherStack : otherStacks) {
|
||||
if (!FluidContainerRegistry.isContainer(otherStack.items[0])
|
||||
|| StackInfo.getFluid(otherStack.items[0]) != null) {
|
||||
return otherStack.item;
|
||||
}
|
||||
}
|
||||
|
||||
return otherStacks.isEmpty() ? null : otherStacks.get(0).item;
|
||||
final PositionedStack result = Recipe
|
||||
.getMainResult(handler.getResultStacks(recipeIndex), pStack -> pStack.items[0]);
|
||||
return result != null ? result.item : null;
|
||||
}
|
||||
|
||||
private static ItemStack getCheapResult(IRecipeHandler handler, int recipeIndex) {
|
||||
final PositionedStack resultStack = handler.getResultStack(recipeIndex);
|
||||
final List<PositionedStack> results = resultStack != null ? Collections.singletonList(resultStack)
|
||||
: handler.getOtherStacks(recipeIndex);
|
||||
final List<PositionedStack> results = handler.getResultStacks(recipeIndex);
|
||||
|
||||
if (results.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ItemStack stack = null;
|
||||
|
||||
if (results.size() > 1) {
|
||||
for (PositionedStack result : results) {
|
||||
if (!FluidContainerRegistry.isContainer(result.item) || StackInfo.getFluid(result.item) != null) {
|
||||
stack = result.item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stack == null) {
|
||||
stack = results.get(0).item;
|
||||
}
|
||||
|
||||
final ItemStack stack = Recipe.getMainResult(results, pStack -> pStack.items[0]).item;
|
||||
int stackSize = 0;
|
||||
|
||||
for (PositionedStack result : results) {
|
||||
|
||||
@@ -207,6 +207,33 @@ public class ItemList {
|
||||
return filters;
|
||||
}
|
||||
|
||||
public static ItemStack[] expandPermutations(ItemStack[] items) {
|
||||
List<ItemStack> stacks = new ArrayList<>();
|
||||
for (ItemStack item : items) {
|
||||
if (item == null || item.getItem() == null) continue;
|
||||
|
||||
if (item.getItemDamage() == Short.MAX_VALUE) {
|
||||
List<ItemStack> permutations = itemMap.get(item.getItem());
|
||||
if (!permutations.isEmpty()) {
|
||||
for (ItemStack stack : permutations) {
|
||||
ItemStack toAdd = stack.copy();
|
||||
toAdd.stackSize = item.stackSize;
|
||||
stacks.add(toAdd);
|
||||
}
|
||||
} else {
|
||||
ItemStack base = new ItemStack(item.getItem(), item.stackSize);
|
||||
base.stackTagCompound = item.stackTagCompound;
|
||||
stacks.add(base);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
stacks.add(item.copy());
|
||||
}
|
||||
|
||||
return stacks.toArray(new ItemStack[0]);
|
||||
}
|
||||
|
||||
public static ForkJoinPool forkJoinPool;
|
||||
|
||||
static {
|
||||
|
||||
@@ -36,7 +36,6 @@ import cpw.mods.fml.common.FMLLog;
|
||||
public class ItemListLoader {
|
||||
|
||||
private static final HashSet<Item> erroredItems = new HashSet<>();
|
||||
private static final HashSet<String> stackTraces = new HashSet<>();
|
||||
private static Map<ItemStack, Integer> ordering = new HashMap<>();
|
||||
|
||||
private ItemListLoader() {}
|
||||
@@ -60,11 +59,10 @@ public class ItemListLoader {
|
||||
} catch (TimeoutException t) {
|
||||
throw t;
|
||||
} catch (Throwable t) {
|
||||
NEIServerUtils.logOnce(
|
||||
t,
|
||||
stackTraces,
|
||||
NEIClientUtils.errorOnce(
|
||||
"ItemListLoader: " + item.toString(),
|
||||
"Ommiting " + item + ":" + damage + " " + item.getClass().getSimpleName(),
|
||||
item.toString());
|
||||
t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,14 +118,7 @@ public class ItemSorter implements Comparator<ItemStack> {
|
||||
return name1.compareTo(name2);
|
||||
});
|
||||
tag.getTag("inventory.itemsort").setDefaultValue(getSaveString(list));
|
||||
API.addOption(new OptionOpenGui("inventory.itemsort", GuiItemSorter.class) {
|
||||
|
||||
@Override
|
||||
public void useGlobals() {
|
||||
super.useGlobals();
|
||||
list = fromSaveString(activeTag().getValue());
|
||||
}
|
||||
});
|
||||
API.addOption(new OptionOpenGui("inventory.itemsort", GuiItemSorter.class));
|
||||
}
|
||||
|
||||
public static String getSaveString(List<SortEntry> list) {
|
||||
|
||||
@@ -127,7 +127,12 @@ public class ItemZoom extends Widget implements IContainerInputHandler {
|
||||
this.displayName = "Unnamed";
|
||||
}
|
||||
|
||||
this.stack = StackInfo.loadFromNBT(StackInfo.itemStackToNBT(stack), 0);
|
||||
// Copying the stack copies its whole NBT, so it is only done when the hovered stack changes
|
||||
final boolean sameStack = this.stack != null && this.stack.isItemEqual(stack)
|
||||
&& ItemStack.areItemStackTagsEqual(this.stack, stack);
|
||||
if (!sameStack) {
|
||||
this.stack = StackInfo.withAmount(stack, 0);
|
||||
}
|
||||
} else {
|
||||
this.stack = null;
|
||||
this.displayName = "";
|
||||
|
||||
@@ -282,6 +282,8 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
|
||||
|
||||
protected boolean[] invalidSlotMap;
|
||||
|
||||
private final GridOverlapScanner overlapScanner = new GridOverlapScanner();
|
||||
|
||||
protected ScreenCapture screenCapture = null;
|
||||
|
||||
public ArrayList<ItemStack> getItems() {
|
||||
@@ -359,12 +361,13 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
|
||||
width = newWidth;
|
||||
height = newHeight;
|
||||
|
||||
columns = width / SLOT_SIZE;
|
||||
rows = height / SLOT_SIZE;
|
||||
this.columns = newWidth / SLOT_SIZE;
|
||||
this.rows = newHeight / SLOT_SIZE;
|
||||
|
||||
paddingLeft = (width % SLOT_SIZE) / 2;
|
||||
|
||||
if (changed) {
|
||||
this.overlapScanner.invalidate();
|
||||
onGridChanged();
|
||||
}
|
||||
}
|
||||
@@ -405,55 +408,42 @@ public abstract class ItemsGrid<T extends ItemsGrid.ItemsGridSlot, M extends Ite
|
||||
}
|
||||
|
||||
public void refresh(GuiContainer gui) {
|
||||
final int gridRenderingCacheMode = getGridRenderingCacheMode();
|
||||
if (gridRenderingCacheMode <= 0 || screenCapture == null || screenCapture.needRefresh(gridRenderingCacheMode)) {
|
||||
if (this.overlapScanner.shouldRefresh()) {
|
||||
updateGuiOverlapSlots(gui);
|
||||
}
|
||||
shiftPage(0);
|
||||
}
|
||||
|
||||
protected void updateGuiOverlapSlots(GuiContainer gui) {
|
||||
final boolean[] oldSlotMap = invalidSlotMap;
|
||||
final int oldRows = rows;
|
||||
final int oldColumns = columns;
|
||||
final boolean[] oldSlotMap = this.invalidSlotMap;
|
||||
final int size = this.rows * this.columns;
|
||||
final boolean[] slotMap = new boolean[size];
|
||||
|
||||
invalidSlotMap = new boolean[rows * columns];
|
||||
perPage = columns * rows;
|
||||
this.perPage = size;
|
||||
|
||||
if (gui != null) {
|
||||
if (gui != null && size > 0) {
|
||||
final INEIGuiHandler[] handlers = GuiInfo.getGuiHandlersSnapshot();
|
||||
if (NEIClientConfig.optimizeGuiOverlapComputation()) {
|
||||
checkGuiOverlap(gui, handlers, 0, columns - 2, 1);
|
||||
checkGuiOverlap(gui, handlers, columns - 1, 1, -1);
|
||||
} else {
|
||||
checkGuiOverlap(gui, handlers, 0, columns, 1);
|
||||
}
|
||||
final Rectangle4i origin = getSlotRect(0, 0);
|
||||
|
||||
this.perPage -= this.overlapScanner.scan(
|
||||
rect -> GuiInfo.hideItemPanelSlot(gui, rect, handlers),
|
||||
origin.x,
|
||||
origin.y,
|
||||
SLOT_SIZE,
|
||||
this.rows,
|
||||
this.columns,
|
||||
origin.x + this.columns * SLOT_SIZE > gui.guiLeft,
|
||||
origin.x < gui.guiLeft + gui.xSize,
|
||||
slotMap);
|
||||
}
|
||||
|
||||
if (oldRows != rows || oldColumns != columns || !Arrays.equals(oldSlotMap, invalidSlotMap)) {
|
||||
this.invalidSlotMap = slotMap;
|
||||
|
||||
if (!Arrays.equals(oldSlotMap, slotMap)) {
|
||||
onGridChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkGuiOverlap(GuiContainer gui, INEIGuiHandler[] handlers, int start, int end, int dir) {
|
||||
boolean validColumn = false;
|
||||
|
||||
for (int c = start; c != end && (!NEIClientConfig.optimizeGuiOverlapComputation() || !validColumn); c += dir) {
|
||||
validColumn = true;
|
||||
|
||||
for (int r = 0; r < rows; r++) {
|
||||
final int idx = columns * r + c;
|
||||
if (idx >= 0 && idx < invalidSlotMap.length
|
||||
&& !invalidSlotMap[idx]
|
||||
&& GuiInfo.hideItemPanelSlot(gui, getSlotRect(r, c), handlers)) {
|
||||
invalidSlotMap[idx] = true;
|
||||
validColumn = false;
|
||||
perPage--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public T getSlotMouseOver(int mousex, int mousey) {
|
||||
if (!contains(mousex, mousey)) {
|
||||
return null;
|
||||
|
||||
@@ -388,6 +388,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
}
|
||||
|
||||
public static void layout(GuiContainer gui) {
|
||||
GridOverlapScanner.beginFrame(gui, GuiContainerManager.shouldShowTooltip(gui));
|
||||
|
||||
VisiblityData visiblity = new VisiblityData();
|
||||
visiblity.showNEI = !isHidden();
|
||||
visiblity.showBookmarkPanel = !isBookmarkPanelHidden();
|
||||
@@ -445,14 +447,14 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
if (!rightclick) {
|
||||
if (Keyboard.getEventKeyState() && getIsAccessibleControlEventKey()
|
||||
&& NEIClientConfig.canChangeCheatMode()) {
|
||||
NEIClientConfig.cycleSetting("inventory.cheatmode", 3);
|
||||
NEIClientConfig.setCheatMode((NEIClientConfig.getCheatMode() + 1) % 3);
|
||||
} else {
|
||||
if (Keyboard.getEventKeyState() && (Keyboard.getEventKey() == Keyboard.KEY_LSHIFT
|
||||
|| Keyboard.getEventKey() == Keyboard.KEY_RSHIFT)) {
|
||||
GuiRecipeTab.loadHandlerInfo();
|
||||
RecipeCatalysts.loadCatalystInfo();
|
||||
}
|
||||
getOptionList().openGui(getGuiContainer(), false);
|
||||
getOptionList().openGui(getGuiContainer());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -821,6 +823,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
|
||||
|
||||
if (!isEnabled()) return;
|
||||
|
||||
GridOverlapScanner.requestScan();
|
||||
AutoFocusWidget.instance.guiTick();
|
||||
|
||||
for (Widget widget : drawWidgets) widget.update();
|
||||
|
||||
@@ -15,6 +15,7 @@ import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.ChatComponentTranslation;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.world.storage.SaveFormatComparator;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
@@ -43,7 +44,9 @@ import codechicken.nei.config.GuiHighlightTips;
|
||||
import codechicken.nei.config.GuiNEIOptionList;
|
||||
import codechicken.nei.config.GuiOptionList;
|
||||
import codechicken.nei.config.GuiPanelSettings;
|
||||
import codechicken.nei.config.OptionButton;
|
||||
import codechicken.nei.config.OptionCycled;
|
||||
import codechicken.nei.config.OptionExportConfig;
|
||||
import codechicken.nei.config.OptionGamemodes;
|
||||
import codechicken.nei.config.OptionIntegerField;
|
||||
import codechicken.nei.config.OptionList;
|
||||
@@ -54,7 +57,6 @@ import codechicken.nei.config.OptionToggleButtonBoubs;
|
||||
import codechicken.nei.config.OptionUtilities;
|
||||
import codechicken.nei.config.preset.GuiPresetList;
|
||||
import codechicken.nei.event.NEIConfigsLoadedEvent;
|
||||
import codechicken.nei.recipe.GuiRecipeTab;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
import codechicken.nei.recipe.InformationHandler;
|
||||
import codechicken.nei.recipe.RecipeCatalysts;
|
||||
@@ -67,6 +69,7 @@ public class NEIClientConfig {
|
||||
private static boolean pluginNEIConfigLoaded;
|
||||
private static boolean enabledOverride;
|
||||
private static String worldPath;
|
||||
private static final String CHEAT_MODE_KEY = "cheatmode";
|
||||
|
||||
public static Logger logger = LogManager.getLogger("NotEnoughItems");
|
||||
public static File configDir = new File(CommonUtils.getMinecraftDir(), "config/NEI/");
|
||||
@@ -155,6 +158,16 @@ public class NEIClientConfig {
|
||||
.getIntValue(-1);
|
||||
API.addOption(new OptionCycled("inventory.cheatmode", 3) {
|
||||
|
||||
@Override
|
||||
public int value() {
|
||||
return getCheatMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(int value) {
|
||||
setCheatMode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean optionValid(int index) {
|
||||
return getLockedMode() == -1 || getLockedMode() == index && NEIInfo.isValidMode(index);
|
||||
@@ -243,10 +256,6 @@ public class NEIClientConfig {
|
||||
.getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.cycledIngredientsTooltip", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.creativeTabStyle").setComment("Creative or JEI style tabs")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.guirecipe.creativeTabStyle", true));
|
||||
|
||||
tag.getTag("inventory.guirecipe.itemPresenceOverlay").setComment("Item presence overlay on ?-hover")
|
||||
.getIntValue(1);
|
||||
API.addOption(new OptionCycled("inventory.guirecipe.itemPresenceOverlay", 3, true));
|
||||
@@ -489,10 +498,6 @@ public class NEIClientConfig {
|
||||
tag.getTag("inventory.showItemQuantityWidget").setComment("Show Item Quantity Widget").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.showItemQuantityWidget", true));
|
||||
|
||||
tag.getTag("inventory.optimize_gui_overlap_computation").setComment("Optimize computation for GUI overlap")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("inventory.optimize_gui_overlap_computation", true));
|
||||
|
||||
tag.getTag("inventory.autocrafting").setComment("Autocrafting").getBooleanValue(true);
|
||||
API.addOption(new OptionToggleButton("inventory.autocrafting", true));
|
||||
|
||||
@@ -514,29 +519,32 @@ public class NEIClientConfig {
|
||||
|
||||
});
|
||||
|
||||
tag.getTag("tools.handler_load_from_config").setComment("ADVANCED: Load handlers from config")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("tools.handler_load_from_config", true) {
|
||||
API.addOption(
|
||||
new OptionButton(
|
||||
"tools.export_configs.all",
|
||||
"tools.export_configs.all",
|
||||
null,
|
||||
"tools.export_configs.all.tip") {
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
super.onClick(button);
|
||||
GuiRecipeTab.loadHandlerInfo();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public String getButtonText() {
|
||||
return translateN("tools.export_configs.button");
|
||||
}
|
||||
|
||||
tag.getTag("tools.catalyst_load_from_config").setComment("ADVANCED: Load catalysts from config")
|
||||
.getBooleanValue(false);
|
||||
API.addOption(new OptionToggleButton("tools.catalyst_load_from_config", true) {
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
int exported = 0;
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
super.onClick(button);
|
||||
RecipeCatalysts.loadCatalystInfo();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (String resource : ClientHandler.DEFAULT_CONFIGS) {
|
||||
if (ClientHandler.exportDefaultConfig(resource)) exported++;
|
||||
}
|
||||
|
||||
NEIClientUtils.printChatMessage(
|
||||
new ChatComponentTranslation("nei.options.tools.export_configs.all.done", exported));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
ClientHandler.DEFAULT_CONFIGS.forEach(fileName -> API.addOption(new OptionExportConfig(fileName)));
|
||||
|
||||
setDefaultKeyBindings();
|
||||
}
|
||||
@@ -545,23 +553,18 @@ public class NEIClientConfig {
|
||||
OptionList.setOptionList(new OptionList("nei.options") {
|
||||
|
||||
@Override
|
||||
public ConfigSet globalConfigSet() {
|
||||
public ConfigSet configSet() {
|
||||
return global;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigSet worldConfigSet() {
|
||||
return world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionList configBase() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuiOptionList getGui(GuiScreen parent, OptionList list, boolean world) {
|
||||
return new GuiNEIOptionList(parent, list, world);
|
||||
public GuiOptionList getGui(GuiScreen parent, OptionList list) {
|
||||
return new GuiNEIOptionList(parent, list);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -928,15 +931,15 @@ public class NEIClientConfig {
|
||||
specificDir.mkdirs();
|
||||
}
|
||||
|
||||
world = new ConfigSet(new File(specificDir, "NEI.dat"), new ConfigFile(new File(specificDir, "NEI.cfg")));
|
||||
world = new ConfigSet(new File(specificDir, "NEI.dat"));
|
||||
|
||||
if (newWorld && Minecraft.getMinecraft().isSingleplayer() && getLockedMode() == -1) {
|
||||
final int globalMode = global.config.getTag("inventory.cheatmode").getIntValue();
|
||||
final int globalMode = getCheatMode();
|
||||
final int worldMode = Math
|
||||
.min(globalMode, NEIClientUtils.mc().playerController.isInCreativeMode() ? 2 : 0);
|
||||
|
||||
if (worldMode != globalMode) {
|
||||
world.config.getTag("inventory.cheatmode").setIntValue(worldMode);
|
||||
setCheatMode(worldMode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -950,9 +953,6 @@ public class NEIClientConfig {
|
||||
}
|
||||
|
||||
private static void onWorldLoad() {
|
||||
world.config.setComment(
|
||||
"World based configuration of NEI.\nMost of these options can be changed ingame.\nDeleting any element will restore it to it's default value");
|
||||
|
||||
setWorldDefaults();
|
||||
creativeInv = new ItemStack[54];
|
||||
LayoutManager.searchField.setText(getSearchExpression());
|
||||
@@ -1058,14 +1058,8 @@ public class NEIClientConfig {
|
||||
|
||||
}
|
||||
|
||||
public static boolean isWorldSpecific(String setting) {
|
||||
if (world == null) return false;
|
||||
ConfigTag tag = world.config.getTag(setting, false);
|
||||
return tag != null && tag.value != null;
|
||||
}
|
||||
|
||||
public static ConfigTag getSetting(String s) {
|
||||
return isWorldSpecific(s) ? world.config.getTag(s) : global.config.getTag(s);
|
||||
return global.config.getTag(s);
|
||||
}
|
||||
|
||||
public static boolean getBooleanSetting(String s) {
|
||||
@@ -1154,10 +1148,6 @@ public class NEIClientConfig {
|
||||
return getIntSetting("inventory.guirecipe.jeiStyleRecipeCatalyst");
|
||||
}
|
||||
|
||||
public static boolean useCreativeTabStyle() {
|
||||
return getBooleanSetting("inventory.guirecipe.creativeTabStyle");
|
||||
}
|
||||
|
||||
public static boolean ignorePotionOverlap() {
|
||||
return getBooleanSetting("inventory.bookmarks.ignorePotionOverlap");
|
||||
}
|
||||
@@ -1166,10 +1156,6 @@ public class NEIClientConfig {
|
||||
return getBooleanSetting("inventory.bookmarks.craftingTreeZoomWithoutModifier");
|
||||
}
|
||||
|
||||
public static boolean optimizeGuiOverlapComputation() {
|
||||
return getBooleanSetting("inventory.optimize_gui_overlap_computation");
|
||||
}
|
||||
|
||||
public static boolean showCycledIngredientsTooltip() {
|
||||
return getBooleanSetting("inventory.guirecipe.cycledIngredientsTooltip");
|
||||
}
|
||||
@@ -1190,14 +1176,6 @@ public class NEIClientConfig {
|
||||
return mainNEIConfigLoaded && pluginNEIConfigLoaded;
|
||||
}
|
||||
|
||||
public static boolean loadHandlersFromJar() {
|
||||
return !getBooleanSetting("tools.handler_load_from_config");
|
||||
}
|
||||
|
||||
public static boolean loadCatalystsFromJar() {
|
||||
return !getBooleanSetting("tools.catalyst_load_from_config");
|
||||
}
|
||||
|
||||
public static boolean isProfileRecipeEnabled() {
|
||||
return NEIClientConfig.getBooleanSetting("inventory.guirecipe.profile");
|
||||
}
|
||||
@@ -1211,12 +1189,18 @@ public class NEIClientConfig {
|
||||
}
|
||||
|
||||
public static int getCheatMode() {
|
||||
if (world != null && world.nbt.hasKey(CHEAT_MODE_KEY)) return world.nbt.getInteger(CHEAT_MODE_KEY);
|
||||
return getIntSetting("inventory.cheatmode");
|
||||
}
|
||||
|
||||
public static void setCheatMode(int mode) {
|
||||
if (world != null) world.nbt.setInteger(CHEAT_MODE_KEY, mode);
|
||||
else setIntSetting("inventory.cheatmode", mode);
|
||||
}
|
||||
|
||||
public static boolean canChangeCheatMode() {
|
||||
if (getLockedMode() != -1) {
|
||||
setIntSetting("inventory.cheatmode", getLockedMode());
|
||||
setCheatMode(getLockedMode());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,12 @@ import static codechicken.nei.NEIClientConfig.invCreativeMode;
|
||||
import static codechicken.nei.NEIClientConfig.world;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.math.RoundingMode;
|
||||
import java.nio.file.Files;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.MessageFormat;
|
||||
@@ -26,6 +29,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -64,6 +68,8 @@ import codechicken.nei.util.NEIKeyboardUtils;
|
||||
|
||||
public class NEIClientUtils extends NEIServerUtils {
|
||||
|
||||
private static final Set<String> REPORTED = ConcurrentHashMap.newKeySet();
|
||||
|
||||
public static class Alignment {
|
||||
|
||||
public final int x, y;
|
||||
@@ -639,4 +645,29 @@ public class NEIClientUtils extends NEIServerUtils {
|
||||
if (!isAlphaTest) GL11.glDisable(GL11.GL_ALPHA_TEST);
|
||||
}
|
||||
|
||||
public static void errorOnce(String key, String message, Throwable error) {
|
||||
if (REPORTED.add(key)) {
|
||||
NEIClientConfig.logger.error(message, error);
|
||||
}
|
||||
}
|
||||
|
||||
public static void warnOnce(String key, String message) {
|
||||
if (REPORTED.add(key)) {
|
||||
NEIClientConfig.logger.warn(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean backupFile(File file) {
|
||||
final File backup = new File(file.getAbsolutePath() + ".backup-" + System.currentTimeMillis());
|
||||
|
||||
try {
|
||||
Files.copy(file.toPath(), backup.toPath());
|
||||
NEIClientConfig.logger.info("Backed up file {} to {}", file, backup);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to backup file {} to {}", file, backup, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,12 +4,9 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.zip.ZipException;
|
||||
|
||||
@@ -509,20 +506,6 @@ public class NEIServerUtils {
|
||||
return sb;
|
||||
}
|
||||
|
||||
public static void logOnce(Throwable t, Set<String> stackTraces, String message) {
|
||||
logOnce(t, stackTraces, message, "");
|
||||
}
|
||||
|
||||
public static void logOnce(Throwable t, Set<String> stackTraces, String message, String identifier) {
|
||||
StringWriter sw = new StringWriter();
|
||||
t.printStackTrace(new PrintWriter(sw));
|
||||
String stackTrace = identifier + sw.toString();
|
||||
if (!stackTraces.contains(stackTrace)) {
|
||||
NEIServerConfig.logger.error(message, t);
|
||||
stackTraces.add(stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
public static ItemStack getModdedItem(String itemId, String nbtString) {
|
||||
int meta = -1;
|
||||
ItemStack itemStack;
|
||||
|
||||
@@ -29,6 +29,9 @@ public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ?
|
||||
|
||||
protected T grid;
|
||||
|
||||
private int headerPaddingLeft;
|
||||
private int headerPaddingRight;
|
||||
|
||||
public ArrayList<ItemStack> getItems() {
|
||||
return this.grid.getItems();
|
||||
}
|
||||
@@ -105,26 +108,15 @@ public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ?
|
||||
|
||||
protected int resizeHeader(GuiContainer gui) {
|
||||
final int BUTTON_SIZE = 16;
|
||||
int paddingLeft = 0;
|
||||
int paddingRight = 0;
|
||||
|
||||
while (paddingLeft < w && GuiInfo.hideItemPanelSlot(
|
||||
gui,
|
||||
new Rectangle4i(x + paddingLeft, y, ItemsGrid.SLOT_SIZE, ItemsGrid.SLOT_SIZE))) {
|
||||
paddingLeft += ItemsGrid.SLOT_SIZE;
|
||||
if (GridOverlapScanner.isScanFrame()) {
|
||||
updateHeaderPadding(gui);
|
||||
}
|
||||
|
||||
while (paddingRight < w && GuiInfo.hideItemPanelSlot(
|
||||
gui,
|
||||
new Rectangle4i(
|
||||
x + w - paddingRight - ItemsGrid.SLOT_SIZE,
|
||||
y,
|
||||
ItemsGrid.SLOT_SIZE,
|
||||
ItemsGrid.SLOT_SIZE))) {
|
||||
paddingRight += ItemsGrid.SLOT_SIZE;
|
||||
}
|
||||
final int paddingLeft = this.headerPaddingLeft;
|
||||
final int paddingRight = this.headerPaddingRight;
|
||||
|
||||
if (paddingLeft + paddingRight >= w) {
|
||||
if (paddingLeft + paddingRight >= this.w) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -132,16 +124,35 @@ public abstract class PanelWidget<T extends ItemsGrid<? extends ItemsGridSlot, ?
|
||||
pagePrev.h = pageNext.h = BUTTON_SIZE;
|
||||
pagePrev.y = pageNext.y = y;
|
||||
|
||||
pagePrev.x = x + paddingLeft;
|
||||
pageNext.x = x + w - pageNext.w - paddingRight;
|
||||
pagePrev.x = this.x + paddingLeft;
|
||||
pageNext.x = this.x + this.w - pageNext.w - paddingRight;
|
||||
|
||||
pageLabel.x = x + paddingLeft + (w - paddingLeft - paddingRight) / 2;
|
||||
pageLabel.y = y + 5;
|
||||
pageLabel.x = this.x + paddingLeft + (this.w - paddingLeft - paddingRight) / 2;
|
||||
pageLabel.y = this.y + 5;
|
||||
pageLabel.text = getLabelText();
|
||||
|
||||
return BUTTON_SIZE + 2;
|
||||
}
|
||||
|
||||
private void updateHeaderPadding(GuiContainer gui) {
|
||||
final INEIGuiHandler[] handlers = GuiInfo.getGuiHandlersSnapshot();
|
||||
final Rectangle4i slot = new Rectangle4i(this.x, this.y, ItemsGrid.SLOT_SIZE, ItemsGrid.SLOT_SIZE);
|
||||
this.headerPaddingLeft = 0;
|
||||
this.headerPaddingRight = 0;
|
||||
|
||||
while (this.headerPaddingLeft < this.w && GuiInfo.hideItemPanelSlot(gui, slot, handlers)) {
|
||||
this.headerPaddingLeft += ItemsGrid.SLOT_SIZE;
|
||||
slot.x += ItemsGrid.SLOT_SIZE;
|
||||
}
|
||||
|
||||
slot.x = this.x + this.w - ItemsGrid.SLOT_SIZE;
|
||||
|
||||
while (this.headerPaddingRight < this.w && GuiInfo.hideItemPanelSlot(gui, slot, handlers)) {
|
||||
this.headerPaddingRight += ItemsGrid.SLOT_SIZE;
|
||||
slot.x -= ItemsGrid.SLOT_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract int resizeFooter(GuiContainer gui);
|
||||
|
||||
public void setVisible() {
|
||||
|
||||
@@ -14,12 +14,8 @@ import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.drawable.DrawableBuilder;
|
||||
import codechicken.nei.drawable.DrawableResource;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.item.FluidDrawer;
|
||||
import codechicken.nei.item.FluidDrawer.FillDirection;
|
||||
@@ -70,31 +66,11 @@ public class PositionedStack implements Cloneable {
|
||||
public void generatePermutations() {
|
||||
if (permutated) return;
|
||||
|
||||
List<ItemStack> stacks = new ArrayList<>();
|
||||
for (ItemStack item : items) {
|
||||
if (item == null || item.getItem() == null) continue;
|
||||
items = ItemList.expandPermutations(items);
|
||||
|
||||
if (item.getItemDamage() == Short.MAX_VALUE) {
|
||||
List<ItemStack> permutations = ItemList.itemMap.get(item.getItem());
|
||||
if (!permutations.isEmpty()) {
|
||||
for (ItemStack stack : permutations) {
|
||||
ItemStack toAdd = stack.copy();
|
||||
toAdd.stackSize = item.stackSize;
|
||||
stacks.add(toAdd);
|
||||
}
|
||||
} else {
|
||||
ItemStack base = new ItemStack(item.getItem(), item.stackSize);
|
||||
base.stackTagCompound = item.stackTagCompound;
|
||||
stacks.add(base);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
stacks.add(item.copy());
|
||||
if (items.length == 0) {
|
||||
items = new ItemStack[] { new ItemStack(Blocks.fire) };
|
||||
}
|
||||
items = stacks.toArray(new ItemStack[0]);
|
||||
|
||||
if (items.length == 0) items = new ItemStack[] { new ItemStack(Blocks.fire) };
|
||||
|
||||
permutated = true;
|
||||
setPermutationToRender(0);
|
||||
@@ -263,7 +239,6 @@ public class PositionedStack implements Cloneable {
|
||||
protected int capacity = 0;
|
||||
protected boolean flowingTexture = false;
|
||||
protected FillDirection fillDirection = FillDirection.AUTO;
|
||||
protected DrawableResource overlay;
|
||||
|
||||
private ItemStack cachedFluidItem;
|
||||
private FluidStack cachedFluidStack;
|
||||
@@ -310,19 +285,6 @@ public class PositionedStack implements Cloneable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public DrawableResource getOverlay() {
|
||||
return this.overlay;
|
||||
}
|
||||
|
||||
public Tank setOverlay(String resourceLocation, int u, int v, int width, int height) {
|
||||
return setOverlay(new DrawableBuilder(resourceLocation, u, v, width, height).build());
|
||||
}
|
||||
|
||||
public Tank setOverlay(DrawableResource overlay) {
|
||||
this.overlay = overlay;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected FluidStack getFluidStack() {
|
||||
|
||||
if (this.item != this.cachedFluidItem) {
|
||||
@@ -339,7 +301,7 @@ public class PositionedStack implements Cloneable {
|
||||
final List<String> customTooltip = super.getTooltip();
|
||||
final FluidStack fluidStack = getFluidStack();
|
||||
|
||||
if (fluidStack != null) {
|
||||
if (fluidStack != null && this.capacity > 0) {
|
||||
tooltip.add(
|
||||
EnumChatFormatting.GRAY + NEIClientUtils
|
||||
.translate("recipe.fluid.tank.amount", NEIClientUtils.formatFluid(fluidStack.amount)));
|
||||
@@ -370,15 +332,6 @@ public class PositionedStack implements Cloneable {
|
||||
fluidStack,
|
||||
this.flowingTexture,
|
||||
this.fillDirection);
|
||||
|
||||
if (this.overlay != null) {
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
this.overlay.draw(this.relx, this.rely);
|
||||
GL11.glEnable(GL11.GL_LIGHTING);
|
||||
GL11.glDisable(GL11.GL_BLEND);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,19 +89,19 @@ public class PresetsList {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PositionedStack result = handler.getResultStack(recipeIndex);
|
||||
final List<PositionedStack> outputs = handler.getResultStacks(recipeIndex);
|
||||
|
||||
if (result != null && matchPositionedStack(result)) {
|
||||
if (matchPositionedStack(outputs, true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final List<PositionedStack> others = handler.getOtherStacks(recipeIndex);
|
||||
final List<PositionedStack> auxiliaries = handler.getAuxiliaryStacks(recipeIndex);
|
||||
|
||||
if (!others.isEmpty() && matchPositionedStack(others, true)) {
|
||||
if (matchPositionedStack(auxiliaries, true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return result == null && others.isEmpty();
|
||||
return outputs.isEmpty() && auxiliaries.isEmpty();
|
||||
}
|
||||
|
||||
private boolean matchPositionedStack(List<PositionedStack> items, boolean dir) {
|
||||
|
||||
@@ -24,7 +24,13 @@ public abstract class RecipeSearchField extends TextField implements ItemFilterP
|
||||
field.setMaxStringLength(maxSearchLength);
|
||||
field.setCursorPositionZero();
|
||||
field.setSkipRecipeTokens(true);
|
||||
((SearchTextFormatter) field.getFormatter()).setContextToken("<>");
|
||||
field.setFormatter(new SearchTextFormatter(SearchField.searchParser) {
|
||||
|
||||
@Override
|
||||
protected String getContextToken() {
|
||||
return this.searchParser.getRecipeContextTokens();
|
||||
}
|
||||
});
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,10 @@ public class SearchTextFormatter implements TextFormatter {
|
||||
this.contextToken = contextToken;
|
||||
}
|
||||
|
||||
protected String getContextToken() {
|
||||
return this.contextToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(String text) {
|
||||
final int patternMode = NEIClientConfig.getIntSetting("inventory.search.patternMode");
|
||||
@@ -32,13 +36,14 @@ public class SearchTextFormatter implements TextFormatter {
|
||||
return SearchExpressionUtils.visitRecipeSearchExpression(text, visitor);
|
||||
} else {
|
||||
final StringBuilder formattedText = new StringBuilder();
|
||||
final String contextToken = getContextToken();
|
||||
|
||||
for (String[] orQuery : searchParser.splitByDelimiters(text, "|", false)) {
|
||||
final String filterText = orQuery[1];
|
||||
|
||||
formattedText.append(SearchExpressionUtils.HIGHLIGHTS.OR + orQuery[0]);
|
||||
|
||||
for (String[] contextPart : searchParser.splitByDelimiters(filterText, this.contextToken, false)) {
|
||||
for (String[] contextPart : searchParser.splitByDelimiters(filterText, contextToken, false)) {
|
||||
|
||||
if (!contextPart[0].isEmpty()) {
|
||||
formattedText.append(
|
||||
@@ -74,7 +79,11 @@ public class SearchTextFormatter implements TextFormatter {
|
||||
formattedText.append(SearchExpressionUtils.HIGHLIGHTS.QUOTED + "\"");
|
||||
}
|
||||
|
||||
if (!token.rawText.isEmpty()) {
|
||||
if (patternMode == 1 && !token.quotes && isRegexToken(token.rawText)) {
|
||||
formattedText.append(SearchExpressionUtils.HIGHLIGHTS.REGEX + token.rawText.substring(0, 2))
|
||||
.append(tokenColor + token.rawText.substring(2, token.rawText.length() - 1))
|
||||
.append(SearchExpressionUtils.HIGHLIGHTS.REGEX + "/");
|
||||
} else if (!token.rawText.isEmpty()) {
|
||||
formattedText.append(tokenColor + token.rawText);
|
||||
}
|
||||
|
||||
@@ -93,4 +102,8 @@ public class SearchTextFormatter implements TextFormatter {
|
||||
return formattedText.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isRegexToken(String search) {
|
||||
return search.length() >= 3 && search.regionMatches(true, 0, "r/", 0, 2) && search.endsWith("/");
|
||||
}
|
||||
}
|
||||
@@ -194,6 +194,7 @@ public class SearchTokenParser {
|
||||
if (patternMode != 3) {
|
||||
return this.filtersCache.computeIfAbsent(skipRecipeTokens + ":" + filterText, _t -> {
|
||||
final List<ItemFilter> searchTokens = new ArrayList<>();
|
||||
final String contextTokens = skipRecipeTokens ? getRecipeContextTokens() : "";
|
||||
|
||||
for (String[] subQuery : splitByDelimiters(filterText, "|", false)) {
|
||||
|
||||
@@ -203,9 +204,10 @@ public class SearchTokenParser {
|
||||
|
||||
final List<ItemFilter> tokens = new ArrayList<>();
|
||||
|
||||
for (String[] contextQuery : splitByDelimiters(subQuery[1], skipRecipeTokens ? "<>" : "", false)) {
|
||||
for (String[] contextQuery : splitByDelimiters(subQuery[1], contextTokens, false)) {
|
||||
|
||||
if (contextQuery[1].isEmpty() || contextQuery[0].startsWith(">")) {
|
||||
if (contextQuery[1].isEmpty() || contextQuery[0].startsWith(">")
|
||||
|| contextQuery[0].startsWith("^")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -277,7 +279,7 @@ public class SearchTokenParser {
|
||||
|
||||
final List<IRecipeFilter> contextList = new ArrayList<>();
|
||||
|
||||
for (String[] contextQuery : splitByDelimiters(orQueryPart[1], "<>", false)) {
|
||||
for (String[] contextQuery : splitByDelimiters(orQueryPart[1], getRecipeContextTokens(), false)) {
|
||||
|
||||
if (contextQuery[1].isEmpty()) {
|
||||
continue;
|
||||
@@ -436,7 +438,9 @@ public class SearchTokenParser {
|
||||
|
||||
final List<String[]> tokens = new ArrayList<>();
|
||||
final int length = input.length();
|
||||
final boolean regexTokens = NEIClientConfig.getIntSetting("inventory.search.patternMode") == 1;
|
||||
boolean insideQuotes = false;
|
||||
boolean insideRegex = false;
|
||||
String token = "";
|
||||
int lastEnd = 0;
|
||||
int index = 0;
|
||||
@@ -444,6 +448,15 @@ public class SearchTokenParser {
|
||||
while (index < length) {
|
||||
final char ch = input.charAt(index);
|
||||
|
||||
if (insideRegex) {
|
||||
if (ch == '/' && input.charAt(index - 1) != '\\') {
|
||||
insideRegex = false;
|
||||
}
|
||||
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!insideQuotes && delimiters.indexOf(ch) >= 0
|
||||
&& (!space || index == 0 || input.charAt(index - 1) == ' ' || lastEnd == index)) {
|
||||
|
||||
@@ -464,6 +477,9 @@ public class SearchTokenParser {
|
||||
|
||||
if (ch == '"' && (index == 0 || input.charAt(index - 1) != '\\')) {
|
||||
insideQuotes = !insideQuotes;
|
||||
} else if (regexTokens && !insideQuotes && isRegexStart(input, index)) {
|
||||
insideRegex = true;
|
||||
index++;
|
||||
}
|
||||
|
||||
index++;
|
||||
@@ -474,6 +490,12 @@ public class SearchTokenParser {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private static boolean isRegexStart(String input, int index) {
|
||||
return Character.toLowerCase(input.charAt(index)) == 'r' && index + 1 < input.length()
|
||||
&& input.charAt(index + 1) == '/'
|
||||
&& (index == 0 || !Character.isLetterOrDigit(input.charAt(index - 1)));
|
||||
}
|
||||
|
||||
public String getPrefixes() {
|
||||
if (this.prefixes == null) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
@@ -490,6 +512,11 @@ public class SearchTokenParser {
|
||||
return this.prefixes;
|
||||
}
|
||||
|
||||
public String getRecipeContextTokens() {
|
||||
// '^' is the start anchor and the negated class in regex mode
|
||||
return NEIClientConfig.getIntSetting("inventory.search.patternMode") == 2 ? "<>" : "<>^";
|
||||
}
|
||||
|
||||
public char getRedefinedPrefix(char prefix) {
|
||||
return this.prefixRedefinitions.getOrDefault(prefix, prefix);
|
||||
}
|
||||
|
||||
@@ -55,6 +55,10 @@ public abstract class Widget {
|
||||
return bounds().contains(px, py);
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public ItemStack getStackMouseOver(int mx, int my) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class WidgetContainer extends Widget {
|
||||
final Rectangle4i bounds = bounds();
|
||||
|
||||
for (Widget widget : this.widgets) {
|
||||
if (widget.bounds().intersects(bounds)) {
|
||||
if (widget.isVisible() && widget.bounds().intersects(bounds)) {
|
||||
widget.draw(mousex, mousey);
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ public class WidgetContainer extends Widget {
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
if (widget.contains(mousex, mousey)) {
|
||||
if (widget.isVisible() && widget.contains(mousex, mousey)) {
|
||||
return widget;
|
||||
}
|
||||
}
|
||||
@@ -113,7 +113,8 @@ public class WidgetContainer extends Widget {
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
if (!widget.contains(mousex, mousey) && widget.handleClickExt(mousex, mousey, button)) {
|
||||
if (widget.isVisible() && !widget.contains(mousex, mousey)
|
||||
&& widget.handleClickExt(mousex, mousey, button)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -126,7 +127,7 @@ public class WidgetContainer extends Widget {
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
widget.mouseDragged(mousex, mousey, button, heldTime);
|
||||
if (widget.isVisible()) widget.mouseDragged(mousex, mousey, button, heldTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +136,7 @@ public class WidgetContainer extends Widget {
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
widget.mouseUp(mousex, mousey, button);
|
||||
if (widget.isVisible()) widget.mouseUp(mousex, mousey, button);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +145,7 @@ public class WidgetContainer extends Widget {
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
if (widget.handleKeyPress(keyCode, keyChar)) {
|
||||
if (widget.isVisible() && widget.handleKeyPress(keyCode, keyChar)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -157,7 +158,7 @@ public class WidgetContainer extends Widget {
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
widget.lastKeyTyped(keyID, keyChar);
|
||||
if (widget.isVisible()) widget.lastKeyTyped(keyID, keyChar);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -227,7 +228,7 @@ public class WidgetContainer extends Widget {
|
||||
public void postDraw(int mousex, int mousey) {
|
||||
|
||||
for (Widget widget : this.widgets) {
|
||||
widget.postDraw(mousex, mousey);
|
||||
if (widget.isVisible()) widget.postDraw(mousex, mousey);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -237,7 +238,7 @@ public class WidgetContainer extends Widget {
|
||||
|
||||
for (int index = this.widgets.size() - 1; index >= 0; index--) {
|
||||
final Widget widget = this.widgets.get(index);
|
||||
widget.onGuiClick(mousex, mousey);
|
||||
if (widget.isVisible()) widget.onGuiClick(mousex, mousey);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -253,6 +254,17 @@ public class WidgetContainer extends Widget {
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> handleItemTooltip(ItemStack itemstack, int mousex, int mousey, List<String> tooltip) {
|
||||
final Widget widget = getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
if (widget != null) {
|
||||
return widget.handleItemTooltip(itemstack, mousex, mousey, tooltip);
|
||||
}
|
||||
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> handleHotkeys(int mousex, int mousey, Map<String, String> hotkeys) {
|
||||
final Widget widget = getWidgetUnderMouse(mousex, mousey);
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.lwjgl.input.Keyboard;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import codechicken.nei.BookmarkContainerInfo;
|
||||
import codechicken.nei.CollapsibleItems;
|
||||
import codechicken.nei.ItemList;
|
||||
import codechicken.nei.ItemSorter;
|
||||
import codechicken.nei.ItemStackSet;
|
||||
@@ -341,6 +342,30 @@ public class API {
|
||||
SubsetWidget.addTag(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a group of items that is collapsed into a single entry in the item panel. Groups registered here have
|
||||
* the lowest priority: an item that matches a preset or a collapsibleitems.cfg group stays there. They are active
|
||||
* only while the Collapsible Items option is enabled. Must be called while plugins are loading.
|
||||
*
|
||||
* @param filter A search string for matching items that belong to this group. Also identifies the group when its
|
||||
* expanded state is saved, so changing it resets the saved state.
|
||||
* @return A handle to optionally set the name shown for the group
|
||||
*/
|
||||
public static CollapsibleItems.ApiGroup addCollapsibleGroup(String filter) {
|
||||
return CollapsibleItems.registerGroup(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #addCollapsibleGroup(String)}, but the group is given as a list of item stacks. The stacks
|
||||
* identify the group when its expanded state is saved, so changing them resets the saved state.
|
||||
*
|
||||
* @param items Item stacks that belong to this group
|
||||
* @return A handle to optionally set the name shown for the group
|
||||
*/
|
||||
public static CollapsibleItems.ApiGroup addCollapsibleGroup(Iterable<ItemStack> items) {
|
||||
return CollapsibleItems.registerGroup(items);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void addSearchProvider(ISearchProvider provider) {}
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ import codechicken.nei.SearchTokenParser.SearchMode;
|
||||
import codechicken.nei.config.ArrayDumper;
|
||||
import codechicken.nei.config.HandlerDumper;
|
||||
import codechicken.nei.config.ItemPanelDumper;
|
||||
import codechicken.nei.config.RecipeDumper;
|
||||
import codechicken.nei.config.RegistryDumper;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.item.FluidDisplayRenderer;
|
||||
@@ -284,6 +285,7 @@ public class ItemInfo {
|
||||
});
|
||||
API.addOption(new ItemPanelDumper("tools.dump.itempanel"));
|
||||
API.addOption(new HandlerDumper("tools.dump.handlers"));
|
||||
API.addOption(new RecipeDumper("tools.dump.recipes"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -333,12 +335,6 @@ public class ItemInfo {
|
||||
}
|
||||
|
||||
private static void addVanillaBlockProperties() {
|
||||
API.setOverrideName(new ItemStack(Blocks.flowing_water), "Water Source");
|
||||
API.setOverrideName(new ItemStack(Blocks.water), "Water Still");
|
||||
API.setOverrideName(new ItemStack(Blocks.flowing_lava), "Lava Source");
|
||||
API.setOverrideName(new ItemStack(Blocks.lava), "Lava Still");
|
||||
API.setOverrideName(new ItemStack(Blocks.end_portal), "End Portal");
|
||||
API.setOverrideName(new ItemStack(Blocks.end_portal_frame), "End Portal Frame");
|
||||
API.hideItem(new ItemStack(Blocks.double_stone_slab, 1, OreDictionary.WILDCARD_VALUE));
|
||||
API.hideItem(new ItemStack(Blocks.double_wooden_slab, 1, OreDictionary.WILDCARD_VALUE));
|
||||
API.hideItem(new ItemStack(Blocks.carrots));
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.util.LinkedList;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.config.GuiOptionList;
|
||||
import codechicken.nei.config.OptionCycled;
|
||||
|
||||
public class NEIInfo {
|
||||
@@ -14,11 +13,7 @@ public class NEIInfo {
|
||||
|
||||
public static void load(World world) {
|
||||
OptionCycled modeOption = (OptionCycled) NEIClientConfig.getOptionList().getOption("inventory.cheatmode");
|
||||
final boolean worldConfig = NEIClientConfig.isWorldSpecific("inventory.cheatmode");
|
||||
// kept alive so the WeakReference in Option.slotRef isn't GC'd before copyGlobals/cycle use it
|
||||
GuiOptionList env = modeOption.parent.synthesizeEnvironment(worldConfig);
|
||||
if (!modeOption.optionValid(modeOption.value())) {
|
||||
modeOption.copyGlobals();
|
||||
modeOption.cycle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ 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;
|
||||
@@ -132,7 +131,7 @@ public class BookmarkGridGenerator {
|
||||
itemIndex++;
|
||||
}
|
||||
|
||||
} else if (group.crafting != null && group.crafting.itemToRecipe.values().contains(bookmarkItem.recipeId)) {
|
||||
} else if (group.crafting != null && group.crafting.recipeToItems.containsKey(bookmarkItem.recipeId)) {
|
||||
absoluteSlotIndex = generateCollapsedRecipe(prevBookmarkItem, itemIndex, absoluteSlotIndex, borderGrid);
|
||||
prevBookmarkItem = bookmarkItem;
|
||||
|
||||
@@ -218,8 +217,7 @@ public class BookmarkGridGenerator {
|
||||
}
|
||||
|
||||
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());
|
||||
return new ArrayList<>(group.crafting.recipeToItems.getOrDefault(recipeId, Collections.emptyList()));
|
||||
}
|
||||
|
||||
private int nextSlotIndex(int index, BookmarkItem previousMeta, BookmarkItem meta, BookmarkViewMode viewMode) {
|
||||
|
||||
@@ -14,7 +14,6 @@ import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
@@ -25,6 +24,7 @@ import com.google.gson.JsonSyntaxException;
|
||||
import codechicken.nei.BookmarkPanel.BookmarkViewMode;
|
||||
import codechicken.nei.ItemPanels;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
import codechicken.nei.util.NBTJson;
|
||||
|
||||
@@ -230,14 +230,7 @@ public class BookmarkStorage {
|
||||
}
|
||||
|
||||
if (wasError) {
|
||||
try {
|
||||
Files.copy(
|
||||
bookmarkFile,
|
||||
new File(bookmarkFile.getAbsolutePath() + ".backup-" + System.currentTimeMillis()));
|
||||
NEIClientConfig.logger.info("Backed up invalid bookmark file to {}", bookmarkFile);
|
||||
} catch (IOException e) {
|
||||
NEIClientConfig.logger.error("Failed to backup invalid bookmark file to {}", bookmarkFile, e);
|
||||
}
|
||||
NEIClientUtils.backupFile(bookmarkFile);
|
||||
}
|
||||
|
||||
for (BookmarkGrid gr : namespaces) {
|
||||
|
||||
@@ -111,6 +111,7 @@ public class RecipeChainDetails {
|
||||
|
||||
public final Map<Integer, BookmarkChainItem> calculatedItems = new HashMap<>();
|
||||
public final Map<Integer, RecipeId> itemToRecipe = new HashMap<>();
|
||||
public final Map<RecipeId, List<Integer>> recipeToItems = new HashMap<>();
|
||||
public final Set<RecipeId> outputRecipes = new HashSet<>();
|
||||
public final Set<RecipeId> recipeInMiddle = new HashSet<>();
|
||||
|
||||
@@ -124,6 +125,7 @@ public class RecipeChainDetails {
|
||||
}
|
||||
|
||||
this.itemToRecipe.clear();
|
||||
this.recipeToItems.clear();
|
||||
this.outputRecipes.clear();
|
||||
this.recipeInMiddle.clear();
|
||||
this.calculatedItems.clear();
|
||||
@@ -180,6 +182,10 @@ public class RecipeChainDetails {
|
||||
|
||||
}
|
||||
|
||||
for (Map.Entry<Integer, RecipeId> entry : this.itemToRecipe.entrySet()) {
|
||||
this.recipeToItems.computeIfAbsent(entry.getValue(), recipeId -> new ArrayList<>()).add(entry.getKey());
|
||||
}
|
||||
|
||||
for (Map.Entry<Integer, BookmarkItem> entry : chainItems.entrySet()) {
|
||||
final int itemIndex = entry.getKey();
|
||||
if (itemIndex >= 0 && this.calculatedItems.containsKey(itemIndex)) {
|
||||
|
||||
@@ -37,8 +37,8 @@ public class SortableItem {
|
||||
&& (group.viewMode == BookmarkViewMode.TODO_LIST || group.crafting != null);
|
||||
this.crossGroup = !group.collapsed && group.viewMode == BookmarkViewMode.TODO_LIST
|
||||
&& bookmarkItem.type != BookmarkItemType.INGREDIENT;
|
||||
this.isCollapsedRecipe = group.crafting != null && group.crafting.itemToRecipe.values().stream()
|
||||
.anyMatch(recipeId -> this.bookmarkItem.equalsRecipe(recipeId, this.bookmarkItem.groupId));
|
||||
this.isCollapsedRecipe = group.crafting != null && this.bookmarkItem.recipeId != null
|
||||
&& group.crafting.recipeToItems.containsKey(this.bookmarkItem.recipeId);
|
||||
|
||||
this.update();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ public class ConfigSet {
|
||||
public NBTTagCompound nbt;
|
||||
public final ConfigTagParent config;
|
||||
|
||||
public ConfigSet(File nbtFile) {
|
||||
this(nbtFile, null);
|
||||
}
|
||||
|
||||
public ConfigSet(File nbtFile, ConfigTagParent config) {
|
||||
this.nbtFile = nbtFile;
|
||||
this.config = config;
|
||||
|
||||
@@ -110,7 +110,7 @@ public abstract class DataDumper extends Option {
|
||||
}
|
||||
|
||||
public int getMode() {
|
||||
return renderTag().getIntValue(0);
|
||||
return getTag().getIntValue(0);
|
||||
}
|
||||
|
||||
public void drawButton(int mousex, int mousey, Rectangle4i b, String text) {
|
||||
|
||||
@@ -29,7 +29,6 @@ public class GuiHighlightTips extends GuiScreenWidget {
|
||||
private GuiCCButton toggleButton;
|
||||
private final Option opt;
|
||||
private final GuiOptionList parentGui;
|
||||
private final boolean world;
|
||||
private Point dragDown;
|
||||
|
||||
public GuiHighlightTips(Option opt) {
|
||||
@@ -37,7 +36,6 @@ public class GuiHighlightTips extends GuiScreenWidget {
|
||||
this.opt = opt;
|
||||
name = opt.name;
|
||||
this.parentGui = (GuiOptionList) Minecraft.getMinecraft().currentScreen;
|
||||
this.world = parentGui.worldConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,15 +61,11 @@ public class GuiHighlightTips extends GuiScreenWidget {
|
||||
}
|
||||
|
||||
private boolean show() {
|
||||
return renderTag(name).getBooleanValue();
|
||||
return getTag(name).getBooleanValue();
|
||||
}
|
||||
|
||||
private ConfigTag getTag(String s) {
|
||||
return (world ? opt.worldConfigSet() : opt.globalConfigSet()).config.getTag(s);
|
||||
}
|
||||
|
||||
private ConfigTag renderTag(String s) {
|
||||
return (world && opt.worldSpecific(s) ? opt.worldConfigSet() : opt.globalConfigSet()).config.getTag(s);
|
||||
return opt.configSet().config.getTag(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -95,7 +89,7 @@ public class GuiHighlightTips extends GuiScreenWidget {
|
||||
}
|
||||
|
||||
public Point getPos() {
|
||||
return new Point(renderTag(name + ".x").getIntValue(), renderTag(name + ".y").getIntValue());
|
||||
return new Point(getTag(name + ".x").getIntValue(), getTag(name + ".y").getIntValue());
|
||||
}
|
||||
|
||||
public Dimension sampleSize() // copied from HUDManager when running with the sample for this gui
|
||||
@@ -161,7 +155,6 @@ public class GuiHighlightTips extends GuiScreenWidget {
|
||||
}
|
||||
|
||||
private void setPos(Point p) {
|
||||
getTag(name).setBooleanValue(show()); // duplicates global tag for the option gui if in world mode
|
||||
getTag(name + ".x").setIntValue(p.x);
|
||||
getTag(name + ".y").setIntValue(p.y);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ public class GuiItemSorter extends GuiOptionPane {
|
||||
public final List<SortItem> slots = new ArrayList<>();
|
||||
public final List<SortEntry> list;
|
||||
private final GuiOptionList parentGui;
|
||||
private final boolean world;
|
||||
|
||||
boolean dragging;
|
||||
public SortItem dragged;
|
||||
@@ -62,8 +61,7 @@ public class GuiItemSorter extends GuiOptionPane {
|
||||
public GuiItemSorter(Option opt) {
|
||||
this.opt = opt;
|
||||
this.parentGui = (GuiOptionList) Minecraft.getMinecraft().currentScreen;
|
||||
this.world = parentGui.worldConfig();
|
||||
list = ItemSorter.fromSaveString(renderTag(opt.configName()).getValue());
|
||||
list = ItemSorter.fromSaveString(getTag(opt.configName()).getValue());
|
||||
for (SortEntry e : list) slots.add(new SortItem(e));
|
||||
}
|
||||
|
||||
@@ -122,10 +120,7 @@ public class GuiItemSorter extends GuiOptionPane {
|
||||
list.add(nslot, dragged.e);
|
||||
|
||||
getTag(opt.configName()).setValue(ItemSorter.getSaveString(list));
|
||||
|
||||
if (opt.activeTag() == getTag(opt.configName())) {
|
||||
ItemSorter.list = new ArrayList<>(list);
|
||||
}
|
||||
ItemSorter.list = new ArrayList<>(list);
|
||||
|
||||
ItemList.refreshItems.restart();
|
||||
}
|
||||
@@ -133,11 +128,7 @@ public class GuiItemSorter extends GuiOptionPane {
|
||||
}
|
||||
|
||||
private ConfigTag getTag(String s) {
|
||||
return (world ? opt.worldConfigSet() : opt.globalConfigSet()).config.getTag(s);
|
||||
}
|
||||
|
||||
private ConfigTag renderTag(String s) {
|
||||
return (world && opt.worldSpecific(s) ? opt.worldConfigSet() : opt.globalConfigSet()).config.getTag(s);
|
||||
return opt.configSet().config.getTag(s);
|
||||
}
|
||||
|
||||
public SortItem itemAt(int mx, int my) {
|
||||
|
||||
@@ -5,8 +5,8 @@ import net.minecraft.client.gui.GuiYesNoCallback;
|
||||
|
||||
public class GuiNEIOptionList extends GuiOptionList implements GuiYesNoCallback {
|
||||
|
||||
public GuiNEIOptionList(GuiScreen parent, OptionList optionList, boolean world) {
|
||||
super(parent, optionList, world);
|
||||
public GuiNEIOptionList(GuiScreen parent, OptionList optionList) {
|
||||
super(parent, optionList);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package codechicken.nei.config;
|
||||
|
||||
import static codechicken.lib.gui.GuiDraw.drawMultilineTip;
|
||||
import static codechicken.lib.gui.GuiDraw.drawStringC;
|
||||
import static codechicken.lib.gui.GuiDraw.fontRenderer;
|
||||
import static codechicken.lib.gui.GuiDraw.getMousePosition;
|
||||
import static net.minecraft.util.StatCollector.translateToLocal;
|
||||
@@ -10,7 +9,6 @@ import java.awt.Dimension;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -23,8 +21,6 @@ import org.lwjgl.opengl.GL11;
|
||||
import codechicken.core.gui.GuiCCButton;
|
||||
import codechicken.core.gui.GuiScreenWidget;
|
||||
import codechicken.core.gui.GuiScrollSlot;
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.LayoutManager;
|
||||
|
||||
public class GuiOptionList extends GuiScreenWidget {
|
||||
|
||||
@@ -66,25 +62,11 @@ public class GuiOptionList extends GuiScreenWidget {
|
||||
protected void drawSlot(int slot, int x, int y, int mx, int my, float frame) {
|
||||
Option o = options.get(slot);
|
||||
GL11.glTranslatef(x, y, 0);
|
||||
if (o.showWorldSelector() && world) drawWorldSelector(o, mx, my);
|
||||
GL11.glTranslatef(24, 2, 0);
|
||||
o.draw(mx - 24, my - 2, frame);
|
||||
GL11.glTranslatef(-x - 24, -y - 2, 0);
|
||||
}
|
||||
|
||||
public Rectangle4i worldButtonSize() {
|
||||
return new Rectangle4i(0, 2, 20, 20);
|
||||
}
|
||||
|
||||
private void drawWorldSelector(Option o, int mousex, int mousey) {
|
||||
Rectangle4i b = worldButtonSize();
|
||||
boolean set = o.hasWorldOverride();
|
||||
boolean mouseover = b.contains(mousex, mousey);
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
LayoutManager.drawButtonBackground(b.x, b.y, b.w, b.h, true, !set ? 0 : mouseover ? 2 : 1);
|
||||
drawStringC("W", b.x, b.y, b.w, b.h, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawBackground(float frame) {
|
||||
Rectangle sbar = scrollbarBounds();
|
||||
@@ -116,16 +98,7 @@ public class GuiOptionList extends GuiScreenWidget {
|
||||
|
||||
@Override
|
||||
protected void slotClicked(int slot, int button, int mx, int my, int count) {
|
||||
Option o = options.get(slot);
|
||||
if (world && o.showWorldSelector() && worldButtonSize().contains(mx, my)) {
|
||||
if (button == 1 && o.hasWorldOverride()) {
|
||||
o.useGlobals();
|
||||
Option.playClickSound();
|
||||
} else if (button == 0 && !o.hasWorldOverride()) {
|
||||
o.copyGlobals();
|
||||
Option.playClickSound();
|
||||
}
|
||||
} else if (slotBounds(slot).contains(mx, my)) {
|
||||
if (slotBounds(slot).contains(mx, my)) {
|
||||
options.get(slot).mouseClicked(mx - 24, my - 2, button);
|
||||
}
|
||||
}
|
||||
@@ -167,26 +140,20 @@ public class GuiOptionList extends GuiScreenWidget {
|
||||
}
|
||||
|
||||
private List<String> handleTooltip(int slot, int mx, int my, List<String> tooltip) {
|
||||
Option o = options.get(slot);
|
||||
if (world && o.showWorldSelector() && worldButtonSize().contains(mx, my))
|
||||
tooltip.add(translateToLocal("nei.options.wbutton.tip." + (o.hasWorldOverride() ? "1" : "0")));
|
||||
if (slotBounds(slot).contains(mx, my)) return o.handleTooltip(mx - 24, my - 2, tooltip);
|
||||
if (slotBounds(slot).contains(mx, my)) return options.get(slot).handleTooltip(mx - 24, my - 2, tooltip);
|
||||
return tooltip;
|
||||
}
|
||||
}
|
||||
|
||||
protected final GuiScreen parent;
|
||||
protected final OptionList optionList;
|
||||
protected boolean world;
|
||||
|
||||
protected OptionScrollSlot slot;
|
||||
protected GuiCCButton backButton;
|
||||
protected GuiCCButton worldButton;
|
||||
|
||||
public GuiOptionList(GuiScreen parent, OptionList optionList, boolean world) {
|
||||
public GuiOptionList(GuiScreen parent, OptionList optionList) {
|
||||
this.parent = parent;
|
||||
this.optionList = optionList;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -202,29 +169,18 @@ public class GuiOptionList extends GuiScreenWidget {
|
||||
backButton.width = Math.min(200, width - 40);
|
||||
backButton.x = (width - backButton.width) / 2;
|
||||
backButton.y = height - 25;
|
||||
worldButton.width = 60;
|
||||
worldButton.x = width - worldButton.width - 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addWidgets() {
|
||||
add(slot = new OptionScrollSlot());
|
||||
add(backButton = new GuiCCButton(0, 0, 0, 20, translateToLocal("nei.options.back")).setActionCommand("back"));
|
||||
add(worldButton = new GuiCCButton(0, 2, 0, 16, worldButtonName()).setActionCommand("world"));
|
||||
}
|
||||
|
||||
private String worldButtonName() {
|
||||
return translateToLocal("nei.options." + (world ? "world" : "global"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(String ident, Object... params) {
|
||||
if (ident.equals("back")) {
|
||||
if (parent instanceof GuiOptionList) ((GuiOptionList) parent).world = world;
|
||||
Minecraft.getMinecraft().displayGuiScreen(parent);
|
||||
} else if (ident.equals("world")) {
|
||||
world = !world;
|
||||
worldButton.text = worldButtonName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,9 +198,6 @@ public class GuiOptionList extends GuiScreenWidget {
|
||||
private void drawTooltip() {
|
||||
List<String> tooltip = new LinkedList<>();
|
||||
Point mouse = getMousePosition();
|
||||
if (worldButton.pointInside(mouse.x, mouse.y))
|
||||
tooltip.addAll(Arrays.asList(translateToLocal("nei.options.global.tip." + (world ? "1" : "0")).split(":")));
|
||||
|
||||
tooltip = slot.handleTooltip(mouse.x, mouse.y, tooltip);
|
||||
drawMultilineTip(mouse.x + 12, mouse.y - 12, tooltip);
|
||||
}
|
||||
@@ -265,8 +218,4 @@ public class GuiOptionList extends GuiScreenWidget {
|
||||
super.keyTyped(c, keycode);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean worldConfig() {
|
||||
return world;
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,6 @@ public class GuiPanelSettings extends GuiScreenWidget {
|
||||
|
||||
private final Option opt;
|
||||
private final String name;
|
||||
private final boolean world;
|
||||
private Rectangle4i margin;
|
||||
private Point dragDown;
|
||||
private String dragDir;
|
||||
@@ -69,10 +68,9 @@ public class GuiPanelSettings extends GuiScreenWidget {
|
||||
private PanelResizeButton rightButton = new PanelResizeButton(PANEL_SIZE, PANEL_SIZE * 2);
|
||||
private PanelResizeButton bottomButton = new PanelResizeButton(PANEL_SIZE * 2, PANEL_SIZE);
|
||||
|
||||
public PanelPlaceholder(Option opt, String name, boolean world) {
|
||||
public PanelPlaceholder(Option opt, String name) {
|
||||
this.opt = opt;
|
||||
this.name = name;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public void resize(Rectangle4i margin) {
|
||||
@@ -163,7 +161,7 @@ public class GuiPanelSettings extends GuiScreenWidget {
|
||||
}
|
||||
|
||||
private ConfigTag getTag(String s) {
|
||||
return (world ? opt.worldConfigSet() : opt.globalConfigSet()).config.getTag(s);
|
||||
return opt.configSet().config.getTag(s);
|
||||
}
|
||||
|
||||
protected void drawItems() {
|
||||
@@ -241,9 +239,8 @@ public class GuiPanelSettings extends GuiScreenWidget {
|
||||
super(176, 198);
|
||||
this.parentGui = (GuiOptionList) Minecraft.getMinecraft().currentScreen;
|
||||
|
||||
boolean world = parentGui.worldConfig();
|
||||
bookmarksPanel = new PanelPlaceholder(opt, opt.name + ".bookmarks", world);
|
||||
itemsPanel = new PanelPlaceholder(opt, opt.name + ".items", world);
|
||||
bookmarksPanel = new PanelPlaceholder(opt, opt.name + ".bookmarks");
|
||||
itemsPanel = new PanelPlaceholder(opt, opt.name + ".items");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -58,7 +58,7 @@ public class ItemPanelDumper extends DataDumper {
|
||||
}
|
||||
|
||||
public int getRes() {
|
||||
int i = renderTag(name + ".res").getIntValue(0);
|
||||
int i = getTag(name + ".res").getIntValue(0);
|
||||
int size = 16 << i;
|
||||
if (size >= getSmallerScreenAxisSize() || i < 0) {
|
||||
getTag(name + ".res").setIntValue(0);
|
||||
@@ -95,7 +95,7 @@ public class ItemPanelDumper extends DataDumper {
|
||||
}
|
||||
if (resButtonSize().contains(mousex, mousey)) {
|
||||
NEIClientUtils.playClickSound();
|
||||
int current = renderTag(name + ".res").getIntValue(0);
|
||||
int current = getTag(name + ".res").getIntValue(0);
|
||||
int next;
|
||||
// 31 - numberOfLeadingZeros(x) = floor(log2(x))
|
||||
int max = 31 - Integer.numberOfLeadingZeros(getSmallerScreenAxisSize()) - 3;
|
||||
|
||||
@@ -59,12 +59,8 @@ public abstract class Option {
|
||||
return elem;
|
||||
}
|
||||
|
||||
public ConfigSet globalConfigSet() {
|
||||
return assertParentOverride(parent.globalConfigSet());
|
||||
}
|
||||
|
||||
public ConfigSet worldConfigSet() {
|
||||
return assertParentOverride(parent.worldConfigSet());
|
||||
public ConfigSet configSet() {
|
||||
return assertParentOverride(parent.configSet());
|
||||
}
|
||||
|
||||
public OptionList configBase() {
|
||||
@@ -72,127 +68,19 @@ public abstract class Option {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the world config contains a tag with this name
|
||||
*/
|
||||
public boolean worldSpecific() {
|
||||
return worldSpecific(configName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the world config contains a tag with this name
|
||||
*/
|
||||
public boolean worldSpecific(String s) {
|
||||
ConfigTag tag = worldConfigSet().config.getTag(s, false);
|
||||
return tag != null && tag.value != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The currently config set for the gui based on the world/global button
|
||||
*/
|
||||
public ConfigSet configSet() {
|
||||
return worldConfig() ? worldConfigSet() : globalConfigSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The tag to render, world if world override, otherwise global
|
||||
*/
|
||||
public ConfigTag renderTag() {
|
||||
return renderTag(configName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The tag to render, world if world override, otherwise global
|
||||
*/
|
||||
public ConfigTag renderTag(String s) {
|
||||
return (worldConfig() && worldSpecific(s) ? worldConfigSet() : globalConfigSet()).config.getTag(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The tag with this name from the current configSet
|
||||
* @return The tag with this name from the config set
|
||||
*/
|
||||
public ConfigTag getTag() {
|
||||
return getTag(configName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The tag with this name from the current configSet
|
||||
* @return The tag with this name from the config set
|
||||
*/
|
||||
public ConfigTag getTag(String s) {
|
||||
return configSet().config.getTag(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The tag currently being used ingame, world if a world override exists, otherwise global
|
||||
*/
|
||||
public ConfigTag activeTag() {
|
||||
return activeTag(configName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The tag currently being used ingame, world if a world override exists, otherwise global
|
||||
*/
|
||||
public ConfigTag activeTag(String s) {
|
||||
return (worldSpecific() ? worldConfigSet() : globalConfigSet()).config.getTag(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the gui is in world config mode
|
||||
*/
|
||||
public boolean worldConfig() {
|
||||
return getSlot().getGui().worldConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if in world mode, but this tag has no world override. Changes should not be made in this mode
|
||||
*/
|
||||
public boolean defaulting() {
|
||||
return defaulting(configName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if in world mode, but this tag has no world override. Changes should not be made in this mode
|
||||
*/
|
||||
public boolean defaulting(String s) {
|
||||
return worldConfig() && !worldSpecific(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when world specific is disabled for this option. Should delete all world specific overrides
|
||||
*/
|
||||
public void useGlobals() {
|
||||
useGlobal(configName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a specific named tag from the worldConfig
|
||||
*/
|
||||
public void useGlobal(String s) {
|
||||
if (worldConfig()) worldConfigSet().config.removeTag(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when world specific is activated for this option. Should copy the global value into a world specific
|
||||
* override
|
||||
*/
|
||||
public void copyGlobals() {
|
||||
copyGlobal(configName(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the global value into a world specific override
|
||||
*/
|
||||
public void copyGlobal(String s) {
|
||||
copyGlobal(s, false);
|
||||
}
|
||||
|
||||
public void copyGlobal(String s, boolean recursive) {
|
||||
if (!worldConfig()) return;
|
||||
|
||||
ConfigTag tag = globalConfigSet().config.getTag(s);
|
||||
worldConfigSet().config.getTag(s).setValue(tag.getValue());
|
||||
if (recursive) for (String s2 : tag.childTagMap().keySet()) copyGlobal(s + "." + s2);
|
||||
}
|
||||
|
||||
public void onAdded(OptionScrollSlot slot) {
|
||||
this.slotRef = new WeakReference<>(slot);
|
||||
}
|
||||
@@ -217,12 +105,4 @@ public abstract class Option {
|
||||
public List<String> handleTooltip(int mx, int my, List<String> currenttip) {
|
||||
return currenttip;
|
||||
}
|
||||
|
||||
public boolean showWorldSelector() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean hasWorldOverride() {
|
||||
return worldSpecific();
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,11 @@ public class OptionCycled extends OptionButton {
|
||||
}
|
||||
|
||||
public int value() {
|
||||
return renderTag().getIntValue();
|
||||
return getTag().getIntValue();
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
getTag().setIntValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,7 +56,7 @@ public class OptionCycled extends OptionButton {
|
||||
|
||||
if (next == value()) return false;
|
||||
|
||||
getTag().setIntValue(next);
|
||||
setValue(next);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package codechicken.nei.config;
|
||||
|
||||
import net.minecraft.util.ChatComponentTranslation;
|
||||
|
||||
import codechicken.nei.ClientHandler;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
|
||||
public class OptionExportConfig extends OptionButton {
|
||||
|
||||
private final String fileName;
|
||||
|
||||
public OptionExportConfig(String fileName) {
|
||||
super("tools.export_configs." + fileName.substring(0, fileName.lastIndexOf('.')));
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefix() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getButtonText() {
|
||||
return translateN("tools.export_configs.button");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTooltip() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
final boolean exported = ClientHandler.exportDefaultConfig(fileName);
|
||||
|
||||
NEIClientUtils.printChatMessage(
|
||||
new ChatComponentTranslation(
|
||||
exported ? "nei.options.tools.export_configs.done" : "nei.options.tools.export_configs.skipped",
|
||||
fileName));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ public class OptionIntegerField extends OptionTextField {
|
||||
@Override
|
||||
protected int getMaxInputWidth() {
|
||||
|
||||
if (renderTag().getValue().startsWith("0x")) {
|
||||
if (getTag().getValue().startsWith("0x")) {
|
||||
return GuiDraw.getStringWidth("0x" + Long.toHexString(this.max).toUpperCase()) + 32;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,12 +20,7 @@ public class OptionList extends OptionButton {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigSet globalConfigSet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigSet worldConfigSet() {
|
||||
public ConfigSet configSet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -35,8 +30,8 @@ public class OptionList extends OptionButton {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuiOptionList getGui(GuiScreen parent, OptionList list, boolean world) {
|
||||
return new GuiOptionList(parent, list, world);
|
||||
public GuiOptionList getGui(GuiScreen parent, OptionList list) {
|
||||
return new GuiOptionList(parent, list);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,41 +113,25 @@ public class OptionList extends OptionButton {
|
||||
*
|
||||
* @param parent The parent screen for the back button
|
||||
* @param list The option list to be displayed in the gui
|
||||
* @param world true if in world config mode, false for global
|
||||
*/
|
||||
public GuiOptionList getGui(GuiScreen parent, OptionList list, boolean world) {
|
||||
return this.parent.getGui(parent, list, world);
|
||||
public GuiOptionList getGui(GuiScreen parent, OptionList list) {
|
||||
return this.parent.getGui(parent, list);
|
||||
}
|
||||
|
||||
public void openGui(GuiScreen parent, boolean world) {
|
||||
Minecraft.getMinecraft().displayGuiScreen(getGui(parent, this, world));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds this option to a temporary slot and gui for internal setting manipulation.
|
||||
*/
|
||||
public GuiOptionList synthesizeEnvironment(boolean world) {
|
||||
GuiOptionList gui = getGui(null, this, world);
|
||||
gui.addWidgets();
|
||||
return gui;
|
||||
public void openGui(GuiScreen parent) {
|
||||
Minecraft.getMinecraft().displayGuiScreen(getGui(parent, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onClick(int button) {
|
||||
openGui(getSlot().getGui(), getSlot().getGui().worldConfig());
|
||||
openGui(getSlot().getGui());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showWorldSelector() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdded(OptionScrollSlot slot) {
|
||||
super.onAdded(slot);
|
||||
|
||||
globalConfigSet().config.getTag(configName()).useBraces();
|
||||
worldConfigSet().config.getTag(configName()).useBraces();
|
||||
configSet().config.getTag(configName()).useBraces();
|
||||
}
|
||||
}
|
||||
@@ -127,7 +127,7 @@ public abstract class OptionStringSet extends Option {
|
||||
}
|
||||
|
||||
public List<String> values() {
|
||||
return Arrays.asList(renderTag().getValue().replace(" ", "").split(","));
|
||||
return Arrays.asList(getTag().getValue().replace(" ", "").split(","));
|
||||
}
|
||||
|
||||
public int buttonX() {
|
||||
|
||||
@@ -16,8 +16,7 @@ public class OptionTextField extends Option {
|
||||
|
||||
@Override
|
||||
public void onTextChange(String oldText) {
|
||||
// don't override global if text hasn't changed
|
||||
if (focused() && isValidValue(text()) && (!defaulting() || !text().equals(getTag().getValue()))) {
|
||||
if (focused() && isValidValue(text())) {
|
||||
getTag().setValue(text());
|
||||
OptionTextField.this.onTextChange(text());
|
||||
}
|
||||
@@ -25,7 +24,7 @@ public class OptionTextField extends Option {
|
||||
|
||||
@Override
|
||||
public void setFocus(boolean focus) {
|
||||
if (!focus && !isValidValue(text())) setText(renderTag().getValue());
|
||||
if (!focus && !isValidValue(text())) setText(getTag().getValue());
|
||||
super.setFocus(focus);
|
||||
}
|
||||
|
||||
@@ -45,7 +44,7 @@ public class OptionTextField extends Option {
|
||||
@Override
|
||||
public void update() {
|
||||
textField.update();
|
||||
if (!textField.focused()) textField.setText(renderTag().getValue());
|
||||
if (!textField.focused()) textField.setText(getTag().getValue());
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
|
||||
@@ -14,7 +14,7 @@ public class OptionToggleButton extends OptionButton {
|
||||
}
|
||||
|
||||
public boolean state() {
|
||||
return renderTag().getBooleanValue();
|
||||
return getTag().getBooleanValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -34,7 +34,7 @@ public class OptionToggleButtonBoubs extends OptionButton {
|
||||
}
|
||||
|
||||
public boolean state() {
|
||||
return renderTag().getBooleanValue();
|
||||
return getTag().getBooleanValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package codechicken.nei.config;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import codechicken.lib.vec.Rectangle4i;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.recipe.RecipeJsonWriter;
|
||||
|
||||
public class RecipeDumper extends DataDumper {
|
||||
|
||||
public RecipeDumper(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] header() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String[]> dump(int mode) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String renderName() {
|
||||
return translateN(name);
|
||||
}
|
||||
|
||||
public Rectangle4i separateButtonSize() {
|
||||
return dumpButtonSize();
|
||||
}
|
||||
|
||||
public Rectangle4i combinedButtonSize() {
|
||||
return modeButtonSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(int mousex, int mousey, float frame) {
|
||||
drawPrefix();
|
||||
drawButton(mousex, mousey, combinedButtonSize(), translateN(name + ".combined"));
|
||||
drawButton(mousex, mousey, separateButtonSize(), translateN(name + ".separate"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(int mousex, int mousey, int button) {
|
||||
final boolean combined = combinedButtonSize().contains(mousex, mousey);
|
||||
|
||||
if (combined || separateButtonSize().contains(mousex, mousey)) {
|
||||
NEIClientUtils.playClickSound();
|
||||
RecipeJsonWriter.dumpAll(!combined);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.api.IRecipeFilter;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
|
||||
@@ -30,7 +30,10 @@ public class AllMultiRecipeFilter implements IRecipeFilter {
|
||||
try {
|
||||
if (filter != null && !filter.matches(handler, recipeIndex)) return false;
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.error("Exception filtering " + handler + " with " + filter, e);
|
||||
NEIClientUtils.errorOnce(
|
||||
"filter:" + handler.getHandlerId() + ":" + filter.getClass().getName(),
|
||||
"Exception filtering " + handler.getHandlerId() + " with " + filter,
|
||||
e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
package codechicken.nei.filter;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.api.IRecipeFilter;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
|
||||
public class AllOthersRecipeFilter implements IRecipeFilter {
|
||||
|
||||
private final ItemFilter filter;
|
||||
|
||||
public AllOthersRecipeFilter(ItemFilter filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(IRecipeHandler handler, int recipeIndex) {
|
||||
|
||||
for (PositionedStack pStack : handler.getOtherStacks(recipeIndex)) {
|
||||
if (!match(pStack)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean match(PositionedStack pStack) {
|
||||
if (pStack == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ItemStack stack : pStack.items) {
|
||||
if (filter.matches(stack)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.api.IRecipeFilter;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
|
||||
@@ -30,7 +30,10 @@ public class AnyMultiRecipeFilter implements IRecipeFilter {
|
||||
try {
|
||||
if (filter != null && filter.matches(handler, recipeIndex)) return true;
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.error("Exception filtering " + handler + " with " + filter, e);
|
||||
NEIClientUtils.errorOnce(
|
||||
"filter:" + handler.getHandlerId() + ":" + filter.getClass().getName(),
|
||||
"Exception filtering " + handler.getHandlerId() + " with " + filter,
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
package codechicken.nei.filter;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.api.IRecipeFilter;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
|
||||
public class AnyOthersRecipeFilter implements IRecipeFilter {
|
||||
|
||||
private final ItemFilter filter;
|
||||
|
||||
public AnyOthersRecipeFilter(ItemFilter filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(IRecipeHandler handler, int recipeIndex) {
|
||||
|
||||
for (PositionedStack pStack : handler.getOtherStacks(recipeIndex)) {
|
||||
if (match(pStack)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean match(PositionedStack pStack) {
|
||||
if (pStack == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ItemStack stack : pStack.items) {
|
||||
if (filter.matches(stack)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,7 +16,8 @@ public class RecipeFilter implements IRecipeFilter {
|
||||
|
||||
ANY,
|
||||
INPUT,
|
||||
OUTPUT;
|
||||
OUTPUT,
|
||||
AUXILIARY;
|
||||
|
||||
public static FilterContext fromChar(char c) {
|
||||
switch (c) {
|
||||
@@ -24,6 +25,8 @@ public class RecipeFilter implements IRecipeFilter {
|
||||
return INPUT;
|
||||
case '>':
|
||||
return OUTPUT;
|
||||
case '^':
|
||||
return AUXILIARY;
|
||||
default:
|
||||
return ANY;
|
||||
}
|
||||
@@ -48,17 +51,14 @@ public class RecipeFilter implements IRecipeFilter {
|
||||
return this.anyMatch;
|
||||
}
|
||||
|
||||
if (this.context == FilterContext.ANY || this.context == FilterContext.OUTPUT) {
|
||||
final PositionedStack result = handler.getResultStack(recipeIndex);
|
||||
|
||||
if (result != null && matchPositionedStack(result) == this.anyMatch) {
|
||||
return this.anyMatch;
|
||||
}
|
||||
|
||||
if (matchPositionedStack(handler.getOtherStacks(recipeIndex), this.anyMatch)) {
|
||||
return this.anyMatch;
|
||||
}
|
||||
if ((this.context == FilterContext.ANY || this.context == FilterContext.OUTPUT)
|
||||
&& matchPositionedStack(handler.getResultStacks(recipeIndex), this.anyMatch)) {
|
||||
return this.anyMatch;
|
||||
}
|
||||
|
||||
if ((this.context == FilterContext.ANY || this.context == FilterContext.AUXILIARY)
|
||||
&& matchPositionedStack(handler.getAuxiliaryStacks(recipeIndex), this.anyMatch)) {
|
||||
return this.anyMatch;
|
||||
}
|
||||
|
||||
return !this.anyMatch;
|
||||
|
||||
@@ -123,11 +123,6 @@ public class AutoCraftingManager {
|
||||
AutoCraftingManager.math = math;
|
||||
|
||||
if (AutoCraftingManager.math != null) {
|
||||
|
||||
if (NEIClientUtils.getGuiContainer() instanceof GuiRecipe<?>gui && gui.firstGui != null) {
|
||||
gui.mc.displayGuiScreen(gui.firstGui);
|
||||
}
|
||||
|
||||
ItemPanels.bookmarkPanel.clearTooltips();
|
||||
math.createMasterRoot();
|
||||
task.restart();
|
||||
|
||||
@@ -200,6 +200,22 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
"recipe.search.tooltip.output",
|
||||
SearchExpressionUtils.HIGHLIGHTS.RECIPE + ">"));
|
||||
|
||||
final int patternMode = NEIClientConfig.getIntSetting("inventory.search.patternMode");
|
||||
|
||||
if (patternMode != 2) {
|
||||
tooltip.add(
|
||||
NEIClientUtils.translate(
|
||||
"recipe.search.tooltip.auxiliary",
|
||||
SearchExpressionUtils.HIGHLIGHTS.RECIPE + "^"));
|
||||
}
|
||||
|
||||
if (patternMode == 3) {
|
||||
tooltip.add(
|
||||
NEIClientUtils.translate(
|
||||
"recipe.search.tooltip.all",
|
||||
SearchExpressionUtils.HIGHLIGHTS.RECIPE + "<&"));
|
||||
}
|
||||
|
||||
for (ISearchParserProvider provider : SearchField.searchParser.getProviders()) {
|
||||
if (provider.getSearchMode() == SearchMode.PREFIX) {
|
||||
addPrefixTooltip(tooltip, provider);
|
||||
@@ -222,6 +238,14 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
"recipe.search.tooltip.exact",
|
||||
SearchExpressionUtils.HIGHLIGHTS.QUOTED + "\"",
|
||||
SearchExpressionUtils.HIGHLIGHTS.QUOTED + "\""));
|
||||
|
||||
if (patternMode == 1 || patternMode == 3) {
|
||||
tooltip.add(
|
||||
NEIClientUtils.translate(
|
||||
"recipe.search.tooltip.regex",
|
||||
SearchExpressionUtils.HIGHLIGHTS.REGEX + "r/",
|
||||
SearchExpressionUtils.HIGHLIGHTS.REGEX + "/"));
|
||||
}
|
||||
} else {
|
||||
tooltip.add(NEIClientUtils.translate("recipe.search.tooltip.shift"));
|
||||
}
|
||||
@@ -682,6 +706,10 @@ public abstract class GuiRecipe<H extends IRecipeHandler> extends GuiContainer i
|
||||
return this.handlerPages.getRecipeIndices();
|
||||
}
|
||||
|
||||
public List<Integer> getFilteredRecipes() {
|
||||
return this.handler.getFilteredRecipes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(char c, int i) {
|
||||
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -31,6 +26,7 @@ import codechicken.nei.ColorUtils;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.Widget;
|
||||
import codechicken.nei.drawable.DrawableBuilder;
|
||||
import codechicken.nei.drawable.DrawableResource;
|
||||
import codechicken.nei.event.NEIRegisterHandlerInfosEvent;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
@@ -48,26 +44,29 @@ public abstract class GuiRecipeTab extends Widget {
|
||||
protected final String handlerName;
|
||||
protected final String handlerID;
|
||||
|
||||
public static final int TAB_WIDTH = 24;
|
||||
public static final int TAB_HEIGHT = 24;
|
||||
private static final DrawableResource selectedTabImage = new DrawableBuilder(
|
||||
"nei:textures/nei_tabbed_sprites.png",
|
||||
0,
|
||||
16,
|
||||
24,
|
||||
24).build();
|
||||
private static final DrawableResource unselectedTabImage = new DrawableBuilder(
|
||||
"nei:textures/nei_tabbed_sprites.png",
|
||||
24,
|
||||
16,
|
||||
24,
|
||||
24).build();
|
||||
|
||||
private boolean selected;
|
||||
|
||||
public abstract int getWidth();
|
||||
|
||||
public abstract int getHeight();
|
||||
|
||||
public abstract DrawableResource getSelectedTabImage();
|
||||
|
||||
public abstract DrawableResource getUnselectedTabImage();
|
||||
|
||||
protected abstract int getForegroundIconX();
|
||||
|
||||
protected abstract int getForegroundIconY();
|
||||
|
||||
public GuiRecipeTab(IRecipeHandler handler, int x, int y) {
|
||||
super();
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.w = getWidth();
|
||||
this.h = getHeight();
|
||||
this.w = TAB_WIDTH;
|
||||
this.h = TAB_HEIGHT;
|
||||
this.handler = handler;
|
||||
this.handlerName = handler.getHandlerId();
|
||||
this.selected = false;
|
||||
@@ -88,21 +87,16 @@ public abstract class GuiRecipeTab extends Widget {
|
||||
public void drawBackground(int mouseX, int mouseY) {
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
final DrawableResource image;
|
||||
if (selected) image = getSelectedTabImage();
|
||||
else image = getUnselectedTabImage();
|
||||
|
||||
final int iconX = x + (w - image.getWidth()) / 2;
|
||||
final int iconY = y + (h - image.getHeight()) / 2;
|
||||
image.draw(iconX, iconY);
|
||||
final DrawableResource image = this.selected ? selectedTabImage : unselectedTabImage;
|
||||
image.draw(this.x, this.y);
|
||||
}
|
||||
|
||||
public void drawForeground(int mouseX, int mouseY) {
|
||||
final int iconX = getForegroundIconX();
|
||||
final int iconY = getForegroundIconY();
|
||||
final int iconX = this.x + 4;
|
||||
final int iconY = this.y + 4;
|
||||
|
||||
final FontRenderer fontRenderer = GuiDraw.fontRenderer;
|
||||
final HandlerInfo handlerInfo = getHandlerInfo(handlerName, handlerID);
|
||||
final HandlerInfo handlerInfo = getHandlerInfo(this.handlerName, this.handlerID);
|
||||
final DrawableResource icon = handlerInfo != null ? handlerInfo.getImage() : null;
|
||||
final ItemStack itemStack = handlerInfo != null ? handlerInfo.getItemStack() : null;
|
||||
|
||||
@@ -117,7 +111,7 @@ public abstract class GuiRecipeTab extends Widget {
|
||||
if (!isEnabled) GL11.glDisable(GL12.GL_RESCALE_NORMAL);
|
||||
} else {
|
||||
// Text fallback
|
||||
String text = handler.getRecipeName();
|
||||
String text = this.handler.getRecipeName();
|
||||
if (text != null && text.length() > 0) {
|
||||
if (text.length() > 2) {
|
||||
text = text.substring(0, 2);
|
||||
@@ -126,9 +120,10 @@ public abstract class GuiRecipeTab extends Widget {
|
||||
text = "??";
|
||||
}
|
||||
|
||||
int textCenterX = x + (int) (getWidth() / 2f);
|
||||
int textCenterY = y + (int) (getHeight() / 2f) - 3;
|
||||
int color = selected ? ColorUtils.buttonLabelHover.getColor() : ColorUtils.buttonLabelNormal.getColor();
|
||||
int textCenterX = this.x + (int) (this.w / 2f);
|
||||
int textCenterY = this.y + (int) (this.h / 2f) - 3;
|
||||
int color = this.selected ? ColorUtils.buttonLabelHover.getColor()
|
||||
: ColorUtils.buttonLabelNormal.getColor();
|
||||
fontRenderer.drawStringWithShadow(
|
||||
text,
|
||||
textCenterX - (int) (fontRenderer.getStringWidth(text) / 2f),
|
||||
@@ -207,41 +202,27 @@ public abstract class GuiRecipeTab extends Widget {
|
||||
}
|
||||
|
||||
public static void loadHandlerInfo() {
|
||||
final boolean fromJar = NEIClientConfig.loadHandlersFromJar();
|
||||
final boolean fromJar = !NEIClientConfig.handlerFile.exists();
|
||||
NEIClientConfig.logger.info("Loading handler info from " + (fromJar ? "JAR" : "Config"));
|
||||
handlerMap.clear();
|
||||
URL handlerUrl = GuiRecipeTab.class.getResource("/assets/nei/csv/handlers.csv");
|
||||
|
||||
URL url;
|
||||
if (fromJar) {
|
||||
url = handlerUrl;
|
||||
if (url == null) {
|
||||
NEIClientConfig.logger.info("Invalid URL for handlers csv.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
File handlerFile = NEIClientConfig.handlerFile;
|
||||
if (!handlerFile.exists()) {
|
||||
NEIClientConfig.logger.info("Config file doesn't exist, creating");
|
||||
try (FileOutputStream fileOutputStream = new FileOutputStream(handlerFile.getAbsoluteFile())) {
|
||||
assert handlerUrl != null;
|
||||
ReadableByteChannel readableByteChannel = Channels.newChannel(handlerUrl.openStream());
|
||||
FileChannel fileChannel = fileOutputStream.getChannel();
|
||||
fileChannel.transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
url = NEIClientConfig.handlerFile.toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
NEIClientConfig.logger.info("Invalid URL for handlers csv (via config).");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
url = fromJar ? GuiRecipeTab.class.getResource("/assets/nei/csv/handlers.csv")
|
||||
: NEIClientConfig.handlerFile.toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
NEIClientConfig.logger.info("Invalid URL for handlers csv (via config).");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) {
|
||||
|
||||
if (url == null) {
|
||||
NEIClientConfig.logger.info("Invalid URL for handlers csv.");
|
||||
return;
|
||||
}
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
|
||||
CSVParser csvParser = CSVFormat.EXCEL.builder().setHeader().setSkipHeaderRecord(true).build().parse(reader);
|
||||
for (CSVRecord record : csvParser) {
|
||||
final String handler = record.get("handler");
|
||||
@@ -282,13 +263,12 @@ public abstract class GuiRecipeTab extends Widget {
|
||||
NEIClientConfig.logger.info("Error setting handler dimensions for " + handler);
|
||||
}
|
||||
|
||||
final boolean allowOverflow = record.isSet("useCustomScroll")
|
||||
&& Boolean.parseBoolean(record.get("useCustomScroll"));
|
||||
info.setAllowOverflowX(
|
||||
record.isSet("allowOverflowX") ? Boolean.parseBoolean(record.get("allowOverflowX")) : true);
|
||||
info.setAllowOverflowY(
|
||||
record.isSet("allowOverflowY") ? Boolean.parseBoolean(record.get("allowOverflowY"))
|
||||
: allowOverflow);
|
||||
final boolean allowOverflow = booleanOrDefault(record, "useCustomScroll", false);
|
||||
info.setAllowOverflowX(booleanOrDefault(record, "allowOverflowX", true));
|
||||
info.setAllowOverflowY(booleanOrDefault(record, "allowOverflowY", allowOverflow));
|
||||
info.setShowFavoritesButton(booleanOrDefault(record, "showFavorites", true));
|
||||
info.setShowOverlayButton(booleanOrDefault(record, "showOverlay", true));
|
||||
info.setShowBadge(booleanOrDefault(record, "showBadge", false));
|
||||
handlerMap.put(handler, info);
|
||||
NEIClientConfig.logger.info("Loaded " + handler);
|
||||
}
|
||||
@@ -325,6 +305,11 @@ public abstract class GuiRecipeTab extends Widget {
|
||||
return info;
|
||||
}
|
||||
|
||||
private static boolean booleanOrDefault(CSVRecord record, String name, boolean defaultValue) {
|
||||
final String str = record.isSet(name) ? record.get(name) : null;
|
||||
return str == null || str.isEmpty() ? defaultValue : Boolean.parseBoolean(str);
|
||||
}
|
||||
|
||||
private static int intOrDefault(String str, int defaultValue) {
|
||||
if (str == null || str.equals("")) return defaultValue;
|
||||
try {
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import codechicken.nei.drawable.DrawableBuilder;
|
||||
import codechicken.nei.drawable.DrawableResource;
|
||||
|
||||
public abstract class GuiRecipeTabCreative extends GuiRecipeTab {
|
||||
|
||||
public static final int TAB_WIDTH = 28;
|
||||
public static final int TAB_HEIGHT = 31;
|
||||
private static final DrawableResource selectedTabImage = new DrawableBuilder(
|
||||
"minecraft:textures/gui/container/creative_inventory/tabs.png",
|
||||
28,
|
||||
32,
|
||||
28,
|
||||
32).build();
|
||||
private static final DrawableResource unselectedTabImage = new DrawableBuilder(
|
||||
"minecraft:textures/gui/container/creative_inventory/tabs.png",
|
||||
28,
|
||||
0,
|
||||
28,
|
||||
30).build();
|
||||
|
||||
public GuiRecipeTabCreative(IRecipeHandler handler, int x, int y) {
|
||||
super(handler, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return TAB_WIDTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return TAB_HEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getForegroundIconX() {
|
||||
return x + (w - 16) / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getForegroundIconY() {
|
||||
return y + h - 22;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DrawableResource getSelectedTabImage() {
|
||||
return selectedTabImage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DrawableResource getUnselectedTabImage() {
|
||||
return unselectedTabImage;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import codechicken.nei.drawable.DrawableBuilder;
|
||||
import codechicken.nei.drawable.DrawableResource;
|
||||
|
||||
public abstract class GuiRecipeTabJEI extends GuiRecipeTab {
|
||||
|
||||
public static final int TAB_WIDTH = 24;
|
||||
public static final int TAB_HEIGHT = 24;
|
||||
private static final DrawableResource selectedTabImage = new DrawableBuilder(
|
||||
"nei:textures/nei_tabbed_sprites.png",
|
||||
0,
|
||||
16,
|
||||
24,
|
||||
24).build();
|
||||
private static final DrawableResource unselectedTabImage = new DrawableBuilder(
|
||||
"nei:textures/nei_tabbed_sprites.png",
|
||||
24,
|
||||
16,
|
||||
24,
|
||||
24).build();
|
||||
|
||||
public GuiRecipeTabJEI(IRecipeHandler handler, int x, int y) {
|
||||
super(handler, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return TAB_WIDTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return TAB_HEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getForegroundIconX() {
|
||||
return x + 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getForegroundIconY() {
|
||||
return y + 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DrawableResource getSelectedTabImage() {
|
||||
return selectedTabImage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DrawableResource getUnselectedTabImage() {
|
||||
return unselectedTabImage;
|
||||
}
|
||||
}
|
||||
@@ -47,11 +47,11 @@ public class GuiRecipeTabs {
|
||||
};
|
||||
|
||||
public static int getTabWidth() {
|
||||
return NEIClientConfig.useCreativeTabStyle() ? GuiRecipeTabCreative.TAB_WIDTH : GuiRecipeTabJEI.TAB_WIDTH;
|
||||
return GuiRecipeTab.TAB_WIDTH;
|
||||
}
|
||||
|
||||
public static int getTabHeight() {
|
||||
return NEIClientConfig.useCreativeTabStyle() ? GuiRecipeTabCreative.TAB_HEIGHT : GuiRecipeTabJEI.TAB_HEIGHT;
|
||||
return GuiRecipeTab.TAB_HEIGHT;
|
||||
}
|
||||
|
||||
public void update(GuiRecipe<?> guiRecipe) {
|
||||
@@ -85,27 +85,15 @@ public class GuiRecipeTabs {
|
||||
final IRecipeHandler handler = this.currenthandlers.get(index);
|
||||
final int tabX = this.area.x + (i * tabWidth);
|
||||
|
||||
if (NEIClientConfig.useCreativeTabStyle()) {
|
||||
tabs.add(new GuiRecipeTabCreative(handler, tabX, this.area.y) {
|
||||
this.tabs.add(new GuiRecipeTab(handler, tabX, this.area.y) {
|
||||
|
||||
@Override
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
setRecipePage(index);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
setRecipePage(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
} else {
|
||||
tabs.add(new GuiRecipeTabJEI(handler, tabX, this.area.y) {
|
||||
|
||||
@Override
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
setRecipePage(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
@@ -77,19 +78,48 @@ public interface IRecipeHandler {
|
||||
List<PositionedStack> getIngredientStacks(int recipe);
|
||||
|
||||
/**
|
||||
* Callers should read {@link #getResultStacks(int)} and {@link #getAuxiliaryStacks(int)} instead.
|
||||
*
|
||||
* @param recipe The recipe index to get items for.
|
||||
* @return A list of the other {@link PositionedStack}s in this recipe relative to the top left corner of your
|
||||
* recipe drawing space. For example fuel in furnaces.
|
||||
* @return The fuel or catalysts when {@link #getResultStack(int)} is present, otherwise all the results of the
|
||||
* recipe. Relative to the top left corner of your recipe drawing space.
|
||||
*/
|
||||
List<PositionedStack> getOtherStacks(int recipe);
|
||||
default List<PositionedStack> getOtherStacks(int recipe) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callers should read {@link #getResultStacks(int)} instead.
|
||||
*
|
||||
* @param recipe The recipe index to get the result for.
|
||||
* @return The recipe result {@link PositionedStack} relative to the top left corner of your recipe drawing space.
|
||||
* @return The single result, or {@code null} when the recipe has several results and returns them from
|
||||
* {@link #getOtherStacks(int)}. Relative to the top left corner of your recipe drawing space.
|
||||
*/
|
||||
PositionedStack getResultStack(int recipe);
|
||||
default PositionedStack getResultStack(int recipe) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Built from {@link #getResultStack(int)} and {@link #getOtherStacks(int)}. Don't override it, return the results
|
||||
* from those methods so mods that still read them see the same results.
|
||||
*
|
||||
* @return The results: the result stack when present, otherwise the other stacks.
|
||||
*/
|
||||
default List<PositionedStack> getResultStacks(int recipe) {
|
||||
final PositionedStack result = getResultStack(recipe);
|
||||
return result != null ? Collections.singletonList(result) : getOtherStacks(recipe);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override it only when the recipe has several results and also fuel or catalysts: the results then go to
|
||||
* {@link #getOtherStacks(int)} and the catalysts can't be returned from the old methods.
|
||||
*
|
||||
* @return The stacks that are neither ingredients nor results (fuel, catalysts): the other stacks when a result
|
||||
* stack is present.
|
||||
*/
|
||||
default List<PositionedStack> getAuxiliaryStacks(int recipe) {
|
||||
return getResultStack(recipe) != null ? getOtherStacks(recipe) : Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param recipe The recipe index to get the group id for.
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.util.Comparator;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
@@ -65,19 +66,11 @@ public class Recipe {
|
||||
|
||||
public static RecipeId of(IRecipeHandler handler, int recipeIndex, List<PositionedStack> ingredients) {
|
||||
final String handlerName = GuiRecipeTab.getHandlerInfo(handler).getHandlerName();
|
||||
PositionedStack pStackResult = handler.getResultStack(recipeIndex);
|
||||
final PositionedStack result = getMainResult(
|
||||
handler.getResultStacks(recipeIndex),
|
||||
pStack -> pStack.items[0]);
|
||||
|
||||
if (pStackResult == null) {
|
||||
for (PositionedStack otherStack : handler.getOtherStacks(recipeIndex)) {
|
||||
if (!FluidContainerRegistry.isContainer(otherStack.items[0])
|
||||
|| StackInfo.getFluid(otherStack.items[0]) != null) {
|
||||
pStackResult = otherStack;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new RecipeId(extractItem(pStackResult), handlerName, extractIngredients(ingredients));
|
||||
return new RecipeId(extractItem(result), handlerName, extractIngredients(ingredients));
|
||||
}
|
||||
|
||||
public static RecipeId of(JsonObject json) {
|
||||
@@ -404,12 +397,8 @@ public class Recipe {
|
||||
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));
|
||||
}
|
||||
for (PositionedStack positionedStack : handler.getResultStacks(recipeIndex)) {
|
||||
results.add(RecipeIngredient.of(positionedStack));
|
||||
}
|
||||
|
||||
return new Recipe(handlerName, ingredients, results);
|
||||
@@ -494,18 +483,8 @@ public class Recipe {
|
||||
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();
|
||||
stack = getMainResult(getResults(), RecipeIngredient::getItemStack).getItemStack();
|
||||
}
|
||||
|
||||
int stackSize = 0;
|
||||
@@ -519,6 +498,19 @@ public class Recipe {
|
||||
return StackInfo.withAmount(stack, stackSize);
|
||||
}
|
||||
|
||||
public static <T> T getMainResult(List<T> results, Function<T, ItemStack> stackOf) {
|
||||
|
||||
for (T result : results) {
|
||||
final ItemStack stack = stackOf.apply(result);
|
||||
|
||||
if (!FluidContainerRegistry.isContainer(stack) || StackInfo.getFluid(stack) != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return results.isEmpty() ? null : results.get(0);
|
||||
}
|
||||
|
||||
public RecipeId getRecipeId() {
|
||||
|
||||
if (this.recipeId == null) {
|
||||
|
||||
@@ -2,14 +2,10 @@ package codechicken.nei.recipe;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -97,43 +93,30 @@ public class RecipeCatalysts {
|
||||
}
|
||||
|
||||
public static void loadCatalystInfo() {
|
||||
final boolean fromJar = NEIClientConfig.loadCatalystsFromJar();
|
||||
final URL handlerUrl = RecipeCatalysts.class.getResource("/assets/nei/csv/catalysts.csv");
|
||||
final File catalystFile = NEIClientConfig.catalystFile;
|
||||
final boolean fromJar = !catalystFile.exists();
|
||||
final Map<String, CatalystInfoList> calculatedCatalysts = new HashMap<>();
|
||||
NEIClientConfig.logger.info("Loading catalyst info from " + (fromJar ? "JAR" : "Config"));
|
||||
|
||||
resolveAdderQueue(calculatedCatalysts);
|
||||
|
||||
URL url;
|
||||
if (fromJar) {
|
||||
url = handlerUrl;
|
||||
if (url == null) {
|
||||
NEIClientConfig.logger.warn("Invalid URL for catalysts csv.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
File catalystFile = NEIClientConfig.catalystFile;
|
||||
if (!catalystFile.exists()) {
|
||||
NEIClientConfig.logger.info("Config file doesn't exist, creating");
|
||||
try (FileOutputStream fileOutputStream = new FileOutputStream(catalystFile.getAbsoluteFile())) {
|
||||
assert handlerUrl != null;
|
||||
ReadableByteChannel readableByteChannel = Channels.newChannel(handlerUrl.openStream());
|
||||
FileChannel fileChannel = fileOutputStream.getChannel();
|
||||
fileChannel.transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
url = NEIClientConfig.catalystFile.toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
NEIClientConfig.logger.warn("Invalid URL for catalysts csv (via config).");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
final URL url;
|
||||
try {
|
||||
url = fromJar ? RecipeCatalysts.class.getResource("/assets/nei/csv/catalysts.csv")
|
||||
: catalystFile.toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
NEIClientConfig.logger.warn("Invalid URL for catalysts csv (via config).");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) {
|
||||
|
||||
if (url == null) {
|
||||
NEIClientConfig.logger.warn("Invalid URL for catalysts csv.");
|
||||
return;
|
||||
}
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
|
||||
CSVParser csvParser = CSVFormat.EXCEL.builder().setHeader().setSkipHeaderRecord(true).build().parse(reader);
|
||||
for (CSVRecord record : csvParser) {
|
||||
final String handler = record.get("handler");
|
||||
@@ -141,10 +124,6 @@ public class RecipeCatalysts {
|
||||
final boolean requiresMod = Boolean.parseBoolean(record.get("modRequired"));
|
||||
final String excludedModId = record.get("excludedModId");
|
||||
final int priority = intOrDefault(record.get("priority"), 0);
|
||||
// todo
|
||||
final String minVersion = record.get("minVersion");
|
||||
final String maxVersion = record.get("maxVersion");
|
||||
//
|
||||
final boolean forceClassName = Boolean.parseBoolean(record.get("forceClassName"));
|
||||
|
||||
if (requiresMod && !Loader.isModLoaded(modId)) continue;
|
||||
|
||||
@@ -149,7 +149,6 @@ public class RecipeHandlerRef {
|
||||
if (overlayHandler != null && overlayHandler.canCraft(firstGui, this.handler, this.recipeIndex)) {
|
||||
|
||||
if (!firstGui.equals(firstGui.mc.currentScreen)) {
|
||||
if (!firstGui.mc.func_152345_ab()) return false;
|
||||
firstGui.mc.displayGuiScreen(firstGui);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,21 @@ import codechicken.nei.recipe.Recipe.RecipeId;
|
||||
|
||||
public class RecipeItemInputHandler implements IContainerInputHandler, IContainerTooltipHandler {
|
||||
|
||||
public static final RecipeItemInputHandler instance = new RecipeItemInputHandler();
|
||||
|
||||
protected RecipeTooltipLineHandler recipeTooltipLineHandler = null;
|
||||
|
||||
protected RecipeItemInputHandler() {
|
||||
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
RecipeItemInputHandler recipeHandler = new RecipeItemInputHandler();
|
||||
GuiContainerManager.addInputHandler(recipeHandler);
|
||||
GuiContainerManager.addTooltipHandler(recipeHandler);
|
||||
GuiContainerManager.addInputHandler(instance);
|
||||
GuiContainerManager.addTooltipHandler(instance);
|
||||
}
|
||||
|
||||
public void clearTooltipCache() {
|
||||
this.recipeTooltipLineHandler = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,16 +73,17 @@ public class RecipeItemInputHandler implements IContainerInputHandler, IContaine
|
||||
: null;
|
||||
|
||||
if (recipeId == null) {
|
||||
recipeTooltipLineHandler = null;
|
||||
} else if (recipeTooltipLineHandler == null || !recipeTooltipLineHandler.getRecipeId().equals(recipeId)) {
|
||||
recipeTooltipLineHandler = new RecipeTooltipLineHandler(recipeId);
|
||||
}
|
||||
clearTooltipCache();
|
||||
} else if (this.recipeTooltipLineHandler == null
|
||||
|| !this.recipeTooltipLineHandler.getRecipeId().equals(recipeId)) {
|
||||
this.recipeTooltipLineHandler = new RecipeTooltipLineHandler(recipeId);
|
||||
}
|
||||
|
||||
if (recipeTooltipLineHandler != null) {
|
||||
currenttip.add(GuiDraw.TOOLTIP_HANDLER + GuiDraw.getTipLineId(recipeTooltipLineHandler));
|
||||
if (this.recipeTooltipLineHandler != null) {
|
||||
currenttip.add(GuiDraw.TOOLTIP_HANDLER + GuiDraw.getTipLineId(this.recipeTooltipLineHandler));
|
||||
}
|
||||
} else {
|
||||
recipeTooltipLineHandler = null;
|
||||
clearTooltipCache();
|
||||
}
|
||||
|
||||
return currenttip;
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.event.ClickEvent;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.ChatComponentText;
|
||||
import net.minecraft.util.ChatComponentTranslation;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import codechicken.core.CommonUtils;
|
||||
import codechicken.nei.NEIClientConfig;
|
||||
import codechicken.nei.NEIClientUtils;
|
||||
import codechicken.nei.PositionedStack;
|
||||
import codechicken.nei.config.GuiItemIconDumper;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.recipe.Recipe.RecipeIngredient;
|
||||
import codechicken.nei.util.NBTJson;
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper;
|
||||
|
||||
/**
|
||||
* Writes recipes as JSON, one object per line, with stacks in the format of {@link StackInfo#itemStackToNBT}.
|
||||
*/
|
||||
public class RecipeJsonWriter {
|
||||
|
||||
protected static Field mEUt = null;
|
||||
protected static Field mDuration = null;
|
||||
protected static Field mRecipe = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
final ClassLoader loader = RecipeJsonWriter.class.getClassLoader();
|
||||
final Class<?> gtRecipe = ReflectionHelper
|
||||
.getClass(loader, "gregtech.api.util.GTRecipe", "gregtech.api.util.GT_Recipe");
|
||||
final Class<?> cachedDefaultRecipe = ReflectionHelper.getClass(
|
||||
loader,
|
||||
"gregtech.nei.GTNEIDefaultHandler$CachedDefaultRecipe",
|
||||
"gregtech.nei.GT_NEI_DefaultHandler$CachedDefaultRecipe");
|
||||
|
||||
mEUt = gtRecipe.getField("mEUt");
|
||||
mDuration = gtRecipe.getField("mDuration");
|
||||
mRecipe = cachedDefaultRecipe.getField("mRecipe");
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
private static final File DUMP_DIR = new File(CommonUtils.getMinecraftDir(), "dumps/recipes");
|
||||
|
||||
// display names by stack NBT without Count, built once per dump
|
||||
private final Map<String, String> names = new HashMap<>();
|
||||
private int dumped = 0;
|
||||
private int skipped = 0;
|
||||
|
||||
public static void dump(IRecipeHandler handler, List<Integer> recipeIndices) {
|
||||
final RecipeJsonWriter dumper = new RecipeJsonWriter();
|
||||
final File file = new File(DUMP_DIR, fileName(handler) + ".jsonl");
|
||||
|
||||
try {
|
||||
final Stopwatch stopwatch = Stopwatch.createStarted();
|
||||
dumper.writeFile(file, Collections.singletonList(handler), h -> recipeIndices);
|
||||
NEIClientConfig.logger.info("Writing " + dumper.dumped + " recipes took " + stopwatch.stop());
|
||||
dumper.printDumped(file);
|
||||
} catch (Exception e) {
|
||||
printFailed(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all recipes of every crafting handler and writes them either all to {@code dumps/recipes.jsonl} or each
|
||||
* handler to its own file in {@code dumps/recipes}.
|
||||
*/
|
||||
public static void dumpAll(boolean separate) {
|
||||
final RecipeJsonWriter dumper = new RecipeJsonWriter();
|
||||
|
||||
try {
|
||||
final Stopwatch stopwatch = Stopwatch.createStarted();
|
||||
final List<ICraftingHandler> handlers = GuiCraftingRecipe.getCraftingHandlers("all");
|
||||
NEIClientConfig.logger.info("Loading " + handlers.size() + " recipe handlers took " + stopwatch.stop());
|
||||
stopwatch.reset().start();
|
||||
|
||||
if (separate) {
|
||||
if (DUMP_DIR.exists()) {
|
||||
for (File f : DUMP_DIR.listFiles()) if (f.isFile()) f.delete();
|
||||
} else DUMP_DIR.mkdirs();
|
||||
|
||||
for (ICraftingHandler handler : handlers) {
|
||||
final String name = fileName(handler);
|
||||
File file = new File(DUMP_DIR, name + ".jsonl");
|
||||
for (int i = 2; file.exists(); i++) file = new File(DUMP_DIR, name + '_' + i + ".jsonl");
|
||||
|
||||
dumper.writeFile(file, Collections.singletonList(handler), RecipeJsonWriter::filteredRecipes);
|
||||
}
|
||||
|
||||
NEIClientConfig.logger.info("Writing " + dumper.dumped + " recipes took " + stopwatch.stop());
|
||||
dumper.printDumped(DUMP_DIR);
|
||||
} else {
|
||||
final File file = new File(CommonUtils.getMinecraftDir(), "dumps/recipes.jsonl");
|
||||
dumper.writeFile(file, handlers, RecipeJsonWriter::filteredRecipes);
|
||||
NEIClientConfig.logger.info("Writing " + dumper.dumped + " recipes took " + stopwatch.stop());
|
||||
dumper.printDumped(file);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
printFailed(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String fileName(IRecipeHandler handler) {
|
||||
return GuiItemIconDumper
|
||||
.cleanFileName(EnumChatFormatting.getTextWithoutFormattingCodes(handler.getRecipeName()).trim());
|
||||
}
|
||||
|
||||
private static List<Integer> filteredRecipes(IRecipeHandler handler) {
|
||||
return new SearchRecipeHandler<>(handler).getFilteredRecipes();
|
||||
}
|
||||
|
||||
private void writeFile(File file, List<? extends IRecipeHandler> handlers,
|
||||
Function<IRecipeHandler, List<Integer>> recipeIndices) throws IOException {
|
||||
file.getParentFile().mkdirs();
|
||||
|
||||
try (PrintWriter writer = new PrintWriter(file, StandardCharsets.UTF_8.name())) {
|
||||
for (IRecipeHandler handler : handlers) {
|
||||
write(writer, handler, recipeIndices.apply(handler));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void printDumped(File file) {
|
||||
final Path minecraftDir = CommonUtils.getMinecraftDir().getAbsoluteFile().toPath().normalize();
|
||||
final String path = minecraftDir.relativize(file.getAbsoluteFile().toPath().normalize()).toString()
|
||||
.replace('\\', '/');
|
||||
final ChatComponentText chatLink = new ChatComponentText(path);
|
||||
chatLink.getChatStyle().setChatClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, file.getAbsolutePath()));
|
||||
chatLink.getChatStyle().setUnderlined(true);
|
||||
NEIClientUtils.printChatMessage(
|
||||
new ChatComponentTranslation("nei.options.tools.dump.recipes.dumped", this.dumped, chatLink));
|
||||
|
||||
if (this.skipped > 0) {
|
||||
NEIClientUtils.printChatMessage(
|
||||
new ChatComponentTranslation("nei.options.tools.dump.recipes.skipped", this.skipped));
|
||||
}
|
||||
}
|
||||
|
||||
private static void printFailed(Exception e) {
|
||||
NEIClientConfig.logger.error("Error dumping recipes", e);
|
||||
NEIClientUtils.printChatMessage(
|
||||
new ChatComponentTranslation("nei.options.tools.dump.recipes.failed", e.getMessage()));
|
||||
}
|
||||
|
||||
private void write(PrintWriter writer, IRecipeHandler handler, List<Integer> recipeIndices) {
|
||||
for (int recipeIndex : recipeIndices) {
|
||||
final String line;
|
||||
|
||||
try {
|
||||
line = recipeJson(handler, recipeIndex);
|
||||
} catch (Exception e) {
|
||||
NEIClientConfig.logger.warn("Skipping recipe {} of {}", recipeIndex, handler.getRecipeName(), e);
|
||||
this.skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
writer.println(line);
|
||||
this.dumped++;
|
||||
}
|
||||
}
|
||||
|
||||
private String recipeJson(IRecipeHandler handler, int recipeIndex) throws IllegalAccessException {
|
||||
final Recipe recipe = Recipe.of(handler, recipeIndex);
|
||||
final JsonObject json = new JsonObject();
|
||||
json.addProperty("handler", recipe.getHandlerName());
|
||||
json.add("ingredients", slotsJson(recipe.getIngredients(), handler instanceof ShapedRecipeHandler));
|
||||
json.add("results", slotsJson(recipe.getResults(), false));
|
||||
|
||||
final JsonObject gt = gtJson(handler, recipeIndex);
|
||||
if (gt != null) {
|
||||
json.add("gt", gt);
|
||||
}
|
||||
|
||||
return NBTJson.toJson(json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Each slot's shown stack, with {@code anyOf} listing every accepted stack. In a crafting grid, an ingredient's
|
||||
* container item (an empty bucket, a damaged tool) goes under {@code returns}.
|
||||
*/
|
||||
private JsonArray slotsJson(List<RecipeIngredient> slots, boolean craftingGrid) {
|
||||
final JsonArray array = new JsonArray();
|
||||
|
||||
for (RecipeIngredient slot : slots) {
|
||||
final ItemStack stack = slot.getItemStack();
|
||||
final JsonObject json = stackJson(stack);
|
||||
|
||||
if (json == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (slot.getChance() != PositionedStack.CHANCE_FULL) {
|
||||
json.addProperty("chance", slot.getChance());
|
||||
}
|
||||
|
||||
if (slot.getPermutations().size() > 1) {
|
||||
final JsonArray anyOf = new JsonArray();
|
||||
|
||||
for (ItemStack permutation : slot.getPermutations()) {
|
||||
final JsonObject option = stackJson(permutation);
|
||||
|
||||
if (option != null) {
|
||||
option.remove("Count");
|
||||
anyOf.add(option);
|
||||
}
|
||||
}
|
||||
|
||||
json.add("anyOf", anyOf);
|
||||
}
|
||||
|
||||
if (craftingGrid) {
|
||||
final JsonObject container = stackJson(containerItem(stack));
|
||||
|
||||
if (container != null) {
|
||||
json.add("returns", container);
|
||||
}
|
||||
}
|
||||
|
||||
array.add(json);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
private JsonObject stackJson(ItemStack stack) {
|
||||
final NBTTagCompound nbTag = stack != null ? StackInfo.itemStackToNBT(stack) : null;
|
||||
|
||||
if (nbTag == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final NBTBase count = nbTag.getTag("Count");
|
||||
nbTag.removeTag("Count");
|
||||
final String name = this.names.computeIfAbsent(
|
||||
nbTag.toString(),
|
||||
key -> EnumChatFormatting
|
||||
.getTextWithoutFormattingCodes(GuiContainerManager.itemDisplayNameShort(stack)));
|
||||
|
||||
if (count != null) {
|
||||
nbTag.setTag("Count", count);
|
||||
}
|
||||
|
||||
final JsonObject json = NBTJson.toJsonObject(nbTag).getAsJsonObject();
|
||||
json.addProperty("name", name);
|
||||
return json;
|
||||
}
|
||||
|
||||
private static ItemStack containerItem(ItemStack stack) {
|
||||
if (!stack.getItem().hasContainerItem(stack)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final boolean isPausedItemDamageSound = StackInfo.isPausedItemDamageSound();
|
||||
|
||||
try {
|
||||
StackInfo.pauseItemDamageSound(true);
|
||||
return stack.getItem().getContainerItem(stack);
|
||||
} finally {
|
||||
StackInfo.pauseItemDamageSound(isPausedItemDamageSound);
|
||||
}
|
||||
}
|
||||
|
||||
private static JsonObject gtJson(IRecipeHandler handler, int recipeIndex) throws IllegalAccessException {
|
||||
if (mRecipe == null || !(handler instanceof TemplateRecipeHandler templateHandler)
|
||||
|| recipeIndex >= templateHandler.arecipes.size()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Object cachedRecipe = templateHandler.arecipes.get(recipeIndex);
|
||||
|
||||
if (!mRecipe.getDeclaringClass().isInstance(cachedRecipe)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Object gtRecipe = mRecipe.get(cachedRecipe);
|
||||
final long eut = ((Number) mEUt.get(gtRecipe)).longValue();
|
||||
final long duration = ((Number) mDuration.get(gtRecipe)).longValue();
|
||||
final JsonObject gt = new JsonObject();
|
||||
gt.addProperty("eut", eut);
|
||||
gt.addProperty("durationTicks", duration);
|
||||
gt.addProperty("totalEU", eut * duration);
|
||||
return gt;
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,6 @@ public class RecipeTooltipLineHandler implements ITooltipLineHandler {
|
||||
|
||||
protected long lastUpdate = System.currentTimeMillis();
|
||||
protected String recipeName = "";
|
||||
protected GuiRecipe<?> gui = null;
|
||||
protected RecipeHandlerRef handlerRef = null;
|
||||
protected RecipeWidget widget = null;
|
||||
protected RecipeId recipeId = null;
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
package codechicken.nei.recipe;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.guihook.IContainerInputHandler;
|
||||
import codechicken.nei.guihook.IContainerTooltipHandler;
|
||||
import codechicken.nei.recipe.TemplateRecipeHandler.RecipeTransferRect;
|
||||
|
||||
public class RecipeTransferRectHandler implements IContainerInputHandler, IContainerTooltipHandler {
|
||||
|
||||
private static final Map<Class<? extends GuiContainer>, Set<RecipeTransferRect>> guiMap = new ConcurrentHashMap<>();
|
||||
|
||||
static {
|
||||
final RecipeTransferRectHandler handler = new RecipeTransferRectHandler();
|
||||
GuiContainerManager.addInputHandler(handler);
|
||||
GuiContainerManager.addTooltipHandler(handler);
|
||||
}
|
||||
|
||||
public static void registerRectsToGuis(List<Class<? extends GuiContainer>> classes,
|
||||
List<RecipeTransferRect> rects) {
|
||||
if (classes == null) return;
|
||||
|
||||
for (Class<? extends GuiContainer> clazz : classes) {
|
||||
guiMap.computeIfAbsent(clazz, k -> new LinkedHashSet<>()).addAll(rects);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canHandle(GuiContainer gui) {
|
||||
return guiMap.containsKey(gui.getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyCode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHotkeyPressed(GuiContainer gui) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
|
||||
if (!canHandle(gui)) return false;
|
||||
|
||||
if (button == 0) {
|
||||
return transferRect(gui, false);
|
||||
} else if (button == 1) {
|
||||
return transferRect(gui, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean transferRect(GuiContainer gui, boolean usage) {
|
||||
final int[] offset = RecipeInfo.getGuiOffset(gui);
|
||||
return TemplateRecipeHandler.transferRect(gui, guiMap.get(gui.getClass()), offset[0], offset[1], usage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKeyTyped(GuiContainer gui, char keyChar, int keyID) {}
|
||||
|
||||
@Override
|
||||
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {}
|
||||
|
||||
@Override
|
||||
public void onMouseUp(GuiContainer gui, int mousex, int mousey, int button) {}
|
||||
|
||||
@Override
|
||||
public boolean keyTyped(GuiContainer gui, char keyChar, int keyID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {}
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
|
||||
if (!canHandle(gui)) return currenttip;
|
||||
|
||||
if (GuiContainerManager.shouldShowTooltip(gui) && currenttip.size() == 0) {
|
||||
int[] offset = RecipeInfo.getGuiOffset(gui);
|
||||
currenttip = TemplateRecipeHandler
|
||||
.transferRectTooltip(gui, guiMap.get(gui.getClass()), offset[0], offset[1], currenttip);
|
||||
}
|
||||
return currenttip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> handleHotkeys(GuiContainer gui, int mousex, int mousey, Map<String, String> hotkeys) {
|
||||
return hotkeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseDragged(GuiContainer gui, int mousex, int mousey, int button, long heldTime) {}
|
||||
}
|
||||
@@ -43,6 +43,10 @@ public class ShapedRecipeHandler extends TemplateRecipeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
protected static List<IRecipe> getCraftingRecipesSnapshot() {
|
||||
return new ArrayList<>(CraftingManager.getInstance().getRecipeList());
|
||||
}
|
||||
|
||||
public class CachedShapedRecipe extends CachedRecipe {
|
||||
|
||||
public ArrayList<PositionedStack> ingredients;
|
||||
@@ -102,7 +106,7 @@ public class ShapedRecipeHandler extends TemplateRecipeHandler {
|
||||
@Override
|
||||
public void loadCraftingRecipes(String outputId, Object... results) {
|
||||
if (outputId.equals("crafting") && getClass() == ShapedRecipeHandler.class) {
|
||||
for (IRecipe irecipe : CraftingManager.getInstance().getRecipeList()) {
|
||||
for (IRecipe irecipe : getCraftingRecipesSnapshot()) {
|
||||
CachedShapedRecipe recipe = null;
|
||||
|
||||
if (irecipe instanceof ShapedRecipes shaped) {
|
||||
@@ -117,7 +121,7 @@ public class ShapedRecipeHandler extends TemplateRecipeHandler {
|
||||
}
|
||||
}
|
||||
} else if (outputId.equals("crafting2x2") && getClass() == ShapedRecipeHandler.class) {
|
||||
for (IRecipe irecipe : CraftingManager.getInstance().getRecipeList()) {
|
||||
for (IRecipe irecipe : getCraftingRecipesSnapshot()) {
|
||||
|
||||
if (irecipe instanceof ShapedRecipes shaped && shaped.recipeWidth <= 2 && shaped.recipeHeight <= 2) {
|
||||
CachedShapedRecipe recipe = new CachedShapedRecipe(shaped);
|
||||
@@ -133,7 +137,7 @@ public class ShapedRecipeHandler extends TemplateRecipeHandler {
|
||||
|
||||
@Override
|
||||
public void loadCraftingRecipes(ItemStack result) {
|
||||
for (IRecipe irecipe : CraftingManager.getInstance().getRecipeList()) {
|
||||
for (IRecipe irecipe : getCraftingRecipesSnapshot()) {
|
||||
if (NEIServerUtils.areStacksSameTypeCrafting(irecipe.getRecipeOutput(), result)) {
|
||||
CachedShapedRecipe recipe = null;
|
||||
if (irecipe instanceof ShapedRecipes) recipe = new CachedShapedRecipe((ShapedRecipes) irecipe);
|
||||
@@ -149,7 +153,7 @@ public class ShapedRecipeHandler extends TemplateRecipeHandler {
|
||||
|
||||
@Override
|
||||
public void loadUsageRecipes(ItemStack ingredient) {
|
||||
for (IRecipe irecipe : CraftingManager.getInstance().getRecipeList()) {
|
||||
for (IRecipe irecipe : getCraftingRecipesSnapshot()) {
|
||||
CachedShapedRecipe recipe = null;
|
||||
if (irecipe instanceof ShapedRecipes) recipe = new CachedShapedRecipe((ShapedRecipes) irecipe);
|
||||
else if (irecipe instanceof ShapedOreRecipe) recipe = forgeShapedRecipe((ShapedOreRecipe) irecipe);
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.CraftingManager;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.ShapelessRecipes;
|
||||
import net.minecraftforge.oredict.ShapelessOreRecipe;
|
||||
@@ -83,7 +82,7 @@ public class ShapelessRecipeHandler extends ShapedRecipeHandler {
|
||||
@Override
|
||||
public void loadCraftingRecipes(String outputId, Object... results) {
|
||||
if (outputId.equals("crafting") && getClass() == ShapelessRecipeHandler.class) {
|
||||
List<IRecipe> allrecipes = CraftingManager.getInstance().getRecipeList();
|
||||
List<IRecipe> allrecipes = getCraftingRecipesSnapshot();
|
||||
for (IRecipe irecipe : allrecipes) {
|
||||
CachedShapelessRecipe recipe = null;
|
||||
|
||||
@@ -98,7 +97,7 @@ public class ShapelessRecipeHandler extends ShapedRecipeHandler {
|
||||
}
|
||||
}
|
||||
} else if (outputId.equals("crafting2x2") && getClass() == ShapelessRecipeHandler.class) {
|
||||
List<IRecipe> allrecipes = CraftingManager.getInstance().getRecipeList();
|
||||
List<IRecipe> allrecipes = getCraftingRecipesSnapshot();
|
||||
for (IRecipe irecipe : allrecipes) {
|
||||
CachedShapelessRecipe recipe = null;
|
||||
|
||||
@@ -119,7 +118,7 @@ public class ShapelessRecipeHandler extends ShapedRecipeHandler {
|
||||
|
||||
@Override
|
||||
public void loadCraftingRecipes(ItemStack result) {
|
||||
List<IRecipe> allrecipes = CraftingManager.getInstance().getRecipeList();
|
||||
List<IRecipe> allrecipes = getCraftingRecipesSnapshot();
|
||||
for (IRecipe irecipe : allrecipes) {
|
||||
if (NEIServerUtils.areStacksSameTypeCrafting(irecipe.getRecipeOutput(), result)) {
|
||||
CachedShapelessRecipe recipe = null;
|
||||
@@ -136,7 +135,7 @@ public class ShapelessRecipeHandler extends ShapedRecipeHandler {
|
||||
|
||||
@Override
|
||||
public void loadUsageRecipes(ItemStack ingredient) {
|
||||
List<IRecipe> allrecipes = CraftingManager.getInstance().getRecipeList();
|
||||
List<IRecipe> allrecipes = getCraftingRecipesSnapshot();
|
||||
for (IRecipe irecipe : allrecipes) {
|
||||
CachedShapelessRecipe recipe = null;
|
||||
if (irecipe instanceof ShapelessRecipes) recipe = shapelessRecipe((ShapelessRecipes) irecipe);
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -16,7 +17,7 @@ import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.IFluidContainerItem;
|
||||
|
||||
import codechicken.nei.ClientHandler;
|
||||
import codechicken.nei.ItemStackMap;
|
||||
import codechicken.nei.ItemStackMap.StackMetaKey;
|
||||
import codechicken.nei.LRUCache;
|
||||
import codechicken.nei.api.IStackStringifyHandler;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
@@ -31,7 +32,7 @@ public class StackInfo {
|
||||
private static final FluidStack NULL_FLUID = new FluidStack(FluidRegistry.WATER, 0);
|
||||
public static final List<IStackStringifyHandler> stackStringifyHandlers = new ArrayList<>();
|
||||
private static final Map<String, HashMap<String, String[]>> guidfilters = new HashMap<>();
|
||||
private static final ItemStackMap<String> guidcache = new ItemStackMap<>();
|
||||
private static final Map<Item, Map<StackMetaKey, String>> guidcache = new ConcurrentHashMap<>();
|
||||
private static final LRUCache<ItemStackKey, FluidStack> fluidcache = new LRUCache<>(200);
|
||||
private static boolean isPausedItemDamageSound = false;
|
||||
|
||||
@@ -182,7 +183,9 @@ public class StackInfo {
|
||||
}
|
||||
|
||||
public static String getItemStackGUID(ItemStack stack) {
|
||||
String guid = guidcache.get(stack);
|
||||
final Item stackItem = stack.getItem();
|
||||
final Map<StackMetaKey, String> itemGuids = stackItem != null ? guidcache.get(stackItem) : null;
|
||||
String guid = itemGuids != null ? itemGuids.get(new StackMetaKey(stack)) : null;
|
||||
|
||||
if (guid != null) {
|
||||
return guid;
|
||||
@@ -190,7 +193,7 @@ public class StackInfo {
|
||||
|
||||
final NBTTagCompound nbTag = itemStackToNBT(stack, false);
|
||||
|
||||
if (nbTag == null) {
|
||||
if (nbTag == null || stack.getItem() == null) {
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
@@ -239,16 +242,15 @@ public class StackInfo {
|
||||
}
|
||||
});
|
||||
|
||||
synchronized (guidcache) {
|
||||
guidcache.put(stack, keys.toString());
|
||||
}
|
||||
guid = keys.toString();
|
||||
} else {
|
||||
synchronized (guidcache) {
|
||||
guidcache.put(stack, NBTHelper.toString(nbTag));
|
||||
}
|
||||
guid = NBTHelper.toString(nbTag);
|
||||
}
|
||||
|
||||
return guidcache.get(stack);
|
||||
guidcache.computeIfAbsent(stack.getItem(), item -> new ConcurrentHashMap<>())
|
||||
.put(new StackMetaKey(stack.copy()), guid);
|
||||
|
||||
return guid;
|
||||
}
|
||||
|
||||
public static void loadGuidFilters() {
|
||||
@@ -269,20 +271,30 @@ public class StackInfo {
|
||||
public static ItemStack getItemStackWithMinimumDamage(ItemStack[] stacks) {
|
||||
ItemStack result = stacks[0];
|
||||
|
||||
if (stacks.length > 1) {
|
||||
for (ItemStack stack : stacks) {
|
||||
// to optimize compare recipes from permutation, an item with a minimum strId and damage is taken so as
|
||||
// not to check everything permutation items
|
||||
if (stack.getItem() != null && !ItemInfo.isHidden(stack)
|
||||
&& (stack.getItemDamage() < result.getItemDamage()
|
||||
|| stack.getItemDamage() == result.getItemDamage()
|
||||
&& Item.itemRegistry.getNameForObject(stack.getItem())
|
||||
.compareTo(Item.itemRegistry.getNameForObject(result.getItem())) < 0)) {
|
||||
result = stack;
|
||||
}
|
||||
for (int i = 1; i < stacks.length; i++) {
|
||||
final ItemStack stack = stacks[i];
|
||||
if (stack.getItem() != null && isLess(stack, result) && !ItemInfo.isHidden(stack)) {
|
||||
result = stack;
|
||||
}
|
||||
}
|
||||
|
||||
return result.copy();
|
||||
}
|
||||
|
||||
private static boolean isLess(ItemStack stack, ItemStack other) {
|
||||
if (stack.getItemDamage() != other.getItemDamage()) {
|
||||
return stack.getItemDamage() < other.getItemDamage();
|
||||
}
|
||||
|
||||
final String name = getItemName(stack);
|
||||
if (name == null) return false;
|
||||
|
||||
final String otherName = getItemName(other);
|
||||
return otherName == null || name.compareTo(otherName) < 0;
|
||||
}
|
||||
|
||||
private static String getItemName(ItemStack stack) {
|
||||
final Item item = stack.getItem();
|
||||
return item == null ? null : Item.itemRegistry.getNameForObject(item);
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,12 @@ import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -40,8 +39,6 @@ import codechicken.nei.api.IOverlayHandler;
|
||||
import codechicken.nei.api.IRecipeOverlayRenderer;
|
||||
import codechicken.nei.api.IStackPositioner;
|
||||
import codechicken.nei.guihook.GuiContainerManager;
|
||||
import codechicken.nei.guihook.IContainerInputHandler;
|
||||
import codechicken.nei.guihook.IContainerTooltipHandler;
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
|
||||
/**
|
||||
@@ -176,6 +173,16 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read only when {@link #getResult()} is {@code null} and {@link #getOtherStacks()} returns the results, see
|
||||
* {@link IRecipeHandler#getAuxiliaryStacks(int)}.
|
||||
*
|
||||
* @return The fuel or catalysts of a recipe with several results.
|
||||
*/
|
||||
public List<PositionedStack> getAuxiliaries() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public List<PositionedStack> getCycledIngredients(int cycle, List<PositionedStack> ingredients) {
|
||||
return ingredients;
|
||||
@@ -262,114 +269,26 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
|
||||
return rect;
|
||||
}
|
||||
|
||||
Rectangle rect;
|
||||
String outputId;
|
||||
Object[] results;
|
||||
public boolean contains(GuiContainer gui, int offsetx, int offsety) {
|
||||
final Point pos = GuiDraw.getMousePosition();
|
||||
return rect.contains(pos.x - gui.guiLeft - offsetx, pos.y - gui.guiTop - offsety);
|
||||
}
|
||||
|
||||
public boolean open(boolean usage) {
|
||||
return usage ? GuiUsageRecipe.openRecipeGui(outputId, results)
|
||||
: GuiCraftingRecipe.openRecipeGui(outputId, results);
|
||||
}
|
||||
|
||||
public Rectangle rect;
|
||||
public String outputId;
|
||||
public Object[] results;
|
||||
}
|
||||
|
||||
public static class RecipeTransferRectHandler implements IContainerInputHandler, IContainerTooltipHandler {
|
||||
|
||||
private static final Map<Class<? extends GuiContainer>, HashSet<RecipeTransferRect>> guiMap = new ConcurrentHashMap<>();
|
||||
|
||||
public static void registerRectsToGuis(List<Class<? extends GuiContainer>> classes,
|
||||
List<RecipeTransferRect> rects) {
|
||||
if (classes == null) return;
|
||||
|
||||
for (Class<? extends GuiContainer> clazz : classes) {
|
||||
HashSet<RecipeTransferRect> set = guiMap.computeIfAbsent(clazz, k -> new HashSet<>());
|
||||
set.addAll(rects);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canHandle(GuiContainer gui) {
|
||||
return guiMap.containsKey(gui.getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyCode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHotkeyPressed(GuiContainer gui) {
|
||||
if (!canHandle(gui)) return false;
|
||||
|
||||
if (KeyManager.isKeyDown("recipe.recipe")) {
|
||||
return transferRect(gui, false);
|
||||
} else if (KeyManager.isKeyDown("recipe.usage")) {
|
||||
return transferRect(gui, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
|
||||
if (!canHandle(gui)) return false;
|
||||
|
||||
if (button == 0) return transferRect(gui, false);
|
||||
else if (button == 1) return transferRect(gui, true);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean transferRect(GuiContainer gui, boolean usage) {
|
||||
int[] offset = RecipeInfo.getGuiOffset(gui);
|
||||
return TemplateRecipeHandler.transferRect(gui, guiMap.get(gui.getClass()), offset[0], offset[1], usage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKeyTyped(GuiContainer gui, char keyChar, int keyID) {}
|
||||
|
||||
@Override
|
||||
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {}
|
||||
|
||||
@Override
|
||||
public void onMouseUp(GuiContainer gui, int mousex, int mousey, int button) {}
|
||||
|
||||
@Override
|
||||
public boolean keyTyped(GuiContainer gui, char keyChar, int keyID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {}
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
|
||||
if (!canHandle(gui)) return currenttip;
|
||||
|
||||
if (GuiContainerManager.shouldShowTooltip(gui) && currenttip.size() == 0) {
|
||||
int[] offset = RecipeInfo.getGuiOffset(gui);
|
||||
currenttip = TemplateRecipeHandler
|
||||
.transferRectTooltip(gui, guiMap.get(gui.getClass()), offset[0], offset[1], 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseDragged(GuiContainer gui, int mousex, int mousey, int button, long heldTime) {}
|
||||
}
|
||||
|
||||
static {
|
||||
GuiContainerManager.addInputHandler(new RecipeTransferRectHandler());
|
||||
GuiContainerManager.addTooltipHandler(new RecipeTransferRectHandler());
|
||||
/**
|
||||
* @deprecated moved to {@link codechicken.nei.recipe.RecipeTransferRectHandler}
|
||||
*/
|
||||
@Deprecated
|
||||
public static class RecipeTransferRectHandler extends codechicken.nei.recipe.RecipeTransferRectHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -641,6 +560,16 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
|
||||
return arecipes.get(recipe).getOtherStacks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PositionedStack> getAuxiliaryStacks(int recipe) {
|
||||
// goes through the handler methods, subclasses may override them instead of the cached recipe ones
|
||||
if (getResultStack(recipe) != null) {
|
||||
return getOtherStacks(recipe);
|
||||
}
|
||||
|
||||
return arecipes.get(recipe).getAuxiliaries();
|
||||
}
|
||||
|
||||
public void onUpdate() {
|
||||
cycleticks++;
|
||||
}
|
||||
@@ -709,25 +638,19 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
|
||||
return transferRect(gui, transferRects, offset.x, offset.y, usage);
|
||||
}
|
||||
|
||||
private static boolean transferRect(GuiContainer gui, Collection<RecipeTransferRect> transferRects, int offsetx,
|
||||
static boolean transferRect(GuiContainer gui, Collection<RecipeTransferRect> transferRects, int offsetx,
|
||||
int offsety, boolean usage) {
|
||||
Point pos = GuiDraw.getMousePosition();
|
||||
Point relMouse = new Point(pos.x - gui.guiLeft - offsetx, pos.y - gui.guiTop - offsety);
|
||||
for (RecipeTransferRect rect : transferRects) {
|
||||
if (rect.rect.contains(relMouse) && (usage ? GuiUsageRecipe.openRecipeGui(rect.outputId, rect.results)
|
||||
: GuiCraftingRecipe.openRecipeGui(rect.outputId, rect.results)))
|
||||
return true;
|
||||
if (rect.contains(gui, offsetx, offsety) && rect.open(usage)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static List<String> transferRectTooltip(GuiContainer gui, Collection<RecipeTransferRect> transferRects,
|
||||
int offsetx, int offsety, List<String> currenttip) {
|
||||
Point pos = GuiDraw.getMousePosition();
|
||||
Point relMouse = new Point(pos.x - gui.guiLeft - offsetx, pos.y - gui.guiTop - offsety);
|
||||
static List<String> transferRectTooltip(GuiContainer gui, Collection<RecipeTransferRect> transferRects, int offsetx,
|
||||
int offsety, List<String> currenttip) {
|
||||
for (RecipeTransferRect rect : transferRects) {
|
||||
if (rect.rect.contains(relMouse)) {
|
||||
if (rect.contains(gui, offsetx, offsety)) {
|
||||
currenttip.add(NEIClientUtils.translate("recipe.tooltip"));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import codechicken.nei.recipe.GuiRecipeTab;
|
||||
import codechicken.nei.recipe.HandlerInfo;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
import codechicken.nei.recipe.RecipeHandlerRef;
|
||||
import codechicken.nei.recipe.RecipeJsonWriter;
|
||||
import codechicken.nei.recipe.ShapedRecipeHandler;
|
||||
import codechicken.nei.recipe.TemplateRecipeHandler;
|
||||
import codechicken.nei.recipe.TemplateRecipeHandler.RecipeTransferRect;
|
||||
@@ -272,6 +273,8 @@ public class DebugHandlerWidget extends Widget implements IContainerTooltipHandl
|
||||
API.addRecipeFilter(() -> this.duplicatesOnly ? this::isDuplicate : null);
|
||||
}
|
||||
|
||||
y = addExportWidget("ExportRecipes", y);
|
||||
|
||||
this.h = 10 + LINE_HEIGHT + y;
|
||||
this.container.h = this.h - INLINE_PADDING * 2 - LINE_HEIGHT;
|
||||
}
|
||||
@@ -332,6 +335,45 @@ public class DebugHandlerWidget extends Widget implements IContainerTooltipHandl
|
||||
return y + value.h + 1;
|
||||
}
|
||||
|
||||
private int addExportWidget(String key, int y) {
|
||||
final LabelWidget label = new LabelWidget(0x888888, false) {
|
||||
|
||||
@Override
|
||||
public List<String> handleTooltip(int mx, int my, List<String> tooltip) {
|
||||
if (contains(mx, my)) {
|
||||
super.handleTooltip(mx, my, tooltip);
|
||||
tooltip.add(
|
||||
EnumChatFormatting.GRAY + NEIClientUtils.translate("debug.RecipeHandler.export.tooltip"));
|
||||
}
|
||||
|
||||
return tooltip;
|
||||
}
|
||||
};
|
||||
final Button value = new Button(NEIClientUtils.translate("debug.RecipeHandler.export")) {
|
||||
|
||||
@Override
|
||||
public boolean onButtonPress(boolean rightclick) {
|
||||
if (rightclick || !(NEIClientUtils.getGuiContainer() instanceof GuiRecipe<?>recipe)) return false;
|
||||
|
||||
RecipeJsonWriter.dump(recipe.getHandler(), recipe.getFilteredRecipes());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
value.w = 58;
|
||||
value.h = 16;
|
||||
value.y = label.y = y;
|
||||
value.x = this.w - INLINE_PADDING * 2 - value.w - 1;
|
||||
label.w = value.x;
|
||||
|
||||
label.updateValue(NEIClientUtils.translate(TOOLTIP_PREFIX + key));
|
||||
|
||||
this.container.addWidget(label);
|
||||
this.container.addWidget(value);
|
||||
|
||||
return y + value.h + 1;
|
||||
}
|
||||
|
||||
private int addOverrideInfoWidget(String key, int y) {
|
||||
final LabelWidget label = new LabelWidget(0x888888, false);
|
||||
final LabelWidget value = new LabelWidget(0xffffff, true);
|
||||
@@ -691,6 +733,10 @@ public class DebugHandlerWidget extends Widget implements IContainerTooltipHandl
|
||||
});
|
||||
}
|
||||
|
||||
public void clearGuiReferences() {
|
||||
this.hoveredRecipe = null;
|
||||
}
|
||||
|
||||
public void loadHandlerInfoPatch() {
|
||||
|
||||
ClientHandler.loadSettingsFile("handlers.patch", lines -> {
|
||||
|
||||
@@ -10,6 +10,9 @@ import net.minecraftforge.fluids.Fluid;
|
||||
import net.minecraftforge.fluids.FluidRegistry;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
import codechicken.nei.api.IStackStringifyHandler;
|
||||
import codechicken.nei.item.ItemFluidDisplay;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
@@ -22,6 +25,11 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler {
|
||||
protected static Class<?> gtMetaGeneratedTool = null;
|
||||
protected static Field playSound = null;
|
||||
|
||||
private static final Supplier<Item> AE2FC_FLUID_PACKET = Suppliers
|
||||
.memoize(() -> GameRegistry.findItem("ae2fc", "fluid_packet"));
|
||||
private static final Supplier<Item> AE2FC_FLUID_DROP = Suppliers
|
||||
.memoize(() -> GameRegistry.findItem("ae2fc", "fluid_drop"));
|
||||
|
||||
static {
|
||||
try {
|
||||
final ClassLoader loader = GTFluidStackStringifyHandler.class.getClassLoader();
|
||||
@@ -94,11 +102,11 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler {
|
||||
return new FluidStack(fluid, 0);
|
||||
}
|
||||
|
||||
} else if (item == GameRegistry.findItem("ae2fc", "fluid_packet")) {
|
||||
} else if (item == AE2FC_FLUID_PACKET.get()) {
|
||||
NBTTagCompound nbtTag = stack.getTagCompound();
|
||||
|
||||
return FluidStack.loadFluidStackFromNBT((NBTTagCompound) nbtTag.getTag("FluidStack"));
|
||||
} else if (item == GameRegistry.findItem("ae2fc", "fluid_drop")) {
|
||||
} else if (item == AE2FC_FLUID_DROP.get()) {
|
||||
NBTTagCompound nbtTag = stack.getTagCompound();
|
||||
Fluid fluid = FluidRegistry.getFluid(nbtTag.getString("Fluid").toLowerCase());
|
||||
|
||||
@@ -113,9 +121,9 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler {
|
||||
|
||||
@Override
|
||||
public ItemStack normalizeRecipeQueryStack(ItemStack stack) {
|
||||
final Item item = stack.getItem();
|
||||
|
||||
if (stack.getItem() == GameRegistry.findItem("ae2fc", "fluid_drop")
|
||||
|| stack.getItem() == GameRegistry.findItem("ae2fc", "fluid_packet")) {
|
||||
if (item == AE2FC_FLUID_DROP.get() || item == AE2FC_FLUID_PACKET.get()) {
|
||||
final FluidStack fluidStack = getFluid(stack);
|
||||
|
||||
if (fluidStack != null) {
|
||||
@@ -139,8 +147,7 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler {
|
||||
@Override
|
||||
public boolean isFluidDisplayItem(ItemStack stack) {
|
||||
final Item item = stack.getItem();
|
||||
return (itemFluidDisplay != null && itemFluidDisplay.isInstance(item))
|
||||
|| item == GameRegistry.findItem("ae2fc", "fluid_packet");
|
||||
return (itemFluidDisplay != null && itemFluidDisplay.isInstance(item)) || item == AE2FC_FLUID_PACKET.get();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -225,15 +225,10 @@ public class RecipeGroup {
|
||||
|
||||
protected MemberStacks loadStacks(int member) {
|
||||
final int recipeIndex = getRecipeIndex(member);
|
||||
final List<PositionedStack> inputs = new ArrayList<>(this.handler.getIngredientStacks(recipeIndex));
|
||||
final PositionedStack pStackResult = this.handler.getResultStack(recipeIndex);
|
||||
final List<PositionedStack> others = new ArrayList<>(this.handler.getOtherStacks(recipeIndex));
|
||||
|
||||
if (pStackResult != null) {
|
||||
return new MemberStacks(inputs, Collections.singletonList(pStackResult), others);
|
||||
}
|
||||
|
||||
return new MemberStacks(inputs, others, Collections.emptyList());
|
||||
return new MemberStacks(
|
||||
new ArrayList<>(this.handler.getIngredientStacks(recipeIndex)),
|
||||
new ArrayList<>(this.handler.getResultStacks(recipeIndex)),
|
||||
new ArrayList<>(this.handler.getAuxiliaryStacks(recipeIndex)));
|
||||
}
|
||||
|
||||
// re-reads the member stacks from the handler, keeps the cached instances when nothing changed
|
||||
|
||||
@@ -2,15 +2,12 @@ package codechicken.nei.search;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import codechicken.nei.ItemList.EverythingItemFilter;
|
||||
import codechicken.nei.SearchTokenParser;
|
||||
import codechicken.nei.api.IRecipeFilter;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.filter.AllMultiRecipeFilter;
|
||||
import codechicken.nei.filter.AllOthersRecipeFilter;
|
||||
import codechicken.nei.filter.AnyOthersRecipeFilter;
|
||||
import codechicken.nei.filter.RecipeFilter;
|
||||
import codechicken.nei.filter.RecipeFilter.FilterContext;
|
||||
|
||||
@@ -51,11 +48,7 @@ public class RecipeFilterVisitor extends AbstractSearchExpressionVisitor<IRecipe
|
||||
case 1:
|
||||
return new RecipeFilter(FilterContext.OUTPUT, !ctx.allRecipe, itemFilter);
|
||||
case 2:
|
||||
return getAllOrAnyFilter(
|
||||
ctx.allRecipe,
|
||||
itemFilter,
|
||||
AnyOthersRecipeFilter::new,
|
||||
AllOthersRecipeFilter::new);
|
||||
return new RecipeFilter(FilterContext.AUXILIARY, !ctx.allRecipe, itemFilter);
|
||||
// Doesn't support all by default
|
||||
case 3:
|
||||
return new RecipeFilter(FilterContext.ANY, !ctx.allRecipe, itemFilter);
|
||||
@@ -64,15 +57,6 @@ public class RecipeFilterVisitor extends AbstractSearchExpressionVisitor<IRecipe
|
||||
}
|
||||
}
|
||||
|
||||
private IRecipeFilter getAllOrAnyFilter(boolean allRecipe, ItemFilter itemFilter,
|
||||
Function<ItemFilter, IRecipeFilter> createAnyFilter, Function<ItemFilter, IRecipeFilter> createAllFilter) {
|
||||
if (allRecipe) {
|
||||
return createAllFilter.apply(itemFilter);
|
||||
} else {
|
||||
return createAnyFilter.apply(itemFilter);
|
||||
}
|
||||
}
|
||||
|
||||
private IRecipeFilter constructFilter(List<IRecipeFilter> filters) {
|
||||
if (!filters.isEmpty()) {
|
||||
// Propagate the result up
|
||||
|
||||
@@ -26,6 +26,9 @@ public class FavoriteStorage {
|
||||
protected final Map<RecipeId, Long> recipeIdToItemHash = new HashMap<>();
|
||||
protected final Map<Long, ItemStack> itemHashToItemStack = new HashMap<>();
|
||||
|
||||
/** The key of the last looked up stack. Its NBT copies the whole stack, which is looked up every frame. */
|
||||
private static volatile LookupKey lastLookupKey = null;
|
||||
|
||||
public void clear() {
|
||||
this.itemStackToRecipeId.clear();
|
||||
this.fluidToRecipeId.clear();
|
||||
@@ -95,7 +98,7 @@ public class FavoriteStorage {
|
||||
RecipeId recipeId = this.itemHashToRecipeId.get(getItemKey(stack));
|
||||
|
||||
if (recipeId == null) {
|
||||
recipeId = this.itemStackToRecipeId.get(StackInfo.itemStackToNBT(stack, false));
|
||||
recipeId = this.itemStackToRecipeId.get(getLookupKey(stack));
|
||||
}
|
||||
|
||||
if (recipeId == null) {
|
||||
@@ -105,6 +108,28 @@ public class FavoriteStorage {
|
||||
return recipeId;
|
||||
}
|
||||
|
||||
private static NBTTagCompound getLookupKey(ItemStack stack) {
|
||||
LookupKey key = lastLookupKey;
|
||||
|
||||
if (key == null || !key.stack.isItemEqual(stack) || !ItemStack.areItemStackTagsEqual(key.stack, stack)) {
|
||||
key = new LookupKey(stack.copy(), StackInfo.itemStackToNBT(stack, false));
|
||||
lastLookupKey = key;
|
||||
}
|
||||
|
||||
return key.nbt;
|
||||
}
|
||||
|
||||
private static class LookupKey {
|
||||
|
||||
private final ItemStack stack;
|
||||
private final NBTTagCompound nbt;
|
||||
|
||||
private LookupKey(ItemStack stack, NBTTagCompound nbt) {
|
||||
this.stack = stack;
|
||||
this.nbt = nbt;
|
||||
}
|
||||
}
|
||||
|
||||
public ItemStack getItemStack(RecipeId recipeId) {
|
||||
NBTTagCompound itemStackNBT = this.recipeIdToItemStack.get(recipeId);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
@@ -128,8 +129,8 @@ public class ItemUntranslator {
|
||||
private static final String CONFIG_FILE = "untranslator.cfg";
|
||||
private static final ItemUntranslator instance = new ItemUntranslator();
|
||||
|
||||
private final Map<String, String> secondNames = new HashMap<>();
|
||||
private final Map<String, String> processedNames = new HashMap<>();
|
||||
private final Map<String, String> secondNames = new ConcurrentHashMap<>();
|
||||
private final Map<String, String> processedNames = new ConcurrentHashMap<>();
|
||||
|
||||
private ItemUntranslator() {}
|
||||
|
||||
@@ -241,14 +242,19 @@ public class ItemUntranslator {
|
||||
return EnumChatFormatting.getTextWithoutFormattingCodes(name).trim();
|
||||
}
|
||||
|
||||
public synchronized String getItemStackDisplayName(ItemStack stack) {
|
||||
public String getItemStackDisplayName(ItemStack stack) {
|
||||
|
||||
if (stack == null || this.secondNames.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
final String guidKey = StackInfo.getItemStackGUID(stack);
|
||||
final String displayName = this.processedNames.get(guidKey);
|
||||
|
||||
return displayName != null ? displayName : processDisplayName(stack, guidKey);
|
||||
}
|
||||
|
||||
private synchronized String processDisplayName(ItemStack stack, String guidKey) {
|
||||
return this.processedNames.computeIfAbsent(guidKey, stackKey -> {
|
||||
String displayName = this.secondNames.get(stackKey);
|
||||
|
||||
@@ -379,7 +385,7 @@ public class ItemUntranslator {
|
||||
LanguageRegistryPatch.secondLanguageListCache = null;
|
||||
this.processedNames.clear();
|
||||
|
||||
if (ClientHandler.loadSettingsFile(CONFIG_FILE, null, this::parseStream)
|
||||
if (ClientHandler.loadSettingsFile(CONFIG_FILE, this::parseStream)
|
||||
|| ClientHandler.loadSettingsResource(CONFIG_FILE, this::parseStream)) {
|
||||
NEIClientConfig.logger.info("Untranslator loaded");
|
||||
}
|
||||
|
||||
@@ -52,11 +52,6 @@ nei.chat.chunkoverlay.3=Chunk Overlay: GT Ore Veins
|
||||
nei.options=NEI volby
|
||||
nei.options.back=Zpět
|
||||
nei.options.world=Svět
|
||||
nei.options.global=Globální
|
||||
nei.options.global.tip.0=Nastavení se aplikuje pro všechny světy
|
||||
nei.options.global.tip.1=Klikni na W vedle :option pro povolení :override pro tento svět
|
||||
nei.options.wbutton.tip.0=Používám globální nastavení
|
||||
nei.options.wbutton.tip.1=Přepisuji globální nastavení
|
||||
|
||||
nei.options.keys=Nastavení kláves
|
||||
nei.options.keys.gui=NEI Inventář
|
||||
|
||||
@@ -56,11 +56,6 @@ nei.chat.chunkoverlay.3=Chunk Overlay: GT Ore Veins
|
||||
nei.options=NEI-Optionen
|
||||
nei.options.back=Zurück
|
||||
nei.options.world=Welt
|
||||
nei.options.global=Global
|
||||
nei.options.global.tip.0=Optionen werden auf alle Welten angewandt
|
||||
nei.options.global.tip.1=Klicke W neben einer:Option , um das Übergehen: für diese Welt zu aktivieren
|
||||
nei.options.wbutton.tip.0=Nutzt globale Einstellungen
|
||||
nei.options.wbutton.tip.1=Übergeht globale Einstellungen
|
||||
|
||||
nei.options.keys=Tastenbelegung
|
||||
nei.options.keys.gui=NEI Inventar
|
||||
|
||||
@@ -213,11 +213,6 @@ nei.options=NEI Options
|
||||
nei.options.back=Back
|
||||
nei.options.save=Save
|
||||
nei.options.world=World
|
||||
nei.options.global=Global
|
||||
nei.options.global.tip.0=Options apply to all worlds
|
||||
nei.options.global.tip.1=Click the W beside an:option to enable an:override for this world
|
||||
nei.options.wbutton.tip.0=Using global settings
|
||||
nei.options.wbutton.tip.1=Overriding global setting
|
||||
|
||||
nei.options.keys=KeyBindings
|
||||
nei.options.keys.tip=Configure NEI key bindings in the Minecraft controls screen
|
||||
@@ -417,12 +412,6 @@ nei.options.inventory.search.subsetsSearchMode=Item Subsets Search
|
||||
nei.options.inventory.search.subsetsSearchMode.0=Always
|
||||
nei.options.inventory.search.subsetsSearchMode.1=Prefix: %s
|
||||
nei.options.inventory.search.subsetsSearchMode.2=Never
|
||||
nei.options.inventory.guirecipe.creativeTabStyle=Creative or JEI tab style
|
||||
nei.options.inventory.guirecipe.creativeTabStyle.true=Creative
|
||||
nei.options.inventory.guirecipe.creativeTabStyle.false=JEI
|
||||
nei.options.inventory.optimize_gui_overlap_computation=Optimize computation for GUI overlap
|
||||
nei.options.inventory.optimize_gui_overlap_computation.true=Yes
|
||||
nei.options.inventory.optimize_gui_overlap_computation.false=No
|
||||
nei.options.inventory.autocrafting=Autocrafting
|
||||
nei.options.inventory.autocrafting.true=Enabled
|
||||
nei.options.inventory.autocrafting.false=Disabled
|
||||
@@ -576,12 +565,12 @@ nei.options.world.overlays.lock.true=Enabled
|
||||
nei.options.world.overlays.lock.false=Disabled
|
||||
|
||||
nei.options.tools=Tools
|
||||
nei.options.tools.handler_load_from_config=Load handlers from Config
|
||||
nei.options.tools.handler_load_from_config.true=Config
|
||||
nei.options.tools.handler_load_from_config.false=JAR
|
||||
nei.options.tools.catalyst_load_from_config=Load catalysts from Config
|
||||
nei.options.tools.catalyst_load_from_config.true=Config
|
||||
nei.options.tools.catalyst_load_from_config.false=JAR
|
||||
nei.options.tools.export_configs=Default Config Files
|
||||
nei.options.tools.export_configs.button=Export
|
||||
nei.options.tools.export_configs.done=%s was exported to config/NEI
|
||||
nei.options.tools.export_configs.skipped=%s was not exported, see the log
|
||||
nei.options.tools.export_configs.all=All files
|
||||
nei.options.tools.export_configs.all.done=%s default config files were exported to config/NEI
|
||||
nei.options.tools.dump=Data Dumps
|
||||
nei.options.tools.dump.dump=Dump
|
||||
nei.options.tools.dump.dumped=%s IDs dumped to %s
|
||||
@@ -612,6 +601,12 @@ nei.options.tools.dump.handlers=NEI Handlers
|
||||
nei.options.tools.dump.handlers.dumped=handlers were dumped to %s
|
||||
nei.options.tools.dump.handlers.mode.0=CSV
|
||||
nei.options.tools.dump.handlers.mode.1=Json
|
||||
nei.options.tools.dump.recipes=All Handler Recipes
|
||||
nei.options.tools.dump.recipes.combined=Combined
|
||||
nei.options.tools.dump.recipes.separate=Separate
|
||||
nei.options.tools.dump.recipes.dumped=%s recipes were dumped to %s
|
||||
nei.options.tools.dump.recipes.skipped=%s recipes threw an error and were skipped, see the log
|
||||
nei.options.tools.dump.recipes.failed=Failed to dump recipes: %s
|
||||
|
||||
nei.debug.RecipeHandler.title=Debug Recipe Handler
|
||||
nei.debug.RecipeHandler.copy=Copy
|
||||
@@ -633,6 +628,9 @@ nei.debug.RecipeHandler.DuplicatesOnly=Duplicates Only
|
||||
nei.debug.RecipeHandler.AllowOverflowY=Allow Overflow Y
|
||||
nei.debug.RecipeHandler.AllowOverflowX=Allow Overflow X
|
||||
nei.debug.RecipeHandler.Override=Override
|
||||
nei.debug.RecipeHandler.ExportRecipes=Export Recipes
|
||||
nei.debug.RecipeHandler.export=Export
|
||||
nei.debug.RecipeHandler.export.tooltip=Exports the currently visible recipes to JSON.
|
||||
nei.debug.RecipeHandler.checkbox.on=On
|
||||
nei.debug.RecipeHandler.checkbox.off=Off
|
||||
nei.debug.RecipeHandler.yes=Yes
|
||||
@@ -648,6 +646,8 @@ nei.recipe.search.tooltip.name=Filter Syntax
|
||||
nei.recipe.search.tooltip.shift=§7Hold §6Shift§7 for more info
|
||||
nei.recipe.search.tooltip.input=%s§ftext§8 - §7search in inputs
|
||||
nei.recipe.search.tooltip.output=%s§ftext§8 - §7search in outputs
|
||||
nei.recipe.search.tooltip.auxiliary=%s§ftext§8 - §7search in other stacks (fuel, catalysts)
|
||||
nei.recipe.search.tooltip.all=%s§ftext§8 - §7all inputs must match (same with > and ^)
|
||||
nei.recipe.search.tooltip.prefix=%stext§8 - §7%s
|
||||
|
||||
nei.recipe.search.tooltip.prefix.modName=search by mod
|
||||
@@ -661,6 +661,7 @@ nei.recipe.search.tooltip.exclude=%s§ftext§8 - §7exclude items with text
|
||||
nei.recipe.search.tooltip.exclude_recipe=%s§ftext§8 - §7exclude recipes with text
|
||||
nei.recipe.search.tooltip.or=§fa%s§fb§8 - §7match a or b
|
||||
nei.recipe.search.tooltip.exact=%s§ftext%s§8 - §7match exact phrase
|
||||
nei.recipe.search.tooltip.regex=%s§ftext%s§8 - §7match regular expression
|
||||
|
||||
nei.recipe.shaped=Shaped Crafting
|
||||
nei.recipe.shapeless=Shapeless Crafting
|
||||
|
||||
@@ -55,11 +55,6 @@ nei.chat.chunkoverlay.3=Chunk Overlay: GT Ore Veins
|
||||
nei.options=NEI Valikud
|
||||
nei.options.back=Tagasi
|
||||
nei.options.world=Maailm
|
||||
nei.options.global=Globaalne
|
||||
nei.options.global.tip.0=Valikud mõjutavad kõiki maailmi
|
||||
nei.options.global.tip.1=Vajuta W kõrval:valiku, et ületeh:ületeha see maailm
|
||||
nei.options.wbutton.tip.0=Kasutab globaalseid seadeid
|
||||
nei.options.wbutton.tip.1=Globaalsete seadmete ületegemine
|
||||
|
||||
nei.options.keys=Klahviseosed
|
||||
nei.options.keys.gui=NEI Seljakott
|
||||
|
||||
@@ -53,11 +53,6 @@ nei.chat.chunkoverlay.3=Chunk Overlay: GT Ore Veins
|
||||
nei.options=NEI Options
|
||||
nei.options.back=Retour
|
||||
nei.options.world=Monde
|
||||
nei.options.global=Global
|
||||
nei.options.global.tip.0=Les options s'appliquent à tous les mondes
|
||||
nei.options.global.tip.1=Cliquez sur le "W" à coté d'une option pour l'activer pour ce monde
|
||||
nei.options.wbutton.tip.0=Utilisation des paramètres globaux
|
||||
nei.options.wbutton.tip.1=Annuler l'utilisation des paramètres globaux
|
||||
|
||||
nei.options.keys=Raccourcis clavier
|
||||
nei.options.keys.gui=NEI Inventaire
|
||||
|
||||
@@ -56,11 +56,6 @@ nei.chat.chunkoverlay.3=Chunk Overlay: GT Ore Veins
|
||||
nei.options=Opzioni NEI
|
||||
nei.options.back=Indietro
|
||||
nei.options.world=Mondo
|
||||
nei.options.global=Globale
|
||||
nei.options.global.tip.0=Opzioni cambiano su tutti i mondi
|
||||
nei.options.global.tip.1=Clicca la W vicino a una:opzione per impostarla:solo su questo mondo
|
||||
nei.options.wbutton.tip.0=Usando le opzioni globali
|
||||
nei.options.wbutton.tip.1=Sovrascrivendo le opzioni globali
|
||||
|
||||
nei.options.keys=Controlli
|
||||
nei.options.keys.gui=NEI Inventario
|
||||
|
||||
@@ -51,11 +51,6 @@ nei.chat.chunkoverlay.3=Chunk Overlay: GT Ore Veins
|
||||
nei.options=NEI 옵션
|
||||
nei.options.back=뒤로
|
||||
nei.options.world=세계
|
||||
nei.options.global=글로벌
|
||||
nei.options.global.tip.0= 모든세계의 NEI의 옵션을 적용합니다
|
||||
nei.options.global.tip.1= 월드의 설정을 재정의 하려면 w를 클릭
|
||||
nei.options.wbutton.tip.0=글로벌로 세팅
|
||||
nei.options.wbutton.tip.1=전역 설정
|
||||
|
||||
nei.options.keys=키 바인딩
|
||||
nei.options.keys.gui=NEI 인벤토리
|
||||
|
||||
@@ -52,11 +52,6 @@ nei.chat.chunkoverlay.3=Chunk Overlay: GT Ore Veins
|
||||
nei.options=Opcje NEI
|
||||
nei.options.back=Wstecz
|
||||
nei.options.world=Światowe
|
||||
nei.options.global=Globalne
|
||||
nei.options.global.tip.0=Opcje działają we wszystkich światach
|
||||
nei.options.global.tip.1=Naciśnij 'W' obok opcji by włączyć nadpis dla tego świata
|
||||
nei.options.wbutton.tip.0=Używanie ustawień globalnych
|
||||
nei.options.wbutton.tip.1=Nadpisywanie ustawienia globalnego
|
||||
|
||||
nei.options.keys=Ustawienia klawiszy
|
||||
nei.options.keys.gui=NEI Ekwipunek
|
||||
|
||||
@@ -52,11 +52,6 @@ nei.chat.chunkoverlay.3=Chunk Overlay: GT Ore Veins
|
||||
nei.options=Opções do NEI
|
||||
nei.options.back=Voltar
|
||||
nei.options.world=Mundo
|
||||
nei.options.global=Global
|
||||
nei.options.global.tip.0=Opções se aplicam a todos os mundos
|
||||
nei.options.global.tip.1=Clique no W do lado de uma:opção para permitir uma :ultrapassagem para esse mundo.
|
||||
nei.options.wbutton.tip.0=Usando configurações globais
|
||||
nei.options.wbutton.tip.1=Substituindo configurações globais
|
||||
|
||||
nei.options.keys=Atalhos de Teclado
|
||||
nei.options.keys.gui=NEI Inventário
|
||||
|
||||
@@ -115,11 +115,6 @@ nei.options=Настройки NEI
|
||||
nei.options.back=Назад
|
||||
nei.options.save=Сохранить
|
||||
nei.options.world=Мир
|
||||
nei.options.global=Глобальные
|
||||
nei.options.global.tip.0=Настройки применяются ко всем мирам
|
||||
nei.options.global.tip.1=Нажмите W рядом с опцией, чтобы включить переопределение для этого мира
|
||||
nei.options.wbutton.tip.0=Используются глобальные настройки
|
||||
nei.options.wbutton.tip.1=Переопределение глобальной настройки
|
||||
|
||||
nei.options.keys=Привязки клавиш
|
||||
nei.options.keys.tip=Настройте привязки клавиш NEI на экране управления Minecraft
|
||||
@@ -256,12 +251,6 @@ nei.options.inventory.search.subsetsSearchMode=Поиск по подмноже
|
||||
nei.options.inventory.search.subsetsSearchMode.0=Всегда
|
||||
nei.options.inventory.search.subsetsSearchMode.1=Префикс: %s
|
||||
nei.options.inventory.search.subsetsSearchMode.2=Никогда
|
||||
nei.options.inventory.guirecipe.creativeTabStyle=Стиль вкладок: Творческий или JEI
|
||||
nei.options.inventory.guirecipe.creativeTabStyle.true=Творческий
|
||||
nei.options.inventory.guirecipe.creativeTabStyle.false=JEI
|
||||
nei.options.inventory.optimize_gui_overlap_computation=Оптимизация вычислений при перекрытии GUI
|
||||
nei.options.inventory.optimize_gui_overlap_computation.true=Да
|
||||
nei.options.inventory.optimize_gui_overlap_computation.false=Нет
|
||||
nei.options.inventory.guirecipe.shiftOverlayRecipe=Требовать удержание Shift для перемещения предметов при отображении рецепта
|
||||
nei.options.inventory.guirecipe.shiftOverlayRecipe.true=Да
|
||||
nei.options.inventory.guirecipe.shiftOverlayRecipe.false=Нет
|
||||
@@ -374,12 +363,12 @@ nei.options.world.panels=Настройки панелей
|
||||
nei.options.world.presets=Список пресетов
|
||||
|
||||
nei.options.tools=Инструменты
|
||||
nei.options.tools.handler_load_from_config=Загрузить обработчики из конфигурации
|
||||
nei.options.tools.handler_load_from_config.true=Конфигурация
|
||||
nei.options.tools.handler_load_from_config.false=JAR
|
||||
nei.options.tools.catalyst_load_from_config=Загрузить катализаторы из конфигурации
|
||||
nei.options.tools.catalyst_load_from_config.true=Конфигурация
|
||||
nei.options.tools.catalyst_load_from_config.false=JAR
|
||||
nei.options.tools.export_configs=Файлы конфигурации по умолчанию
|
||||
nei.options.tools.export_configs.button=Экспорт
|
||||
nei.options.tools.export_configs.done=%s экспортирован в config/NEI
|
||||
nei.options.tools.export_configs.skipped=%s не экспортирован, см. лог
|
||||
nei.options.tools.export_configs.all=Все файлы
|
||||
nei.options.tools.export_configs.all.done=Файлов конфигурации по умолчанию экспортировано в config/NEI: %s
|
||||
nei.options.tools.dump=Выгрузка данных
|
||||
nei.options.tools.dump.dump=Выгрузить
|
||||
nei.options.tools.dump.dumped=%s ID сохранены в %s
|
||||
|
||||
@@ -52,11 +52,6 @@ nei.chat.chunkoverlay.3=Chunk Overlay: GT Ore Veins
|
||||
nei.options=Nastavenia NEI
|
||||
nei.options.back=Späť
|
||||
nei.options.world=Svet
|
||||
nei.options.global=Globálne
|
||||
nei.options.global.tip.0=Nastavenia sa aplikujú na všetky svety
|
||||
nei.options.global.tip.1=Klikni W vedľa an:možnosti a povoľ an:náhradu pre tento svet
|
||||
nei.options.wbutton.tip.0=Používajú sa globálne nastavenia
|
||||
nei.options.wbutton.tip.1=Globálne nastavenia sú nahradené
|
||||
|
||||
nei.options.keys=Klávesové skratky
|
||||
nei.options.keys.gui=NEI Inventár
|
||||
|
||||
@@ -52,11 +52,6 @@ nei.chat.chunkoverlay.3=Chunk Overlay: GT Ore Veins
|
||||
nei.options=NEI Ayarları
|
||||
nei.options.back=Geri
|
||||
nei.options.world=Dünya
|
||||
nei.options.global=Genel
|
||||
nei.options.global.tip.0=Ayarlar tüm dünyalar için kaydedilecek
|
||||
nei.options.global.tip.1=W tuşuna tıklayın:seçeneği aç:dünyada gör
|
||||
nei.options.wbutton.tip.0=Genel ayarları kullanıyorsunuz
|
||||
nei.options.wbutton.tip.1=Genel ayarların üstüne yazılıyor
|
||||
|
||||
nei.options.keys=Tuşlar
|
||||
nei.options.keys.gui=NEI Envanter
|
||||
|
||||
@@ -165,11 +165,6 @@ nei.options=Налаштування NEI
|
||||
nei.options.back=Повернутися
|
||||
nei.options.save=Зберегти
|
||||
nei.options.world=Світ
|
||||
nei.options.global=Глобально
|
||||
nei.options.global.tip.0=Налаштування застосовуються до всіх світів
|
||||
nei.options.global.tip.1=Натисніть W біля налаштування, щоб увімкнути перевизначення для цього світу
|
||||
nei.options.wbutton.tip.0=Використовуються глобальні налаштування
|
||||
nei.options.wbutton.tip.1=Перевизначення глобального налаштування
|
||||
|
||||
nei.options.keys=Прив’язка клавіш
|
||||
nei.options.keys.tip=Налаштувати гарячі клавіші NEI у вікні керування Minecraft
|
||||
@@ -364,12 +359,6 @@ nei.options.inventory.search.subsetsSearchMode=Пошук у підгрупах
|
||||
nei.options.inventory.search.subsetsSearchMode.0=Завжди
|
||||
nei.options.inventory.search.subsetsSearchMode.1=Префікс: %s
|
||||
nei.options.inventory.search.subsetsSearchMode.2=Ніколи
|
||||
nei.options.inventory.guirecipe.creativeTabStyle=Стиль вкладок Creative чи JEI
|
||||
nei.options.inventory.guirecipe.creativeTabStyle.true=Creative
|
||||
nei.options.inventory.guirecipe.creativeTabStyle.false=JEI
|
||||
nei.options.inventory.optimize_gui_overlap_computation=Оптимізувати обчислення перекриття інтерфейсів
|
||||
nei.options.inventory.optimize_gui_overlap_computation.true=Так
|
||||
nei.options.inventory.optimize_gui_overlap_computation.false=Ні
|
||||
nei.options.inventory.autocrafting=Автокрафт
|
||||
nei.options.inventory.autocrafting.true=Увімкнено
|
||||
nei.options.inventory.autocrafting.false=Вимкнено
|
||||
@@ -505,12 +494,6 @@ nei.options.world.overlays.lock.true=Увімкнено
|
||||
nei.options.world.overlays.lock.false=Вимкнено
|
||||
|
||||
nei.options.tools=Інструменти
|
||||
nei.options.tools.handler_load_from_config=Завантажувати обробники з конфігураційного файлу
|
||||
nei.options.tools.handler_load_from_config.true=Конфігурація
|
||||
nei.options.tools.handler_load_from_config.false=JAR
|
||||
nei.options.tools.catalyst_load_from_config=Завантажувати каталізатори з конфігураційного файлу
|
||||
nei.options.tools.catalyst_load_from_config.true=Конфігурація
|
||||
nei.options.tools.catalyst_load_from_config.false=JAR
|
||||
nei.options.tools.dump=Дампи даних
|
||||
nei.options.tools.dump.dump=Створити дамп
|
||||
nei.options.tools.dump.dumped=ID %s збережено в %s
|
||||
|
||||
@@ -80,11 +80,6 @@ nei.chat.chunkoverlay.3=Chunk Overlay: GT Ore Veins
|
||||
nei.options=NEI选项
|
||||
nei.options.back=后退
|
||||
nei.options.world=世界
|
||||
nei.options.global=全局
|
||||
nei.options.global.tip.0=选项适用于所有世界
|
||||
nei.options.global.tip.1=点击选项左侧W按钮可覆写该世界设置
|
||||
nei.options.wbutton.tip.0=使用全局设置
|
||||
nei.options.wbutton.tip.1=覆写全局设置
|
||||
|
||||
nei.options.keys=按键绑定
|
||||
nei.options.keys.showenchant=显示附魔值
|
||||
@@ -142,9 +137,6 @@ nei.options.inventory.bookmarks.showRecipeMarker.0=否
|
||||
nei.options.inventory.showItemQuantityWidget=显示物品数量栏(右下角)
|
||||
nei.options.inventory.showItemQuantityWidget.true=是
|
||||
nei.options.inventory.showItemQuantityWidget.false=否
|
||||
nei.options.inventory.guirecipe.creativeTabStyle=创造模式/JEI标签页
|
||||
nei.options.inventory.guirecipe.creativeTabStyle.true=创造模式
|
||||
nei.options.inventory.guirecipe.creativeTabStyle.false=JEI
|
||||
nei.options.inventory.bookmarks.ignorePotionOverlap=忽略书签与药水效果重叠
|
||||
nei.options.inventory.bookmarks.ignorePotionOverlap.true=忽略
|
||||
nei.options.inventory.bookmarks.ignorePotionOverlap.false=规避
|
||||
@@ -208,12 +200,6 @@ nei.options.world.highlight_tips.sample=样本
|
||||
nei.options.world.panels=面板布局
|
||||
|
||||
nei.options.tools=工具
|
||||
nei.options.tools.handler_load_from_config=从Config加载handler(加工所使用的机器类别)
|
||||
nei.options.tools.handler_load_from_config.true=Config
|
||||
nei.options.tools.handler_load_from_config.false=JAR
|
||||
nei.options.tools.catalyst_load_from_config=从Config加载catalysts(加工所使用的具体机器等)
|
||||
nei.options.tools.catalyst_load_from_config.true=Config
|
||||
nei.options.tools.catalyst_load_from_config.false=JAR
|
||||
nei.options.tools.dump=数据存储
|
||||
nei.options.tools.dump.dump=存储
|
||||
nei.options.tools.dump.dumped=%s ID已保存到.minecraft/%s
|
||||
|
||||
@@ -51,11 +51,6 @@ nei.chat.chunkoverlay.3=Chunk Overlay: GT Ore Veins
|
||||
nei.options=NEI 選項
|
||||
nei.options.back=後退
|
||||
nei.options.world=世界
|
||||
nei.options.global=全局
|
||||
nei.options.global.tip.0=選項適用於所有世界
|
||||
nei.options.global.tip.1=點擊旁邊的W可重寫該世界設置
|
||||
nei.options.wbutton.tip.0=使用全局設定
|
||||
nei.options.wbutton.tip.1=覆蓋全局設定
|
||||
|
||||
nei.options.keys=按鍵設定
|
||||
nei.options.keys.gui=NEI 物品欄
|
||||
|
||||
@@ -4,7 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -16,7 +15,7 @@ import org.junit.jupiter.api.Test;
|
||||
public class ItemsGridTest {
|
||||
|
||||
@Test
|
||||
void synchronizesOverlapAndCaptureRefresh() {
|
||||
void refreshesCaptureOnlyWhenGridChanged() {
|
||||
TestGrid grid = new TestGrid();
|
||||
ItemsGrid.ScreenCapture capture = mock(ItemsGrid.ScreenCapture.class);
|
||||
grid.screenCapture = capture;
|
||||
@@ -24,22 +23,48 @@ public class ItemsGridTest {
|
||||
grid.setGridSize(1, 2, 18, 18);
|
||||
grid.setGridSize(1, 2, 18, 18);
|
||||
verify(capture, times(1)).refreshBuffer();
|
||||
}
|
||||
|
||||
when(capture.needRefresh(1)).thenReturn(false, true);
|
||||
grid.refresh(null);
|
||||
@Test
|
||||
void refreshesOverlapOnlyOnGridChangeOrScanFrame() {
|
||||
TestGrid grid = new TestGrid();
|
||||
|
||||
GridOverlapScanner.requestScan();
|
||||
GridOverlapScanner.beginFrame(null, true);
|
||||
grid.setGridSize(1, 2, 18, 18);
|
||||
grid.refresh(null);
|
||||
assertEquals(1, grid.overlapRefreshes);
|
||||
|
||||
GridOverlapScanner.beginFrame(null, true);
|
||||
grid.refresh(null);
|
||||
assertEquals(1, grid.overlapRefreshes);
|
||||
|
||||
grid.setGridSize(1, 2, 36, 18);
|
||||
grid.refresh(null);
|
||||
assertEquals(2, grid.overlapRefreshes);
|
||||
|
||||
GridOverlapScanner.requestScan();
|
||||
GridOverlapScanner.beginFrame(null, true);
|
||||
grid.refresh(null);
|
||||
assertEquals(3, grid.overlapRefreshes);
|
||||
|
||||
GridOverlapScanner.beginFrame(null, false);
|
||||
grid.refresh(null);
|
||||
assertEquals(4, grid.overlapRefreshes);
|
||||
|
||||
GridOverlapScanner.beginFrame(null, false);
|
||||
grid.refresh(null);
|
||||
assertEquals(4, grid.overlapRefreshes);
|
||||
|
||||
GridOverlapScanner.beginFrame(null, true);
|
||||
grid.refresh(null);
|
||||
assertEquals(5, grid.overlapRefreshes);
|
||||
}
|
||||
|
||||
private static final class TestGrid extends ItemsGrid<ItemsGrid.ItemsGridSlot, ItemsGrid.MouseContext> {
|
||||
|
||||
private int overlapRefreshes;
|
||||
|
||||
@Override
|
||||
protected int getGridRenderingCacheMode() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateGuiOverlapSlots(GuiContainer gui) {
|
||||
overlapRefreshes++;
|
||||
|
||||
@@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Named.named;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
@@ -32,6 +33,8 @@ import codechicken.nei.ItemList.AnyMultiItemFilter;
|
||||
import codechicken.nei.ItemList.PatternItemFilter;
|
||||
import codechicken.nei.SearchField.SearchParserProvider;
|
||||
import codechicken.nei.api.ItemFilter;
|
||||
import codechicken.nei.api.ItemInfo;
|
||||
import codechicken.nei.recipe.IRecipeHandler;
|
||||
import codechicken.nei.search.IdentifierFilter;
|
||||
|
||||
@DisplayName("Search expression")
|
||||
@@ -65,6 +68,7 @@ public class SearchTokenParserTest {
|
||||
private static final ModeValue[] extendedPlusPatternMode = { patternModes[3] };
|
||||
private static final ModeValue[] extendedPatternModes = { patternModes[1], patternModes[3] };
|
||||
private static final ModeValue[] nonGrammarPatternModes = { patternModes[0], patternModes[1], patternModes[2] };
|
||||
private static final ModeValue[] nonRegexPatternModes = { patternModes[0], patternModes[1], patternModes[3] };
|
||||
|
||||
private static final SearchParserProvider defaultParserProvider = parserProvider(
|
||||
'\0',
|
||||
@@ -140,6 +144,14 @@ public class SearchTokenParserTest {
|
||||
spaceModes,
|
||||
extendedPatternModes);
|
||||
|
||||
private static final List<Arguments> extendedOnlyAllSpaceModesTestProvider = combinationsProvider(
|
||||
spaceModes,
|
||||
new ModeValue[] { patternModes[1] });
|
||||
|
||||
private static final List<Arguments> nonRegexAllSpaceModesTestProvider = combinationsProvider(
|
||||
spaceModes,
|
||||
nonRegexPatternModes);
|
||||
|
||||
private static final List<Arguments> spaceIsAndExtendedPlusModeTestProvider = combinationsProvider(
|
||||
spaceIsAndMode,
|
||||
extendedPlusPatternMode);
|
||||
@@ -176,6 +188,7 @@ public class SearchTokenParserTest {
|
||||
config.when(() -> NEIClientConfig.getBooleanSetting(eq("inventory.search.logSearchExceptions")))
|
||||
.thenReturn(false);
|
||||
|
||||
mockStatic(ItemInfo.class);
|
||||
}
|
||||
|
||||
// All modes tests
|
||||
@@ -321,6 +334,62 @@ public class SearchTokenParserTest {
|
||||
assertTrue(matchedItems.contains(itemABC));
|
||||
}
|
||||
|
||||
@DisplayName("Regex with delimiters")
|
||||
@ParameterizedTest(name = "{argumentsWithNames}")
|
||||
@FieldSource("extendedOnlyAllSpaceModesTestProvider")
|
||||
public void testRegexWithDelimiters(int spaceMode, int patternMode) {
|
||||
SearchTokenParser searchParser = new SearchTokenParser();
|
||||
searchParser.addProvider(defaultParserProvider);
|
||||
Set<ItemStack> matchedItems = testFilterAgainstAllItems(
|
||||
spaceMode,
|
||||
patternMode,
|
||||
searchParser,
|
||||
"r/^" + itemA.getDisplayName() + "|^" + itemC.getDisplayName() + "/",
|
||||
true);
|
||||
|
||||
assertEquals(4, matchedItems.size());
|
||||
assertTrue(matchedItems.contains(itemA));
|
||||
assertTrue(matchedItems.contains(itemC));
|
||||
assertTrue(matchedItems.contains(itemAB));
|
||||
assertTrue(matchedItems.contains(itemABC));
|
||||
}
|
||||
|
||||
@DisplayName("Regex followed by delimiter")
|
||||
@ParameterizedTest(name = "{argumentsWithNames}")
|
||||
@FieldSource("extendedAllSpaceModesTestProvider")
|
||||
public void testRegexFollowedByDelimiter(int spaceMode, int patternMode) {
|
||||
SearchTokenParser searchParser = new SearchTokenParser();
|
||||
searchParser.addProvider(defaultParserProvider);
|
||||
Set<ItemStack> matchedItems = testFilterAgainstAllItems(
|
||||
spaceMode,
|
||||
patternMode,
|
||||
searchParser,
|
||||
"r/^" + itemA.getDisplayName() + "$/|" + itemC.getDisplayName());
|
||||
|
||||
assertEquals(3, matchedItems.size());
|
||||
assertTrue(matchedItems.contains(itemA));
|
||||
assertTrue(matchedItems.contains(itemC));
|
||||
assertTrue(matchedItems.contains(itemABC));
|
||||
}
|
||||
|
||||
@DisplayName("Recipe context")
|
||||
@ParameterizedTest(name = "{argumentsWithNames}")
|
||||
@FieldSource("nonRegexAllSpaceModesTestProvider")
|
||||
public void testRecipeContext(int spaceMode, int patternMode) {
|
||||
SearchTokenParser searchParser = new SearchTokenParser();
|
||||
searchParser.addProvider(defaultParserProvider);
|
||||
IRecipeHandler handler = mock(IRecipeHandler.class);
|
||||
when(handler.getIngredientStacks(0)).thenReturn(positionedStacks(itemA));
|
||||
when(handler.getResultStacks(0)).thenReturn(positionedStacks(itemB));
|
||||
when(handler.getAuxiliaryStacks(0)).thenReturn(positionedStacks(itemC));
|
||||
|
||||
assertTrue(testRecipeFilter(spaceMode, patternMode, searchParser, "<" + itemA.getDisplayName(), handler));
|
||||
assertTrue(testRecipeFilter(spaceMode, patternMode, searchParser, ">" + itemB.getDisplayName(), handler));
|
||||
assertTrue(testRecipeFilter(spaceMode, patternMode, searchParser, "^" + itemC.getDisplayName(), handler));
|
||||
assertFalse(testRecipeFilter(spaceMode, patternMode, searchParser, "^" + itemB.getDisplayName(), handler));
|
||||
assertFalse(testRecipeFilter(spaceMode, patternMode, searchParser, ">" + itemC.getDisplayName(), handler));
|
||||
}
|
||||
|
||||
// Extended+ specific tests
|
||||
|
||||
@DisplayName("Sequence")
|
||||
@@ -403,10 +472,14 @@ public class SearchTokenParserTest {
|
||||
|
||||
private static Set<ItemStack> testFilterAgainstAllItems(int spaceMode, int patternMode,
|
||||
SearchTokenParser searchParser, String search) {
|
||||
config.when(() -> NEIClientConfig.getIntSetting(eq("inventory.search.patternMode"))).thenReturn(patternMode);
|
||||
config.when(() -> NEIClientConfig.getIntSetting(eq("inventory.search.spaceMode"))).thenReturn(spaceMode);
|
||||
return testFilterAgainstAllItems(spaceMode, patternMode, searchParser, search, false);
|
||||
}
|
||||
|
||||
ItemFilter filter = searchParser.getFilter(search);
|
||||
private static Set<ItemStack> testFilterAgainstAllItems(int spaceMode, int patternMode,
|
||||
SearchTokenParser searchParser, String search, boolean skipRecipeTokens) {
|
||||
setModes(spaceMode, patternMode);
|
||||
|
||||
ItemFilter filter = searchParser.getFilter(search, skipRecipeTokens);
|
||||
if (filter instanceof SearchTokenParser.IsRegisteredItemFilter) {
|
||||
filter = ((SearchTokenParser.IsRegisteredItemFilter) filter).filter;
|
||||
}
|
||||
@@ -415,6 +488,23 @@ public class SearchTokenParserTest {
|
||||
return matchedItems;
|
||||
}
|
||||
|
||||
private static boolean testRecipeFilter(int spaceMode, int patternMode, SearchTokenParser searchParser,
|
||||
String search, IRecipeHandler handler) {
|
||||
setModes(spaceMode, patternMode);
|
||||
return searchParser.getRecipeFilter(search).matches(handler, 0);
|
||||
}
|
||||
|
||||
private static void setModes(int spaceMode, int patternMode) {
|
||||
config.when(() -> NEIClientConfig.getIntSetting(eq("inventory.search.patternMode"))).thenReturn(patternMode);
|
||||
config.when(() -> NEIClientConfig.getIntSetting(eq("inventory.search.spaceMode"))).thenReturn(spaceMode);
|
||||
}
|
||||
|
||||
private static List<PositionedStack> positionedStacks(ItemStack stack) {
|
||||
PositionedStack pStack = mock(PositionedStack.class);
|
||||
pStack.items = new ItemStack[] { stack };
|
||||
return Collections.singletonList(pStack);
|
||||
}
|
||||
|
||||
private static SearchParserProvider parserProvider(char prefix, String name,
|
||||
SearchTokenParser.SearchMode searchMode, Function<Pattern, ItemFilter> createFilter) {
|
||||
return new SearchParserProvider(prefix, name, EnumChatFormatting.RESET, createFilter) {
|
||||
|
||||
Reference in new issue
Block a user