diff --git a/ItemsAdder/tfmc_cooking/contents/items.yml b/ItemsAdder/tfmc_cooking/contents/items.yml index 24f0b64..ae06fee 100644 --- a/ItemsAdder/tfmc_cooking/contents/items.yml +++ b/ItemsAdder/tfmc_cooking/contents/items.yml @@ -1293,6 +1293,20 @@ items: generate: false model_path: item/liquid/red_dark_plated + milk_plated: + display_name: "Milk Plated" + resource: + material: TROPICAL_FISH + generate: false + model_path: item/liquid/milk_plated + + water_plated: + display_name: "Water Plated" + resource: + material: TROPICAL_FISH + generate: false + model_path: item/liquid/water_plated + ladle: display_name: "Ladle" resource: diff --git a/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/models/item/liquid/milk_plated.json b/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/models/item/liquid/milk_plated.json new file mode 100644 index 0000000..bf022fb --- /dev/null +++ b/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/models/item/liquid/milk_plated.json @@ -0,0 +1,22 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "textures": { + "0": "tfmc_cooking:item/liquid/milk_plated", + "particle": "tfmc_cooking:item/liquid/milk_plated" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 0, 16], + "faces": { + "north": {"uv": [0, 0, 16, 0], "texture": "#0"}, + "east": {"uv": [0, 0, 16, 0], "texture": "#0"}, + "south": {"uv": [0, 0, 16, 0], "texture": "#0"}, + "west": {"uv": [0, 0, 16, 0], "texture": "#0"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#0"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/models/item/liquid/water_plated.json b/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/models/item/liquid/water_plated.json new file mode 100644 index 0000000..3f6b8df --- /dev/null +++ b/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/models/item/liquid/water_plated.json @@ -0,0 +1,22 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "textures": { + "0": "tfmc_cooking:item/liquid/water_plated", + "particle": "tfmc_cooking:item/liquid/water_plated" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 0, 16], + "faces": { + "north": {"uv": [0, 0, 16, 0], "texture": "#0"}, + "east": {"uv": [0, 0, 16, 0], "texture": "#0"}, + "south": {"uv": [0, 0, 16, 0], "texture": "#0"}, + "west": {"uv": [0, 0, 16, 0], "texture": "#0"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#0"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/textures/item/liquid/milk_plated.png b/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/textures/item/liquid/milk_plated.png new file mode 100644 index 0000000..607992a Binary files /dev/null and b/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/textures/item/liquid/milk_plated.png differ diff --git a/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/textures/item/liquid/milk_plated.png.mcmeta b/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/textures/item/liquid/milk_plated.png.mcmeta new file mode 100644 index 0000000..994ad4a --- /dev/null +++ b/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/textures/item/liquid/milk_plated.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation": { + "frametime": 15 + } +} \ No newline at end of file diff --git a/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/textures/item/liquid/water_plated.png b/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/textures/item/liquid/water_plated.png new file mode 100644 index 0000000..debf7e5 Binary files /dev/null and b/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/textures/item/liquid/water_plated.png differ diff --git a/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/textures/item/liquid/water_plated.png.mcmeta b/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/textures/item/liquid/water_plated.png.mcmeta new file mode 100644 index 0000000..994ad4a --- /dev/null +++ b/ItemsAdder/tfmc_cooking/resourcepack/assets/tfmc_cooking/textures/item/liquid/water_plated.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation": { + "frametime": 15 + } +} \ No newline at end of file diff --git a/src/main/java/net/tfminecraft/cooking/cache/CategoryDictionary.java b/src/main/java/net/tfminecraft/cooking/cache/CategoryDictionary.java index dd506ad..7ee5a3d 100644 --- a/src/main/java/net/tfminecraft/cooking/cache/CategoryDictionary.java +++ b/src/main/java/net/tfminecraft/cooking/cache/CategoryDictionary.java @@ -24,12 +24,17 @@ public static String getName(String key) { return StringFormatter.formatHex(dictionary.getOrDefault(key, "#8f8f8f" + WordUtils.capitalize(new String(key).replace("_", " ")))); } + /** sauce-dict entries are "station model|plated model"; index 1 picks the plated one. */ + public static final int PLATED = 1; + public static String getSauceItemPath(String colour, int index) { + // A plate needs a splash: the station fallback is a pan-sized liquid surface. + String fallback = index == PLATED ? ItemCache.platedLiquidFallback : ItemCache.liquidFallback; // Uncoloured names (water-only mixes, or older "000000Mixed Sauce" items) have no hex to read. - if (colour == null) return ItemCache.liquidFallback; + if (colour == null) return fallback; int rTotal = 0, gTotal = 0, bTotal = 0, count = 0; String hex = colour.replace("#", ""); - if (hex.equalsIgnoreCase("000000")) return ItemCache.liquidFallback; + if (hex.equalsIgnoreCase("000000")) return fallback; try { int r = Integer.parseInt(hex.substring(0, 2), 16); @@ -43,7 +48,7 @@ public static String getSauceItemPath(String colour, int index) { } catch (Exception ignored) {} if (count == 0) - return ItemCache.liquidFallback; + return fallback; int rAvg = rTotal / count; int gAvg = gTotal / count; @@ -82,6 +87,6 @@ public static String getSauceItemPath(String colour, int index) { } } - return ItemCache.liquidFallback; + return fallback; } } diff --git a/src/main/java/net/tfminecraft/cooking/cache/ItemCache.java b/src/main/java/net/tfminecraft/cooking/cache/ItemCache.java index 5a04408..f95782c 100644 --- a/src/main/java/net/tfminecraft/cooking/cache/ItemCache.java +++ b/src/main/java/net/tfminecraft/cooking/cache/ItemCache.java @@ -47,6 +47,7 @@ public class ItemCache { public static HashMap liquidModels = new HashMap<>(); public static HashMap colourMap = new HashMap<>(); public static String liquidFallback; + public static String platedLiquidFallback; //TOOLS public static String ladle; diff --git a/src/main/java/net/tfminecraft/cooking/loader/ConfigLoader.java b/src/main/java/net/tfminecraft/cooking/loader/ConfigLoader.java index 36640a1..7e8b69a 100644 --- a/src/main/java/net/tfminecraft/cooking/loader/ConfigLoader.java +++ b/src/main/java/net/tfminecraft/cooking/loader/ConfigLoader.java @@ -55,6 +55,7 @@ public void loadConfig(File configFile) { ItemCache.firePitSpinAxis = config.getString("fire-pit-spin-axis", "x").toLowerCase(); ItemCache.carveTool = config.getString("carve-tool", "ia.tfmc_cooking:cutting_knife"); ItemCache.liquidFallback = config.getString("liquid-fallback", "ia.tfmc_cooking:water"); + ItemCache.platedLiquidFallback = config.getString("plated-liquid-fallback", "ia.tfmc_cooking:water_plated"); ItemCache.water = config.getString("water", "v.water_bucket"); ItemCache.emptyCup = config.getString("empty-cup", "ia.tfmc_cooking:empty_cup"); diff --git a/src/main/java/net/tfminecraft/cooking/manager/PlateManager.java b/src/main/java/net/tfminecraft/cooking/manager/PlateManager.java index df3d78d..dfff5b0 100644 --- a/src/main/java/net/tfminecraft/cooking/manager/PlateManager.java +++ b/src/main/java/net/tfminecraft/cooking/manager/PlateManager.java @@ -171,7 +171,7 @@ public void addSauce(Player p, Furniture f, FoodItem sauce, ItemStack base) { ItemMeta baseMeta = base.getItemMeta(); String saucePath = CategoryDictionary.getSauceItemPath(sauceColour( baseMeta.getPersistentDataContainer().get(Keys.SAUCE_COLOUR, PersistentDataType.STRING), - baseMeta.getDisplayName()), 1); + baseMeta.getDisplayName()), CategoryDictionary.PLATED); ItemStack visual = TLibs.getItemAPI().getCreator().getItemFromPath(saucePath); if (visual != null && !visual.getType().isAir()) f.getOrCreatePlacedSlot("sauce").forceModel(visual); f.getLoc().getWorld().playSound(f.getLoc(), Sound.ITEM_BUCKET_FILL, 1f, 1f); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 411332a..57c2efa 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -33,6 +33,7 @@ carve-tool: ia.tfmc_cooking:cutting_knife water: ia.tfmc_cooking:water liquid-fallback: ia.tfmc_cooking:water +plated-liquid-fallback: ia.tfmc_cooking:water_plated empty-cup: ia.tfmc_cooking:empty_cup cup-of-water: ia.tfmc_cooking:cup_of_water cup-of-milk: ia.tfmc_cooking:cup_of_milk @@ -181,7 +182,7 @@ dictionary: liquid: "#3d85c6Liquid" sauce-dict: - - ffffff ia.tfmc_cooking:milk|ia.tfmc_cooking:milk + - ffffff ia.tfmc_cooking:milk|ia.tfmc_cooking:milk_plated - 80352e ia.tfmc_cooking:red_dark|ia.tfmc_cooking:red_dark_plated - a8552e ia.tfmc_cooking:red_light|ia.tfmc_cooking:red_light_plated - a86c2e ia.tfmc_cooking:brown_light|ia.tfmc_cooking:brown_light_plated diff --git a/src/test/java/net/tfminecraft/cooking/cache/BundledSauceVisualsTest.java b/src/test/java/net/tfminecraft/cooking/cache/BundledSauceVisualsTest.java new file mode 100644 index 0000000..21c9db9 --- /dev/null +++ b/src/test/java/net/tfminecraft/cooking/cache/BundledSauceVisualsTest.java @@ -0,0 +1,78 @@ +package net.tfminecraft.cooking.cache; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; +import org.junit.jupiter.api.Test; + +/** The bundled sauce visuals have to exist in the bundled ItemsAdder pack and fit their furniture. */ +class BundledSauceVisualsTest { + private static final String NAMESPACE = "ia.tfmc_cooking:"; + private static final File PACK = new File("ItemsAdder/tfmc_cooking"); + // Model JSON is indented with tabs, which YAML refuses, so read the texture paths directly. + private static final Pattern TEXTURE = Pattern.compile("\"tfmc_cooking:([^\"]+)\""); + + private final YamlConfiguration config = YamlConfiguration.loadConfiguration(new File("src/main/resources/config.yml")); + private final ConfigurationSection items = YamlConfiguration + .loadConfiguration(new File(PACK, "contents/items.yml")).getConfigurationSection("items"); + + @Test + void everySauceHasItsOwnPlatedSplash() { + List entries = config.getStringList("sauce-dict"); + assertTrue(entries.size() > 0); + for (String entry : entries) { + String[] paths = entry.split("\\s+")[1].split("\\|", 2); + assertEquals(2, paths.length, entry); + // A station model on a plate is a pan-sized sheet of liquid floating over the food. + assertNotEquals(paths[0], paths[1], entry); + assertTrue(paths[1].endsWith("_plated"), entry); + assertPackItem(paths[0]); + assertPackItem(paths[1]); + } + } + + @Test + void fallbacksMatchTheirFurniture() { + assertPackItem(config.getString("liquid-fallback")); + String plated = config.getString("plated-liquid-fallback"); + assertTrue(plated.endsWith("_plated"), plated); + assertPackItem(plated); + } + + private static String read(File file) { + try { + return Files.readString(file.toPath()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private void assertPackItem(String path) { + assertTrue(path.startsWith(NAMESPACE), path); + ConfigurationSection item = items.getConfigurationSection(path.substring(NAMESPACE.length())); + assertNotNull(item, path + " is not in the bundled pack"); + String model = item.getString("resource.model_path"); + File json = new File(PACK, "resourcepack/assets/tfmc_cooking/models/" + model + ".json"); + assertTrue(json.isFile(), json.getPath()); + Matcher texture = TEXTURE.matcher(read(json)); + int found = 0; + while (texture.find()) { + File png = new File(PACK, "resourcepack/assets/tfmc_cooking/textures/" + texture.group(1) + ".png"); + assertTrue(png.isFile(), png.getPath()); + found++; + } + assertTrue(found > 0, json.getPath()); + } +} diff --git a/src/test/java/net/tfminecraft/cooking/cache/CachesCoverageTest.java b/src/test/java/net/tfminecraft/cooking/cache/CachesCoverageTest.java index 53d09bd..98b18d6 100644 --- a/src/test/java/net/tfminecraft/cooking/cache/CachesCoverageTest.java +++ b/src/test/java/net/tfminecraft/cooking/cache/CachesCoverageTest.java @@ -156,13 +156,16 @@ class CachesCoverageTest { @Test void categoryNamesAndSauceColoursUseConfiguredValuesOrFallbacks() { CategoryDictionary.dictionary.put("meat","Custom Meat"); assertEquals("Custom Meat",CategoryDictionary.getName("meat")); assertTrue(CategoryDictionary.getName("garden_vegetable").endsWith("Garden Vegetable")); - ItemCache.liquidFallback="fallback"; CategoryDictionary.sauceDict.put("ff0000","red|deep.red"); + ItemCache.liquidFallback="fallback"; ItemCache.platedLiquidFallback="plated.fallback"; CategoryDictionary.sauceDict.put("ff0000","red|deep.red"); CategoryDictionary.sauceDict.put("000000","black"); CategoryDictionary.sauceDict.put("bad","invalid"); assertEquals("red",CategoryDictionary.getSauceItemPath("#fe0101",0)); assertEquals("deep.red",CategoryDictionary.getSauceItemPath("ff0000",1)); for(String colour:new String[]{null,"000000","bad"}) assertEquals("fallback",CategoryDictionary.getSauceItemPath(colour,0)); + for(String colour:new String[]{null,"000000","bad"}) assertEquals("plated.fallback",CategoryDictionary.getSauceItemPath(colour,CategoryDictionary.PLATED)); assertEquals("fallback",CategoryDictionary.getSauceItemPath("ff0000",-1)); assertEquals("fallback",CategoryDictionary.getSauceItemPath("ff0000",2)); - CategoryDictionary.sauceDict.put("ff0000","red| "); assertEquals("fallback",CategoryDictionary.getSauceItemPath("ff0000",1)); + CategoryDictionary.sauceDict.put("ff0000","red| "); assertEquals("plated.fallback",CategoryDictionary.getSauceItemPath("ff0000",1)); + CategoryDictionary.sauceDict.put("ff0000","red"); assertEquals("plated.fallback",CategoryDictionary.getSauceItemPath("ff0000",1)); CategoryDictionary.sauceDict.clear(); assertEquals("fallback",CategoryDictionary.getSauceItemPath("ff0000",0)); + assertEquals("plated.fallback",CategoryDictionary.getSauceItemPath("ff0000",1)); assertNotNull(new CategoryDictionary()); } diff --git a/src/test/java/net/tfminecraft/cooking/cache/SauceColourTest.java b/src/test/java/net/tfminecraft/cooking/cache/SauceColourTest.java index d6c32f7..07e52c3 100644 --- a/src/test/java/net/tfminecraft/cooking/cache/SauceColourTest.java +++ b/src/test/java/net/tfminecraft/cooking/cache/SauceColourTest.java @@ -15,16 +15,20 @@ class SauceColourTest { private static final String WATER = "ia.test:water"; + private static final String WATER_PLATED = "ia.test:water_plated"; private static final String MILK_PLATED = "ia.test:milk_plated"; private String previousFallback; + private String previousPlatedFallback; private HashMap previousDict; @BeforeEach void setUp() { previousFallback = ItemCache.liquidFallback; + previousPlatedFallback = ItemCache.platedLiquidFallback; previousDict = CategoryDictionary.sauceDict; ItemCache.liquidFallback = WATER; + ItemCache.platedLiquidFallback = WATER_PLATED; CategoryDictionary.sauceDict = new HashMap<>(); CategoryDictionary.sauceDict.put("ffffff", "ia.test:milk|" + MILK_PLATED); } @@ -32,6 +36,7 @@ void setUp() { @AfterEach void tearDown() { ItemCache.liquidFallback = previousFallback; + ItemCache.platedLiquidFallback = previousPlatedFallback; CategoryDictionary.sauceDict = previousDict; } @@ -52,23 +57,23 @@ void uncolouredMixesAreNamedWhite() { } @Test - void waterOnlySauceNameShowsTheWaterVisual() { + void waterOnlySauceNameShowsThePlatedWaterVisual() { String name = StringFormatter.formatHex( DisplayUtils.getNameColour(DisplayUtils.getMergedColour(List.of("000000"))) + "Mixed Sauce"); assertEquals("§fMixed Sauce", name); assertNull(StringFormatter.extractHexColor(name)); - assertEquals(WATER, CategoryDictionary.getSauceItemPath(StringFormatter.extractHexColor(name), 1)); + assertEquals(WATER_PLATED, CategoryDictionary.getSauceItemPath(StringFormatter.extractHexColor(name), CategoryDictionary.PLATED)); } @Test - void olderUncolouredSauceNameShowsTheWaterVisual() { - assertEquals(WATER, CategoryDictionary.getSauceItemPath(StringFormatter.extractHexColor("000000Mixed Sauce"), 1)); + void olderUncolouredSauceNameShowsThePlatedWaterVisual() { + assertEquals(WATER_PLATED, CategoryDictionary.getSauceItemPath(StringFormatter.extractHexColor("000000Mixed Sauce"), CategoryDictionary.PLATED)); } @Test void milkOnlySauceColourShowsTheMilkVisual() { // Scooping stores this merged colour on the ladle; the name alone can't carry it (Paper keeps #ffffff as named white). - assertEquals(MILK_PLATED, CategoryDictionary.getSauceItemPath(DisplayUtils.getMergedColour(List.of("ffffff")), 1)); + assertEquals(MILK_PLATED, CategoryDictionary.getSauceItemPath(DisplayUtils.getMergedColour(List.of("ffffff")), CategoryDictionary.PLATED)); } }