2024-07-26 18:44:54 +03:00
|
|
|
package codechicken.nei;
|
|
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.HashSet;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
import net.minecraft.item.ItemStack;
|
|
|
|
|
|
|
|
|
|
import org.apache.commons.io.IOUtils;
|
|
|
|
|
|
|
|
|
|
import com.google.gson.JsonObject;
|
|
|
|
|
import com.google.gson.JsonParser;
|
|
|
|
|
import com.google.gson.JsonPrimitive;
|
|
|
|
|
import com.google.gson.JsonSyntaxException;
|
|
|
|
|
|
|
|
|
|
import codechicken.core.CommonUtils;
|
2025-08-22 15:22:09 +03:00
|
|
|
import codechicken.nei.SubsetWidget.SubsetTag;
|
2024-07-26 18:44:54 +03:00
|
|
|
import codechicken.nei.api.API;
|
|
|
|
|
import codechicken.nei.api.IRecipeFilter;
|
|
|
|
|
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
|
|
|
|
|
import codechicken.nei.api.ItemFilter;
|
|
|
|
|
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
|
|
|
|
|
import codechicken.nei.recipe.IRecipeHandler;
|
|
|
|
|
import codechicken.nei.recipe.StackInfo;
|
|
|
|
|
import codechicken.nei.util.NBTJson;
|
|
|
|
|
|
|
|
|
|
public class PresetsList {
|
|
|
|
|
|
2024-09-28 19:05:06 +03:00
|
|
|
public enum PresetMode {
|
2025-08-22 15:22:09 +03:00
|
|
|
SUBSET,
|
2024-07-26 18:44:54 +03:00
|
|
|
HIDE,
|
|
|
|
|
REMOVE,
|
|
|
|
|
GROUP;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static class Preset implements ItemFilter {
|
|
|
|
|
|
|
|
|
|
public String name = "";
|
|
|
|
|
public boolean enabled = true;
|
|
|
|
|
public PresetMode mode = PresetMode.HIDE;
|
|
|
|
|
public Set<String> items = new HashSet<>();
|
|
|
|
|
|
|
|
|
|
public static String getIdentifier(ItemStack stack) {
|
|
|
|
|
return StackInfo.getItemStackGUID(stack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean matches(ItemStack item) {
|
|
|
|
|
return items.contains(Preset.getIdentifier(item));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Preset copy() {
|
|
|
|
|
Preset preset = new Preset();
|
|
|
|
|
|
|
|
|
|
preset.name = name;
|
|
|
|
|
preset.enabled = enabled;
|
|
|
|
|
preset.mode = mode;
|
|
|
|
|
preset.items = new HashSet<>(items);
|
|
|
|
|
|
|
|
|
|
return preset;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-24 10:35:59 +03:00
|
|
|
protected static class PresetRecipeFilter implements IRecipeFilterProvider, IRecipeFilter {
|
2024-07-26 18:44:54 +03:00
|
|
|
|
|
|
|
|
public Set<String> cache;
|
|
|
|
|
|
2025-08-24 10:35:59 +03:00
|
|
|
public IRecipeFilter getRecipeFilter() {
|
2024-07-26 18:44:54 +03:00
|
|
|
|
|
|
|
|
if (cache == null) {
|
|
|
|
|
cache = PresetsList.presets.stream().filter(p -> p.enabled && p.mode == PresetMode.REMOVE)
|
|
|
|
|
.flatMap(p -> p.items.stream()).collect(Collectors.toSet());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cache.isEmpty() ? null : this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2025-09-04 16:59:51 +03:00
|
|
|
public boolean matches(IRecipeHandler handler, int recipeIndex) {
|
2024-07-26 18:44:54 +03:00
|
|
|
|
2025-09-04 16:59:51 +03:00
|
|
|
if (matchPositionedStack(handler.getIngredientStacks(recipeIndex), false)) {
|
2024-07-26 18:44:54 +03:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-04 16:59:51 +03:00
|
|
|
final PositionedStack result = handler.getResultStack(recipeIndex);
|
|
|
|
|
|
2024-07-26 18:44:54 +03:00
|
|
|
if (result != null && matchPositionedStack(result)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-04 16:59:51 +03:00
|
|
|
final List<PositionedStack> others = handler.getOtherStacks(recipeIndex);
|
|
|
|
|
|
2024-07-26 18:44:54 +03:00
|
|
|
if (!others.isEmpty() && matchPositionedStack(others, true)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result == null && others.isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean matchPositionedStack(List<PositionedStack> items, boolean dir) {
|
|
|
|
|
for (PositionedStack pStack : items) {
|
|
|
|
|
if (matchPositionedStack(pStack) == dir) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean matchPositionedStack(PositionedStack pStack) {
|
|
|
|
|
for (ItemStack stack : pStack.items) {
|
|
|
|
|
if (!cache.contains(Preset.getIdentifier(stack))) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected static class ItemPanelFilter implements ItemFilterProvider, ItemFilter {
|
|
|
|
|
|
|
|
|
|
public Set<String> cache;
|
|
|
|
|
|
|
|
|
|
public ItemFilter getFilter() {
|
|
|
|
|
|
|
|
|
|
if (cache == null) {
|
|
|
|
|
cache = PresetsList.presets.stream()
|
|
|
|
|
.filter(p -> p.enabled && (p.mode == PresetMode.HIDE || p.mode == PresetMode.REMOVE))
|
|
|
|
|
.flatMap(p -> p.items.stream()).collect(Collectors.toSet());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cache.isEmpty() ? null : this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean matches(ItemStack stack) {
|
|
|
|
|
return !cache.contains(Preset.getIdentifier(stack));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static final List<Preset> presets = new ArrayList<>();
|
2025-08-24 10:35:59 +03:00
|
|
|
protected static PresetRecipeFilter recipeFilter = new PresetRecipeFilter();
|
2024-07-26 18:44:54 +03:00
|
|
|
protected static ItemPanelFilter itemFilter = new ItemPanelFilter();
|
|
|
|
|
|
|
|
|
|
static {
|
|
|
|
|
API.addItemFilter(itemFilter);
|
|
|
|
|
API.addRecipeFilter(recipeFilter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static ItemFilter getItemFilter() {
|
|
|
|
|
return itemFilter.getFilter();
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-29 23:14:52 +03:00
|
|
|
public static void load() {
|
|
|
|
|
final File presetsFile = new File(CommonUtils.getMinecraftDir(), "saves/NEI/global/presets.ini");
|
2024-07-26 18:44:54 +03:00
|
|
|
|
|
|
|
|
if (presetsFile == null || !presetsFile.exists()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<String> itemStrings;
|
|
|
|
|
try (FileInputStream reader = new FileInputStream(presetsFile)) {
|
|
|
|
|
NEIClientConfig.logger.info("Loading presets from file {}", presetsFile);
|
|
|
|
|
itemStrings = IOUtils.readLines(reader, StandardCharsets.UTF_8);
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
NEIClientConfig.logger.error("Failed to load presets from file {}", presetsFile, e);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JsonParser parser = new JsonParser();
|
|
|
|
|
Preset preset = new Preset();
|
|
|
|
|
presets.clear();
|
|
|
|
|
|
|
|
|
|
for (String itemStr : itemStrings) {
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
|
|
if (itemStr.isEmpty()) {
|
|
|
|
|
itemStr = "; {}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (itemStr.startsWith("; ")) {
|
|
|
|
|
JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
|
|
|
|
|
|
|
|
|
|
if (!preset.items.isEmpty()) {
|
|
|
|
|
// do not create empty namespaces
|
|
|
|
|
presets.add(preset);
|
|
|
|
|
preset = new Preset();
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-29 23:14:52 +03:00
|
|
|
if (settings.has("name")) {
|
2024-07-26 18:44:54 +03:00
|
|
|
preset.name = settings.get("name").getAsString();
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-29 23:14:52 +03:00
|
|
|
if (settings.has("enabled")) {
|
2024-07-26 18:44:54 +03:00
|
|
|
preset.enabled = settings.get("enabled").getAsBoolean();
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-29 23:14:52 +03:00
|
|
|
if (settings.has("mode")) {
|
2024-07-26 18:44:54 +03:00
|
|
|
preset.mode = PresetMode.valueOf(settings.get("mode").getAsString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
preset.items.add(itemStr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
|
|
|
|
|
NEIClientConfig.logger.error("Failed to load presets ItemStack from json string:\n{}", itemStr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!preset.items.isEmpty()) {
|
|
|
|
|
presets.add(preset);
|
|
|
|
|
}
|
2025-08-22 15:22:09 +03:00
|
|
|
|
|
|
|
|
updateSubsets();
|
2024-07-26 18:44:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void savePresets() {
|
2024-08-29 23:14:52 +03:00
|
|
|
final File presetsFile = new File(CommonUtils.getMinecraftDir(), "saves/NEI/global/presets.ini");
|
|
|
|
|
final List<String> strings = new ArrayList<>();
|
2024-07-26 18:44:54 +03:00
|
|
|
|
|
|
|
|
for (Preset preset : presets) {
|
|
|
|
|
JsonObject settings = new JsonObject();
|
|
|
|
|
|
|
|
|
|
settings.add("name", new JsonPrimitive(preset.name));
|
|
|
|
|
settings.add("enabled", new JsonPrimitive(preset.enabled));
|
|
|
|
|
settings.add("mode", new JsonPrimitive(preset.mode.toString()));
|
|
|
|
|
|
|
|
|
|
strings.add("; " + NBTJson.toJson(settings));
|
|
|
|
|
strings.addAll(preset.items);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try (FileOutputStream output = new FileOutputStream(presetsFile)) {
|
|
|
|
|
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
|
|
|
|
|
} catch (IOException e) {
|
2025-08-16 14:56:59 +03:00
|
|
|
NEIClientConfig.logger.error("Failed to save presets list to file {}", presetsFile, e);
|
2024-07-26 18:44:54 +03:00
|
|
|
}
|
|
|
|
|
|
2024-08-29 23:14:52 +03:00
|
|
|
recipeFilter.cache = null;
|
|
|
|
|
itemFilter.cache = null;
|
2025-08-22 15:22:09 +03:00
|
|
|
updateSubsets();
|
2024-12-05 21:25:17 +02:00
|
|
|
CollapsibleItems.saveStates();
|
|
|
|
|
CollapsibleItems.load();
|
2024-08-29 23:14:52 +03:00
|
|
|
LayoutManager.markItemsDirty();
|
2024-07-26 18:44:54 +03:00
|
|
|
}
|
|
|
|
|
|
2025-08-22 15:22:09 +03:00
|
|
|
private static void updateSubsets() {
|
|
|
|
|
SubsetWidget.removeTag("Presets");
|
|
|
|
|
|
|
|
|
|
for (Preset preset : PresetsList.presets) {
|
|
|
|
|
if (preset.enabled && preset.mode == PresetMode.SUBSET) {
|
|
|
|
|
SubsetWidget.addTag(
|
|
|
|
|
new SubsetTag(
|
|
|
|
|
"Presets." + preset.name,
|
|
|
|
|
stack -> preset.items.contains(Preset.getIdentifier(stack))));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-26 18:44:54 +03:00
|
|
|
}
|