diff options
9 files changed, 769 insertions, 567 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..2381ceb8 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +/src/main/java/io/github/moulberry/notenoughupdates/recipes/* @romangraef +/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java @romangraef diff --git a/build.gradle.kts b/build.gradle.kts index 2b45fe9a..2ab7ee48 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,58 +1,76 @@ -import java.io.ByteArrayOutputStream import net.minecraftforge.gradle.user.ReobfMappingType +import java.io.ByteArrayOutputStream + plugins { - java - id("net.minecraftforge.gradle.forge") version "6f5327738df" - id("com.github.johnrengelman.shadow") version "6.1.0" - id("org.spongepowered.mixin") version "d75e32e" + java + id("net.minecraftforge.gradle.forge") version "6f5327738df" + id("com.github.johnrengelman.shadow") version "6.1.0" + id("org.spongepowered.mixin") version "d75e32e" } group = "io.github.moulberry" val baseVersion = "2.1" -var buildVersion = properties["BUILD_VERSION"] -if (buildVersion == null) { - val stdout = ByteArrayOutputStream() - val execResult = exec { - commandLine("git", "describe", "--always", "--first-parent", "--abbrev=7") - standardOutput = stdout - } - if (execResult.exitValue == 0) - buildVersion = String(stdout.toByteArray()).trim() +val buildExtra = mutableListOf<String>() +val buildVersion = properties["BUILD_VERSION"] as? String +if (buildVersion != null) + buildExtra.add(buildVersion) +val githubCi = properties["GITHUB_ACTIONS"] as? String +if (githubCi == "true") + buildExtra.add("ci") + +val stdout = ByteArrayOutputStream() +val execResult = exec { + commandLine("git", "describe", "--always", "--first-parent", "--abbrev=7") + standardOutput = stdout + isIgnoreExitValue = true +} +if (execResult.exitValue == 0) { + buildExtra.add(String(stdout.toByteArray()).trim()) +} + +val gitDiffStdout = ByteArrayOutputStream() +val gitDiffResult = exec { + commandLine("git", "status", "--porcelain") + standardOutput = gitDiffStdout + isIgnoreExitValue = true +} +if (gitDiffStdout.toByteArray().isNotEmpty()) { + buildExtra.add("dirty") } -version = baseVersion + (buildVersion?.let { "+$it" } ?: "") +version = baseVersion + (if (buildExtra.isEmpty()) "" else buildExtra.joinToString(prefix = "+", separator = ".")) // Toolchains: java { - // Forge Gradle currently prevents using the toolchain: toolchain.languageVersion.set(JavaLanguageVersion.of(8)) - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + // Forge Gradle currently prevents using the toolchain: toolchain.languageVersion.set(JavaLanguageVersion.of(8)) + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } minecraft { - version = "1.8.9-11.15.1.2318-1.8.9" - runDir = "run" - mappings = "stable_22" - clientJvmArgs.addAll( - listOf( - "-Dmixin.debug=true", - "-Dasmhelper.verbose=true" - ) - ) - clientRunArgs.addAll( - listOf( - "--tweakClass org.spongepowered.asm.launch.MixinTweaker", - "--mixin mixins.notenoughupdates.json" - ) - ) + version = "1.8.9-11.15.1.2318-1.8.9" + runDir = "run" + mappings = "stable_22" + clientJvmArgs.addAll( + listOf( + "-Dmixin.debug=true", + "-Dasmhelper.verbose=true" + ) + ) + clientRunArgs.addAll( + listOf( + "--tweakClass org.spongepowered.asm.launch.MixinTweaker", + "--mixin mixins.notenoughupdates.json" + ) + ) } mixin { - add(sourceSets.main.get(), "mixins.notenoughupdates.refmap.json") + add(sourceSets.main.get(), "mixins.notenoughupdates.refmap.json") } // Dependencies: @@ -67,14 +85,13 @@ dependencies { annotationProcessor("org.spongepowered:mixin:0.7.11-SNAPSHOT") implementation("com.fasterxml.jackson.core:jackson-core:2.13.1") implementation("info.bliki.wiki:bliki-core:3.1.0") - testImplementation("org.junit.jupiter:junit-jupiter:5.8.2") } // Tasks: tasks.withType(JavaCompile::class) { - options.encoding = "UTF-8" + options.encoding = "UTF-8" } tasks.named<Test>("test") { @@ -82,61 +99,61 @@ tasks.named<Test>("test") { } tasks.withType(Jar::class) { - archiveBaseName.set("NotEnoughUpdates") - manifest.attributes.run { - this["Main-Class"] = "NotSkyblockAddonsInstallerFrame" - this["TweakClass"] = "org.spongepowered.asm.launch.MixinTweaker" - this["MixinConfigs"] = "mixins.notenoughupdates.json" - this["FMLCorePluginContainsFMLMod"] = "true" - this["ForceLoadAsMod"] = "true" - this["FMLAT"] = "notenoughupdates_at.cfg" - } + archiveBaseName.set("NotEnoughUpdates") + manifest.attributes.run { + this["Main-Class"] = "NotSkyblockAddonsInstallerFrame" + this["TweakClass"] = "org.spongepowered.asm.launch.MixinTweaker" + this["MixinConfigs"] = "mixins.notenoughupdates.json" + this["FMLCorePluginContainsFMLMod"] = "true" + this["ForceLoadAsMod"] = "true" + this["FMLAT"] = "notenoughupdates_at.cfg" + } } tasks.shadowJar { - archiveClassifier.set("dep") - exclude( - "module-info.class", - "LICENSE.txt" - ) - dependencies { - include(dependency("org.spongepowered:mixin:0.7.11-SNAPSHOT")) - - include(dependency("commons-io:commons-io")) - include(dependency("org.apache.commons:commons-lang3")) - include(dependency("com.fasterxml.jackson.core:jackson-databind:2.10.2")) - include(dependency("com.fasterxml.jackson.core:jackson-annotations:2.10.2")) - include(dependency("com.fasterxml.jackson.core:jackson-core:2.10.2")) - - include(dependency("info.bliki.wiki:bliki-core:3.1.0")) - include(dependency("org.slf4j:slf4j-api:1.7.18")) - include(dependency("org.luaj:luaj-jse:3.0.1")) - } - fun relocate(name: String) = relocate(name, "io.github.moulberry.notenoughupdates.deps.$name") - relocate("com.fasterxml.jackson") - relocate("org.eclipse") - relocate("org.slf4j") + archiveClassifier.set("dep") + exclude( + "module-info.class", + "LICENSE.txt" + ) + dependencies { + include(dependency("org.spongepowered:mixin:0.7.11-SNAPSHOT")) + + include(dependency("commons-io:commons-io")) + include(dependency("org.apache.commons:commons-lang3")) + include(dependency("com.fasterxml.jackson.core:jackson-databind:2.10.2")) + include(dependency("com.fasterxml.jackson.core:jackson-annotations:2.10.2")) + include(dependency("com.fasterxml.jackson.core:jackson-core:2.10.2")) + + include(dependency("info.bliki.wiki:bliki-core:3.1.0")) + include(dependency("org.slf4j:slf4j-api:1.7.18")) + include(dependency("org.luaj:luaj-jse:3.0.1")) + } + fun relocate(name: String) = relocate(name, "io.github.moulberry.notenoughupdates.deps.$name") + relocate("com.fasterxml.jackson") + relocate("org.eclipse") + relocate("org.slf4j") } tasks.build.get().dependsOn(tasks.shadowJar) reobf { - create("shadowJar") { - mappingType = ReobfMappingType.SEARGE - } + create("shadowJar") { + mappingType = ReobfMappingType.SEARGE + } } tasks.processResources { - from(sourceSets.main.get().resources.srcDirs) - filesMatching("mcmod.info") { - expand( - "version" to project.version, - "mcversion" to minecraft.version - ) - } - rename("(.+_at.cfg)".toPattern(), "META-INF/$1") + from(sourceSets.main.get().resources.srcDirs) + filesMatching("mcmod.info") { + expand( + "version" to project.version, + "mcversion" to minecraft.version + ) + } + rename("(.+_at.cfg)".toPattern(), "META-INF/$1") } sourceSets.main { - output.setResourcesDir(file("$buildDir/classes/java/main")) + output.setResourcesDir(file("$buildDir/classes/java/main")) } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java index abe0bdcf..0e683e5a 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java @@ -1570,4 +1570,10 @@ public class NEUManager { } } } + + public ItemStack createItem(String internalname) { + JsonObject jsonObject = itemMap.get(internalname); + if (jsonObject == null) return null; + return jsonToStack(jsonObject); + } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java index 0a77c677..6b2fd09e 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java @@ -35,6 +35,7 @@ import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.Custom import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.DwarvenMinesTextures; import io.github.moulberry.notenoughupdates.miscgui.CalendarOverlay; import io.github.moulberry.notenoughupdates.miscgui.InventoryStorageSelector; +import io.github.moulberry.notenoughupdates.mixins.AccessorMinecraft; import io.github.moulberry.notenoughupdates.options.NEUConfig; import io.github.moulberry.notenoughupdates.overlays.FuelBar; import io.github.moulberry.notenoughupdates.overlays.OverlayManager; @@ -58,6 +59,7 @@ import net.minecraft.world.biome.BiomeGenJungle; import net.minecraft.world.biome.BiomeGenMesa; import net.minecraft.world.biome.BiomeGenSnow; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventHandler; @@ -160,6 +162,13 @@ public class NotEnoughUpdates { return this.neuDir; } + public NotEnoughUpdates() { + // Budget Construction Event + ((AccessorMinecraft) FMLClientHandler.instance().getClient()) + .onGetDefaultResourcePacks() + .add(new NEURepoResourcePack(null, "neurepo")); + } + /** * Instantiates NEUIo, NEUManager and NEUOverlay instances. Registers keybinds and adds a shutdown hook to clear tmp folder. */ diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java index 127fa911..9256a193 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java @@ -6,15 +6,12 @@ import io.github.moulberry.notenoughupdates.recipes.NeuRecipe; import io.github.moulberry.notenoughupdates.recipes.RecipeSlot; import io.github.moulberry.notenoughupdates.recipes.RecipeType; import io.github.moulberry.notenoughupdates.util.Utils; -import net.minecraft.block.state.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.entity.player.InventoryPlayer; -import net.minecraft.init.Blocks; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.MathHelper; @@ -23,264 +20,342 @@ import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; -import java.awt.Color; +import java.awt.*; import java.io.IOException; +import java.util.List; import java.util.*; public class GuiItemRecipe extends GuiScreen { - public static final ResourceLocation resourcePacksTexture = new ResourceLocation("textures/gui/resource_packs.png"); - public static final ResourceLocation tabsTexture = new ResourceLocation("notenoughupdates", "textures/gui/tab.png"); - - public static final int SLOT_SIZE = 16; - public static final int SLOT_SPACING = SLOT_SIZE + 2; - public static final int BUTTON_WIDTH = 7; - public static final int BUTTON_HEIGHT = 11; - public static final int BUTTON_POSITION_Y = 90; - public static final int BUTTON_POSITION_LEFT_X = 110; - public static final int BUTTON_POSITION_RIGHT_X = 147; - public static final int PAGE_STRING_X = 132; - public static final int PAGE_STRING_Y = BUTTON_POSITION_Y+6; - public static final int TITLE_X = 28; - public static final int TITLE_Y = 6; - public static final int HOTBAR_SLOT_X = 8; - public static final int HOTBAR_SLOT_Y = 197; - public static final int PLAYER_INVENTORY_X = 8; - public static final int PLAYER_INVENTORY_Y = 140; - public static final int TAB_POS_X = -26; - public static final int TAB_POS_Y = 8; - public static final int TAB_OFFSET_Y = 30; - public static final int TAB_SIZE_X = 26; - public static final int TAB_SIZE_Y = 30; - public static final int TAB_TEXTURE_SIZE_X = 29; - - - private int currentIndex = 0; - private int currentTab = 0; - - private final String title; - private final Map<RecipeType, List<NeuRecipe>> craftingRecipes = new HashMap<>(); - private final List<RecipeType> tabs = new ArrayList<>(); - private final NEUManager manager; - - public int guiLeft = 0; - public int guiTop = 0; - public int xSize = 176; - public int ySize = 222; - - public GuiItemRecipe(String title, List<NeuRecipe> unsortedRecipes, NEUManager manager) { - this.manager = manager; - this.title = title; - - for (NeuRecipe recipe : unsortedRecipes) { - craftingRecipes.computeIfAbsent(recipe.getType(), ignored -> new ArrayList<>()).add(recipe); - if (!tabs.contains(recipe.getType())) - tabs.add(recipe.getType()); - } - } - - public NeuRecipe getCurrentRecipe() { - List<NeuRecipe> currentRecipes = getCurrentRecipeList(); - currentIndex = MathHelper.clamp_int(currentIndex, 0, currentRecipes.size() - 1); - return currentRecipes.get(currentIndex); - } - - public List<NeuRecipe> getCurrentRecipeList() { - return craftingRecipes.get(getCurrentTab()); - } - - public RecipeType getCurrentTab() { - currentTab = MathHelper.clamp_int(currentTab, 0, tabs.size() - 1); - return tabs.get(currentTab); - } - - - public boolean isWithinRect(int x, int y, int topLeftX, int topLeftY, int width, int height) { - return topLeftX <= x && x <= topLeftX + width - && topLeftY <= y && y <= topLeftY + height; - } - - private ImmutableList<RecipeSlot> getAllRenderedSlots() { - return ImmutableList.<RecipeSlot>builder() - .addAll(getPlayerInventory()) - .addAll(getCurrentRecipe().getSlots()).build(); - } - - @Override - public void drawScreen(int mouseX, int mouseY, float partialTicks) { - drawDefaultBackground(); - FontRenderer fontRendererObj = Minecraft.getMinecraft().fontRendererObj; - - this.guiLeft = (width - this.xSize) / 2; - this.guiTop = (height - this.ySize) / 2; - - GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); - - NeuRecipe currentRecipe = getCurrentRecipe(); - - Minecraft.getMinecraft().getTextureManager().bindTexture(currentRecipe.getBackground()); - this.drawTexturedModalRect(guiLeft, guiTop, 0, 0, this.xSize, this.ySize); - - drawTabs(); - - currentRecipe.drawExtraBackground(this, mouseX, mouseY); - - List<RecipeSlot> slots = getAllRenderedSlots(); - for (RecipeSlot slot : slots) { - Utils.drawItemStack(slot.getItemStack(), slot.getX(this), slot.getY(this)); - } - - drawArrows(mouseX, mouseY); - - Utils.drawStringScaledMaxWidth(title, fontRendererObj, guiLeft + TITLE_X, guiTop + TITLE_Y, false, xSize - 38, 0x404040); - - currentRecipe.drawExtraInfo(this, mouseX, mouseY); - - for (RecipeSlot slot : slots) { - if (isWithinRect(mouseX, mouseY, slot.getX(this), slot.getY(this), SLOT_SIZE, SLOT_SIZE)) { - if (slot.getItemStack() == null) continue; - Utils.drawHoveringText(slot.getItemStack().getTooltip(Minecraft.getMinecraft().thePlayer, false), mouseX, mouseY, width, height, -1, fontRendererObj); - } - } - currentRecipe.drawHoverInformation(this, mouseX, mouseY); - drawTabHoverInformation(mouseX, mouseY); - } - - private void drawTabHoverInformation(int mouseX, int mouseY) { - if (tabs.size() < 2) return; - for (int i = 0; i < tabs.size(); i++) { - if (isWithinRect(mouseX - guiLeft, mouseY - guiTop, TAB_POS_X, TAB_POS_Y + TAB_OFFSET_Y * i, TAB_SIZE_X, TAB_SIZE_Y)) { - RecipeType type = tabs.get(i); - Utils.drawHoveringText( - Arrays.asList( - "" + EnumChatFormatting.RESET + EnumChatFormatting.GREEN + type.getLabel(), - "" + EnumChatFormatting.RESET + EnumChatFormatting.GRAY + craftingRecipes.get(type).size() + " Recipes" - ), - mouseX, mouseY, width, height, -1, Minecraft.getMinecraft().fontRendererObj); - return; - } - } - } - - private void drawTabs() { - if (tabs.size() < 2) return; - for (int i = 0; i < tabs.size(); i++) { - RecipeType recipeType = tabs.get(i); - int tabPosX = guiLeft + TAB_POS_X, tabPosY = guiTop + TAB_OFFSET_Y * i + TAB_POS_Y; - int textureOffset = 0; - if (currentTab == i) { - textureOffset = 30; - } - Minecraft.getMinecraft().getTextureManager().bindTexture(tabsTexture); - drawTexturedModalRect( - tabPosX, tabPosY, - 0, textureOffset, - TAB_TEXTURE_SIZE_X, TAB_SIZE_Y - ); - Minecraft.getMinecraft().getTextureManager().bindTexture(recipeType.getIcon()); - drawTexturedModalRect(tabPosX + 7, tabPosY + 7, 6, 0, 16, 16); - } - } - - private void drawArrows(int mouseX, int mouseY) { - int recipeCount = getCurrentRecipeList().size(); - if (recipeCount < 2) return; - boolean leftSelected = isWithinRect(mouseX - guiLeft, mouseY - guiTop, BUTTON_POSITION_LEFT_X, BUTTON_POSITION_Y, BUTTON_WIDTH, BUTTON_HEIGHT); - boolean rightSelected = isWithinRect(mouseX - guiLeft, mouseY - guiTop, BUTTON_POSITION_RIGHT_X, BUTTON_POSITION_Y, BUTTON_WIDTH, BUTTON_HEIGHT); - Minecraft.getMinecraft().getTextureManager().bindTexture(resourcePacksTexture); - - if (currentIndex != 0) - Utils.drawTexturedRect(guiLeft + BUTTON_POSITION_LEFT_X, guiTop + BUTTON_POSITION_Y, BUTTON_WIDTH, BUTTON_HEIGHT, - 34 / 256f, 48 / 256f, - leftSelected ? 37 / 256f : 5 / 256f, leftSelected ? 59 / 256f : 27 / 256f - ); - if (currentIndex != recipeCount - 1) - Utils.drawTexturedRect(guiLeft + BUTTON_POSITION_RIGHT_X, guiTop + BUTTON_POSITION_Y, BUTTON_WIDTH, BUTTON_HEIGHT, - 10 / 256f, 24 / 256f, - rightSelected ? 37 / 256f : 5 / 256f, rightSelected ? 59 / 256f : 27 / 256f - ); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); - - String selectedPage = (currentIndex + 1) + "/" + recipeCount; - - Utils.drawStringCenteredScaledMaxWidth(selectedPage, fontRendererObj, - guiLeft + PAGE_STRING_X, guiTop + PAGE_STRING_Y, false, 24, Color.BLACK.getRGB()); - } - - public List<RecipeSlot> getPlayerInventory() { - List<RecipeSlot> slots = new ArrayList<>(); - ItemStack[] inventory = Minecraft.getMinecraft().thePlayer.inventory.mainInventory; - int hotbarSize = InventoryPlayer.getHotbarSize(); - for (int i = 0; i < inventory.length; i++) { - ItemStack item = inventory[i]; - if (item == null || item.stackSize == 0) continue; - int row = i / hotbarSize; - int col = i % hotbarSize; - if (row == 0) - slots.add(new RecipeSlot(HOTBAR_SLOT_X + i * SLOT_SPACING, HOTBAR_SLOT_Y, item)); - else - slots.add(new RecipeSlot(PLAYER_INVENTORY_X + col * SLOT_SPACING, PLAYER_INVENTORY_Y + (row - 1) * SLOT_SPACING, item)); - } - return slots; - } - - @Override - public void handleKeyboardInput() throws IOException { - super.handleKeyboardInput(); - - ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); - int width = scaledResolution.getScaledWidth(); - int height = scaledResolution.getScaledHeight(); - int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; - int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; - int keyPressed = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter()+256 : Keyboard.getEventKey(); - if (Keyboard.getEventKeyState()) return; - for (RecipeSlot slot : getAllRenderedSlots()) { - if (isWithinRect(mouseX, mouseY, slot.getX(this), slot.getY(this), SLOT_SIZE, SLOT_SIZE)) { - ItemStack itemStack = slot.getItemStack(); - if (keyPressed == manager.keybindViewRecipe.getKeyCode()) { - manager.displayGuiItemRecipe(manager.getInternalNameForItem(itemStack), null); - } else if (keyPressed == manager.keybindViewUsages.getKeyCode()) { - manager.displayGuiItemUsages(manager.getInternalNameForItem(itemStack)); - } - } - } - } - - @Override - protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { - super.mouseClicked(mouseX, mouseY, mouseButton); - - if (isWithinRect(mouseX - guiLeft, mouseY - guiTop, BUTTON_POSITION_LEFT_X, BUTTON_POSITION_Y, BUTTON_WIDTH, BUTTON_HEIGHT) && - currentIndex > 0) { - currentIndex = currentIndex - 1; - Utils.playPressSound(); - return; - } - - if (isWithinRect(mouseX - guiLeft, mouseY - guiTop, BUTTON_POSITION_RIGHT_X, BUTTON_POSITION_Y, BUTTON_WIDTH, BUTTON_HEIGHT) && - currentIndex < getCurrentRecipeList().size()) { - currentIndex = currentIndex + 1; - Utils.playPressSound(); - return; - } - - for (int i = 0; i < tabs.size(); i++) { - if (isWithinRect(mouseX - guiLeft, mouseY - guiTop, TAB_POS_X, TAB_POS_Y + TAB_OFFSET_Y * i, TAB_SIZE_X, TAB_SIZE_Y)) { - currentTab = i; - Utils.playPressSound(); - return; - } - } - - for (RecipeSlot slot : getAllRenderedSlots()) { - if (isWithinRect(mouseX, mouseY, slot.getX(this), slot.getY(this), SLOT_SIZE, SLOT_SIZE)) { - ItemStack itemStack = slot.getItemStack(); - if (mouseButton == 0) { - manager.displayGuiItemRecipe(manager.getInternalNameForItem(itemStack), null); - } else if (mouseButton == 1) { - manager.displayGuiItemUsages(manager.getInternalNameForItem(itemStack)); - } - } - } - } + public static final ResourceLocation resourcePacksTexture = new ResourceLocation("textures/gui/resource_packs.png"); + public static final ResourceLocation tabsTexture = new ResourceLocation("notenoughupdates", "textures/gui/tab.png"); + + public static final int SLOT_SIZE = 16; + public static final int SLOT_SPACING = SLOT_SIZE + 2; + public static final int BUTTON_WIDTH = 7; + public static final int BUTTON_HEIGHT = 11; + public static final int TITLE_X = 28; + public static final int TITLE_Y = 6; + public static final int HOTBAR_SLOT_X = 8; + public static final int HOTBAR_SLOT_Y = 197; + public static final int PLAYER_INVENTORY_X = 8; + public static final int PLAYER_INVENTORY_Y = 140; + public static final int TAB_POS_X = -26; + public static final int TAB_POS_Y = 8; + public static final int TAB_OFFSET_Y = 30; + public static final int TAB_SIZE_X = 26; + public static final int TAB_SIZE_Y = 30; + public static final int TAB_TEXTURE_SIZE_X = 29; + + private int currentIndex = 0; + private int currentTab = 0; + + private final String title; + private final Map<RecipeType, List<NeuRecipe>> craftingRecipes = new HashMap<>(); + private final List<RecipeType> tabs = new ArrayList<>(); + private final NEUManager manager; + + public int guiLeft = 0; + public int guiTop = 0; + public int xSize = 176; + public int ySize = 222; + + public GuiItemRecipe(String title, List<NeuRecipe> unsortedRecipes, NEUManager manager) { + this.manager = manager; + this.title = title; + + for (NeuRecipe recipe : unsortedRecipes) { + craftingRecipes.computeIfAbsent(recipe.getType(), ignored -> new ArrayList<>()).add(recipe); + if (!tabs.contains(recipe.getType())) + tabs.add(recipe.getType()); + } + } + + public NeuRecipe getCurrentRecipe() { + List<NeuRecipe> currentRecipes = getCurrentRecipeList(); + currentIndex = MathHelper.clamp_int(currentIndex, 0, currentRecipes.size() - 1); + return currentRecipes.get(currentIndex); + } + + public List<NeuRecipe> getCurrentRecipeList() { + return craftingRecipes.get(getCurrentTab()); + } + + public RecipeType getCurrentTab() { + currentTab = MathHelper.clamp_int(currentTab, 0, tabs.size() - 1); + return tabs.get(currentTab); + } + + public boolean isWithinRect(int x, int y, int topLeftX, int topLeftY, int width, int height) { + return topLeftX <= x && x <= topLeftX + width + && topLeftY <= y && y <= topLeftY + height; + } + + private ImmutableList<RecipeSlot> getAllRenderedSlots() { + return ImmutableList.<RecipeSlot>builder() + .addAll(getPlayerInventory()) + .addAll(getCurrentRecipe().getSlots()).build(); + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + drawDefaultBackground(); + FontRenderer fontRendererObj = Minecraft.getMinecraft().fontRendererObj; + + this.guiLeft = (width - this.xSize) / 2; + this.guiTop = (height - this.ySize) / 2; + + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + + NeuRecipe currentRecipe = getCurrentRecipe(); + + Minecraft.getMinecraft().getTextureManager().bindTexture(currentRecipe.getBackground()); + this.drawTexturedModalRect(guiLeft, guiTop, 0, 0, this.xSize, this.ySize); + + drawTabs(); + + currentRecipe.drawExtraBackground(this, mouseX, mouseY); + + List<RecipeSlot> slots = getAllRenderedSlots(); + for (RecipeSlot slot : slots) { + Utils.drawItemStack(slot.getItemStack(), slot.getX(this), slot.getY(this)); + } + + drawArrows(currentRecipe, mouseX, mouseY); + + Utils.drawStringScaledMaxWidth( + title, + fontRendererObj, + guiLeft + TITLE_X, + guiTop + TITLE_Y, + false, + xSize - 38, + 0x404040 + ); + + currentRecipe.drawExtraInfo(this, mouseX, mouseY); + + for (RecipeSlot slot : slots) { + if (isWithinRect(mouseX, mouseY, slot.getX(this), slot.getY(this), SLOT_SIZE, SLOT_SIZE)) { + if (slot.getItemStack() == null) continue; + Utils.drawHoveringText( + slot.getItemStack().getTooltip(Minecraft.getMinecraft().thePlayer, false), + mouseX, + mouseY, + width, + height, + -1, + fontRendererObj + ); + } + } + currentRecipe.drawHoverInformation(this, mouseX, mouseY); + drawTabHoverInformation(mouseX, mouseY); + } + + private void drawTabHoverInformation(int mouseX, int mouseY) { + if (tabs.size() < 2) return; + for (int i = 0; i < tabs.size(); i++) { + if (isWithinRect( + mouseX - guiLeft, + mouseY - guiTop, + TAB_POS_X, + TAB_POS_Y + TAB_OFFSET_Y * i, + TAB_SIZE_X, + TAB_SIZE_Y + )) { + RecipeType type = tabs.get(i); + Utils.drawHoveringText( + Arrays.asList( + "" + EnumChatFormatting.RESET + EnumChatFormatting.GREEN + type.getLabel(), + "" + EnumChatFormatting.RESET + EnumChatFormatting.GRAY + craftingRecipes.get(type).size() + " Recipes" + ), + mouseX, mouseY, width, height, -1, Minecraft.getMinecraft().fontRendererObj + ); + return; + } + } + } + + private void drawTabs() { + if (tabs.size() < 2) return; + for (int i = 0; i < tabs.size(); i++) { + RecipeType recipeType = tabs.get(i); + int tabPosX = guiLeft + TAB_POS_X, tabPosY = guiTop + TAB_OFFSET_Y * i + TAB_POS_Y; + int textureOffset = 0; + if (currentTab == i) { + textureOffset = 30; + } + Minecraft.getMinecraft().getTextureManager().bindTexture(tabsTexture); + drawTexturedModalRect( + tabPosX, tabPosY, + 0, textureOffset, + TAB_TEXTURE_SIZE_X, TAB_SIZE_Y + ); + Minecraft.getMinecraft().getTextureManager().bindTexture(recipeType.getIcon()); + drawTexturedModalRect(tabPosX + 7, tabPosY + 7, 6, 0, 16, 16); + } + } + + public static final int BUTTON_POSITION_RIGHT_OFFSET_X = 37; + public static final int PAGE_STRING_OFFSET_X = 22; + public static final int PAGE_STRING_OFFSET_Y = 6; + + private void drawArrows( + NeuRecipe currentRecipe, + int mouseX, + int mouseY + ) { + int recipeCount = getCurrentRecipeList().size(); + if (recipeCount < 2) return; + int[] topLeft = currentRecipe.getPageFlipPositionLeftTopCorner(); + int buttonPositionLeftX = topLeft[0]; + int buttonPositionRightX = buttonPositionLeftX + BUTTON_POSITION_RIGHT_OFFSET_X; + int pageStringX = buttonPositionLeftX + PAGE_STRING_OFFSET_X; + int buttonPositionY = topLeft[1]; + int pageStringY = buttonPositionY + PAGE_STRING_OFFSET_Y; + + boolean leftSelected = isWithinRect( + mouseX - guiLeft, + mouseY - guiTop, + buttonPositionLeftX, + buttonPositionY, + BUTTON_WIDTH, + BUTTON_HEIGHT + ); + boolean rightSelected = isWithinRect( + mouseX - guiLeft, + mouseY - guiTop, + buttonPositionRightX, + buttonPositionY, + BUTTON_WIDTH, + BUTTON_HEIGHT + ); + Minecraft.getMinecraft().getTextureManager().bindTexture(resourcePacksTexture); + + if (currentIndex != 0) + Utils.drawTexturedRect(guiLeft + buttonPositionLeftX, guiTop + buttonPositionY, BUTTON_WIDTH, BUTTON_HEIGHT, + 34 / 256f, 48 / 256f, + leftSelected ? 37 / 256f : 5 / 256f, leftSelected ? 59 / 256f : 27 / 256f + ); + if (currentIndex != recipeCount - 1) + Utils.drawTexturedRect(guiLeft + buttonPositionRightX, guiTop + buttonPositionY, BUTTON_WIDTH, BUTTON_HEIGHT, + 10 / 256f, 24 / 256f, + rightSelected ? 37 / 256f : 5 / 256f, rightSelected ? 59 / 256f : 27 / 256f + ); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + + String selectedPage = (currentIndex + 1) + "/" + recipeCount; + + Utils.drawStringCenteredScaledMaxWidth(selectedPage, fontRendererObj, + guiLeft + pageStringX, guiTop + pageStringY, false, 24, Color.BLACK.getRGB() + ); + } + + public List<RecipeSlot> getPlayerInventory() { + List<RecipeSlot> slots = new ArrayList<>(); + ItemStack[] inventory = Minecraft.getMinecraft().thePlayer.inventory.mainInventory; + int hotbarSize = InventoryPlayer.getHotbarSize(); + for (int i = 0; i < inventory.length; i++) { + ItemStack item = inventory[i]; + if (item == null || item.stackSize == 0) continue; + int row = i / hotbarSize; + int col = i % hotbarSize; + if (row == 0) + slots.add(new RecipeSlot(HOTBAR_SLOT_X + i * SLOT_SPACING, HOTBAR_SLOT_Y, item)); + else + slots.add(new RecipeSlot( + PLAYER_INVENTORY_X + col * SLOT_SPACING, + PLAYER_INVENTORY_Y + (row - 1) * SLOT_SPACING, + item + )); + } + return slots; + } + + @Override + public void handleKeyboardInput() throws IOException { + super.handleKeyboardInput(); + + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + int width = scaledResolution.getScaledWidth(); + int height = scaledResolution.getScaledHeight(); + int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; + int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; + int keyPressed = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey(); + if (Keyboard.getEventKeyState()) return; + for (RecipeSlot slot : getAllRenderedSlots()) { + if (isWithinRect(mouseX, mouseY, slot.getX(this), slot.getY(this), SLOT_SIZE, SLOT_SIZE)) { + ItemStack itemStack = slot.getItemStack(); + if (keyPressed == manager.keybindViewRecipe.getKeyCode()) { + manager.displayGuiItemRecipe(manager.getInternalNameForItem(itemStack), null); + } else if (keyPressed == manager.keybindViewUsages.getKeyCode()) { + manager.displayGuiItemUsages(manager.getInternalNameForItem(itemStack)); + } + } + } + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { + super.mouseClicked(mouseX, mouseY, mouseButton); + NeuRecipe currentRecipe = getCurrentRecipe(); + int[] topLeft = currentRecipe.getPageFlipPositionLeftTopCorner(); + int buttonPositionLeftX = topLeft[0]; + int buttonPositionRightX = buttonPositionLeftX + BUTTON_POSITION_RIGHT_OFFSET_X; + int buttonPositionY = topLeft[1]; + + if (isWithinRect( + mouseX - guiLeft, + mouseY - guiTop, + buttonPositionLeftX, + buttonPositionY, + BUTTON_WIDTH, + BUTTON_HEIGHT + ) && + currentIndex > 0) { + currentIndex = currentIndex - 1; + Utils.playPressSound(); + return; + } + + if (isWithinRect( + mouseX - guiLeft, + mouseY - guiTop, + buttonPositionRightX, + buttonPositionY, + BUTTON_WIDTH, + BUTTON_HEIGHT + ) && + currentIndex < getCurrentRecipeList().size()) { + currentIndex = currentIndex + 1; + Utils.playPressSound(); + return; + } + + for (int i = 0; i < tabs.size(); i++) { + if (isWithinRect( + mouseX - guiLeft, + mouseY - guiTop, + TAB_POS_X, + TAB_POS_Y + TAB_OFFSET_Y * i, + TAB_SIZE_X, + TAB_SIZE_Y + )) { + currentTab = i; + Utils.playPressSound(); + return; + } + } + + for (RecipeSlot slot : getAllRenderedSlots()) { + if (isWithinRect(mouseX, mouseY, slot.getX(this), slot.getY(this), SLOT_SIZE, SLOT_SIZE)) { + ItemStack itemStack = slot.getItemStack(); + if (mouseButton == 0) { + manager.displayGuiItemRecipe(manager.getInternalNameForItem(itemStack), null); + } else if (mouseButton == 1) { + manager.displayGuiItemUsages(manager.getInternalNameForItem(itemStack)); + } + } + } + } } 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 5670f1bd..5cc32528 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java @@ -8,214 +8,258 @@ 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.JsonUtils; 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.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; import java.util.stream.Collectors; -import java.util.stream.StreamSupport; public class MobLootRecipe implements NeuRecipe { - private static final int MOB_POS_X = 38, MOB_POS_Y = 100; - private static final int SLOT_POS_X = 82, SLOT_POS_Y = 23; - - public static class MobDrop { - public final Ingredient drop; - public final String chance; - public final List<String> extra; - - public MobDrop(Ingredient drop, String chance, List<String> extra) { - this.drop = drop; - this.chance = chance; - this.extra = extra; - } - } - - 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; - private final int combatXp; - 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 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; - this.name = name; - this.render = render; - } - - public String getName() { - return name; - } - - public List<MobDrop> getDrops() { - return drops; - } - - public int getCoins() { - return coins; - } - - public int getCombatXp() { - return combatXp; - } - - public int getXp() { - return xp; - } - - public String getRender() { - return render; - } - - public synchronized EntityLivingBase getRenderEntity() { - if (entityLivingBase == null) { - if (render == null) return null; - if (render.startsWith("@")) { - entityLivingBase = EntityViewer.constructEntity(new ResourceLocation(render.substring(1))); - } else { - entityLivingBase = EntityViewer.constructEntity(render, Collections.emptyList()); - } - } - return entityLivingBase; - } - - @Override - public Set<Ingredient> getIngredients() { - return Collections.emptySet(); - } - - @Override - public Set<Ingredient> getOutputs() { - return drops.stream().map(it -> it.drop).collect(Collectors.toSet()); - } - - @Override - public List<RecipeSlot> getSlots() { - List<RecipeSlot> slots = new ArrayList<>(); - for (int i = 0; i < drops.size(); i++) { - MobDrop mobDrop = drops.get(i); - int x = i % 5; - int y = i / 5; - slots.add(new RecipeSlot( - SLOT_POS_X + x * 16, - SLOT_POS_Y + y * 16, - mobDrop.drop.getItemStack() - )); - } - return slots; - } - - @Override - public RecipeType getType() { - return RecipeType.MOB_LOOT; - } - - @Override - public boolean shouldUseForCraftCost() { - return false; - } - - @Override - public boolean hasVariableCost() { - 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) { - 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() { - 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 - public ResourceLocation getBackground() { - return BACKGROUND; - } - - public static MobLootRecipe parseRecipe(NEUManager manager, JsonObject recipe, JsonObject outputItemJson) { - List<MobDrop> drops = new ArrayList<>(); - for (JsonElement jsonElement : recipe.getAsJsonArray("drops")) { - if (jsonElement.isJsonPrimitive()) { - drops.add(new MobDrop(new Ingredient(manager, jsonElement.getAsString()), null, Collections.emptyList())); - } else { - JsonObject jsonObject = jsonElement.getAsJsonObject(); - drops.add( - new MobDrop( - new Ingredient(manager, jsonObject.get("id").getAsString()), - jsonObject.has("chance") ? jsonObject.get("chance").getAsString() : null, - jsonObject.has("extra") ? - StreamSupport.stream(jsonObject.getAsJsonArray("extra").spliterator(), false) - .map(JsonElement::getAsString) - .collect(Collectors.toList()) : Collections.emptyList() - )); - } - } - - 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.has("render") && !recipe.get("render").isJsonNull() ? recipe.get("render").getAsString() : null - ); - } + private static final int MOB_POS_X = 38, MOB_POS_Y = 100; + private static final int SLOT_POS_X = 82, SLOT_POS_Y = 23; + + public static class MobDrop { + public final Ingredient drop; + public final String chance; + public final List<String> extra; + + public MobDrop(Ingredient drop, String chance, List<String> extra) { + this.drop = drop; + this.chance = chance; + this.extra = extra; + } + } + + 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; + private final int combatXp; + private final int xp; + private final String name; + private final String render; + private final int level; + private final List<String> extra; + private EntityLivingBase entityLivingBase; + + public MobLootRecipe( + List<MobDrop> drops, + int level, + int coins, + int xp, + int combatXp, + String name, + String render, + List<String> extra + ) { + this.drops = drops; + this.level = level; + this.coins = coins; + this.xp = xp; + this.extra = extra; + this.combatXp = combatXp; + this.name = name; + this.render = render; + } + + public String getName() { + return name; + } + + public List<MobDrop> getDrops() { + return drops; + } + + public int getCoins() { + return coins; + } + + public int getCombatXp() { + return combatXp; + } + + public int getXp() { + return xp; + } + + public String getRender() { + return render; + } + + public synchronized EntityLivingBase getRenderEntity() { + if (entityLivingBase == null) { + if (render == null) return null; + if (render.startsWith("@")) { + entityLivingBase = EntityViewer.constructEntity(new ResourceLocation(render.substring(1))); + } else { + entityLivingBase = EntityViewer.constructEntity(render, Collections.emptyList()); + } + } + return entityLivingBase; + } + + @Override + public Set<Ingredient> getIngredients() { + return Collections.emptySet(); + } + + @Override + public Set<Ingredient> getOutputs() { + return drops.stream().map(it -> it.drop).collect(Collectors.toSet()); + } + + @Override + public List<RecipeSlot> getSlots() { + List<RecipeSlot> slots = new ArrayList<>(); + for (int i = 0; i < drops.size(); i++) { + MobDrop mobDrop = drops.get(i); + int x = i % 5; + int y = i / 5; + slots.add(new RecipeSlot( + SLOT_POS_X + x * 16, + SLOT_POS_Y + y * 16, + mobDrop.drop.getItemStack() + )); + } + return slots; + } + + @Override + public RecipeType getType() { + return RecipeType.MOB_LOOT; + } + + @Override + public boolean shouldUseForCraftCost() { + return false; + } + + @Override + public boolean hasVariableCost() { + 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) { + 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 + )) { + List<String> stuff = new ArrayList<>(extra); + stuff.add(0, "[Lvl " + level + "] " + name); + Utils.drawHoveringText( + stuff, + mouseX, + mouseY, + gui.width, + gui.height, + -1, + Minecraft.getMinecraft().fontRendererObj + ); + } + } + + @Override + public int[] getPageFlipPositionLeftTopCorner() { + return new int[]{14, 118}; + } + + @Override + public JsonObject serialize() { + 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()); + recipe.add("extra", JsonUtils.transformListToJsonArray(extra, JsonPrimitive::new)); + recipe.add("drops", JsonUtils.transformListToJsonArray(drops, drop -> { + 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); + return dropObject; + })); + return recipe; + } + + @Override + public ResourceLocation getBackground() { + return BACKGROUND; + } + + public static MobLootRecipe parseRecipe(NEUManager manager, JsonObject recipe, JsonObject outputItemJson) { + List<MobDrop> drops = new ArrayList<>(); + for (JsonElement jsonElement : recipe.getAsJsonArray("drops")) { + if (jsonElement.isJsonPrimitive()) { + drops.add(new MobDrop(new Ingredient(manager, jsonElement.getAsString()), null, Collections.emptyList())); + } else { + JsonObject jsonObject = jsonElement.getAsJsonObject(); + drops.add( + new MobDrop( + new Ingredient(manager, jsonObject.get("id").getAsString()), + jsonObject.has("chance") ? jsonObject.get("chance").getAsString() : null, + JsonUtils.getJsonArrayOrEmpty(jsonObject, "extra", JsonElement::getAsString) + )); + } + } + + 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.has("render") && !recipe.get("render").isJsonNull() ? recipe.get("render").getAsString() : null, + JsonUtils.getJsonArrayOrEmpty(recipe, "extra", JsonElement::getAsString) + ); + } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/NeuRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/NeuRecipe.java index b14a724e..232e1629 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/NeuRecipe.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/NeuRecipe.java @@ -9,43 +9,50 @@ import java.util.List; import java.util.Set; public interface NeuRecipe { - Set<Ingredient> getIngredients(); + Set<Ingredient> getIngredients(); - Set<Ingredient> getOutputs(); + Set<Ingredient> getOutputs(); - List<RecipeSlot> getSlots(); + List<RecipeSlot> getSlots(); - RecipeType getType(); + RecipeType getType(); - default void drawExtraInfo(GuiItemRecipe gui, int mouseX, int mouseY) { - } + default void drawExtraInfo(GuiItemRecipe gui, int mouseX, int mouseY) { + } - default void drawExtraBackground(GuiItemRecipe gui, int mouseX, int mouseY) { - } + default void drawExtraBackground(GuiItemRecipe gui, int mouseX, int mouseY) { + } - default void drawHoverInformation(GuiItemRecipe gui, int mouseX, int mouseY) { - } + default void drawHoverInformation(GuiItemRecipe gui, int mouseX, int mouseY) { + } - boolean hasVariableCost(); + boolean hasVariableCost(); - JsonObject serialize(); + JsonObject serialize(); - ResourceLocation getBackground(); + ResourceLocation getBackground(); - static NeuRecipe parseRecipe(NEUManager manager, JsonObject recipe, JsonObject output) { - RecipeType recipeType = RecipeType.CRAFTING; - if (recipe.has("type")) { - recipeType = RecipeType.getRecipeTypeForId(recipe.get("type").getAsString()); - } - if (recipeType == null) return null; - return recipeType.createRecipe(manager, recipe, output); - } + static NeuRecipe parseRecipe(NEUManager manager, JsonObject recipe, JsonObject output) { + RecipeType recipeType = RecipeType.CRAFTING; + if (recipe.has("type")) { + recipeType = RecipeType.getRecipeTypeForId(recipe.get("type").getAsString()); + } + if (recipeType == null) return null; + return recipeType.createRecipe(manager, recipe, output); + } - default boolean shouldUseForCraftCost() { - return true; - } + default boolean shouldUseForCraftCost() { + return true; + } - default boolean isAvailable() { - return true; - } + default boolean isAvailable() { + return true; + } + + /** + * @return an array of length two in the format [leftmost x, topmost y] of the page buttons + */ + default int[] getPageFlipPositionLeftTopCorner() { + return new int[]{110, 90}; + } } 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 09e60003..6c2d1102 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeGenerator.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeGenerator.java @@ -165,7 +165,7 @@ public class RecipeGenerator { } } - recipes.add(new MobLootRecipe(drops, level, coins, xp, combatXp, name, null)); + recipes.add(new MobLootRecipe(drops, level, coins, xp, combatXp, name, null, new ArrayList<>())); } boolean saved = false; try { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/JsonUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/JsonUtils.java new file mode 100644 index 00000000..916631b7 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/JsonUtils.java @@ -0,0 +1,42 @@ +package io.github.moulberry.notenoughupdates.util; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import java.util.Collections; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +public class JsonUtils { + public static Stream<JsonElement> getJsonArrayAsStream(JsonArray array) { + return StreamSupport.stream(array.spliterator(), false); + } + + public static <T> List<T> transformJsonArrayToList(JsonArray array, Function<? super JsonElement, ? extends T> mapper) { + return getJsonArrayAsStream(array).map(mapper).collect(Collectors.toList()); + } + + public static <T> List<T> getJsonArrayOrEmpty(JsonObject rootObject, String name, Function<? super JsonElement, ? extends T> mapper) { + if (!rootObject.has(name)) { + return Collections.emptyList(); + } + JsonElement jsonElement = rootObject.get(name); + if (jsonElement.isJsonArray()) { + return transformJsonArrayToList(jsonElement.getAsJsonArray(), mapper); + } + return Collections.emptyList(); + } + + public static <T> JsonArray transformListToJsonArray(List<T> things, Function<? super T, ? extends JsonElement> mapper) { + JsonArray array = new JsonArray(); + for (T t : things) { + array.add(mapper.apply(t)); + } + return array; + } + +} |