mirror of
https://github.com/LeavesMC/Leaves.git
synced 2025-12-19 14:59:32 +00:00
591 lines
26 KiB
Diff
591 lines
26 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: violetc <58360096+s-yh-china@users.noreply.github.com>
|
|
Date: Mon, 4 Sep 2023 00:16:09 +0800
|
|
Subject: [PATCH] Wool Hopper Counter
|
|
|
|
This patch is Powered by fabric-carpet(https://github.com/gnembon/fabric-carpet)
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/item/crafting/Ingredient.java b/src/main/java/net/minecraft/world/item/crafting/Ingredient.java
|
|
index e314f36951e9ac15c57137e24fce8c410373130a..dd232d9e86c5bf03cfb4597d3291a172d8c17741 100644
|
|
--- a/src/main/java/net/minecraft/world/item/crafting/Ingredient.java
|
|
+++ b/src/main/java/net/minecraft/world/item/crafting/Ingredient.java
|
|
@@ -35,7 +35,7 @@ public final class Ingredient implements Predicate<ItemStack> {
|
|
}, (recipeitemstack) -> {
|
|
return Arrays.asList(recipeitemstack.getItems());
|
|
});
|
|
- private final Ingredient.Value[] values;
|
|
+ public final Ingredient.Value[] values; // Leaves - private -> public
|
|
@Nullable
|
|
public ItemStack[] itemStacks;
|
|
@Nullable
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
|
index cee74a6c47cd56a17a8faf68405fee09d6fd4655..9cc932fb547686db7c06f7ef29e3b07b2e755982 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
|
@@ -447,7 +447,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
|
private static final java.util.function.BiPredicate<ItemStack, Integer> IS_EMPTY_TEST = (itemstack, i) -> itemstack.isEmpty();
|
|
// Paper end - Perf: Optimize Hoppers
|
|
|
|
+ // Leaves start - hopper counter
|
|
private static boolean ejectItems(Level world, BlockPos pos, HopperBlockEntity blockEntity) {
|
|
+ if (org.leavesmc.leaves.util.HopperCounter.isEnabled()) {
|
|
+ if (woolHopperCounter(world, pos, world.getBlockState(pos), (Container) blockEntity, blockEntity)) {
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ // Leaves end - hopper counter
|
|
Container iinventory = HopperBlockEntity.getAttachedContainer(world, pos, blockEntity);
|
|
|
|
if (iinventory == null) {
|
|
@@ -511,6 +518,23 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
|
}
|
|
}
|
|
|
|
+ // Leaves start - hopper counter
|
|
+ private static boolean woolHopperCounter(Level level, BlockPos blockPos, BlockState state, Container container, HopperBlockEntity hopper) {
|
|
+ net.minecraft.world.item.DyeColor woolColor = org.leavesmc.leaves.util.WoolUtils.getWoolColorAtPosition(level, blockPos.relative(state.getValue(HopperBlock.FACING)));
|
|
+ if (woolColor != null) {
|
|
+ for (int i = 0; i < container.getContainerSize(); ++i) {
|
|
+ if (!container.getItem(i).isEmpty()) {
|
|
+ ItemStack itemstack = container.getItem(i);
|
|
+ org.leavesmc.leaves.util.HopperCounter.getCounter(woolColor).add(level.getServer(), itemstack);
|
|
+ container.setItem(i, ItemStack.EMPTY);
|
|
+ }
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+ // Leaves end - hopper counter
|
|
+
|
|
private static int[] getSlots(Container inventory, Direction side) {
|
|
if (inventory instanceof WorldlyContainer iworldinventory) {
|
|
return iworldinventory.getSlotsForFace(side);
|
|
diff --git a/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java b/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java
|
|
index 92a8c3e4fc400988b3d984e7632a8149a2ce152e..99823283690fcc1e6c0f76d8dcbcca9dfb50470d 100644
|
|
--- a/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java
|
|
+++ b/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java
|
|
@@ -34,6 +34,7 @@ public final class LeavesCommand extends Command {
|
|
commands.put(Set.of("config"), new ConfigCommand());
|
|
commands.put(Set.of("update"), new UpdateCommand());
|
|
commands.put(Set.of("peaceful"), new PeacefulModeSwitchCommand());
|
|
+ commands.put(Set.of("counter"), new CounterCommand());
|
|
|
|
return commands.entrySet().stream()
|
|
.flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue())))
|
|
diff --git a/src/main/java/org/leavesmc/leaves/command/subcommands/CounterCommand.java b/src/main/java/org/leavesmc/leaves/command/subcommands/CounterCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..06b4d287bf545a51b9eeb7cd24fdc6a0c05271d9
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/command/subcommands/CounterCommand.java
|
|
@@ -0,0 +1,121 @@
|
|
+package org.leavesmc.leaves.command.subcommands;
|
|
+
|
|
+import net.kyori.adventure.text.Component;
|
|
+import net.kyori.adventure.text.JoinConfiguration;
|
|
+import net.kyori.adventure.text.format.NamedTextColor;
|
|
+import net.kyori.adventure.text.format.TextColor;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import net.minecraft.world.item.DyeColor;
|
|
+import org.bukkit.command.CommandSender;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.leavesmc.leaves.LeavesConfig;
|
|
+import org.leavesmc.leaves.command.LeavesCommandUtil;
|
|
+import org.leavesmc.leaves.command.LeavesSubcommand;
|
|
+import org.leavesmc.leaves.util.HopperCounter;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.Arrays;
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+
|
|
+public class CounterCommand implements LeavesSubcommand {
|
|
+
|
|
+ @Override
|
|
+ public boolean execute(CommandSender sender, String subCommand, String[] args) {
|
|
+ if (!LeavesConfig.hopperCounter) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (args.length < 1) {
|
|
+ sender.sendMessage(Component.join(JoinConfiguration.noSeparators(),
|
|
+ Component.text("Hopper Counter: ", NamedTextColor.GRAY),
|
|
+ Component.text(HopperCounter.isEnabled(), HopperCounter.isEnabled() ? NamedTextColor.AQUA : NamedTextColor.GRAY)
|
|
+ ));
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ if (!HopperCounter.isEnabled()) {
|
|
+ if (args[0].equals("enable")) {
|
|
+ HopperCounter.setEnabled(true);
|
|
+ sender.sendMessage(Component.text("Hopper Counter now is enabled", NamedTextColor.AQUA));
|
|
+ } else {
|
|
+ sender.sendMessage(Component.text("Hopper Counter is not enabled", NamedTextColor.RED));
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ DyeColor color = DyeColor.byName(args[0], null);
|
|
+ if (color != null) {
|
|
+ HopperCounter counter = HopperCounter.getCounter(color);
|
|
+ if (args.length < 2) {
|
|
+ displayCounter(sender, counter, false);
|
|
+ } else {
|
|
+ switch (args[1]) {
|
|
+ case "reset" -> {
|
|
+ counter.reset(MinecraftServer.getServer());
|
|
+ sender.sendMessage(Component.join(JoinConfiguration.noSeparators(),
|
|
+ Component.text("Restarted "),
|
|
+ Component.text(color.getName(), TextColor.color(color.getTextColor())),
|
|
+ Component.text(" counter")
|
|
+ ));
|
|
+ }
|
|
+ case "realtime" -> displayCounter(sender, counter, true);
|
|
+ }
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ switch (args[0]) {
|
|
+ case "reset" -> {
|
|
+ HopperCounter.resetAll(MinecraftServer.getServer(), false);
|
|
+ sender.sendMessage(Component.text("Restarted all counters"));
|
|
+ }
|
|
+ case "disable" -> {
|
|
+ HopperCounter.setEnabled(false);
|
|
+ HopperCounter.resetAll(MinecraftServer.getServer(), true);
|
|
+ sender.sendMessage(Component.text("Hopper Counter now is disabled", NamedTextColor.GRAY));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ private void displayCounter(CommandSender sender, @NotNull HopperCounter counter, boolean realTime) {
|
|
+ for (Component component : counter.format(MinecraftServer.getServer(), realTime)) {
|
|
+ sender.sendMessage(component);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public List<String> tabComplete(CommandSender sender, String subCommand, String[] args) {
|
|
+ if (!LeavesConfig.hopperCounter) {
|
|
+ return Collections.emptyList();
|
|
+ }
|
|
+
|
|
+ switch (args.length) {
|
|
+ case 1 -> {
|
|
+ if (!HopperCounter.isEnabled()) {
|
|
+ return Collections.singletonList("enable");
|
|
+ }
|
|
+
|
|
+ List<String> list = new ArrayList<>(Arrays.stream(DyeColor.values()).map(DyeColor::getName).toList());
|
|
+ list.add("reset");
|
|
+ list.add("disable");
|
|
+ return LeavesCommandUtil.getListMatchingLast(sender, args, list);
|
|
+ }
|
|
+
|
|
+ case 2 -> {
|
|
+ if (DyeColor.byName(args[0], null) != null) {
|
|
+ return LeavesCommandUtil.getListMatchingLast(sender, args, "reset", "realtime");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return Collections.emptyList();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean tabCompletes() {
|
|
+ return LeavesConfig.hopperCounter;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/util/HopperCounter.java b/src/main/java/org/leavesmc/leaves/util/HopperCounter.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..1a83b3918bc040ab32e648b54b498e9a556c17a3
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/util/HopperCounter.java
|
|
@@ -0,0 +1,338 @@
|
|
+package org.leavesmc.leaves.util;
|
|
+
|
|
+import it.unimi.dsi.fastutil.objects.Object2LongLinkedOpenHashMap;
|
|
+import it.unimi.dsi.fastutil.objects.Object2LongMap;
|
|
+import net.kyori.adventure.text.Component;
|
|
+import net.kyori.adventure.text.TextComponent;
|
|
+import net.kyori.adventure.text.format.NamedTextColor;
|
|
+import net.kyori.adventure.text.format.Style;
|
|
+import net.kyori.adventure.text.format.TextColor;
|
|
+import net.kyori.adventure.text.format.TextDecoration;
|
|
+import net.minecraft.core.Registry;
|
|
+import net.minecraft.core.RegistryAccess;
|
|
+import net.minecraft.core.registries.Registries;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import net.minecraft.world.item.BlockItem;
|
|
+import net.minecraft.world.item.DyeColor;
|
|
+import net.minecraft.world.item.DyeItem;
|
|
+import net.minecraft.world.item.Item;
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+import net.minecraft.world.item.Items;
|
|
+import net.minecraft.world.item.crafting.Ingredient;
|
|
+import net.minecraft.world.item.crafting.Recipe;
|
|
+import net.minecraft.world.item.crafting.RecipeHolder;
|
|
+import net.minecraft.world.item.crafting.RecipeManager;
|
|
+import net.minecraft.world.item.crafting.RecipeType;
|
|
+import net.minecraft.world.level.block.AbstractBannerBlock;
|
|
+import net.minecraft.world.level.block.BeaconBeamBlock;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+import net.minecraft.world.level.block.Blocks;
|
|
+import net.minecraft.world.level.material.MapColor;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.LeavesConfig;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.Arrays;
|
|
+import java.util.Collection;
|
|
+import java.util.Collections;
|
|
+import java.util.EnumMap;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+
|
|
+import static java.util.Map.entry;
|
|
+
|
|
+public class HopperCounter {
|
|
+
|
|
+ private static boolean enabled = false;
|
|
+ private static final Map<DyeColor, HopperCounter> COUNTERS;
|
|
+
|
|
+ static {
|
|
+ EnumMap<DyeColor, HopperCounter> counterMap = new EnumMap<>(DyeColor.class);
|
|
+ for (DyeColor color : DyeColor.values()) {
|
|
+ counterMap.put(color, new HopperCounter(color));
|
|
+ }
|
|
+ COUNTERS = Collections.unmodifiableMap(counterMap);
|
|
+ }
|
|
+
|
|
+ public final DyeColor color;
|
|
+ private final TextComponent coloredName;
|
|
+ private final Object2LongMap<Item> counter = new Object2LongLinkedOpenHashMap<>();
|
|
+ private long startTick;
|
|
+ private long startMillis;
|
|
+
|
|
+ private HopperCounter(DyeColor color) {
|
|
+ this.startTick = -1;
|
|
+ this.color = color;
|
|
+ this.coloredName = Component.text(color.getName(), TextColor.color(color.getTextColor()));
|
|
+ }
|
|
+
|
|
+ public void add(MinecraftServer server, ItemStack stack) {
|
|
+ if (startTick < 0) {
|
|
+ startTick = server.overworld().getGameTime();
|
|
+ startMillis = System.currentTimeMillis();
|
|
+ }
|
|
+ Item item = stack.getItem();
|
|
+ counter.put(item, counter.getLong(item) + stack.getCount());
|
|
+ }
|
|
+
|
|
+ public void reset(MinecraftServer server) {
|
|
+ counter.clear();
|
|
+ startTick = server.overworld().getGameTime();
|
|
+ startMillis = System.currentTimeMillis();
|
|
+ }
|
|
+
|
|
+ public List<Component> format(MinecraftServer server, boolean realTime) {
|
|
+ long ticks = Math.max(realTime ? (System.currentTimeMillis() - startMillis) / 50 : server.overworld().getGameTime() - startTick, -1);
|
|
+
|
|
+ if (startTick < 0 || ticks == -1) {
|
|
+ return Collections.singletonList(Component.text().append(coloredName, Component.text(" hasn't started counting yet")).build());
|
|
+ }
|
|
+
|
|
+ long total = getTotalItems();
|
|
+ if (total <= 0) {
|
|
+ return Collections.singletonList(Component.text()
|
|
+ .append(Component.text("No items for "), coloredName)
|
|
+ .append(Component.text(" yet ("), Component.text(String.format("%.2f ", ticks / (20.0 * 60.0)), Style.style(TextDecoration.BOLD)))
|
|
+ .append(Component.text("min"), Component.text(realTime ? " - real time" : ""), Component.text(")"))
|
|
+ .build());
|
|
+ }
|
|
+
|
|
+ List<Component> items = new ArrayList<>();
|
|
+ items.add(Component.text()
|
|
+ .append(Component.text("Items for "), coloredName, Component.text(" "))
|
|
+ .append(Component.text("("), Component.text(String.format("%.2f ", ticks * 1.0 / (20 * 60)), Style.style(TextDecoration.BOLD)))
|
|
+ .append(Component.text("min"), Component.text(realTime ? " - real time" : ""), Component.text("), "))
|
|
+ .append(Component.text("total: "), Component.text(total, Style.style(TextDecoration.BOLD)), Component.text(", "))
|
|
+ .append(Component.text("("), Component.text(String.format("%.1f", total * 1.0 * (20 * 60 * 60) / ticks), Style.style(TextDecoration.BOLD)))
|
|
+ .append(Component.text("/h):"))
|
|
+ .build());
|
|
+
|
|
+ counter.object2LongEntrySet().forEach(entry -> {
|
|
+ Item item = entry.getKey();
|
|
+ Component name = Component.translatable(item.getDescriptionId());
|
|
+ TextColor textColor = guessColor(server, item);
|
|
+
|
|
+ if (textColor != null) {
|
|
+ name = name.style(name.style().merge(Style.style(textColor)));
|
|
+ } else {
|
|
+ name = name.style(name.style().merge(Style.style(TextDecoration.ITALIC)));
|
|
+ }
|
|
+
|
|
+ long count = entry.getLongValue();
|
|
+ items.add(Component.text()
|
|
+ .append(Component.text("- ", NamedTextColor.GRAY))
|
|
+ .append(name)
|
|
+ .append(Component.text(": ", NamedTextColor.GRAY))
|
|
+ .append(Component.text(count, Style.style(TextDecoration.BOLD)), Component.text(", ", NamedTextColor.GRAY))
|
|
+ .append(Component.text(String.format("%.1f", count * (20.0 * 60.0 * 60.0) / ticks), Style.style(TextDecoration.BOLD)))
|
|
+ .append(Component.text("/h"))
|
|
+ .build());
|
|
+ });
|
|
+ return items;
|
|
+ }
|
|
+
|
|
+ private static final Map<Item, Block> DEFAULTS = Map.<Item, Block>ofEntries(
|
|
+ entry(Items.DANDELION, Blocks.YELLOW_WOOL),
|
|
+ entry(Items.POPPY, Blocks.RED_WOOL),
|
|
+ entry(Items.BLUE_ORCHID, Blocks.LIGHT_BLUE_WOOL),
|
|
+ entry(Items.ALLIUM, Blocks.MAGENTA_WOOL),
|
|
+ entry(Items.AZURE_BLUET, Blocks.SNOW_BLOCK),
|
|
+ entry(Items.RED_TULIP, Blocks.RED_WOOL),
|
|
+ entry(Items.ORANGE_TULIP, Blocks.ORANGE_WOOL),
|
|
+ entry(Items.WHITE_TULIP, Blocks.SNOW_BLOCK),
|
|
+ entry(Items.PINK_TULIP, Blocks.PINK_WOOL),
|
|
+ entry(Items.OXEYE_DAISY, Blocks.SNOW_BLOCK),
|
|
+ entry(Items.CORNFLOWER, Blocks.BLUE_WOOL),
|
|
+ entry(Items.WITHER_ROSE, Blocks.BLACK_WOOL),
|
|
+ entry(Items.LILY_OF_THE_VALLEY, Blocks.WHITE_WOOL),
|
|
+ entry(Items.BROWN_MUSHROOM, Blocks.BROWN_MUSHROOM_BLOCK),
|
|
+ entry(Items.RED_MUSHROOM, Blocks.RED_MUSHROOM_BLOCK),
|
|
+ entry(Items.STICK, Blocks.OAK_PLANKS),
|
|
+ entry(Items.GOLD_INGOT, Blocks.GOLD_BLOCK),
|
|
+ entry(Items.IRON_INGOT, Blocks.IRON_BLOCK),
|
|
+ entry(Items.DIAMOND, Blocks.DIAMOND_BLOCK),
|
|
+ entry(Items.NETHERITE_INGOT, Blocks.NETHERITE_BLOCK),
|
|
+ entry(Items.SUNFLOWER, Blocks.YELLOW_WOOL),
|
|
+ entry(Items.LILAC, Blocks.MAGENTA_WOOL),
|
|
+ entry(Items.ROSE_BUSH, Blocks.RED_WOOL),
|
|
+ entry(Items.PEONY, Blocks.PINK_WOOL),
|
|
+ entry(Items.CARROT, Blocks.ORANGE_WOOL),
|
|
+ entry(Items.APPLE, Blocks.RED_WOOL),
|
|
+ entry(Items.WHEAT, Blocks.HAY_BLOCK),
|
|
+ entry(Items.PORKCHOP, Blocks.PINK_WOOL),
|
|
+ entry(Items.RABBIT, Blocks.PINK_WOOL),
|
|
+ entry(Items.CHICKEN, Blocks.WHITE_TERRACOTTA),
|
|
+ entry(Items.BEEF, Blocks.NETHERRACK),
|
|
+ entry(Items.ENCHANTED_GOLDEN_APPLE, Blocks.GOLD_BLOCK),
|
|
+ entry(Items.COD, Blocks.WHITE_TERRACOTTA),
|
|
+ entry(Items.SALMON, Blocks.ACACIA_PLANKS),
|
|
+ entry(Items.ROTTEN_FLESH, Blocks.BROWN_WOOL),
|
|
+ entry(Items.PUFFERFISH, Blocks.YELLOW_TERRACOTTA),
|
|
+ entry(Items.TROPICAL_FISH, Blocks.ORANGE_WOOL),
|
|
+ entry(Items.POTATO, Blocks.WHITE_TERRACOTTA),
|
|
+ entry(Items.MUTTON, Blocks.RED_WOOL),
|
|
+ entry(Items.BEETROOT, Blocks.NETHERRACK),
|
|
+ entry(Items.MELON_SLICE, Blocks.MELON),
|
|
+ entry(Items.POISONOUS_POTATO, Blocks.SLIME_BLOCK),
|
|
+ entry(Items.SPIDER_EYE, Blocks.NETHERRACK),
|
|
+ entry(Items.GUNPOWDER, Blocks.GRAY_WOOL),
|
|
+ entry(Items.TURTLE_SCUTE, Blocks.LIME_WOOL),
|
|
+ entry(Items.ARMADILLO_SCUTE, Blocks.ANCIENT_DEBRIS),
|
|
+ entry(Items.FEATHER, Blocks.WHITE_WOOL),
|
|
+ entry(Items.FLINT, Blocks.BLACK_WOOL),
|
|
+ entry(Items.LEATHER, Blocks.SPRUCE_PLANKS),
|
|
+ entry(Items.GLOWSTONE_DUST, Blocks.GLOWSTONE),
|
|
+ entry(Items.PAPER, Blocks.WHITE_WOOL),
|
|
+ entry(Items.BRICK, Blocks.BRICKS),
|
|
+ entry(Items.INK_SAC, Blocks.BLACK_WOOL),
|
|
+ entry(Items.SNOWBALL, Blocks.SNOW_BLOCK),
|
|
+ entry(Items.WATER_BUCKET, Blocks.WATER),
|
|
+ entry(Items.LAVA_BUCKET, Blocks.LAVA),
|
|
+ entry(Items.MILK_BUCKET, Blocks.WHITE_WOOL),
|
|
+ entry(Items.CLAY_BALL, Blocks.CLAY),
|
|
+ entry(Items.COCOA_BEANS, Blocks.COCOA),
|
|
+ entry(Items.BONE, Blocks.BONE_BLOCK),
|
|
+ entry(Items.COD_BUCKET, Blocks.BROWN_TERRACOTTA),
|
|
+ entry(Items.PUFFERFISH_BUCKET, Blocks.YELLOW_TERRACOTTA),
|
|
+ entry(Items.SALMON_BUCKET, Blocks.PINK_TERRACOTTA),
|
|
+ entry(Items.TROPICAL_FISH_BUCKET, Blocks.ORANGE_TERRACOTTA),
|
|
+ entry(Items.SUGAR, Blocks.WHITE_WOOL),
|
|
+ entry(Items.BLAZE_POWDER, Blocks.GOLD_BLOCK),
|
|
+ entry(Items.ENDER_PEARL, Blocks.WARPED_PLANKS),
|
|
+ entry(Items.NETHER_STAR, Blocks.DIAMOND_BLOCK),
|
|
+ entry(Items.PRISMARINE_CRYSTALS, Blocks.SEA_LANTERN),
|
|
+ entry(Items.PRISMARINE_SHARD, Blocks.PRISMARINE),
|
|
+ entry(Items.RABBIT_HIDE, Blocks.OAK_PLANKS),
|
|
+ entry(Items.CHORUS_FRUIT, Blocks.PURPUR_BLOCK),
|
|
+ entry(Items.SHULKER_SHELL, Blocks.SHULKER_BOX),
|
|
+ entry(Items.NAUTILUS_SHELL, Blocks.BONE_BLOCK),
|
|
+ entry(Items.HEART_OF_THE_SEA, Blocks.CONDUIT),
|
|
+ entry(Items.HONEYCOMB, Blocks.HONEYCOMB_BLOCK),
|
|
+ entry(Items.NAME_TAG, Blocks.BONE_BLOCK),
|
|
+ entry(Items.TOTEM_OF_UNDYING, Blocks.YELLOW_TERRACOTTA),
|
|
+ entry(Items.TRIDENT, Blocks.PRISMARINE),
|
|
+ entry(Items.GHAST_TEAR, Blocks.WHITE_WOOL),
|
|
+ entry(Items.PHANTOM_MEMBRANE, Blocks.BONE_BLOCK),
|
|
+ entry(Items.EGG, Blocks.BONE_BLOCK),
|
|
+ entry(Items.COPPER_INGOT, Blocks.COPPER_BLOCK),
|
|
+ entry(Items.AMETHYST_SHARD, Blocks.AMETHYST_BLOCK)
|
|
+ );
|
|
+
|
|
+ @Nullable
|
|
+ public static TextColor guessColor(@NotNull MinecraftServer server, Item item) {
|
|
+ RegistryAccess registryAccess = server.registryAccess();
|
|
+ TextColor direct = fromItem(item, registryAccess);
|
|
+ if (direct != null) {
|
|
+ return direct;
|
|
+ }
|
|
+
|
|
+ ResourceLocation id = registryAccess.registryOrThrow(Registries.ITEM).getKey(item);
|
|
+ for (RecipeType<?> type : registryAccess.registryOrThrow(Registries.RECIPE_TYPE)) {
|
|
+ for (Recipe<?> r : getAllMatching(server.getRecipeManager(), type, id, registryAccess)) {
|
|
+ for (Ingredient ingredient : r.getIngredients()) {
|
|
+ for (Collection<ItemStack> stacks : getRecipeStacks(ingredient)) {
|
|
+ for (ItemStack itemStack : stacks) {
|
|
+ TextColor textColor = fromItem(itemStack.getItem(), registryAccess);
|
|
+ if (textColor != null) {
|
|
+ return textColor;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Nullable
|
|
+ public static TextColor fromItem(Item item, RegistryAccess registryAccess) {
|
|
+ if (DEFAULTS.containsKey(item)) {
|
|
+ return TextColor.color(appropriateColor(DEFAULTS.get(item).defaultMapColor().col));
|
|
+ }
|
|
+ if (item instanceof DyeItem dye) {
|
|
+ return TextColor.color(appropriateColor(dye.getDyeColor().getMapColor().col));
|
|
+ }
|
|
+
|
|
+ Block block = null;
|
|
+ final Registry<Item> itemRegistry = registryAccess.registryOrThrow(Registries.ITEM);
|
|
+ final Registry<Block> blockRegistry = registryAccess.registryOrThrow(Registries.BLOCK);
|
|
+ ResourceLocation id = itemRegistry.getKey(item);
|
|
+ if (item instanceof BlockItem blockItem) {
|
|
+ block = blockItem.getBlock();
|
|
+ } else if (blockRegistry.getOptional(id).isPresent()) {
|
|
+ block = blockRegistry.get(id);
|
|
+ }
|
|
+
|
|
+ if (block != null) {
|
|
+ if (block instanceof AbstractBannerBlock) {
|
|
+ return TextColor.color(appropriateColor(((AbstractBannerBlock) block).getColor().getMapColor().col));
|
|
+ } else if (block instanceof BeaconBeamBlock) {
|
|
+ return TextColor.color(appropriateColor(((BeaconBeamBlock) block).getColor().getMapColor().col));
|
|
+ }
|
|
+ return TextColor.color(appropriateColor(block.defaultMapColor().col));
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ public static List<Recipe<?>> getAllMatching(@NotNull RecipeManager manager, RecipeType<?> type, ResourceLocation output, final RegistryAccess registryAccess) {
|
|
+ RecipeHolder<?> recipe = manager.byName.get(output);
|
|
+ if (recipe != null && recipe.value().getType().equals(type)) {
|
|
+ return List.of(recipe.value());
|
|
+ }
|
|
+ if (!manager.byType.containsKey(type)) {
|
|
+ return List.of();
|
|
+ }
|
|
+
|
|
+ Collection<RecipeHolder<?>> typeRecipes = manager.byType.get(type);
|
|
+ Registry<Item> regs = registryAccess.registryOrThrow(Registries.ITEM);
|
|
+ Item item = regs.get(output);
|
|
+ return typeRecipes.stream()
|
|
+ .<Recipe<?>>map(RecipeHolder::value)
|
|
+ .filter(r -> r.getResultItem(registryAccess).getItem() == item)
|
|
+ .toList();
|
|
+ }
|
|
+
|
|
+ public static List<Collection<ItemStack>> getRecipeStacks(@NotNull Ingredient ingredient) {
|
|
+ return Arrays.stream(ingredient.values).map(Ingredient.Value::getItems).toList();
|
|
+ }
|
|
+
|
|
+ public static int appropriateColor(int color) {
|
|
+ if (color == 0) {
|
|
+ return MapColor.SNOW.col;
|
|
+ }
|
|
+ int r = (color >> 16 & 255);
|
|
+ int g = (color >> 8 & 255);
|
|
+ int b = (color & 255);
|
|
+ if (r < 70) r = 70;
|
|
+ if (g < 70) g = 70;
|
|
+ if (b < 70) b = 70;
|
|
+ return (r << 16) + (g << 8) + b;
|
|
+ }
|
|
+
|
|
+ public long getTotalItems() {
|
|
+ return counter.isEmpty() ? 0 : counter.values().longStream().sum();
|
|
+ }
|
|
+
|
|
+ public static void resetAll(MinecraftServer server, boolean fresh) {
|
|
+ for (HopperCounter counter : COUNTERS.values()) {
|
|
+ counter.reset(server);
|
|
+ if (fresh) {
|
|
+ counter.startTick = -1;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static HopperCounter getCounter(DyeColor color) {
|
|
+ return COUNTERS.get(color);
|
|
+ }
|
|
+
|
|
+ public static void setEnabled(boolean is) {
|
|
+ enabled = is;
|
|
+ }
|
|
+
|
|
+ public static boolean isEnabled() {
|
|
+ return LeavesConfig.hopperCounter && enabled;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/util/WoolUtils.java b/src/main/java/org/leavesmc/leaves/util/WoolUtils.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..a4cd63179a15e5f172c43a2da963e23d7d71fc28
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/util/WoolUtils.java
|
|
@@ -0,0 +1,38 @@
|
|
+package org.leavesmc.leaves.util;
|
|
+
|
|
+import net.minecraft.core.BlockPos;
|
|
+import net.minecraft.world.item.DyeColor;
|
|
+import net.minecraft.world.level.Level;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+import net.minecraft.world.level.block.Blocks;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+
|
|
+import java.util.Map;
|
|
+
|
|
+import static java.util.Map.entry;
|
|
+
|
|
+public class WoolUtils {
|
|
+ private static final Map<Block, DyeColor> WOOL_BLOCK_TO_DYE = Map.ofEntries(
|
|
+ entry(Blocks.WHITE_WOOL, DyeColor.WHITE),
|
|
+ entry(Blocks.ORANGE_WOOL, DyeColor.ORANGE),
|
|
+ entry(Blocks.MAGENTA_WOOL, DyeColor.MAGENTA),
|
|
+ entry(Blocks.LIGHT_BLUE_WOOL, DyeColor.LIGHT_BLUE),
|
|
+ entry(Blocks.YELLOW_WOOL, DyeColor.YELLOW),
|
|
+ entry(Blocks.LIME_WOOL, DyeColor.LIME),
|
|
+ entry(Blocks.PINK_WOOL, DyeColor.PINK),
|
|
+ entry(Blocks.GRAY_WOOL, DyeColor.GRAY),
|
|
+ entry(Blocks.LIGHT_GRAY_WOOL, DyeColor.LIGHT_GRAY),
|
|
+ entry(Blocks.CYAN_WOOL, DyeColor.CYAN),
|
|
+ entry(Blocks.PURPLE_WOOL, DyeColor.PURPLE),
|
|
+ entry(Blocks.BLUE_WOOL, DyeColor.BLUE),
|
|
+ entry(Blocks.BROWN_WOOL, DyeColor.BROWN),
|
|
+ entry(Blocks.GREEN_WOOL, DyeColor.GREEN),
|
|
+ entry(Blocks.RED_WOOL, DyeColor.RED),
|
|
+ entry(Blocks.BLACK_WOOL, DyeColor.BLACK)
|
|
+ );
|
|
+
|
|
+ public static DyeColor getWoolColorAtPosition(Level worldIn, BlockPos pos) {
|
|
+ BlockState state = worldIn.getBlockState(pos);
|
|
+ return WOOL_BLOCK_TO_DYE.get(state.getBlock());
|
|
+ }
|
|
+}
|