mirror of
https://github.com/LeavesMC/Leaves.git
synced 2025-12-19 14:59:32 +00:00
3552 lines
142 KiB
Diff
3552 lines
142 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: violetc <58360096+s-yh-china@users.noreply.github.com>
|
|
Date: Sat, 3 Dec 2022 08:57:15 +0800
|
|
Subject: [PATCH] Jade Protocol
|
|
|
|
This patch is Powered by Jade(https://github.com/Snownee/Jade)
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java b/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java
|
|
index 729fd2d52dd48e25ee7a077a3ffafc80ecef7c9f..28d6b1d49045c125214c40895efd484e4ae20c2b 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java
|
|
@@ -63,7 +63,7 @@ public class Armadillo extends Animal {
|
|
public final AnimationState rollOutAnimationState = new AnimationState();
|
|
public final AnimationState rollUpAnimationState = new AnimationState();
|
|
public final AnimationState peekAnimationState = new AnimationState();
|
|
- private int scuteTime;
|
|
+ public int scuteTime; // Leaves - private -> public
|
|
private boolean peekReceivedClient = false;
|
|
|
|
public Armadillo(EntityType<? extends Animal> type, Level world) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java
|
|
index 43046f4a0cff620834ac4647efdcde227185b2ff..a08cd692e332a6caed33cd3db2373e847621ad6a 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java
|
|
@@ -256,7 +256,7 @@ public class Tadpole extends AbstractFish {
|
|
|
|
}
|
|
|
|
- private int getTicksLeftUntilAdult() {
|
|
+ public int getTicksLeftUntilAdult() { // Leaves - private -> public
|
|
return Math.max(0, Tadpole.ticksToBeFrog - this.age);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerData.java b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerData.java
|
|
index 6684ded7135f943f8cea954b417f596369215357..0621c6c026678cb4ac3626342d73290c0f2803d9 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerData.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawnerData.java
|
|
@@ -72,7 +72,7 @@ public class TrialSpawnerData {
|
|
});
|
|
public final Set<UUID> detectedPlayers;
|
|
public final Set<UUID> currentMobs;
|
|
- protected long cooldownEndsAt;
|
|
+ public long cooldownEndsAt; // Leaves - protected -> public
|
|
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..438dfee78f7114e7c8d3d57c5dcc90e1fcc75a4c
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/JadeProtocol.java
|
|
@@ -0,0 +1,311 @@
|
|
+package org.leavesmc.leaves.protocol.jade;
|
|
+
|
|
+import com.google.common.base.Suppliers;
|
|
+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.resources.ResourceLocation;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import net.minecraft.util.Mth;
|
|
+import net.minecraft.world.entity.AgeableMob;
|
|
+import net.minecraft.world.entity.Entity;
|
|
+import net.minecraft.world.entity.LivingEntity;
|
|
+import net.minecraft.world.entity.animal.Animal;
|
|
+import net.minecraft.world.entity.animal.Chicken;
|
|
+import net.minecraft.world.entity.animal.allay.Allay;
|
|
+import net.minecraft.world.entity.animal.armadillo.Armadillo;
|
|
+import net.minecraft.world.entity.animal.frog.Tadpole;
|
|
+import net.minecraft.world.entity.boss.EnderDragonPart;
|
|
+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;
|
|
+import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.BlockEntity;
|
|
+import net.minecraft.world.level.block.entity.BrewingStandBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.CalibratedSculkSensorBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.ChiseledBookShelfBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.CommandBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.ComparatorBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.HopperBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.JukeboxBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.LecternBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+import net.minecraft.world.phys.BlockHitResult;
|
|
+import net.minecraft.world.phys.EntityHitResult;
|
|
+import org.jetbrains.annotations.Contract;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.leavesmc.leaves.LeavesConfig;
|
|
+import org.leavesmc.leaves.LeavesLogger;
|
|
+import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
|
+import org.leavesmc.leaves.protocol.core.ProtocolHandler;
|
|
+import org.leavesmc.leaves.protocol.core.ProtocolUtils;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessorImpl;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessorImpl;
|
|
+import org.leavesmc.leaves.protocol.jade.payload.ReceiveDataPayload;
|
|
+import org.leavesmc.leaves.protocol.jade.payload.RequestBlockPayload;
|
|
+import org.leavesmc.leaves.protocol.jade.payload.RequestEntityPayload;
|
|
+import org.leavesmc.leaves.protocol.jade.payload.ServerPingPayload;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.IJadeProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.IServerDataProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.IServerExtensionProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.ItemStorageExtensionProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.block.BeehiveProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.block.BrewingStandProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.block.CampfireProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.block.ChiseledBookshelfProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.block.CommandBlockProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.block.FurnaceProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.block.HopperLockProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.ItemStorageProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.block.JukeboxProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.block.LecternProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.block.MobSpawnerCooldownProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.block.ObjectNameProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.block.RedstoneProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.entity.AnimalOwnerProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.entity.MobBreedingProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.entity.MobGrowthProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.entity.NextEntityDropProvider;
|
|
+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.Collections;
|
|
+import java.util.List;
|
|
+
|
|
+@LeavesProtocol(namespace = "jade")
|
|
+public class JadeProtocol {
|
|
+
|
|
+ public static PriorityStore<ResourceLocation, IJadeProvider> priorities;
|
|
+ private static List<Block> shearableBlocks = null;
|
|
+
|
|
+ public static final String PROTOCOL_ID = "jade";
|
|
+
|
|
+ public static final HierarchyLookup<IServerDataProvider<EntityAccessor>> entityDataProviders = new HierarchyLookup<>(Entity.class);
|
|
+ public static final PairHierarchyLookup<IServerDataProvider<BlockAccessor>> blockDataProviders = new PairHierarchyLookup<>(new HierarchyLookup<>(Block.class), new HierarchyLookup<>(BlockEntity.class));
|
|
+ public static final WrappedHierarchyLookup<IServerExtensionProvider<ItemStack>> itemStorageProviders = new WrappedHierarchyLookup<>();
|
|
+
|
|
+ @Contract("_ -> new")
|
|
+ public static @NotNull ResourceLocation id(String path) {
|
|
+ return new ResourceLocation(PROTOCOL_ID, path);
|
|
+ }
|
|
+
|
|
+ @Contract("_ -> new")
|
|
+ public static @NotNull ResourceLocation mc_id(String path) {
|
|
+ return ResourceLocation.withDefaultNamespace(path);
|
|
+ }
|
|
+
|
|
+ @ProtocolHandler.Init
|
|
+ public static void init() {
|
|
+ priorities = new PriorityStore<>(IJadeProvider::getDefaultPriority, IJadeProvider::getUid);
|
|
+
|
|
+ // core plugin
|
|
+ blockDataProviders.register(BlockEntity.class, ObjectNameProvider.ForBlock.INSTANCE);
|
|
+
|
|
+ // universal plugin
|
|
+ entityDataProviders.register(Entity.class, ItemStorageProvider.getEntity());
|
|
+ blockDataProviders.register(Block.class, ItemStorageProvider.getBlock());
|
|
+
|
|
+ itemStorageProviders.register(Object.class, ItemStorageExtensionProvider.INSTANCE);
|
|
+ itemStorageProviders.register(Block.class, ItemStorageExtensionProvider.INSTANCE);
|
|
+
|
|
+ // vanilla plugin
|
|
+ entityDataProviders.register(Entity.class, AnimalOwnerProvider.INSTANCE);
|
|
+ entityDataProviders.register(LivingEntity.class, StatusEffectsProvider.INSTANCE);
|
|
+ entityDataProviders.register(AgeableMob.class, MobGrowthProvider.INSTANCE);
|
|
+ entityDataProviders.register(Tadpole.class, MobGrowthProvider.INSTANCE);
|
|
+ entityDataProviders.register(Animal.class, MobBreedingProvider.INSTANCE);
|
|
+ entityDataProviders.register(Allay.class, MobBreedingProvider.INSTANCE);
|
|
+
|
|
+ entityDataProviders.register(Chicken.class, NextEntityDropProvider.INSTANCE);
|
|
+ entityDataProviders.register(Armadillo.class, NextEntityDropProvider.INSTANCE);
|
|
+
|
|
+ entityDataProviders.register(ZombieVillager.class, ZombieVillagerProvider.INSTANCE);
|
|
+
|
|
+ blockDataProviders.register(BrewingStandBlockEntity.class, BrewingStandProvider.INSTANCE);
|
|
+ blockDataProviders.register(BeehiveBlockEntity.class, BeehiveProvider.INSTANCE);
|
|
+ blockDataProviders.register(CommandBlockEntity.class, CommandBlockProvider.INSTANCE);
|
|
+ blockDataProviders.register(JukeboxBlockEntity.class, JukeboxProvider.INSTANCE);
|
|
+ blockDataProviders.register(LecternBlockEntity.class, LecternProvider.INSTANCE);
|
|
+
|
|
+ blockDataProviders.register(ComparatorBlockEntity.class, RedstoneProvider.INSTANCE);
|
|
+ blockDataProviders.register(HopperBlockEntity.class, HopperLockProvider.INSTANCE);
|
|
+ blockDataProviders.register(CalibratedSculkSensorBlockEntity.class, RedstoneProvider.INSTANCE);
|
|
+
|
|
+ blockDataProviders.register(AbstractFurnaceBlockEntity.class, FurnaceProvider.INSTANCE);
|
|
+ blockDataProviders.register(ChiseledBookShelfBlockEntity.class, ChiseledBookshelfProvider.INSTANCE);
|
|
+ blockDataProviders.register(TrialSpawnerBlockEntity.class, MobSpawnerCooldownProvider.INSTANCE);
|
|
+
|
|
+ blockDataProviders.idMapped();
|
|
+ entityDataProviders.idMapped();
|
|
+ itemStorageProviders.register(CampfireBlock.class, CampfireProvider.INSTANCE);
|
|
+
|
|
+ blockDataProviders.loadComplete(priorities);
|
|
+ entityDataProviders.loadComplete(priorities);
|
|
+ itemStorageProviders.loadComplete(priorities);
|
|
+
|
|
+ try {
|
|
+ shearableBlocks = Collections.unmodifiableList(LootTableMineableCollector.execute(
|
|
+ MinecraftServer.getServer().reloadableRegistries().get().registryOrThrow(Registries.LOOT_TABLE),
|
|
+ Items.SHEARS.getDefaultInstance()));
|
|
+ } catch (Throwable ignore) {
|
|
+ shearableBlocks = List.of();
|
|
+ LeavesLogger.LOGGER.severe("Failed to collect shearable blocks");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @ProtocolHandler.PlayerJoin
|
|
+ public static void onPlayerJoin(ServerPlayer player) {
|
|
+ if (!LeavesConfig.jadeProtocol) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ sendPingPacket(player);
|
|
+ }
|
|
+
|
|
+ @ProtocolHandler.PayloadReceiver(payload = RequestEntityPayload.class, payloadId = "request_entity")
|
|
+ public static void requestEntityData(ServerPlayer player, RequestEntityPayload payload) {
|
|
+ if (!LeavesConfig.jadeProtocol) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ MinecraftServer server = MinecraftServer.getServer();
|
|
+ server.execute(() -> {
|
|
+ Level world = player.level();
|
|
+ boolean showDetails = payload.data().showDetails();
|
|
+ Entity entity = world.getEntity(payload.data().id());
|
|
+ double maxDistance = Mth.square(player.entityInteractionRange() + 21);
|
|
+
|
|
+ if (entity == null || player.distanceToSqr(entity) > maxDistance) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (payload.data().partIndex() >= 0 && entity instanceof EnderDragon dragon) {
|
|
+ EnderDragonPart[] parts = dragon.getSubEntities();
|
|
+ if (payload.data().partIndex() < parts.length) {
|
|
+ entity = parts[payload.data().partIndex()];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ var providers = entityDataProviders.get(entity);
|
|
+ if (providers.isEmpty()) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ final Entity finalEntity = entity;
|
|
+ CompoundTag tag = new CompoundTag();
|
|
+ EntityAccessor accessor = new EntityAccessorImpl.Builder()
|
|
+ .level(world)
|
|
+ .player(player)
|
|
+ .showDetails(showDetails)
|
|
+ .entity(entity)
|
|
+ .hit(Suppliers.memoize(() -> new EntityHitResult(finalEntity, payload.data().hitVec())))
|
|
+ .build();
|
|
+
|
|
+ for (IServerDataProvider<EntityAccessor> provider : providers) {
|
|
+ try {
|
|
+ provider.appendServerData(tag, accessor);
|
|
+ } catch (Exception e) {
|
|
+ LeavesLogger.LOGGER.warning("Error while saving data for entity " + entity);
|
|
+ }
|
|
+ }
|
|
+ tag.putInt("EntityId", entity.getId());
|
|
+
|
|
+ ProtocolUtils.sendPayloadPacket(player, new ReceiveDataPayload(tag));
|
|
+ });
|
|
+ }
|
|
+
|
|
+ @ProtocolHandler.PayloadReceiver(payload = RequestBlockPayload.class, payloadId = "request_block")
|
|
+ public static void requestBlockData(ServerPlayer player, RequestBlockPayload payload) {
|
|
+ if (!LeavesConfig.jadeProtocol) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ MinecraftServer server = MinecraftServer.getServer();
|
|
+ server.execute(() -> {
|
|
+ Level world = player.level();
|
|
+ BlockState blockState = payload.data().blockState();
|
|
+ Block block = blockState.getBlock();
|
|
+ BlockHitResult result = payload.data().hit();
|
|
+ BlockPos pos = result.getBlockPos();
|
|
+ boolean showDetails = payload.data().showDetails();
|
|
+
|
|
+ double maxDistance = Mth.square(player.blockInteractionRange() + 21);
|
|
+ if (pos.distSqr(player.blockPosition()) > maxDistance || !world.isLoaded(pos)) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ BlockEntity blockEntity = null;
|
|
+ if (blockState.hasBlockEntity()) {
|
|
+ blockEntity = world.getBlockEntity(pos);
|
|
+ }
|
|
+
|
|
+ List<IServerDataProvider<BlockAccessor>> providers;
|
|
+ if (blockEntity != null) {
|
|
+ providers = blockDataProviders.getMerged(block, blockEntity);
|
|
+ } else {
|
|
+ providers = blockDataProviders.first.get(block);
|
|
+ }
|
|
+
|
|
+ if (providers.isEmpty()) {
|
|
+ player.getBukkitEntity().sendMessage("Provider is empty!");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ CompoundTag tag = new CompoundTag();
|
|
+ BlockAccessor accessor = new BlockAccessorImpl.Builder()
|
|
+ .level(world)
|
|
+ .player(player)
|
|
+ .showDetails(showDetails)
|
|
+ .hit(result)
|
|
+ .blockState(blockState)
|
|
+ .blockEntity(blockEntity)
|
|
+ .build();
|
|
+
|
|
+ for (IServerDataProvider<BlockAccessor> provider : providers) {
|
|
+ try {
|
|
+ provider.appendServerData(tag, accessor);
|
|
+ } catch (Exception e) {
|
|
+ LeavesLogger.LOGGER.warning("Error while saving data for block " + blockState);
|
|
+ }
|
|
+ }
|
|
+ tag.putInt("x", pos.getX());
|
|
+ tag.putInt("y", pos.getY());
|
|
+ tag.putInt("z", pos.getZ());
|
|
+ tag.putString("BlockId", BuiltInRegistries.BLOCK.getKey(block).toString());
|
|
+
|
|
+ ProtocolUtils.sendPayloadPacket(player, new ReceiveDataPayload(tag));
|
|
+ });
|
|
+ }
|
|
+
|
|
+ @ProtocolHandler.ReloadServer
|
|
+ public static void onServerReload() {
|
|
+ if (LeavesConfig.jadeProtocol) {
|
|
+ enableAllPlayer();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static void enableAllPlayer() {
|
|
+ for (ServerPlayer player : MinecraftServer.getServer().getPlayerList().players) {
|
|
+ sendPingPacket(player);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static void sendPingPacket(ServerPlayer player) {
|
|
+ ProtocolUtils.sendPayloadPacket(player, new ServerPingPayload(Collections.emptyMap(), shearableBlocks, blockDataProviders.mappedIds(), entityDataProviders.mappedIds()));
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/Accessor.java b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/Accessor.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..1a637045d9375ae357ca1e592ec0dc7b45fa47fa
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/Accessor.java
|
|
@@ -0,0 +1,32 @@
|
|
+package org.leavesmc.leaves.protocol.jade.accessor;
|
|
+
|
|
+import net.minecraft.nbt.Tag;
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.StreamEncoder;
|
|
+import net.minecraft.world.entity.player.Player;
|
|
+import net.minecraft.world.level.Level;
|
|
+import net.minecraft.world.phys.HitResult;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+
|
|
+public interface Accessor<T extends HitResult> {
|
|
+
|
|
+ Level getLevel();
|
|
+
|
|
+ Player getPlayer();
|
|
+
|
|
+ <D> Tag encodeAsNbt(StreamEncoder<RegistryFriendlyByteBuf, D> codec, D value);
|
|
+
|
|
+ T getHitResult();
|
|
+
|
|
+ /**
|
|
+ * @return {@code true} if the dedicated server has Jade installed.
|
|
+ */
|
|
+ boolean isServerConnected();
|
|
+
|
|
+ boolean showDetails();
|
|
+
|
|
+ @Nullable
|
|
+ Object getTarget();
|
|
+
|
|
+ float tickRate();
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/AccessorImpl.java b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/AccessorImpl.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..a04fbb45b466d8999b40717d8d48f650b81fe82a
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/AccessorImpl.java
|
|
@@ -0,0 +1,83 @@
|
|
+package org.leavesmc.leaves.protocol.jade.accessor;
|
|
+
|
|
+import java.util.function.Supplier;
|
|
+
|
|
+import org.apache.commons.lang3.ArrayUtils;
|
|
+
|
|
+import io.netty.buffer.Unpooled;
|
|
+import net.minecraft.nbt.ByteArrayTag;
|
|
+import net.minecraft.nbt.Tag;
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.StreamEncoder;
|
|
+import net.minecraft.world.entity.player.Player;
|
|
+import net.minecraft.world.level.Level;
|
|
+import net.minecraft.world.phys.HitResult;
|
|
+
|
|
+public abstract class AccessorImpl<T extends HitResult> implements Accessor<T> {
|
|
+
|
|
+ private final Level level;
|
|
+ private final Player player;
|
|
+ private final Supplier<T> hit;
|
|
+ private final boolean serverConnected;
|
|
+ private final boolean showDetails;
|
|
+ protected boolean verify;
|
|
+ private RegistryFriendlyByteBuf buffer;
|
|
+
|
|
+ public AccessorImpl(Level level, Player player, Supplier<T> hit, boolean serverConnected, boolean showDetails) {
|
|
+ this.level = level;
|
|
+ this.player = player;
|
|
+ this.hit = hit;
|
|
+ this.serverConnected = serverConnected;
|
|
+ this.showDetails = showDetails;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Level getLevel() {
|
|
+ return level;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Player getPlayer() {
|
|
+ return player;
|
|
+ }
|
|
+
|
|
+ private RegistryFriendlyByteBuf buffer() {
|
|
+ if (buffer == null) {
|
|
+ buffer = new RegistryFriendlyByteBuf(Unpooled.buffer(), level.registryAccess());
|
|
+ }
|
|
+ buffer.clear();
|
|
+ return buffer;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public <D> Tag encodeAsNbt(StreamEncoder<RegistryFriendlyByteBuf, D> streamCodec, D value) {
|
|
+ RegistryFriendlyByteBuf buffer = buffer();
|
|
+ streamCodec.encode(buffer, value);
|
|
+ ByteArrayTag tag = new ByteArrayTag(ArrayUtils.subarray(buffer.array(), 0, buffer.readableBytes()));
|
|
+ buffer.clear();
|
|
+ return tag;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public T getHitResult() {
|
|
+ return hit.get();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns true if dedicated server has Jade installed.
|
|
+ */
|
|
+ @Override
|
|
+ public boolean isServerConnected() {
|
|
+ return serverConnected;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean showDetails() {
|
|
+ return showDetails;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public float tickRate() {
|
|
+ return getLevel().tickRateManager().tickrate();
|
|
+ }
|
|
+}
|
|
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
|
|
index 0000000000000000000000000000000000000000..12d689ca80887dcd5dbf68ea2c38a8adcc5ddee4
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessor.java
|
|
@@ -0,0 +1,50 @@
|
|
+package org.leavesmc.leaves.protocol.jade.accessor;
|
|
+
|
|
+import net.minecraft.core.BlockPos;
|
|
+import net.minecraft.core.Direction;
|
|
+import net.minecraft.world.entity.player.Player;
|
|
+import net.minecraft.world.level.Level;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+import net.minecraft.world.level.block.entity.BlockEntity;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+import net.minecraft.world.phys.BlockHitResult;
|
|
+import org.jetbrains.annotations.ApiStatus;
|
|
+
|
|
+import java.util.function.Supplier;
|
|
+
|
|
+public interface BlockAccessor extends Accessor<BlockHitResult> {
|
|
+
|
|
+ Block getBlock();
|
|
+
|
|
+ BlockState getBlockState();
|
|
+
|
|
+ BlockEntity getBlockEntity();
|
|
+
|
|
+ BlockPos getPosition();
|
|
+
|
|
+ Direction getSide();
|
|
+
|
|
+ @ApiStatus.NonExtendable
|
|
+ interface Builder {
|
|
+ Builder level(Level level);
|
|
+
|
|
+ Builder player(Player player);
|
|
+
|
|
+ Builder showDetails(boolean showDetails);
|
|
+
|
|
+ Builder hit(BlockHitResult hit);
|
|
+
|
|
+ Builder blockState(BlockState state);
|
|
+
|
|
+ default Builder blockEntity(BlockEntity blockEntity) {
|
|
+ return blockEntity(() -> blockEntity);
|
|
+ }
|
|
+
|
|
+ Builder blockEntity(Supplier<BlockEntity> blockEntity);
|
|
+
|
|
+ Builder from(BlockAccessor accessor);
|
|
+
|
|
+ BlockAccessor build();
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessorImpl.java b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessorImpl.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..9e4a321b91a8afc480ef506487608255db2b9c89
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessorImpl.java
|
|
@@ -0,0 +1,163 @@
|
|
+package org.leavesmc.leaves.protocol.jade.accessor;
|
|
+
|
|
+import java.util.function.Supplier;
|
|
+
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+
|
|
+import com.google.common.base.Suppliers;
|
|
+
|
|
+import net.minecraft.core.BlockPos;
|
|
+import net.minecraft.core.Direction;
|
|
+import net.minecraft.network.FriendlyByteBuf;
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import net.minecraft.world.entity.player.Player;
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+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.entity.BlockEntity;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+import net.minecraft.world.phys.BlockHitResult;
|
|
+
|
|
+/**
|
|
+ * Class to get information of block target and context.
|
|
+ */
|
|
+public class BlockAccessorImpl extends AccessorImpl<BlockHitResult> implements BlockAccessor {
|
|
+
|
|
+ private final BlockState blockState;
|
|
+ @Nullable
|
|
+ private final Supplier<BlockEntity> blockEntity;
|
|
+
|
|
+ private BlockAccessorImpl(Builder builder) {
|
|
+ super(builder.level, builder.player, Suppliers.ofInstance(builder.hit), builder.connected, builder.showDetails);
|
|
+ blockState = builder.blockState;
|
|
+ blockEntity = builder.blockEntity;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Block getBlock() {
|
|
+ return getBlockState().getBlock();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public BlockState getBlockState() {
|
|
+ return blockState;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public BlockEntity getBlockEntity() {
|
|
+ return blockEntity == null ? null : blockEntity.get();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public BlockPos getPosition() {
|
|
+ return getHitResult().getBlockPos();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Direction getSide() {
|
|
+ return getHitResult().getDirection();
|
|
+ }
|
|
+
|
|
+ @Nullable
|
|
+ @Override
|
|
+ public Object getTarget() {
|
|
+ return getBlockEntity();
|
|
+ }
|
|
+
|
|
+ public static class Builder implements BlockAccessor.Builder {
|
|
+
|
|
+ private Level level;
|
|
+ private Player player;
|
|
+ private boolean connected;
|
|
+ private boolean showDetails;
|
|
+ private BlockHitResult hit;
|
|
+ private BlockState blockState = Blocks.AIR.defaultBlockState();
|
|
+ private Supplier<BlockEntity> blockEntity;
|
|
+
|
|
+ @Override
|
|
+ public Builder level(Level level) {
|
|
+ this.level = level;
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Builder player(Player player) {
|
|
+ this.player = player;
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Builder showDetails(boolean showDetails) {
|
|
+ this.showDetails = showDetails;
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Builder hit(BlockHitResult hit) {
|
|
+ this.hit = hit;
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Builder blockState(BlockState blockState) {
|
|
+ this.blockState = blockState;
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Builder blockEntity(Supplier<BlockEntity> blockEntity) {
|
|
+ this.blockEntity = blockEntity;
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Builder from(BlockAccessor accessor) {
|
|
+ level = accessor.getLevel();
|
|
+ player = accessor.getPlayer();
|
|
+ connected = accessor.isServerConnected();
|
|
+ showDetails = accessor.showDetails();
|
|
+ hit = accessor.getHitResult();
|
|
+ blockEntity = accessor::getBlockEntity;
|
|
+ blockState = accessor.getBlockState();
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public BlockAccessor build() {
|
|
+ return new BlockAccessorImpl(this);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public record SyncData(boolean showDetails, BlockHitResult hit, BlockState blockState, ItemStack fakeBlock) {
|
|
+ public static final StreamCodec<RegistryFriendlyByteBuf, SyncData> STREAM_CODEC = StreamCodec.composite(
|
|
+ ByteBufCodecs.BOOL,
|
|
+ SyncData::showDetails,
|
|
+ StreamCodec.of(FriendlyByteBuf::writeBlockHitResult, FriendlyByteBuf::readBlockHitResult),
|
|
+ SyncData::hit,
|
|
+ ByteBufCodecs.idMapper(Block.BLOCK_STATE_REGISTRY),
|
|
+ SyncData::blockState,
|
|
+ ItemStack.OPTIONAL_STREAM_CODEC,
|
|
+ SyncData::fakeBlock,
|
|
+ SyncData::new
|
|
+ );
|
|
+
|
|
+ public BlockAccessor unpack(ServerPlayer player) {
|
|
+ Supplier<BlockEntity> blockEntity = null;
|
|
+ if (blockState.hasBlockEntity()) {
|
|
+ blockEntity = Suppliers.memoize(() -> player.level().getBlockEntity(hit.getBlockPos()));
|
|
+ }
|
|
+ return new Builder()
|
|
+ .level(player.level())
|
|
+ .player(player)
|
|
+ .showDetails(showDetails)
|
|
+ .hit(hit)
|
|
+ .blockState(blockState)
|
|
+ .blockEntity(blockEntity)
|
|
+ .build();
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessor.java b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessor.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..454360d5e5c01cad3c197b078d536a9f34e2c6a2
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessor.java
|
|
@@ -0,0 +1,44 @@
|
|
+package org.leavesmc.leaves.protocol.jade.accessor;
|
|
+
|
|
+import net.minecraft.world.entity.Entity;
|
|
+import net.minecraft.world.entity.player.Player;
|
|
+import net.minecraft.world.level.Level;
|
|
+import net.minecraft.world.phys.EntityHitResult;
|
|
+import org.jetbrains.annotations.ApiStatus;
|
|
+
|
|
+import java.util.function.Supplier;
|
|
+
|
|
+public interface EntityAccessor extends Accessor<EntityHitResult> {
|
|
+
|
|
+ Entity getEntity();
|
|
+
|
|
+ /**
|
|
+ * For part entity like ender dragon's, getEntity() will return the parent entity.
|
|
+ */
|
|
+ Entity getRawEntity();
|
|
+
|
|
+ @ApiStatus.NonExtendable
|
|
+ interface Builder {
|
|
+ Builder level(Level level);
|
|
+
|
|
+ Builder player(Player player);
|
|
+
|
|
+ Builder showDetails(boolean showDetails);
|
|
+
|
|
+ default Builder hit(EntityHitResult hit) {
|
|
+ return hit(() -> hit);
|
|
+ }
|
|
+
|
|
+ Builder hit(Supplier<EntityHitResult> hit);
|
|
+
|
|
+ default Builder entity(Entity entity) {
|
|
+ return entity(() -> entity);
|
|
+ }
|
|
+
|
|
+ Builder entity(Supplier<Entity> entity);
|
|
+
|
|
+ Builder from(EntityAccessor accessor);
|
|
+
|
|
+ EntityAccessor build();
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessorImpl.java b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessorImpl.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..65d16c0024372ede4cec230b7aad54de28de15f2
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessorImpl.java
|
|
@@ -0,0 +1,123 @@
|
|
+package org.leavesmc.leaves.protocol.jade.accessor;
|
|
+
|
|
+import com.google.common.base.Suppliers;
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import net.minecraft.world.entity.Entity;
|
|
+import net.minecraft.world.entity.player.Player;
|
|
+import net.minecraft.world.level.Level;
|
|
+import net.minecraft.world.phys.EntityHitResult;
|
|
+import net.minecraft.world.phys.Vec3;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.leavesmc.leaves.protocol.jade.util.CommonUtil;
|
|
+
|
|
+import java.util.function.Supplier;
|
|
+
|
|
+public class EntityAccessorImpl extends AccessorImpl<EntityHitResult> implements EntityAccessor {
|
|
+
|
|
+ private final Supplier<Entity> entity;
|
|
+
|
|
+ public EntityAccessorImpl(Builder builder) {
|
|
+ super(builder.level, builder.player, builder.hit, builder.connected, builder.showDetails);
|
|
+ entity = builder.entity;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Entity getEntity() {
|
|
+ return CommonUtil.wrapPartEntityParent(getRawEntity());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Entity getRawEntity() {
|
|
+ return entity.get();
|
|
+ }
|
|
+
|
|
+ @NotNull
|
|
+ @Override
|
|
+ public Object getTarget() {
|
|
+ return getEntity();
|
|
+ }
|
|
+
|
|
+ public static class Builder implements EntityAccessor.Builder {
|
|
+
|
|
+ public boolean showDetails;
|
|
+ private Level level;
|
|
+ private Player player;
|
|
+ private boolean connected;
|
|
+ private Supplier<EntityHitResult> hit;
|
|
+ private Supplier<Entity> entity;
|
|
+
|
|
+ @Override
|
|
+ public Builder level(Level level) {
|
|
+ this.level = level;
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Builder player(Player player) {
|
|
+ this.player = player;
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Builder showDetails(boolean showDetails) {
|
|
+ this.showDetails = showDetails;
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Builder hit(Supplier<EntityHitResult> hit) {
|
|
+ this.hit = hit;
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Builder entity(Supplier<Entity> entity) {
|
|
+ this.entity = entity;
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Builder from(EntityAccessor accessor) {
|
|
+ level = accessor.getLevel();
|
|
+ player = accessor.getPlayer();
|
|
+ connected = accessor.isServerConnected();
|
|
+ showDetails = accessor.showDetails();
|
|
+ hit = accessor::getHitResult;
|
|
+ entity = accessor::getEntity;
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public EntityAccessor build() {
|
|
+ return new EntityAccessorImpl(this);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public record SyncData(boolean showDetails, int id, int partIndex, Vec3 hitVec) {
|
|
+ public static final StreamCodec<RegistryFriendlyByteBuf, SyncData> STREAM_CODEC = StreamCodec.composite(
|
|
+ ByteBufCodecs.BOOL,
|
|
+ SyncData::showDetails,
|
|
+ ByteBufCodecs.VAR_INT,
|
|
+ SyncData::id,
|
|
+ ByteBufCodecs.VAR_INT,
|
|
+ SyncData::partIndex,
|
|
+ ByteBufCodecs.VECTOR3F.map(Vec3::new, Vec3::toVector3f),
|
|
+ SyncData::hitVec,
|
|
+ SyncData::new
|
|
+ );
|
|
+
|
|
+ public EntityAccessor unpack(ServerPlayer player) {
|
|
+ Supplier<Entity> entity = Suppliers.memoize(() -> CommonUtil.getPartEntity(player.level().getEntity(id), partIndex));
|
|
+ return new EntityAccessorImpl.Builder()
|
|
+ .level(player.level())
|
|
+ .player(player)
|
|
+ .showDetails(showDetails)
|
|
+ .entity(entity)
|
|
+ .hit(Suppliers.memoize(() -> new EntityHitResult(entity.get(), hitVec)))
|
|
+ .build();
|
|
+ }
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ReceiveDataPayload.java b/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ReceiveDataPayload.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..1b474ea8c1075b3dbaa7cd27e5bd95aa904fbe97
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ReceiveDataPayload.java
|
|
@@ -0,0 +1,28 @@
|
|
+package org.leavesmc.leaves.protocol.jade.payload;
|
|
+
|
|
+import net.minecraft.nbt.CompoundTag;
|
|
+import net.minecraft.network.FriendlyByteBuf;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+
|
|
+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/payload/RequestBlockPayload.java b/src/main/java/org/leavesmc/leaves/protocol/jade/payload/RequestBlockPayload.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..480ec35f28c850bfbe4f787d080fd7bbd84ca24c
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/payload/RequestBlockPayload.java
|
|
@@ -0,0 +1,51 @@
|
|
+package org.leavesmc.leaves.protocol.jade.payload;
|
|
+
|
|
+import io.netty.buffer.ByteBuf;
|
|
+import net.minecraft.network.FriendlyByteBuf;
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessorImpl;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.IServerDataProvider;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.Objects;
|
|
+
|
|
+import static org.leavesmc.leaves.protocol.jade.JadeProtocol.blockDataProviders;
|
|
+
|
|
+public record RequestBlockPayload(BlockAccessorImpl.SyncData data, List<@Nullable IServerDataProvider<BlockAccessor>> dataProviders) implements LeavesCustomPayload<RequestBlockPayload> {
|
|
+
|
|
+ private static final ResourceLocation PACKET_REQUEST_BLOCK = JadeProtocol.id("request_block");
|
|
+ private static final StreamCodec<RegistryFriendlyByteBuf, RequestBlockPayload> CODEC = StreamCodec.composite(
|
|
+ BlockAccessorImpl.SyncData.STREAM_CODEC,
|
|
+ RequestBlockPayload::data,
|
|
+ ByteBufCodecs.<ByteBuf, IServerDataProvider<BlockAccessor>>list()
|
|
+ .apply(ByteBufCodecs.idMapper(
|
|
+ $ -> Objects.requireNonNull(blockDataProviders.idMapper()).byId($),
|
|
+ $ -> Objects.requireNonNull(blockDataProviders.idMapper()).getIdOrThrow($))),
|
|
+ RequestBlockPayload::dataProviders,
|
|
+ RequestBlockPayload::new);
|
|
+
|
|
+ @Override
|
|
+ public void write(FriendlyByteBuf buf) {
|
|
+ CODEC.encode(new RegistryFriendlyByteBuf(buf, MinecraftServer.getServer().registryAccess()), this);
|
|
+ }
|
|
+
|
|
+ @New
|
|
+ public static RequestBlockPayload create(ResourceLocation location, FriendlyByteBuf buf) {
|
|
+ return CODEC.decode(new RegistryFriendlyByteBuf(buf, MinecraftServer.getServer().registryAccess()));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ @NotNull
|
|
+ public ResourceLocation id() {
|
|
+ return PACKET_REQUEST_BLOCK;
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/payload/RequestEntityPayload.java b/src/main/java/org/leavesmc/leaves/protocol/jade/payload/RequestEntityPayload.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..ef7ee32f0f2fd78b7e7891d622f76cddb8cb0680
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/payload/RequestEntityPayload.java
|
|
@@ -0,0 +1,53 @@
|
|
+package org.leavesmc.leaves.protocol.jade.payload;
|
|
+
|
|
+import io.netty.buffer.ByteBuf;
|
|
+import net.minecraft.network.FriendlyByteBuf;
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessorImpl;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.IServerDataProvider;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.Objects;
|
|
+
|
|
+import static org.leavesmc.leaves.protocol.jade.JadeProtocol.entityDataProviders;
|
|
+
|
|
+public record RequestEntityPayload(EntityAccessorImpl.SyncData data, List<@Nullable IServerDataProvider<EntityAccessor>> dataProviders) implements LeavesCustomPayload<RequestEntityPayload> {
|
|
+
|
|
+ private static final ResourceLocation PACKET_REQUEST_ENTITY = JadeProtocol.id("request_entity");
|
|
+ private static final StreamCodec<RegistryFriendlyByteBuf, RequestEntityPayload> CODEC = StreamCodec.composite(
|
|
+ EntityAccessorImpl.SyncData.STREAM_CODEC,
|
|
+ RequestEntityPayload::data,
|
|
+ ByteBufCodecs.<ByteBuf, IServerDataProvider<EntityAccessor>>list()
|
|
+ .apply(ByteBufCodecs.idMapper(
|
|
+ $ -> Objects.requireNonNull(entityDataProviders.idMapper()).byId($),
|
|
+ $ -> Objects.requireNonNull(entityDataProviders.idMapper())
|
|
+ .getIdOrThrow($))),
|
|
+ RequestEntityPayload::dataProviders,
|
|
+ RequestEntityPayload::new);
|
|
+
|
|
+
|
|
+ @Override
|
|
+ public void write(FriendlyByteBuf buf) {
|
|
+ CODEC.encode(new RegistryFriendlyByteBuf(buf, MinecraftServer.getServer().registryAccess()), this);
|
|
+ }
|
|
+
|
|
+ @New
|
|
+ public static RequestEntityPayload create(ResourceLocation location, FriendlyByteBuf buf) {
|
|
+ return CODEC.decode(new RegistryFriendlyByteBuf(buf, MinecraftServer.getServer().registryAccess()));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ @NotNull
|
|
+ public ResourceLocation id() {
|
|
+ return PACKET_REQUEST_ENTITY;
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ServerPingPayload.java b/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ServerPingPayload.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..f4419962a7fedaea05140bbf6eaa01cc94c05049
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/payload/ServerPingPayload.java
|
|
@@ -0,0 +1,49 @@
|
|
+package org.leavesmc.leaves.protocol.jade.payload;
|
|
+
|
|
+import com.google.common.collect.Maps;
|
|
+import io.netty.buffer.ByteBuf;
|
|
+import net.minecraft.core.registries.Registries;
|
|
+import net.minecraft.network.FriendlyByteBuf;
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+
|
|
+import static org.leavesmc.leaves.protocol.jade.util.JadeCodec.PRIMITIVE_STREAM_CODEC;
|
|
+
|
|
+public record ServerPingPayload(
|
|
+ Map<ResourceLocation, Object> serverConfig,
|
|
+ List<Block> shearableBlocks,
|
|
+ List<ResourceLocation> blockProviderIds,
|
|
+ List<ResourceLocation> entityProviderIds) implements LeavesCustomPayload<ServerPingPayload> {
|
|
+
|
|
+ private static final ResourceLocation PACKET_SERVER_HANDSHAKE = JadeProtocol.id("server_ping_v1");
|
|
+ private static final StreamCodec<RegistryFriendlyByteBuf, ServerPingPayload> CODEC = StreamCodec.composite(
|
|
+ ByteBufCodecs.map(Maps::newHashMapWithExpectedSize, ResourceLocation.STREAM_CODEC, PRIMITIVE_STREAM_CODEC),
|
|
+ ServerPingPayload::serverConfig,
|
|
+ ByteBufCodecs.registry(Registries.BLOCK).apply(ByteBufCodecs.list()),
|
|
+ ServerPingPayload::shearableBlocks,
|
|
+ ByteBufCodecs.<ByteBuf, ResourceLocation>list().apply(ResourceLocation.STREAM_CODEC),
|
|
+ ServerPingPayload::blockProviderIds,
|
|
+ ByteBufCodecs.<ByteBuf, ResourceLocation>list().apply(ResourceLocation.STREAM_CODEC),
|
|
+ ServerPingPayload::entityProviderIds,
|
|
+ ServerPingPayload::new);
|
|
+
|
|
+ @Override
|
|
+ public void write(FriendlyByteBuf buf) {
|
|
+ CODEC.encode(new RegistryFriendlyByteBuf(buf, MinecraftServer.getServer().registryAccess()), this);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation id() {
|
|
+ return PACKET_SERVER_HANDSHAKE;
|
|
+ }
|
|
+}
|
|
+
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IJadeProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IJadeProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..d62fc8f96fcdee7dbb0204d2460ff6fee4074e1a
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IJadeProvider.java
|
|
@@ -0,0 +1,12 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider;
|
|
+
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+
|
|
+public interface IJadeProvider {
|
|
+
|
|
+ ResourceLocation getUid();
|
|
+
|
|
+ default int getDefaultPriority() {
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IServerDataProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IServerDataProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..7d839f17601ca4d2b8717222989cf566a0eb6524
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IServerDataProvider.java
|
|
@@ -0,0 +1,8 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider;
|
|
+
|
|
+import net.minecraft.nbt.CompoundTag;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.Accessor;
|
|
+
|
|
+public interface IServerDataProvider<T extends Accessor<?>> extends IJadeProvider {
|
|
+ void appendServerData(CompoundTag data, T accessor);
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IServerExtensionProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IServerExtensionProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..6e32eed15f028020223e2500849b4db3892f68c3
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/IServerExtensionProvider.java
|
|
@@ -0,0 +1,10 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider;
|
|
+
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.Accessor;
|
|
+import org.leavesmc.leaves.protocol.jade.util.ViewGroup;
|
|
+
|
|
+import java.util.List;
|
|
+
|
|
+public interface IServerExtensionProvider<T> extends IJadeProvider {
|
|
+ List<ViewGroup<T>> getGroups(Accessor<?> request);
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageExtensionProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageExtensionProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..797558f3804a1a8143eafafd5dc46cc72ea19a42
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageExtensionProvider.java
|
|
@@ -0,0 +1,138 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider;
|
|
+
|
|
+import com.google.common.cache.Cache;
|
|
+import com.google.common.cache.CacheBuilder;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.Container;
|
|
+import net.minecraft.world.LockCode;
|
|
+import net.minecraft.world.RandomizableContainer;
|
|
+import net.minecraft.world.WorldlyContainerHolder;
|
|
+import net.minecraft.world.entity.animal.horse.AbstractHorse;
|
|
+import net.minecraft.world.entity.player.Player;
|
|
+import net.minecraft.world.entity.vehicle.ContainerEntity;
|
|
+import net.minecraft.world.inventory.PlayerEnderChestContainer;
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+import net.minecraft.world.level.block.ChestBlock;
|
|
+import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.ChestBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.EnderChestBlockEntity;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.LeavesLogger;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.Accessor;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.util.ItemCollector;
|
|
+import org.leavesmc.leaves.protocol.jade.util.ItemIterator;
|
|
+import org.leavesmc.leaves.protocol.jade.util.ViewGroup;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.concurrent.ExecutionException;
|
|
+import java.util.concurrent.TimeUnit;
|
|
+
|
|
+public enum ItemStorageExtensionProvider implements IServerExtensionProvider<ItemStack> {
|
|
+ INSTANCE;
|
|
+
|
|
+ public static final Cache<Object, ItemCollector<?>> targetCache = CacheBuilder.newBuilder().weakKeys().expireAfterAccess(60, TimeUnit.SECONDS).build();
|
|
+
|
|
+ private static final ResourceLocation UNIVERSAL_ITEM_STORAGE = JadeProtocol.mc_id("item_storage.default");
|
|
+
|
|
+ @Override
|
|
+ public List<ViewGroup<ItemStack>> getGroups(Accessor<?> request) {
|
|
+ Object target = request.getTarget();
|
|
+
|
|
+ switch (target) {
|
|
+ case null -> {
|
|
+ return createItemCollector(request).update(request);
|
|
+ }
|
|
+ case RandomizableContainer te when te.getLootTable() != null -> {
|
|
+ return List.of();
|
|
+ }
|
|
+ case ContainerEntity containerEntity when containerEntity.getLootTable() != null -> {
|
|
+ return List.of();
|
|
+ }
|
|
+ default -> {
|
|
+ }
|
|
+ }
|
|
+
|
|
+ Player player = request.getPlayer();
|
|
+ if (!player.isCreative() && !player.isSpectator() && target instanceof BaseContainerBlockEntity te) {
|
|
+ if (te.lockKey != LockCode.NO_LOCK) {
|
|
+ return List.of();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (target instanceof EnderChestBlockEntity) {
|
|
+ PlayerEnderChestContainer inventory = player.getEnderChestInventory();
|
|
+ return new ItemCollector<>(new ItemIterator.ContainerItemIterator(x -> inventory, 0)).update(request);
|
|
+ }
|
|
+
|
|
+ ItemCollector<?> itemCollector;
|
|
+ try {
|
|
+ itemCollector = targetCache.get(target, () -> createItemCollector(request));
|
|
+ } catch (ExecutionException e) {
|
|
+ LeavesLogger.LOGGER.severe("Failed to get item collector for " + target);
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ return itemCollector.update(request);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return UNIVERSAL_ITEM_STORAGE;
|
|
+ }
|
|
+
|
|
+ public static ItemCollector<?> createItemCollector(Accessor<?> request) {
|
|
+ if (request.getTarget() instanceof AbstractHorse) {
|
|
+ return new ItemCollector<>(new ItemIterator.ContainerItemIterator(o -> {
|
|
+ if (o instanceof AbstractHorse horse) {
|
|
+ return horse.inventory;
|
|
+ }
|
|
+ return null;
|
|
+ }, 2));
|
|
+ }
|
|
+
|
|
+ // TODO BlockEntity like fabric's ItemStorage
|
|
+
|
|
+ final Container container = findContainer(request);
|
|
+ if (container != null) {
|
|
+ if (container instanceof ChestBlockEntity) {
|
|
+ return new ItemCollector<>(new ItemIterator.ContainerItemIterator(o -> {
|
|
+ if (o instanceof ChestBlockEntity blockEntity) {
|
|
+ if (blockEntity.getBlockState().getBlock() instanceof ChestBlock chestBlock) {
|
|
+ Container compound = null;
|
|
+ if (blockEntity.getLevel() != null) {
|
|
+ compound = ChestBlock.getContainer(chestBlock, blockEntity.getBlockState(), blockEntity.getLevel(), blockEntity.getBlockPos(), false);
|
|
+ }
|
|
+ if (compound != null) {
|
|
+ return compound;
|
|
+ }
|
|
+ }
|
|
+ return blockEntity;
|
|
+ }
|
|
+ return null;
|
|
+ }, 0));
|
|
+ }
|
|
+ return new ItemCollector<>(new ItemIterator.ContainerItemIterator(0));
|
|
+ }
|
|
+
|
|
+ return ItemCollector.EMPTY;
|
|
+ }
|
|
+
|
|
+ public static @Nullable Container findContainer(@NotNull Accessor<?> accessor) {
|
|
+ Object target = accessor.getTarget();
|
|
+ if (target == null && accessor instanceof BlockAccessor blockAccessor &&
|
|
+ blockAccessor.getBlock() instanceof WorldlyContainerHolder holder) {
|
|
+ return holder.getContainer(blockAccessor.getBlockState(), accessor.getLevel(), blockAccessor.getPosition());
|
|
+ } else if (target instanceof Container container) {
|
|
+ return container;
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getDefaultPriority() {
|
|
+ return IServerExtensionProvider.super.getDefaultPriority() + 1000;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..8289b5c48213348a7346dfdbb30ee1b8787d2a2d
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageProvider.java
|
|
@@ -0,0 +1,88 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider;
|
|
+
|
|
+import net.minecraft.nbt.CompoundTag;
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.LockCode;
|
|
+import net.minecraft.world.RandomizableContainer;
|
|
+import net.minecraft.world.entity.player.Player;
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.Accessor;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.util.CommonUtil;
|
|
+import org.leavesmc.leaves.protocol.jade.util.ItemCollector;
|
|
+import org.leavesmc.leaves.protocol.jade.util.ViewGroup;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+
|
|
+public abstract class ItemStorageProvider<T extends Accessor<?>> implements IServerDataProvider<T> {
|
|
+
|
|
+ private static final StreamCodec<RegistryFriendlyByteBuf, Map.Entry<ResourceLocation, List<ViewGroup<ItemStack>>>> STREAM_CODEC = ViewGroup.listCodec(
|
|
+ ItemStack.OPTIONAL_STREAM_CODEC);
|
|
+
|
|
+ private static final ResourceLocation UNIVERSAL_ITEM_STORAGE = JadeProtocol.mc_id("item_storage");
|
|
+
|
|
+ public static ForBlock getBlock() {
|
|
+ return ForBlock.INSTANCE;
|
|
+ }
|
|
+
|
|
+ public static ForEntity getEntity() {
|
|
+ return ForEntity.INSTANCE;
|
|
+ }
|
|
+
|
|
+ public static class ForBlock extends ItemStorageProvider<BlockAccessor> {
|
|
+ private static final ForBlock INSTANCE = new ForBlock();
|
|
+ }
|
|
+
|
|
+ public static class ForEntity extends ItemStorageProvider<EntityAccessor> {
|
|
+ private static final ForEntity INSTANCE = new ForEntity();
|
|
+ }
|
|
+
|
|
+ public static void putData(CompoundTag tag, @NotNull Accessor<?> accessor) {
|
|
+ Object target = accessor.getTarget();
|
|
+ Player player = accessor.getPlayer();
|
|
+ Map.Entry<ResourceLocation, List<ViewGroup<ItemStack>>> entry = CommonUtil.getServerExtensionData(accessor, JadeProtocol.itemStorageProviders);
|
|
+ if (entry != null) {
|
|
+ List<ViewGroup<ItemStack>> groups = entry.getValue();
|
|
+ for (ViewGroup<ItemStack> group : groups) {
|
|
+ if (group.views.size() > ItemCollector.MAX_SIZE) {
|
|
+ group.views = group.views.subList(0, ItemCollector.MAX_SIZE);
|
|
+ }
|
|
+ }
|
|
+ tag.put(UNIVERSAL_ITEM_STORAGE.toString(), accessor.encodeAsNbt(STREAM_CODEC, entry));
|
|
+ return;
|
|
+ }
|
|
+ if (target instanceof RandomizableContainer containerEntity && containerEntity.getLootTable() != null) {
|
|
+ tag.putBoolean("Loot", true);
|
|
+ } else if (!player.isCreative() && !player.isSpectator() && target instanceof BaseContainerBlockEntity te) {
|
|
+ if (te.lockKey != LockCode.NO_LOCK) {
|
|
+ tag.putBoolean("Locked", true);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return UNIVERSAL_ITEM_STORAGE;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void appendServerData(CompoundTag tag, @NotNull T accessor) {
|
|
+ if (accessor.getTarget() instanceof AbstractFurnaceBlockEntity) {
|
|
+ return;
|
|
+ }
|
|
+ putData(tag, accessor);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getDefaultPriority() {
|
|
+ return 9999;
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/StreamServerDataProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/StreamServerDataProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..52887edb3359c5eb1900cd1eec912e52afef2c9f
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/StreamServerDataProvider.java
|
|
@@ -0,0 +1,26 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider;
|
|
+
|
|
+import net.minecraft.nbt.CompoundTag;
|
|
+import net.minecraft.nbt.Tag;
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.Accessor;
|
|
+
|
|
+import java.util.Optional;
|
|
+
|
|
+public interface StreamServerDataProvider<T extends Accessor<?>, D> extends IServerDataProvider<T> {
|
|
+
|
|
+ @Override
|
|
+ default void appendServerData(CompoundTag data, T accessor) {
|
|
+ D value = streamData(accessor);
|
|
+ if (value != null) {
|
|
+ data.put(getUid().toString(), accessor.encodeAsNbt(streamCodec(), value));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Nullable
|
|
+ D streamData(T accessor);
|
|
+
|
|
+ StreamCodec<RegistryFriendlyByteBuf, D> streamCodec();
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BeehiveProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BeehiveProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..ee92d79bf4d328c95c51178a2ad43beb0a54cd29
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BeehiveProvider.java
|
|
@@ -0,0 +1,34 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.block;
|
|
+
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
|
+
|
|
+public enum BeehiveProvider implements StreamServerDataProvider<BlockAccessor, Byte> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final ResourceLocation MC_BEEHIVE = JadeProtocol.mc_id("beehive");
|
|
+
|
|
+ @Override
|
|
+ public @NotNull StreamCodec<RegistryFriendlyByteBuf, Byte> streamCodec() {
|
|
+ return ByteBufCodecs.BYTE.cast();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Byte streamData(@NotNull BlockAccessor accessor) {
|
|
+ BeehiveBlockEntity beehive = (BeehiveBlockEntity) accessor.getBlockEntity();
|
|
+ int bees = beehive.getOccupantCount();
|
|
+ return (byte) (beehive.isFull() ? bees : -bees);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_BEEHIVE;
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BrewingStandProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BrewingStandProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..e6f15f87819d4a7c4d4383db735d8318ea30a03c
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/BrewingStandProvider.java
|
|
@@ -0,0 +1,43 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.block;
|
|
+
|
|
+import io.netty.buffer.ByteBuf;
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.level.block.entity.BrewingStandBlockEntity;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
|
+
|
|
+public enum BrewingStandProvider implements StreamServerDataProvider<BlockAccessor, BrewingStandProvider.Data> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final ResourceLocation MC_BREWING_STAND = JadeProtocol.mc_id("brewing_stand");
|
|
+
|
|
+ @Override
|
|
+ public @NotNull Data streamData(@NotNull BlockAccessor accessor) {
|
|
+ BrewingStandBlockEntity brewingStand = (BrewingStandBlockEntity) accessor.getBlockEntity();
|
|
+ return new Data(brewingStand.fuel, brewingStand.brewTime);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @NotNull StreamCodec<RegistryFriendlyByteBuf, Data> streamCodec() {
|
|
+ return Data.STREAM_CODEC.cast();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_BREWING_STAND;
|
|
+ }
|
|
+
|
|
+ public record Data(int fuel, int time) {
|
|
+ public static final StreamCodec<ByteBuf, Data> STREAM_CODEC = StreamCodec.composite(
|
|
+ ByteBufCodecs.VAR_INT,
|
|
+ Data::fuel,
|
|
+ ByteBufCodecs.VAR_INT,
|
|
+ Data::time,
|
|
+ Data::new);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CampfireProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CampfireProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..2deb3777a320d6a50168e06f234ba4c21da48e9a
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CampfireProvider.java
|
|
@@ -0,0 +1,55 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.block;
|
|
+
|
|
+import com.google.common.collect.Lists;
|
|
+import com.mojang.serialization.Codec;
|
|
+import com.mojang.serialization.MapCodec;
|
|
+import net.minecraft.core.component.DataComponents;
|
|
+import net.minecraft.nbt.NbtOps;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+import net.minecraft.world.item.component.CustomData;
|
|
+import net.minecraft.world.level.block.entity.CampfireBlockEntity;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.jetbrains.annotations.Unmodifiable;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.Accessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.IServerExtensionProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.util.ViewGroup;
|
|
+
|
|
+import java.util.List;
|
|
+
|
|
+public enum CampfireProvider implements IServerExtensionProvider<ItemStack> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final MapCodec<Integer> COOKING_TIME_CODEC = Codec.INT.fieldOf("jade:cooking");
|
|
+ private static final ResourceLocation MC_CAMPFIRE = JadeProtocol.mc_id("campfire");
|
|
+
|
|
+ @Override
|
|
+ public @Nullable @Unmodifiable List<ViewGroup<ItemStack>> getGroups(@NotNull Accessor<?> request) {
|
|
+ if (request.getTarget() instanceof CampfireBlockEntity campfire) {
|
|
+ List<ItemStack> list = Lists.newArrayList();
|
|
+ for (int i = 0; i < campfire.cookingTime.length; i++) {
|
|
+ ItemStack stack = campfire.getItems().get(i);
|
|
+ if (stack.isEmpty()) {
|
|
+ continue;
|
|
+ }
|
|
+ stack = stack.copy();
|
|
+
|
|
+ CustomData customData = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY)
|
|
+ .update(NbtOps.INSTANCE, COOKING_TIME_CODEC, campfire.cookingTime[i] - campfire.cookingProgress[i])
|
|
+ .getOrThrow();
|
|
+ stack.set(DataComponents.CUSTOM_DATA, customData);
|
|
+
|
|
+ list.add(stack);
|
|
+ }
|
|
+ return List.of(new ViewGroup<>(list));
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_CAMPFIRE;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/ChiseledBookshelfProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/ChiseledBookshelfProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..bde872cc5ebd9d79af307c8a4b38acd385cec11b
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/ChiseledBookshelfProvider.java
|
|
@@ -0,0 +1,39 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.block;
|
|
+
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+import net.minecraft.world.level.block.ChiseledBookShelfBlock;
|
|
+import net.minecraft.world.level.block.entity.ChiseledBookShelfBlockEntity;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
|
+
|
|
+public enum ChiseledBookshelfProvider implements StreamServerDataProvider<BlockAccessor, ItemStack> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final ResourceLocation MC_CHISELED_BOOKSHELF = JadeProtocol.mc_id("chiseled_bookshelf");
|
|
+
|
|
+ @Override
|
|
+ public @Nullable ItemStack streamData(@NotNull BlockAccessor accessor) {
|
|
+ int slot = ((ChiseledBookShelfBlock) accessor.getBlock()).getHitSlot(accessor.getHitResult(), accessor.getBlockState()).orElse(-1);
|
|
+ if (slot == -1) {
|
|
+ return null;
|
|
+ }
|
|
+ return ((ChiseledBookShelfBlockEntity) accessor.getBlockEntity()).getItem(slot);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public StreamCodec<RegistryFriendlyByteBuf, ItemStack> streamCodec() {
|
|
+ return ItemStack.OPTIONAL_STREAM_CODEC;
|
|
+ }
|
|
+
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_CHISELED_BOOKSHELF;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CommandBlockProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CommandBlockProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..5f71fadae8fe95e3386e3ee5465eb33f850a37b0
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CommandBlockProvider.java
|
|
@@ -0,0 +1,40 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.block;
|
|
+
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.level.block.entity.CommandBlockEntity;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
|
+
|
|
+public enum CommandBlockProvider implements StreamServerDataProvider<BlockAccessor, String> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final ResourceLocation MC_COMMAND_BLOCK = JadeProtocol.mc_id("command_block");
|
|
+
|
|
+ @Nullable
|
|
+ public String streamData(@NotNull BlockAccessor accessor) {
|
|
+ if (!accessor.getPlayer().canUseGameMasterBlocks()) {
|
|
+ return null;
|
|
+ }
|
|
+ String command = ((CommandBlockEntity) accessor.getBlockEntity()).getCommandBlock().getCommand();
|
|
+ if (command.length() > 40) {
|
|
+ command = command.substring(0, 37) + "...";
|
|
+ }
|
|
+ return command;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @NotNull StreamCodec<RegistryFriendlyByteBuf, String> streamCodec() {
|
|
+ return ByteBufCodecs.STRING_UTF8.cast();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_COMMAND_BLOCK;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/FurnaceProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/FurnaceProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..090e6a350a5c19c0204ecf9a2c2c42e8d012cb3d
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/FurnaceProvider.java
|
|
@@ -0,0 +1,60 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.block;
|
|
+
|
|
+import net.minecraft.nbt.CompoundTag;
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
|
+
|
|
+import java.util.List;
|
|
+
|
|
+public enum FurnaceProvider implements StreamServerDataProvider<BlockAccessor, FurnaceProvider.Data> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final ResourceLocation MC_FURNACE = JadeProtocol.mc_id("furnace");
|
|
+
|
|
+ @Override
|
|
+ public @Nullable Data streamData(@NotNull BlockAccessor accessor) {
|
|
+ if (!(accessor.getTarget() instanceof AbstractFurnaceBlockEntity furnace)) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ if (furnace.isEmpty()) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ CompoundTag furnaceTag = furnace.saveWithoutMetadata(accessor.getLevel().registryAccess());
|
|
+ return new Data(
|
|
+ furnaceTag.getInt("CookTime"),
|
|
+ furnaceTag.getInt("CookTimeTotal"),
|
|
+ List.of(furnace.getItem(0), furnace.getItem(1), furnace.getItem(2)));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public StreamCodec<RegistryFriendlyByteBuf, Data> streamCodec() {
|
|
+ return Data.STREAM_CODEC;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_FURNACE;
|
|
+ }
|
|
+
|
|
+ public record Data(int progress, int total, List<ItemStack> inventory) {
|
|
+ public static final StreamCodec<RegistryFriendlyByteBuf, Data> STREAM_CODEC = StreamCodec.composite(
|
|
+ ByteBufCodecs.VAR_INT,
|
|
+ Data::progress,
|
|
+ ByteBufCodecs.VAR_INT,
|
|
+ Data::total,
|
|
+ ItemStack.OPTIONAL_LIST_STREAM_CODEC,
|
|
+ Data::inventory,
|
|
+ Data::new);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/HopperLockProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/HopperLockProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..a3937081bd923d3b6f2ee966dc95aa235c3eb57c
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/HopperLockProvider.java
|
|
@@ -0,0 +1,32 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.block;
|
|
+
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
|
+
|
|
+public enum HopperLockProvider implements StreamServerDataProvider<BlockAccessor, Boolean> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final ResourceLocation MC_HOPPER_LOCK = JadeProtocol.mc_id("hopper_lock");
|
|
+
|
|
+ @Override
|
|
+ public Boolean streamData(@NotNull BlockAccessor accessor) {
|
|
+ return !accessor.getBlockState().getValue(BlockStateProperties.ENABLED);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @NotNull StreamCodec<RegistryFriendlyByteBuf, Boolean> streamCodec() {
|
|
+ return ByteBufCodecs.BOOL.cast();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_HOPPER_LOCK;
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/JukeboxProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/JukeboxProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..0b6e224ebc8d6acdc29abf51f7d98b667baf0984
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/JukeboxProvider.java
|
|
@@ -0,0 +1,32 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.block;
|
|
+
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+import net.minecraft.world.level.block.entity.JukeboxBlockEntity;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
|
+
|
|
+public enum JukeboxProvider implements StreamServerDataProvider<BlockAccessor, ItemStack> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final ResourceLocation MC_JUKEBOX = JadeProtocol.mc_id("jukebox");
|
|
+
|
|
+ @Override
|
|
+ public @NotNull ItemStack streamData(BlockAccessor accessor) {
|
|
+ return ((JukeboxBlockEntity) accessor.getBlockEntity()).getTheItem();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public StreamCodec<RegistryFriendlyByteBuf, ItemStack> streamCodec() {
|
|
+ return ItemStack.OPTIONAL_STREAM_CODEC;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_JUKEBOX;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/LecternProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/LecternProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..c363bd616fa41eca3266ccb485432cfd90ad7473
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/LecternProvider.java
|
|
@@ -0,0 +1,33 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.block;
|
|
+
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+import net.minecraft.world.level.block.entity.LecternBlockEntity;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
|
+
|
|
+public enum LecternProvider implements StreamServerDataProvider<BlockAccessor, ItemStack> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final ResourceLocation MC_LECTERN = JadeProtocol.mc_id("lectern");
|
|
+
|
|
+ @Override
|
|
+ public @NotNull ItemStack streamData(@NotNull BlockAccessor accessor) {
|
|
+ return ((LecternBlockEntity) accessor.getBlockEntity()).getBook();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public StreamCodec<RegistryFriendlyByteBuf, ItemStack> streamCodec() {
|
|
+ return ItemStack.OPTIONAL_STREAM_CODEC;
|
|
+ }
|
|
+
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_LECTERN;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/MobSpawnerCooldownProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/MobSpawnerCooldownProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..a70f4a81166221ec1971b1fbf06e4c73efffcbe4
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/MobSpawnerCooldownProvider.java
|
|
@@ -0,0 +1,42 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.block;
|
|
+
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.server.level.ServerLevel;
|
|
+import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
|
+
|
|
+public enum MobSpawnerCooldownProvider implements StreamServerDataProvider<BlockAccessor, Integer> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final ResourceLocation MC_MOB_SPAWNER_COOLDOWN = JadeProtocol.mc_id("mob_spawner.cooldown");
|
|
+
|
|
+ @Override
|
|
+ public @Nullable Integer streamData(@NotNull BlockAccessor accessor) {
|
|
+ TrialSpawnerBlockEntity spawner = (TrialSpawnerBlockEntity) accessor.getBlockEntity();
|
|
+ TrialSpawnerData spawnerData = spawner.getTrialSpawner().getData();
|
|
+ ServerLevel level = ((ServerLevel) accessor.getLevel());
|
|
+ if (spawner.getTrialSpawner().canSpawnInLevel(level) && level.getGameTime() < spawnerData.cooldownEndsAt) {
|
|
+ return (int) (spawnerData.cooldownEndsAt - level.getGameTime());
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @NotNull StreamCodec<RegistryFriendlyByteBuf, Integer> streamCodec() {
|
|
+ return ByteBufCodecs.VAR_INT.cast();
|
|
+ }
|
|
+
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_MOB_SPAWNER_COOLDOWN;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/ObjectNameProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/ObjectNameProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..e97fb13707365cceaf28f2624791d0472e56169c
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/ObjectNameProvider.java
|
|
@@ -0,0 +1,57 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.block;
|
|
+
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.chat.Component;
|
|
+import net.minecraft.network.chat.ComponentSerialization;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.MenuProvider;
|
|
+import net.minecraft.world.Nameable;
|
|
+import net.minecraft.world.level.block.ChestBlock;
|
|
+import net.minecraft.world.level.block.entity.ChestBlockEntity;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
|
+
|
|
+public abstract class ObjectNameProvider implements StreamServerDataProvider<BlockAccessor, Component> {
|
|
+
|
|
+ private static final ResourceLocation CORE_OBJECT_NAME = JadeProtocol.id("object_name");
|
|
+
|
|
+ public static class ForBlock extends ObjectNameProvider implements StreamServerDataProvider<BlockAccessor, Component> {
|
|
+ public static final ForBlock INSTANCE = new ForBlock();
|
|
+
|
|
+ @Override
|
|
+ @Nullable
|
|
+ public Component streamData(@NotNull BlockAccessor accessor) {
|
|
+ if (!(accessor.getBlockEntity() instanceof Nameable nameable)) {
|
|
+ return null;
|
|
+ }
|
|
+ if (nameable instanceof ChestBlockEntity && accessor.getBlock() instanceof ChestBlock) {
|
|
+ MenuProvider menuProvider = accessor.getBlockState().getMenuProvider(accessor.getLevel(), accessor.getPosition());
|
|
+ if (menuProvider != null) {
|
|
+ return menuProvider.getDisplayName();
|
|
+ }
|
|
+ } else if (nameable.hasCustomName()) {
|
|
+ return nameable.getDisplayName();
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public StreamCodec<RegistryFriendlyByteBuf, Component> streamCodec() {
|
|
+ return ComponentSerialization.STREAM_CODEC;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return CORE_OBJECT_NAME;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getDefaultPriority() {
|
|
+ return -10100;
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/RedstoneProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/RedstoneProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..1cdcf21ed69744f96f47673100d8bf0114850f4f
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/RedstoneProvider.java
|
|
@@ -0,0 +1,36 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.block;
|
|
+
|
|
+import net.minecraft.core.Direction;
|
|
+import net.minecraft.nbt.CompoundTag;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.level.block.CalibratedSculkSensorBlock;
|
|
+import net.minecraft.world.level.block.entity.BlockEntity;
|
|
+import net.minecraft.world.level.block.entity.CalibratedSculkSensorBlockEntity;
|
|
+import net.minecraft.world.level.block.entity.ComparatorBlockEntity;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.IServerDataProvider;
|
|
+
|
|
+public enum RedstoneProvider implements IServerDataProvider<BlockAccessor> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final ResourceLocation MC_REDSTONE = JadeProtocol.mc_id("redstone");
|
|
+
|
|
+ @Override
|
|
+ public void appendServerData(CompoundTag data, @NotNull BlockAccessor accessor) {
|
|
+ BlockEntity blockEntity = accessor.getBlockEntity();
|
|
+ if (blockEntity instanceof ComparatorBlockEntity comparator) {
|
|
+ data.putInt("Signal", comparator.getOutputSignal());
|
|
+ } else if (blockEntity instanceof CalibratedSculkSensorBlockEntity) {
|
|
+ Direction direction = accessor.getBlockState().getValue(CalibratedSculkSensorBlock.FACING).getOpposite();
|
|
+ int signal = accessor.getLevel().getSignal(accessor.getPosition().relative(direction), direction);
|
|
+ data.putInt("Signal", signal);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_REDSTONE;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/AnimalOwnerProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/AnimalOwnerProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..ff50ef60e3b37ab231161c870c432ef8e3018458
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/AnimalOwnerProvider.java
|
|
@@ -0,0 +1,43 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.entity;
|
|
+
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.entity.Entity;
|
|
+import net.minecraft.world.entity.OwnableEntity;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
|
+import org.leavesmc.leaves.protocol.jade.util.CommonUtil;
|
|
+
|
|
+import java.util.UUID;
|
|
+
|
|
+public enum AnimalOwnerProvider implements StreamServerDataProvider<EntityAccessor, String> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final ResourceLocation MC_ANIMAL_OWNER = JadeProtocol.mc_id("animal_owner");
|
|
+
|
|
+ @Override
|
|
+ public String streamData(@NotNull EntityAccessor accessor) {
|
|
+ return CommonUtil.getLastKnownUsername(getOwnerUUID(accessor.getEntity()));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @NotNull StreamCodec<RegistryFriendlyByteBuf, String> streamCodec() {
|
|
+ return ByteBufCodecs.STRING_UTF8.cast();
|
|
+ }
|
|
+
|
|
+ public static UUID getOwnerUUID(Entity entity) {
|
|
+ if (entity instanceof OwnableEntity ownableEntity) {
|
|
+ return ownableEntity.getOwnerUUID();
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_ANIMAL_OWNER;
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/MobBreedingProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/MobBreedingProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..0acba2f9700e4a65e764077b22e65e18d787be2a
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/MobBreedingProvider.java
|
|
@@ -0,0 +1,44 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.entity;
|
|
+
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.entity.Entity;
|
|
+import net.minecraft.world.entity.animal.Animal;
|
|
+import net.minecraft.world.entity.animal.allay.Allay;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
|
+
|
|
+public enum MobBreedingProvider implements StreamServerDataProvider<EntityAccessor, Integer> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final ResourceLocation MC_MOB_BREEDING = JadeProtocol.mc_id("mob_breeding");
|
|
+
|
|
+ @Override
|
|
+ public @Nullable Integer streamData(@NotNull EntityAccessor accessor) {
|
|
+ int time = 0;
|
|
+ Entity entity = accessor.getEntity();
|
|
+ if (entity instanceof Allay allay) {
|
|
+ if (allay.duplicationCooldown > 0 && allay.duplicationCooldown < Integer.MAX_VALUE) {
|
|
+ time = (int) allay.duplicationCooldown;
|
|
+ }
|
|
+ } else {
|
|
+ time = ((Animal) entity).getAge();
|
|
+ }
|
|
+ return time > 0 ? time : null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @NotNull StreamCodec<RegistryFriendlyByteBuf, Integer> streamCodec() {
|
|
+ return ByteBufCodecs.VAR_INT.cast();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_MOB_BREEDING;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/MobGrowthProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/MobGrowthProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..44f5f4b8bf3b9fe66b2f8b93b36284c3ae5d1d87
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/MobGrowthProvider.java
|
|
@@ -0,0 +1,43 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.entity;
|
|
+
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.entity.AgeableMob;
|
|
+import net.minecraft.world.entity.Entity;
|
|
+import net.minecraft.world.entity.animal.frog.Tadpole;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
|
+
|
|
+public enum MobGrowthProvider implements StreamServerDataProvider<EntityAccessor, Integer> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final ResourceLocation MC_MOB_GROWTH = JadeProtocol.mc_id("mob_growth");
|
|
+
|
|
+ @Override
|
|
+ public @Nullable Integer streamData(@NotNull EntityAccessor accessor) {
|
|
+ int time = -1;
|
|
+ Entity entity = accessor.getEntity();
|
|
+ if (entity instanceof AgeableMob ageable) {
|
|
+ time = -ageable.getAge();
|
|
+ } else if (entity instanceof Tadpole tadpole) {
|
|
+ time = tadpole.getTicksLeftUntilAdult();
|
|
+ }
|
|
+ return time > 0 ? time : null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @NotNull StreamCodec<RegistryFriendlyByteBuf, Integer> streamCodec() {
|
|
+ return ByteBufCodecs.VAR_INT.cast();
|
|
+ }
|
|
+
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_MOB_GROWTH;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/NextEntityDropProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/NextEntityDropProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..892911a3d0087a5bf48b2df8326e3c5ce27835a0
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/NextEntityDropProvider.java
|
|
@@ -0,0 +1,35 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.entity;
|
|
+
|
|
+import net.minecraft.nbt.CompoundTag;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.entity.animal.Chicken;
|
|
+import net.minecraft.world.entity.animal.armadillo.Armadillo;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.IServerDataProvider;
|
|
+
|
|
+public enum NextEntityDropProvider implements IServerDataProvider<EntityAccessor> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final ResourceLocation MC_NEXT_ENTITY_DROP = JadeProtocol.mc_id("next_entity_drop");
|
|
+
|
|
+ @Override
|
|
+ public void appendServerData(CompoundTag tag, @NotNull EntityAccessor accessor) {
|
|
+ int max = 24000 * 2;
|
|
+ if (accessor.getEntity() instanceof Chicken chicken) {
|
|
+ if (!chicken.isBaby() && chicken.eggTime < max) {
|
|
+ tag.putInt("NextEggIn", chicken.eggTime);
|
|
+ }
|
|
+ } else if (accessor.getEntity() instanceof Armadillo armadillo) {
|
|
+ if (!armadillo.isBaby() && armadillo.scuteTime < max) {
|
|
+ tag.putInt("NextScuteIn", armadillo.scuteTime);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_NEXT_ENTITY_DROP;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/StatusEffectsProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/StatusEffectsProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..ffc571875f620fe53b2210583c246d6579c3df1f
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/StatusEffectsProvider.java
|
|
@@ -0,0 +1,45 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.entity;
|
|
+
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.effect.MobEffectInstance;
|
|
+import net.minecraft.world.entity.LivingEntity;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
|
+
|
|
+import java.util.List;
|
|
+
|
|
+public enum StatusEffectsProvider implements StreamServerDataProvider<EntityAccessor, List<MobEffectInstance>> {
|
|
+ INSTANCE;
|
|
+
|
|
+
|
|
+ private static final StreamCodec<RegistryFriendlyByteBuf, List<MobEffectInstance>> STREAM_CODEC = ByteBufCodecs.<RegistryFriendlyByteBuf, MobEffectInstance>list()
|
|
+ .apply(MobEffectInstance.STREAM_CODEC);
|
|
+ private static final ResourceLocation MC_POTION_EFFECTS = JadeProtocol.mc_id("potion_effects");
|
|
+
|
|
+ @Override
|
|
+ @Nullable
|
|
+ public List<MobEffectInstance> streamData(@NotNull EntityAccessor accessor) {
|
|
+ List<MobEffectInstance> effects = ((LivingEntity) accessor.getEntity()).getActiveEffects()
|
|
+ .stream()
|
|
+ .filter(MobEffectInstance::isVisible)
|
|
+ .toList();
|
|
+ return effects.isEmpty() ? null : effects;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public StreamCodec<RegistryFriendlyByteBuf, List<MobEffectInstance>> streamCodec() {
|
|
+ return STREAM_CODEC;
|
|
+ }
|
|
+
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ return MC_POTION_EFFECTS;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/ZombieVillagerProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/ZombieVillagerProvider.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..b7c9afd29f3ddead6871c8f2b1f2b0815605cea5
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/entity/ZombieVillagerProvider.java
|
|
@@ -0,0 +1,34 @@
|
|
+package org.leavesmc.leaves.protocol.jade.provider.entity;
|
|
+
|
|
+import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.entity.monster.ZombieVillager;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.StreamServerDataProvider;
|
|
+
|
|
+public enum ZombieVillagerProvider implements StreamServerDataProvider<EntityAccessor, Integer> {
|
|
+ INSTANCE;
|
|
+
|
|
+ private static final ResourceLocation MC_ZOMBIE_VILLAGER = JadeProtocol.mc_id("zombie_villager");
|
|
+
|
|
+ @Override
|
|
+ public @Nullable Integer streamData(@NotNull EntityAccessor accessor) {
|
|
+ int time = ((ZombieVillager) accessor.getEntity()).villagerConversionTime;
|
|
+ return time > 0 ? time : null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @NotNull StreamCodec<RegistryFriendlyByteBuf, Integer> streamCodec() {
|
|
+ return ByteBufCodecs.VAR_INT.cast();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ResourceLocation getUid() {
|
|
+ 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..6a9cd9f0e71331c4fd3bef7bbeabebcc5d0e80cb
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/tool/ShearsToolHandler.java
|
|
@@ -0,0 +1,32 @@
|
|
+package org.leavesmc.leaves.protocol.jade.tool;
|
|
+
|
|
+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.Blocks;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+
|
|
+import java.util.List;
|
|
+
|
|
+public class ShearsToolHandler extends SimpleToolHandler {
|
|
+
|
|
+ private static final ShearsToolHandler INSTANCE = new ShearsToolHandler();
|
|
+
|
|
+ public static ShearsToolHandler getInstance() {
|
|
+ return INSTANCE;
|
|
+ }
|
|
+
|
|
+ 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)) {
|
|
+ return tools.getFirst();
|
|
+ }
|
|
+ return super.test(state, world, pos);
|
|
+ }
|
|
+}
|
|
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..d45ecdb17a78d7e0c5eb280ee584960761ced1d2
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/tool/SimpleToolHandler.java
|
|
@@ -0,0 +1,71 @@
|
|
+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 org.jetbrains.annotations.Contract;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+
|
|
+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, @NotNull List<ItemStack> tools, boolean skipInstaBreakingBlock) {
|
|
+ this.uid = uid;
|
|
+ Preconditions.checkArgument(!tools.isEmpty(), "tools cannot be empty");
|
|
+ this.tools.addAll(tools);
|
|
+ this.skipInstaBreakingBlock = skipInstaBreakingBlock;
|
|
+ }
|
|
+
|
|
+ @Contract("_, _ -> new")
|
|
+ public static @NotNull SimpleToolHandler create(ResourceLocation uid, List<Item> tools) {
|
|
+ return create(uid, tools, true);
|
|
+ }
|
|
+
|
|
+ @Contract("_, _, _ -> new")
|
|
+ public static @NotNull 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/CommonUtil.java b/src/main/java/org/leavesmc/leaves/protocol/jade/util/CommonUtil.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..a0a85361693980eb5b0bf7f9d486475c77b646f7
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/util/CommonUtil.java
|
|
@@ -0,0 +1,79 @@
|
|
+package org.leavesmc.leaves.protocol.jade.util;
|
|
+
|
|
+import com.mojang.authlib.GameProfile;
|
|
+import net.minecraft.core.registries.BuiltInRegistries;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.entity.Entity;
|
|
+import net.minecraft.world.entity.boss.EnderDragonPart;
|
|
+import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+import net.minecraft.world.level.block.entity.SkullBlockEntity;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.LeavesLogger;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.Accessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.IServerExtensionProvider;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Optional;
|
|
+import java.util.UUID;
|
|
+
|
|
+public class CommonUtil {
|
|
+
|
|
+ public static @NotNull ResourceLocation getId(Block block) {
|
|
+ return BuiltInRegistries.BLOCK.getKey(block);
|
|
+ }
|
|
+
|
|
+ public static Entity wrapPartEntityParent(Entity target) {
|
|
+ if (target instanceof EnderDragonPart part) {
|
|
+ return part.parentMob;
|
|
+ }
|
|
+ return target;
|
|
+ }
|
|
+
|
|
+ public static Entity getPartEntity(Entity parent, int index) {
|
|
+ if (parent == null) {
|
|
+ return null;
|
|
+ }
|
|
+ if (index < 0) {
|
|
+ return parent;
|
|
+ }
|
|
+ if (parent instanceof EnderDragon dragon) {
|
|
+ EnderDragonPart[] parts = dragon.getSubEntities();
|
|
+ if (index < parts.length) {
|
|
+ return parts[index];
|
|
+ }
|
|
+ }
|
|
+ return parent;
|
|
+ }
|
|
+
|
|
+
|
|
+ @Nullable
|
|
+ public static String getLastKnownUsername(@Nullable UUID uuid) {
|
|
+ if (uuid == null) {
|
|
+ return null;
|
|
+ }
|
|
+ Optional<GameProfile> optional = SkullBlockEntity.fetchGameProfile(String.valueOf(uuid)).getNow(Optional.empty());
|
|
+ return optional.map(GameProfile::getName).orElse(null);
|
|
+ }
|
|
+
|
|
+
|
|
+ public static <T> Map.Entry<ResourceLocation, List<ViewGroup<T>>> getServerExtensionData(
|
|
+ Accessor<?> accessor,
|
|
+ WrappedHierarchyLookup<IServerExtensionProvider<T>> lookup) {
|
|
+ for (var provider : lookup.wrappedGet(accessor)) {
|
|
+ List<ViewGroup<T>> groups;
|
|
+ try {
|
|
+ groups = provider.getGroups(accessor);
|
|
+ } catch (Exception e) {
|
|
+ LeavesLogger.LOGGER.severe(e.toString());
|
|
+ continue;
|
|
+ }
|
|
+ if (groups != null) {
|
|
+ return Map.entry(provider.getUid(), groups);
|
|
+ }
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+}
|
|
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..0070fd22b096281a094d1cd19c93fdbccc03a3cc
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/util/HierarchyLookup.java
|
|
@@ -0,0 +1,139 @@
|
|
+package org.leavesmc.leaves.protocol.jade.util;
|
|
+
|
|
+import com.google.common.base.Preconditions;
|
|
+import com.google.common.cache.Cache;
|
|
+import com.google.common.cache.CacheBuilder;
|
|
+import com.google.common.collect.ArrayListMultimap;
|
|
+import com.google.common.collect.ImmutableList;
|
|
+import com.google.common.collect.ImmutableListMultimap;
|
|
+import com.google.common.collect.ListMultimap;
|
|
+import com.google.common.collect.Lists;
|
|
+import com.google.common.collect.Sets;
|
|
+import net.minecraft.core.IdMapper;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.LeavesLogger;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.IJadeProvider;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.Comparator;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Objects;
|
|
+import java.util.Set;
|
|
+import java.util.concurrent.ExecutionException;
|
|
+import java.util.stream.Stream;
|
|
+
|
|
+public class HierarchyLookup<T extends IJadeProvider> implements IHierarchyLookup<T> {
|
|
+ private final Class<?> baseClass;
|
|
+ private final Cache<Class<?>, List<T>> resultCache = CacheBuilder.newBuilder().build();
|
|
+ private final boolean singleton;
|
|
+ protected boolean idMapped;
|
|
+ @Nullable
|
|
+ protected IdMapper<T> idMapper;
|
|
+ private ListMultimap<Class<?>, T> objects = ArrayListMultimap.create();
|
|
+
|
|
+ public HierarchyLookup(Class<?> baseClass) {
|
|
+ this(baseClass, false);
|
|
+ }
|
|
+
|
|
+ public HierarchyLookup(Class<?> baseClass, boolean singleton) {
|
|
+ this.baseClass = baseClass;
|
|
+ this.singleton = singleton;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void idMapped() {
|
|
+ this.idMapped = true;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ @Nullable
|
|
+ public IdMapper<T> idMapper() {
|
|
+ return idMapper;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void register(Class<?> clazz, T provider) {
|
|
+ Preconditions.checkArgument(isClassAcceptable(clazz), "Class %s is not acceptable", clazz);
|
|
+ Objects.requireNonNull(provider.getUid());
|
|
+ JadeProtocol.priorities.put(provider);
|
|
+ objects.put(clazz, provider);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isClassAcceptable(Class<?> clazz) {
|
|
+ return baseClass.isAssignableFrom(clazz);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public List<T> get(Class<?> clazz) {
|
|
+ try {
|
|
+ return resultCache.get(clazz, () -> {
|
|
+ List<T> list = Lists.newArrayList();
|
|
+ getInternal(clazz, list);
|
|
+ list = ImmutableList.sortedCopyOf(Comparator.comparingInt(JadeProtocol.priorities::byValue), list);
|
|
+ if (singleton && !list.isEmpty()) {
|
|
+ return ImmutableList.of(list.getFirst());
|
|
+ }
|
|
+ return list;
|
|
+ });
|
|
+ } catch (ExecutionException e) {
|
|
+ LeavesLogger.LOGGER.warning("HierarchyLookup error", e);
|
|
+ }
|
|
+ return List.of();
|
|
+ }
|
|
+
|
|
+ private void getInternal(Class<?> clazz, List<T> list) {
|
|
+ if (clazz != baseClass && clazz != Object.class) {
|
|
+ getInternal(clazz.getSuperclass(), list);
|
|
+ }
|
|
+ list.addAll(objects.get(clazz));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return objects.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Stream<Map.Entry<Class<?>, Collection<T>>> entries() {
|
|
+ return objects.asMap().entrySet().stream();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void invalidate() {
|
|
+ resultCache.invalidateAll();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void loadComplete(PriorityStore<ResourceLocation, IJadeProvider> priorityStore) {
|
|
+ objects.asMap().forEach((clazz, list) -> {
|
|
+ if (list.size() < 2) {
|
|
+ return;
|
|
+ }
|
|
+ Set<ResourceLocation> set = Sets.newHashSetWithExpectedSize(list.size());
|
|
+ for (T provider : list) {
|
|
+ if (set.contains(provider.getUid())) {
|
|
+ throw new IllegalStateException("Duplicate UID: %s for %s".formatted(provider.getUid(), list.stream()
|
|
+ .filter(p -> p.getUid().equals(provider.getUid()))
|
|
+ .map(p -> p.getClass().getName())
|
|
+ .toList()
|
|
+ ));
|
|
+ }
|
|
+ set.add(provider.getUid());
|
|
+ }
|
|
+ });
|
|
+
|
|
+ objects = ImmutableListMultimap.<Class<?>, T>builder()
|
|
+ .orderValuesBy(Comparator.comparingInt(priorityStore::byValue))
|
|
+ .putAll(objects)
|
|
+ .build();
|
|
+
|
|
+ if (idMapped) {
|
|
+ idMapper = createIdMapper();
|
|
+ }
|
|
+ }
|
|
+
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/util/IHierarchyLookup.java b/src/main/java/org/leavesmc/leaves/protocol/jade/util/IHierarchyLookup.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..137cdf619879390477b4fc8c4b7ecee5b762dc30
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/util/IHierarchyLookup.java
|
|
@@ -0,0 +1,66 @@
|
|
+package org.leavesmc.leaves.protocol.jade.util;
|
|
+
|
|
+import com.google.common.collect.Streams;
|
|
+import net.minecraft.core.IdMapper;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.IJadeProvider;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Objects;
|
|
+import java.util.stream.Stream;
|
|
+
|
|
+public interface IHierarchyLookup<T extends IJadeProvider> {
|
|
+ default IHierarchyLookup<? extends T> cast() {
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ void idMapped();
|
|
+
|
|
+ @Nullable
|
|
+ IdMapper<T> idMapper();
|
|
+
|
|
+ default List<ResourceLocation> mappedIds() {
|
|
+ return Streams.stream(Objects.requireNonNull(idMapper()))
|
|
+ .map(IJadeProvider::getUid)
|
|
+ .toList();
|
|
+ }
|
|
+
|
|
+ void register(Class<?> clazz, T provider);
|
|
+
|
|
+ boolean isClassAcceptable(Class<?> clazz);
|
|
+
|
|
+ default List<T> get(Object obj) {
|
|
+ if (obj == null) {
|
|
+ return List.of();
|
|
+ }
|
|
+ return get(obj.getClass());
|
|
+ }
|
|
+
|
|
+ List<T> get(Class<?> clazz);
|
|
+
|
|
+ boolean isEmpty();
|
|
+
|
|
+ Stream<Map.Entry<Class<?>, Collection<T>>> entries();
|
|
+
|
|
+ void invalidate();
|
|
+
|
|
+ void loadComplete(PriorityStore<ResourceLocation, IJadeProvider> priorityStore);
|
|
+
|
|
+ default IdMapper<T> createIdMapper() {
|
|
+ List<T> list = entries().flatMap(entry -> entry.getValue().stream()).toList();
|
|
+ IdMapper<T> idMapper = idMapper();
|
|
+ if (idMapper == null) {
|
|
+ idMapper = new IdMapper<>(list.size());
|
|
+ }
|
|
+ for (T provider : list) {
|
|
+ if (idMapper.getId(provider) == -1) {
|
|
+ idMapper.add(provider);
|
|
+ }
|
|
+ }
|
|
+ return idMapper;
|
|
+ }
|
|
+}
|
|
+
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemCollector.java b/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemCollector.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..8f57cb0714dc684bd90325a6d2e84d5b1b303d6e
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemCollector.java
|
|
@@ -0,0 +1,116 @@
|
|
+package org.leavesmc.leaves.protocol.jade.util;
|
|
+
|
|
+import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap;
|
|
+import net.minecraft.core.component.DataComponentPatch;
|
|
+import net.minecraft.core.component.DataComponents;
|
|
+import net.minecraft.nbt.CompoundTag;
|
|
+import net.minecraft.world.item.Item;
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+import net.minecraft.world.item.component.CustomData;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.Accessor;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.Locale;
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
+import java.util.function.Predicate;
|
|
+
|
|
+public class ItemCollector<T> {
|
|
+ public static final int MAX_SIZE = 54;
|
|
+ public static final ItemCollector<?> EMPTY = new ItemCollector<>(null);
|
|
+ private static final Predicate<ItemStack> NON_EMPTY = stack -> {
|
|
+ if (stack.isEmpty()) {
|
|
+ return false;
|
|
+ }
|
|
+ CustomData customData = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY);
|
|
+ if (customData.contains("CustomModelData")) {
|
|
+ CompoundTag tag = customData.copyTag();
|
|
+ for (String key : tag.getAllKeys()) {
|
|
+ if (key.toLowerCase(Locale.ENGLISH).endsWith("clear") && tag.getBoolean(key)) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return true;
|
|
+ };
|
|
+ private final Object2IntLinkedOpenHashMap<ItemDefinition> items = new Object2IntLinkedOpenHashMap<>();
|
|
+ private final ItemIterator<T> iterator;
|
|
+ public long version;
|
|
+ public long lastTimeFinished;
|
|
+ public List<ViewGroup<ItemStack>> mergedResult;
|
|
+
|
|
+ public ItemCollector(ItemIterator<T> iterator) {
|
|
+ this.iterator = iterator;
|
|
+ }
|
|
+
|
|
+ public List<ViewGroup<ItemStack>> update(Accessor<?> request) {
|
|
+ if (iterator == null) {
|
|
+ return null;
|
|
+ }
|
|
+ T container = iterator.find(request.getTarget());
|
|
+ if (container == null) {
|
|
+ return null;
|
|
+ }
|
|
+ long currentVersion = iterator.getVersion(container);
|
|
+ long gameTime = request.getLevel().getGameTime();
|
|
+ if (mergedResult != null && iterator.isFinished()) {
|
|
+ if (version == currentVersion) {
|
|
+ return mergedResult; // content not changed
|
|
+ }
|
|
+ if (lastTimeFinished + 5 > gameTime) {
|
|
+ return mergedResult; // avoid update too frequently
|
|
+ }
|
|
+ iterator.reset();
|
|
+ }
|
|
+ AtomicInteger count = new AtomicInteger();
|
|
+ iterator.populate(container).forEach(stack -> {
|
|
+ count.incrementAndGet();
|
|
+ if (NON_EMPTY.test(stack)) {
|
|
+ ItemDefinition def = new ItemDefinition(stack);
|
|
+ items.addTo(def, stack.getCount());
|
|
+ }
|
|
+ });
|
|
+ iterator.afterPopulate(count.get());
|
|
+ if (mergedResult != null && !iterator.isFinished()) {
|
|
+ updateCollectingProgress(mergedResult.getFirst());
|
|
+ return mergedResult;
|
|
+ }
|
|
+ List<ItemStack> partialResult = items.object2IntEntrySet().stream().limit(54).map(entry -> {
|
|
+ ItemDefinition def = entry.getKey();
|
|
+ return def.toStack(entry.getIntValue());
|
|
+ }).toList();
|
|
+ List<ViewGroup<ItemStack>> groups = List.of(updateCollectingProgress(new ViewGroup<>(partialResult)));
|
|
+ if (iterator.isFinished()) {
|
|
+ mergedResult = groups;
|
|
+ version = currentVersion;
|
|
+ lastTimeFinished = gameTime;
|
|
+ items.clear();
|
|
+ }
|
|
+ return groups;
|
|
+ }
|
|
+
|
|
+ protected ViewGroup<ItemStack> updateCollectingProgress(ViewGroup<ItemStack> group) {
|
|
+ float progress = iterator.getCollectingProgress();
|
|
+ CompoundTag data = group.getExtraData();
|
|
+ if (Float.isNaN(progress)) {
|
|
+ progress = 0;
|
|
+ }
|
|
+ if (progress >= 1) {
|
|
+ data.remove("Collecting");
|
|
+ } else {
|
|
+ data.putFloat("Collecting", progress);
|
|
+ }
|
|
+ return group;
|
|
+ }
|
|
+
|
|
+ public record ItemDefinition(Item item, DataComponentPatch components) {
|
|
+ ItemDefinition(ItemStack stack) {
|
|
+ this(stack.getItem(), stack.getComponentsPatch());
|
|
+ }
|
|
+
|
|
+ public ItemStack toStack(int count) {
|
|
+ ItemStack itemStack = new ItemStack(item, count);
|
|
+ itemStack.applyComponents(components);
|
|
+ return itemStack;
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemIterator.java b/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemIterator.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..4d65e9a8b5224bd268b1bf18bc39a58dc0113850
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemIterator.java
|
|
@@ -0,0 +1,102 @@
|
|
+package org.leavesmc.leaves.protocol.jade.util;
|
|
+
|
|
+import net.minecraft.world.Container;
|
|
+import net.minecraft.world.item.ItemStack;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+
|
|
+import java.util.concurrent.atomic.AtomicLong;
|
|
+import java.util.function.Function;
|
|
+import java.util.stream.IntStream;
|
|
+import java.util.stream.Stream;
|
|
+
|
|
+public abstract class ItemIterator<T> {
|
|
+ public static final AtomicLong version = new AtomicLong();
|
|
+ protected final Function<Object, @Nullable T> containerFinder;
|
|
+ protected final int fromIndex;
|
|
+ protected boolean finished;
|
|
+ protected int currentIndex;
|
|
+
|
|
+ protected ItemIterator(Function<Object, @Nullable T> containerFinder, int fromIndex) {
|
|
+ this.containerFinder = containerFinder;
|
|
+ this.currentIndex = this.fromIndex = fromIndex;
|
|
+ }
|
|
+
|
|
+ public @Nullable T find(Object target) {
|
|
+ return containerFinder.apply(target);
|
|
+ }
|
|
+
|
|
+ public final boolean isFinished() {
|
|
+ return finished;
|
|
+ }
|
|
+
|
|
+ public long getVersion(T container) {
|
|
+ return version.getAndIncrement();
|
|
+ }
|
|
+
|
|
+ public abstract Stream<ItemStack> populate(T container);
|
|
+
|
|
+ public void reset() {
|
|
+ currentIndex = fromIndex;
|
|
+ finished = false;
|
|
+ }
|
|
+
|
|
+ public void afterPopulate(int count) {
|
|
+ currentIndex += count;
|
|
+ if (count == 0 || currentIndex >= 10000) {
|
|
+ finished = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public float getCollectingProgress() {
|
|
+ return Float.NaN;
|
|
+ }
|
|
+
|
|
+ public static abstract class SlottedItemIterator<T> extends ItemIterator<T> {
|
|
+ protected float progress;
|
|
+
|
|
+ public SlottedItemIterator(Function<Object, @Nullable T> containerFinder, int fromIndex) {
|
|
+ super(containerFinder, fromIndex);
|
|
+ }
|
|
+
|
|
+ protected abstract int getSlotCount(T container);
|
|
+
|
|
+ protected abstract ItemStack getItemInSlot(T container, int slot);
|
|
+
|
|
+ @Override
|
|
+ public Stream<ItemStack> populate(T container) {
|
|
+ int slotCount = getSlotCount(container);
|
|
+ int toIndex = currentIndex + ItemCollector.MAX_SIZE * 2;
|
|
+ if (toIndex >= slotCount) {
|
|
+ toIndex = slotCount;
|
|
+ finished = true;
|
|
+ }
|
|
+ progress = (float) (currentIndex - fromIndex) / (slotCount - fromIndex);
|
|
+ return IntStream.range(currentIndex, toIndex).mapToObj(slot -> getItemInSlot(container, slot));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public float getCollectingProgress() {
|
|
+ return progress;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static class ContainerItemIterator extends SlottedItemIterator<Container> {
|
|
+ public ContainerItemIterator(int fromIndex) {
|
|
+ this(Container.class::cast, fromIndex);
|
|
+ }
|
|
+
|
|
+ public ContainerItemIterator(Function<Object, @Nullable Container> containerFinder, int fromIndex) {
|
|
+ super(containerFinder, fromIndex);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected int getSlotCount(Container container) {
|
|
+ return container.getContainerSize();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected ItemStack getItemInSlot(Container container, int slot) {
|
|
+ return container.getItem(slot);
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/util/JadeCodec.java b/src/main/java/org/leavesmc/leaves/protocol/jade/util/JadeCodec.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..a046ae4e542efcadd0001b7225440c309a7a7570
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/util/JadeCodec.java
|
|
@@ -0,0 +1,59 @@
|
|
+package org.leavesmc.leaves.protocol.jade.util;
|
|
+
|
|
+import io.netty.buffer.ByteBuf;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+
|
|
+public class JadeCodec {
|
|
+ public static final StreamCodec<ByteBuf, Object> PRIMITIVE_STREAM_CODEC = new StreamCodec<>() {
|
|
+ @Override
|
|
+ public @NotNull Object decode(@NotNull ByteBuf buf) {
|
|
+ byte b = buf.readByte();
|
|
+ if (b == 0) {
|
|
+ return false;
|
|
+ } else if (b == 1) {
|
|
+ return true;
|
|
+ } else if (b == 2) {
|
|
+ return ByteBufCodecs.VAR_INT.decode(buf);
|
|
+ } else if (b == 3) {
|
|
+ return ByteBufCodecs.FLOAT.decode(buf);
|
|
+ } else if (b == 4) {
|
|
+ return ByteBufCodecs.STRING_UTF8.decode(buf);
|
|
+ } else if (b > 20) {
|
|
+ return b - 20;
|
|
+ }
|
|
+ throw new IllegalArgumentException("Unknown primitive type: " + b);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void encode(@NotNull ByteBuf buf, @NotNull Object o) {
|
|
+ switch (o) {
|
|
+ case Boolean b -> buf.writeByte(b ? 1 : 0);
|
|
+ case Number n -> {
|
|
+ float f = n.floatValue();
|
|
+ if (f != (int) f) {
|
|
+ buf.writeByte(3);
|
|
+ ByteBufCodecs.FLOAT.encode(buf, f);
|
|
+ }
|
|
+ int i = n.intValue();
|
|
+ if (i <= Byte.MAX_VALUE - 20 && i >= 0) {
|
|
+ buf.writeByte(i + 20);
|
|
+ } else {
|
|
+ ByteBufCodecs.VAR_INT.encode(buf, i);
|
|
+ }
|
|
+ }
|
|
+ case String s -> {
|
|
+ buf.writeByte(4);
|
|
+ ByteBufCodecs.STRING_UTF8.encode(buf, s);
|
|
+ }
|
|
+ case Enum<?> anEnum -> {
|
|
+ buf.writeByte(4);
|
|
+ ByteBufCodecs.STRING_UTF8.encode(buf, anEnum.name());
|
|
+ }
|
|
+ case null -> throw new NullPointerException();
|
|
+ default -> throw new IllegalArgumentException("Unknown primitive type: %s (%s)".formatted(o, o.getClass()));
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+}
|
|
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..63f4d0a31232525db3620095fc662f0225c5f306
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/util/LootTableMineableCollector.java
|
|
@@ -0,0 +1,105 @@
|
|
+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.jetbrains.annotations.NotNull;
|
|
+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 @NotNull 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(@NotNull 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(@NotNull 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..cb5c8201958b3f444d990082d7aac615090cc2a8
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/util/PairHierarchyLookup.java
|
|
@@ -0,0 +1,120 @@
|
|
+package org.leavesmc.leaves.protocol.jade.util;
|
|
+
|
|
+import com.google.common.cache.Cache;
|
|
+import com.google.common.cache.CacheBuilder;
|
|
+import com.google.common.collect.ImmutableList;
|
|
+import com.google.common.collect.Iterables;
|
|
+import net.minecraft.core.IdMapper;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import org.apache.commons.lang3.tuple.Pair;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.LeavesLogger;
|
|
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.IJadeProvider;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.Comparator;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Objects;
|
|
+import java.util.concurrent.ExecutionException;
|
|
+import java.util.stream.Stream;
|
|
+
|
|
+public class PairHierarchyLookup<T extends IJadeProvider> implements IHierarchyLookup<T> {
|
|
+ public final IHierarchyLookup<T> first;
|
|
+ public final IHierarchyLookup<T> second;
|
|
+ private final Cache<Pair<Class<?>, Class<?>>, List<T>> mergedCache = CacheBuilder.newBuilder().build();
|
|
+ protected boolean idMapped;
|
|
+ @Nullable
|
|
+ protected IdMapper<T> idMapper;
|
|
+
|
|
+ public PairHierarchyLookup(IHierarchyLookup<T> first, IHierarchyLookup<T> second) {
|
|
+ this.first = first;
|
|
+ this.second = second;
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ public <ANY> List<ANY> getMerged(Object first, Object second) {
|
|
+ Objects.requireNonNull(first);
|
|
+ Objects.requireNonNull(second);
|
|
+ try {
|
|
+ return (List<ANY>) mergedCache.get(Pair.of(first.getClass(), second.getClass()), () -> {
|
|
+ List<T> firstList = this.first.get(first);
|
|
+ List<T> secondList = this.second.get(second);
|
|
+ if (firstList.isEmpty()) {
|
|
+ return secondList;
|
|
+ } else if (secondList.isEmpty()) {
|
|
+ return firstList;
|
|
+ }
|
|
+ return ImmutableList.sortedCopyOf(
|
|
+ Comparator.comparingInt(JadeProtocol.priorities::byValue),
|
|
+ Iterables.concat(firstList, secondList)
|
|
+ );
|
|
+ });
|
|
+ } catch (ExecutionException e) {
|
|
+ LeavesLogger.LOGGER.severe(e.toString());
|
|
+ }
|
|
+ return List.of();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void idMapped() {
|
|
+ idMapped = true;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @Nullable IdMapper<T> idMapper() {
|
|
+ return idMapper;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void register(Class<?> clazz, T provider) {
|
|
+ if (first.isClassAcceptable(clazz)) {
|
|
+ first.register(clazz, provider);
|
|
+ } else if (second.isClassAcceptable(clazz)) {
|
|
+ second.register(clazz, provider);
|
|
+ } else {
|
|
+ throw new IllegalArgumentException("Class " + clazz + " is not acceptable");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isClassAcceptable(Class<?> clazz) {
|
|
+ return first.isClassAcceptable(clazz) || second.isClassAcceptable(clazz);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public List<T> get(Class<?> clazz) {
|
|
+ List<T> result = first.get(clazz);
|
|
+ if (result.isEmpty()) {
|
|
+ result = second.get(clazz);
|
|
+ }
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return first.isEmpty() && second.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Stream<Map.Entry<Class<?>, Collection<T>>> entries() {
|
|
+ return Stream.concat(first.entries(), second.entries());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void invalidate() {
|
|
+ first.invalidate();
|
|
+ second.invalidate();
|
|
+ mergedCache.invalidateAll();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void loadComplete(PriorityStore<ResourceLocation, IJadeProvider> priorityStore) {
|
|
+ first.loadComplete(priorityStore);
|
|
+ second.loadComplete(priorityStore);
|
|
+ if (idMapped) {
|
|
+ idMapper = createIdMapper();
|
|
+ }
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/util/PriorityStore.java b/src/main/java/org/leavesmc/leaves/protocol/jade/util/PriorityStore.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..da4d5a7751b1076417e63b63dc1f91c0fcc73ff9
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/util/PriorityStore.java
|
|
@@ -0,0 +1,40 @@
|
|
+package org.leavesmc.leaves.protocol.jade.util;
|
|
+
|
|
+import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap;
|
|
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
|
+
|
|
+import java.util.Objects;
|
|
+import java.util.function.Function;
|
|
+import java.util.function.ToIntFunction;
|
|
+
|
|
+public class PriorityStore<K, V> {
|
|
+
|
|
+ private final Object2IntMap<K> priorities = new Object2IntLinkedOpenHashMap<>();
|
|
+ private final Function<V, K> keyGetter;
|
|
+ private final ToIntFunction<V> defaultPriorityGetter;
|
|
+
|
|
+ public PriorityStore(ToIntFunction<V> defaultPriorityGetter, Function<V, K> keyGetter) {
|
|
+ this.defaultPriorityGetter = defaultPriorityGetter;
|
|
+ this.keyGetter = keyGetter;
|
|
+ }
|
|
+
|
|
+ public void put(V provider) {
|
|
+ Objects.requireNonNull(provider);
|
|
+ put(provider, defaultPriorityGetter.applyAsInt(provider));
|
|
+ }
|
|
+
|
|
+ public void put(V provider, int priority) {
|
|
+ Objects.requireNonNull(provider);
|
|
+ K uid = keyGetter.apply(provider);
|
|
+ Objects.requireNonNull(uid);
|
|
+ priorities.put(uid, priority);
|
|
+ }
|
|
+
|
|
+ public int byValue(V value) {
|
|
+ return byKey(keyGetter.apply(value));
|
|
+ }
|
|
+
|
|
+ public int byKey(K id) {
|
|
+ return priorities.getInt(id);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/util/ViewGroup.java b/src/main/java/org/leavesmc/leaves/protocol/jade/util/ViewGroup.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..520eadbf6de55141524741b4e4063cd542ef7128
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/util/ViewGroup.java
|
|
@@ -0,0 +1,62 @@
|
|
+package org.leavesmc.leaves.protocol.jade.util;
|
|
+
|
|
+import io.netty.buffer.ByteBuf;
|
|
+import net.minecraft.nbt.CompoundTag;
|
|
+import net.minecraft.network.codec.ByteBufCodecs;
|
|
+import net.minecraft.network.codec.StreamCodec;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Optional;
|
|
+
|
|
+public class ViewGroup<T> {
|
|
+ public static <B extends ByteBuf, T> StreamCodec<B, ViewGroup<T>> codec(StreamCodec<B, T> viewCodec) {
|
|
+ return StreamCodec.composite(
|
|
+ ByteBufCodecs.<B, T>list().apply(viewCodec),
|
|
+ $ -> $.views,
|
|
+ ByteBufCodecs.optional(ByteBufCodecs.STRING_UTF8),
|
|
+ $ -> Optional.ofNullable($.id),
|
|
+ ByteBufCodecs.optional(ByteBufCodecs.COMPOUND_TAG),
|
|
+ $ -> Optional.ofNullable($.extraData),
|
|
+ ViewGroup::new);
|
|
+ }
|
|
+
|
|
+ public static <B extends ByteBuf, T> StreamCodec<B, Map.Entry<ResourceLocation, List<ViewGroup<T>>>> listCodec(StreamCodec<B, T> viewCodec) {
|
|
+ return StreamCodec.composite(
|
|
+ ResourceLocation.STREAM_CODEC,
|
|
+ Map.Entry::getKey,
|
|
+ ByteBufCodecs.<B, ViewGroup<T>>list().apply(codec(viewCodec)),
|
|
+ Map.Entry::getValue,
|
|
+ Map::entry);
|
|
+ }
|
|
+
|
|
+ public List<T> views;
|
|
+ @Nullable
|
|
+ public String id;
|
|
+ @Nullable
|
|
+ protected CompoundTag extraData;
|
|
+
|
|
+ public ViewGroup(List<T> views) {
|
|
+ this(views, Optional.empty(), Optional.empty());
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
|
+ public ViewGroup(List<T> views, Optional<String> id, Optional<CompoundTag> extraData) {
|
|
+ this.views = views;
|
|
+ this.id = id.orElse(null);
|
|
+ this.extraData = extraData.orElse(null);
|
|
+ }
|
|
+
|
|
+ public CompoundTag getExtraData() {
|
|
+ if (extraData == null) {
|
|
+ extraData = new CompoundTag();
|
|
+ }
|
|
+ return extraData;
|
|
+ }
|
|
+
|
|
+ public void setProgress(float progress) {
|
|
+ getExtraData().putFloat("Progress", progress);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/util/WrappedHierarchyLookup.java b/src/main/java/org/leavesmc/leaves/protocol/jade/util/WrappedHierarchyLookup.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..11d66b88327a954c8d530a002aa87c9abae8da12
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/util/WrappedHierarchyLookup.java
|
|
@@ -0,0 +1,96 @@
|
|
+package org.leavesmc.leaves.protocol.jade.util;
|
|
+
|
|
+import com.google.common.collect.Lists;
|
|
+import net.minecraft.resources.ResourceLocation;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+import org.apache.commons.lang3.tuple.Pair;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.Accessor;
|
|
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
|
|
+import org.leavesmc.leaves.protocol.jade.provider.IJadeProvider;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.function.Function;
|
|
+import java.util.stream.Stream;
|
|
+
|
|
+public class WrappedHierarchyLookup<T extends IJadeProvider> extends HierarchyLookup<T> {
|
|
+ public final List<Pair<IHierarchyLookup<T>, Function<Accessor<?>, @Nullable Object>>> overrides = Lists.newArrayList();
|
|
+ private boolean empty = true;
|
|
+
|
|
+ public WrappedHierarchyLookup() {
|
|
+ super(Object.class, true);
|
|
+ overrides.add(Pair.of(new HierarchyLookup<>(Block.class, true), accessor -> {
|
|
+ if (accessor instanceof BlockAccessor blockAccessor) {
|
|
+ return blockAccessor.getBlock();
|
|
+ }
|
|
+ return null;
|
|
+ }));
|
|
+ }
|
|
+
|
|
+ public List<T> wrappedGet(Accessor<?> accessor) {
|
|
+ List<T> list = Lists.newArrayList();
|
|
+ for (var override : overrides) {
|
|
+ Object o = override.getRight().apply(accessor);
|
|
+ if (o != null) {
|
|
+ list.addAll(override.getLeft().get(o));
|
|
+ }
|
|
+ }
|
|
+ list.addAll(get(accessor.getTarget()));
|
|
+ return list;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void register(Class<?> clazz, T provider) {
|
|
+ for (var override : overrides) {
|
|
+ if (override.getLeft().isClassAcceptable(clazz)) {
|
|
+ override.getLeft().register(clazz, provider);
|
|
+ empty = false;
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ super.register(clazz, provider);
|
|
+ empty = false;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isClassAcceptable(Class<?> clazz) {
|
|
+ for (var override : overrides) {
|
|
+ if (override.getLeft().isClassAcceptable(clazz)) {
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ return super.isClassAcceptable(clazz);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void invalidate() {
|
|
+ for (var override : overrides) {
|
|
+ override.getLeft().invalidate();
|
|
+ }
|
|
+ super.invalidate();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void loadComplete(PriorityStore<ResourceLocation, IJadeProvider> priorityStore) {
|
|
+ for (var override : overrides) {
|
|
+ override.getLeft().loadComplete(priorityStore);
|
|
+ }
|
|
+ super.loadComplete(priorityStore);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return empty;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Stream<Map.Entry<Class<?>, Collection<T>>> entries() {
|
|
+ Stream<Map.Entry<Class<?>, Collection<T>>> stream = super.entries();
|
|
+ for (var override : overrides) {
|
|
+ stream = Stream.concat(stream, override.getLeft().entries());
|
|
+ }
|
|
+ return stream;
|
|
+ }
|
|
+}
|