aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman / Nea <roman.graef@gmail.com>2022-04-18 17:33:32 +0200
committerGitHub <noreply@github.com>2022-04-18 17:33:32 +0200
commit2692193e54e4dd6c0117dcdb85368dc83bb04f1a (patch)
tree96f01454c404ac04a46ea0d9bf684c7dc5619a57
parent9fe86ccb4d30b78826e513a6576027ca6e4c1600 (diff)
downloadNotEnoughUpdates-2692193e54e4dd6c0117dcdb85368dc83bb04f1a.tar.gz
NotEnoughUpdates-2692193e54e4dd6c0117dcdb85368dc83bb04f1a.tar.bz2
NotEnoughUpdates-2692193e54e4dd6c0117dcdb85368dc83bb04f1a.zip
Mob loot recipe PR (#81)
* entity renderer (somewhat functionaL) * more modifiers and entities * Fix cookie fuckup * add neu repo as resource pack, cause why not at this point * add tabs, because i can * add extra skin parts and make less tabs * hot tall men * fix texture offsets and also parts:true * some untested changes * still broken, but better (just like me (stop being edgy nea ( no u )))) * stuff (with er skeletons * niceities * skytils interop * horseys * horseys ouch * panos * stupid tests :angery: * NPE * add drop chance * colored leather armo * finish off * move shit into hover cause items look pretty terrible * Update 2.1.md * better recipe display name * always show mobs toggle * moving parts
-rw-r--r--.github/CODEOWNERS2
-rw-r--r--Update Notes/2.1.md1
-rw-r--r--build.gradle.kts193
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java18
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEURepoResourcePack.java75
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java9
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/EntityViewerCommand.java81
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/AgeModifier.java30
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/ChargedModifier.java17
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewer.java177
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewerModifier.java8
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EquipmentModifier.java72
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/GUIClientPlayer.java40
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/HorseModifier.java66
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/InvisibleModifier.java12
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/RidingModifier.java14
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/SkinModifier.java46
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/WitherModifier.java29
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java199
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityAgeable.java12
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityArmorStand.java12
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorMinecraft.java14
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityAgeable.java1
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityHorse.java17
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntitySkeleton.java17
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java4
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Itemlist.java10
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java36
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/Panorama.java38
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingOverlay.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingRecipe.java257
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/ForgeRecipe.java442
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/Ingredient.java5
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java309
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/NeuRecipe.java24
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeGenerator.java169
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeType.java59
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/VillagerTradeRecipe.java256
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java33
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/JsonUtils.java42
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/SkytilsCompat.java82
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java17
-rw-r--r--src/main/resources/assets/notenoughupdates/dream.json49
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/crafting_table_tall.pngbin0 -> 12019 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/entity_viewer.pngbin0 -> 8085 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe.pngbin889 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe_tall.pngbin0 -> 9257 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/mob_loot_tall.pngbin0 -> 9503 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/tab.pngbin0 -> 1247 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe.pngbin8633 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe_tall.pngbin0 -> 9218 bytes
-rw-r--r--src/main/resources/mixins.notenoughupdates.json7
54 files changed, 2302 insertions, 705 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/Update Notes/2.1.md b/Update Notes/2.1.md
index 18a4ba8a..dff52a65 100644
--- a/Update Notes/2.1.md
+++ b/Update Notes/2.1.md
@@ -19,6 +19,7 @@
- Added support for official Hypixel wiki, can be toggled in /neu misc - DeDiamondPro
### **Minor Changes:**
- Add built-in recipes for forge crafts - nea89
+- Add mob drop viewer in the recipe viewer - nea89
- Add Stranded Villager Trades to the item list - nea89
- Make cata xp in /pv be calculated on how many runs you have and shows master mode xp rates
- Added a config option to hide Dwarven Mines waypoints when already at the location - Lulonaut
diff --git a/build.gradle.kts b/build.gradle.kts
index e134387e..3ffaf61a 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,14 @@ 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")
+ 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,72 +100,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")
-}
-
-val moveResources by tasks.creating {
- doLast {
- ant.withGroovyBuilder {
- "move"(
- "file" to "$buildDir/resources/main",
- "todir" to "$buildDir/classes/java"
- )
- }
- }
- dependsOn(tasks.processResources)
-}
-
-tasks.classes { dependsOn(moveResources) }
+ 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"))
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
index abe0bdcf..6572431b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
@@ -895,12 +895,12 @@ public class NEUManager {
String clickcommand = item.get("clickcommand").getAsString();
switch (clickcommand.intern()) {
case "viewrecipe":
- displayGuiItemRecipe(internalName, null);
+ displayGuiItemRecipe(internalName);
break;
case "viewoption":
neu.sendChatMessage("/viewpotion " + internalName.split(";")[0].toLowerCase(Locale.ROOT));
}
- displayGuiItemRecipe(internalName, "");
+ displayGuiItemRecipe(internalName);
}
public void showRecipe(String internalName) {
@@ -990,16 +990,16 @@ public class NEUManager {
List<NeuRecipe> usages = getAvailableUsagesFor(internalName);
if (usages.isEmpty()) return false;
Minecraft.getMinecraft().displayGuiScreen(
- new GuiItemRecipe("Item Usages", usages, this));
+ new GuiItemRecipe(usages, this));
return true;
}
- public boolean displayGuiItemRecipe(String internalName, String text) {
+ public boolean displayGuiItemRecipe(String internalName) {
if (!recipesMap.containsKey(internalName)) return false;
List<NeuRecipe> recipes = getAvailableRecipesFor(internalName);
if (recipes.isEmpty()) return false;
Minecraft.getMinecraft().displayGuiScreen(
- new GuiItemRecipe(text != null ? text : "Item Recipe", recipes, this));
+ new GuiItemRecipe(recipes, this));
return true;
}
@@ -1010,7 +1010,7 @@ public class NEUManager {
public boolean failViewItem(String text) {
if (viewItemAttemptID != null && !viewItemAttemptID.isEmpty()) {
if (System.currentTimeMillis() - viewItemAttemptTime < 500) {
- return displayGuiItemRecipe(viewItemAttemptID, text);
+ return displayGuiItemRecipe(viewItemAttemptID);
}
}
return false;
@@ -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/NEUOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
index 7965abae..8d0955bb 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
@@ -1358,7 +1358,7 @@ public class NEUOverlay extends Gui {
}
if (getSortMode() == SORT_MODE_ALL) {
- return !internalname.matches(mobRegex);
+ return NotEnoughUpdates.INSTANCE.config.itemlist.alwaysShowMonsters || !internalname.matches(mobRegex);
} else if (getSortMode() == SORT_MODE_MOB) {
return internalname.matches(mobRegex);
} else if (getSortMode() == SORT_MODE_PET) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEURepoResourcePack.java b/src/main/java/io/github/moulberry/notenoughupdates/NEURepoResourcePack.java
new file mode 100644
index 00000000..2a5cda92
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEURepoResourcePack.java
@@ -0,0 +1,75 @@
+package io.github.moulberry.notenoughupdates;
+
+import com.google.gson.JsonObject;
+import net.minecraft.client.resources.IResourcePack;
+import net.minecraft.client.resources.data.IMetadataSection;
+import net.minecraft.client.resources.data.IMetadataSerializer;
+import net.minecraft.util.ResourceLocation;
+
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.util.HashSet;
+import java.util.Set;
+
+public class NEURepoResourcePack implements IResourcePack {
+
+ File repoLocation;
+ Set<String> resourceDomains = new HashSet<>();
+
+ public NEURepoResourcePack(File repoLocation, String domain) {
+ this.repoLocation = repoLocation;
+ resourceDomains.add(domain);
+ }
+
+ public boolean loadRepoLocation() {
+ if (repoLocation != null) return true;
+ NotEnoughUpdates instance = NotEnoughUpdates.INSTANCE;
+ if (instance == null) return false;
+ NEUManager manager = instance.manager;
+ if (manager == null) return false;
+ repoLocation = manager.repoLocation;
+ return repoLocation != null;
+ }
+
+ public File getFileForResource(ResourceLocation loc) {
+ if (repoLocation == null) {
+ if (!loadRepoLocation())
+ return null;
+ }
+ if (!"neurepo".equals(loc.getResourceDomain())) {
+ return null;
+ }
+ return new File(repoLocation, loc.getResourcePath());
+ }
+
+ @Override
+ public InputStream getInputStream(ResourceLocation resourceLocation) throws IOException {
+ return new BufferedInputStream(new FileInputStream(getFileForResource(resourceLocation)));
+ }
+
+ @Override
+ public boolean resourceExists(ResourceLocation resourceLocation) {
+ File file = getFileForResource(resourceLocation);
+ return file != null && file.exists();
+ }
+
+ @Override
+ public Set<String> getResourceDomains() {
+ return resourceDomains;
+ }
+
+ @Override
+ public <T extends IMetadataSection> T getPackMetadata(IMetadataSerializer iMetadataSerializer, String s) throws IOException {
+ return iMetadataSerializer.parseMetadataSection(s, new JsonObject());
+ }
+
+ @Override
+ public BufferedImage getPackImage() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getPackName() {
+ return "NEU Repo Resources";
+ }
+}
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/commands/EntityViewerCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/EntityViewerCommand.java
new file mode 100644
index 00000000..c7b1862e
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/EntityViewerCommand.java
@@ -0,0 +1,81 @@
+package io.github.moulberry.notenoughupdates.commands;
+
+import com.google.common.collect.Lists;
+import io.github.moulberry.notenoughupdates.miscfeatures.entityviewer.EntityViewer;
+import net.minecraft.client.Minecraft;
+import net.minecraft.command.CommandException;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.event.ClickEvent;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.ChatStyle;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedDeque;
+
+public class EntityViewerCommand extends ClientCommandBase {
+ public EntityViewerCommand() {
+ super("neushowentity");
+ MinecraftForge.EVENT_BUS.register(this);
+ }
+
+ @Override
+ public List<String> getCommandAliases() {
+ return Lists.newArrayList("neuentityviewer");
+ }
+
+ @Override
+ public String getCommandUsage(ICommandSender sender) {
+ return EnumChatFormatting.RED + "Use /neushowentity list";
+ }
+
+ public void showUsage(ICommandSender sender) {
+ sender.addChatMessage(new ChatComponentText(getCommandUsage(sender)));
+ }
+
+ private final Queue<EntityViewer> queuedGUIS = new ConcurrentLinkedDeque<>();
+
+ @SubscribeEvent
+ public void onTick(TickEvent event) {
+ if (Minecraft.getMinecraft().currentScreen == null) {
+ EntityViewer poll = queuedGUIS.poll();
+ if (poll == null) return;
+ Minecraft.getMinecraft().displayGuiScreen(poll);
+ }
+ }
+
+ @Override
+ public void processCommand(ICommandSender sender, String[] strings) throws CommandException {
+ if (strings.length == 0) {
+ showUsage(sender);
+ return;
+ }
+ if (strings[0].equals("list")) {
+ for (String label : EntityViewer.validEntities.keySet()) {
+ sender.addChatMessage(new ChatComponentText(EnumChatFormatting.BLUE + " " + label)
+ .setChatStyle(new ChatStyle().setChatClickEvent(
+ new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/neuentityviewer " + label))));
+ }
+ return;
+ }
+ EntityLivingBase entityLivingBase;
+ if (strings[0].startsWith("@")) {
+ ResourceLocation resourceLocation = new ResourceLocation(strings[0].substring(1));
+ entityLivingBase = EntityViewer.constructEntity(resourceLocation);
+ } else {
+ entityLivingBase = EntityViewer.constructEntity(strings[0], Arrays.copyOfRange(strings, 1, strings.length));
+ }
+ if (entityLivingBase == null) {
+ sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "Could not create that entity"));
+ return;
+ }
+ queuedGUIS.add(new EntityViewer(strings[0], entityLivingBase));
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java
index 53a7894b..27944c92 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java
@@ -1,4 +1,4 @@
-package io.github.moulberry.notenoughupdates.commands.dev;
+ package io.github.moulberry.notenoughupdates.commands.dev;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/AgeModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/AgeModifier.java
new file mode 100644
index 00000000..5884512f
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/AgeModifier.java
@@ -0,0 +1,30 @@
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.mixins.AccessorEntityAgeable;
+import io.github.moulberry.notenoughupdates.mixins.AccessorEntityArmorStand;
+import net.minecraft.entity.EntityAgeable;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.entity.monster.EntityZombie;
+
+public class AgeModifier extends EntityViewerModifier {
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ boolean baby = info.has("baby") && info.get("baby").getAsBoolean();
+ if (base instanceof EntityAgeable) {
+ ((AccessorEntityAgeable) base).setGrowingAgeDirect(baby ? -1 : 1);
+ return base;
+ }
+ if (base instanceof EntityZombie) {
+ ((EntityZombie) base).setChild(baby);
+ return base;
+ }
+ if (base instanceof EntityArmorStand) {
+ ((AccessorEntityArmorStand) base).setSmallDirect(baby);
+ return base;
+ }
+ System.out.println("Cannot apply age to a non ageable entity: " + base);
+ return null;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/ChargedModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/ChargedModifier.java
new file mode 100644
index 00000000..17dce66d
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/ChargedModifier.java
@@ -0,0 +1,17 @@
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonObject;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.monster.EntityCreeper;
+
+public class ChargedModifier extends EntityViewerModifier {
+
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ if (base instanceof EntityCreeper) {
+ base.getDataWatcher().updateObject(17, (byte) 1);
+ return base;
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewer.java
new file mode 100644
index 00000000..e9075e47
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewer.java
@@ -0,0 +1,177 @@
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.inventory.GuiInventory;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.boss.EntityDragon;
+import net.minecraft.entity.boss.EntityWither;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.entity.monster.*;
+import net.minecraft.entity.passive.*;
+import net.minecraft.util.ResourceLocation;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+public class EntityViewer extends GuiScreen {
+
+ public static Map<String, Supplier<? extends EntityLivingBase>> validEntities = new HashMap<String, Supplier<? extends EntityLivingBase>>() {{
+ put("Zombie", () -> new EntityZombie(null));
+ put("Chicken", () -> new EntityChicken(null));
+ put("Slime", () -> new EntitySlime(null));
+ put("Wolf", () -> new EntityWolf(null));
+ put("Skeleton", () -> new EntitySkeleton(null));
+ put("Creeper", () -> new EntityCreeper(null));
+ put("Ocelot", () -> new EntityOcelot(null));
+ put("Blaze", () -> new EntityBlaze(null));
+ put("Rabbit", () -> new EntityRabbit(null));
+ put("Sheep", () -> new EntitySheep(null));
+ put("Horse", () -> new EntityHorse(null));
+ put("Eisengolem", () -> new EntityIronGolem(null));
+ put("Silverfish", () -> new EntitySilverfish(null));
+ put("Witch", () -> new EntityWitch(null));
+ put("Endermite", () -> new EntityEndermite(null));
+ put("Snowman", () -> new EntitySnowman(null));
+ put("Villager", () -> new EntityVillager(null));
+ put("Guardian", () -> new EntityGuardian(null));
+ put("ArmorStand", () -> new EntityArmorStand(null));
+ put("Squid", () -> new EntitySquid(null));
+ put("Bat", () -> new EntityBat(null));
+ put("Spider", () -> new EntitySpider(null));
+ put("CaveSpider", () -> new EntityCaveSpider(null));
+ put("Pigman", () -> new EntityPigZombie(null));
+ put("Ghast", () -> new EntityGhast(null));
+ put("MagmaCube", () -> new EntityMagmaCube(null));
+ put("Wither", () -> new EntityWither(null));
+ put("Enderman", () -> new EntityEnderman(null));
+ put("Mooshroom", ()-> new EntityMooshroom(null));
+ put("WitherSkeleton", () -> {
+ EntitySkeleton skeleton = new EntitySkeleton(null);
+ skeleton.setSkeletonType(1);
+ return skeleton;
+ });
+ put("Cow", () -> new EntityCow(null));
+ put("Dragon", ()-> new EntityDragon(null));
+ put("Player", () -> new GUIClientPlayer());
+ }};
+
+ public static Map<String, EntityViewerModifier> validModifiers = new HashMap<String, EntityViewerModifier>() {{
+ put("playerdata", new SkinModifier());
+ put("equipment", new EquipmentModifier());
+ put("riding", new RidingModifier());
+ put("charged", new ChargedModifier());
+ put("witherdata", new WitherModifier());
+ put("invisible", new InvisibleModifier());
+ put("age", new AgeModifier());
+ put("horse", new HorseModifier());
+ }};
+
+ public int guiLeft = 0;
+ public int guiTop = 0;
+ public int xSize = 176;
+ public int ySize = 166;
+
+ private final String label;
+ private final EntityLivingBase entity;
+ private static final ResourceLocation BACKGROUND = new ResourceLocation("notenoughupdates", "textures/gui/entity_viewer.png");
+
+ public EntityViewer(String label, EntityLivingBase entity) {
+ this.label = label;
+ this.entity = entity;
+ }
+
+ public static EntityLivingBase constructEntity(ResourceLocation resourceLocation) {
+ Gson gson = NotEnoughUpdates.INSTANCE.manager.gson;
+ try (Reader is = new InputStreamReader(
+ Minecraft.getMinecraft().getResourceManager().getResource(resourceLocation).getInputStream(), StandardCharsets.UTF_8)) {
+ return constructEntity(gson.fromJson(is, JsonObject.class));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static EntityLivingBase constructEntity(JsonObject info) {
+ List<JsonObject> modifiers = info.has("modifiers") ?
+ StreamSupport.stream(info.get("modifiers").getAsJsonArray().spliterator(), false)
+ .map(JsonElement::getAsJsonObject).collect(Collectors.toList())
+ : Collections.emptyList();
+ return EntityViewer.constructEntity(info.get("entity").getAsString(), modifiers);
+ }
+
+ public static EntityLivingBase constructEntity(String string, String[] modifiers) {
+ Gson gson = NotEnoughUpdates.INSTANCE.manager.gson;
+ return constructEntity(string, Arrays.stream(modifiers).map(it -> gson.fromJson(it, JsonObject.class)).collect(Collectors.toList()));
+ }
+
+ public static EntityLivingBase constructEntity(String string, List<JsonObject> modifiers) {
+ Supplier<? extends EntityLivingBase> aClass = validEntities.get(string);
+ if (aClass == null) {
+ System.err.println("Could not find entity of type: " + string);
+ return null;
+ }
+ try {
+ EntityLivingBase entity = aClass.get();
+ for (JsonObject modifier : modifiers) {
+ String type = modifier.get("type").getAsString();
+ EntityViewerModifier entityViewerModifier = validModifiers.get(type);
+ entity = entityViewerModifier.applyModifier(entity, modifier);
+ if (entity == null) break;
+ }
+ return entity;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public void drawScreen(int mouseX, int mouseY, float partialTicks) {
+ drawDefaultBackground();
+ FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj;
+
+ this.guiLeft = (width - this.xSize) / 2;
+ this.guiTop = (height - this.ySize) / 2;
+
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(BACKGROUND);
+ drawTexturedModalRect(guiLeft, guiTop, 0, 0, this.xSize, this.ySize);
+
+
+ Utils.drawStringScaledMaxWidth(label, fontRenderer, guiLeft + 10, guiTop + 10, false, 100, 0xFF00FF);
+ renderEntity(entity, guiLeft + 90, guiTop + 75, mouseX, mouseY);
+ }
+
+ public static void renderEntity(EntityLivingBase entity, int posX, int posY, int mouseX, int mouseY) {
+ GlStateManager.color(1F, 1F, 1F, 1F);
+
+ int scale = 30;
+ float bottomOffset = 0F;
+ EntityLivingBase stack = entity;
+ while (true) {
+
+ stack.ticksExisted = Minecraft.getMinecraft().thePlayer.ticksExisted;
+ GuiInventory.drawEntityOnScreen(posX, (int) (posY - bottomOffset * scale), scale, posX - mouseX, (int) (posY - stack.getEyeHeight() * scale - mouseY), stack);
+ bottomOffset += stack.getMountedYOffset();
+ if (!(stack.riddenByEntity instanceof EntityLivingBase)) {
+ break;
+ }
+ stack = (EntityLivingBase) stack.riddenByEntity;
+ }
+
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewerModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewerModifier.java
new file mode 100644
index 00000000..bab6c354
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewerModifier.java
@@ -0,0 +1,8 @@
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonObject;
+import net.minecraft.entity.EntityLivingBase;
+
+public abstract class EntityViewerModifier {
+ public abstract EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info);
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EquipmentModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EquipmentModifier.java
new file mode 100644
index 00000000..3011e479
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EquipmentModifier.java
@@ -0,0 +1,72 @@
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NEUManager;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemArmor;
+import net.minecraft.item.ItemStack;
+
+public class EquipmentModifier extends EntityViewerModifier {
+
+ private ItemStack createItem(String item) {
+ NEUManager manager = NotEnoughUpdates.INSTANCE.manager;
+ String[] split = item.split("#");
+ if (split.length == 2) {
+ switch (split[0].intern()) {
+ case "LEATHER_LEGGINGS":
+ return coloredLeatherArmor(Items.leather_leggings, split[1]);
+ case "LEATHER_HELMET":
+ return coloredLeatherArmor(Items.leather_helmet, split[1]);
+ case "LEATHER_CHESTPLATE":
+ return coloredLeatherArmor(Items.leather_chestplate, split[1]);
+ case "LEATHER_BOOTS":
+ return coloredLeatherArmor(Items.leather_boots, split[1]);
+ default:
+ throw new RuntimeException("Unknown leather piece: " + item);
+ }
+ }
+ return manager.createItem(item);
+ }
+
+ private ItemStack coloredLeatherArmor(ItemArmor item, String colorHex) {
+ ItemStack is = new ItemStack(item);
+ item.setColor(is, Integer.parseInt(colorHex, 16));
+ return is;
+ }
+
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ if (info.has("hand"))
+ setCurrentItemOrArmor(base, 0, createItem(info.get("hand").getAsString()));
+ if (info.has("helmet"))
+ setCurrentItemOrArmor(base, 4, createItem(info.get("helmet").getAsString()));
+ if (info.has("chestplate"))
+ setCurrentItemOrArmor(base, 3, createItem(info.get("chestplate").getAsString()));
+ if (info.has("leggings"))
+ setCurrentItemOrArmor(base, 2, createItem(info.get("leggings").getAsString()));
+ if (info.has("feet"))
+ setCurrentItemOrArmor(base, 1, createItem(info.get("feet").getAsString()));
+ return base;
+ }
+
+ public void setCurrentItemOrArmor(EntityLivingBase entity, int slot, ItemStack itemStack) {
+ if (entity instanceof EntityPlayer) {
+ setPlayerCurrentItemOrArmor((EntityPlayer) entity, slot, itemStack);
+ } else {
+ entity.setCurrentItemOrArmor(slot, itemStack);
+ }
+ }
+
+ // Biscuit person needs to learn how to code and not fuck up valid vanilla behaviour
+ public static void setPlayerCurrentItemOrArmor(EntityPlayer player, int slot, ItemStack itemStack) {
+ if (slot == 0) {
+ player.inventory.mainInventory[player.inventory.currentItem] = itemStack;
+ } else {
+ player.inventory.armorInventory[slot - 1] = itemStack;
+ }
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/GUIClientPlayer.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/GUIClientPlayer.java
new file mode 100644
index 00000000..bbff2db1
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/GUIClientPlayer.java
@@ -0,0 +1,40 @@
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.mojang.authlib.GameProfile;
+import net.minecraft.client.entity.AbstractClientPlayer;
+import net.minecraft.client.network.NetworkPlayerInfo;
+import net.minecraft.client.resources.DefaultPlayerSkin;
+import net.minecraft.util.ResourceLocation;
+
+import java.util.UUID;
+
+public class GUIClientPlayer extends AbstractClientPlayer {
+ public GUIClientPlayer() {
+ super(null, new GameProfile(UUID.randomUUID(), "GuiPlayer"));
+ }
+
+ ResourceLocation overrideSkin = DefaultPlayerSkin.getDefaultSkinLegacy();
+ ResourceLocation overrideCape = null;
+ boolean overrideIsSlim = false;
+ NetworkPlayerInfo playerInfo = new NetworkPlayerInfo(this.getGameProfile()) {
+ @Override
+ public String getSkinType() {
+ return overrideIsSlim ? "slim" : "default";
+ }
+
+ @Override
+ public ResourceLocation getLocationSkin() {
+ return overrideSkin;
+ }
+
+ @Override
+ public ResourceLocation getLocationCape() {
+ return overrideCape;
+ }
+ };
+
+ @Override
+ protected NetworkPlayerInfo getPlayerInfo() {
+ return playerInfo;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/HorseModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/HorseModifier.java
new file mode 100644
index 00000000..7fd2dadd
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/HorseModifier.java
@@ -0,0 +1,66 @@
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.passive.EntityHorse;
+import net.minecraft.init.Items;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+
+public class HorseModifier extends EntityViewerModifier {
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ if (!(base instanceof EntityHorse))
+ return null;
+ EntityHorse horse = (EntityHorse) base;
+ if (info.has("kind")) {
+ String type = info.get("kind").getAsString().intern();
+ switch (type) {
+ case "skeleton":
+ horse.setHorseType(4);
+ break;
+ case "zombie":
+ horse.setHorseType(3);
+ break;
+ case "mule":
+ horse.setHorseType(2);
+ break;
+ case "donkey":
+ horse.setHorseType(1);
+ break;
+ case "horse":
+ horse.setHorseType(0);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown horse type: " + type);
+ }
+ }
+ if (info.has("armor")) {
+ JsonElement el = info.get("armor");
+ if (el.isJsonNull()) {
+ horse.setHorseArmorStack(null);
+ } else {
+ Item item;
+ switch (el.getAsString().intern()) {
+ case "iron":
+ item = Items.iron_horse_armor;
+ break;
+ case "golden":
+ item = Items.golden_horse_armor;
+ break;
+ case "diamond":
+ item = Items.diamond_horse_armor;
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown horse armor: " + el.getAsString());
+ }
+ horse.setHorseArmorStack(new ItemStack(item));
+ }
+ }
+ if (info.has("saddled")) {
+ horse.setHorseSaddled(info.get("saddled").getAsBoolean());
+ }
+ return horse;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/InvisibleModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/InvisibleModifier.java
new file mode 100644
index 00000000..c2138b3f
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/InvisibleModifier.java
@@ -0,0 +1,12 @@
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonObject;
+import net.minecraft.entity.EntityLivingBase;
+
+public class InvisibleModifier extends EntityViewerModifier {
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ base.setInvisible(!info.has("invisible") || info.get("invisible").getAsBoolean());
+ return base;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/RidingModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/RidingModifier.java
new file mode 100644
index 00000000..9879542a
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/RidingModifier.java
@@ -0,0 +1,14 @@
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonObject;
+import net.minecraft.entity.EntityLivingBase;
+
+public class RidingModifier extends EntityViewerModifier {
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ EntityLivingBase newEntity = EntityViewer.constructEntity(info);
+ if (newEntity == null) return null;
+ newEntity.mountEntity(base);
+ return base;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/SkinModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/SkinModifier.java
new file mode 100644
index 00000000..55e8a432
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/SkinModifier.java
@@ -0,0 +1,46 @@
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.player.EnumPlayerModelParts;
+import net.minecraft.util.ResourceLocation;
+
+import java.util.Map;
+
+public class SkinModifier extends EntityViewerModifier {
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ if (base instanceof GUIClientPlayer) {
+ GUIClientPlayer player = (GUIClientPlayer) base;
+ if (info.has("cape")) {
+ player.overrideCape = new ResourceLocation(info.get("cape").getAsString());
+ }
+ if (info.has("skin")) {
+ player.overrideSkin = new ResourceLocation(info.get("skin").getAsString());
+ }
+ if (info.has("slim")) {
+ player.overrideIsSlim = info.get("slim").getAsBoolean();
+ }
+ if (info.has("parts")) {
+ JsonElement parts = info.get("parts");
+ byte partBitField = player.getDataWatcher().getWatchableObjectByte(10);
+ if (parts.isJsonPrimitive() && parts.getAsJsonPrimitive().isBoolean()) {
+ partBitField = parts.getAsBoolean() ? (byte) -1 : 0;
+ } else {
+ JsonObject obj = parts.getAsJsonObject();
+ for (Map.Entry<String, JsonElement> part : obj.entrySet()) {
+ EnumPlayerModelParts modelPart = EnumPlayerModelParts.valueOf(part.getKey());
+ if (part.getValue().getAsBoolean()) {
+ partBitField |= modelPart.getPartMask();
+ } else {
+ partBitField &= ~modelPart.getPartMask();
+ }
+ }
+ }
+ player.getDataWatcher().updateObject(10, partBitField);
+ }
+ }
+ return base;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/WitherModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/WitherModifier.java
new file mode 100644
index 00000000..c5580f17
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/WitherModifier.java
@@ -0,0 +1,29 @@
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonObject;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.boss.EntityWither;
+
+public class WitherModifier extends EntityViewerModifier {
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ if (!(base instanceof EntityWither))
+ return null;
+ EntityWither wither = (EntityWither) base;
+ if (info.has("tiny")) {
+ if (info.get("tiny").getAsBoolean()) {
+ wither.setInvulTime(800);
+ } else {
+ wither.setInvulTime(0);
+ }
+ }
+ if (info.has("armored")) {
+ if (info.get("armored").getAsBoolean()) {
+ wither.setHealth(1);
+ } else {
+ wither.setHealth(wither.getMaxHealth());
+ }
+ }
+ return base;
+ }
+}
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 63a4d6d8..be9ce6c7 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
import io.github.moulberry.notenoughupdates.NEUManager;
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.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
@@ -12,6 +13,7 @@ import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.MathHelper;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.input.Keyboard;
@@ -20,48 +22,65 @@ import org.lwjgl.opengl.GL11;
import java.awt.*;
import java.io.IOException;
-import java.util.ArrayList;
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 = 63;
- 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 = 69;
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 = 142;
+ public static final int HOTBAR_SLOT_Y = 197;
public static final int PLAYER_INVENTORY_X = 8;
- public static final int PLAYER_INVENTORY_Y = 84;
+ 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 List<NeuRecipe> craftingRecipes;
+ 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 = 166;
+ public int ySize = 222;
- public GuiItemRecipe(String title, List<NeuRecipe> craftingRecipes, NEUManager manager) {
- this.craftingRecipes = craftingRecipes;
+ public GuiItemRecipe(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() {
- currentIndex = MathHelper.clamp_int(currentIndex, 0, craftingRecipes.size());
- return craftingRecipes.get(currentIndex);
+ 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) {
@@ -90,17 +109,19 @@ public class GuiItemRecipe extends GuiScreen {
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));
+ Utils.drawItemStack(slot.getItemStack(), slot.getX(this), slot.getY(this), true);
}
- if (craftingRecipes.size() > 1) drawArrows(mouseX, mouseY);
+ drawArrows(currentRecipe, mouseX, mouseY);
Utils.drawStringScaledMaxWidth(
- title,
+ currentRecipe.getTitle(),
fontRendererObj,
guiLeft + TITLE_X,
guiTop + TITLE_Y,
@@ -126,42 +147,104 @@ public class GuiItemRecipe extends GuiScreen {
}
}
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 drawArrows(int mouseX, int mouseY) {
+ 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
+ );
+ Utils.drawItemStack(recipeType.getIcon(), tabPosX + 7, tabPosY + 7);
+ }
+ }
+
+ 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,
- BUTTON_POSITION_LEFT_X,
- BUTTON_POSITION_Y,
+ buttonPositionLeftX,
+ buttonPositionY,
BUTTON_WIDTH,
BUTTON_HEIGHT
);
boolean rightSelected = isWithinRect(
mouseX - guiLeft,
mouseY - guiTop,
- BUTTON_POSITION_RIGHT_X,
- BUTTON_POSITION_Y,
+ buttonPositionRightX,
+ buttonPositionY,
BUTTON_WIDTH,
BUTTON_HEIGHT
);
-
Minecraft.getMinecraft().getTextureManager().bindTexture(resourcePacksTexture);
- 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
- );
- 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
- );
+ 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) + "/" + craftingRecipes.size();
+ String selectedPage = (currentIndex + 1) + "/" + recipeCount;
Utils.drawStringCenteredScaledMaxWidth(selectedPage, fontRendererObj,
- guiLeft + PAGE_STRING_X, guiTop + PAGE_STRING_Y, false, 24, Color.BLACK.getRGB()
+ guiLeft + pageStringX, guiTop + pageStringY, false, 24, Color.BLACK.getRGB()
);
}
@@ -196,12 +279,12 @@ public class GuiItemRecipe extends GuiScreen {
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()) { // TODO: rework this so it doesnt skip recipe chains
- manager.displayGuiItemRecipe(manager.getInternalNameForItem(itemStack), "");
+ if (keyPressed == manager.keybindViewRecipe.getKeyCode()) {
+ manager.displayGuiItemRecipe(manager.getInternalNameForItem(itemStack));
} else if (keyPressed == manager.keybindViewUsages.getKeyCode()) {
manager.displayGuiItemUsages(manager.getInternalNameForItem(itemStack));
}
@@ -212,16 +295,22 @@ public class GuiItemRecipe extends GuiScreen {
@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,
- BUTTON_POSITION_LEFT_X,
- BUTTON_POSITION_Y,
+ buttonPositionLeftX,
+ buttonPositionY,
BUTTON_WIDTH,
BUTTON_HEIGHT
- )) {
- currentIndex = currentIndex == 0 ? 0 : currentIndex - 1;
+ ) &&
+ currentIndex > 0) {
+ currentIndex = currentIndex - 1;
Utils.playPressSound();
return;
}
@@ -229,21 +318,37 @@ public class GuiItemRecipe extends GuiScreen {
if (isWithinRect(
mouseX - guiLeft,
mouseY - guiTop,
- BUTTON_POSITION_RIGHT_X,
- BUTTON_POSITION_Y,
+ buttonPositionRightX,
+ buttonPositionY,
BUTTON_WIDTH,
BUTTON_HEIGHT
- )) {
- currentIndex = currentIndex == craftingRecipes.size() - 1 ? currentIndex : currentIndex + 1;
+ ) &&
+ 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), "");
+ manager.displayGuiItemRecipe(manager.getInternalNameForItem(itemStack));
} else if (mouseButton == 1) {
manager.displayGuiItemUsages(manager.getInternalNameForItem(itemStack));
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityAgeable.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityAgeable.java
new file mode 100644
index 00000000..9228f93d
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityAgeable.java
@@ -0,0 +1,12 @@
+package io.github.moulberry.notenoughupdates.mixins;
+
+import net.minecraft.entity.EntityAgeable;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+@Mixin(EntityAgeable.class)
+public interface AccessorEntityAgeable {
+ @Accessor(value = "growingAge")
+ void setGrowingAgeDirect(int newValue);
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityArmorStand.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityArmorStand.java
new file mode 100644
index 00000000..b6a3ca6e
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityArmorStand.java
@@ -0,0 +1,12 @@
+package io.github.moulberry.notenoughupdates.mixins;
+
+import net.minecraft.entity.item.EntityArmorStand;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Invoker;
+
+@Mixin(EntityArmorStand.class)
+public interface AccessorEntityArmorStand {
+ @Invoker(value = "setSmall")
+ void setSmallDirect(boolean isSmall);
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorMinecraft.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorMinecraft.java
new file mode 100644
index 00000000..0277a18b
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorMinecraft.java
@@ -0,0 +1,14 @@
+package io.github.moulberry.notenoughupdates.mixins;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.resources.IResourcePack;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+import java.util.List;
+
+@Mixin(Minecraft.class)
+public interface AccessorMinecraft {
+ @Accessor(value = "defaultResourcePacks")
+ List<IResourcePack> onGetDefaultResourcePacks();
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityAgeable.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityAgeable.java
index b8f07b53..801b9041 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityAgeable.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityAgeable.java
@@ -3,6 +3,7 @@ package io.github.moulberry.notenoughupdates.mixins;
import net.minecraft.entity.EntityAgeable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityHorse.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityHorse.java
new file mode 100644
index 00000000..fe88922e
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityHorse.java
@@ -0,0 +1,17 @@
+package io.github.moulberry.notenoughupdates.mixins;
+
+import net.minecraft.entity.passive.EntityHorse;
+import net.minecraft.world.World;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+@Mixin(EntityHorse.class)
+public class MixinEntityHorse {
+ @Redirect(method = "updateHorseSlots", at = @At(value = "FIELD", target = "Lnet/minecraft/world/World;isRemote:Z"))
+ public boolean onUpdateHorseSlots(World instance) {
+ if (instance == null)
+ return true;
+ return instance.isRemote;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntitySkeleton.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntitySkeleton.java
new file mode 100644
index 00000000..54fe53f3
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntitySkeleton.java
@@ -0,0 +1,17 @@
+package io.github.moulberry.notenoughupdates.mixins;
+
+import net.minecraft.entity.monster.EntitySkeleton;
+import net.minecraft.world.World;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+@Mixin(EntitySkeleton.class)
+public class MixinEntitySkeleton {
+ @Redirect(method = "setCurrentItemOrArmor", at = @At(value = "FIELD", target = "Lnet/minecraft/world/World;isRemote:Z"))
+ public boolean onSetCurrentItemOrArmor(World instance) {
+ if (instance == null)
+ return true;
+ return instance.isRemote;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java b/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java
index 2fba6e80..68449ba8 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java
@@ -150,6 +150,10 @@ public class NEUConfig extends Config {
return;
case 20:
FairySouls.getInstance().setTrackFairySouls(NotEnoughUpdates.INSTANCE.config.misc.trackFairySouls);
+ return;
+ case 21:
+ NotEnoughUpdates.INSTANCE.overlay.updateSearch();
+ return;
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Itemlist.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Itemlist.java
index 3e5a4cdf..db154c24 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Itemlist.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Itemlist.java
@@ -107,4 +107,14 @@ public class Itemlist {
)
@ConfigEditorColour
public String backgroundColour = "15:6:0:0:255";
+
+ @Expose
+ @ConfigOption(
+ name = "Always show Monsters",
+ desc = "Always show Monster Items in the item list"
+ )
+ @ConfigEditorBoolean(
+ runnableId = 21
+ )
+ public boolean alwaysShowMonsters = false;
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
index 11c10ea0..691ccaae 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
@@ -2222,7 +2222,7 @@ public class GuiProfileViewer extends GuiScreen {
}
Panorama.drawPanorama(-backgroundRotation, guiLeft + 212, guiTop + 44, 81, 108, -0.37f, 0.6f,
- getPanoramasForLocation(location == null ? "dynamic" : location, panoramaIdentifier)
+ Panorama.getPanoramasForLocation(location == null ? "dynamic" : location, panoramaIdentifier)
);
Minecraft.getMinecraft().getTextureManager().bindTexture(pv_pets);
@@ -3114,38 +3114,6 @@ public class GuiProfileViewer extends GuiScreen {
return entityPlayer;
}
- public ResourceLocation[] getPanoramasForLocation(String location, String identifier) {
- if (panoramasMap.containsKey(location + identifier)) return panoramasMap.get(location + identifier);
- try {
- ResourceLocation[] panoramasArray = new ResourceLocation[6];
- for (int i = 0; i < 6; i++) {
- panoramasArray[i] =
- new ResourceLocation("notenoughupdates:panoramas/" + location + "_" + identifier + "/panorama_" + i + ".jpg");
- Minecraft.getMinecraft().getResourceManager().getResource(panoramasArray[i]);
- }
- panoramasMap.put(location + identifier, panoramasArray);
- return panoramasArray;
- } catch (IOException e) {
- try {
- ResourceLocation[] panoramasArray = new ResourceLocation[6];
- for (int i = 0; i < 6; i++) {
- panoramasArray[i] =
- new ResourceLocation("notenoughupdates:panoramas/" + location + "/panorama_" + i + ".jpg");
- Minecraft.getMinecraft().getResourceManager().getResource(panoramasArray[i]);
- }
- panoramasMap.put(location + identifier, panoramasArray);
- return panoramasArray;
- } catch (IOException e2) {
- ResourceLocation[] panoramasArray = new ResourceLocation[6];
- for (int i = 0; i < 6; i++) {
- panoramasArray[i] = new ResourceLocation("notenoughupdates:panoramas/unknown/panorama_" + i + ".jpg");
- }
- panoramasMap.put(location + identifier, panoramasArray);
- return panoramasArray;
- }
- }
- }
-
private void drawExtraPage(int mouseX, int mouseY, float partialTicks) {
FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
@@ -4717,7 +4685,7 @@ public class GuiProfileViewer extends GuiScreen {
}
Panorama.drawPanorama(-backgroundRotation - extraRotation, guiLeft + 23, guiTop + 44, 81, 108, 0.37f, 0.8f,
- getPanoramasForLocation(location == null ? "unknown" : location, panoramaIdentifier)
+ Panorama.getPanoramasForLocation(location == null ? "unknown" : location, panoramaIdentifier)
);
Minecraft.getMinecraft().getTextureManager().bindTexture(pv_basic);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/Panorama.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/Panorama.java
index ac117bc2..a2d297f5 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/Panorama.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/Panorama.java
@@ -15,6 +15,9 @@ import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.Project;
+import java.io.IOException;
+import java.util.HashMap;
+
public class Panorama {
private static final TexLoc tl = new TexLoc(97, 19, Keyboard.KEY_P);
private static final TexLoc tl2 = new TexLoc(37, 80, Keyboard.KEY_L);
@@ -24,6 +27,41 @@ public class Panorama {
private static int lastWidth = 0;
private static int lastHeight = 0;
+
+ private static final HashMap<String, ResourceLocation[]> panoramasMap = new HashMap<>();
+
+ public static synchronized ResourceLocation[] getPanoramasForLocation(String location, String identifier) {
+ if (panoramasMap.containsKey(location + identifier)) return panoramasMap.get(location + identifier);
+ try {
+ ResourceLocation[] panoramasArray = new ResourceLocation[6];
+ for (int i = 0; i < 6; i++) {
+ panoramasArray[i] =
+ new ResourceLocation("notenoughupdates:panoramas/" + location + "_" + identifier + "/panorama_" + i + ".jpg");
+ Minecraft.getMinecraft().getResourceManager().getResource(panoramasArray[i]);
+ }
+ panoramasMap.put(location + identifier, panoramasArray);
+ return panoramasArray;
+ } catch (IOException e) {
+ try {
+ ResourceLocation[] panoramasArray = new ResourceLocation[6];
+ for (int i = 0; i < 6; i++) {
+ panoramasArray[i] =
+ new ResourceLocation("notenoughupdates:panoramas/" + location + "/panorama_" + i + ".jpg");
+ Minecraft.getMinecraft().getResourceManager().getResource(panoramasArray[i]);
+ }
+ panoramasMap.put(location + identifier, panoramasArray);
+ return panoramasArray;
+ } catch (IOException e2) {
+ ResourceLocation[] panoramasArray = new ResourceLocation[6];
+ for (int i = 0; i < 6; i++) {
+ panoramasArray[i] = new ResourceLocation("notenoughupdates:panoramas/unknown/panorama_" + i + ".jpg");
+ }
+ panoramasMap.put(location + identifier, panoramasArray);
+ return panoramasArray;
+ }
+ }
+ }
+
public static void drawPanorama(
float angle,
int x,
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingOverlay.java
index d0b464f6..9d305e1d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingOverlay.java
@@ -103,7 +103,7 @@ public class CraftingOverlay {
if (Keyboard.getEventKey() == Keyboard.KEY_R)
manager.showRecipe(recipeIngredient.getInternalItemId());
if (Keyboard.getEventKey() == Keyboard.KEY_U)
- manager.displayGuiItemRecipe(recipeIngredient.getInternalItemId(), null);
+ manager.displayGuiItemRecipe(recipeIngredient.getInternalItemId());
}
});
});
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingRecipe.java
index 576cbbd4..79f349fa 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingRecipe.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingRecipe.java
@@ -17,130 +17,135 @@ import java.util.Set;
public class CraftingRecipe implements NeuRecipe {
- public static final ResourceLocation BACKGROUND = new ResourceLocation("textures/gui/container/crafting_table.png");
-
- private static final int EXTRA_STRING_X = 132;
- private static final int EXTRA_STRING_Y = 25;
-
- private final NEUManager manager;
- private final Ingredient[] inputs;
- private final String extraText;
- private final Ingredient outputIngredient;
- private List<RecipeSlot> slots;
-
- public CraftingRecipe(NEUManager manager, Ingredient[] inputs, Ingredient output, String extra) {
- this.manager = manager;
- this.inputs = inputs;
- this.outputIngredient = output;
- this.extraText = extra;
- if (inputs.length != 9)
- throw new IllegalArgumentException("Cannot construct crafting recipe with non standard crafting grid size");
- }
-
- @Override
- public Set<Ingredient> getIngredients() {
- Set<Ingredient> ingredients = Sets.newHashSet(inputs);
- ingredients.remove(null);
- return ingredients;
- }
-
- @Override
- public boolean hasVariableCost() {
- return false;
- }
-
- @Override
- public Set<Ingredient> getOutputs() {
- return Collections.singleton(getOutput());
- }
-
- public Ingredient getOutput() {
- return outputIngredient;
- }
-
- public Ingredient[] getInputs() {
- return inputs;
- }
-
- @Override
- public List<RecipeSlot> getSlots() {
- if (slots != null) return slots;
- slots = new ArrayList<>();
- for (int x = 0; x < 3; x++) {
- for (int y = 0; y < 3; y++) {
- Ingredient input = inputs[x + y * 3];
- if (input == null) continue;
- ItemStack item = input.getItemStack();
- if (item == null) continue;
- slots.add(new RecipeSlot(30 + x * GuiItemRecipe.SLOT_SPACING, 17 + y * GuiItemRecipe.SLOT_SPACING, item));
- }
- }
- slots.add(new RecipeSlot(124, 35, outputIngredient.getItemStack()));
- return slots;
- }
-
- public String getCraftText() {
- return extraText;
- }
-
- @Override
- public ResourceLocation getBackground() {
- return BACKGROUND;
- }
-
- @Override
- public void drawExtraInfo(GuiItemRecipe gui, int mouseX, int mouseY) {
- FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj;
-
- String craftingText = getCraftText();
- if (craftingText != null)
- Utils.drawStringCenteredScaledMaxWidth(craftingText, fontRenderer,
- gui.guiLeft + EXTRA_STRING_X, gui.guiTop + EXTRA_STRING_Y, false, 75, 0x404040
- );
- }
-
- @Override
- public JsonObject serialize() {
- JsonObject object = new JsonObject();
- object.addProperty("type", "crafting");
- object.addProperty("count", outputIngredient.getCount());
- object.addProperty("overrideOutputId", outputIngredient.getInternalItemId());
- for (int i = 0; i < 9; i++) {
- Ingredient ingredient = inputs[i];
- if (ingredient == null) continue;
- String[] x = {"1", "2", "3"};
- String[] y = {"A", "B", "C"};
- String name = x[i / 3] + y[i % 3];
- object.addProperty(name, ingredient.serialize());
- }
- if (extraText != null)
- object.addProperty("crafttext", extraText);
- return object;
- }
-
- public static CraftingRecipe parseCraftingRecipe(NEUManager manager, JsonObject recipe, JsonObject outputItem) {
- Ingredient[] craftMatrix = new Ingredient[9];
-
- String[] x = {"1", "2", "3"};
- String[] y = {"A", "B", "C"};
- for (int i = 0; i < 9; i++) {
- String name = y[i / 3] + x[i % 3];
- if (!recipe.has(name)) continue;
- String item = recipe.get(name).getAsString();
- if (item == null || item.isEmpty()) continue;
- craftMatrix[i] = new Ingredient(manager, item);
- }
- int resultCount = 1;
- if (recipe.has("count"))
- resultCount = recipe.get("count").getAsInt();
- String extra = null;
- if (outputItem.has("crafttext"))
- extra = outputItem.get("crafttext").getAsString();
- if (recipe.has("crafttext"))
- extra = recipe.get("crafttext").getAsString();
- String outputItemId = outputItem.get("internalname").getAsString();
- if (recipe.has("overrideOutputId"))
- outputItemId = recipe.get("overrideOutputId").getAsString();
- return new CraftingRecipe(manager, craftMatrix, new Ingredient(manager, outputItemId, resultCount), extra);
- }
+ public static final ResourceLocation BACKGROUND = new ResourceLocation("notenoughupdates","textures/gui/crafting_table_tall.png");
+
+ private static final int EXTRA_STRING_X = 132;
+ private static final int EXTRA_STRING_Y = 50;
+
+ private final NEUManager manager;
+ private final Ingredient[] inputs;
+ private final String extraText;
+ private final Ingredient outputIngredient;
+ private List<RecipeSlot> slots;
+
+ public CraftingRecipe(NEUManager manager, Ingredient[] inputs, Ingredient output, String extra) {
+ this.manager = manager;
+ this.inputs = inputs;
+ this.outputIngredient = output;
+ this.extraText = extra;
+ if (inputs.length != 9)
+ throw new IllegalArgumentException("Cannot construct crafting recipe with non standard crafting grid size");
+ }
+
+ @Override
+ public Set<Ingredient> getIngredients() {
+ Set<Ingredient> ingredients = Sets.newHashSet(inputs);
+ ingredients.remove(null);
+ return ingredients;
+ }
+
+ @Override
+ public RecipeType getType() {
+ return RecipeType.CRAFTING;
+ }
+
+ @Override
+ public boolean hasVariableCost() {
+ return false;
+ }
+
+ @Override
+ public Set<Ingredient> getOutputs() {
+ return Collections.singleton(getOutput());
+ }
+
+ public Ingredient getOutput() {
+ return outputIngredient;
+ }
+
+ public Ingredient[] getInputs() {
+ return inputs;
+ }
+
+
+ @Override
+ public List<RecipeSlot> getSlots() {
+ if (slots != null) return slots;
+ slots = new ArrayList<>();
+ for (int x = 0; x < 3; x++) {
+ for (int y = 0; y < 3; y++) {
+ Ingredient input = inputs[x + y * 3];
+ if (input == null) continue;
+ ItemStack item = input.getItemStack();
+ if (item == null) continue;
+ slots.add(new RecipeSlot(30 + x * GuiItemRecipe.SLOT_SPACING, 48 + y * GuiItemRecipe.SLOT_SPACING, item));
+ }
+ }
+ slots.add(new RecipeSlot(124, 66, outputIngredient.getItemStack()));
+ return slots;
+ }
+
+ public String getCraftText() {
+ return extraText;
+ }
+
+ @Override
+ public ResourceLocation getBackground() {
+ return BACKGROUND;
+ }
+
+ @Override
+ public void drawExtraInfo(GuiItemRecipe gui, int mouseX, int mouseY) {
+ FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj;
+
+ String craftingText = getCraftText();
+ if (craftingText != null)
+ Utils.drawStringCenteredScaledMaxWidth(craftingText, fontRenderer,
+ gui.guiLeft + EXTRA_STRING_X, gui.guiTop + EXTRA_STRING_Y, false, 75, 0x404040);
+ }
+
+ @Override
+ public JsonObject serialize() {
+ JsonObject object = new JsonObject();
+ object.addProperty("type", "crafting");
+ object.addProperty("count", outputIngredient.getCount());
+ object.addProperty("overrideOutputId", outputIngredient.getInternalItemId());
+ for (int i = 0; i < 9; i++) {
+ Ingredient ingredient = inputs[i];
+ if (ingredient == null) continue;
+ String[] x = {"1", "2", "3"};
+ String[] y = {"A", "B", "C"};
+ String name = x[i / 3] + y[i % 3];
+ object.addProperty(name, ingredient.serialize());
+ }
+ if(extraText != null)
+ object.addProperty("crafttext", extraText);
+ return object;
+ }
+
+ public static CraftingRecipe parseCraftingRecipe(NEUManager manager, JsonObject recipe, JsonObject outputItem) {
+ Ingredient[] craftMatrix = new Ingredient[9];
+
+ String[] x = {"1", "2", "3"};
+ String[] y = {"A", "B", "C"};
+ for (int i = 0; i < 9; i++) {
+ String name = y[i / 3] + x[i % 3];
+ if (!recipe.has(name)) continue;
+ String item = recipe.get(name).getAsString();
+ if (item == null || item.isEmpty()) continue;
+ craftMatrix[i] = new Ingredient(manager, item);
+ }
+ int resultCount = 1;
+ if (recipe.has("count"))
+ resultCount = recipe.get("count").getAsInt();
+ String extra = null;
+ if (outputItem.has("crafttext"))
+ extra = outputItem.get("crafttext").getAsString();
+ if (recipe.has("crafttext"))
+ extra = recipe.get("crafttext").getAsString();
+ String outputItemId = outputItem.get("internalname").getAsString();
+ if (recipe.has("overrideOutputId"))
+ outputItemId = recipe.get("overrideOutputId").getAsString();
+ return new CraftingRecipe(manager, craftMatrix, new Ingredient(manager, outputItemId, resultCount), extra);
+ }
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/ForgeRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/ForgeRecipe.java
index c971d82a..7847b0b4 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/ForgeRecipe.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/ForgeRecipe.java
@@ -19,238 +19,212 @@ import java.util.*;
public class ForgeRecipe implements NeuRecipe {
- private static final ResourceLocation BACKGROUND =
- new ResourceLocation("notenoughupdates", "textures/gui/forge_recipe.png");
-
- private static final int SLOT_IMAGE_U = 176;
- private static final int SLOT_IMAGE_V = 0;
- private static final int SLOT_IMAGE_SIZE = 18;
- private static final int SLOT_PADDING = 1;
- private static final int EXTRA_INFO_MAX_WIDTH = 75;
- public static final int EXTRA_INFO_X = 132;
- public static final int EXTRA_INFO_Y = 25;
-
- public enum ForgeType {
- REFINING, ITEM_FORGING
- }
-
- private final NEUManager manager;
- private final List<Ingredient> inputs;
- private final Ingredient output;
- private final int hotmLevel;
- private final int timeInSeconds; // TODO: quick forge
- private List<RecipeSlot> slots;
-
- public ForgeRecipe(
- NEUManager manager,
- List<Ingredient> inputs,
- Ingredient output,
- int durationInSeconds,
- int hotmLevel
- ) {
- this.manager = manager;
- this.inputs = inputs;
- this.output = output;
- this.hotmLevel = hotmLevel;
- this.timeInSeconds = durationInSeconds;
- }
-
- public List<Ingredient> getInputs() {
- return inputs;
- }
-
- public Ingredient getOutput() {
- return output;
- }
-
- public int getHotmLevel() {
- return hotmLevel;
- }
-
- public int getTimeInSeconds() {
- return timeInSeconds;
- }
-
- @Override
- public ResourceLocation getBackground() {
- return BACKGROUND;
- }
-
- @Override
- public Set<Ingredient> getIngredients() {
- return Sets.newHashSet(inputs);
- }
-
- @Override
- public boolean hasVariableCost() {
- return false;
- }
-
- @Override
- public Set<Ingredient> getOutputs() {
- return Collections.singleton(output);
- }
-
- @Override
- public List<RecipeSlot> getSlots() {
- if (slots != null) return slots;
- slots = new ArrayList<>();
- for (int i = 0; i < inputs.size(); i++) {
- Ingredient input = inputs.get(i);
- ItemStack itemStack = input.getItemStack();
- if (itemStack == null) continue;
- int[] slotCoordinates = getSlotCoordinates(i, inputs.size());
- slots.add(new RecipeSlot(slotCoordinates[0], slotCoordinates[1], itemStack));
- }
- slots.add(new RecipeSlot(124, 35, output.getItemStack()));
- return slots;
- }
-
- @Override
- public void drawExtraBackground(GuiItemRecipe gui, int mouseX, int mouseY) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(BACKGROUND);
- for (int i = 0; i < inputs.size(); i++) {
- int[] slotCoordinates = getSlotCoordinates(i, inputs.size());
- gui.drawTexturedModalRect(
- gui.guiLeft + slotCoordinates[0] - SLOT_PADDING, gui.guiTop + slotCoordinates[1] - SLOT_PADDING,
- SLOT_IMAGE_U, SLOT_IMAGE_V,
- SLOT_IMAGE_SIZE, SLOT_IMAGE_SIZE
- );
- }
- }
-
- @Override
- public void drawExtraInfo(GuiItemRecipe gui, int mouseX, int mouseY) {
- FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj;
- if (timeInSeconds > 0)
- Utils.drawStringCenteredScaledMaxWidth(
- formatDuration(timeInSeconds),
- fontRenderer,
- gui.guiLeft + EXTRA_INFO_X,
- gui.guiTop + EXTRA_INFO_Y,
- false,
- EXTRA_INFO_MAX_WIDTH,
- 0xff00ff
- );
- }
-
- @Override
- public void drawHoverInformation(GuiItemRecipe gui, int mouseX, int mouseY) {
- manager.hotm.getInformationOnCurrentProfile().ifPresent(hotmTree -> {
- if (timeInSeconds > 0 && gui.isWithinRect(
- mouseX, mouseY,
- gui.guiLeft + EXTRA_INFO_X - EXTRA_INFO_MAX_WIDTH / 2,
- gui.guiTop + EXTRA_INFO_Y - 8,
- EXTRA_INFO_MAX_WIDTH, 16
- )) {
- int qf = hotmTree.getLevel("forge_time");
- int reducedTime = getReducedTime(qf);
- if (qf > 0) {
-
- Utils.drawHoveringText(
- Arrays.asList(
- EnumChatFormatting.YELLOW + formatDuration(reducedTime) + " with Quick Forge (Level " + qf + ")"),
- mouseX,
- mouseY,
- gui.width,
- gui.height,
- 500,
- Minecraft.getMinecraft().fontRendererObj
- );
- }
- }
- });
- }
-
- public int getReducedTime(int quickForgeUpgradeLevel) {
- return HotmInformation.getQuickForgeMultiplier(quickForgeUpgradeLevel) * timeInSeconds / 1000;
- }
-
- @Override
- public JsonObject serialize() {
- JsonObject object = new JsonObject();
- JsonArray ingredients = new JsonArray();
- for (Ingredient input : inputs) {
- ingredients.add(new JsonPrimitive(input.serialize()));
- }
- object.addProperty("type", "forge");
- object.add("inputs", ingredients);
- object.addProperty("count", output.getCount());
- object.addProperty("overrideOutputId", output.getInternalItemId());
- if (hotmLevel >= 0)
- object.addProperty("hotmLevel", hotmLevel);
- if (timeInSeconds >= 0)
- object.addProperty("duration", timeInSeconds);
- return object;
- }
-
- static ForgeRecipe parseForgeRecipe(NEUManager manager, JsonObject recipe, JsonObject output) {
- List<Ingredient> ingredients = new ArrayList<>();
- for (JsonElement element : recipe.getAsJsonArray("inputs")) {
- String ingredientString = element.getAsString();
- ingredients.add(new Ingredient(manager, ingredientString));
- }
- String internalItemId = output.get("internalname").getAsString();
- if (recipe.has("overrideOutputId"))
- internalItemId = recipe.get("overrideOutputId").getAsString();
- int resultCount = 1;
- if (recipe.has("count")) {
- resultCount = recipe.get("count").getAsInt();
- }
- int duration = -1;
- if (recipe.has("duration")) {
- duration = recipe.get("duration").getAsInt();
- }
- int hotmLevel = -1;
- if (recipe.has("hotmLevel")) {
- hotmLevel = recipe.get("hotmLevel").getAsInt();
- }
- return new ForgeRecipe(
- manager,
- ingredients,
- new Ingredient(manager, internalItemId, resultCount),
- duration,
- hotmLevel
- );
- }
-
- private static final int RECIPE_CENTER_X = 40;
- private static final int RECIPE_CENTER_Y = 34;
- private static final int SLOT_DISTANCE_FROM_CENTER = 22;
- private static final int RECIPE_FALLBACK_X = 20;
- private static final int RECIPE_FALLBACK_Y = 15;
-
- static int[] getSlotCoordinates(int slotNumber, int totalSlotCount) {
- if (totalSlotCount > 6) {
- return new int[]{
- RECIPE_FALLBACK_X + (slotNumber % 4) * GuiItemRecipe.SLOT_SPACING,
- RECIPE_FALLBACK_Y + (slotNumber / 4) * GuiItemRecipe.SLOT_SPACING,
- };
- }
- if (totalSlotCount == 1) {
- return new int[]{
- RECIPE_CENTER_X - GuiItemRecipe.SLOT_SIZE / 2,
- RECIPE_CENTER_Y - GuiItemRecipe.SLOT_SIZE / 2
- };
- }
- double rad = Math.PI * 2 * slotNumber / totalSlotCount;
- int x = (int) (Math.cos(rad) * SLOT_DISTANCE_FROM_CENTER);
- int y = (int) (Math.sin(rad) * SLOT_DISTANCE_FROM_CENTER);
- return new int[]{RECIPE_CENTER_X + x, RECIPE_CENTER_Y + y};
- }
-
- static String formatDuration(int seconds) {
- int minutes = seconds / 60;
- seconds %= 60;
- int hours = minutes / 60;
- minutes %= 60;
- int days = hours / 24;
- hours %= 24;
- StringBuilder sB = new StringBuilder();
- if (days != 0) sB.append(days).append("d ");
- if (hours != 0) sB.append(hours).append("h ");
- if (minutes != 0) sB.append(minutes).append("m ");
- if (seconds != 0) sB.append(seconds).append("s ");
- return sB.substring(0, sB.length() - 1);
- }
+ private static final ResourceLocation BACKGROUND = new ResourceLocation("notenoughupdates", "textures/gui/forge_recipe_tall.png");
+
+ private static final int SLOT_IMAGE_U = 176;
+ private static final int SLOT_IMAGE_V = 0;
+ private static final int SLOT_IMAGE_SIZE = 18;
+ private static final int SLOT_PADDING = 1;
+ private static final int EXTRA_INFO_MAX_WIDTH = 75;
+ public static final int EXTRA_INFO_X = 132;
+ public static final int EXTRA_INFO_Y = 55;
+
+ public enum ForgeType {
+ REFINING, ITEM_FORGING
+ }
+
+ private final NEUManager manager;
+ private final List<Ingredient> inputs;
+ private final Ingredient output;
+ private final int hotmLevel;
+ private final int timeInSeconds; // TODO: quick forge
+ private List<RecipeSlot> slots;
+
+ public ForgeRecipe(NEUManager manager, List<Ingredient> inputs, Ingredient output, int durationInSeconds, int hotmLevel) {
+ this.manager = manager;
+ this.inputs = inputs;
+ this.output = output;
+ this.hotmLevel = hotmLevel;
+ this.timeInSeconds = durationInSeconds;
+ }
+
+ public List<Ingredient> getInputs() {
+ return inputs;
+ }
+
+ public Ingredient getOutput() {
+ return output;
+ }
+
+ public int getHotmLevel() {
+ return hotmLevel;
+ }
+
+ public int getTimeInSeconds() {
+ return timeInSeconds;
+ }
+
+ @Override
+ public ResourceLocation getBackground() {
+ return BACKGROUND;
+ }
+
+ @Override
+ public RecipeType getType() {
+ return RecipeType.FORGE;
+ }
+
+ @Override
+ public Set<Ingredient> getIngredients() {
+ return Sets.newHashSet(inputs);
+ }
+
+ @Override
+ public boolean hasVariableCost() {
+ return false;
+ }
+
+ @Override
+ public Set<Ingredient> getOutputs() {
+ return Collections.singleton(output);
+ }
+
+ @Override
+ public List<RecipeSlot> getSlots() {
+ if (slots != null) return slots;
+ slots = new ArrayList<>();
+ for (int i = 0; i < inputs.size(); i++) {
+ Ingredient input = inputs.get(i);
+ ItemStack itemStack = input.getItemStack();
+ if (itemStack == null) continue;
+ int[] slotCoordinates = getSlotCoordinates(i, inputs.size());
+ slots.add(new RecipeSlot(slotCoordinates[0], slotCoordinates[1], itemStack));
+ }
+ slots.add(new RecipeSlot(124, 66, output.getItemStack()));
+ return slots;
+ }
+
+ @Override
+ public void drawExtraBackground(GuiItemRecipe gui, int mouseX, int mouseY) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(BACKGROUND);
+ for (int i = 0; i < inputs.size(); i++) {
+ int[] slotCoordinates = getSlotCoordinates(i, inputs.size());
+ gui.drawTexturedModalRect(
+ gui.guiLeft + slotCoordinates[0] - SLOT_PADDING, gui.guiTop + slotCoordinates[1] - SLOT_PADDING,
+ SLOT_IMAGE_U, SLOT_IMAGE_V,
+ SLOT_IMAGE_SIZE, SLOT_IMAGE_SIZE);
+ }
+ }
+
+ @Override
+ public void drawExtraInfo(GuiItemRecipe gui, int mouseX, int mouseY) {
+ FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj;
+ if (timeInSeconds > 0)
+ Utils.drawStringCenteredScaledMaxWidth(formatDuration(timeInSeconds), fontRenderer, gui.guiLeft + EXTRA_INFO_X, gui.guiTop + EXTRA_INFO_Y, false, EXTRA_INFO_MAX_WIDTH, 0xff00ff);
+ }
+
+ @Override
+ public void drawHoverInformation(GuiItemRecipe gui, int mouseX, int mouseY) {
+ manager.hotm.getInformationOnCurrentProfile().ifPresent(hotmTree -> {
+ if (timeInSeconds > 0 && gui.isWithinRect(
+ mouseX, mouseY,
+ gui.guiLeft + EXTRA_INFO_X - EXTRA_INFO_MAX_WIDTH / 2,
+ gui.guiTop + EXTRA_INFO_Y - 8,
+ EXTRA_INFO_MAX_WIDTH, 16
+ )) {
+ int qf = hotmTree.getLevel("forge_time");
+ int reducedTime = getReducedTime(qf);
+ if (qf > 0) {
+
+ Utils.drawHoveringText(Arrays.asList(EnumChatFormatting.YELLOW + formatDuration(reducedTime) + " with Quick Forge (Level " + qf + ")"), mouseX, mouseY, gui.width, gui.height, 500, Minecraft.getMinecraft().fontRendererObj);
+ }
+ }
+ });
+ }
+
+ public int getReducedTime(int quickForgeUpgradeLevel) {
+ return HotmInformation.getQuickForgeMultiplier(quickForgeUpgradeLevel) * timeInSeconds / 1000;
+ }
+
+ @Override
+ public JsonObject serialize() {
+ JsonObject object = new JsonObject();
+ JsonArray ingredients = new JsonArray();
+ for (Ingredient input : inputs) {
+ ingredients.add(new JsonPrimitive(input.serialize()));
+ }
+ object.addProperty("type", "forge");
+ object.add("inputs", ingredients);
+ object.addProperty("count", output.getCount());
+ object.addProperty("overrideOutputId", output.getInternalItemId());
+ if (hotmLevel >= 0)
+ object.addProperty("hotmLevel", hotmLevel);
+ if (timeInSeconds >= 0)
+ object.addProperty("duration", timeInSeconds);
+ return object;
+ }
+
+ static ForgeRecipe parseForgeRecipe(NEUManager manager, JsonObject recipe, JsonObject output) {
+ List<Ingredient> ingredients = new ArrayList<>();
+ for (JsonElement element : recipe.getAsJsonArray("inputs")) {
+ String ingredientString = element.getAsString();
+ ingredients.add(new Ingredient(manager, ingredientString));
+ }
+ String internalItemId = output.get("internalname").getAsString();
+ if (recipe.has("overrideOutputId"))
+ internalItemId = recipe.get("overrideOutputId").getAsString();
+ int resultCount = 1;
+ if (recipe.has("count")) {
+ resultCount = recipe.get("count").getAsInt();
+ }
+ int duration = -1;
+ if (recipe.has("duration")) {
+ duration = recipe.get("duration").getAsInt();
+ }
+ int hotmLevel = -1;
+ if (recipe.has("hotmLevel")) {
+ hotmLevel = recipe.get("hotmLevel").getAsInt();
+ }
+ return new ForgeRecipe(manager, ingredients, new Ingredient(manager, internalItemId, resultCount), duration, hotmLevel);
+ }
+
+ private static final int RECIPE_CENTER_X = 49;
+ private static final int RECIPE_CENTER_Y = 74;
+ private static final int SLOT_DISTANCE_FROM_CENTER = 30;
+ private static final int RECIPE_FALLBACK_X = 20;
+ private static final int RECIPE_FALLBACK_Y = 15;
+
+ static int[] getSlotCoordinates(int slotNumber, int totalSlotCount) {
+ if (totalSlotCount > 8) {
+ return new int[]{
+ RECIPE_FALLBACK_X + (slotNumber % 4) * GuiItemRecipe.SLOT_SPACING,
+ RECIPE_FALLBACK_Y + (slotNumber / 4) * GuiItemRecipe.SLOT_SPACING,
+ };
+ }
+ if (totalSlotCount == 1) {
+ return new int[]{
+ RECIPE_CENTER_X - GuiItemRecipe.SLOT_SIZE / 2,
+ RECIPE_CENTER_Y - GuiItemRecipe.SLOT_SIZE / 2
+ };
+ }
+ double rad = Math.PI * 2 * slotNumber / totalSlotCount;
+ int x = (int) (Math.cos(rad) * SLOT_DISTANCE_FROM_CENTER);
+ int y = (int) (Math.sin(rad) * SLOT_DISTANCE_FROM_CENTER);
+ return new int[]{RECIPE_CENTER_X + x - GuiItemRecipe.SLOT_SIZE / 2, RECIPE_CENTER_Y + y - GuiItemRecipe.SLOT_SIZE / 2};
+ }
+
+ static String formatDuration(int seconds) {
+ int minutes = seconds / 60;
+ seconds %= 60;
+ int hours = minutes / 60;
+ minutes %= 60;
+ int days = hours / 24;
+ hours %= 24;
+ StringBuilder sB = new StringBuilder();
+ if (days != 0) sB.append(days).append("d ");
+ if (hours != 0) sB.append(hours).append("h ");
+ if (minutes != 0) sB.append(minutes).append("m ");
+ if (seconds != 0) sB.append(seconds).append("s ");
+ return sB.substring(0, sB.length() - 1);
+ }
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/Ingredient.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/Ingredient.java
index 79b548da..c4928605 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/Ingredient.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/Ingredient.java
@@ -2,6 +2,7 @@ package io.github.moulberry.notenoughupdates.recipes;
import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.NEUManager;
+import io.github.moulberry.notenoughupdates.util.ItemUtils;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
@@ -75,9 +76,7 @@ public class Ingredient {
public ItemStack getItemStack() {
if (itemStack != null) return itemStack;
if (isCoins()) {
- itemStack = new ItemStack(Items.gold_nugget);
- itemStack.setStackDisplayName("\u00A7r\u00A76" + Utils.formatNumberWithDots(getCount()) + " Coins");
- return itemStack;
+ return ItemUtils.getCoinItemStack(count);
}
JsonObject itemInfo = manager.getItemInformation().get(internalItemId);
itemStack = manager.jsonToStack(itemInfo);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java
new file mode 100644
index 00000000..dcbf71da
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java
@@ -0,0 +1,309 @@
+package io.github.moulberry.notenoughupdates.recipes;
+
+import com.google.common.collect.Sets;
+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.ItemUtils;
+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.init.Items;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.ResourceLocation;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+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 = 24;
+
+ public static class MobDrop {
+ public final Ingredient drop;
+ public final String chance;
+ public final List<String> extra;
+
+ private ItemStack itemStack;
+
+ public MobDrop(Ingredient drop, String chance, List<String> extra) {
+ this.drop = drop;
+ this.chance = chance;
+ this.extra = extra;
+ }
+
+ public ItemStack getItemStack() {
+ if (itemStack == null) {
+ itemStack = drop.getItemStack().copy();
+ List<String> arrayList = new ArrayList<>(extra);
+ arrayList.add("§r§e§lDrop Chance: §6" + chance);
+ ItemUtils.appendLore(itemStack, arrayList);
+ }
+ return itemStack;
+ }
+ }
+
+ public static ResourceLocation BACKGROUND = new ResourceLocation(
+ "notenoughupdates",
+ "textures/gui/mob_loot_tall.png"
+ );
+ private final Ingredient mobIngredient;
+ 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;
+
+ private final String panoName;
+
+ private ResourceLocation[] panos = null;
+
+ public MobLootRecipe(
+ Ingredient mobIngredient,
+ List<MobDrop> drops,
+ int level,
+ int coins,
+ int xp,
+ int combatXp,
+ String name,
+ String render,
+ List<String> extra,
+ String panoName
+ ) {
+ this.mobIngredient = mobIngredient;
+ this.drops = drops;
+ this.level = level;
+ this.coins = coins;
+ this.xp = xp;
+ this.extra = extra;
+ this.combatXp = combatXp;
+ this.name = name;
+ this.render = render;
+ this.panoName = panoName;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public List<MobDrop> getDrops() {
+ return drops;
+ }
+
+ public int getCoins() {
+ return coins;
+ }
+
+ public int getCombatXp() {
+ return combatXp;
+ }
+
+ public Ingredient getMob() {
+ return mobIngredient;
+ }
+
+ 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 Sets.newHashSet(mobIngredient);
+ }
+
+ @Override
+ public Set<Ingredient> getOutputs() {
+ return Stream.concat(drops.stream().map(it -> it.drop), Stream.of(mobIngredient)).collect(Collectors.toSet());
+ }
+
+ @Override
+ public String getTitle() {
+ return getFullMobName();
+ }
+
+ public String getFullMobName() {
+ return (level > 0 ? "§8[§7Lv " + level + "§8] §c" : "§c") + name;
+ }
+
+ @Override
+ public List<RecipeSlot> getSlots() {
+ List<RecipeSlot> slots = new ArrayList<>();
+ BiConsumer<Integer, ItemStack> addSlot = (sl, is) -> slots.add(
+ new RecipeSlot(
+ SLOT_POS_X + (sl % 5) * 16,
+ SLOT_POS_Y + (sl / 5) * 16,
+ is
+ ));
+ int i = 0;
+ for (; i < drops.size(); i++) {
+ MobDrop mobDrop = drops.get(i);
+ addSlot.accept(i, mobDrop.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) {
+ if (panos == null) {
+ panos = Panorama.getPanoramasForLocation(panoName, "day");
+ }
+ Panorama.drawPanorama(
+ ((System.nanoTime() / 20000000000F) % 1) * 360,
+ gui.guiLeft + PANORAMA_POS_X,
+ gui.guiTop + PANORAMA_POS_Y,
+ PANORAMA_WIDTH,
+ PANORAMA_HEIGHT,
+ 0F,
+ 0F,
+ panos
+ );
+ 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<>();
+ stuff.add(getFullMobName());
+ stuff.add("");
+ if (coins > 0)
+ stuff.add("§r§6Coins: " + coins);
+ if (xp > 0)
+ stuff.add("§r§aExperience: " + xp);
+ if (combatXp > 0)
+ stuff.add("§r§bCombat Experience: " + xp);
+ stuff.addAll(extra);
+ 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.addProperty("panorama", "unknown");
+ 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());
+ dropObject.add("extra", JsonUtils.transformListToJsonArray(drop.extra, JsonPrimitive::new));
+ 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(
+ new Ingredient(manager, outputItemJson.get("internalname").getAsString(), 1),
+ 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),
+ recipe.has("panorama") ? recipe.get("panorama").getAsString() : "unknown"
+ );
+ }
+}
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 3516f707..8202bb48 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/NeuRecipe.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/NeuRecipe.java
@@ -15,6 +15,12 @@ public interface NeuRecipe {
List<RecipeSlot> getSlots();
+ RecipeType getType();
+
+ default String getTitle() {
+ return getType().getLabel();
+ }
+
default void drawExtraInfo(GuiItemRecipe gui, int mouseX, int mouseY) {
}
@@ -31,15 +37,12 @@ public interface NeuRecipe {
ResourceLocation getBackground();
static NeuRecipe parseRecipe(NEUManager manager, JsonObject recipe, JsonObject output) {
+ RecipeType recipeType = RecipeType.CRAFTING;
if (recipe.has("type")) {
- switch (recipe.get("type").getAsString().intern()) {
- case "forge":
- return ForgeRecipe.parseForgeRecipe(manager, recipe, output);
- case "trade":
- return VillagerTradeRecipe.parseStaticRecipe(manager, recipe);
- }
+ recipeType = RecipeType.getRecipeTypeForId(recipe.get("type").getAsString());
}
- return CraftingRecipe.parseCraftingRecipe(manager, recipe, output);
+ if (recipeType == null) return null;
+ return recipeType.createRecipe(manager, recipe, output);
}
default boolean shouldUseForCraftCost() {
@@ -49,4 +52,11 @@ public interface NeuRecipe {
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 46aff6c4..e5028146 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,10 +21,10 @@ 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: ";
@@ -81,7 +83,7 @@ public class RecipeGenerator {
" seconds (no QF) ."));
boolean saved = false;
try {
- saved = saveRecipe(recipe);
+ saved = saveRecipes(recipe.getOutput().getInternalItemId(), Collections.singletonList(recipe));
} catch (IOException e) {
}
if (!saved)
@@ -93,21 +95,152 @@ public class RecipeGenerator {
" Failed to save recipe. Does the item already exist?"));
}
}
+ if (saveRecipe) attemptToSaveBestiary(menu);
}
- 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());
+ 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<>();
+ String internalMobName =
+ menu.getDisplayName().getUnformattedText().split("➜")[1].toUpperCase(Locale.ROOT).trim() + "_MONSTER";
+ 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(
+ new Ingredient(neu.manager, internalMobName, 1),
+ drops,
+ level,
+ coins,
+ xp,
+ combatXp,
+ name,
+ null,
+ new ArrayList<>(),
+ "unknown"
+ ));
+ }
+ boolean saved = false;
+ try {
+ saved = saveRecipes(internalMobName, 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;
}
@@ -149,7 +282,7 @@ public class RecipeGenerator {
);
}
- private static final Map<Character, Integer> durationSuffixLengthMap = new HashMap<Character, Integer>() {{
+ private static Map<Character, Integer> durationSuffixLengthMap = new HashMap<Character, Integer>() {{
put('d', 60 * 60 * 24);
put('h', 60 * 60);
put('m', 60);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeType.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeType.java
new file mode 100644
index 00000000..cc8b50be
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeType.java
@@ -0,0 +1,59 @@
+package io.github.moulberry.notenoughupdates.recipes;
+
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NEUManager;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemStack;
+
+public enum RecipeType {
+ CRAFTING("crafting", "Crafting", CraftingRecipe::parseCraftingRecipe, new ItemStack(Blocks.crafting_table)),
+ FORGE("forge", "Forging", ForgeRecipe::parseForgeRecipe, new ItemStack(Blocks.anvil)),
+ TRADE("trade", "Trading", VillagerTradeRecipe::parseStaticRecipe, new ItemStack(Items.emerald)),
+ MOB_LOOT("drops", "Mob Loot", MobLootRecipe::parseRecipe, new ItemStack(Items.diamond_sword));
+
+ private final String id;
+ private final String label;
+ private final RecipeFactory recipeFactory;
+ private final ItemStack icon;
+
+ RecipeType(String id, String label, RecipeFactory recipeFactory, ItemStack icon) {
+ this.id = id;
+ this.label = label;
+ this.recipeFactory = recipeFactory;
+ this.icon = icon;
+ icon.setStackDisplayName("neurecipe-" + id);
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public RecipeFactory getRecipeFactory() {
+ return recipeFactory;
+ }
+
+ public ItemStack getIcon() {
+ return icon;
+ }
+
+ public NeuRecipe createRecipe(NEUManager manager, JsonObject recipe, JsonObject outputItemJson) {
+ return recipeFactory.createRecipe(manager, recipe, outputItemJson);
+ }
+
+ public static RecipeType getRecipeTypeForId(String id) {
+ for (RecipeType value : values()) {
+ if (value.id.equals(id)) return value;
+ }
+ return null;
+ }
+
+ @FunctionalInterface
+ interface RecipeFactory {
+ NeuRecipe createRecipe(NEUManager manager, JsonObject recipe, JsonObject outputItemJson);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/VillagerTradeRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/VillagerTradeRecipe.java
index 371d4f3c..2e53e153 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/VillagerTradeRecipe.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/VillagerTradeRecipe.java
@@ -21,136 +21,130 @@ import java.util.*;
public class VillagerTradeRecipe implements NeuRecipe {
- public static final int COST_SLOT_X = 51;
- public static final int COST_SLOT_Y = 34;
- public static final int RESULT_SLOT_Y = 35;
- public static final int RESULT_SLOT_X = 124;
-
- private static class Holder { // This holder object exists to defer initialization to first access
- private static final GameProfile DREAM_PROFILE =
- new GameProfile(UUID.fromString("ec70bcaf-702f-4bb8-b48d-276fa52a780c"), "Dream");
- private static final EntityLivingBase DEMO_DREAM = new AbstractClientPlayer(null, DREAM_PROFILE) {
- @Override
- protected NetworkPlayerInfo getPlayerInfo() {
- return new NetworkPlayerInfo(DREAM_PROFILE) {
- @Override
- public ResourceLocation getLocationSkin() {
- return new ResourceLocation("notenoughupdates", "dreamskin.png");
- }
- };
- }
- };
- private static final EntityLivingBase DEMO_VILLAGER = new EntityVillager(null);
-
- private static boolean isAprilFirst() {
- Calendar cal = Calendar.getInstance();
- return cal.get(Calendar.DAY_OF_MONTH) == 1 && cal.get(Calendar.MONTH) == Calendar.APRIL;
- }
-
- private static final EntityLivingBase DEMO_ENTITY = isAprilFirst() ? DEMO_DREAM : DEMO_VILLAGER;
-
- }
-
- private final static ResourceLocation BACKGROUND =
- new ResourceLocation("notenoughupdates", "textures/gui/villager_recipe.png");
-
- private final Ingredient result;
- private final Ingredient cost;
- private final int minCost, maxCost;
-
- public VillagerTradeRecipe(Ingredient result, Ingredient cost, int minCost, int maxCost) {
- this.result = result;
- this.cost = cost;
- this.minCost = minCost;
- this.maxCost = maxCost;
- }
-
- public VillagerTradeRecipe(Ingredient result, Ingredient cost) {
- this(result, cost, -1, -1);
- }
-
- public boolean hasVariableCost() {
- return minCost != -1 && maxCost != -1;
- }
-
- @Override
- public Set<Ingredient> getIngredients() {
- return Sets.newHashSet(cost);
- }
-
- @Override
- public Set<Ingredient> getOutputs() {
- return Sets.newHashSet(result);
- }
-
- @Override
- public List<RecipeSlot> getSlots() {
- return Arrays.asList(
- new RecipeSlot(COST_SLOT_X, COST_SLOT_Y, cost.getItemStack()),
- new RecipeSlot(RESULT_SLOT_X, RESULT_SLOT_Y, result.getItemStack())
- );
- }
-
- @Override
- public boolean shouldUseForCraftCost() {
- return false;
- }
-
- @Override
- public boolean isAvailable() {
- return SBInfo.getInstance().getCurrentMode() == SBInfo.Gamemode.STRANDED ||
- NotEnoughUpdates.INSTANCE.config.hidden.dev;
- }
-
- @Override
- public void drawExtraInfo(GuiItemRecipe gui, int mouseX, int mouseY) {
- if (hasVariableCost()) {
- FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj;
- Utils.drawStringCenteredScaledMaxWidth(
- minCost + " - " + maxCost, fontRenderer,
- gui.guiLeft + 50, gui.guiTop + 60, false, 75, 0xff00ff
- );
-
- }
- }
-
- @Override
- public void drawExtraBackground(GuiItemRecipe gui, int mouseX, int mouseY) {
- GuiInventory.drawEntityOnScreen(
- gui.guiLeft + 90,
- gui.guiTop + 75,
- 30,
- gui.guiLeft - mouseX + 80,
- gui.guiTop + 60 - mouseY,
- Holder.DEMO_ENTITY
- );
- }
-
- @Override
- public JsonObject serialize() {
- JsonObject jsonObject = new JsonObject();
- jsonObject.addProperty("type", "trade");
- jsonObject.addProperty("result", result.serialize());
- jsonObject.addProperty("cost", cost.getInternalItemId());
- if (minCost > 0)
- jsonObject.addProperty("min", minCost);
- if (maxCost > 0)
- jsonObject.addProperty("max", maxCost);
- return jsonObject;
- }
-
- @Override
- public ResourceLocation getBackground() {
- return BACKGROUND;
- }
-
- public static VillagerTradeRecipe parseStaticRecipe(NEUManager manager, JsonObject recipe) {
- return new VillagerTradeRecipe(
- new Ingredient(manager, recipe.get("result").getAsString()),
- new Ingredient(manager, recipe.get("cost").getAsString()),
- recipe.has("min") ? recipe.get("min").getAsInt() : -1,
- recipe.has("max") ? recipe.get("max").getAsInt() : -1
- );
- }
+ public static final int COST_SLOT_X = 52;
+ public static final int COST_SLOT_Y = 66;
+ public static final int RESULT_SLOT_Y = 66;
+ public static final int RESULT_SLOT_X = 124;
+
+ private static class Holder { // This holder object exists to defer initialization to first access
+ private static final GameProfile DREAM_PROFILE = new GameProfile(UUID.fromString("ec70bcaf-702f-4bb8-b48d-276fa52a780c"), "Dream");
+ private static final EntityLivingBase DEMO_DREAM = new AbstractClientPlayer(null, DREAM_PROFILE) {
+ @Override
+ protected NetworkPlayerInfo getPlayerInfo() {
+ return new NetworkPlayerInfo(DREAM_PROFILE) {
+ @Override
+ public ResourceLocation getLocationSkin() {
+ return new ResourceLocation("notenoughupdates", "dreamskin.png");
+ }
+ };
+ }
+ };
+ private static final EntityLivingBase DEMO_VILLAGER = new EntityVillager(null);
+
+ private static boolean isAprilFirst() {
+ Calendar cal = Calendar.getInstance();
+ return cal.get(Calendar.DAY_OF_MONTH) == 1 && cal.get(Calendar.MONTH) == Calendar.APRIL;
+ }
+
+ private static final EntityLivingBase DEMO_ENTITY = isAprilFirst() ? DEMO_DREAM : DEMO_VILLAGER;
+
+ }
+
+ private final static ResourceLocation BACKGROUND = new ResourceLocation("notenoughupdates", "textures/gui/villager_recipe_tall.png");
+
+ private final Ingredient result;
+ private final Ingredient cost;
+ private final int minCost, maxCost;
+
+ public VillagerTradeRecipe(Ingredient result, Ingredient cost, int minCost, int maxCost) {
+ this.result = result;
+ this.cost = cost;
+ this.minCost = minCost;
+ this.maxCost = maxCost;
+ }
+
+ public VillagerTradeRecipe(Ingredient result, Ingredient cost) {
+ this(result, cost, -1, -1);
+ }
+
+ public boolean hasVariableCost() {
+ return minCost != -1 && maxCost != -1;
+ }
+
+ @Override
+ public RecipeType getType() {
+ return RecipeType.TRADE;
+ }
+
+ @Override
+ public Set<Ingredient> getIngredients() {
+ return Sets.newHashSet(cost);
+ }
+
+ @Override
+ public Set<Ingredient> getOutputs() {
+ return Sets.newHashSet(result);
+ }
+
+ @Override
+ public List<RecipeSlot> getSlots() {
+ return Arrays.asList(
+ new RecipeSlot(COST_SLOT_X, COST_SLOT_Y, cost.getItemStack()),
+ new RecipeSlot(RESULT_SLOT_X, RESULT_SLOT_Y, result.getItemStack())
+ );
+ }
+
+ @Override
+ public boolean shouldUseForCraftCost() {
+ return false;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return SBInfo.getInstance().getCurrentMode() == SBInfo.Gamemode.STRANDED || NotEnoughUpdates.INSTANCE.config.hidden.dev;
+ }
+
+ @Override
+ public void drawExtraInfo(GuiItemRecipe gui, int mouseX, int mouseY) {
+ if (hasVariableCost()) {
+ FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj;
+ Utils.drawStringCenteredScaledMaxWidth(
+ minCost + " - " + maxCost, fontRenderer,
+ gui.guiLeft + 50, gui.guiTop + 90, false, 75, 0xff00ff);
+
+ }
+ }
+
+ @Override
+ public void drawExtraBackground(GuiItemRecipe gui, int mouseX, int mouseY) {
+ GuiInventory.drawEntityOnScreen(gui.guiLeft + 90, gui.guiTop + 100, 30, gui.guiLeft - mouseX + 110, gui.guiTop + 60 - mouseY, Holder.DEMO_ENTITY);
+ }
+
+ @Override
+ public JsonObject serialize() {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("type", "trade");
+ jsonObject.addProperty("result", result.serialize());
+ jsonObject.addProperty("cost", cost.getInternalItemId());
+ if (minCost > 0)
+ jsonObject.addProperty("min", minCost);
+ if (maxCost > 0)
+ jsonObject.addProperty("max", maxCost);
+ return jsonObject;
+ }
+
+ @Override
+ public ResourceLocation getBackground() {
+ return BACKGROUND;
+ }
+
+ public static VillagerTradeRecipe parseStaticRecipe(NEUManager manager, JsonObject recipe, JsonObject result) {
+ return new VillagerTradeRecipe(
+ new Ingredient(manager, recipe.get("result").getAsString()),
+ new Ingredient(manager, recipe.get("cost").getAsString()),
+ recipe.has("min") ? recipe.get("min").getAsInt() : -1,
+ recipe.has("max") ? recipe.get("max").getAsInt() : -1
+ );
+ }
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java
new file mode 100644
index 00000000..e3d90aaa
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java
@@ -0,0 +1,33 @@
+package io.github.moulberry.notenoughupdates.util;
+
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.nbt.NBTTagString;
+
+import java.util.List;
+
+public class ItemUtils {
+
+ public static ItemStack getCoinItemStack(int coinAmount) {
+ ItemStack itemStack = new ItemStack(Items.gold_nugget);
+ itemStack.setStackDisplayName("\u00A7r\u00A76" + Utils.formatNumberWithDots(coinAmount) + " Coins");
+ return itemStack;
+ }
+
+ public static void appendLore(ItemStack is, List<String> moreLore) {
+ NBTTagCompound tagCompound = is.getTagCompound();
+ if (tagCompound == null) {
+ tagCompound = new NBTTagCompound();
+ }
+ NBTTagCompound display = tagCompound.getCompoundTag("display");
+ NBTTagList lore = display.getTagList("Lore", 8);
+ for (String s : moreLore) {
+ lore.appendTag(new NBTTagString(s));
+ }
+ display.setTag("Lore", lore);
+ tagCompound.setTag("display", display);
+ is.setTagCompound(tagCompound);
+ }
+}
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;
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/SkytilsCompat.java b/src/main/java/io/github/moulberry/notenoughupdates/util/SkytilsCompat.java
new file mode 100644
index 00000000..193f6133
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/SkytilsCompat.java
@@ -0,0 +1,82 @@
+package io.github.moulberry.notenoughupdates.util;
+
+import net.minecraft.item.ItemStack;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+
+public class SkytilsCompat {
+ // Defer static initialization
+ private static class Holder {
+ // Skytils is present in some capacity
+ static boolean isSkytilsPresent = false;
+ // All classes successfully loaded
+ static boolean isSkytilsFullyPresent = false;
+
+ static Class<?> skytilsClass = null;
+ static Method renderRarityMethod = null;
+ static Class<?> renderUtilClass = null;
+
+ static Object skytilsCompanionObject = null;
+
+ static Class<?> skytilsConfigClass = null;
+
+ static Object skytilsConfigObject = null;
+ static Method skytilsGetShowItemRarity = null;
+
+ static {
+ try {
+ skytilsClass = Class.forName("skytils.skytilsmod.Skytils");
+ isSkytilsPresent = true;
+ } catch (ClassNotFoundException ignored) {
+ }
+ try {
+ Class<?> skytilsCompanionClass = Class.forName("skytils.skytilsmod.Skytils$Companion");
+ skytilsConfigClass = Class.forName("skytils.skytilsmod.core.Config");
+ Field skytilsCompanionField = skytilsClass.getField("Companion");
+ skytilsCompanionObject = skytilsCompanionField.get(null);
+ Method skytilsGetConfigMethod = skytilsCompanionClass.getMethod("getConfig");
+ skytilsConfigObject = skytilsGetConfigMethod.invoke(skytilsCompanionObject);
+ skytilsGetShowItemRarity = skytilsConfigClass.getMethod("getShowItemRarity");
+ renderUtilClass = Class.forName("skytils.skytilsmod.utils.RenderUtil");
+ renderRarityMethod = renderUtilClass.getDeclaredMethod(
+ "renderRarity",
+ ItemStack.class,
+ Integer.TYPE,
+ Integer.TYPE
+ );
+ isSkytilsFullyPresent = true;
+ } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException | IllegalAccessException |
+ InvocationTargetException e) {
+ System.err.println("Failed to get Skytils class even tho Skytils mod is present. This is (probably) a NEU bug");
+ e.printStackTrace();
+ }
+ }
+
+ }
+
+ public static boolean isSkytilsFullyLoaded() {
+ return Holder.isSkytilsFullyPresent;
+ }
+
+ public static boolean isSkytilsPresent() {
+ return Holder.isSkytilsPresent;
+ }
+ public static void renderSkytilsRarity(ItemStack stack, int x, int y) {
+ renderSkytilsRarity(stack, x, y, false);
+ }
+
+ public static void renderSkytilsRarity(ItemStack stack, int x, int y, boolean force) {
+ if (Holder.isSkytilsFullyPresent) {
+ try {
+ if (force || (boolean) Holder.skytilsGetShowItemRarity.invoke(Holder.skytilsConfigObject))
+ Holder.renderRarityMethod.invoke(null, stack, x, y);
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
index 31499f7f..5fac9208 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
@@ -9,6 +9,7 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.miscfeatures.SlotLocking;
+import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.entity.EntityPlayerSP;
@@ -175,8 +176,13 @@ public class Utils {
}
public static void drawItemStackWithText(ItemStack stack, int x, int y, String text) {
- if (stack == null) return;
+ drawItemStackWithText(stack, x, y, text, false);
+ }
+ public static void drawItemStackWithText(ItemStack stack, int x, int y, String text, boolean skytilsRarity) {
+ if (stack == null) return;
+ if (skytilsRarity)
+ SkytilsCompat.renderSkytilsRarity(stack, x, y);
RenderItem itemRender = Minecraft.getMinecraft().getRenderItem();
disableCustomDungColours = true;
@@ -190,11 +196,13 @@ public class Utils {
}
public static void drawItemStack(ItemStack stack, int x, int y) {
- if (stack == null) return;
-
drawItemStackWithText(stack, x, y, null);
}
+ public static void drawItemStack(ItemStack stack, int x, int y, boolean skytilsRarity) {
+ drawItemStackWithText(stack, x, y, null, skytilsRarity);
+ }
+
private static final EnumChatFormatting[] rainbow = new EnumChatFormatting[]{
EnumChatFormatting.RED,
EnumChatFormatting.GOLD,
@@ -767,6 +775,9 @@ public class Utils {
public static ItemStack createItemStack(Item item, String displayname, String... lore) {
return createItemStack(item, displayname, 0, lore);
}
+ public static ItemStack createItemStack(Block item, String displayname, String... lore) {
+ return createItemStack(Item.getItemFromBlock(item), displayname, lore);
+ }
public static ItemStack createItemStack(Item item, String displayname, int damage, String... lore) {
ItemStack stack = new ItemStack(item, 1, damage);
diff --git a/src/main/resources/assets/notenoughupdates/dream.json b/src/main/resources/assets/notenoughupdates/dream.json
new file mode 100644
index 00000000..6f27e89e
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/dream.json
@@ -0,0 +1,49 @@
+{
+ "entity": "Player",
+ "modifiers": [
+ {
+ "type": "playerdata",
+ "skin": "notenoughupdates:dreamskin.png"
+ },
+ {
+ "type": "riding",
+ "entity": "ArmorStand",
+ "modifiers": [
+ {
+ "type": "age",
+ "baby": true
+ },
+ {
+ "type": "riding",
+ "entity": "Zombie",
+ "modifiers": [
+ {
+ "type": "equipment",
+ "hand": "BOW",
+ "feet": "DIAMOND_BOOTS"
+ },
+ {
+ "type": "age",
+ "baby": true
+ },
+ {
+ "type": "riding",
+ "entity": "Sheep",
+ "modifiers": [
+ {
+ "type": "age",
+ "baby": true
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "equipment",
+ "hand": "DIAMOND_SWORD",
+ "feet": "DIAMOND_BOOTS"
+ }
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/crafting_table_tall.png b/src/main/resources/assets/notenoughupdates/textures/gui/crafting_table_tall.png
new file mode 100644
index 00000000..5a5fa825
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/textures/gui/crafting_table_tall.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/entity_viewer.png b/src/main/resources/assets/notenoughupdates/textures/gui/entity_viewer.png
new file mode 100644
index 00000000..18085170
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/textures/gui/entity_viewer.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe.png b/src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe.png
deleted file mode 100644
index 2c3d2eb1..00000000
--- a/src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe_tall.png b/src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe_tall.png
new file mode 100644
index 00000000..b07e5ca1
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe_tall.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/mob_loot_tall.png b/src/main/resources/assets/notenoughupdates/textures/gui/mob_loot_tall.png
new file mode 100644
index 00000000..facd6d6c
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/textures/gui/mob_loot_tall.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/tab.png b/src/main/resources/assets/notenoughupdates/textures/gui/tab.png
new file mode 100644
index 00000000..91d317ca
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/textures/gui/tab.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe.png b/src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe.png
deleted file mode 100644
index 42b6241c..00000000
--- a/src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe_tall.png b/src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe_tall.png
new file mode 100644
index 00000000..ed982599
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe_tall.png
Binary files differ
diff --git a/src/main/resources/mixins.notenoughupdates.json b/src/main/resources/mixins.notenoughupdates.json
index a566ee2e..6c95e480 100644
--- a/src/main/resources/mixins.notenoughupdates.json
+++ b/src/main/resources/mixins.notenoughupdates.json
@@ -3,14 +3,18 @@
"refmap": "mixins.notenoughupdates.refmap.json",
"compatibilityLevel": "JAVA_8",
"mixins": [
+ "AccessorEntityAgeable",
+ "AccessorEntityArmorStand",
"MixinAbstractClientPlayer",
"MixinContainer",
"MixinEffectRenderer",
"MixinEntity",
"MixinEntityAgeable",
+ "MixinEntityHorse",
"MixinEntityPlayer",
"MixinEntityPlayerSP",
"MixinEntityRenderer",
+ "MixinEntitySkeleton",
"MixinGuiChest",
"MixinGuiContainer",
"MixinGuiIngame",
@@ -39,5 +43,8 @@
"MixinVboRenderList",
"MixinWorld",
"MixinWorldClient"
+ ],
+ "client": [
+ "AccessorMinecraft"
]
}