From 51003c4f72d174c2256e1238a902202c293c6fae Mon Sep 17 00:00:00 2001 From: MrTJP Date: Thu, 11 Apr 2024 14:07:48 -0400 Subject: [PATCH 1/5] fix: project bench shift-click dupe issues --- .../expansion/inventory/container/ProjectBenchContainer.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/expansion/src/main/java/mrtjp/projectred/expansion/inventory/container/ProjectBenchContainer.java b/expansion/src/main/java/mrtjp/projectred/expansion/inventory/container/ProjectBenchContainer.java index c826da88f..781d332ea 100644 --- a/expansion/src/main/java/mrtjp/projectred/expansion/inventory/container/ProjectBenchContainer.java +++ b/expansion/src/main/java/mrtjp/projectred/expansion/inventory/container/ProjectBenchContainer.java @@ -118,6 +118,10 @@ public ItemStack quickMoveStack(Player player, int slotIndex) { if (!moveToStorage(stack, true) && !moveToEntireInventory(stack, false)) return ItemStack.EMPTY; } else if (isResultSlot(slotIndex)) { + // Usualy, mayPickup is only queried once, and then this method is called repeatedly until EMPTY is returned. + // Since this slot is allowed to remain non-empty even after pickup is not possible, we must check this every time. + // See AbstractContainerMenu#doClick + if (!slot.mayPickup(player)) return ItemStack.EMPTY; if (!moveToEntireInventory(stack, true) && !moveToStorage(stack, true)) return ItemStack.EMPTY; } else if (isPlayerInventory(slotIndex) || isHotbar(slotIndex)) { From 84c979352df5d98f1f1b28624e511f2deb63d78e Mon Sep 17 00:00:00 2001 From: MrTJP Date: Thu, 11 Apr 2024 14:10:28 -0400 Subject: [PATCH 2/5] fix: project bench not crafting from grid once storage is empty --- .../projectred/expansion/CraftingHelper.java | 58 ++++++++----------- .../screen/inventory/ProjectBenchScreen.java | 14 ++--- .../expansion/tile/ProjectBenchTile.java | 5 ++ 3 files changed, 36 insertions(+), 41 deletions(-) diff --git a/expansion/src/main/java/mrtjp/projectred/expansion/CraftingHelper.java b/expansion/src/main/java/mrtjp/projectred/expansion/CraftingHelper.java index a5d6510d9..bb7dcc5c3 100644 --- a/expansion/src/main/java/mrtjp/projectred/expansion/CraftingHelper.java +++ b/expansion/src/main/java/mrtjp/projectred/expansion/CraftingHelper.java @@ -83,7 +83,7 @@ public void loadRecipe() { public void loadOutput() { - result = craftFromStorage(true); + result = craftFromStorageOrMatrix(true); } public boolean hasRecipe() { @@ -109,7 +109,7 @@ public int getMissingIngredientMask() { public boolean onCraftedByPlayer(Player player, boolean leaveRemainingInGrid) { if (recipe == null) return false; - CraftingResult result = craftFromStorage(false); + CraftingResult result = craftFromStorageOrMatrix(false); if (!result.isCraftable()) { return false; @@ -117,7 +117,6 @@ public boolean onCraftedByPlayer(Player player, boolean leaveRemainingInGrid) { // Re-obtain remaining items in case "setCraftingPlayer" changes remaining items ForgeHooks.setCraftingPlayer(player); -// NonNullList remainingStacks = player.level.getRecipeManager().getRemainingItemsFor(IRecipeType.CRAFTING, craftingInventory, player.level); NonNullList remainingStacks = recipe.getRemainingItems(craftingInventory); // Skip re-searching for recipe, should be ok ForgeHooks.setCraftingPlayer(null); @@ -155,7 +154,21 @@ public boolean onCraftedIntoStorage() { return true; } + private CraftingResult craftFromStorageOrMatrix(boolean simulate) { + CraftingResult result = craftFromStorage(simulate); + if (!result.isCraftable() && inputSource.canConsumeFromCraftingMatrix()) { + // TODO maybe merge the missingIngredientMasks of these two results? + result = craftFromSource(inputSource.getCraftingMatrix(), simulate); + } + // TODO Hybrid craft that consumes from both sources instead of one or the other? + return result; + } + private CraftingResult craftFromStorage(boolean simulate) { + return craftFromSource(inputSource.getStorage(), simulate); + } + + private CraftingResult craftFromSource(Container source, boolean simulate) { if (recipe == null) return CraftingResult.EMPTY; @@ -164,9 +177,8 @@ private CraftingResult craftFromStorage(boolean simulate) { ItemStack result = recipe.assemble(craftingInventory); if (result.isEmpty()) return CraftingResult.EMPTY; - Container storage = inputSource.getStorage(); if (simulate) { - storage = copyInventory(storage); + source = copyInventory(source); } // Try to consume all ingredients @@ -176,7 +188,7 @@ private CraftingResult craftFromStorage(boolean simulate) { ItemStack previousInput = craftingInventory.getItem(slot); if (previousInput.isEmpty()) continue; - boolean isPresent = consumeIngredient(storage, 0, input -> { + boolean isPresent = consumeIngredient(source, 0, input -> { // Candidate ingredient must be same item if (!input.sameItemStackIgnoreDurability(previousInput)) return false; @@ -199,31 +211,9 @@ private CraftingResult craftFromStorage(boolean simulate) { return CraftingResult.missingIngredients(missingIngredientMask); } - return new CraftingResult(result, recipe.getRemainingItems(craftingInventory), 0, simulate ? storage : copyInventory(storage)); + return new CraftingResult(result, recipe.getRemainingItems(craftingInventory), 0, simulate ? source : copyInventory(source)); } -// private boolean insertResultsIntoInventory(NonNullList inventory, boolean simulate) { -// if (result.outputStack.isEmpty() || result.missingIngredientMask != 0) { -// return false; -// } -// -// IInventory storage = copyInventory(result.remainingStorage); -// -// // Try to insert into remaining storage -// ItemStack output = outputStack.copy(); -// InventoryLib.injectItemStack(storage, output, true); -// if (!output.isEmpty()) return false; -// -// // Try to insert remaining items -// for (ItemStack stack : remainingItems) { -// ItemStack remaining = stack.copy(); -// InventoryLib.injectItemStack(storage, remaining, true); -// if (!remaining.isEmpty()) return false; -// } -// -// return true; -// } - private boolean consumeIngredient(Container storage, int startIndex, Predicate matchFunc) { int i = startIndex; @@ -250,7 +240,7 @@ private static Container copyInventory(Container inventory) { return copy; } - private static class CraftingResult { + private static final class CraftingResult { private static final CraftingResult EMPTY = new CraftingResult(ItemStack.EMPTY, NonNullList.create(), 0, null); @@ -294,10 +284,6 @@ private boolean canFitResultsIntoStorage() { return InventoryLib.injectAllItemStacks(storage, getCopyOfAllResults(), true); } - public static CraftingResult empty() { - return EMPTY; - } - public static CraftingResult missingIngredients(int missingIngredientMask) { return new CraftingResult(ItemStack.EMPTY, NonNullList.create(), missingIngredientMask, null); } @@ -309,6 +295,10 @@ public interface InventorySource { Container getStorage(); + default boolean canConsumeFromCraftingMatrix() { + return false; + } + Level getWorld(); // Required for recipe lookup } } diff --git a/expansion/src/main/java/mrtjp/projectred/expansion/gui/screen/inventory/ProjectBenchScreen.java b/expansion/src/main/java/mrtjp/projectred/expansion/gui/screen/inventory/ProjectBenchScreen.java index 66b7bcc9e..2d43fafb3 100644 --- a/expansion/src/main/java/mrtjp/projectred/expansion/gui/screen/inventory/ProjectBenchScreen.java +++ b/expansion/src/main/java/mrtjp/projectred/expansion/gui/screen/inventory/ProjectBenchScreen.java @@ -13,6 +13,7 @@ import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.Container; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; @@ -77,10 +78,9 @@ public void drawBack(PoseStack stack, Point mouse, float partialFrame) { blit(stack, x, y, 0, 0, getFrame().width(), getFrame().height()); ProjectBenchTile tile = getMenu().getProjectBenchTile(); - ItemStack plan = tile.getPlanInventory().getItem(0); - if (!plan.isEmpty() && tile.isPlanRecipe()) { - ItemStack[] inputs = RecipePlanItem.loadPlanInputs(plan); - int missingMask = getMenu().getProjectBenchTile().getCraftingHelper().getMissingIngredientMask(); + if (tile.isPlanRecipe()) { + int missingMask = tile.getCraftingHelper().getMissingIngredientMask(); + Container inputs = tile.getCraftingHelper().getCraftingInventory(); drawPlanIngredientsOverlay(stack, inputs, missingMask, x + 48, y + 18); } } @@ -93,7 +93,7 @@ public void drawFront(PoseStack stack, Point mouse, float partialFrame) { } } - private void drawPlanIngredientsOverlay(PoseStack mStack, ItemStack[] ingredients, int missingMask, int xPos, int yPos) { + private void drawPlanIngredientsOverlay(PoseStack mStack, Container ingredients, int missingMask, int xPos, int yPos) { for (int y = 0; y < 3; y++) { for (int x = 0; x < 3; x++) { @@ -101,8 +101,8 @@ private void drawPlanIngredientsOverlay(PoseStack mStack, ItemStack[] ingredient int drawPosY = yPos + (y * 18); int index = (y * 3) + x; - ItemStack ingredient = ingredients[index]; - int colour = (missingMask & 1 << index) != 0 ? EnumColour.RED.argb() : EnumColour.GRAY.argb(); + ItemStack ingredient = ingredients.getItem(index); + int colour = (missingMask & 1 << index) != 0 ? EnumColour.RED.argb(0x77) : EnumColour.GRAY.argb(0x77); if (!ingredient.isEmpty()) { fillGradient(mStack, drawPosX, drawPosY, drawPosX + 16, drawPosY + 16, colour, colour); diff --git a/expansion/src/main/java/mrtjp/projectred/expansion/tile/ProjectBenchTile.java b/expansion/src/main/java/mrtjp/projectred/expansion/tile/ProjectBenchTile.java index c5e7d60a4..d1441078c 100644 --- a/expansion/src/main/java/mrtjp/projectred/expansion/tile/ProjectBenchTile.java +++ b/expansion/src/main/java/mrtjp/projectred/expansion/tile/ProjectBenchTile.java @@ -230,6 +230,11 @@ public Container getStorage() { return storageInventory; } + @Override + public boolean canConsumeFromCraftingMatrix() { + return !isPlanRecipe; + } + @Override public Level getWorld() { return getLevel(); From dc8e8df45631c783ee72d7518790eda4cd0ebc1a Mon Sep 17 00:00:00 2001 From: MrTJP Date: Fri, 12 Apr 2024 12:54:12 -0400 Subject: [PATCH 3/5] fix: world gen features not respecting config file settings --- .../mrtjp/projectred/core/Configurator.java | 48 ++- .../8334375f2c689bc1064105fb5f28a68385b7f9ae | 11 +- .../add_electrotine_ore_to_overworld.json | 62 ++++ ...json => add_marble_cave_to_overworld.json} | 1 + .../biome_modifier/add_overworld_ores.json | 313 ------------------ .../add_peridot_ore_to_overworld.json | 56 ++++ .../add_ruby_ore_to_overworld.json | 56 ++++ .../add_sapphire_ore_to_overworld.json | 56 ++++ .../add_silver_ore_to_overworld.json | 56 ++++ .../add_tin_ore_to_overworld.json | 56 ++++ .../exploration/ProjectRedExploration.java | 6 + .../init/ExplorationWorldFeatures.java | 49 ++- .../world/gen/AddCarversBiomeModifier.java | 39 --- ...FileControlledAddCarversBiomeModifier.java | 49 +++ ...ileControlledAddFeaturesBiomeModifier.java | 49 +++ 15 files changed, 501 insertions(+), 406 deletions(-) create mode 100644 exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_electrotine_ore_to_overworld.json rename exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/{add_overworld_carvers.json => add_marble_cave_to_overworld.json} (98%) delete mode 100644 exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_overworld_ores.json create mode 100644 exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_peridot_ore_to_overworld.json create mode 100644 exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_ruby_ore_to_overworld.json create mode 100644 exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_sapphire_ore_to_overworld.json create mode 100644 exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_silver_ore_to_overworld.json create mode 100644 exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_tin_ore_to_overworld.json delete mode 100644 exploration/src/main/java/mrtjp/projectred/exploration/world/gen/AddCarversBiomeModifier.java create mode 100644 exploration/src/main/java/mrtjp/projectred/exploration/world/gen/ConfigFileControlledAddCarversBiomeModifier.java create mode 100644 exploration/src/main/java/mrtjp/projectred/exploration/world/gen/ConfigFileControlledAddFeaturesBiomeModifier.java diff --git a/core/src/main/java/mrtjp/projectred/core/Configurator.java b/core/src/main/java/mrtjp/projectred/core/Configurator.java index 762b40897..ad7f2d1cf 100644 --- a/core/src/main/java/mrtjp/projectred/core/Configurator.java +++ b/core/src/main/java/mrtjp/projectred/core/Configurator.java @@ -4,6 +4,8 @@ import codechicken.lib.config.ConfigFile; import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; import static mrtjp.projectred.core.ProjectRedCore.MOD_ID; @@ -27,19 +29,21 @@ public class Configurator { public static boolean fabulousLights = true; /* World Gen */ + public static String rubyOreKey = "ruby_ore"; + public static String sapphireOreKey = "sapphire_ore"; + public static String peridotOreKey = "peridot_ore"; + public static String tinOreKey = "tin_ore"; + public static String silverOreKey = "silver_ore"; + public static String electrotineOreKey = "electrotine_ore"; + public static String marbleCaveKey = "marble_cave"; public static boolean gen_MarbleCave = true; public static boolean gen_Ruby = true; - public static int gen_RubyVeinSize = 8; public static boolean gen_Sapphire = true; - public static int gen_SapphireVeinSize = 8; public static boolean gen_Peridot = true; - public static int gen_PeridotVeinSize = 10; public static boolean gen_Tin = true; - public static int gen_TinVeinSize = 8; public static boolean gen_Silver = true; - public static int gen_SilverVeinSize = 9; public static boolean gen_Electrotine = true; - public static int gen_ElectrotineVeinSize = 8; + public static Map worldFeatures = new HashMap<>(); /* Compatibility */ public static boolean compat_CCBundledCable = true; @@ -54,6 +58,12 @@ public static void load() { config.save(); } + private static boolean loadAndStoreFeature(ConfigCategory gen, String key, boolean def) { + boolean value = gen.getValue(key).setDefaultBoolean(def).getBoolean(); + worldFeatures.put(key, value); + return value; + } + private static void loadValues(ConfigCategory config) { //TODO remove later @@ -77,19 +87,13 @@ private static void loadValues(ConfigCategory config) { fabulousLights = rendering.getValue("fabulous_lights").setDefaultBoolean(fabulousLights).setComment("Use fabulous shader pipeline for lights when on Fabulous Graphics mode").getBoolean(); ConfigCategory gen = config.getCategory("world_gen").setComment("World gen settings"); - gen_Ruby = gen.getValue("ruby_ore").setDefaultBoolean(gen_Ruby).setComment("Enable Ruby Ore generation").getBoolean(); - gen_RubyVeinSize = gen.getValue("ruby_ore_vein_size").setDefaultInt(gen_RubyVeinSize).setComment("Ruby Ore vein size").getInt(); - gen_Sapphire = gen.getValue("sapphire_ore").setDefaultBoolean(gen_Sapphire).setComment("Enable Sapphire Ore generation").getBoolean(); - gen_SapphireVeinSize = gen.getValue("sapphire_ore_vein_size").setDefaultInt(gen_SapphireVeinSize).setComment("Sapphire Ore vein size").getInt(); - gen_Peridot = gen.getValue("peridot_ore").setDefaultBoolean(gen_Peridot).setComment("Enable Peridot Ore generation").getBoolean(); - gen_PeridotVeinSize = gen.getValue("peridot_ore_vein_size").setDefaultInt(gen_PeridotVeinSize).setComment("Peridot Ore vein size").getInt(); - gen_Tin = gen.getValue("tin_ore").setDefaultBoolean(gen_Tin).setComment("Enable Tin Ore generation").getBoolean(); - gen_TinVeinSize = gen.getValue("tin_ore_vein_size").setDefaultInt(gen_TinVeinSize).setComment("Tin Ore vein size").getInt(); - gen_Silver = gen.getValue("silver_ore").setDefaultBoolean(gen_Silver).setComment("Enable Silver Ore generation").getBoolean(); - gen_SilverVeinSize = gen.getValue("silver_ore_vein_size").setDefaultInt(gen_SilverVeinSize).setComment("Silver Ore vein size").getInt(); - gen_Electrotine = gen.getValue("electrotine_ore").setDefaultBoolean(gen_Electrotine).setComment("Enable Electrotine Ore generation").getBoolean(); - gen_ElectrotineVeinSize = gen.getValue("electrotine_ore_vein_size").setDefaultInt(gen_ElectrotineVeinSize).setComment("Electrotine Ore vein size").getInt(); - gen_MarbleCave = gen.getValue("marble_cave").setDefaultBoolean(gen_MarbleCave).setComment("Enable Marble Cave generation").getBoolean(); + gen_Ruby = loadAndStoreFeature(gen, rubyOreKey, true); + gen_Sapphire = loadAndStoreFeature(gen, sapphireOreKey, true); + gen_Peridot = loadAndStoreFeature(gen, peridotOreKey, true); + gen_Tin = loadAndStoreFeature(gen, tinOreKey, true); + gen_Silver = loadAndStoreFeature(gen, silverOreKey, true); + gen_Electrotine = loadAndStoreFeature(gen, electrotineOreKey, true); + gen_MarbleCave = loadAndStoreFeature(gen, marbleCaveKey, true); ConfigCategory compat = config.getCategory("compatibility").setComment("Control the loading of various compatibility hooks. These settings are ignored unless the Compatibility module is installed."); compat_CCBundledCable = compat.getValue("computercraft").setDefaultBoolean(compat_CCBundledCable).setComment("This allows computers to connect to bundled cables with the RS API.").getBoolean(); @@ -123,17 +127,11 @@ private static void loadAndDeleteLegacyValues(ConfigCategory config) { ConfigCategory gen = config.getCategory("World Gen"); gen_Ruby = gen.getValue("Ruby Ore").setDefaultBoolean(gen_Ruby).getBoolean(); - gen_RubyVeinSize = gen.getValue("Ruby Ore vein size").setDefaultInt(gen_RubyVeinSize).getInt(); gen_Sapphire = gen.getValue("Sapphire Ore").setDefaultBoolean(gen_Sapphire).getBoolean(); - gen_SapphireVeinSize = gen.getValue("Sapphire Ore vein size").setDefaultInt(gen_SapphireVeinSize).getInt(); gen_Peridot = gen.getValue("Peridot Ore").setDefaultBoolean(gen_Peridot).getBoolean(); - gen_PeridotVeinSize = gen.getValue("Peridot Ore vein size").setDefaultInt(gen_PeridotVeinSize).getInt(); gen_Tin = gen.getValue("Tin Ore").setDefaultBoolean(gen_Tin).getBoolean(); - gen_TinVeinSize = gen.getValue("Tin Ore vein size").setDefaultInt(gen_TinVeinSize).getInt(); gen_Silver = gen.getValue("Silver Ore").setDefaultBoolean(gen_Silver).getBoolean(); - gen_SilverVeinSize = gen.getValue("Silver Ore vein size").setDefaultInt(gen_SilverVeinSize).getInt(); gen_Electrotine = gen.getValue("Electrotine Ore").setDefaultBoolean(gen_Electrotine).getBoolean(); - gen_ElectrotineVeinSize = gen.getValue("Electrotine Ore vein size").setDefaultInt(gen_ElectrotineVeinSize).getInt(); gen_MarbleCave = gen.getValue("Marble Caves").setDefaultBoolean(gen_MarbleCave).getBoolean(); ConfigCategory compat = config.getCategory("Compatibility"); diff --git a/exploration/src/main/generated/.cache/8334375f2c689bc1064105fb5f28a68385b7f9ae b/exploration/src/main/generated/.cache/8334375f2c689bc1064105fb5f28a68385b7f9ae index ccd0f7deb..74bab02fa 100644 --- a/exploration/src/main/generated/.cache/8334375f2c689bc1064105fb5f28a68385b7f9ae +++ b/exploration/src/main/generated/.cache/8334375f2c689bc1064105fb5f28a68385b7f9ae @@ -1,3 +1,8 @@ -// 1.19.2 2024-03-04T11:32:53.74826 forge/biome_modifier generator for projectred_exploration -d945627f6efcd004553c4907dafa754afd32182e data/projectred_exploration/forge/biome_modifier/add_overworld_carvers.json -867d7ebae686f787cde12b48c638e594733e28ae data/projectred_exploration/forge/biome_modifier/add_overworld_ores.json +// 1.19.2 2024-04-12T12:50:48.118367 forge/biome_modifier generator for projectred_exploration +a9ee4e4ea7ce9d6a5e98587da776a55196704fa2 data/projectred_exploration/forge/biome_modifier/add_electrotine_ore_to_overworld.json +b040a155acc4c4c41dadb18f3a2a8d514cf7cd22 data/projectred_exploration/forge/biome_modifier/add_marble_cave_to_overworld.json +d44596fde99ef0bd30d0ead290049c629e8b74b1 data/projectred_exploration/forge/biome_modifier/add_peridot_ore_to_overworld.json +bdc09c896ef2863532a7ef17a2e3567274819eef data/projectred_exploration/forge/biome_modifier/add_ruby_ore_to_overworld.json +691f03827983499ee1547931cc06a5cfbecb3349 data/projectred_exploration/forge/biome_modifier/add_sapphire_ore_to_overworld.json +05ade71ce944b91d3b8309ba9b396cef7377b64a data/projectred_exploration/forge/biome_modifier/add_silver_ore_to_overworld.json +c4f8a9b2d88c1b62f59e68aca1d58249ffe5c0cf data/projectred_exploration/forge/biome_modifier/add_tin_ore_to_overworld.json diff --git a/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_electrotine_ore_to_overworld.json b/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_electrotine_ore_to_overworld.json new file mode 100644 index 000000000..316d6b489 --- /dev/null +++ b/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_electrotine_ore_to_overworld.json @@ -0,0 +1,62 @@ +{ + "type": "projectred_exploration:add_features", + "biomes": "#minecraft:is_overworld", + "configKey": "electrotine_ore", + "features": { + "feature": { + "type": "minecraft:ore", + "config": { + "discard_chance_on_air_exposure": 0.0, + "size": 8, + "targets": [ + { + "state": { + "Name": "projectred_exploration:electrotine_ore", + "Properties": { + "lit": "false" + } + }, + "target": { + "predicate_type": "minecraft:tag_match", + "tag": "minecraft:stone_ore_replaceables" + } + }, + { + "state": { + "Name": "projectred_exploration:deepslate_electrotine_ore", + "Properties": { + "lit": "false" + } + }, + "target": { + "predicate_type": "minecraft:tag_match", + "tag": "minecraft:deepslate_ore_replaceables" + } + } + ] + } + }, + "placement": [ + { + "type": "minecraft:count", + "count": 4 + }, + { + "type": "minecraft:in_square" + }, + { + "type": "minecraft:height_range", + "height": { + "type": "minecraft:trapezoid", + "max_inclusive": { + "absolute": 32 + }, + "min_inclusive": { + "absolute": -32 + } + } + } + ] + }, + "step": "underground_ores" +} \ No newline at end of file diff --git a/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_overworld_carvers.json b/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_marble_cave_to_overworld.json similarity index 98% rename from exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_overworld_carvers.json rename to exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_marble_cave_to_overworld.json index 67c96e80d..5f3c88cf2 100644 --- a/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_overworld_carvers.json +++ b/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_marble_cave_to_overworld.json @@ -72,5 +72,6 @@ } } }, + "configKey": "marble_cave", "step": "air" } \ No newline at end of file diff --git a/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_overworld_ores.json b/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_overworld_ores.json deleted file mode 100644 index 488baea53..000000000 --- a/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_overworld_ores.json +++ /dev/null @@ -1,313 +0,0 @@ -{ - "type": "forge:add_features", - "biomes": "#minecraft:is_overworld", - "features": [ - { - "feature": { - "type": "minecraft:ore", - "config": { - "discard_chance_on_air_exposure": 0.0, - "size": 8, - "targets": [ - { - "state": { - "Name": "projectred_exploration:ruby_ore" - }, - "target": { - "predicate_type": "minecraft:tag_match", - "tag": "minecraft:stone_ore_replaceables" - } - }, - { - "state": { - "Name": "projectred_exploration:deepslate_ruby_ore" - }, - "target": { - "predicate_type": "minecraft:tag_match", - "tag": "minecraft:deepslate_ore_replaceables" - } - } - ] - } - }, - "placement": [ - { - "type": "minecraft:count", - "count": 1 - }, - { - "type": "minecraft:in_square" - }, - { - "type": "minecraft:height_range", - "height": { - "type": "minecraft:trapezoid", - "max_inclusive": { - "absolute": 80 - }, - "min_inclusive": { - "absolute": -80 - } - } - } - ] - }, - { - "feature": { - "type": "minecraft:ore", - "config": { - "discard_chance_on_air_exposure": 0.0, - "size": 8, - "targets": [ - { - "state": { - "Name": "projectred_exploration:sapphire_ore" - }, - "target": { - "predicate_type": "minecraft:tag_match", - "tag": "minecraft:stone_ore_replaceables" - } - }, - { - "state": { - "Name": "projectred_exploration:deepslate_sapphire_ore" - }, - "target": { - "predicate_type": "minecraft:tag_match", - "tag": "minecraft:deepslate_ore_replaceables" - } - } - ] - } - }, - "placement": [ - { - "type": "minecraft:count", - "count": 1 - }, - { - "type": "minecraft:in_square" - }, - { - "type": "minecraft:height_range", - "height": { - "type": "minecraft:trapezoid", - "max_inclusive": { - "absolute": 80 - }, - "min_inclusive": { - "absolute": -80 - } - } - } - ] - }, - { - "feature": { - "type": "minecraft:ore", - "config": { - "discard_chance_on_air_exposure": 0.0, - "size": 10, - "targets": [ - { - "state": { - "Name": "projectred_exploration:peridot_ore" - }, - "target": { - "predicate_type": "minecraft:tag_match", - "tag": "minecraft:stone_ore_replaceables" - } - }, - { - "state": { - "Name": "projectred_exploration:deepslate_peridot_ore" - }, - "target": { - "predicate_type": "minecraft:tag_match", - "tag": "minecraft:deepslate_ore_replaceables" - } - } - ] - } - }, - "placement": [ - { - "type": "minecraft:count", - "count": 1 - }, - { - "type": "minecraft:in_square" - }, - { - "type": "minecraft:height_range", - "height": { - "type": "minecraft:trapezoid", - "max_inclusive": { - "absolute": 80 - }, - "min_inclusive": { - "absolute": -80 - } - } - } - ] - }, - { - "feature": { - "type": "minecraft:ore", - "config": { - "discard_chance_on_air_exposure": 0.0, - "size": 8, - "targets": [ - { - "state": { - "Name": "projectred_exploration:electrotine_ore", - "Properties": { - "lit": "false" - } - }, - "target": { - "predicate_type": "minecraft:tag_match", - "tag": "minecraft:stone_ore_replaceables" - } - }, - { - "state": { - "Name": "projectred_exploration:deepslate_electrotine_ore", - "Properties": { - "lit": "false" - } - }, - "target": { - "predicate_type": "minecraft:tag_match", - "tag": "minecraft:deepslate_ore_replaceables" - } - } - ] - } - }, - "placement": [ - { - "type": "minecraft:count", - "count": 4 - }, - { - "type": "minecraft:in_square" - }, - { - "type": "minecraft:height_range", - "height": { - "type": "minecraft:trapezoid", - "max_inclusive": { - "absolute": 32 - }, - "min_inclusive": { - "absolute": -32 - } - } - } - ] - }, - { - "feature": { - "type": "minecraft:ore", - "config": { - "discard_chance_on_air_exposure": 0.0, - "size": 8, - "targets": [ - { - "state": { - "Name": "projectred_exploration:tin_ore" - }, - "target": { - "predicate_type": "minecraft:tag_match", - "tag": "minecraft:stone_ore_replaceables" - } - }, - { - "state": { - "Name": "projectred_exploration:deepslate_tin_ore" - }, - "target": { - "predicate_type": "minecraft:tag_match", - "tag": "minecraft:deepslate_ore_replaceables" - } - } - ] - } - }, - "placement": [ - { - "type": "minecraft:count", - "count": 8 - }, - { - "type": "minecraft:in_square" - }, - { - "type": "minecraft:height_range", - "height": { - "type": "minecraft:trapezoid", - "max_inclusive": { - "absolute": 56 - }, - "min_inclusive": { - "absolute": -24 - } - } - } - ] - }, - { - "feature": { - "type": "minecraft:ore", - "config": { - "discard_chance_on_air_exposure": 0.0, - "size": 9, - "targets": [ - { - "state": { - "Name": "projectred_exploration:silver_ore" - }, - "target": { - "predicate_type": "minecraft:tag_match", - "tag": "minecraft:stone_ore_replaceables" - } - }, - { - "state": { - "Name": "projectred_exploration:deepslate_silver_ore" - }, - "target": { - "predicate_type": "minecraft:tag_match", - "tag": "minecraft:deepslate_ore_replaceables" - } - } - ] - } - }, - "placement": [ - { - "type": "minecraft:count", - "count": 6 - }, - { - "type": "minecraft:in_square" - }, - { - "type": "minecraft:height_range", - "height": { - "type": "minecraft:trapezoid", - "max_inclusive": { - "absolute": 32 - }, - "min_inclusive": { - "absolute": -64 - } - } - } - ] - } - ], - "step": "underground_ores" -} \ No newline at end of file diff --git a/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_peridot_ore_to_overworld.json b/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_peridot_ore_to_overworld.json new file mode 100644 index 000000000..9bb2e7cbb --- /dev/null +++ b/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_peridot_ore_to_overworld.json @@ -0,0 +1,56 @@ +{ + "type": "projectred_exploration:add_features", + "biomes": "#minecraft:is_overworld", + "configKey": "peridot_ore", + "features": { + "feature": { + "type": "minecraft:ore", + "config": { + "discard_chance_on_air_exposure": 0.0, + "size": 10, + "targets": [ + { + "state": { + "Name": "projectred_exploration:peridot_ore" + }, + "target": { + "predicate_type": "minecraft:tag_match", + "tag": "minecraft:stone_ore_replaceables" + } + }, + { + "state": { + "Name": "projectred_exploration:deepslate_peridot_ore" + }, + "target": { + "predicate_type": "minecraft:tag_match", + "tag": "minecraft:deepslate_ore_replaceables" + } + } + ] + } + }, + "placement": [ + { + "type": "minecraft:count", + "count": 1 + }, + { + "type": "minecraft:in_square" + }, + { + "type": "minecraft:height_range", + "height": { + "type": "minecraft:trapezoid", + "max_inclusive": { + "absolute": 80 + }, + "min_inclusive": { + "absolute": -80 + } + } + } + ] + }, + "step": "underground_ores" +} \ No newline at end of file diff --git a/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_ruby_ore_to_overworld.json b/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_ruby_ore_to_overworld.json new file mode 100644 index 000000000..306439ac0 --- /dev/null +++ b/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_ruby_ore_to_overworld.json @@ -0,0 +1,56 @@ +{ + "type": "projectred_exploration:add_features", + "biomes": "#minecraft:is_overworld", + "configKey": "ruby_ore", + "features": { + "feature": { + "type": "minecraft:ore", + "config": { + "discard_chance_on_air_exposure": 0.0, + "size": 8, + "targets": [ + { + "state": { + "Name": "projectred_exploration:ruby_ore" + }, + "target": { + "predicate_type": "minecraft:tag_match", + "tag": "minecraft:stone_ore_replaceables" + } + }, + { + "state": { + "Name": "projectred_exploration:deepslate_ruby_ore" + }, + "target": { + "predicate_type": "minecraft:tag_match", + "tag": "minecraft:deepslate_ore_replaceables" + } + } + ] + } + }, + "placement": [ + { + "type": "minecraft:count", + "count": 1 + }, + { + "type": "minecraft:in_square" + }, + { + "type": "minecraft:height_range", + "height": { + "type": "minecraft:trapezoid", + "max_inclusive": { + "absolute": 80 + }, + "min_inclusive": { + "absolute": -80 + } + } + } + ] + }, + "step": "underground_ores" +} \ No newline at end of file diff --git a/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_sapphire_ore_to_overworld.json b/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_sapphire_ore_to_overworld.json new file mode 100644 index 000000000..9c68a38d6 --- /dev/null +++ b/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_sapphire_ore_to_overworld.json @@ -0,0 +1,56 @@ +{ + "type": "projectred_exploration:add_features", + "biomes": "#minecraft:is_overworld", + "configKey": "sapphire_ore", + "features": { + "feature": { + "type": "minecraft:ore", + "config": { + "discard_chance_on_air_exposure": 0.0, + "size": 8, + "targets": [ + { + "state": { + "Name": "projectred_exploration:sapphire_ore" + }, + "target": { + "predicate_type": "minecraft:tag_match", + "tag": "minecraft:stone_ore_replaceables" + } + }, + { + "state": { + "Name": "projectred_exploration:deepslate_sapphire_ore" + }, + "target": { + "predicate_type": "minecraft:tag_match", + "tag": "minecraft:deepslate_ore_replaceables" + } + } + ] + } + }, + "placement": [ + { + "type": "minecraft:count", + "count": 1 + }, + { + "type": "minecraft:in_square" + }, + { + "type": "minecraft:height_range", + "height": { + "type": "minecraft:trapezoid", + "max_inclusive": { + "absolute": 80 + }, + "min_inclusive": { + "absolute": -80 + } + } + } + ] + }, + "step": "underground_ores" +} \ No newline at end of file diff --git a/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_silver_ore_to_overworld.json b/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_silver_ore_to_overworld.json new file mode 100644 index 000000000..cb8dc7777 --- /dev/null +++ b/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_silver_ore_to_overworld.json @@ -0,0 +1,56 @@ +{ + "type": "projectred_exploration:add_features", + "biomes": "#minecraft:is_overworld", + "configKey": "silver_ore", + "features": { + "feature": { + "type": "minecraft:ore", + "config": { + "discard_chance_on_air_exposure": 0.0, + "size": 9, + "targets": [ + { + "state": { + "Name": "projectred_exploration:silver_ore" + }, + "target": { + "predicate_type": "minecraft:tag_match", + "tag": "minecraft:stone_ore_replaceables" + } + }, + { + "state": { + "Name": "projectred_exploration:deepslate_silver_ore" + }, + "target": { + "predicate_type": "minecraft:tag_match", + "tag": "minecraft:deepslate_ore_replaceables" + } + } + ] + } + }, + "placement": [ + { + "type": "minecraft:count", + "count": 6 + }, + { + "type": "minecraft:in_square" + }, + { + "type": "minecraft:height_range", + "height": { + "type": "minecraft:trapezoid", + "max_inclusive": { + "absolute": 32 + }, + "min_inclusive": { + "absolute": -64 + } + } + } + ] + }, + "step": "underground_ores" +} \ No newline at end of file diff --git a/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_tin_ore_to_overworld.json b/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_tin_ore_to_overworld.json new file mode 100644 index 000000000..a37714b5d --- /dev/null +++ b/exploration/src/main/generated/data/projectred_exploration/forge/biome_modifier/add_tin_ore_to_overworld.json @@ -0,0 +1,56 @@ +{ + "type": "projectred_exploration:add_features", + "biomes": "#minecraft:is_overworld", + "configKey": "tin_ore", + "features": { + "feature": { + "type": "minecraft:ore", + "config": { + "discard_chance_on_air_exposure": 0.0, + "size": 8, + "targets": [ + { + "state": { + "Name": "projectred_exploration:tin_ore" + }, + "target": { + "predicate_type": "minecraft:tag_match", + "tag": "minecraft:stone_ore_replaceables" + } + }, + { + "state": { + "Name": "projectred_exploration:deepslate_tin_ore" + }, + "target": { + "predicate_type": "minecraft:tag_match", + "tag": "minecraft:deepslate_ore_replaceables" + } + } + ] + } + }, + "placement": [ + { + "type": "minecraft:count", + "count": 8 + }, + { + "type": "minecraft:in_square" + }, + { + "type": "minecraft:height_range", + "height": { + "type": "minecraft:trapezoid", + "max_inclusive": { + "absolute": 56 + }, + "min_inclusive": { + "absolute": -24 + } + } + } + ] + }, + "step": "underground_ores" +} \ No newline at end of file diff --git a/exploration/src/main/java/mrtjp/projectred/exploration/ProjectRedExploration.java b/exploration/src/main/java/mrtjp/projectred/exploration/ProjectRedExploration.java index e4023b537..f1ef4f029 100644 --- a/exploration/src/main/java/mrtjp/projectred/exploration/ProjectRedExploration.java +++ b/exploration/src/main/java/mrtjp/projectred/exploration/ProjectRedExploration.java @@ -6,6 +6,7 @@ import com.mojang.serialization.Codec; import mrtjp.projectred.exploration.data.*; import mrtjp.projectred.exploration.init.*; +import net.minecraft.core.Registry; import net.minecraft.data.DataGenerator; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.MenuType; @@ -14,6 +15,9 @@ import net.minecraft.world.item.crafting.RecipeSerializer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.levelgen.carver.WorldCarver; +import net.minecraft.world.level.levelgen.placement.PlacementFilter; +import net.minecraft.world.level.levelgen.placement.PlacementModifier; +import net.minecraft.world.level.levelgen.placement.PlacementModifierType; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.data.ExistingFileHelper; import net.minecraftforge.common.world.BiomeModifier; @@ -42,6 +46,8 @@ public class ProjectRedExploration { public static final DeferredRegister> RECIPE_SERIALIZERS = DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, MOD_ID); public static final DeferredRegister MICRO_MATERIALS = DeferredRegister.create(new ResourceLocation(CBMicroblock.MOD_ID, "micro_material"), MOD_ID); + public static final DeferredRegister> PLACEMENT_MODIFIERS = DeferredRegister.create(Registry.PLACEMENT_MODIFIER_REGISTRY, MOD_ID); + public static final SimpleCreativeTab EXPLORATION_CREATIVE_TAB = new SimpleCreativeTab(MOD_ID, () -> new ItemStack(MARBLE_BRICK_BLOCK.get())); static { diff --git a/exploration/src/main/java/mrtjp/projectred/exploration/init/ExplorationWorldFeatures.java b/exploration/src/main/java/mrtjp/projectred/exploration/init/ExplorationWorldFeatures.java index 2cfed4bad..9f7f20443 100644 --- a/exploration/src/main/java/mrtjp/projectred/exploration/init/ExplorationWorldFeatures.java +++ b/exploration/src/main/java/mrtjp/projectred/exploration/init/ExplorationWorldFeatures.java @@ -5,7 +5,8 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; import mrtjp.projectred.core.Configurator; -import mrtjp.projectred.exploration.world.gen.AddCarversBiomeModifier; +import mrtjp.projectred.exploration.world.gen.ConfigFileControlledAddCarversBiomeModifier; +import mrtjp.projectred.exploration.world.gen.ConfigFileControlledAddFeaturesBiomeModifier; import mrtjp.projectred.exploration.world.gen.MarbleCaveWorldCarver; import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; @@ -35,7 +36,6 @@ import net.minecraftforge.common.data.ExistingFileHelper; import net.minecraftforge.common.data.JsonCodecProvider; import net.minecraftforge.common.world.BiomeModifier; -import net.minecraftforge.common.world.ForgeBiomeModifiers; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegistryObject; @@ -55,7 +55,8 @@ public class ExplorationWorldFeatures { public static RegistryObject> MARBLE_CAVE_CARVER; // Biome Modifier Codecs - public static RegistryObject> ADD_CARVER_BIOME_MODIFIER_CODEC; + public static RegistryObject> ADD_CARVER_BIOME_MODIFIER_CODEC; + public static RegistryObject> ADD_FEATURES_BIOME_MODIFIER_CODEC; public static void register() { @@ -65,8 +66,9 @@ public static void register() { // Features // None yet. For custom ores, we register a configured variant of Vanilla Feature.ORE - // Codecs (since forge doesnt provide a default "Add Carvers" biome modifier) - ADD_CARVER_BIOME_MODIFIER_CODEC = BIOME_MODIFIER_SERIALIZERS.register("add_carver", () -> AddCarversBiomeModifier.CODEC); + // Codecs + ADD_CARVER_BIOME_MODIFIER_CODEC = BIOME_MODIFIER_SERIALIZERS.register("add_carver", ConfigFileControlledAddCarversBiomeModifier::createCodec); + ADD_FEATURES_BIOME_MODIFIER_CODEC = BIOME_MODIFIER_SERIALIZERS.register("add_features", ConfigFileControlledAddFeaturesBiomeModifier::createCodec); } public static JsonCodecProvider biomeModifiersProvider(DataGenerator dataGenerator, ExistingFileHelper existingFileHelper) { @@ -88,12 +90,12 @@ public static JsonCodecProvider biomeModifiersProvider(DataGenera UniformFloat.of(-1.0F, -0.4F))); // floor level // Configured ores - ConfiguredFeature rubyOreConfiguration = createOreConfiguration(RUBY_ORE_BLOCK, DEEPSLATE_RUBY_ORE_BLOCK, Configurator.gen_RubyVeinSize); - ConfiguredFeature sapphireOreConfiguration = createOreConfiguration(SAPPHIRE_ORE_BLOCK, DEEPSLATE_SAPPHIRE_ORE_BLOCK, Configurator.gen_SapphireVeinSize); - ConfiguredFeature peridotOreConfiguration = createOreConfiguration(PERIDOT_ORE_BLOCK, DEEPSLATE_PERIDOT_ORE_BLOCK, Configurator.gen_PeridotVeinSize); - ConfiguredFeature electrotineOreConfiguration = createOreConfiguration(ELECTROTINE_ORE_BLOCK, DEEPSLATE_ELECTROTINE_ORE_BLOCK, Configurator.gen_ElectrotineVeinSize); - ConfiguredFeature tinOreConfiguration = createOreConfiguration(TIN_ORE_BLOCK, DEEPSLATE_TIN_ORE_BLOCK, Configurator.gen_TinVeinSize); - ConfiguredFeature silverOreConfiguration = createOreConfiguration(SILVER_ORE_BLOCK, DEEPSLATE_SILVER_ORE_BLOCK, Configurator.gen_SilverVeinSize); + ConfiguredFeature rubyOreConfiguration = createOreConfiguration(RUBY_ORE_BLOCK, DEEPSLATE_RUBY_ORE_BLOCK, 8); + ConfiguredFeature sapphireOreConfiguration = createOreConfiguration(SAPPHIRE_ORE_BLOCK, DEEPSLATE_SAPPHIRE_ORE_BLOCK, 8); + ConfiguredFeature peridotOreConfiguration = createOreConfiguration(PERIDOT_ORE_BLOCK, DEEPSLATE_PERIDOT_ORE_BLOCK, 10); + ConfiguredFeature electrotineOreConfiguration = createOreConfiguration(ELECTROTINE_ORE_BLOCK, DEEPSLATE_ELECTROTINE_ORE_BLOCK, 8); + ConfiguredFeature tinOreConfiguration = createOreConfiguration(TIN_ORE_BLOCK, DEEPSLATE_TIN_ORE_BLOCK, 8); + ConfiguredFeature silverOreConfiguration = createOreConfiguration(SILVER_ORE_BLOCK, DEEPSLATE_SILVER_ORE_BLOCK, 9); // Placements PlacedFeature rubyOrePlacedFeature = createOrePlacement(rubyOreConfiguration, -80, 80, 1); @@ -110,21 +112,16 @@ public static JsonCodecProvider biomeModifiersProvider(DataGenera ops, ForgeRegistries.Keys.BIOME_MODIFIERS, Map.of( - new ResourceLocation(MOD_ID, "add_overworld_ores"), new ForgeBiomeModifiers.AddFeaturesBiomeModifier( - isOverworldBiomes, - HolderSet.direct( - Holder.direct(rubyOrePlacedFeature), - Holder.direct(sapphireOrePlacedFeature), - Holder.direct(peridotOrePlacedFeature), - Holder.direct(electrotineOrePlacedFeature), - Holder.direct(tinOrePlacedFeature), - Holder.direct(silverOrePlacedFeature) - ), - GenerationStep.Decoration.UNDERGROUND_ORES), - new ResourceLocation(MOD_ID, "add_overworld_carvers"), new AddCarversBiomeModifier( - isOverworldBiomes, - HolderSet.direct(Holder.direct(marbleCaveConfiguredCarver)), - GenerationStep.Carving.AIR) + // Overworld ores + new ResourceLocation(MOD_ID, "add_ruby_ore_to_overworld"), new ConfigFileControlledAddFeaturesBiomeModifier(isOverworldBiomes, HolderSet.direct(Holder.direct(rubyOrePlacedFeature)), GenerationStep.Decoration.UNDERGROUND_ORES, Configurator.rubyOreKey), + new ResourceLocation(MOD_ID, "add_sapphire_ore_to_overworld"), new ConfigFileControlledAddFeaturesBiomeModifier(isOverworldBiomes, HolderSet.direct(Holder.direct(sapphireOrePlacedFeature)), GenerationStep.Decoration.UNDERGROUND_ORES, Configurator.sapphireOreKey), + new ResourceLocation(MOD_ID, "add_peridot_ore_to_overworld"), new ConfigFileControlledAddFeaturesBiomeModifier(isOverworldBiomes, HolderSet.direct(Holder.direct(peridotOrePlacedFeature)), GenerationStep.Decoration.UNDERGROUND_ORES, Configurator.peridotOreKey), + new ResourceLocation(MOD_ID, "add_electrotine_ore_to_overworld"), new ConfigFileControlledAddFeaturesBiomeModifier(isOverworldBiomes, HolderSet.direct(Holder.direct(electrotineOrePlacedFeature)), GenerationStep.Decoration.UNDERGROUND_ORES, Configurator.electrotineOreKey), + new ResourceLocation(MOD_ID, "add_tin_ore_to_overworld"), new ConfigFileControlledAddFeaturesBiomeModifier(isOverworldBiomes, HolderSet.direct(Holder.direct(tinOrePlacedFeature)), GenerationStep.Decoration.UNDERGROUND_ORES, Configurator.tinOreKey), + new ResourceLocation(MOD_ID, "add_silver_ore_to_overworld"), new ConfigFileControlledAddFeaturesBiomeModifier(isOverworldBiomes, HolderSet.direct(Holder.direct(silverOrePlacedFeature)), GenerationStep.Decoration.UNDERGROUND_ORES, Configurator.silverOreKey), + + // Overworld carvers + new ResourceLocation(MOD_ID, "add_marble_cave_to_overworld"), new ConfigFileControlledAddCarversBiomeModifier(isOverworldBiomes, HolderSet.direct(Holder.direct(marbleCaveConfiguredCarver)), GenerationStep.Carving.AIR, Configurator.marbleCaveKey) )); } diff --git a/exploration/src/main/java/mrtjp/projectred/exploration/world/gen/AddCarversBiomeModifier.java b/exploration/src/main/java/mrtjp/projectred/exploration/world/gen/AddCarversBiomeModifier.java deleted file mode 100644 index 08e5185bc..000000000 --- a/exploration/src/main/java/mrtjp/projectred/exploration/world/gen/AddCarversBiomeModifier.java +++ /dev/null @@ -1,39 +0,0 @@ -package mrtjp.projectred.exploration.world.gen; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.minecraft.core.Holder; -import net.minecraft.core.HolderSet; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.levelgen.GenerationStep; -import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver; -import net.minecraftforge.common.world.BiomeGenerationSettingsBuilder; -import net.minecraftforge.common.world.BiomeModifier; -import net.minecraftforge.common.world.ForgeBiomeModifiers; -import net.minecraftforge.common.world.ModifiableBiomeInfo; - -/** - * For some reason, Forge does not provide this in {@link ForgeBiomeModifiers}. - */ -public record AddCarversBiomeModifier(HolderSet biomes, HolderSet> carvers, GenerationStep.Carving step) implements BiomeModifier { - - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - Biome.LIST_CODEC.fieldOf("biomes").forGetter(m -> m.biomes), - ConfiguredWorldCarver.LIST_CODEC.fieldOf("carvers").forGetter(m -> m.carvers), - GenerationStep.Carving.CODEC.fieldOf("step").forGetter(m -> m.step) - ).apply(instance, AddCarversBiomeModifier::new)); - - @Override - public void modify(Holder biome, Phase phase, ModifiableBiomeInfo.BiomeInfo.Builder builder) { - - if (phase == Phase.ADD && this.biomes.contains(biome)) { - BiomeGenerationSettingsBuilder generationSettings = builder.getGenerationSettings(); - this.carvers.forEach(holder -> generationSettings.addCarver(this.step, holder)); - } - } - - @Override - public Codec codec() { - return CODEC; - } -} diff --git a/exploration/src/main/java/mrtjp/projectred/exploration/world/gen/ConfigFileControlledAddCarversBiomeModifier.java b/exploration/src/main/java/mrtjp/projectred/exploration/world/gen/ConfigFileControlledAddCarversBiomeModifier.java new file mode 100644 index 000000000..e7c7dd65b --- /dev/null +++ b/exploration/src/main/java/mrtjp/projectred/exploration/world/gen/ConfigFileControlledAddCarversBiomeModifier.java @@ -0,0 +1,49 @@ +package mrtjp.projectred.exploration.world.gen; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import mrtjp.projectred.core.Configurator; +import mrtjp.projectred.exploration.init.ExplorationWorldFeatures; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver; +import net.minecraftforge.common.world.BiomeGenerationSettingsBuilder; +import net.minecraftforge.common.world.BiomeModifier; +import net.minecraftforge.common.world.ForgeBiomeModifiers; +import net.minecraftforge.common.world.ModifiableBiomeInfo; + +/** + * For some reason, Forge does not provide this in {@link ForgeBiomeModifiers}. This one also allows for + * dynamic control via ProjectRed's mod config file. + */ +public record ConfigFileControlledAddCarversBiomeModifier(HolderSet biomes, HolderSet> carvers, GenerationStep.Carving step, String configKey) implements BiomeModifier { + + @Override + public void modify(Holder biome, Phase phase, ModifiableBiomeInfo.BiomeInfo.Builder builder) { + + if (isEnabled() && phase == Phase.ADD && this.biomes.contains(biome)) { + BiomeGenerationSettingsBuilder generationSettings = builder.getGenerationSettings(); + this.carvers.forEach(holder -> generationSettings.addCarver(this.step, holder)); + } + } + + @Override + public Codec codec() { + return ExplorationWorldFeatures.ADD_CARVER_BIOME_MODIFIER_CODEC.get(); + } + + private boolean isEnabled() { + return Configurator.worldFeatures.getOrDefault(configKey, false); + } + + public static Codec createCodec() { + return RecordCodecBuilder.create(instance -> instance.group( + Biome.LIST_CODEC.fieldOf("biomes").forGetter(m -> m.biomes), + ConfiguredWorldCarver.LIST_CODEC.fieldOf("carvers").forGetter(m -> m.carvers), + GenerationStep.Carving.CODEC.fieldOf("step").forGetter(m -> m.step), + Codec.STRING.fieldOf("configKey").forGetter(m -> m.configKey) + ).apply(instance, ConfigFileControlledAddCarversBiomeModifier::new)); + } +} diff --git a/exploration/src/main/java/mrtjp/projectred/exploration/world/gen/ConfigFileControlledAddFeaturesBiomeModifier.java b/exploration/src/main/java/mrtjp/projectred/exploration/world/gen/ConfigFileControlledAddFeaturesBiomeModifier.java new file mode 100644 index 000000000..468ed07e3 --- /dev/null +++ b/exploration/src/main/java/mrtjp/projectred/exploration/world/gen/ConfigFileControlledAddFeaturesBiomeModifier.java @@ -0,0 +1,49 @@ +package mrtjp.projectred.exploration.world.gen; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import mrtjp.projectred.core.Configurator; +import mrtjp.projectred.exploration.init.ExplorationWorldFeatures; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.levelgen.placement.PlacedFeature; +import net.minecraftforge.common.world.BiomeGenerationSettingsBuilder; +import net.minecraftforge.common.world.BiomeModifier; +import net.minecraftforge.common.world.ForgeBiomeModifiers; +import net.minecraftforge.common.world.ModifiableBiomeInfo; + +/** + * A type of {@link ForgeBiomeModifiers.AddFeaturesBiomeModifier} that can be disabled by its corresponding + * field in ProjectRed's Config file. + */ +public record ConfigFileControlledAddFeaturesBiomeModifier(HolderSet biomes, HolderSet features, GenerationStep.Decoration step, String configKey) implements BiomeModifier { + + @Override + public void modify(Holder biome, Phase phase, ModifiableBiomeInfo.BiomeInfo.Builder builder) { + + if (isEnabled() && phase == Phase.ADD && this.biomes.contains(biome)) { + BiomeGenerationSettingsBuilder generationSettings = builder.getGenerationSettings(); + this.features.forEach(holder -> generationSettings.addFeature(this.step, holder)); + } + } + + @Override + public Codec codec() { + return ExplorationWorldFeatures.ADD_FEATURES_BIOME_MODIFIER_CODEC.get(); + } + + private boolean isEnabled() { + return Configurator.worldFeatures.getOrDefault(configKey, false); + } + + public static Codec createCodec() { + return RecordCodecBuilder.create(instance -> instance.group( + Biome.LIST_CODEC.fieldOf("biomes").forGetter(m -> m.biomes), + PlacedFeature.LIST_CODEC.fieldOf("features").forGetter(m -> m.features), + GenerationStep.Decoration.CODEC.fieldOf("step").forGetter(m -> m.step), + Codec.STRING.fieldOf("configKey").forGetter(m -> m.configKey) + ).apply(instance, ConfigFileControlledAddFeaturesBiomeModifier::new)); + } +} From f9c104b8e4b018cef5378301d9d11d52442ad8d5 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Sun, 21 Apr 2024 12:04:39 -0400 Subject: [PATCH 4/5] fix: ic timer rendering not synced after world load --- .../projectred/fabrication/editor/ICEditorStateMachine.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java index abfa3410f..03f95c3dd 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/editor/ICEditorStateMachine.java @@ -108,6 +108,7 @@ public void load(CompoundTag tag) { public void writeDesc(MCDataOutput out) { out.writeByte(currentState); + out.writeLong(lastSimStartTime); simulationContainer.writeDesc(out); compilerLog.writeDesc(out); writeAutoCompileState(out); @@ -115,6 +116,7 @@ public void writeDesc(MCDataOutput out) { public void readDesc(MCDataInput in) { currentState = in.readUByte(); + lastSimStartTime = in.readLong(); simulationContainer.readDesc(in); compilerLog.readDesc(in); readAutoCompileState(in); From a6f130d3576c88ca65e0839ded91c4b44f67cba6 Mon Sep 17 00:00:00 2001 From: MrTJP Date: Mon, 29 Apr 2024 17:43:59 -0400 Subject: [PATCH 5/5] feat: compile step tree navigation in ic workbench --- .../mrtjp/projectred/redui/ScrollBarNode.java | 9 +- .../projectred/redui/SpriteButtonNode.java | 39 +++ .../af9e6e51e4f0a9c76d168bf51cd141f0b8234be4 | 4 +- .../projectred_fabrication/lang/en_us.json | 62 +++- .../data/FabricationLanguageProvider.java | 44 +++ .../fabrication/engine/log/ICCompilerLog.java | 81 ++++- .../fabrication/gui/CTNListNode.java | 86 ++++-- .../fabrication/gui/CompileProblemsTab.java | 16 +- .../fabrication/gui/CompileStackTab.java | 16 +- .../fabrication/gui/CompileTreeTab.java | 291 +++++++++++++++++- .../fabrication/gui/ProblemListNode.java | 18 +- .../fabrication/init/FabricationUnlocal.java | 68 +++- .../textures/gui/compile_tab.png | Bin 13123 -> 13336 bytes gradle.properties | 2 +- 14 files changed, 653 insertions(+), 83 deletions(-) create mode 100644 core/src/main/java/mrtjp/projectred/redui/SpriteButtonNode.java diff --git a/core/src/main/java/mrtjp/projectred/redui/ScrollBarNode.java b/core/src/main/java/mrtjp/projectred/redui/ScrollBarNode.java index f7bdca46c..1794d12d6 100644 --- a/core/src/main/java/mrtjp/projectred/redui/ScrollBarNode.java +++ b/core/src/main/java/mrtjp/projectred/redui/ScrollBarNode.java @@ -1,9 +1,11 @@ package mrtjp.projectred.redui; +import codechicken.lib.colour.EnumColour; import com.mojang.blaze3d.vertex.PoseStack; import mrtjp.projectred.lib.Point; import mrtjp.projectred.lib.Rect; import mrtjp.projectred.lib.Size; +import net.minecraft.client.gui.GuiComponent; public abstract class ScrollBarNode extends AbstractGuiNode { @@ -28,7 +30,12 @@ public void setSliderSize(int w, int h) { @Override public void drawBack(PoseStack stack, Point mouse, float partialFrame) { - // Draw scroll bar background + // Draw semi-transparent grey background + int x = getFrame().x(); + int y = getFrame().y(); + GuiComponent.fillGradient(stack, x, y, x + getFrame().width(), y + getFrame().height(), EnumColour.BLACK.argb(127), EnumColour.BLACK.argb(127), 0); + + // Draw slider rectangle drawSlider(stack, sliderFrame); } diff --git a/core/src/main/java/mrtjp/projectred/redui/SpriteButtonNode.java b/core/src/main/java/mrtjp/projectred/redui/SpriteButtonNode.java new file mode 100644 index 000000000..3dcbcdc8c --- /dev/null +++ b/core/src/main/java/mrtjp/projectred/redui/SpriteButtonNode.java @@ -0,0 +1,39 @@ +package mrtjp.projectred.redui; + +import com.mojang.blaze3d.vertex.PoseStack; + +import java.util.function.Supplier; + +public class SpriteButtonNode extends AbstractButtonNode { + + private RedUISprite sprite; + private Runnable clickReceiver = () -> { }; + private Supplier isDisabledProvider = () -> false; + + public SpriteButtonNode(RedUISprite sprite) { + this.sprite = sprite; + } + + public void setClickReceiver(Runnable clickReceiver) { + this.clickReceiver = clickReceiver; + } + + public void setIsDisabledProvider(Supplier isDisabledProvider) { + this.isDisabledProvider = isDisabledProvider; + } + + @Override + protected boolean isButtonDisabled() { + return isDisabledProvider.get(); + } + + @Override + protected void onButtonClicked() { + clickReceiver.run(); + } + + @Override + protected void drawButtonBody(PoseStack stack, boolean mouseover) { + blitSpriteCentered(stack, sprite); + } +} diff --git a/fabrication/src/main/generated/.cache/af9e6e51e4f0a9c76d168bf51cd141f0b8234be4 b/fabrication/src/main/generated/.cache/af9e6e51e4f0a9c76d168bf51cd141f0b8234be4 index 41322c2d9..5029e3fc2 100644 --- a/fabrication/src/main/generated/.cache/af9e6e51e4f0a9c76d168bf51cd141f0b8234be4 +++ b/fabrication/src/main/generated/.cache/af9e6e51e4f0a9c76d168bf51cd141f0b8234be4 @@ -1,2 +1,2 @@ -// 1.19.2 2024-04-05T16:47:53.695184 ProjectRed-Fabrication Languages: en_us -dd1226a77b7ec67a85f9d088ba5a3f78a16f2bf4 assets/projectred_fabrication/lang/en_us.json +// 1.19.2 2024-04-29T13:40:44.325463 ProjectRed-Fabrication Languages: en_us +5da5b8cc9a7b6e62337421001761920875beea36 assets/projectred_fabrication/lang/en_us.json diff --git a/fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json b/fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json index 2895e9e7c..76bce5331 100644 --- a/fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json +++ b/fabrication/src/main/generated/assets/projectred_fabrication/lang/en_us.json @@ -12,12 +12,53 @@ "item.projectred_fabrication.rough_silicon_wafer": "Rough Silicon Wafer", "item.projectred_fabrication.valid_die": "Valid Die", "itemGroup.projectred_fabrication": "Project Red: Fabrication", - "projectred_fabrication.dimensions.dies": "%d dies x %d dies", - "projectred_fabrication.dimensions.dies_total": "%d dies x %d dies (%d dies^2)", - "projectred_fabrication.dimensions.nm": "%d nm x %d nm", - "projectred_fabrication.dimensions.nm_total": "%d nm x %d nm (%d nm^2)", - "projectred_fabrication.dimensions.tiles": "%d tiles x %d tiles", - "projectred_fabrication.dimensions.tiles_total": "%d tiles x %d tiles (%d tiles^2)", + "projectred_fabrication.compile.stack": "Stack", + "projectred_fabrication.compile.step.check_flat_maps": "Check flat maps", + "projectred_fabrication.compile.step.check_flat_maps.desc": "Check for flat maps to merge", + "projectred_fabrication.compile.step.check_tile_maps": "Check tile maps", + "projectred_fabrication.compile.step.check_tile_maps.desc": "Check for tile maps to compile", + "projectred_fabrication.compile.step.merge_flat_map": "Compile flat map", + "projectred_fabrication.compile.step.merge_flat_map.desc": "Merge flat map", + "projectred_fabrication.compile.step.merge_tile_map": "Compile tile map", + "projectred_fabrication.compile.step.merge_tile_map.desc": "Compile tile map", + "projectred_fabrication.compile.step.merge_tile_map_add_remaps": "Add remaps", + "projectred_fabrication.compile.step.merge_tile_map_add_remaps.desc": "Declare remaps", + "projectred_fabrication.compile.step.merge_tile_map_alloc": "Alloc", + "projectred_fabrication.compile.step.merge_tile_map_alloc.desc": "Output registers and gate allocation", + "projectred_fabrication.compile.step.merge_tile_map_collect": "Collect", + "projectred_fabrication.compile.step.merge_tile_map_collect.desc": "Gates and registers collected", + "projectred_fabrication.compile.step.merge_tile_map_consume_remaps": "Remap", + "projectred_fabrication.compile.step.merge_tile_map_consume_remaps.desc": "Apply remaps", + "projectred_fabrication.compile.step.merge_tile_map_manifest_search": "Lookup", + "projectred_fabrication.compile.step.merge_tile_map_manifest_search.desc": "Passing signals lookup", + "projectred_fabrication.compile.step.merge_tile_map_pathfind": "Pathfind", + "projectred_fabrication.compile.step.merge_tile_map_pathfind.desc": "Input register search", + "projectred_fabrication.compile.step.merge_tile_map_phase1": "Allocation phase", + "projectred_fabrication.compile.step.merge_tile_map_phase1.desc": "Allocate memory for all tiles", + "projectred_fabrication.compile.step.merge_tile_map_phase2": "Pathfind phase", + "projectred_fabrication.compile.step.merge_tile_map_phase2.desc": "Search for connected registers", + "projectred_fabrication.compile.step.merge_tile_map_phase3": "Lookup phase", + "projectred_fabrication.compile.step.merge_tile_map_phase3.desc": "Look up passing signals", + "projectred_fabrication.compile.step.merge_tile_map_phase4": "Add remaps phase", + "projectred_fabrication.compile.step.merge_tile_map_phase4.desc": "Declare register remaps", + "projectred_fabrication.compile.step.merge_tile_map_phase5": "Remap phase", + "projectred_fabrication.compile.step.merge_tile_map_phase5.desc": "Apply register remaps", + "projectred_fabrication.compile.step.merge_tile_map_phase6": "Collection phase", + "projectred_fabrication.compile.step.merge_tile_map_phase6.desc": "Collect gates and registers", + "projectred_fabrication.compile.step.merge_tile_map_post": "Post-compile", + "projectred_fabrication.compile.step.merge_tile_map_post.desc": "Post-compile", + "projectred_fabrication.compile.step.merge_tile_map_pre": "Pre-compile", + "projectred_fabrication.compile.step.merge_tile_map_pre.desc": "Pre-compile", + "projectred_fabrication.compile.tree": "Tree", + "projectred_fabrication.f.dimensions.dies": "%d dies x %d dies", + "projectred_fabrication.f.dimensions.dies_total": "%d dies x %d dies (%d dies^2)", + "projectred_fabrication.f.dimensions.nm": "%d nm x %d nm", + "projectred_fabrication.f.dimensions.nm_total": "%d nm x %d nm (%d nm^2)", + "projectred_fabrication.f.dimensions.tiles": "%d tiles x %d tiles", + "projectred_fabrication.f.dimensions.tiles_total": "%d tiles x %d tiles (%d tiles^2)", + "projectred_fabrication.f.unit.errors": "%d errors", + "projectred_fabrication.f.unit.ticks": "%d ticks", + "projectred_fabrication.f.unit.warnings": "%d warnings", "projectred_fabrication.interact.default_state": "Default state", "projectred_fabrication.interact.delay": "Delay", "projectred_fabrication.interact.io_direction": "IO direction", @@ -111,8 +152,9 @@ "projectred_fabrication.ui.wafer_type": "Wafer type", "projectred_fabrication.ui.yield": "Yield", "projectred_fabrication.ui.yield_calculator": "Yield Calculator", - "projectred_fabrication.unit.errors": "%d errors", - "projectred_fabrication.unit.ticks": "%d ticks", - "projectred_fabrication.unit.warnings": "%d warnings", - "projectred_fabrication.unit_only.ticks": "ticks" + "projectred_fabrication.unit.gates": "gates", + "projectred_fabrication.unit.none": "none", + "projectred_fabrication.unit.registers": "registers", + "projectred_fabrication.unit.remaps": "remaps", + "projectred_fabrication.unit.ticks": "ticks" } \ No newline at end of file diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java index 99b75cccd..a53996a55 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/data/FabricationLanguageProvider.java @@ -66,6 +66,46 @@ protected void addTranslations() { add(UL_TIME_DELAY, "Delay"); add(UL_DEFAULT_STATE, "Default state"); + add(UL_COMPILE_TREE, "Tree"); + add(UL_COMPILE_STACK, "Stack"); + add(UL_COMPILE_CHECK_TILE_MAP, "Check tile maps"); + add(UL_COMPILE_CHECK_FLAT_MAP, "Check flat maps"); + add(UL_COMPILE_MERGE_TILE_MAP, "Compile tile map"); + add(UL_COMPILE_MERGE_FLAT_MAP, "Compile flat map"); + add(UL_COMPILE_MERGE_TILE_MAP_PRE, "Pre-compile"); + add(UL_COMPILE_PHASE_1, "Allocation phase"); + add(UL_COMPILE_ALLOC, "Alloc"); + add(UL_COMPILE_PHASE_2, "Pathfind phase"); + add(UL_COMPILE_PATHFIND, "Pathfind"); + add(UL_COMPILE_PHASE_3, "Lookup phase"); + add(UL_COMPILE_PF_MANIFEST, "Lookup"); + add(UL_COMPILE_PHASE_4, "Add remaps phase"); + add(UL_COMPILE_ADD_REMAPS, "Add remaps"); + add(UL_COMPILE_PHASE_5, "Remap phase"); + add(UL_COMPILE_REMAP, "Remap"); + add(UL_COMPILE_PHASE_6, "Collection phase"); + add(UL_COMPILE_COLLECT, "Collect"); + add(UL_COMPILE_MERGE_TILE_MAP_POST, "Post-compile"); + + add(UL_COMPILE_CHECK_TILE_MAP_DESC, "Check for tile maps to compile"); + add(UL_COMPILE_CHECK_FLAT_MAP_DESC, "Check for flat maps to merge"); + add(UL_COMPILE_MERGE_TILE_MAP_DESC, "Compile tile map"); + add(UL_COMPILE_MERGE_FLAT_MAP_DESC, "Merge flat map"); + add(UL_COMPILE_MERGE_TILE_MAP_PRE_DESC, "Pre-compile"); + add(UL_COMPILE_PHASE_1_DESC, "Allocate memory for all tiles"); + add(UL_COMPILE_ALLOC_DESC, "Output registers and gate allocation"); + add(UL_COMPILE_PHASE_2_DESC, "Search for connected registers"); + add(UL_COMPILE_PATHFIND_DESC, "Input register search"); + add(UL_COMPILE_PHASE_3_DESC, "Look up passing signals"); + add(UL_COMPILE_PF_MANIFEST_DESC, "Passing signals lookup"); + add(UL_COMPILE_PHASE_4_DESC, "Declare register remaps"); + add(UL_COMPILE_ADD_REMAPS_DESC, "Declare remaps"); + add(UL_COMPILE_PHASE_5_DESC, "Apply register remaps"); + add(UL_COMPILE_REMAP_DESC, "Apply remaps"); + add(UL_COMPILE_PHASE_6_DESC, "Collect gates and registers"); + add(UL_COMPILE_COLLECT_DESC, "Gates and registers collected"); + add(UL_COMPILE_MERGE_TILE_MAP_POST_DESC, "Post-compile"); + add(UL_MULTIPLE_DRIVERS_TITLE, "Multiple drivers"); add(UL_MULTIPLE_DRIVERS_DESC, "Multiple registers connected to an input:"); add(UL_DEAD_WIRE_TITLE, "Dead wire"); @@ -155,5 +195,9 @@ protected void addTranslations() { add(UL_DIMENSIONS_DIES_TOTAL, "%d dies x %d dies (%d dies^2)"); add(UL_UNIT_ONLY_TICKS, "ticks"); + add(UL_UNIT_ONLY_REGISTERS, "registers"); + add(UL_UNIT_ONLY_GATES, "gates"); + add(UL_UNIT_ONLY_REMAPS, "remaps"); + add(UL_UNIT_ONLY_NONE, "none"); } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/ICCompilerLog.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/ICCompilerLog.java index 17a5ee548..cdb623ca8 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/ICCompilerLog.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/engine/log/ICCompilerLog.java @@ -29,6 +29,8 @@ public class ICCompilerLog implements ICStepThroughAssembler.EventReceiver { private int warningCount = 0; private int errorCount = 0; + private final List treeChangedListeners = new LinkedList<>(); + public ICCompilerLog(ICEditorStateMachine stateMachine) { this.stateMachine = stateMachine; } @@ -100,6 +102,7 @@ public void clear() { problems.clear(); warningCount = 0; errorCount = 0; + notifyListeners(); } public int getTotalSteps() { @@ -122,6 +125,16 @@ public int getWarningCount() { return warningCount; } + public void addTreeChangedListener(Runnable listener) { + treeChangedListeners.add(listener); + } + + private void notifyListeners() { + for (Runnable listener : treeChangedListeners) { + listener.run(); + } + } + //region ICStepThroughAssembler.EventReceiver @Override public void onStepAdded(ICStepThroughAssembler.AssemblerStepDescriptor descriptor) { @@ -129,6 +142,7 @@ public void onStepAdded(ICStepThroughAssembler.AssemblerStepDescriptor descripto node.step = descriptor.getStepType(); sendNodeAdded(node, descriptor.getTreePath()); + notifyListeners(); } @Override @@ -144,6 +158,7 @@ public void onStepExecuted(ICStepThroughAssembler.AssemblerStepResult result) { completedSteps++; sendNodeExecuted(node, result.getTreePath()); + notifyListeners(); } //endregion @@ -162,20 +177,11 @@ public void addProblem(CompileProblem problem) { //region Packet handling public void readLogStream(MCDataInput in, int key) { switch (key) { - case KEY_COMPILER_LOG_CLEARED: - clear(); - break; - case KEY_COMPILER_LOG_NODE_ADDED: - readNodeAdded(in); - break; - case KEY_COMPILER_LOG_NODE_EXECUTED: - readNodeExecuted(in); - break; - case KEY_COMPILER_LOG_PROBLEM_ADDED: - readProblemAdded(in); - break; - default: - throw new IllegalArgumentException("Unknown compiler stream key: " + key); + case KEY_COMPILER_LOG_CLEARED -> clear(); + case KEY_COMPILER_LOG_NODE_ADDED -> readNodeAdded(in); + case KEY_COMPILER_LOG_NODE_EXECUTED -> readNodeExecuted(in); + case KEY_COMPILER_LOG_PROBLEM_ADDED -> readProblemAdded(in); + default -> throw new IllegalArgumentException("Unknown compiler stream key: " + key); } } //endregion @@ -215,6 +221,7 @@ private void addProblemInternal(CompileProblem problem) { case WARNING -> warningCount++; case ERROR -> errorCount++; } + notifyListeners(); } //endregion @@ -227,6 +234,7 @@ private void readNodeAdded(MCDataInput in) { } CompileTreeNode node = compileTree.findOrCreateNode(path); node.step = ICStepThroughAssembler.AssemblerStepType.values()[in.readUByte()]; + notifyListeners(); } private void readNodeExecuted(MCDataInput in) { @@ -241,6 +249,7 @@ private void readNodeExecuted(MCDataInput in) { currentPath.clear(); currentPath.addAll(path); completedSteps++; + notifyListeners(); } private void readProblemAdded(MCDataInput in) { @@ -253,6 +262,10 @@ public List getCurrentStack() { return compileTree.getStack(currentPath); } + public List getRootNodes() { + return compileTree.rootNodes; + } + public int getProgressScaled(int scale) { int size = compileTree.size(); return size == 0 ? 0 : completedSteps * scale / size; @@ -399,6 +412,46 @@ protected void readDesc(MCDataInput in) { children.add(child); } } + + public int countRegIdsInSubtree() { + //TODO cache + int count = registerIds.size(); + for (CompileTreeNode child : children) { + count += child.countRegIdsInSubtree(); + } + return count; + } + + public int countGateIdsInSubtree() { + //TODO cache + int count = gateIds.size(); + for (CompileTreeNode child : children) { + count += child.countGateIdsInSubtree(); + } + return count; + } + + public int countRemapsInSubtree() { + //TODO cache + int count = registerRemaps.size(); + for (CompileTreeNode child : children) { + count += child.countRemapsInSubtree(); + } + return count; + } + + public boolean isEmpty() { + return registerIds.isEmpty() && gateIds.isEmpty() && registerRemaps.isEmpty(); + } + + public void getPositionsInTree(List pList) { + if (!isEmpty()) { + pList.addAll(tileCoords); + for (CompileTreeNode child : children) { + child.getPositionsInTree(pList); + } + } + } } public static class CompileTree { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CTNListNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CTNListNode.java index 0af7a58fa..14431d2f4 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CTNListNode.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CTNListNode.java @@ -7,20 +7,23 @@ import mrtjp.projectred.lib.Point; import mrtjp.projectred.lib.Rect; import mrtjp.projectred.redui.AbstractGuiNode; -import net.minecraft.client.gui.GuiComponent; +import mrtjp.projectred.redui.RedUISprite; import net.minecraft.network.chat.Component; +import javax.annotation.Nullable; import java.util.LinkedList; import java.util.List; +import static mrtjp.projectred.fabrication.editor.ICWorkbenchEditor.UNIFORM; + public class CTNListNode extends AbstractGuiNode { private final List nodeList = new LinkedList<>(); - private final AbstractGuiNode listParent = new AbstractGuiNode() { - }; + private double scroll = 0; + public CTNListNode() { initSubNodes(); } @@ -30,9 +33,11 @@ private void initSubNodes() { } public void setNodeList(List nodeList) { - this.nodeList.clear(); - this.nodeList.addAll(nodeList); - refreshListItems(); + if (!this.nodeList.equals(nodeList)) { + this.nodeList.clear(); + this.nodeList.addAll(nodeList); + refreshListItems(); + } } private void refreshListItems() { @@ -46,6 +51,32 @@ private void refreshListItems() { listParent.addChild(item); y += item.calculateAccumulatedFrame().height(); } + + moveListToScroll(); + } + + public void setScrollPercentage(double scrollPercentage) { + this.scroll = scrollPercentage; + moveListToScroll(); + } + + private void moveListToScroll() { + Rect subFrame = calculateChildrenFrame(); + if (subFrame.height() <= getFrame().height()) return; + + int totalScroll = subFrame.height() - getFrame().height(); // How much scroll is possible + int dist = (int) (totalScroll * scroll); // How much we want to scroll + + listParent.setPosition(0, -dist); + } + + public @Nullable CompileTreeNode getSelectedNode() { + for (var child : listParent.getOurChildren()) { + if (child instanceof CompileTreeNodeListItem item && item.selected) { + return item.node; + } + } + return null; } @Override @@ -63,27 +94,34 @@ public void onSubTreePostDrawBack() { RenderSystem.disableScissor(); } + private void selectNodeInList(CompileTreeNodeListItem node) { + for (var child : listParent.getOurChildren()) { + if (child instanceof CompileTreeNodeListItem item) { + item.selected = item == node; + } + } + } + private class CompileTreeNodeListItem extends AbstractGuiNode { + private static final RedUISprite BACKGROUND_UNSELECTED = new RedUISprite(ICWorkbenchCompileTab.TAB_BACKGROUND, 1, 375, 79, 12, 512, 512); + private static final RedUISprite BACKGROUND_SELECTED = new RedUISprite(ICWorkbenchCompileTab.TAB_BACKGROUND, 81, 375, 79, 12, 512, 512); + private final CompileTreeNode node; + private boolean selected = false; public CompileTreeNodeListItem(CompileTreeNode node) { this.node = node; - - setSize(67, 16); + setSize(68, 12); } @Override public void drawBack(PoseStack stack, Point mouse, float partialFrame) { - RenderSystem.setShaderTexture(0, ICWorkbenchCompileTab.TAB_BACKGROUND); + blitSprite(stack, selected ? BACKGROUND_SELECTED : BACKGROUND_UNSELECTED); - GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 1, 358, getFrame().width(), getFrame().height(), 512, 512); - - String s = node.step.toString(); - if (s.length() > 10) { - s = s.substring(s.length() - 10); - } - getRoot().getFontRenderer().draw(stack, s, getFrame().x() + 2, getFrame().y() + 2, 0xFFFFFF); + var fr = getRoot().getFontRenderer(); + Component c = CompileTreeTab.getTitleForCTNNode(node).copy().withStyle(UNIFORM); + fr.draw(stack, c, getFrame().x() + 2, getFrame().y() + getFrame().height() / 2f - fr.lineHeight / 2f, 0xFFFFFF); } @Override @@ -92,12 +130,7 @@ public void drawFront(PoseStack stack, Point mouse, float partialFrame) { if (!isFirstHit(mouse)) return; List toolTip = new LinkedList<>(); - toolTip.add(Component.literal(node.step.toString())); //TODO localize - toolTip.add(Component.literal("Positions: " + node.tileCoords.size())); - toolTip.add(Component.literal("Registers: " + node.registerIds.size())); - toolTip.add(Component.literal("Gates: " + node.gateIds.size())); - toolTip.add(Component.literal("Remaps: " + node.registerRemaps.size())); - + CompileTreeTab.buildTooltipForCTNNode(node, toolTip); renderTooltip(stack, mouse, toolTip); } @@ -105,5 +138,14 @@ public void drawFront(PoseStack stack, Point mouse, float partialFrame) { public boolean checkHit(Point absPoint) { return super.checkHit(absPoint) && CTNListNode.this.convertParentRectToScreen(CTNListNode.this.getFrame()).contains(absPoint); } + + @Override + public boolean mouseClicked(Point p, int glfwMouseButton, boolean consumed) { + if (!consumed && isFirstHit(p)) { + selectNodeInList(this); + return true; + } + return false; + } } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileProblemsTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileProblemsTab.java index e63e1f686..2b2328846 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileProblemsTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileProblemsTab.java @@ -35,10 +35,10 @@ private void initSubNodes() { // Stack issueListNode.setPosition(6, 31); - issueListNode.setSize(67, 95); + issueListNode.setSize(79, 95); addChild(issueListNode); - // Scrollbar //TODO + // Scrollbar ScrollBar scrollBar = new ScrollBar(); scrollBar.setPosition(77, 31); scrollBar.setZPosition(0.2); @@ -54,11 +54,13 @@ public void drawBack(PoseStack stack, Point mouse, float partialFrame) { } @Override - public void update() { - if (!isHidden()) { - // TODO only do this when issue log changes - issueListNode.setProblemList(editor.getStateMachine().getCompilerLog().getProblems()); - } + public void onAddedToParent() { + editor.getStateMachine().getCompilerLog().addTreeChangedListener(this::refreshList); + refreshList(); + } + + private void refreshList() { + issueListNode.setProblemList(editor.getStateMachine().getCompilerLog().getProblems()); } //region ICompileTabOverlayRenderer diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileStackTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileStackTab.java index d095abcf4..a6707c8da 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileStackTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileStackTab.java @@ -37,7 +37,7 @@ private void initSubNodes() { // Stack ctnListNode.setPosition(6, 31); - ctnListNode.setSize(67, 95); + ctnListNode.setSize(79, 95); addChild(ctnListNode); // Scrollbar //TODO @@ -56,12 +56,14 @@ public void drawBack(PoseStack stack, Point mouse, float partialFrame) { } @Override - public void update() { - if (!isHidden()) { - // TODO only do this when the stack changes - List execStack = editor.getStateMachine().getCompilerLog().getCurrentStack(); - ctnListNode.setNodeList(execStack); - } + public void onAddedToParent() { + editor.getStateMachine().getCompilerLog().addTreeChangedListener(this::refreshList); + refreshList(); + } + + private void refreshList() { + List execStack = editor.getStateMachine().getCompilerLog().getCurrentStack(); + ctnListNode.setNodeList(execStack); } private void renderCompileTreeNode(ICCompilerLog.CompileTreeNode node, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileTreeTab.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileTreeTab.java index 555cd1eef..ead8f1ae8 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileTreeTab.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/CompileTreeTab.java @@ -1,23 +1,93 @@ package mrtjp.projectred.fabrication.gui; +import codechicken.lib.colour.EnumColour; import codechicken.lib.render.CCRenderState; import codechicken.lib.vec.Vector3; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.fengine.TileCoord; +import mrtjp.fengine.api.ICStepThroughAssembler; import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; +import mrtjp.projectred.fabrication.engine.log.ICCompilerLog.CompileTreeNode; import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchCompileTab; import mrtjp.projectred.lib.Point; +import mrtjp.projectred.lib.Rect; import mrtjp.projectred.redui.AbstractGuiNode; +import mrtjp.projectred.redui.RedUISprite; +import mrtjp.projectred.redui.ScrollBarNode; +import mrtjp.projectred.redui.SpriteButtonNode; +import net.covers1624.quack.collection.FastStream; import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; -import java.util.List; +import javax.annotation.Nullable; +import java.util.*; + +import static mrtjp.fengine.api.ICStepThroughAssembler.AssemblerStepType.*; +import static mrtjp.projectred.fabrication.editor.ICWorkbenchEditor.UNIFORM_DARK_GRAY; +import static mrtjp.projectred.fabrication.editor.ICWorkbenchEditor.UNIFORM_GRAY; +import static mrtjp.projectred.fabrication.init.FabricationUnlocal.*; public class CompileTreeTab extends AbstractGuiNode implements ICompileOverlayRenderer { + public static final Map STEP_TYPE_NAMES; + public static final Map STEP_TYPE_DESC; + static { + Map map = new EnumMap<>(ICStepThroughAssembler.AssemblerStepType.class); + map.put(CHECK_OPEN_TILE_MAPS, UL_COMPILE_CHECK_TILE_MAP); + map.put(CHECK_OPEN_FLAT_MAPS, UL_COMPILE_CHECK_FLAT_MAP); + map.put(MERGE_TILE_MAP, UL_COMPILE_MERGE_TILE_MAP); + map.put(MERGE_FLAT_MAP, UL_COMPILE_MERGE_FLAT_MAP); + map.put(MERGE_TILE_MAP_PRE, UL_COMPILE_MERGE_TILE_MAP_PRE); + map.put(MERGE_TILE_MAP_PHASE1, UL_COMPILE_PHASE_1); + map.put(PHASE1_ALLOC, UL_COMPILE_ALLOC); + map.put(MERGE_TILE_MAP_PHASE2, UL_COMPILE_PHASE_2); + map.put(PHASE2_PATHFIND, UL_COMPILE_PATHFIND); + map.put(MERGE_TILE_MAP_PHASE3, UL_COMPILE_PHASE_3); + map.put(PHASE3_PF_MANIFEST_SEARCH, UL_COMPILE_PF_MANIFEST); + map.put(MERGE_TILE_MAP_PHASE4, UL_COMPILE_PHASE_4); + map.put(PHASE4_REGISTER_REMAPS, UL_COMPILE_ADD_REMAPS); + map.put(MERGE_TILE_MAP_PHASE5, UL_COMPILE_PHASE_5); + map.put(PHASE5_CONSUME_REMAPS, UL_COMPILE_REMAP); + map.put(MERGE_TILE_MAP_PHASE6, UL_COMPILE_PHASE_6); + map.put(PHASE6_COLLECT, UL_COMPILE_COLLECT); + map.put(MERGE_TILE_MAP_POST, UL_COMPILE_MERGE_TILE_MAP_POST); + STEP_TYPE_NAMES = Collections.unmodifiableMap(map); + + map = new EnumMap<>(ICStepThroughAssembler.AssemblerStepType.class); + map.put(CHECK_OPEN_TILE_MAPS, UL_COMPILE_CHECK_TILE_MAP_DESC); + map.put(CHECK_OPEN_FLAT_MAPS, UL_COMPILE_CHECK_FLAT_MAP_DESC); + map.put(MERGE_TILE_MAP, UL_COMPILE_MERGE_TILE_MAP_DESC); + map.put(MERGE_FLAT_MAP, UL_COMPILE_MERGE_FLAT_MAP_DESC); + map.put(MERGE_TILE_MAP_PRE, UL_COMPILE_MERGE_TILE_MAP_PRE_DESC); + map.put(MERGE_TILE_MAP_PHASE1, UL_COMPILE_PHASE_1_DESC); + map.put(PHASE1_ALLOC, UL_COMPILE_ALLOC_DESC); + map.put(MERGE_TILE_MAP_PHASE2, UL_COMPILE_PHASE_2_DESC); + map.put(PHASE2_PATHFIND, UL_COMPILE_PATHFIND_DESC); + map.put(MERGE_TILE_MAP_PHASE3, UL_COMPILE_PHASE_3_DESC); + map.put(PHASE3_PF_MANIFEST_SEARCH, UL_COMPILE_PF_MANIFEST_DESC); + map.put(MERGE_TILE_MAP_PHASE4, UL_COMPILE_PHASE_4_DESC); + map.put(PHASE4_REGISTER_REMAPS, UL_COMPILE_ADD_REMAPS_DESC); + map.put(MERGE_TILE_MAP_PHASE5, UL_COMPILE_PHASE_5_DESC); + map.put(PHASE5_CONSUME_REMAPS, UL_COMPILE_REMAP_DESC); + map.put(MERGE_TILE_MAP_PHASE6, UL_COMPILE_PHASE_6_DESC); + map.put(PHASE6_COLLECT, UL_COMPILE_COLLECT_DESC); + map.put(MERGE_TILE_MAP_POST, UL_COMPILE_MERGE_TILE_MAP_POST_DESC); + STEP_TYPE_DESC = Collections.unmodifiableMap(map); + } + + private static final RedUISprite STEP_OUT_SPRITE = new RedUISprite(ICWorkbenchCompileTab.TAB_BACKGROUND, 335, 41, 14, 14, 512, 512); + private static final RedUISprite STEP_IN_SPRITE = new RedUISprite(ICWorkbenchCompileTab.TAB_BACKGROUND, 320, 41, 14, 14, 512, 512); + private final ICWorkbenchEditor editor; + private final CTNListNode ctnListNode = new CTNListNode(); + + private final Stack backStack = new Stack<>(); + private @Nullable CompileTreeNode currentNode = null; + public CompileTreeTab(ICWorkbenchEditor editor) { this.editor = editor; setSize(91, 134); @@ -25,23 +95,242 @@ public CompileTreeTab(ICWorkbenchEditor editor) { } private void initSubNodes() { + + // Stack + ctnListNode.setPosition(6, 31); + ctnListNode.setSize(79, 95); + addChild(ctnListNode); + + // Scrollbar + ScrollBar scrollBar = new ScrollBar(); + scrollBar.setPosition(77, 31); + scrollBar.setZPosition(0.2); + scrollBar.setSize(8, 95); + scrollBar.setSliderSize(8, 16); + addChild(scrollBar); + + // Step out button + SpriteButtonNode stepOut = new SpriteButtonNode(STEP_OUT_SPRITE); + stepOut.setClickReceiver(this::stepOut); + stepOut.setIsDisabledProvider(() -> currentNode == null); + stepOut.setPosition(5, 5); + stepOut.setSize(16, 16); + addChild(stepOut); + + // Step in button + SpriteButtonNode stepIn = new SpriteButtonNode(STEP_IN_SPRITE); + stepIn.setClickReceiver(this::stepIn); + stepIn.setIsDisabledProvider(() -> { + var n = ctnListNode.getSelectedNode(); + return n == null || n.children.isEmpty(); + }); + stepIn.setPosition(23, 5); + stepIn.setSize(16, 16); + addChild(stepIn); } @Override public void drawBack(PoseStack stack, Point mouse, float partialFrame) { RenderSystem.setShaderTexture(0, ICWorkbenchCompileTab.TAB_BACKGROUND); GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 92, 223, getFrame().width(), getFrame().height(), 512, 512); + + // Title of current node + if (currentNode != null) { + var fr = getRoot().getFontRenderer(); + Component c = getTitleForCTNNode(currentNode).copy().withStyle(UNIFORM_DARK_GRAY); + fr.draw(stack, c, getFrame().x() + 6, getFrame().y() + 21, 0xFFFFFF); + } + } + + //region Navigation control + private void stepIn() { + // Get the selected node that we will step into + var selected = ctnListNode.getSelectedNode(); + if (selected == null) return; + + // Add current node to backstack and switch to new node + if (currentNode != null) backStack.push(currentNode); + currentNode = selected; + + // Update list + refreshList(); + } + + private void stepOut() { + // Set to null if no more previous nodes. This will force root nodes to be displayed + currentNode = backStack.isEmpty() ? null : backStack.pop(); + + // Refresh list + refreshList(); + } + //endregion + + @Override + public void onAddedToParent() { + editor.getStateMachine().getCompilerLog().addTreeChangedListener(this::refreshList); + refreshList(); + } + + private void refreshList() { + var log = editor.getStateMachine().getCompilerLog(); + if (log.getCurrentStack().isEmpty()) { //TODO separate receiver for this case? + currentNode = null; + backStack.clear(); + } else if (currentNode == null) { + ctnListNode.setNodeList(editor.getStateMachine().getCompilerLog().getRootNodes()); + } else { + ctnListNode.setNodeList(currentNode.children); + } } //region ICompileTabOverlayRenderer @Override public void renderOverlay(ICRenderNode renderNode, Vector3 mousePosition, boolean isFirstHit, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + var node = ctnListNode.getSelectedNode(); + if (node == null) node = currentNode; + + if (node != null) { + renderOverlayForNode(node, ccrs, getter, matrixStack); + } } @Override public void buildTooltip(ICRenderNode renderNode, Vector3 mousePosition, List tooltip) { } + + private void renderOverlayForNode(CompileTreeNode node, CCRenderState ccrs, MultiBufferSource getter, PoseStack matrixStack) { + ccrs.reset(); + ccrs.bind(ICRenderTypes.selectionRenderType, getter, matrixStack); + + // Render subnode positions in fainter color + ccrs.baseColour = EnumColour.WHITE.rgba(127); + + List coords = new LinkedList<>(); + for (var c : node.children) { + c.getPositionsInTree(coords); + } + + for (var pos : coords) { + Vector3 p = new Vector3(pos.x, pos.y, pos.z); + ICRenderTypes.renderSelection(ccrs, p, p.copy().add(0.01), 3 / 16D, 2 / 16D); + } + + // Render current node positions in full color + ccrs.baseColour = EnumColour.WHITE.rgba(); + for (var pos : node.tileCoords) { + Vector3 p = new Vector3(pos.x, pos.y, pos.z); + ICRenderTypes.renderSelection(ccrs, p, p.copy().add(0.01), 3 / 16D, 2 / 16D); + } + } //endregion + + public static Component getTitleForCTNNode(CompileTreeNode node) { + + String pos = node.tileCoords.isEmpty() ? "" : "[%d, %d, %d]".formatted(node.tileCoords.get(0).x, node.tileCoords.get(0).y, node.tileCoords.get(0).z); + return switch (node.step) { + case PHASE1_ALLOC -> Component.translatable(UL_COMPILE_ALLOC).append(" " + pos); + case PHASE2_PATHFIND -> Component.translatable(UL_COMPILE_PATHFIND).append(" " + pos); + case PHASE3_PF_MANIFEST_SEARCH -> Component.translatable(UL_COMPILE_PF_MANIFEST).append(" " + pos); + case PHASE4_REGISTER_REMAPS -> Component.translatable(UL_COMPILE_ADD_REMAPS).append(" " + pos); + case PHASE5_CONSUME_REMAPS -> Component.translatable(UL_COMPILE_REMAP).append(" " + pos); + case PHASE6_COLLECT -> Component.translatable(UL_COMPILE_COLLECT).append(" " + pos); + + default -> Component.translatable(STEP_TYPE_NAMES.get(node.step)); + }; + } + + public static void buildTooltipForCTNNode(CompileTreeNode node, List toolTip) { + toolTip.add(getTitleForCTNNode(node)); + toolTip.add(Component.translatable(STEP_TYPE_DESC.get(node.step)).withStyle(UNIFORM_GRAY)); + + if (!node.registerIds.isEmpty()) { + toolTip.add(Component.translatable(UL_UNIT_ONLY_REGISTERS).append(":").withStyle(UNIFORM_GRAY)); + addIntegerList(toolTip, node.registerIds, "R", 2, 4, UNIFORM_GRAY); + } + + if (!node.gateIds.isEmpty()) { + toolTip.add(Component.translatable(UL_UNIT_ONLY_GATES).append(":").withStyle(UNIFORM_GRAY)); + addIntegerList(toolTip, node.gateIds, "G", 2, 4, UNIFORM_GRAY); + } + + if (!node.registerRemaps.isEmpty()) { + toolTip.add(Component.translatable(UL_UNIT_ONLY_REMAPS).append(":").withStyle(UNIFORM_GRAY)); + addIntegerMap(toolTip, node.registerRemaps, "R", 2, 4, UNIFORM_GRAY); + } + + if (!node.children.isEmpty()) { + int r = node.countRegIdsInSubtree(); + int g = node.countGateIdsInSubtree(); + int m = node.countRemapsInSubtree(); + + if (r > 0) { + toolTip.add(Component.literal(" " + r + " ").append(Component.translatable(UL_UNIT_ONLY_REGISTERS)).withStyle(UNIFORM_GRAY)); + } + if (g > 0) { + toolTip.add(Component.literal(" " + g + " ").append(Component.translatable(UL_UNIT_ONLY_GATES)).withStyle(UNIFORM_GRAY)); + } + if (m > 0) { + toolTip.add(Component.literal(" " + m + " ").append(Component.translatable(UL_UNIT_ONLY_REMAPS)).withStyle(UNIFORM_GRAY)); + } + } + } + + private static void addIntegerMap(List toolTip, Map regMap, String prefix, int indent, int limitPerLine, Style style) { + var list = FastStream.of(regMap.entrySet()).map(e -> prefix + e.getKey() + " -> " + prefix + e.getValue()).toList(); + addStringList(toolTip, list, indent, limitPerLine, style); + } + + private static void addIntegerList(List toolTip, List regList, String prefix, int indent, int limitPerLine, Style style) { + var list = FastStream.of(regList).map(i -> prefix + i).toList(); + addStringList(toolTip, list, indent, limitPerLine, style); + } + + private static void addStringList(List toolTip, List strList, int indent, int limitPerLine, Style style) { + + Component indentStr = Component.literal(" ".repeat(indent)); + + if (strList.isEmpty()) { + toolTip.add(indentStr.copy().append(Component.translatable(UL_UNIT_ONLY_NONE)).withStyle(UNIFORM_GRAY)); + return; + } + + StringBuilder s = new StringBuilder(); + int i = 0; + for (var str : strList) { + s.append(str); + + // Add comma if not last element + if (i < strList.size() - 1) { + s.append(", "); + } + + i++; + + // If last string or line is ended + if (i == strList.size() || (i > 0 && i % limitPerLine == 0)) { + toolTip.add(indentStr.copy().append(s.toString()).withStyle(style)); + s = new StringBuilder(); + } + } + } + + private class ScrollBar extends ScrollBarNode { + + public ScrollBar() { + super(ScrollAxis.VERTICAL); + } + + @Override + protected void drawSlider(PoseStack stack, Rect sliderFrame) { + RenderSystem.setShaderTexture(0, ICWorkbenchCompileTab.TAB_BACKGROUND); + GuiComponent.blit(stack, sliderFrame.x(), sliderFrame.y(), 305, 58, sliderFrame.width(), sliderFrame.height(), 512, 512); + } + + @Override + protected void adjustContent(double scrollPercentage) { + ctnListNode.setScrollPercentage(scrollPercentage); + } + } } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ProblemListNode.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ProblemListNode.java index 0ab125ecd..e84f614fe 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ProblemListNode.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/gui/ProblemListNode.java @@ -2,12 +2,13 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +import mrtjp.projectred.fabrication.editor.ICWorkbenchEditor; import mrtjp.projectred.fabrication.engine.log.CompileProblem; import mrtjp.projectred.fabrication.gui.screen.ICWorkbenchCompileTab; import mrtjp.projectred.lib.Point; import mrtjp.projectred.lib.Rect; import mrtjp.projectred.redui.AbstractGuiNode; -import net.minecraft.client.gui.GuiComponent; +import mrtjp.projectred.redui.RedUISprite; import net.minecraft.network.chat.Component; import java.util.LinkedList; @@ -84,21 +85,23 @@ public void onSubTreePostDrawBack() { private class IssueListItemNode extends AbstractGuiNode { + private static final RedUISprite BACKGROUND_UNSELECTED = new RedUISprite(ICWorkbenchCompileTab.TAB_BACKGROUND, 1, 375, 79, 12, 512, 512); +// private static final RedUISprite BACKGROUND_SELECTED = new RedUISprite(ICWorkbenchCompileTab.TAB_BACKGROUND, 81, 375, 79, 12, 512, 512); + private final CompileProblem issue; public IssueListItemNode(CompileProblem issue) { this.issue = issue; - setSize(67, 12); + setSize(79, 12); } @Override public void drawBack(PoseStack stack, Point mouse, float partialFrame) { - RenderSystem.setShaderTexture(0, ICWorkbenchCompileTab.TAB_BACKGROUND); - - GuiComponent.blit(stack, getFrame().x(), getFrame().y(), 1, 375, getFrame().width(), getFrame().height(), 512, 512); + blitSprite(stack, BACKGROUND_UNSELECTED); - Component s = issue.getName(); - getRoot().getFontRenderer().draw(stack, s, getFrame().x() + 2, getFrame().y() + 2, 0xFFFFFF); + var fr = getRoot().getFontRenderer(); + Component c = issue.getName().copy().withStyle(ICWorkbenchEditor.UNIFORM); + fr.draw(stack, c, getFrame().x() + 2, getFrame().y() + getFrame().height() / 2f - fr.lineHeight / 2f, 0xFFFFFF); } @Override @@ -106,6 +109,7 @@ public void drawFront(PoseStack stack, Point mouse, float partialFrame) { if (!isFirstHit(mouse)) return; List toolTip = new LinkedList<>(); + toolTip.add(issue.getName()); issue.buildToolTip(toolTip); renderTooltip(stack, mouse, toolTip); } diff --git a/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java index 1f2b7d161..e4d990e4a 100644 --- a/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java +++ b/fabrication/src/main/java/mrtjp/projectred/fabrication/init/FabricationUnlocal.java @@ -34,6 +34,48 @@ public class FabricationUnlocal { public static final String UL_TIME_DELAY = PREFIX + "interact.delay"; public static final String UL_DEFAULT_STATE = PREFIX + "interact.default_state"; + // Compile + public static final String UL_COMPILE_TREE = PREFIX + "compile.tree"; + public static final String UL_COMPILE_STACK = PREFIX + "compile.stack"; + public static final String UL_COMPILE_CHECK_TILE_MAP = PREFIX + "compile.step.check_tile_maps"; + public static final String UL_COMPILE_CHECK_FLAT_MAP = PREFIX + "compile.step.check_flat_maps"; + public static final String UL_COMPILE_MERGE_TILE_MAP = PREFIX + "compile.step.merge_tile_map"; + public static final String UL_COMPILE_MERGE_FLAT_MAP = PREFIX + "compile.step.merge_flat_map"; + public static final String UL_COMPILE_MERGE_TILE_MAP_PRE = PREFIX + "compile.step.merge_tile_map_pre"; + public static final String UL_COMPILE_PHASE_1 = PREFIX + "compile.step.merge_tile_map_phase1"; + public static final String UL_COMPILE_ALLOC = PREFIX + "compile.step.merge_tile_map_alloc"; + public static final String UL_COMPILE_PHASE_2 = PREFIX + "compile.step.merge_tile_map_phase2"; + public static final String UL_COMPILE_PATHFIND = PREFIX + "compile.step.merge_tile_map_pathfind"; + public static final String UL_COMPILE_PHASE_3 = PREFIX + "compile.step.merge_tile_map_phase3"; + public static final String UL_COMPILE_PF_MANIFEST = PREFIX + "compile.step.merge_tile_map_manifest_search"; + public static final String UL_COMPILE_PHASE_4 = PREFIX + "compile.step.merge_tile_map_phase4"; + public static final String UL_COMPILE_ADD_REMAPS = PREFIX + "compile.step.merge_tile_map_add_remaps"; + public static final String UL_COMPILE_PHASE_5 = PREFIX + "compile.step.merge_tile_map_phase5"; + public static final String UL_COMPILE_REMAP = PREFIX + "compile.step.merge_tile_map_consume_remaps"; + public static final String UL_COMPILE_PHASE_6 = PREFIX + "compile.step.merge_tile_map_phase6"; + public static final String UL_COMPILE_COLLECT = PREFIX + "compile.step.merge_tile_map_collect"; + public static final String UL_COMPILE_MERGE_TILE_MAP_POST = PREFIX + "compile.step.merge_tile_map_post"; + + public static final String UL_COMPILE_CHECK_TILE_MAP_DESC = PREFIX + "compile.step.check_tile_maps.desc"; + public static final String UL_COMPILE_CHECK_FLAT_MAP_DESC = PREFIX + "compile.step.check_flat_maps.desc"; + public static final String UL_COMPILE_MERGE_TILE_MAP_DESC = PREFIX + "compile.step.merge_tile_map.desc"; + public static final String UL_COMPILE_MERGE_FLAT_MAP_DESC = PREFIX + "compile.step.merge_flat_map.desc"; + public static final String UL_COMPILE_MERGE_TILE_MAP_PRE_DESC = PREFIX + "compile.step.merge_tile_map_pre.desc"; + public static final String UL_COMPILE_PHASE_1_DESC = PREFIX + "compile.step.merge_tile_map_phase1.desc"; + public static final String UL_COMPILE_ALLOC_DESC = PREFIX + "compile.step.merge_tile_map_alloc.desc"; + public static final String UL_COMPILE_PHASE_2_DESC = PREFIX + "compile.step.merge_tile_map_phase2.desc"; + public static final String UL_COMPILE_PATHFIND_DESC = PREFIX + "compile.step.merge_tile_map_pathfind.desc"; + public static final String UL_COMPILE_PHASE_3_DESC = PREFIX + "compile.step.merge_tile_map_phase3.desc"; + public static final String UL_COMPILE_PF_MANIFEST_DESC = PREFIX + "compile.step.merge_tile_map_manifest_search.desc"; + public static final String UL_COMPILE_PHASE_4_DESC = PREFIX + "compile.step.merge_tile_map_phase4.desc"; + public static final String UL_COMPILE_ADD_REMAPS_DESC = PREFIX + "compile.step.merge_tile_map_add_remaps.desc"; + public static final String UL_COMPILE_PHASE_5_DESC = PREFIX + "compile.step.merge_tile_map_phase5.desc"; + public static final String UL_COMPILE_REMAP_DESC = PREFIX + "compile.step.merge_tile_map_consume_remaps.desc"; + public static final String UL_COMPILE_PHASE_6_DESC = PREFIX + "compile.step.merge_tile_map_phase6.desc"; + public static final String UL_COMPILE_COLLECT_DESC = PREFIX + "compile.step.merge_tile_map_collect.desc"; + public static final String UL_COMPILE_MERGE_TILE_MAP_POST_DESC = PREFIX + "compile.step.merge_tile_map_post.desc"; + + // Problems public static final String UL_MULTIPLE_DRIVERS_TITLE = PREFIX + "problems.multiple_drivers.title"; public static final String UL_MULTIPLE_DRIVERS_DESC = PREFIX + "problems.multiple_drivers.desc"; @@ -119,15 +161,19 @@ public class FabricationUnlocal { public static final String UL_INTERFACE_BUNDLED = PREFIX + "interface.bundled"; // Numbers and measurements //TODO drop this formattable ones and just do it in code - public static final String UL_UNIT_WARNINGS = PREFIX + "unit.warnings"; - public static final String UL_UNIT_ERRORS = PREFIX + "unit.errors"; - public static final String UL_UNIT_TICKS = PREFIX + "unit.ticks"; - public static final String UL_DIMENSIONS_NM = PREFIX + "dimensions.nm"; - public static final String UL_DIMENSIONS_TILES = PREFIX + "dimensions.tiles"; - public static final String UL_DIMENSIONS_DIES = PREFIX + "dimensions.dies"; - public static final String UL_DIMENSIONS_NM_TOTAL = PREFIX + "dimensions.nm_total"; - public static final String UL_DIMENSIONS_TILES_TOTAL = PREFIX + "dimensions.tiles_total"; - public static final String UL_DIMENSIONS_DIES_TOTAL = PREFIX + "dimensions.dies_total"; - - public static final String UL_UNIT_ONLY_TICKS = PREFIX + "unit_only.ticks"; + public static final String UL_UNIT_WARNINGS = PREFIX + "f.unit.warnings"; + public static final String UL_UNIT_ERRORS = PREFIX + "f.unit.errors"; + public static final String UL_UNIT_TICKS = PREFIX + "f.unit.ticks"; + public static final String UL_DIMENSIONS_NM = PREFIX + "f.dimensions.nm"; + public static final String UL_DIMENSIONS_TILES = PREFIX + "f.dimensions.tiles"; + public static final String UL_DIMENSIONS_DIES = PREFIX + "f.dimensions.dies"; + public static final String UL_DIMENSIONS_NM_TOTAL = PREFIX + "f.dimensions.nm_total"; + public static final String UL_DIMENSIONS_TILES_TOTAL = PREFIX + "f.dimensions.tiles_total"; + public static final String UL_DIMENSIONS_DIES_TOTAL = PREFIX + "f.dimensions.dies_total"; + + public static final String UL_UNIT_ONLY_TICKS = PREFIX + "unit.ticks"; + public static final String UL_UNIT_ONLY_REGISTERS = PREFIX + "unit.registers"; + public static final String UL_UNIT_ONLY_GATES = PREFIX + "unit.gates"; + public static final String UL_UNIT_ONLY_REMAPS = PREFIX + "unit.remaps"; + public static final String UL_UNIT_ONLY_NONE = PREFIX + "unit.none"; } diff --git a/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/compile_tab.png b/fabrication/src/main/resources/assets/projectred_fabrication/textures/gui/compile_tab.png index 22f3fb54769beaa8564822f69c18f843731394f5..6aa7ca8b54e3246adc5f6b49d8a07e31d7f66866 100644 GIT binary patch delta 9313 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 ZWW4<(=l! diff --git a/gradle.properties b/gradle.properties index 7bf035b23..605ac8bf8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,6 +11,6 @@ cbm_version=3.2.0.+ jei_version=11.5.0.+ cct_version=1.101.3 -fabrication_version=0.1.0-alpha-17 +fabrication_version=0.1.0-alpha-19 org.gradle.jvmargs=-Xmx4096M