9
0
mirror of https://github.com/LeavesMC/Leaves.git synced 2025-12-19 14:59:32 +00:00

Update Jade Protocol, and fix #250

This commit is contained in:
violetc
2024-07-07 18:17:30 +08:00
parent 0f2f631b74
commit b6ddd0b090

View File

@@ -44,17 +44,97 @@ index 055f4b87c01ee7ecf7d2a111b72cc5aa85d9fbe8..5d9030f4787a43c56ae9455180badd56
protected long nextMobSpawnsAt;
protected int totalMobsSpawned;
public Optional<SpawnData> nextSpawnData;
diff --git a/src/main/java/net/minecraft/world/level/storage/loot/LootPool.java b/src/main/java/net/minecraft/world/level/storage/loot/LootPool.java
index 38078c44b35e917d1d243a5f8599aa858d8611de..13dbadfb50278b79b33d9dce10413c93c9e4ff31 100644
--- a/src/main/java/net/minecraft/world/level/storage/loot/LootPool.java
+++ b/src/main/java/net/minecraft/world/level/storage/loot/LootPool.java
@@ -36,7 +36,7 @@ public class LootPool {
)
.apply(instance, LootPool::new)
);
- private final List<LootPoolEntryContainer> entries;
+ public final List<LootPoolEntryContainer> entries; // Leaves - private -> public
private final List<LootItemCondition> conditions;
private final Predicate<LootContext> compositeCondition;
private final List<LootItemFunction> functions;
diff --git a/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java b/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java
index edaf7f1692ae059581f3abc24bb228874e6d114b..f09cfc472d4dbdc8cb0b6a45ef240b25a865ffba 100644
--- a/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java
+++ b/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java
@@ -58,7 +58,7 @@ public class LootTable {
public static final Codec<Holder<LootTable>> CODEC = RegistryFileCodec.create(Registries.LOOT_TABLE, LootTable.DIRECT_CODEC);
private final LootContextParamSet paramSet;
private final Optional<ResourceLocation> randomSequence;
- private final List<LootPool> pools;
+ public final List<LootPool> pools; // Leaves - private -> public
private final List<LootItemFunction> functions;
private final BiFunction<ItemStack, LootContext, ItemStack> compositeFunction;
public CraftLootTable craftLootTable; // CraftBukkit
diff --git a/src/main/java/net/minecraft/world/level/storage/loot/entries/CompositeEntryBase.java b/src/main/java/net/minecraft/world/level/storage/loot/entries/CompositeEntryBase.java
index 128792f76f02d74c1ccf84beb8e7973453424639..775fbddf3e3b133e33f54aaa8e8a07d131095e34 100644
--- a/src/main/java/net/minecraft/world/level/storage/loot/entries/CompositeEntryBase.java
+++ b/src/main/java/net/minecraft/world/level/storage/loot/entries/CompositeEntryBase.java
@@ -9,7 +9,7 @@ import net.minecraft.world.level.storage.loot.ValidationContext;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
public abstract class CompositeEntryBase extends LootPoolEntryContainer {
- protected final List<LootPoolEntryContainer> children;
+ public final List<LootPoolEntryContainer> children; // Leaves - private -> public
private final ComposableEntryContainer composedChildren;
protected CompositeEntryBase(List<LootPoolEntryContainer> terms, List<LootItemCondition> conditions) {
diff --git a/src/main/java/net/minecraft/world/level/storage/loot/entries/LootPoolEntryContainer.java b/src/main/java/net/minecraft/world/level/storage/loot/entries/LootPoolEntryContainer.java
index 1d2f2bb352abf6772cd20293575fc79e8e64ce3b..b157dfaf1efffebd3f2ae8cb8fcf0972fe742258 100644
--- a/src/main/java/net/minecraft/world/level/storage/loot/entries/LootPoolEntryContainer.java
+++ b/src/main/java/net/minecraft/world/level/storage/loot/entries/LootPoolEntryContainer.java
@@ -13,7 +13,7 @@ import net.minecraft.world.level.storage.loot.predicates.ConditionUserBuilder;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
public abstract class LootPoolEntryContainer implements ComposableEntryContainer {
- protected final List<LootItemCondition> conditions;
+ public final List<LootItemCondition> conditions; // Leaves - private -> public
private final Predicate<LootContext> compositeCondition;
protected LootPoolEntryContainer(List<LootItemCondition> conditions) {
diff --git a/src/main/java/net/minecraft/world/level/storage/loot/entries/NestedLootTable.java b/src/main/java/net/minecraft/world/level/storage/loot/entries/NestedLootTable.java
index 71989359192c8f30a1a8d343a2c6cb5b92330491..ec273bd4d0e61f54532df599f00695e8b9d44800 100644
--- a/src/main/java/net/minecraft/world/level/storage/loot/entries/NestedLootTable.java
+++ b/src/main/java/net/minecraft/world/level/storage/loot/entries/NestedLootTable.java
@@ -25,7 +25,7 @@ public class NestedLootTable extends LootPoolSingletonContainer {
.and(singletonFields(instance))
.apply(instance, NestedLootTable::new)
);
- private final Either<ResourceKey<LootTable>, LootTable> contents;
+ public final Either<ResourceKey<LootTable>, LootTable> contents; // Leaves - private -> public
private NestedLootTable(
Either<ResourceKey<LootTable>, LootTable> value, int weight, int quality, List<LootItemCondition> conditions, List<LootItemFunction> functions
diff --git a/src/main/java/net/minecraft/world/level/storage/loot/predicates/CompositeLootItemCondition.java b/src/main/java/net/minecraft/world/level/storage/loot/predicates/CompositeLootItemCondition.java
index 30d0133a42ce990352f5c492fcf9beb105364848..1ab2eab686b3a89d406f127a6036c0e2932db4a6 100644
--- a/src/main/java/net/minecraft/world/level/storage/loot/predicates/CompositeLootItemCondition.java
+++ b/src/main/java/net/minecraft/world/level/storage/loot/predicates/CompositeLootItemCondition.java
@@ -11,7 +11,7 @@ import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.ValidationContext;
public abstract class CompositeLootItemCondition implements LootItemCondition {
- protected final List<LootItemCondition> terms;
+ public final List<LootItemCondition> terms; // Leaves - private -> public
private final Predicate<LootContext> composedPredicate;
protected CompositeLootItemCondition(List<LootItemCondition> terms, Predicate<LootContext> predicate) {
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/JadeProtocol.java b/src/main/java/org/leavesmc/leaves/protocol/jade/JadeProtocol.java
new file mode 100644
index 0000000000000000000000000000000000000000..33741d707715619929e5412a786470c5372f5978
index 0000000000000000000000000000000000000000..0f40d3b95de7cefbf1318109cb45d13732f25534
--- /dev/null
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/JadeProtocol.java
@@ -0,0 +1,343 @@
@@ -0,0 +1,397 @@
+package org.leavesmc.leaves.protocol.jade;
+
+import io.netty.buffer.ByteBuf;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.RegistryFriendlyByteBuf;
+import net.minecraft.network.codec.ByteBufCodecs;
@@ -75,6 +155,7 @@ index 0000000000000000000000000000000000000000..33741d707715619929e5412a786470c5
+import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
+import net.minecraft.world.entity.monster.ZombieVillager;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.Items;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.CampfireBlock;
@@ -128,11 +209,13 @@ index 0000000000000000000000000000000000000000..33741d707715619929e5412a786470c5
+import org.leavesmc.leaves.protocol.jade.provider.entity.StatusEffectsProvider;
+import org.leavesmc.leaves.protocol.jade.provider.entity.ZombieVillagerProvider;
+import org.leavesmc.leaves.protocol.jade.util.HierarchyLookup;
+import org.leavesmc.leaves.protocol.jade.util.LootTableMineableCollector;
+import org.leavesmc.leaves.protocol.jade.util.PairHierarchyLookup;
+import org.leavesmc.leaves.protocol.jade.util.PriorityStore;
+import org.leavesmc.leaves.protocol.jade.util.WrappedHierarchyLookup;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.function.Predicate;
@@ -140,14 +223,12 @@ index 0000000000000000000000000000000000000000..33741d707715619929e5412a786470c5
+
+@LeavesProtocol(namespace = "jade")
+public class JadeProtocol {
+
+ public static PriorityStore<ResourceLocation, IJadeProvider> priorities;
+ private static List<Block> shearableBlocks = List.of();
+
+ public static final String PROTOCOL_ID = "jade";
+
+ // send
+ public static final ResourceLocation PACKET_SERVER_PING = id("server_ping");
+ public static final ResourceLocation PACKET_RECEIVE_DATA = id("receive_data");
+
+ private static final HierarchyLookup<IJadeDataProvider<EntityAccessor>> entityDataProviders = new HierarchyLookup<>(Entity.class);
+ private static final PairHierarchyLookup<IJadeDataProvider<BlockAccessor>> blockDataProviders = new PairHierarchyLookup<>(new HierarchyLookup<>(Block.class), new HierarchyLookup<>(BlockEntity.class));
+
@@ -224,12 +305,20 @@ index 0000000000000000000000000000000000000000..33741d707715619929e5412a786470c5
+ blockDataProviders.register(TrialSpawnerBlockEntity.class, MobSpawnerCooldownProvider.INSTANCE);
+
+ itemStorageProviders.register(CampfireBlock.class, CampfireProvider.INSTANCE);
+
+ try {
+ shearableBlocks = Collections.unmodifiableList(LootTableMineableCollector.execute(
+ MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.LOOT_TABLE),
+ Items.SHEARS.getDefaultInstance()));
+ } catch (Throwable ignore) {
+ LeavesLogger.LOGGER.severe("Failed to collect shearable blocks");
+ }
+ }
+
+ @ProtocolHandler.PlayerJoin
+ public static void onPlayerJoin(ServerPlayer player) {
+ if (LeavesConfig.jadeProtocol) {
+ ProtocolUtils.sendPayloadPacket(player, PACKET_SERVER_PING, buf -> buf.writeUtf(""));
+ ProtocolUtils.sendPayloadPacket(player, new ServerPingPayload("", shearableBlocks));
+ }
+ }
+
@@ -273,7 +362,7 @@ index 0000000000000000000000000000000000000000..33741d707715619929e5412a786470c5
+ }
+ tag.putInt("EntityId", entity.getId());
+
+ ProtocolUtils.sendPayloadPacket(player, PACKET_RECEIVE_DATA, buf -> buf.writeNbt(tag));
+ ProtocolUtils.sendPayloadPacket(player, new ReceiveDataPayload(tag));
+ });
+ }
+
@@ -327,7 +416,7 @@ index 0000000000000000000000000000000000000000..33741d707715619929e5412a786470c5
+ tag.putInt("z", pos.getZ());
+ tag.putString("BlockId", BuiltInRegistries.BLOCK.getKey(block).toString());
+
+ ProtocolUtils.sendPayloadPacket(player, PACKET_RECEIVE_DATA, buf -> buf.writeNbt(tag));
+ ProtocolUtils.sendPayloadPacket(player, new ReceiveDataPayload(tag));
+ });
+ }
+
@@ -349,12 +438,12 @@ index 0000000000000000000000000000000000000000..33741d707715619929e5412a786470c5
+ private static final ResourceLocation PACKET_REQUEST_ENTITY = JadeProtocol.id("request_entity");
+
+ @New
+ public RequestEntityPayload(ResourceLocation id, FriendlyByteBuf buf) {
+ public RequestEntityPayload(ResourceLocation id, @NotNull FriendlyByteBuf buf) {
+ this(buf.readBoolean(), buf.readVarInt(), buf.readVarInt(), new Vec3(buf.readVector3f()));
+ }
+
+ @Override
+ public void write(FriendlyByteBuf buf) {
+ public void write(@NotNull FriendlyByteBuf buf) {
+ buf.writeBoolean(showDetails);
+ buf.writeVarInt(entityId);
+ buf.writeVarInt(partIndex);
@@ -369,17 +458,18 @@ index 0000000000000000000000000000000000000000..33741d707715619929e5412a786470c5
+ }
+
+ public record RequestBlockPayload(boolean showDetails, BlockHitResult hitResult, BlockState blockState, ItemStack fakeBlock) implements LeavesCustomPayload<RequestBlockPayload> {
+
+ private static final ResourceLocation PACKET_REQUEST_BLOCK = JadeProtocol.id("request_block");
+ private static final StreamCodec<RegistryFriendlyByteBuf, ItemStack> ITEM_STACK_CODEC = ItemStack.OPTIONAL_STREAM_CODEC;
+ private static final StreamCodec<ByteBuf, BlockState> BLOCK_STATE_CODEC = ByteBufCodecs.idMapper(Block.BLOCK_STATE_REGISTRY);
+ private static final ResourceLocation PACKET_REQUEST_BLOCK = JadeProtocol.id("request_block");
+
+ @New
+ public RequestBlockPayload(ResourceLocation id, FriendlyByteBuf buf) {
+ public RequestBlockPayload(ResourceLocation id, @NotNull FriendlyByteBuf buf) {
+ this(buf.readBoolean(), buf.readBlockHitResult(), BLOCK_STATE_CODEC.decode(buf), ITEM_STACK_CODEC.decode(ProtocolUtils.decorate(buf)));
+ }
+
+ @Override
+ public void write(FriendlyByteBuf buf) {
+ public void write(@NotNull FriendlyByteBuf buf) {
+ buf.writeBoolean(showDetails);
+ buf.writeBlockHitResult(hitResult);
+ BLOCK_STATE_CODEC.encode(buf, blockState);
@@ -392,6 +482,48 @@ index 0000000000000000000000000000000000000000..33741d707715619929e5412a786470c5
+ return PACKET_REQUEST_BLOCK;
+ }
+ }
+
+ public record ServerPingPayload(String serverConfig, List<Block> shearableBlocks) implements LeavesCustomPayload<ServerPingPayload> {
+
+ private static final ResourceLocation PACKET_SERVER_PING = JadeProtocol.id("server_ping_v1");
+ private static final StreamCodec<RegistryFriendlyByteBuf, List<Block>> SHEARABLE_BLOCKS_CODEC = ByteBufCodecs.registry(Registries.BLOCK).apply(ByteBufCodecs.list());
+
+ @New
+ public ServerPingPayload(ResourceLocation id, @NotNull FriendlyByteBuf buf) {
+ this(buf.readUtf(), SHEARABLE_BLOCKS_CODEC.decode(ProtocolUtils.decorate(buf)));
+ }
+
+ @Override
+ public void write(FriendlyByteBuf buf) {
+ buf.writeUtf(serverConfig);
+ SHEARABLE_BLOCKS_CODEC.encode(ProtocolUtils.decorate(buf), shearableBlocks);
+ }
+
+ @Override
+ public ResourceLocation id() {
+ return PACKET_SERVER_PING;
+ }
+ }
+
+ public record ReceiveDataPayload(CompoundTag tag) implements LeavesCustomPayload<ReceiveDataPayload> {
+
+ private static final ResourceLocation PACKET_RECEIVE_DATA = JadeProtocol.id("receive_data");
+
+ @New
+ public ReceiveDataPayload(ResourceLocation id, FriendlyByteBuf buf) {
+ this(buf.readNbt());
+ }
+
+ @Override
+ public void write(@NotNull FriendlyByteBuf buf) {
+ buf.writeNbt(tag);
+ }
+
+ @Override
+ public ResourceLocation id() {
+ return PACKET_RECEIVE_DATA;
+ }
+ }
+}
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessor.java b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessor.java
new file mode 100644
@@ -1565,6 +1697,151 @@ index 0000000000000000000000000000000000000000..d48ef5d8c72b57ff5525ab06b59724d0
+ return MC_ZOMBIE_VILLAGER;
+ }
+}
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/tool/ShearsToolHandler.java b/src/main/java/org/leavesmc/leaves/protocol/jade/tool/ShearsToolHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..0e6f19a4cf55d952d8f20bf703635c8584a5f0bd
--- /dev/null
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/tool/ShearsToolHandler.java
@@ -0,0 +1,43 @@
+package org.leavesmc.leaves.protocol.jade.tool;
+
+import com.google.common.collect.Sets;
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.Items;
+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 org.leavesmc.leaves.protocol.jade.JadeProtocol;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+public class ShearsToolHandler extends SimpleToolHandler {
+
+ private static final ShearsToolHandler INSTANCE = new ShearsToolHandler();
+
+ public static ShearsToolHandler getInstance() {
+ return INSTANCE;
+ }
+
+ private final Set<Block> shearableBlocks = Sets.newIdentityHashSet();
+
+ public ShearsToolHandler() {
+ super(JadeProtocol.id("shears"), List.of(Items.SHEARS.getDefaultInstance()), true);
+ }
+
+ @Override
+ public ItemStack test(BlockState state, Level world, BlockPos pos) {
+ if (state.is(Blocks.TRIPWIRE) || shearableBlocks.contains(state.getBlock())) {
+ return tools.getFirst();
+ }
+ return super.test(state, world, pos);
+ }
+
+ public void setShearableBlocks(Collection<Block> blocks) {
+ shearableBlocks.clear();
+ shearableBlocks.addAll(blocks);
+ }
+}
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/tool/SimpleToolHandler.java b/src/main/java/org/leavesmc/leaves/protocol/jade/tool/SimpleToolHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..22fee6ecc49bbda94a7d32ee9dcf2a9ee661904b
--- /dev/null
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/tool/SimpleToolHandler.java
@@ -0,0 +1,67 @@
+package org.leavesmc.leaves.protocol.jade.tool;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.component.DataComponents;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.item.Item;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.component.Tool;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.state.BlockState;
+
+import java.util.List;
+
+public class SimpleToolHandler implements ToolHandler {
+
+ protected final List<ItemStack> tools = Lists.newArrayList();
+ private final ResourceLocation uid;
+ private final boolean skipInstaBreakingBlock;
+
+ protected SimpleToolHandler(ResourceLocation uid, List<ItemStack> tools, boolean skipInstaBreakingBlock) {
+ this.uid = uid;
+ Preconditions.checkArgument(!tools.isEmpty(), "tools cannot be empty");
+ this.tools.addAll(tools);
+ this.skipInstaBreakingBlock = skipInstaBreakingBlock;
+ }
+
+ public static SimpleToolHandler create(ResourceLocation uid, List<Item> tools) {
+ return create(uid, tools, true);
+ }
+
+ public static SimpleToolHandler create(ResourceLocation uid, List<Item> tools, boolean skipInstaBreakingBlock) {
+ return new SimpleToolHandler(uid, Lists.transform(tools, Item::getDefaultInstance), skipInstaBreakingBlock);
+ }
+
+ @Override
+ public ItemStack test(BlockState state, Level world, BlockPos pos) {
+ if (skipInstaBreakingBlock && !state.requiresCorrectToolForDrops() && state.getDestroySpeed(world, pos) == 0) {
+ return ItemStack.EMPTY;
+ }
+ return test(state);
+ }
+
+ public ItemStack test(BlockState state) {
+ for (ItemStack toolItem : tools) {
+ if (toolItem.isCorrectToolForDrops(state)) {
+ return toolItem;
+ }
+ Tool tool = toolItem.get(DataComponents.TOOL);
+ if (tool != null && tool.getMiningSpeed(state) > tool.defaultMiningSpeed()) {
+ return toolItem;
+ }
+ }
+ return ItemStack.EMPTY;
+ }
+
+ @Override
+ public List<ItemStack> getTools() {
+ return tools;
+ }
+
+ @Override
+ public ResourceLocation getUid() {
+ return uid;
+ }
+}
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/tool/ToolHandler.java b/src/main/java/org/leavesmc/leaves/protocol/jade/tool/ToolHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..18f11e701189ce3615e08c631e31112d53ea5686
--- /dev/null
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/tool/ToolHandler.java
@@ -0,0 +1,17 @@
+package org.leavesmc.leaves.protocol.jade.tool;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.state.BlockState;
+import org.leavesmc.leaves.protocol.jade.provider.IJadeProvider;
+
+import java.util.List;
+
+public interface ToolHandler extends IJadeProvider {
+
+ ItemStack test(BlockState state, Level world, BlockPos pos);
+
+ List<ItemStack> getTools();
+
+}
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/util/HierarchyLookup.java b/src/main/java/org/leavesmc/leaves/protocol/jade/util/HierarchyLookup.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e88dc87bd4a86c15b2b0d11ac4b095174b1c3d3
@@ -1962,6 +2239,116 @@ index 0000000000000000000000000000000000000000..4d65e9a8b5224bd268b1bf18bc39a58d
+ }
+ }
+}
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/util/LootTableMineableCollector.java b/src/main/java/org/leavesmc/leaves/protocol/jade/util/LootTableMineableCollector.java
new file mode 100644
index 0000000000000000000000000000000000000000..c811f89295964b1cb86c3eea39cd20f979ebceb9
--- /dev/null
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/util/LootTableMineableCollector.java
@@ -0,0 +1,104 @@
+package org.leavesmc.leaves.protocol.jade.util;
+
+import com.google.common.collect.Lists;
+import net.minecraft.advancements.critereon.ItemPredicate;
+import net.minecraft.core.Registry;
+import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.storage.loot.LootPool;
+import net.minecraft.world.level.storage.loot.LootTable;
+import net.minecraft.world.level.storage.loot.entries.AlternativesEntry;
+import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer;
+import net.minecraft.world.level.storage.loot.entries.NestedLootTable;
+import net.minecraft.world.level.storage.loot.predicates.AnyOfCondition;
+import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
+import net.minecraft.world.level.storage.loot.predicates.MatchTool;
+import org.leavesmc.leaves.protocol.jade.tool.ShearsToolHandler;
+
+import java.util.List;
+import java.util.function.Function;
+
+public class LootTableMineableCollector {
+
+ private final Registry<LootTable> lootRegistry;
+ private final ItemStack toolItem;
+
+ public LootTableMineableCollector(Registry<LootTable> lootRegistry, ItemStack toolItem) {
+ this.lootRegistry = lootRegistry;
+ this.toolItem = toolItem;
+ }
+
+ public static List<Block> execute(Registry<LootTable> lootRegistry, ItemStack toolItem) {
+ LootTableMineableCollector collector = new LootTableMineableCollector(lootRegistry, toolItem);
+ List<Block> list = Lists.newArrayList();
+ for (Block block : BuiltInRegistries.BLOCK) {
+ if (!ShearsToolHandler.getInstance().test(block.defaultBlockState()).isEmpty()) {
+ continue;
+ }
+
+ LootTable lootTable = lootRegistry.get(block.getLootTable());
+ if (collector.doLootTable(lootTable)) {
+ list.add(block);
+ }
+ }
+ return list;
+ }
+
+ private boolean doLootTable(LootTable lootTable) {
+ if (lootTable == null || lootTable == LootTable.EMPTY) {
+ return false;
+ }
+
+ for (LootPool pool : lootTable.pools) {
+ if (doLootPool(pool)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean doLootPool(LootPool lootPool) {
+ for (LootPoolEntryContainer entry : lootPool.entries) {
+ if (doLootPoolEntry(entry)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean doLootPoolEntry(LootPoolEntryContainer entry) {
+ if (entry instanceof AlternativesEntry alternativesEntry) {
+ for (LootPoolEntryContainer child : alternativesEntry.children) {
+ if (doLootPoolEntry(child)) {
+ return true;
+ }
+ }
+ } else if (entry instanceof NestedLootTable nestedLootTable) {
+ LootTable lootTable = nestedLootTable.contents.map(lootRegistry::get, Function.identity());
+ return doLootTable(lootTable);
+ } else {
+ return isCorrectConditions(entry.conditions, toolItem);
+ }
+ return false;
+ }
+
+ public static boolean isCorrectConditions(List<LootItemCondition> conditions, ItemStack toolItem) {
+ if (conditions.size() != 1) {
+ return false;
+ }
+
+ LootItemCondition condition = conditions.getFirst();
+ if (condition instanceof MatchTool matchTool) {
+ ItemPredicate itemPredicate = matchTool.predicate().orElse(null);
+ return itemPredicate != null && itemPredicate.test(toolItem);
+ } else if (condition instanceof AnyOfCondition anyOfCondition) {
+ for (LootItemCondition child : anyOfCondition.terms) {
+ if (isCorrectConditions(List.of(child), toolItem)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/util/PairHierarchyLookup.java b/src/main/java/org/leavesmc/leaves/protocol/jade/util/PairHierarchyLookup.java
new file mode 100644
index 0000000000000000000000000000000000000000..580b299d9dc2514d9758c04caac39a82982c0ca1