aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornea <romangraef@gmail.com>2022-03-10 03:26:26 +0100
committernea <romangraef@gmail.com>2022-04-14 04:10:06 +0200
commitb797adcf4ca1fa4d9d19ece07f292664bcc2c142 (patch)
tree081ea93af3cfeb279b10dffb0698a59f8ca6a408
parent580e8ab2bc47fd84c61c3e0fc7ee6b11f4812be4 (diff)
downloadNotEnoughUpdates-b797adcf4ca1fa4d9d19ece07f292664bcc2c142.tar.gz
NotEnoughUpdates-b797adcf4ca1fa4d9d19ece07f292664bcc2c142.tar.bz2
NotEnoughUpdates-b797adcf4ca1fa4d9d19ece07f292664bcc2c142.zip
still broken, but better (just like me (stop being edgy nea ( no u ))))
-rw-r--r--build.gradle.kts15
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/MobDropRecipe.java4
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java65
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeGenerator.java437
4 files changed, 329 insertions, 192 deletions
diff --git a/build.gradle.kts b/build.gradle.kts
index e134387e..2b45fe9a 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -137,17 +137,6 @@ tasks.processResources {
rename("(.+_at.cfg)".toPattern(), "META-INF/$1")
}
-val moveResources by tasks.creating {
- doLast {
- ant.withGroovyBuilder {
- "move"(
- "file" to "$buildDir/resources/main",
- "todir" to "$buildDir/classes/java"
- )
- }
- }
- dependsOn(tasks.processResources)
+sourceSets.main {
+ output.setResourcesDir(file("$buildDir/classes/java/main"))
}
-
-tasks.classes { dependsOn(moveResources) }
-
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobDropRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobDropRecipe.java
deleted file mode 100644
index 22888e5d..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobDropRecipe.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package io.github.moulberry.notenoughupdates.recipes;
-
-public class MobDropRecipe {
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java
index 7d81c9c3..5670f1bd 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java
@@ -1,17 +1,19 @@
package io.github.moulberry.notenoughupdates.recipes;
+import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
import io.github.moulberry.notenoughupdates.NEUManager;
import io.github.moulberry.notenoughupdates.miscfeatures.entityviewer.EntityViewer;
import io.github.moulberry.notenoughupdates.miscgui.GuiItemRecipe;
+import io.github.moulberry.notenoughupdates.profileviewer.Panorama;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.ResourceLocation;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
@@ -32,6 +34,13 @@ public class MobLootRecipe implements NeuRecipe {
}
}
+ public static ResourceLocation[] PANORAMAS = new ResourceLocation[6];
+
+ static {
+ for (int i = 0; i < 6; i++)
+ PANORAMAS[i] = new ResourceLocation("notenoughupdates:panoramas/unknown/panorama_" + i + ".jpg");
+ }
+
public static ResourceLocation BACKGROUND = new ResourceLocation("notenoughupdates", "textures/gui/mob_loot_tall.png");
private final List<MobDrop> drops;
private final int coins;
@@ -39,10 +48,12 @@ public class MobLootRecipe implements NeuRecipe {
private final int xp;
private final String name;
private final String render;
+ private final int level;
private EntityLivingBase entityLivingBase;
- public MobLootRecipe(List<MobDrop> drops, int coins, int xp, int combatXp, String name, String render) {
+ public MobLootRecipe(List<MobDrop> drops, int level, int coins, int xp, int combatXp, String name, String render) {
this.drops = drops;
+ this.level = level;
this.coins = coins;
this.xp = xp;
this.combatXp = combatXp;
@@ -76,6 +87,7 @@ public class MobLootRecipe implements NeuRecipe {
public synchronized EntityLivingBase getRenderEntity() {
if (entityLivingBase == null) {
+ if (render == null) return null;
if (render.startsWith("@")) {
entityLivingBase = EntityViewer.constructEntity(new ResourceLocation(render.substring(1)));
} else {
@@ -126,14 +138,50 @@ public class MobLootRecipe implements NeuRecipe {
return true;
}
+ public static final int PANORAMA_POS_X = 13;
+ public static final int PANORAMA_POS_Y = 23;
+ public static final int PANORAMA_WIDTH = 50;
+ public static final int PANORAMA_HEIGHT = 80;
+
@Override
public void drawExtraBackground(GuiItemRecipe gui, int mouseX, int mouseY) {
- EntityViewer.renderEntity(getRenderEntity(), gui.guiLeft + MOB_POS_X, gui.guiLeft + MOB_POS_Y, mouseX, mouseY);
+ Panorama.drawPanorama(((System.nanoTime() / 20000000000F) % 1) * 360, gui.guiLeft + PANORAMA_POS_X, gui.guiTop + PANORAMA_POS_Y, PANORAMA_WIDTH, PANORAMA_HEIGHT, 0F, 0F, PANORAMAS);
+ if (getRenderEntity() != null)
+ EntityViewer.renderEntity(entityLivingBase, gui.guiLeft + MOB_POS_X, gui.guiTop + MOB_POS_Y, mouseX, mouseY);
+ }
+
+ @Override
+ public void drawHoverInformation(GuiItemRecipe gui, int mouseX, int mouseY) {
+ if (gui.isWithinRect(mouseX, mouseY, gui.guiLeft + PANORAMA_POS_X, gui.guiTop + PANORAMA_POS_Y, PANORAMA_WIDTH, PANORAMA_HEIGHT)) {
+ Utils.drawHoveringText(Arrays.asList("Hehe", name), mouseX, mouseY, gui.width, gui.height, -1, Minecraft.getMinecraft().fontRendererObj);
+ }
+
}
@Override
public JsonObject serialize() {
- return null; //TODO
+ JsonObject recipe = new JsonObject();
+ recipe.addProperty("level", level);
+ recipe.addProperty("coins", coins);
+ recipe.addProperty("xp", xp);
+ recipe.addProperty("combat_xp", combatXp);
+ recipe.addProperty("name", name);
+ recipe.addProperty("render", render);
+ recipe.addProperty("type", getType().getId());
+ JsonArray drops = new JsonArray();
+ for (MobDrop drop : this.drops) {
+ JsonObject dropObject = new JsonObject();
+ dropObject.addProperty("id", drop.drop.serialize());
+ JsonArray extraText = new JsonArray();
+ for (String extraLine : drop.extra) {
+ extraText.add(new JsonPrimitive(extraLine));
+ }
+ dropObject.add("extra", extraText);
+ dropObject.addProperty("chance", drop.chance);
+ drops.add(dropObject);
+ }
+ recipe.add("drops", drops);
+ return recipe;
}
@Override
@@ -162,11 +210,12 @@ public class MobLootRecipe implements NeuRecipe {
return new MobLootRecipe(
drops,
+ recipe.has("level") ? recipe.get("level").getAsInt() : 0,
recipe.has("coins") ? recipe.get("coins").getAsInt() : 0,
recipe.has("xp") ? recipe.get("xp").getAsInt() : 0,
recipe.has("combat_xp") ? recipe.get("combat_xp").getAsInt() : 0,
recipe.get("name").getAsString(),
- recipe.get("render").getAsString()
+ recipe.has("render") && !recipe.get("render").isJsonNull() ? recipe.get("render").getAsString() : null
);
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeGenerator.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeGenerator.java
index 46aff6c4..09e60003 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeGenerator.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeGenerator.java
@@ -9,9 +9,11 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.init.Items;
import net.minecraft.inventory.ContainerChest;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@@ -19,174 +21,275 @@ import net.minecraftforge.fml.common.gameevent.TickEvent;
import org.lwjgl.input.Keyboard;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
public class RecipeGenerator {
- public static final String DURATION = "Duration: ";
- public static final String COINS_SUFFIX = " Coins";
-
- private final NotEnoughUpdates neu;
-
- private final Map<String, String> savedForgingDurations = new HashMap<>();
-
- private final Debouncer debouncer = new Debouncer(1000 * 1000 * 50 /* 50 ms */);
- private final Debouncer durationDebouncer = new Debouncer(1000 * 1000 * 500);
-
- public RecipeGenerator(NotEnoughUpdates neu) {
- this.neu = neu;
- }
-
- @SubscribeEvent
- public void onTick(TickEvent event) {
- if (!neu.config.hidden.enableItemEditing) return;
- GuiScreen currentScreen = Minecraft.getMinecraft().currentScreen;
- if (currentScreen == null) return;
- if (!(currentScreen instanceof GuiChest)) return;
- analyzeUI((GuiChest) currentScreen);
- }
-
- private boolean shouldSaveRecipe() {
- return Keyboard.isKeyDown(Keyboard.KEY_O) && debouncer.trigger();
- }
-
- public void analyzeUI(GuiChest gui) {
- ContainerChest container = (ContainerChest) gui.inventorySlots;
- IInventory menu = container.getLowerChestInventory();
- String uiTitle = menu.getDisplayName().getUnformattedText();
- EntityPlayerSP p = Minecraft.getMinecraft().thePlayer;
- if (uiTitle.startsWith("Item Casting") || uiTitle.startsWith("Refine")) {
- if (durationDebouncer.trigger())
- parseAllForgeItemMetadata(menu);
- }
- boolean saveRecipe = shouldSaveRecipe();
- if (uiTitle.equals("Confirm Process") && saveRecipe) {
- ForgeRecipe recipe = parseSingleForgeRecipe(menu);
- if (recipe == null) {
- p.addChatMessage(new ChatComponentText(
- "" + EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + "Could not parse recipe for this UI"));
- } else {
- p.addChatMessage(new ChatComponentText(
- "" + EnumChatFormatting.GREEN + EnumChatFormatting.BOLD + "Parsed recipe:"));
- p.addChatMessage(new ChatComponentText("" + EnumChatFormatting.AQUA + " Inputs:"));
- for (Ingredient i : recipe.getInputs())
- p.addChatMessage(new ChatComponentText(
- " - " + EnumChatFormatting.AQUA + i.getInternalItemId() + " x " + i.getCount()));
- p.addChatMessage(new ChatComponentText("" + EnumChatFormatting.AQUA + " Output: " + EnumChatFormatting.GOLD +
- recipe.getOutput().getInternalItemId() + " x " + recipe.getOutput().getCount()));
- p.addChatMessage(new ChatComponentText(
- "" + EnumChatFormatting.AQUA + " Time: " + EnumChatFormatting.GRAY + recipe.getTimeInSeconds() +
- " seconds (no QF) ."));
- boolean saved = false;
- try {
- saved = saveRecipe(recipe);
- } catch (IOException e) {
- }
- if (!saved)
- p.addChatMessage(new ChatComponentText("" +
- EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + EnumChatFormatting.OBFUSCATED + "#" +
- EnumChatFormatting.RESET + EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + " ERROR " +
- EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + EnumChatFormatting.OBFUSCATED + "#" +
- EnumChatFormatting.RESET + EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD +
- " Failed to save recipe. Does the item already exist?"));
- }
- }
- }
-
- public boolean saveRecipe(NeuRecipe recipe) throws IOException {
- JsonObject recipeJson = recipe.serialize();
- for (Ingredient i : recipe.getOutputs()) {
- if (i.isCoins()) continue;
- JsonObject outputJson = neu.manager.readJsonDefaultDir(i.getInternalItemId() + ".json");
- if (outputJson == null) return false;
- outputJson.addProperty("clickcommand", "viewrecipe");
- JsonArray array = new JsonArray();
- array.add(recipeJson);
- outputJson.add("recipes", array);
- neu.manager.writeJsonDefaultDir(outputJson, i.getInternalItemId() + ".json");
- neu.manager.loadItem(i.getInternalItemId());
- }
- return true;
- }
-
- public ForgeRecipe parseSingleForgeRecipe(IInventory chest) {
- int durationInSeconds = -1;
- List<Ingredient> inputs = new ArrayList<>();
- Ingredient output = null;
- for (int i = 0; i < chest.getSizeInventory(); i++) {
- int col = i % 9;
- ItemStack itemStack = chest.getStackInSlot(i);
- if (itemStack == null) continue;
- String name = Utils.cleanColour(itemStack.getDisplayName());
- String internalId = neu.manager.getInternalNameForItem(itemStack);
- Ingredient ingredient = null;
- if (itemStack.getDisplayName().endsWith(COINS_SUFFIX)) {
- int coinCost = Integer.parseInt(
- name.substring(0, name.length() - COINS_SUFFIX.length())
- .replace(",", ""));
- ingredient = Ingredient.coinIngredient(neu.manager, coinCost);
- } else if (internalId != null) {
- ingredient = new Ingredient(neu.manager, internalId, itemStack.stackSize);
- }
- if (ingredient == null) continue;
- if (col < 4) {
- inputs.add(ingredient);
- } else {
- output = ingredient;
- }
- }
- if (output == null || inputs.isEmpty()) return null;
- if (savedForgingDurations.containsKey(output.getInternalItemId()))
- durationInSeconds = parseDuration(savedForgingDurations.get(output.getInternalItemId()));
- return new ForgeRecipe(
- neu.manager,
- new ArrayList<>(Ingredient.mergeIngredients(inputs)),
- output,
- durationInSeconds,
- -1
- );
- }
-
- private static final Map<Character, Integer> durationSuffixLengthMap = new HashMap<Character, Integer>() {{
- put('d', 60 * 60 * 24);
- put('h', 60 * 60);
- put('m', 60);
- put('s', 1);
- }};
-
- public int parseDuration(String durationString) {
- String[] parts = durationString.split(" ");
- int timeInSeconds = 0;
- for (String part : parts) {
- char signifier = part.charAt(part.length() - 1);
- int value = Integer.parseInt(part.substring(0, part.length() - 1));
- if (!durationSuffixLengthMap.containsKey(signifier)) {
- return -1;
- }
- timeInSeconds += value * durationSuffixLengthMap.get(signifier);
- }
- return timeInSeconds;
- }
-
- private void parseAllForgeItemMetadata(IInventory chest) {
- for (int i = 0; i < chest.getSizeInventory(); i++) {
- ItemStack stack = chest.getStackInSlot(i);
- if (stack == null) continue;
- String internalName = neu.manager.getInternalNameForItem(stack);
- if (internalName == null) continue;
- List<String> tooltip = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
- String durationInfo = null;
- for (String s : tooltip) {
- String info = Utils.cleanColour(s);
- if (info.startsWith(DURATION)) {
- durationInfo = info.substring(DURATION.length());
- }
- }
- if (durationInfo != null)
- savedForgingDurations.put(internalName, durationInfo);
- }
- }
+ public static final String DURATION = "Duration: ";
+ public static final String COINS_SUFFIX = " Coins";
+
+ private final NotEnoughUpdates neu;
+
+ private final Map<String, String> savedForgingDurations = new HashMap<>();
+
+ private final Debouncer debouncer = new Debouncer(1000 * 1000 * 50 /* 50 ms */);
+ private final Debouncer durationDebouncer = new Debouncer(1000 * 1000 * 500);
+
+
+ public RecipeGenerator(NotEnoughUpdates neu) {
+ this.neu = neu;
+ }
+
+ @SubscribeEvent
+ public void onTick(TickEvent event) {
+ if (!neu.config.hidden.enableItemEditing) return;
+ GuiScreen currentScreen = Minecraft.getMinecraft().currentScreen;
+ if (currentScreen == null) return;
+ if (!(currentScreen instanceof GuiChest)) return;
+ analyzeUI((GuiChest) currentScreen);
+ }
+
+ private boolean shouldSaveRecipe() {
+ return Keyboard.isKeyDown(Keyboard.KEY_O) && debouncer.trigger();
+ }
+
+ public void analyzeUI(GuiChest gui) {
+ ContainerChest container = (ContainerChest) gui.inventorySlots;
+ IInventory menu = container.getLowerChestInventory();
+ String uiTitle = menu.getDisplayName().getUnformattedText();
+ EntityPlayerSP p = Minecraft.getMinecraft().thePlayer;
+ if (uiTitle.startsWith("Item Casting") || uiTitle.startsWith("Refine")) {
+ if (durationDebouncer.trigger())
+ parseAllForgeItemMetadata(menu);
+ }
+ boolean saveRecipe = shouldSaveRecipe();
+ if (uiTitle.equals("Confirm Process") && saveRecipe) {
+ ForgeRecipe recipe = parseSingleForgeRecipe(menu);
+ if (recipe == null) {
+ p.addChatMessage(new ChatComponentText("" + EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + "Could not parse recipe for this UI"));
+ } else {
+ p.addChatMessage(new ChatComponentText("" + EnumChatFormatting.GREEN + EnumChatFormatting.BOLD + "Parsed recipe:"));
+ p.addChatMessage(new ChatComponentText("" + EnumChatFormatting.AQUA + " Inputs:"));
+ for (Ingredient i : recipe.getInputs())
+ p.addChatMessage(new ChatComponentText(" - " + EnumChatFormatting.AQUA + i.getInternalItemId() + " x " + i.getCount()));
+ p.addChatMessage(new ChatComponentText("" + EnumChatFormatting.AQUA + " Output: " + EnumChatFormatting.GOLD + recipe.getOutput().getInternalItemId() + " x " + recipe.getOutput().getCount()));
+ p.addChatMessage(new ChatComponentText("" + EnumChatFormatting.AQUA + " Time: " + EnumChatFormatting.GRAY + recipe.getTimeInSeconds() + " seconds (no QF) ."));
+ boolean saved = false;
+ try {
+ saved = saveRecipes(recipe.getOutput().getInternalItemId(), Collections.singletonList(recipe));
+ } catch (IOException e) {
+ }
+ if (!saved)
+ p.addChatMessage(new ChatComponentText("" +
+ EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + EnumChatFormatting.OBFUSCATED + "#" +
+ EnumChatFormatting.RESET + EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + " ERROR " +
+ EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + EnumChatFormatting.OBFUSCATED + "#" +
+ EnumChatFormatting.RESET + EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + " Failed to save recipe. Does the item already exist?"));
+ }
+ }
+ if (saveRecipe) attemptToSaveBestiary(menu);
+ }
+
+ private List<String> getLore(ItemStack item) {
+ NBTTagList loreTag = item.getTagCompound().getCompoundTag("display").getTagList("Lore", 8);
+ List<String> loreList = new ArrayList<>();
+ for (int i = 0; i < loreTag.tagCount(); i++) {
+ loreList.add(loreTag.getStringTagAt(i));
+ }
+ return loreList;
+ }
+
+ // §8[§7Lv1§8] §fZombie Villager
+ private static final Pattern MOB_DISPLAY_NAME_PATTERN = Pattern.compile("^§8\\[§7Lv(?<level>\\d+)§8] (?<name>.*)$");
+ // §7Coins per Kill: §61
+ // §7Combat Exp: §3120
+ // §8 ■ §7§5Skeleton Grunt Helmet §8(§a5%§8)
+ // §8 ■ §7§fRotten Flesh
+ // §8 ■ Dragon Essence §8x3-5
+ private static final Pattern LORE_PATTERN = Pattern.compile("^(?:" +
+ "§7Coins per Kill: §6(?<coins>[,\\d]+)|" +
+ "§7Combat Exp: §3(?<combatxp>[,\\d]+)|" +
+ "§7XP Orbs: §3(?<xp>[,\\d]+)|" +
+ "§8 ■ (?:§7)?(?<dropName>(?:§.)?.+?)(?: §8\\(§a(?<dropChances>[\\d.<]+%)§8\\)| §8(?<dropCount>x.*))?|" +
+ "§7Kills: §a[,\\d]+|" +
+ "§.[a-zA-Z]+ Loot|" +
+ "§7Deaths: §a[,\\d]+|" +
+ " §8■ (?<missing>§c\\?\\?\\?)|" +
+ "" +
+ ")$");
+
+ private void attemptToSaveBestiary(IInventory menu) {
+ if (!menu.getDisplayName().getUnformattedText().contains("➜")) return;
+ ItemStack backArrow = menu.getStackInSlot(48);
+ if (backArrow == null || backArrow.getItem() != Items.arrow) return;
+ if (!getLore(backArrow).stream().anyMatch(it -> it.startsWith("§7To Bestiary ➜"))) return;
+ List<NeuRecipe> recipes = new ArrayList<>();
+ for (int i = 9; i < 44; i++) {
+ ItemStack mobStack = menu.getStackInSlot(i);
+ if (mobStack == null || mobStack.getItem() != Items.skull) continue;
+ Matcher matcher = MOB_DISPLAY_NAME_PATTERN.matcher(mobStack.getDisplayName());
+ if (!matcher.matches()) continue;
+ String name = matcher.group("name");
+ int level = parseIntIgnoringCommas(matcher.group("level"));
+ List<String> mobLore = getLore(mobStack);
+ int coins = 0, xp = 0, combatXp = 0;
+ List<MobLootRecipe.MobDrop> drops = new ArrayList<>();
+
+ for (String loreLine : mobLore) {
+ Matcher loreMatcher = LORE_PATTERN.matcher(loreLine);
+ if (!loreMatcher.matches()) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("[WARNING] Unknown lore line: " + loreLine));
+ continue;
+ }
+ if (loreMatcher.group("coins") != null)
+ coins = parseIntIgnoringCommas(loreMatcher.group("coins"));
+ if (loreMatcher.group("combatxp") != null)
+ combatXp = parseIntIgnoringCommas(loreMatcher.group("combatxp"));
+ if (loreMatcher.group("xp") != null)
+ xp = parseIntIgnoringCommas(loreMatcher.group("xp"));
+ if (loreMatcher.group("dropName") != null) {
+ String dropName = loreMatcher.group("dropName");
+ List<JsonObject> possibleItems = neu.manager.getItemInformation().values().stream().filter(it -> it.get("displayname").getAsString().equals(dropName)).collect(Collectors.toList());
+ if (possibleItems.size() != 1) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("[WARNING] Could not parse drop, ambiguous or missing item information: " + loreLine));
+ continue;
+ }
+ Ingredient item = new Ingredient(neu.manager, possibleItems.get(0).get("internalname").getAsString());
+ String chance = loreMatcher.group("dropChances") != null ? loreMatcher.group("dropChances") : loreMatcher.group("dropCount");
+ drops.add(new MobLootRecipe.MobDrop(item, chance, new ArrayList<>()));
+ }
+ if (loreMatcher.group("missing") != null) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("[WARNING] You are missing Bestiary levels for drop: " + loreLine));
+
+ }
+ }
+ recipes.add(new MobLootRecipe(drops, level, coins, xp, combatXp, name, null));
+ }
+ boolean saved = false;
+ try {
+ saved = saveRecipes(menu.getDisplayName().getUnformattedText().split("➜")[1].toUpperCase(Locale.ROOT).trim() + "_MONSTER", recipes);
+ } catch (IOException e) {
+ }
+ if (!saved)
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("" +
+ EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + EnumChatFormatting.OBFUSCATED + "#" +
+ EnumChatFormatting.RESET + EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + " ERROR " +
+ EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + EnumChatFormatting.OBFUSCATED + "#" +
+ EnumChatFormatting.RESET + EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + " Failed to save recipe. Does the item already exist?")); // TODO: MERGE CODE OVER
+ }
+
+ private int parseIntIgnoringCommas(String text) {
+ return Integer.parseInt(text.replace(",", ""));
+ }
+
+ /*{
+ id: "minecraft:skull",
+ Count: 1b,
+ tag: {
+ overrideMeta: 1b,
+ SkullOwner: {
+ Id: "2005daad-730b-363c-abae-e6f3830816fb",
+ Properties: {
+ textures: [{
+ Value: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTZjMGIzNmQ1M2ZmZjY5YTQ5YzdkNmYzOTMyZjJiMGZlOTQ4ZTAzMjIyNmQ1ZTgwNDVlYzU4NDA4YTM2ZTk1MSJ9fX0="
+ }]
+ }
+ },
+ display: {
+ Lore: ["§7Coins per Kill: §610", "§7Combat Exp: §340", "§7XP Orbs: §312", "", "§7Kills: §a990", "§7Deaths: §a2", "", "§fCommon Loot", "§8 ■ §7§fEnder Pearl §8x1-3", "", "§9Rare Loot", "§8 ■ §7§aEnchanted Ender Pearl §8(§a1%§8)", "", "§6Legendary Loot", "§8 ■ §7§7[Lvl 1] §aEnderman §8(§a0.02%§8)", "§8 ■ §7§7[Lvl 1] §fEnderman §8(§a0.05%§8)", "§8 ■ §7§5Ender Helmet §8(§a0.1%§8)", "§8 ■ §7§5Ender Boots §8(§a0.1%§8)", "§8 ■ §7§5Ender Leggings §8(§a0.1%§8)", "§8 ■ §7§5Ender Chestplate §8(§a0.1%§8)", "", "§dRNGesus Loot", " §8■ §c???"],
+ Name: "§8[§7Lv42§8] §fEnderman"
+ },
+ AttributeModifiers: []
+ },
+ Damage: 3s
+}*/
+ public boolean saveRecipes(String relevantItem, List<NeuRecipe> recipes) throws IOException {
+ JsonObject outputJson = neu.manager.readJsonDefaultDir(relevantItem + ".json");
+ if (outputJson == null) return false;
+ outputJson.addProperty("clickcommand", "viewrecipe");
+ JsonArray array = new JsonArray();
+ for (NeuRecipe recipe : recipes) {
+ array.add(recipe.serialize());
+ }
+ outputJson.add("recipes", array);
+ neu.manager.writeJsonDefaultDir(outputJson, relevantItem + ".json");
+ neu.manager.loadItem(relevantItem);
+ return true;
+ }
+
+
+ public ForgeRecipe parseSingleForgeRecipe(IInventory chest) {
+ int durationInSeconds = -1;
+ List<Ingredient> inputs = new ArrayList<>();
+ Ingredient output = null;
+ for (int i = 0; i < chest.getSizeInventory(); i++) {
+ int col = i % 9;
+ ItemStack itemStack = chest.getStackInSlot(i);
+ if (itemStack == null) continue;
+ String name = Utils.cleanColour(itemStack.getDisplayName());
+ String internalId = neu.manager.getInternalNameForItem(itemStack);
+ Ingredient ingredient = null;
+ if (itemStack.getDisplayName().endsWith(COINS_SUFFIX)) {
+ int coinCost = Integer.parseInt(
+ name.substring(0, name.length() - COINS_SUFFIX.length())
+ .replace(",", ""));
+ ingredient = Ingredient.coinIngredient(neu.manager, coinCost);
+ } else if (internalId != null) {
+ ingredient = new Ingredient(neu.manager, internalId, itemStack.stackSize);
+ }
+ if (ingredient == null) continue;
+ if (col < 4) {
+ inputs.add(ingredient);
+ } else {
+ output = ingredient;
+ }
+ }
+ if (output == null || inputs.isEmpty()) return null;
+ if (savedForgingDurations.containsKey(output.getInternalItemId()))
+ durationInSeconds = parseDuration(savedForgingDurations.get(output.getInternalItemId()));
+ return new ForgeRecipe(neu.manager, new ArrayList<>(Ingredient.mergeIngredients(inputs)), output, durationInSeconds, -1);
+ }
+
+ private static Map<Character, Integer> durationSuffixLengthMap = new HashMap<Character, Integer>() {{
+ put('d', 60 * 60 * 24);
+ put('h', 60 * 60);
+ put('m', 60);
+ put('s', 1);
+ }};
+
+ public int parseDuration(String durationString) {
+ String[] parts = durationString.split(" ");
+ int timeInSeconds = 0;
+ for (String part : parts) {
+ char signifier = part.charAt(part.length() - 1);
+ int value = Integer.parseInt(part.substring(0, part.length() - 1));
+ if (!durationSuffixLengthMap.containsKey(signifier)) {
+ return -1;
+ }
+ timeInSeconds += value * durationSuffixLengthMap.get(signifier);
+ }
+ return timeInSeconds;
+ }
+
+ private void parseAllForgeItemMetadata(IInventory chest) {
+ for (int i = 0; i < chest.getSizeInventory(); i++) {
+ ItemStack stack = chest.getStackInSlot(i);
+ if (stack == null) continue;
+ String internalName = neu.manager.getInternalNameForItem(stack);
+ if (internalName == null) continue;
+ List<String> tooltip = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
+ String durationInfo = null;
+ for (String s : tooltip) {
+ String info = Utils.cleanColour(s);
+ if (info.startsWith(DURATION)) {
+ durationInfo = info.substring(DURATION.length());
+ }
+ }
+ if (durationInfo != null)
+ savedForgingDurations.put(internalName, durationInfo);
+ }
+ }
}